Magellan Linux

Annotation of /trunk/mkinitrd-magellan/busybox/findutils/grep.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 816 - (hide annotations) (download)
Fri Apr 24 18:33:46 2009 UTC (15 years, 1 month ago) by niro
File MIME type: text/plain
File size: 19339 byte(s)
-updated to busybox-1.13.4
1 niro 532 /* vi: set sw=4 ts=4: */
2     /*
3     * Mini grep implementation for busybox using libc regex.
4     *
5     * Copyright (C) 1999,2000,2001 by Lineo, inc. and Mark Whitley
6     * Copyright (C) 1999,2000,2001 by Mark Whitley <markw@codepoet.org>
7     *
8     * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
9     */
10 niro 816 /* BB_AUDIT SUSv3 defects - unsupported option -x "match whole line only". */
11 niro 532 /* BB_AUDIT GNU defects - always acts as -a. */
12     /* http://www.opengroup.org/onlinepubs/007904975/utilities/grep.html */
13     /*
14     * 2004,2006 (C) Vladimir Oleynik <dzo@simtreas.ru> -
15     * correction "-e pattern1 -e pattern2" logic and more optimizations.
16     * precompiled regex
17     */
18     /*
19     * (C) 2006 Jac Goudsmit added -o option
20     */
21    
22 niro 816 #include "libbb.h"
23 niro 532 #include "xregex.h"
24    
25 niro 816 /* options */
26     #define OPTSTR_GREP \
27     "lnqvscFiHhe:f:Lorm:" \
28     USE_FEATURE_GREP_CONTEXT("A:B:C:") \
29     USE_FEATURE_GREP_EGREP_ALIAS("E") \
30     USE_DESKTOP("w") \
31     "aI"
32     /* ignored: -a "assume all files to be text" */
33     /* ignored: -I "assume binary files have no matches" */
34 niro 532
35 niro 816 enum {
36     OPTBIT_l, /* list matched file names only */
37     OPTBIT_n, /* print line# */
38     OPTBIT_q, /* quiet - exit(EXIT_SUCCESS) of first match */
39     OPTBIT_v, /* invert the match, to select non-matching lines */
40     OPTBIT_s, /* suppress errors about file open errors */
41     OPTBIT_c, /* count matches per file (suppresses normal output) */
42     OPTBIT_F, /* literal match */
43     OPTBIT_i, /* case-insensitive */
44     OPTBIT_H, /* force filename display */
45     OPTBIT_h, /* inhibit filename display */
46     OPTBIT_e, /* -e PATTERN */
47     OPTBIT_f, /* -f FILE_WITH_PATTERNS */
48     OPTBIT_L, /* list unmatched file names only */
49     OPTBIT_o, /* show only matching parts of lines */
50     OPTBIT_r, /* recurse dirs */
51     OPTBIT_m, /* -m MAX_MATCHES */
52     USE_FEATURE_GREP_CONTEXT( OPTBIT_A ,) /* -A NUM: after-match context */
53     USE_FEATURE_GREP_CONTEXT( OPTBIT_B ,) /* -B NUM: before-match context */
54     USE_FEATURE_GREP_CONTEXT( OPTBIT_C ,) /* -C NUM: -A and -B combined */
55     USE_FEATURE_GREP_EGREP_ALIAS(OPTBIT_E ,) /* extended regexp */
56     USE_DESKTOP( OPTBIT_w ,) /* whole word match */
57     OPT_l = 1 << OPTBIT_l,
58     OPT_n = 1 << OPTBIT_n,
59     OPT_q = 1 << OPTBIT_q,
60     OPT_v = 1 << OPTBIT_v,
61     OPT_s = 1 << OPTBIT_s,
62     OPT_c = 1 << OPTBIT_c,
63     OPT_F = 1 << OPTBIT_F,
64     OPT_i = 1 << OPTBIT_i,
65     OPT_H = 1 << OPTBIT_H,
66     OPT_h = 1 << OPTBIT_h,
67     OPT_e = 1 << OPTBIT_e,
68     OPT_f = 1 << OPTBIT_f,
69     OPT_L = 1 << OPTBIT_L,
70     OPT_o = 1 << OPTBIT_o,
71     OPT_r = 1 << OPTBIT_r,
72     OPT_m = 1 << OPTBIT_m,
73     OPT_A = USE_FEATURE_GREP_CONTEXT( (1 << OPTBIT_A)) + 0,
74     OPT_B = USE_FEATURE_GREP_CONTEXT( (1 << OPTBIT_B)) + 0,
75     OPT_C = USE_FEATURE_GREP_CONTEXT( (1 << OPTBIT_C)) + 0,
76     OPT_E = USE_FEATURE_GREP_EGREP_ALIAS((1 << OPTBIT_E)) + 0,
77     OPT_w = USE_DESKTOP( (1 << OPTBIT_w)) + 0,
78     };
79    
80     #define PRINT_FILES_WITH_MATCHES (option_mask32 & OPT_l)
81     #define PRINT_LINE_NUM (option_mask32 & OPT_n)
82     #define BE_QUIET (option_mask32 & OPT_q)
83     #define SUPPRESS_ERR_MSGS (option_mask32 & OPT_s)
84     #define PRINT_MATCH_COUNTS (option_mask32 & OPT_c)
85     #define FGREP_FLAG (option_mask32 & OPT_F)
86     #define PRINT_FILES_WITHOUT_MATCHES (option_mask32 & OPT_L)
87    
88     struct globals {
89     int max_matches;
90     #if !ENABLE_EXTRA_COMPAT
91     int reflags;
92 niro 532 #else
93 niro 816 RE_TRANSLATE_TYPE case_fold; /* RE_TRANSLATE_TYPE is [[un]signed] char* */
94 niro 532 #endif
95 niro 816 smalluint invert_search;
96     smalluint print_filename;
97     smalluint open_errors;
98     #if ENABLE_FEATURE_GREP_CONTEXT
99     smalluint did_print_line;
100     int lines_before;
101     int lines_after;
102     char **before_buf;
103     USE_EXTRA_COMPAT(size_t *before_buf_size;)
104     int last_line_printed;
105     #endif
106     /* globals used internally */
107     llist_t *pattern_head; /* growable list of patterns to match */
108     const char *cur_file; /* the current file we are reading */
109     };
110     #define G (*(struct globals*)&bb_common_bufsiz1)
111     #define INIT_G() do { \
112     struct G_sizecheck { \
113     char G_sizecheck[sizeof(G) > COMMON_BUFSIZE ? -1 : 1]; \
114     }; \
115     } while (0)
116     #define max_matches (G.max_matches )
117     #if !ENABLE_EXTRA_COMPAT
118     #define reflags (G.reflags )
119 niro 532 #else
120 niro 816 #define case_fold (G.case_fold )
121     /* http://www.delorie.com/gnu/docs/regex/regex_46.html */
122     #define reflags re_syntax_options
123     #undef REG_NOSUB
124     #undef REG_EXTENDED
125     #undef REG_ICASE
126     #define REG_NOSUB bug:is:here /* should not be used */
127     #define REG_EXTENDED RE_SYNTAX_EGREP
128     #define REG_ICASE bug:is:here /* should not be used */
129 niro 532 #endif
130 niro 816 #define invert_search (G.invert_search )
131     #define print_filename (G.print_filename )
132     #define open_errors (G.open_errors )
133     #define did_print_line (G.did_print_line )
134     #define lines_before (G.lines_before )
135     #define lines_after (G.lines_after )
136     #define before_buf (G.before_buf )
137     #define before_buf_size (G.before_buf_size )
138     #define last_line_printed (G.last_line_printed )
139     #define pattern_head (G.pattern_head )
140     #define cur_file (G.cur_file )
141 niro 532
142    
143 niro 816 typedef struct grep_list_data_t {
144 niro 532 char *pattern;
145 niro 816 /* for GNU regex, matched_range must be persistent across grep_file() calls */
146     #if !ENABLE_EXTRA_COMPAT
147     regex_t compiled_regex;
148     regmatch_t matched_range;
149     #else
150     struct re_pattern_buffer compiled_regex;
151     struct re_registers matched_range;
152     #endif
153     #define ALLOCATED 1
154 niro 532 #define COMPILED 2
155     int flg_mem_alocated_compiled;
156     } grep_list_data_t;
157    
158 niro 816 #if !ENABLE_EXTRA_COMPAT
159     #define print_line(line, line_len, linenum, decoration) \
160     print_line(line, linenum, decoration)
161     #endif
162     static void print_line(const char *line, size_t line_len, int linenum, char decoration)
163 niro 532 {
164     #if ENABLE_FEATURE_GREP_CONTEXT
165 niro 816 /* Happens when we go to next file, immediately hit match
166     * and try to print prev context... from prev file! Don't do it */
167     if (linenum < 1)
168     return;
169 niro 532 /* possibly print the little '--' separator */
170 niro 816 if ((lines_before || lines_after) && did_print_line
171     && last_line_printed != linenum - 1
172     ) {
173 niro 532 puts("--");
174     }
175 niro 816 /* guard against printing "--" before first line of first file */
176     did_print_line = 1;
177 niro 532 last_line_printed = linenum;
178     #endif
179     if (print_filename)
180     printf("%s%c", cur_file, decoration);
181     if (PRINT_LINE_NUM)
182     printf("%i%c", linenum, decoration);
183     /* Emulate weird GNU grep behavior with -ov */
184 niro 816 if ((option_mask32 & (OPT_v|OPT_o)) != (OPT_v|OPT_o)) {
185     #if !ENABLE_EXTRA_COMPAT
186 niro 532 puts(line);
187 niro 816 #else
188     fwrite(line, 1, line_len, stdout);
189     putchar('\n');
190     #endif
191     }
192 niro 532 }
193    
194 niro 816 #if ENABLE_EXTRA_COMPAT
195     /* Unlike getline, this one removes trailing '\n' */
196     static ssize_t FAST_FUNC bb_getline(char **line_ptr, size_t *line_alloc_len, FILE *file)
197     {
198     ssize_t res_sz;
199     char *line;
200 niro 532
201 niro 816 res_sz = getline(line_ptr, line_alloc_len, file);
202     line = *line_ptr;
203    
204     if (res_sz > 0) {
205     if (line[res_sz - 1] == '\n')
206     line[--res_sz] = '\0';
207     } else {
208     free(line); /* uclibc allocates a buffer even on EOF. WTF? */
209     }
210     return res_sz;
211     }
212     #endif
213    
214 niro 532 static int grep_file(FILE *file)
215     {
216 niro 816 smalluint found;
217 niro 532 int linenum = 0;
218     int nmatches = 0;
219 niro 816 #if !ENABLE_EXTRA_COMPAT
220     char *line;
221     #else
222     char *line = NULL;
223     ssize_t line_len;
224     size_t line_alloc_len;
225     #define rm_so start[0]
226     #define rm_eo end[0]
227     #endif
228 niro 532 #if ENABLE_FEATURE_GREP_CONTEXT
229     int print_n_lines_after = 0;
230     int curpos = 0; /* track where we are in the circular 'before' buffer */
231     int idx = 0; /* used for iteration through the circular buffer */
232 niro 816 #else
233     enum { print_n_lines_after = 0 };
234 niro 532 #endif /* ENABLE_FEATURE_GREP_CONTEXT */
235    
236 niro 816 while (
237     #if !ENABLE_EXTRA_COMPAT
238     (line = xmalloc_fgetline(file)) != NULL
239     #else
240     (line_len = bb_getline(&line, &line_alloc_len, file)) >= 0
241     #endif
242     ) {
243 niro 532 llist_t *pattern_ptr = pattern_head;
244 niro 816 grep_list_data_t *gl = gl; /* for gcc */
245 niro 532
246     linenum++;
247 niro 816 found = 0;
248 niro 532 while (pattern_ptr) {
249     gl = (grep_list_data_t *)pattern_ptr->data;
250     if (FGREP_FLAG) {
251 niro 816 found |= (strstr(line, gl->pattern) != NULL);
252 niro 532 } else {
253     if (!(gl->flg_mem_alocated_compiled & COMPILED)) {
254     gl->flg_mem_alocated_compiled |= COMPILED;
255 niro 816 #if !ENABLE_EXTRA_COMPAT
256     xregcomp(&gl->compiled_regex, gl->pattern, reflags);
257     #else
258     memset(&gl->compiled_regex, 0, sizeof(gl->compiled_regex));
259     gl->compiled_regex.translate = case_fold; /* for -i */
260     if (re_compile_pattern(gl->pattern, strlen(gl->pattern), &gl->compiled_regex))
261     bb_error_msg_and_die("bad regex '%s'", gl->pattern);
262     #endif
263 niro 532 }
264 niro 816 #if !ENABLE_EXTRA_COMPAT
265     gl->matched_range.rm_so = 0;
266     gl->matched_range.rm_eo = 0;
267     #endif
268     if (
269     #if !ENABLE_EXTRA_COMPAT
270     regexec(&gl->compiled_regex, line, 1, &gl->matched_range, 0) == 0
271     #else
272     re_search(&gl->compiled_regex, line, line_len,
273     /*start:*/ 0, /*range:*/ line_len,
274     &gl->matched_range) >= 0
275     #endif
276     ) {
277     if (!(option_mask32 & OPT_w))
278     found = 1;
279     else {
280     char c = ' ';
281     if (gl->matched_range.rm_so)
282     c = line[gl->matched_range.rm_so - 1];
283     if (!isalnum(c) && c != '_') {
284     c = line[gl->matched_range.rm_eo];
285     if (!c || (!isalnum(c) && c != '_'))
286     found = 1;
287     }
288     }
289     }
290 niro 532 }
291 niro 816 /* If it's non-inverted search, we can stop
292     * at first match */
293     if (found && !invert_search)
294     goto do_found;
295 niro 532 pattern_ptr = pattern_ptr->link;
296     } /* while (pattern_ptr) */
297    
298 niro 816 if (found ^ invert_search) {
299     do_found:
300     /* keep track of matches */
301     nmatches++;
302 niro 532
303 niro 816 /* quiet/print (non)matching file names only? */
304     if (option_mask32 & (OPT_q|OPT_l|OPT_L)) {
305     free(line); /* we don't need line anymore */
306     if (BE_QUIET) {
307     /* manpage says about -q:
308     * "exit immediately with zero status
309     * if any match is found,
310     * even if errors were detected" */
311     exit(EXIT_SUCCESS);
312     }
313 niro 532 /* if we're just printing filenames, we stop after the first match */
314 niro 816 if (PRINT_FILES_WITH_MATCHES) {
315     puts(cur_file);
316     /* fall through to "return 1" */
317     }
318     /* OPT_L aka PRINT_FILES_WITHOUT_MATCHES: return early */
319     return 1; /* one match */
320     }
321 niro 532
322     #if ENABLE_FEATURE_GREP_CONTEXT
323 niro 816 /* Were we printing context and saw next (unwanted) match? */
324     if ((option_mask32 & OPT_m) && nmatches > max_matches)
325     break;
326     #endif
327 niro 532
328 niro 816 /* print the matched line */
329     if (PRINT_MATCH_COUNTS == 0) {
330     #if ENABLE_FEATURE_GREP_CONTEXT
331     int prevpos = (curpos == 0) ? lines_before - 1 : curpos - 1;
332 niro 532
333 niro 816 /* if we were told to print 'before' lines and there is at least
334     * one line in the circular buffer, print them */
335     if (lines_before && before_buf[prevpos] != NULL) {
336     int first_buf_entry_line_num = linenum - lines_before;
337 niro 532
338 niro 816 /* advance to the first entry in the circular buffer, and
339     * figure out the line number is of the first line in the
340     * buffer */
341     idx = curpos;
342     while (before_buf[idx] == NULL) {
343     idx = (idx + 1) % lines_before;
344     first_buf_entry_line_num++;
345 niro 532 }
346    
347 niro 816 /* now print each line in the buffer, clearing them as we go */
348     while (before_buf[idx] != NULL) {
349     print_line(before_buf[idx], before_buf_size[idx], first_buf_entry_line_num, '-');
350     free(before_buf[idx]);
351     before_buf[idx] = NULL;
352     idx = (idx + 1) % lines_before;
353     first_buf_entry_line_num++;
354 niro 532 }
355     }
356 niro 816
357     /* make a note that we need to print 'after' lines */
358     print_n_lines_after = lines_after;
359     #endif
360     if (option_mask32 & OPT_o) {
361     if (FGREP_FLAG) {
362     /* -Fo just prints the pattern
363     * (unless -v: -Fov doesnt print anything at all) */
364     if (found)
365     print_line(gl->pattern, strlen(gl->pattern), linenum, ':');
366     } else while (1) {
367     char old = line[gl->matched_range.rm_eo];
368     line[gl->matched_range.rm_eo] = '\0';
369     print_line(line + gl->matched_range.rm_so,
370     gl->matched_range.rm_eo - gl->matched_range.rm_so,
371     linenum, ':');
372     line[gl->matched_range.rm_eo] = old;
373     #if !ENABLE_EXTRA_COMPAT
374     break;
375     #else
376     if (re_search(&gl->compiled_regex, line, line_len,
377     gl->matched_range.rm_eo, line_len - gl->matched_range.rm_eo,
378     &gl->matched_range) < 0)
379     break;
380     #endif
381     }
382     } else {
383     print_line(line, line_len, linenum, ':');
384     }
385 niro 532 }
386 niro 816 }
387 niro 532 #if ENABLE_FEATURE_GREP_CONTEXT
388 niro 816 else { /* no match */
389     /* if we need to print some context lines after the last match, do so */
390     if (print_n_lines_after) {
391     print_line(line, strlen(line), linenum, '-');
392     print_n_lines_after--;
393     } else if (lines_before) {
394 niro 532 /* Add the line to the circular 'before' buffer */
395 niro 816 free(before_buf[curpos]);
396     before_buf[curpos] = line;
397     USE_EXTRA_COMPAT(before_buf_size[curpos] = line_len;)
398     curpos = (curpos + 1) % lines_before;
399     /* avoid free(line) - we took the line */
400     line = NULL;
401 niro 532 }
402 niro 816 }
403 niro 532
404     #endif /* ENABLE_FEATURE_GREP_CONTEXT */
405 niro 816 #if !ENABLE_EXTRA_COMPAT
406 niro 532 free(line);
407 niro 816 #endif
408     /* Did we print all context after last requested match? */
409     if ((option_mask32 & OPT_m)
410     && !print_n_lines_after && nmatches == max_matches)
411     break;
412     } /* while (read line) */
413 niro 532
414     /* special-case file post-processing for options where we don't print line
415     * matches, just filenames and possibly match counts */
416    
417     /* grep -c: print [filename:]count, even if count is zero */
418     if (PRINT_MATCH_COUNTS) {
419     if (print_filename)
420     printf("%s:", cur_file);
421     printf("%d\n", nmatches);
422     }
423    
424 niro 816 /* grep -L: print just the filename */
425     if (PRINT_FILES_WITHOUT_MATCHES) {
426     /* nmatches is zero, no need to check it:
427     * we return 1 early if we detected a match
428     * and PRINT_FILES_WITHOUT_MATCHES is set */
429 niro 532 puts(cur_file);
430     }
431    
432     return nmatches;
433     }
434    
435     #if ENABLE_FEATURE_CLEAN_UP
436     #define new_grep_list_data(p, m) add_grep_list_data(p, m)
437 niro 816 static char *add_grep_list_data(char *pattern, int flg_used_mem)
438 niro 532 #else
439     #define new_grep_list_data(p, m) add_grep_list_data(p)
440 niro 816 static char *add_grep_list_data(char *pattern)
441 niro 532 #endif
442     {
443 niro 816 grep_list_data_t *gl = xzalloc(sizeof(*gl));
444 niro 532 gl->pattern = pattern;
445     #if ENABLE_FEATURE_CLEAN_UP
446     gl->flg_mem_alocated_compiled = flg_used_mem;
447     #else
448 niro 816 /*gl->flg_mem_alocated_compiled = 0;*/
449 niro 532 #endif
450     return (char *)gl;
451     }
452    
453     static void load_regexes_from_file(llist_t *fopt)
454     {
455     char *line;
456     FILE *f;
457    
458     while (fopt) {
459     llist_t *cur = fopt;
460     char *ffile = cur->data;
461    
462     fopt = cur->link;
463     free(cur);
464 niro 816 f = xfopen_stdin(ffile);
465     while ((line = xmalloc_fgetline(f)) != NULL) {
466 niro 532 llist_add_to(&pattern_head,
467 niro 816 new_grep_list_data(line, ALLOCATED));
468 niro 532 }
469     }
470     }
471    
472 niro 816 static int FAST_FUNC file_action_grep(const char *filename,
473     struct stat *statbuf UNUSED_PARAM,
474     void* matched,
475     int depth UNUSED_PARAM)
476 niro 532 {
477 niro 816 FILE *file = fopen_for_read(filename);
478 niro 532 if (file == NULL) {
479     if (!SUPPRESS_ERR_MSGS)
480 niro 816 bb_simple_perror_msg(filename);
481 niro 532 open_errors = 1;
482     return 0;
483     }
484     cur_file = filename;
485     *(int*)matched += grep_file(file);
486     fclose(file);
487     return 1;
488     }
489    
490     static int grep_dir(const char *dir)
491     {
492     int matched = 0;
493     recursive_action(dir,
494 niro 816 /* recurse=yes */ ACTION_RECURSE |
495     /* followLinks=no */
496     /* depthFirst=yes */ ACTION_DEPTHFIRST,
497 niro 532 /* fileAction= */ file_action_grep,
498     /* dirAction= */ NULL,
499     /* userData= */ &matched,
500     /* depth= */ 0);
501     return matched;
502     }
503    
504 niro 816 int grep_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
505 niro 532 int grep_main(int argc, char **argv)
506     {
507     FILE *file;
508     int matched;
509     llist_t *fopt = NULL;
510    
511     /* do normal option parsing */
512     #if ENABLE_FEATURE_GREP_CONTEXT
513 niro 816 int Copt;
514 niro 532
515 niro 816 /* -H unsets -h; -C unsets -A,-B; -e,-f are lists;
516     * -m,-A,-B,-C have numeric param */
517     opt_complementary = "H-h:C-AB:e::f::m+:A+:B+:C+";
518     getopt32(argv,
519     OPTSTR_GREP,
520     &pattern_head, &fopt, &max_matches,
521     &lines_after, &lines_before, &Copt);
522 niro 532
523 niro 816 if (option_mask32 & OPT_C) {
524 niro 532 /* -C unsets prev -A and -B, but following -A or -B
525     may override it */
526 niro 816 if (!(option_mask32 & OPT_A)) /* not overridden */
527     lines_after = Copt;
528     if (!(option_mask32 & OPT_B)) /* not overridden */
529     lines_before = Copt;
530 niro 532 }
531     /* sanity checks */
532 niro 816 if (option_mask32 & (OPT_c|OPT_q|OPT_l|OPT_L)) {
533     option_mask32 &= ~OPT_n;
534 niro 532 lines_before = 0;
535     lines_after = 0;
536 niro 816 } else if (lines_before > 0) {
537     before_buf = xzalloc(lines_before * sizeof(before_buf[0]));
538     USE_EXTRA_COMPAT(before_buf_size = xzalloc(lines_before * sizeof(before_buf_size[0]));)
539     }
540 niro 532 #else
541     /* with auto sanity checks */
542 niro 816 /* -H unsets -h; -c,-q or -l unset -n; -e,-f are lists; -m N */
543     opt_complementary = "H-h:c-n:q-n:l-n:e::f::m+";
544     getopt32(argv, OPTSTR_GREP,
545     &pattern_head, &fopt, &max_matches);
546 niro 532 #endif
547 niro 816 invert_search = ((option_mask32 & OPT_v) != 0); /* 0 | 1 */
548 niro 532
549     if (pattern_head != NULL) {
550 niro 816 /* convert char **argv to grep_list_data_t */
551 niro 532 llist_t *cur;
552    
553     for (cur = pattern_head; cur; cur = cur->link)
554     cur->data = new_grep_list_data(cur->data, 0);
555     }
556 niro 816 if (option_mask32 & OPT_f)
557 niro 532 load_regexes_from_file(fopt);
558    
559     if (ENABLE_FEATURE_GREP_FGREP_ALIAS && applet_name[0] == 'f')
560 niro 816 option_mask32 |= OPT_F;
561 niro 532
562 niro 816 #if !ENABLE_EXTRA_COMPAT
563     if (!(option_mask32 & (OPT_o | OPT_w)))
564 niro 532 reflags = REG_NOSUB;
565 niro 816 #endif
566 niro 532
567 niro 816 if (ENABLE_FEATURE_GREP_EGREP_ALIAS
568     && (applet_name[0] == 'e' || (option_mask32 & OPT_E))
569     ) {
570 niro 532 reflags |= REG_EXTENDED;
571 niro 816 }
572     #if ENABLE_EXTRA_COMPAT
573     else {
574     reflags = RE_SYNTAX_GREP;
575     }
576     #endif
577 niro 532
578 niro 816 if (option_mask32 & OPT_i) {
579     #if !ENABLE_EXTRA_COMPAT
580 niro 532 reflags |= REG_ICASE;
581 niro 816 #else
582     int i;
583     case_fold = xmalloc(256);
584     for (i = 0; i < 256; i++)
585     case_fold[i] = (unsigned char)i;
586     for (i = 'a'; i <= 'z'; i++)
587     case_fold[i] = (unsigned char)(i - ('a' - 'A'));
588     #endif
589     }
590 niro 532
591     argv += optind;
592     argc -= optind;
593    
594 niro 816 /* if we didn't get a pattern from -e and no command file was specified,
595     * first parameter should be the pattern. no pattern, no worky */
596 niro 532 if (pattern_head == NULL) {
597 niro 816 char *pattern;
598 niro 532 if (*argv == NULL)
599     bb_show_usage();
600 niro 816 pattern = new_grep_list_data(*argv++, 0);
601     llist_add_to(&pattern_head, pattern);
602     argc--;
603 niro 532 }
604    
605 niro 816 /* argv[0..(argc-1)] should be names of file to grep through. If
606 niro 532 * there is more than one file to grep, we will print the filenames. */
607     if (argc > 1)
608     print_filename = 1;
609     /* -H / -h of course override */
610 niro 816 if (option_mask32 & OPT_H)
611 niro 532 print_filename = 1;
612 niro 816 if (option_mask32 & OPT_h)
613 niro 532 print_filename = 0;
614    
615     /* If no files were specified, or '-' was specified, take input from
616     * stdin. Otherwise, we grep through all the files specified. */
617     matched = 0;
618 niro 816 do {
619 niro 532 cur_file = *argv++;
620     file = stdin;
621 niro 816 if (!cur_file || LONE_DASH(cur_file)) {
622 niro 532 cur_file = "(standard input)";
623     } else {
624 niro 816 if (option_mask32 & OPT_r) {
625 niro 532 struct stat st;
626     if (stat(cur_file, &st) == 0 && S_ISDIR(st.st_mode)) {
627 niro 816 if (!(option_mask32 & OPT_h))
628 niro 532 print_filename = 1;
629     matched += grep_dir(cur_file);
630     goto grep_done;
631     }
632     }
633     /* else: fopen(dir) will succeed, but reading won't */
634 niro 816 file = fopen_for_read(cur_file);
635 niro 532 if (file == NULL) {
636     if (!SUPPRESS_ERR_MSGS)
637 niro 816 bb_simple_perror_msg(cur_file);
638 niro 532 open_errors = 1;
639     continue;
640     }
641     }
642     matched += grep_file(file);
643     fclose_if_not_stdin(file);
644 niro 816 grep_done: ;
645     } while (--argc > 0);
646 niro 532
647     /* destroy all the elments in the pattern list */
648     if (ENABLE_FEATURE_CLEAN_UP) {
649     while (pattern_head) {
650     llist_t *pattern_head_ptr = pattern_head;
651 niro 816 grep_list_data_t *gl = (grep_list_data_t *)pattern_head_ptr->data;
652 niro 532
653     pattern_head = pattern_head->link;
654 niro 816 if (gl->flg_mem_alocated_compiled & ALLOCATED)
655 niro 532 free(gl->pattern);
656 niro 816 if (gl->flg_mem_alocated_compiled & COMPILED)
657     regfree(&gl->compiled_regex);
658     free(gl);
659 niro 532 free(pattern_head_ptr);
660     }
661     }
662     /* 0 = success, 1 = failed, 2 = error */
663     if (open_errors)
664     return 2;
665 niro 816 return !matched; /* invert return value: 0 = success, 1 = failed */
666 niro 532 }