search: make a regex with a beginning-of-word anchor work correctly

The search routine begins searching right after the cursor and behaves
as if the line starts there, which means that a beginning-of-word anchor
(\< or \b) will match there also when in fact the cursor is sitting in
the middle of a word.  To prevent finding a false match, verify that
for a regex that starts with a BOW anchor the found match is actually
the start of a word.

This fixes https://savannah.gnu.org/bugs/?45630.
master
Benno Schulenberg 2017-01-01 20:16:18 +01:00
parent e36e829ad0
commit cbf7e57ed0
1 changed files with 24 additions and 2 deletions

View File

@ -38,6 +38,8 @@ static bool history_changed = FALSE;
#ifdef HAVE_REGEX_H
static bool regexp_compiled = FALSE;
/* Have we compiled any regular expressions? */
static bool bow_anchored = FALSE;
/* Whether a regex starts with a beginning-of-word anchor. */
/* Compile the given regular expression and store it in search_regexp.
* Return TRUE if the expression is valid, and FALSE otherwise. */
@ -60,6 +62,10 @@ bool regexp_init(const char *regexp)
regexp_compiled = TRUE;
/* Remember whether the regex starts with a beginning-of-word anchor. */
bow_anchored = (strncmp(regexp, "\\<", 2) == 0 ||
strncmp(regexp, "\\b", 2) == 0);
return TRUE;
}
@ -292,8 +298,24 @@ int findnextstr(const char *needle, bool whole_word_only, size_t *match_len,
if (found != NULL) {
#ifdef HAVE_REGEX_H
/* When doing a regex search, compute the length of the match. */
if (ISSET(USE_REGEXP))
if (ISSET(USE_REGEXP)) {
found_len = regmatches[0].rm_eo - regmatches[0].rm_so;
/* If the regex starts with a BOW anchor, check that the found
* match actually is the start of a word. If not, continue. */
if (bow_anchored && found != fileptr->data) {
size_t before = move_mbleft(fileptr->data, found - fileptr->data);
/* If a word char is before the match, skip this match. */
if (is_word_mbchar(fileptr->data + before, FALSE)) {
if (ISSET(BACKWARDS_SEARCH))
rev_start = fileptr->data + before;
else
rev_start = found + move_mbright(found, 0);
continue;
}
}
}
#endif
#ifndef DISABLE_SPELLER
/* When we're spell checking, a match is only a true match when
@ -304,7 +326,7 @@ int findnextstr(const char *needle, bool whole_word_only, size_t *match_len,
break;
else {
/* Maybe there is a whole word in the rest of the line. */
rev_start = found + 1;
rev_start = found + move_mbright(found, 0);
continue;
}
} else