grep: add support for -r
authorDenis Vlasenko <vda.linux@googlemail.com>
Sat, 14 Oct 2006 14:24:30 +0000 (14:24 -0000)
committerDenis Vlasenko <vda.linux@googlemail.com>
Sat, 14 Oct 2006 14:24:30 +0000 (14:24 -0000)
findutils/find.c
findutils/grep.c
include/libbb.h
include/usage.h
libbb/recursive_action.c

index 913a778..62cb5d7 100644 (file)
@@ -74,7 +74,7 @@ static int fileAction(const char *fileName, struct stat *statbuf, void* junk)
                        tmp = fileName;
                else
                        tmp++;
-               if (!(fnmatch(pattern, tmp, FNM_PERIOD) == 0))
+               if (fnmatch(pattern, tmp, FNM_PERIOD) != 0)
                        goto no_match;
        }
 #ifdef CONFIG_FEATURE_FIND_TYPE
@@ -143,8 +143,8 @@ static int fileAction(const char *fileName, struct stat *statbuf, void* junk)
 #else
        puts(fileName);
 #endif
-no_match:
-       return (TRUE);
+ no_match:
+       return TRUE;
 }
 
 #ifdef CONFIG_FEATURE_FIND_TYPE
@@ -153,27 +153,27 @@ static int find_type(char *type)
        int mask = 0;
 
        switch (type[0]) {
-               case 'b':
-                       mask = S_IFBLK;
-                       break;
-               case 'c':
-                       mask = S_IFCHR;
-                       break;
-               case 'd':
-                       mask = S_IFDIR;
-                       break;
-               case 'p':
-                       mask = S_IFIFO;
-                       break;
-               case 'f':
-                       mask = S_IFREG;
-                       break;
-               case 'l':
-                       mask = S_IFLNK;
-                       break;
-               case 's':
-                       mask = S_IFSOCK;
-                       break;
+       case 'b':
+               mask = S_IFBLK;
+               break;
+       case 'c':
+               mask = S_IFCHR;
+               break;
+       case 'd':
+               mask = S_IFDIR;
+               break;
+       case 'p':
+               mask = S_IFIFO;
+               break;
+       case 'f':
+               mask = S_IFREG;
+               break;
+       case 'l':
+               mask = S_IFLNK;
+               break;
+       case 's':
+               mask = S_IFSOCK;
+               break;
        }
 
        if (mask == 0 || type[1] != '\0')
@@ -306,12 +306,12 @@ int find_main(int argc, char **argv)
        }
 
        if (firstopt == 1) {
-               if (! recursive_action(".", TRUE, dereference, FALSE, fileAction,
+               if (!recursive_action(".", TRUE, dereference, FALSE, fileAction,
                                        fileAction, NULL))
                        status = EXIT_FAILURE;
        } else {
                for (i = 1; i < firstopt; i++) {
-                       if (! recursive_action(argv[i], TRUE, dereference, FALSE, fileAction,
+                       if (!recursive_action(argv[i], TRUE, dereference, FALSE, fileAction,
                                                fileAction, NULL))
                                status = EXIT_FAILURE;
                }
index c0c495b..1285d21 100644 (file)
 
 
 /* options */
-static unsigned opt;
-#define GREP_OPTS "lnqvscFiHhe:f:Lo"
+#define GREP_OPTS "lnqvscFiHhe:f:Lor"
 #define GREP_OPT_l (1<<0)
-#define PRINT_FILES_WITH_MATCHES (opt & GREP_OPT_l)
+#define PRINT_FILES_WITH_MATCHES (option_mask32 & GREP_OPT_l)
 #define GREP_OPT_n (1<<1)
-#define PRINT_LINE_NUM (opt & GREP_OPT_n)
+#define PRINT_LINE_NUM (option_mask32 & GREP_OPT_n)
 #define GREP_OPT_q (1<<2)
-#define BE_QUIET (opt & GREP_OPT_q)
+#define BE_QUIET (option_mask32 & GREP_OPT_q)
 #define GREP_OPT_v (1<<3)
-typedef char invert_search_t;
-static invert_search_t invert_search;
 #define GREP_OPT_s (1<<4)
-#define SUPPRESS_ERR_MSGS (opt & GREP_OPT_s)
+#define SUPPRESS_ERR_MSGS (option_mask32 & GREP_OPT_s)
 #define GREP_OPT_c (1<<5)
-#define PRINT_MATCH_COUNTS (opt & GREP_OPT_c)
+#define PRINT_MATCH_COUNTS (option_mask32 & GREP_OPT_c)
 #define GREP_OPT_F (1<<6)
-#define FGREP_FLAG (opt & GREP_OPT_F)
+#define FGREP_FLAG (option_mask32 & GREP_OPT_F)
 #define GREP_OPT_i (1<<7)
 #define GREP_OPT_H (1<<8)
 #define GREP_OPT_h (1<<9)
 #define GREP_OPT_e (1<<10)
 #define GREP_OPT_f (1<<11)
 #define GREP_OPT_L (1<<12)
-#define PRINT_FILES_WITHOUT_MATCHES (opt & GREP_OPT_L)
+#define PRINT_FILES_WITHOUT_MATCHES (option_mask32 & GREP_OPT_L)
 #define GREP_OPT_o (1<<13)
+#define GREP_OPT_r (1<<14)
 #if ENABLE_FEATURE_GREP_CONTEXT
-#define GREP_OPT_CONTEXT "A:B:C:"
-#define GREP_OPT_A (1<<14)
-#define GREP_OPT_B (1<<15)
-#define GREP_OPT_C (1<<16)
-#define GREP_OPT_E (1<<17)
+# define GREP_OPT_CONTEXT "A:B:C:"
+# define GREP_OPT_A (1<<15)
+# define GREP_OPT_B (1<<16)
+# define GREP_OPT_C (1<<17)
+# define GREP_OPT_E (1<<18)
 #else
-#define GREP_OPT_CONTEXT ""
-#define GREP_OPT_A 0
-#define GREP_OPT_B 0
-#define GREP_OPT_C 0
-#define GREP_OPT_E (1<<14)
+# define GREP_OPT_CONTEXT ""
+# define GREP_OPT_A 0
+# define GREP_OPT_B 0
+# define GREP_OPT_C 0
+# define GREP_OPT_E (1<<15)
 #endif
 #if ENABLE_FEATURE_GREP_EGREP_ALIAS
 # define OPT_EGREP "E"
@@ -68,8 +66,12 @@ static invert_search_t invert_search;
 # define OPT_EGREP ""
 #endif
 
+typedef unsigned char byte_t;
+
 static int reflags;
-static int print_filename;
+static byte_t invert_search;
+static byte_t print_filename;
+static byte_t open_errors;
 
 #if ENABLE_FEATURE_GREP_CONTEXT
 static int lines_before;
@@ -80,7 +82,7 @@ static int last_line_printed;
 
 /* globals used internally */
 static llist_t *pattern_head;   /* growable list of patterns to match */
-static char *cur_file;          /* the current file we are reading */
+static const char *cur_file;    /* the current file we are reading */
 
 typedef struct GREP_LIST_DATA {
        char *pattern;
@@ -100,12 +102,12 @@ static void print_line(const char *line, int linenum, char decoration)
        }
        last_line_printed = linenum;
 #endif
-       if (print_filename > 0)
+       if (print_filename)
                printf("%s%c", cur_file, decoration);
        if (PRINT_LINE_NUM)
                printf("%i%c", linenum, decoration);
        /* Emulate weird GNU grep behavior with -ov */
-       if ((opt & (GREP_OPT_v+GREP_OPT_o)) != (GREP_OPT_v+GREP_OPT_o))
+       if ((option_mask32 & (GREP_OPT_v+GREP_OPT_o)) != (GREP_OPT_v+GREP_OPT_o))
                puts(line);
 }
 
@@ -113,7 +115,7 @@ static void print_line(const char *line, int linenum, char decoration)
 static int grep_file(FILE *file)
 {
        char *line;
-       invert_search_t ret;
+       byte_t ret;
        int linenum = 0;
        int nmatches = 0;
        regmatch_t regmatch;
@@ -199,7 +201,7 @@ static int grep_file(FILE *file)
                                        /* make a note that we need to print 'after' lines */
                                        print_n_lines_after = lines_after;
 #endif
-                                       if (opt & GREP_OPT_o) {
+                                       if (option_mask32 & GREP_OPT_o) {
                                                line[regmatch.rm_eo] = '\0';
                                                print_line(line + regmatch.rm_so, linenum, ':');
                                        } else {
@@ -231,7 +233,7 @@ static int grep_file(FILE *file)
 
        /* grep -c: print [filename:]count, even if count is zero */
        if (PRINT_MATCH_COUNTS) {
-               if (print_filename > 0)
+               if (print_filename)
                        printf("%s:", cur_file);
                printf("%d\n", nmatches);
        }
@@ -288,48 +290,71 @@ static void load_regexes_from_file(llist_t *fopt)
 }
 
 
+static int file_action_grep(const char *filename, struct stat *statbuf, void* matched)
+{
+       FILE *file = fopen(filename, "r");
+       if (file == NULL) {
+               if (!SUPPRESS_ERR_MSGS)
+                       bb_perror_msg("%s", cur_file);
+               open_errors = 1;
+               return 0;
+       }
+       cur_file = filename;
+       *(int*)matched += grep_file(file);
+       return 1;
+}
+
+
+static int grep_dir(const char *dir)
+{
+       int matched = 0;
+       recursive_action(dir,
+               /* recurse= */ 1,
+               /* followLinks= */ 0,
+               /* depthFirst= */ 1,
+               /* fileAction= */ file_action_grep,
+               /* dirAction= */ NULL,
+               /* userData= */ &matched);
+       return matched;
+}
+
+
 int grep_main(int argc, char **argv)
 {
        FILE *file;
        int matched;
        llist_t *fopt = NULL;
-       int error_open_count = 0;
 
        /* do normal option parsing */
 #if ENABLE_FEATURE_GREP_CONTEXT
-       char *junk;
        char *slines_after;
        char *slines_before;
        char *Copt;
 
        opt_complementary = "H-h:e::f::C-AB";
-       opt = getopt32(argc, argv,
+       getopt32(argc, argv,
                GREP_OPTS GREP_OPT_CONTEXT OPT_EGREP,
                &pattern_head, &fopt,
                &slines_after, &slines_before, &Copt);
 
-       if (opt & GREP_OPT_C) {
+       if (option_mask32 & GREP_OPT_C) {
                /* C option unseted A and B options, but next -A or -B
                   may be ovewrite own option */
-               if (!(opt & GREP_OPT_A))         /* not overwtited */
+               if (!(option_mask32 & GREP_OPT_A))         /* not overwtited */
                        slines_after = Copt;
-               if (!(opt & GREP_OPT_B))         /* not overwtited */
+               if (!(option_mask32 & GREP_OPT_B))         /* not overwtited */
                        slines_before = Copt;
-               opt |= GREP_OPT_A|GREP_OPT_B;   /* set for parse now */
+               option_mask32 |= GREP_OPT_A|GREP_OPT_B;   /* set for parse now */
        }
-       if (opt & GREP_OPT_A) {
-               lines_after = strtoul(slines_after, &junk, 10);
-               if (*junk != '\0')
-                       bb_error_msg_and_die(bb_msg_invalid_arg, slines_after, "-A");
+       if (option_mask32 & GREP_OPT_A) {
+               lines_after = xatoi_u(slines_after);
        }
-       if (opt & GREP_OPT_B) {
-               lines_before = strtoul(slines_before, &junk, 10);
-               if (*junk != '\0')
-                       bb_error_msg_and_die(bb_msg_invalid_arg, slines_before, "-B");
+       if (option_mask32 & GREP_OPT_B) {
+               lines_before = xatoi_u(slines_before);
        }
        /* sanity checks after parse may be invalid numbers ;-) */
-       if (opt & (GREP_OPT_c|GREP_OPT_q|GREP_OPT_l|GREP_OPT_L)) {
-               opt &= ~GREP_OPT_n;
+       if (option_mask32 & (GREP_OPT_c|GREP_OPT_q|GREP_OPT_l|GREP_OPT_L)) {
+               option_mask32 &= ~GREP_OPT_n;
                lines_before = 0;
                lines_after = 0;
        } else if (lines_before > 0)
@@ -337,15 +362,15 @@ int grep_main(int argc, char **argv)
 #else
        /* with auto sanity checks */
        opt_complementary = "H-h:e::f::c-n:q-n:l-n";
-       opt = getopt32(argc, argv, GREP_OPTS OPT_EGREP,
+       getopt32(argc, argv, GREP_OPTS OPT_EGREP,
                &pattern_head, &fopt);
 #endif
-       invert_search = (opt & GREP_OPT_v) != 0;        /* 0 | 1 */
+       invert_search = (option_mask32 & GREP_OPT_v) != 0;        /* 0 | 1 */
 
-       if (opt & GREP_OPT_H)
-               print_filename++;
-       if (opt & GREP_OPT_h)
-               print_filename--;
+       if (option_mask32 & GREP_OPT_H)
+               print_filename = 1;
+       if (option_mask32 & GREP_OPT_h)
+               print_filename = 0;
        if (pattern_head != NULL) {
                /* convert char *argv[] to grep_list_data_t */
                llist_t *cur;
@@ -353,20 +378,20 @@ int grep_main(int argc, char **argv)
                for (cur = pattern_head; cur; cur = cur->link)
                        cur->data = new_grep_list_data(cur->data, 0);
        }
-       if (opt & GREP_OPT_f)
+       if (option_mask32 & GREP_OPT_f)
                load_regexes_from_file(fopt);
 
        if (ENABLE_FEATURE_GREP_FGREP_ALIAS && applet_name[0] == 'f')
-               opt |= GREP_OPT_F;
+               option_mask32 |= GREP_OPT_F;
 
-       if (!(opt & GREP_OPT_o))
+       if (!(option_mask32 & GREP_OPT_o))
                reflags = REG_NOSUB;
 
        if (ENABLE_FEATURE_GREP_EGREP_ALIAS &&
-                       (applet_name[0] == 'e' || (opt & GREP_OPT_E)))
+                       (applet_name[0] == 'e' || (option_mask32 & GREP_OPT_E)))
                reflags |= REG_EXTENDED;
 
-       if (opt & GREP_OPT_i)
+       if (option_mask32 & GREP_OPT_i)
                reflags |= REG_ICASE;
 
        argv += optind;
@@ -386,9 +411,9 @@ int grep_main(int argc, char **argv)
        }
 
        /* argv[(optind)..(argc-1)] should be names of file to grep through. If
-        * there is more than one file to grep, we will print the filenames */
+        * there is more than one file to grep, we will print the filenames. */
        if (argc > 1) {
-               print_filename++;
+               print_filename = 1;
 
        /* If no files were specified, or '-' was specified, take input from
         * stdin. Otherwise, we grep through all the files specified. */
@@ -398,25 +423,35 @@ int grep_main(int argc, char **argv)
        matched = 0;
        while (argc--) {
                cur_file = *argv++;
+               file = stdin;
                if (!cur_file || (*cur_file == '-' && !cur_file[1])) {
                        cur_file = "(standard input)";
-                       file = stdin;
                } else {
+                       if (option_mask32 & GREP_OPT_r) {
+                               struct stat st;
+                               if (stat(cur_file, &st) == 0 && S_ISDIR(st.st_mode)) {
+                                       print_filename = 1;
+                                       matched += grep_dir(cur_file);
+                                       goto grep_done;
+                               }
+                       }
+                       /* else: fopen(dir) will succeed, but reading won't */
                        file = fopen(cur_file, "r");
-               }
-               if (file == NULL) {
-                       if (!SUPPRESS_ERR_MSGS)
-                               bb_perror_msg("%s", cur_file);
-                       error_open_count++;
-               } else {
-                       matched += grep_file(file);
-                       if (matched < 0) {
-                               /* we found a match but were told to be quiet, stop here and
-                               * return success */
-                               break;
+                       if (file == NULL) {
+                               if (!SUPPRESS_ERR_MSGS)
+                                       bb_perror_msg("%s", cur_file);
+                               open_errors = 1;
+                               continue;
                        }
-                       fclose(file);
                }
+               matched += grep_file(file);
+ grep_done:
+               if (matched < 0) {
+                       /* we found a match but were told to be quiet, stop here and
+                       * return success */
+                       break;
+               }
+               bb_fclose_nonstdin(file);
        }
 
        /* destroy all the elments in the pattern list */
@@ -439,7 +474,7 @@ int grep_main(int argc, char **argv)
         * if an input line is selected, even if an error was detected.  */
        if (BE_QUIET && matched)
                return 0;
-       if (error_open_count)
+       if (open_errors)
                return 2;
        return !matched; /* invert return value 0 = success, 1 = failed */
 }
index 0bcabf1..901c7e6 100644 (file)
@@ -252,8 +252,8 @@ extern FILE *bb_wfopen(const char *path, const char *mode);
 extern FILE *bb_wfopen_input(const char *filename);
 extern FILE *xfopen(const char *path, const char *mode);
 
-extern int   bb_fclose_nonstdin(FILE *f);
-extern void  bb_fflush_stdout_and_exit(int retval) ATTRIBUTE_NORETURN;
+extern int bb_fclose_nonstdin(FILE *f);
+extern void bb_fflush_stdout_and_exit(int retval) ATTRIBUTE_NORETURN;
 
 extern void xstat(char *filename, struct stat *buf);
 extern int  xsocket(int domain, int type, int protocol);
index b119c55..320294c 100644 (file)
@@ -992,7 +992,7 @@ USE_FEATURE_DATE_ISOFMT( \
        "\t-H login_host\tLog login_host into the utmp file as the hostname"
 
 #define grep_trivial_usage \
-       "[-ihHnqvso" \
+       "[-rihHnqvso" \
        USE_FEATURE_GREP_EGREP_ALIAS("E") \
        USE_FEATURE_GREP_CONTEXT("ABC") \
        "] PATTERN [FILEs...]"
@@ -1001,6 +1001,7 @@ USE_FEATURE_DATE_ISOFMT( \
        "Options:\n" \
        "\t-H\tprefix output lines with filename where match was found\n" \
        "\t-h\tsuppress the prefixing filename on output\n" \
+       "\t-r\trecurse subdirectories\n" \
        "\t-i\tignore case distinctions\n" \
        "\t-l\tlist names of files that match\n" \
        "\t-L\tlist names of files that do not match\n" \
index 28a4934..6949e34 100644 (file)
@@ -46,14 +46,14 @@ int recursive_action(const char *fileName,
                return FALSE;
        }
 
-       if (! followLinks && (S_ISLNK(statbuf.st_mode))) {
+       if (!followLinks && (S_ISLNK(statbuf.st_mode))) {
                if (fileAction == NULL)
                        return TRUE;
                else
                        return fileAction(fileName, &statbuf, userData);
        }
 
-       if (! recurse) {
+       if (!recurse) {
                if (S_ISDIR(statbuf.st_mode)) {
                        if (dirAction != NULL)
                                return (dirAction(fileName, &statbuf, userData));
@@ -65,9 +65,9 @@ int recursive_action(const char *fileName,
        if (S_ISDIR(statbuf.st_mode)) {
                DIR *dir;
 
-               if (dirAction != NULL && ! depthFirst) {
+               if (dirAction != NULL && !depthFirst) {
                        status = dirAction(fileName, &statbuf, userData);
-                       if (! status) {
+                       if (!status) {
                                bb_perror_msg("%s", fileName);
                                return FALSE;
                        } else if (status == SKIP)
@@ -84,7 +84,7 @@ int recursive_action(const char *fileName,
                        nextFile = concat_subpath_file(fileName, next->d_name);
                        if(nextFile == NULL)
                                continue;
-                       if (! recursive_action(nextFile, TRUE, followLinks, depthFirst,
+                       if (!recursive_action(nextFile, TRUE, followLinks, depthFirst,
                                                fileAction, dirAction, userData)) {
                                status = FALSE;
                        }
@@ -92,12 +92,12 @@ int recursive_action(const char *fileName,
                }
                closedir(dir);
                if (dirAction != NULL && depthFirst) {
-                       if (! dirAction(fileName, &statbuf, userData)) {
+                       if (!dirAction(fileName, &statbuf, userData)) {
                                bb_perror_msg("%s", fileName);
                                return FALSE;
                        }
                }
-               if (! status)
+               if (!status)
                        return FALSE;
        } else {
                if (fileAction == NULL)