grep: fix grep -Fw not respecting the -w option. Closes 5792
authorDenys Vlasenko <vda.linux@googlemail.com>
Sun, 20 Jan 2013 15:57:19 +0000 (16:57 +0100)
committerDenys Vlasenko <vda.linux@googlemail.com>
Sun, 20 Jan 2013 15:57:19 +0000 (16:57 +0100)
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
findutils/grep.c
testsuite/grep.tests

index de4fcf5ad3841ef44e8f0920d1edd703585cc849..70f3516a53eef31b232cddf067a28b64e247d645 100644 (file)
@@ -344,10 +344,34 @@ static int grep_file(FILE *file)
                while (pattern_ptr) {
                        gl = (grep_list_data_t *)pattern_ptr->data;
                        if (FGREP_FLAG) {
-                               found |= (((option_mask32 & OPT_i)
-                                       ? strcasestr(line, gl->pattern)
-                                       : strstr(line, gl->pattern)
-                                       ) != NULL);
+                               char *match;
+                               char *str = line;
+ opt_f_again:
+                               match = ((option_mask32 & OPT_i)
+                                       ? strcasestr(str, gl->pattern)
+                                       : strstr(str, gl->pattern)
+                                       );
+                               if (match) {
+                                       if (option_mask32 & OPT_x) {
+                                               if (match != str)
+                                                       goto opt_f_not_found;
+                                               if (str[strlen(gl->pattern)] != '\0')
+                                                       goto opt_f_not_found;
+                                       } else
+                                       if (option_mask32 & OPT_w) {
+                                               char c = (match != str) ? match[-1] : ' ';
+                                               if (!isalnum(c) && c != '_') {
+                                                       c = match[strlen(gl->pattern)];
+                                                       if (!c || (!isalnum(c) && c != '_'))
+                                                               goto opt_f_found;
+                                               }
+                                               str = match + 1;
+                                               goto opt_f_again;
+                                       }
+ opt_f_found:
+                                       found = 1;
+ opt_f_not_found: ;
+                               }
                        } else {
                                if (!(gl->flg_mem_alocated_compiled & COMPILED)) {
                                        gl->flg_mem_alocated_compiled |= COMPILED;
@@ -376,7 +400,8 @@ static int grep_file(FILE *file)
                                        if (option_mask32 & OPT_x) {
                                                found = (gl->matched_range.rm_so == 0
                                                         && line[gl->matched_range.rm_eo] == '\0');
-                                       } else if (!(option_mask32 & OPT_w)) {
+                                       } else
+                                       if (!(option_mask32 & OPT_w)) {
                                                found = 1;
                                        } else {
                                                char c = ' ';
@@ -387,6 +412,8 @@ static int grep_file(FILE *file)
                                                        if (!c || (!isalnum(c) && c != '_'))
                                                                found = 1;
                                                }
+//BUG: "echo foop foo | grep -w foo" should match, but doesn't:
+//we bail out on first "mismatch" because it's not a word.
                                        }
                                }
                        }
index 006a215e1b723efd59629b2f13f4cfff45edde29..4781f228472e6a68ffee772ce8e2ab3cd0ac1d01 100755 (executable)
@@ -115,6 +115,18 @@ testing "grep -v -f EMPTY_FILE" \
        "" \
        "test\n"
 
+testing "grep -Fw matches only words" \
+       "grep -Fw foo input" \
+       "" \
+       "foop\n" \
+       ""
+
+testing "grep -Fw doesn't stop on 1st mismatch" \
+       "grep -Fw foo input" \
+       "foop foo\n" \
+       "foop foo\n" \
+       ""
+
 # testing "test name" "commands" "expected result" "file input" "stdin"
 #   file input will be file called "input"
 #   test can create a file "actual" instead of writing to stdout