grep: make "-f -" work (+ testsuite)
[platform/upstream/busybox.git] / findutils / grep.c
index c2a6a21..fc78938 100644 (file)
@@ -7,7 +7,7 @@
  *
  * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
  */
-/* BB_AUDIT SUSv3 defects - unsupported option -x */
+/* BB_AUDIT SUSv3 defects - unsupported option -x "match whole line only". */
 /* BB_AUDIT GNU defects - always acts as -a.  */
 /* http://www.opengroup.org/onlinepubs/007904975/utilities/grep.html */
 /*
@@ -35,7 +35,7 @@
 enum {
        OPTBIT_l, /* list matched file names only */
        OPTBIT_n, /* print line# */
-       OPTBIT_q, /* quiet - exit(0) of first match */
+       OPTBIT_q, /* quiet - exit(EXIT_SUCCESS) of first match */
        OPTBIT_v, /* invert the match, to select non-matching lines */
        OPTBIT_s, /* suppress errors about file open errors */
        OPTBIT_c, /* count matches per file (suppresses normal output) */
@@ -126,7 +126,7 @@ struct globals {
 typedef struct grep_list_data_t {
        char *pattern;
        regex_t preg;
-#define PATTERN_MEM_A 1
+#define ALLOCATED 1
 #define COMPILED 2
        int flg_mem_alocated_compiled;
 } grep_list_data_t;
@@ -172,7 +172,7 @@ static int grep_file(FILE *file)
        enum { print_n_lines_after = 0 };
 #endif /* ENABLE_FEATURE_GREP_CONTEXT */
 
-       while ((line = xmalloc_getline(file)) != NULL) {
+       while ((line = xmalloc_fgetline(file)) != NULL) {
                llist_t *pattern_ptr = pattern_head;
                grep_list_data_t *gl = gl; /* for gcc */
 
@@ -224,12 +224,12 @@ static int grep_file(FILE *file)
                                         * "exit immediately with zero status
                                         * if any match is found,
                                         * even if errors were detected" */
-                                       exit(0);
+                                       exit(EXIT_SUCCESS);
                                }
                                /* if we're just printing filenames, we stop after the first match */
                                if (PRINT_FILES_WITH_MATCHES) {
                                        puts(cur_file);
-                                       /* fall thru to "return 1" */
+                                       /* fall through to "return 1" */
                                }
                                /* OPT_L aka PRINT_FILES_WITHOUT_MATCHES: return early */
                                return 1; /* one match */
@@ -299,7 +299,7 @@ static int grep_file(FILE *file)
                                free(before_buf[curpos]);
                                before_buf[curpos] = line;
                                curpos = (curpos + 1) % lines_before;
-                               /* avoid free(line) - we took line */
+                               /* avoid free(line) - we took the line */
                                line = NULL;
                        }
                }
@@ -363,20 +363,23 @@ static void load_regexes_from_file(llist_t *fopt)
 
                fopt = cur->link;
                free(cur);
-               f = xfopen(ffile, "r");
-               while ((line = xmalloc_getline(f)) != NULL) {
+               f = xfopen_stdin(ffile);
+               while ((line = xmalloc_fgetline(f)) != NULL) {
                        llist_add_to(&pattern_head,
-                               new_grep_list_data(line, PATTERN_MEM_A));
+                               new_grep_list_data(line, ALLOCATED));
                }
        }
 }
 
-static int file_action_grep(const char *filename, struct stat *statbuf, void* matched, int depth)
+static int file_action_grep(const char *filename,
+                       struct stat *statbuf ATTRIBUTE_UNUSED,
+                       void* matched,
+                       int depth ATTRIBUTE_UNUSED)
 {
        FILE *file = fopen(filename, "r");
        if (file == NULL) {
                if (!SUPPRESS_ERR_MSGS)
-                       bb_simple_perror_msg(cur_file);
+                       bb_simple_perror_msg(filename);
                open_errors = 1;
                return 0;
        }
@@ -405,35 +408,28 @@ int grep_main(int argc, char **argv)
 {
        FILE *file;
        int matched;
-       char *mopt;
        llist_t *fopt = NULL;
 
        /* do normal option parsing */
 #if ENABLE_FEATURE_GREP_CONTEXT
-       char *slines_after;
-       char *slines_before;
-       char *Copt;
+       int Copt;
 
-       opt_complementary = "H-h:e::f::C-AB";
+       /* -H unsets -h; -C unsets -A,-B; -e,-f are lists;
+        * -m,-A,-B,-C have numeric param */
+       opt_complementary = "H-h:C-AB:e::f::m+:A+:B+:C+";
        getopt32(argv,
                OPTSTR_GREP,
-               &pattern_head, &fopt, &mopt,
-               &slines_after, &slines_before, &Copt);
+               &pattern_head, &fopt, &max_matches,
+               &lines_after, &lines_before, &Copt);
 
        if (option_mask32 & OPT_C) {
                /* -C unsets prev -A and -B, but following -A or -B
                   may override it */
                if (!(option_mask32 & OPT_A)) /* not overridden */
-                       slines_after = Copt;
+                       lines_after = Copt;
                if (!(option_mask32 & OPT_B)) /* not overridden */
-                       slines_before = Copt;
-               option_mask32 |= OPT_A|OPT_B; /* for parser */
-       }
-       if (option_mask32 & OPT_A) {
-               lines_after = xatoi_u(slines_after);
-       }
-       if (option_mask32 & OPT_B) {
-               lines_before = xatoi_u(slines_before);
+                       lines_before = Copt;
+               //option_mask32 |= OPT_A|OPT_B; /* for parser */
        }
        /* sanity checks */
        if (option_mask32 & (OPT_c|OPT_q|OPT_l|OPT_L)) {
@@ -444,13 +440,11 @@ int grep_main(int argc, char **argv)
                before_buf = xzalloc(lines_before * sizeof(char *));
 #else
        /* with auto sanity checks */
-       opt_complementary = "H-h:e::f::c-n:q-n:l-n";
+       /* -H unsets -h; -c,-q or -l unset -n; -e,-f are lists; -m N */
+       opt_complementary = "H-h:c-n:q-n:l-n:e::f::m+";
        getopt32(argv, OPTSTR_GREP,
-               &pattern_head, &fopt, &mopt);
+               &pattern_head, &fopt, &max_matches);
 #endif
-       if (option_mask32 & OPT_m) {
-               max_matches = xatoi_u(mopt);
-       }
        invert_search = ((option_mask32 & OPT_v) != 0); /* 0 | 1 */
 
        if (pattern_head != NULL) {
@@ -481,8 +475,8 @@ int grep_main(int argc, char **argv)
        argv += optind;
        argc -= optind;
 
-       /* if we didn't get a pattern from -e and no command file was specified,
-        * argv[optind] should be the pattern. no pattern, no worky */
+       /* if we didn't get a pattern from -e and no command file was specified,
+        * first parameter should be the pattern. no pattern, no worky */
        if (pattern_head == NULL) {
                char *pattern;
                if (*argv == NULL)
@@ -492,7 +486,7 @@ int grep_main(int argc, char **argv)
                argc--;
        }
 
-       /* argv[(optind)..(argc-1)] should be names of file to grep through. If
+       /* argv[0..(argc-1)] should be names of file to grep through. If
         * there is more than one file to grep, we will print the filenames. */
        if (argc > 1)
                print_filename = 1;
@@ -508,7 +502,7 @@ int grep_main(int argc, char **argv)
        do {
                cur_file = *argv++;
                file = stdin;
-               if (!cur_file || (*cur_file == '-' && !cur_file[1])) {
+               if (!cur_file || LONE_DASH(cur_file)) {
                        cur_file = "(standard input)";
                } else {
                        if (option_mask32 & OPT_r) {
@@ -541,9 +535,9 @@ int grep_main(int argc, char **argv)
                        grep_list_data_t *gl = (grep_list_data_t *)pattern_head_ptr->data;
 
                        pattern_head = pattern_head->link;
-                       if ((gl->flg_mem_alocated_compiled & PATTERN_MEM_A))
+                       if (gl->flg_mem_alocated_compiled & ALLOCATED)
                                free(gl->pattern);
-                       if ((gl->flg_mem_alocated_compiled & COMPILED))
+                       if (gl->flg_mem_alocated_compiled & COMPILED)
                                regfree(&(gl->preg));
                        free(gl);
                        free(pattern_head_ptr);