Index: contrib/netbsd-tests/usr.bin/grep/d_wv_combo_break_a.in =================================================================== --- /dev/null +++ contrib/netbsd-tests/usr.bin/grep/d_wv_combo_break_a.in @@ -0,0 +1 @@ +x xx Index: contrib/netbsd-tests/usr.bin/grep/d_wv_combo_break_b.in =================================================================== --- /dev/null +++ contrib/netbsd-tests/usr.bin/grep/d_wv_combo_break_b.in @@ -0,0 +1 @@ +xx x Index: contrib/netbsd-tests/usr.bin/grep/t_grep.sh =================================================================== --- contrib/netbsd-tests/usr.bin/grep/t_grep.sh +++ contrib/netbsd-tests/usr.bin/grep/t_grep.sh @@ -317,6 +317,24 @@ { atf_check -s exit:1 egrep '{' /dev/null } + +atf_test_case wv_combo_break +wv_combo_break_head() +{ + atf_set "descr" "Check for incorrectly matching lines with both -w and -v flags (PR 218467)" +} +wv_combo_break_body() +{ + atf_check -o file:"$(atf_get_srcdir)/d_wv_combo_break_a.in" \ + grep -w "x" "$(atf_get_srcdir)/d_wv_combo_break_a.in" + + atf_check -o file:"$(atf_get_srcdir)/d_wv_combo_break_b.in" \ + grep -w "x" "$(atf_get_srcdir)/d_wv_combo_break_b.in" + + atf_check -s exit:1 grep -v -w "x" "$(atf_get_srcdir)/d_wv_combo_break_a.in" + + atf_check -s exit:1 grep -v -w "x" "$(atf_get_srcdir)/d_wv_combo_break_b.in" +} # End FreeBSD atf_init_test_cases() @@ -344,5 +362,6 @@ atf_add_test_case f_file_empty atf_add_test_case escmap atf_add_test_case egrep_empty_invalid + atf_add_test_case wv_combo_break # End FreeBSD } Index: usr.bin/grep/tests/Makefile =================================================================== --- usr.bin/grep/tests/Makefile +++ usr.bin/grep/tests/Makefile @@ -45,6 +45,8 @@ ${PACKAGE}FILES+= d_recurse_symlink.out ${PACKAGE}FILES+= d_whole_line.out ${PACKAGE}FILES+= d_word_regexps.out +${PACKAGE}FILES+= d_wv_combo_break_a.in +${PACKAGE}FILES+= d_wv_combo_break_b.in ${PACKAGE}FILES+= d_zgrep.out .include Index: usr.bin/grep/util.c =================================================================== --- usr.bin/grep/util.c +++ usr.bin/grep/util.c @@ -281,6 +281,7 @@ unsigned int i; int c = 0, m = 0, r = 0, lastmatches = 0, leflags = eflags; int startm = 0; + bool retry; /* Initialize to avoid a false positive warning from GCC. */ lastmatch.rm_so = lastmatch.rm_eo = 0; @@ -289,6 +290,7 @@ while (st <= l->len) { lastmatches = 0; startm = m; + retry = false; if (st > 0) leflags |= REG_NOTBOL; /* Loop to compare with all the patterns */ @@ -326,6 +328,14 @@ else if (iswword(wbegin) || iswword(wend)) r = REG_NOMATCH; + /* + * If we're doing whole word matching and we matched once, then we should + * try the pattern again after advancing another character. This allows + * the pattern to match later on in the line and possibly still match + * a whole word. + */ + if (r == REG_NOMATCH) + retry = true; } if (r == 0) { lastmatches++; @@ -358,9 +368,10 @@ } } - if (vflag) { - c = !c; - break; + /* Advance a character, try again just in case we still have a chance */ + if (lastmatches == 0 && retry) { + st++; + continue; } /* One pass if we are not recording matches */ @@ -383,6 +394,9 @@ } + if (vflag) + c = !c; + /* Count the matches if we have a match limit */ if (mflag) mcount -= c;