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 @@ -391,6 +391,23 @@ atf_check -o inline:"Eggs\nCheese\n" grep -v -e "^$" test1 } + +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() +{ + printf "x xx\n" > test1 + printf "xx x\n" > test2 + + atf_check -o file:test1 grep -w "x" test1 + atf_check -o file:test2 grep -w "x" test2 + + atf_check -s exit:1 grep -v -w "x" test1 + atf_check -s exit:1 grep -v -w "x" test2 +} # End FreeBSD atf_init_test_cases() @@ -419,5 +436,6 @@ atf_add_test_case escmap atf_add_test_case egrep_empty_invalid atf_add_test_case zerolen + atf_add_test_case wv_combo_break # End FreeBSD } Index: usr.bin/grep/util.c =================================================================== --- usr.bin/grep/util.c +++ usr.bin/grep/util.c @@ -303,6 +303,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; @@ -311,6 +312,7 @@ while (st <= l->len) { lastmatches = 0; startm = m; + retry = false; if (st > 0) leflags |= REG_NOTBOL; /* Loop to compare with all the patterns */ @@ -348,6 +350,16 @@ 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++; @@ -377,9 +389,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 */ @@ -402,6 +415,9 @@ } + if (vflag) + c = !c; + /* Count the matches if we have a match limit */ if (mflag) mcount -= c;