25 |
/* options */ |
/* options */ |
26 |
#define OPTSTR_GREP \ |
#define OPTSTR_GREP \ |
27 |
"lnqvscFiHhe:f:Lorm:" \ |
"lnqvscFiHhe:f:Lorm:" \ |
28 |
USE_FEATURE_GREP_CONTEXT("A:B:C:") \ |
IF_FEATURE_GREP_CONTEXT("A:B:C:") \ |
29 |
USE_FEATURE_GREP_EGREP_ALIAS("E") \ |
IF_FEATURE_GREP_EGREP_ALIAS("E") \ |
30 |
USE_DESKTOP("w") \ |
IF_DESKTOP("w") \ |
31 |
|
IF_EXTRA_COMPAT("z") \ |
32 |
"aI" |
"aI" |
33 |
|
|
34 |
/* ignored: -a "assume all files to be text" */ |
/* ignored: -a "assume all files to be text" */ |
35 |
/* ignored: -I "assume binary files have no matches" */ |
/* ignored: -I "assume binary files have no matches" */ |
36 |
|
|
51 |
OPTBIT_o, /* show only matching parts of lines */ |
OPTBIT_o, /* show only matching parts of lines */ |
52 |
OPTBIT_r, /* recurse dirs */ |
OPTBIT_r, /* recurse dirs */ |
53 |
OPTBIT_m, /* -m MAX_MATCHES */ |
OPTBIT_m, /* -m MAX_MATCHES */ |
54 |
USE_FEATURE_GREP_CONTEXT( OPTBIT_A ,) /* -A NUM: after-match context */ |
IF_FEATURE_GREP_CONTEXT( OPTBIT_A ,) /* -A NUM: after-match context */ |
55 |
USE_FEATURE_GREP_CONTEXT( OPTBIT_B ,) /* -B NUM: before-match context */ |
IF_FEATURE_GREP_CONTEXT( OPTBIT_B ,) /* -B NUM: before-match context */ |
56 |
USE_FEATURE_GREP_CONTEXT( OPTBIT_C ,) /* -C NUM: -A and -B combined */ |
IF_FEATURE_GREP_CONTEXT( OPTBIT_C ,) /* -C NUM: -A and -B combined */ |
57 |
USE_FEATURE_GREP_EGREP_ALIAS(OPTBIT_E ,) /* extended regexp */ |
IF_FEATURE_GREP_EGREP_ALIAS(OPTBIT_E ,) /* extended regexp */ |
58 |
USE_DESKTOP( OPTBIT_w ,) /* whole word match */ |
IF_DESKTOP( OPTBIT_w ,) /* whole word match */ |
59 |
|
IF_EXTRA_COMPAT( OPTBIT_z ,) /* input is NUL terminated */ |
60 |
OPT_l = 1 << OPTBIT_l, |
OPT_l = 1 << OPTBIT_l, |
61 |
OPT_n = 1 << OPTBIT_n, |
OPT_n = 1 << OPTBIT_n, |
62 |
OPT_q = 1 << OPTBIT_q, |
OPT_q = 1 << OPTBIT_q, |
73 |
OPT_o = 1 << OPTBIT_o, |
OPT_o = 1 << OPTBIT_o, |
74 |
OPT_r = 1 << OPTBIT_r, |
OPT_r = 1 << OPTBIT_r, |
75 |
OPT_m = 1 << OPTBIT_m, |
OPT_m = 1 << OPTBIT_m, |
76 |
OPT_A = USE_FEATURE_GREP_CONTEXT( (1 << OPTBIT_A)) + 0, |
OPT_A = IF_FEATURE_GREP_CONTEXT( (1 << OPTBIT_A)) + 0, |
77 |
OPT_B = USE_FEATURE_GREP_CONTEXT( (1 << OPTBIT_B)) + 0, |
OPT_B = IF_FEATURE_GREP_CONTEXT( (1 << OPTBIT_B)) + 0, |
78 |
OPT_C = USE_FEATURE_GREP_CONTEXT( (1 << OPTBIT_C)) + 0, |
OPT_C = IF_FEATURE_GREP_CONTEXT( (1 << OPTBIT_C)) + 0, |
79 |
OPT_E = USE_FEATURE_GREP_EGREP_ALIAS((1 << OPTBIT_E)) + 0, |
OPT_E = IF_FEATURE_GREP_EGREP_ALIAS((1 << OPTBIT_E)) + 0, |
80 |
OPT_w = USE_DESKTOP( (1 << OPTBIT_w)) + 0, |
OPT_w = IF_DESKTOP( (1 << OPTBIT_w)) + 0, |
81 |
|
OPT_z = IF_EXTRA_COMPAT( (1 << OPTBIT_z)) + 0, |
82 |
}; |
}; |
83 |
|
|
84 |
#define PRINT_FILES_WITH_MATCHES (option_mask32 & OPT_l) |
#define PRINT_FILES_WITH_MATCHES (option_mask32 & OPT_l) |
88 |
#define PRINT_MATCH_COUNTS (option_mask32 & OPT_c) |
#define PRINT_MATCH_COUNTS (option_mask32 & OPT_c) |
89 |
#define FGREP_FLAG (option_mask32 & OPT_F) |
#define FGREP_FLAG (option_mask32 & OPT_F) |
90 |
#define PRINT_FILES_WITHOUT_MATCHES (option_mask32 & OPT_L) |
#define PRINT_FILES_WITHOUT_MATCHES (option_mask32 & OPT_L) |
91 |
|
#define NUL_DELIMITED (option_mask32 & OPT_z) |
92 |
|
|
93 |
struct globals { |
struct globals { |
94 |
int max_matches; |
int max_matches; |
105 |
int lines_before; |
int lines_before; |
106 |
int lines_after; |
int lines_after; |
107 |
char **before_buf; |
char **before_buf; |
108 |
USE_EXTRA_COMPAT(size_t *before_buf_size;) |
IF_EXTRA_COMPAT(size_t *before_buf_size;) |
109 |
int last_line_printed; |
int last_line_printed; |
110 |
#endif |
#endif |
111 |
/* globals used internally */ |
/* globals used internally */ |
120 |
} while (0) |
} while (0) |
121 |
#define max_matches (G.max_matches ) |
#define max_matches (G.max_matches ) |
122 |
#if !ENABLE_EXTRA_COMPAT |
#if !ENABLE_EXTRA_COMPAT |
123 |
#define reflags (G.reflags ) |
# define reflags (G.reflags ) |
124 |
#else |
#else |
125 |
#define case_fold (G.case_fold ) |
# define case_fold (G.case_fold ) |
126 |
/* http://www.delorie.com/gnu/docs/regex/regex_46.html */ |
/* http://www.delorie.com/gnu/docs/regex/regex_46.html */ |
127 |
#define reflags re_syntax_options |
# define reflags re_syntax_options |
128 |
#undef REG_NOSUB |
# undef REG_NOSUB |
129 |
#undef REG_EXTENDED |
# undef REG_EXTENDED |
130 |
#undef REG_ICASE |
# undef REG_ICASE |
131 |
#define REG_NOSUB bug:is:here /* should not be used */ |
# define REG_NOSUB bug:is:here /* should not be used */ |
132 |
#define REG_EXTENDED RE_SYNTAX_EGREP |
/* Just RE_SYNTAX_EGREP is not enough, need to enable {n[,[m]]} too */ |
133 |
#define REG_ICASE bug:is:here /* should not be used */ |
# define REG_EXTENDED (RE_SYNTAX_EGREP | RE_INTERVALS | RE_NO_BK_BRACES) |
134 |
|
# define REG_ICASE bug:is:here /* should not be used */ |
135 |
#endif |
#endif |
136 |
#define invert_search (G.invert_search ) |
#define invert_search (G.invert_search ) |
137 |
#define print_filename (G.print_filename ) |
#define print_filename (G.print_filename ) |
192 |
puts(line); |
puts(line); |
193 |
#else |
#else |
194 |
fwrite(line, 1, line_len, stdout); |
fwrite(line, 1, line_len, stdout); |
195 |
putchar('\n'); |
putchar(NUL_DELIMITED ? '\0' : '\n'); |
196 |
#endif |
#endif |
197 |
} |
} |
198 |
} |
} |
203 |
{ |
{ |
204 |
ssize_t res_sz; |
ssize_t res_sz; |
205 |
char *line; |
char *line; |
206 |
|
int delim = (NUL_DELIMITED ? '\0' : '\n'); |
207 |
|
|
208 |
res_sz = getline(line_ptr, line_alloc_len, file); |
res_sz = getdelim(line_ptr, line_alloc_len, delim, file); |
209 |
line = *line_ptr; |
line = *line_ptr; |
210 |
|
|
211 |
if (res_sz > 0) { |
if (res_sz > 0) { |
212 |
if (line[res_sz - 1] == '\n') |
if (line[res_sz - 1] == delim) |
213 |
line[--res_sz] = '\0'; |
line[--res_sz] = '\0'; |
214 |
} else { |
} else { |
215 |
free(line); /* uclibc allocates a buffer even on EOF. WTF? */ |
free(line); /* uclibc allocates a buffer even on EOF. WTF? */ |
229 |
char *line = NULL; |
char *line = NULL; |
230 |
ssize_t line_len; |
ssize_t line_len; |
231 |
size_t line_alloc_len; |
size_t line_alloc_len; |
232 |
#define rm_so start[0] |
# define rm_so start[0] |
233 |
#define rm_eo end[0] |
# define rm_eo end[0] |
234 |
#endif |
#endif |
235 |
#if ENABLE_FEATURE_GREP_CONTEXT |
#if ENABLE_FEATURE_GREP_CONTEXT |
236 |
int print_n_lines_after = 0; |
int print_n_lines_after = 0; |
238 |
int idx = 0; /* used for iteration through the circular buffer */ |
int idx = 0; /* used for iteration through the circular buffer */ |
239 |
#else |
#else |
240 |
enum { print_n_lines_after = 0 }; |
enum { print_n_lines_after = 0 }; |
241 |
#endif /* ENABLE_FEATURE_GREP_CONTEXT */ |
#endif |
242 |
|
|
243 |
while ( |
while ( |
244 |
#if !ENABLE_EXTRA_COMPAT |
#if !ENABLE_EXTRA_COMPAT |
371 |
if (found) |
if (found) |
372 |
print_line(gl->pattern, strlen(gl->pattern), linenum, ':'); |
print_line(gl->pattern, strlen(gl->pattern), linenum, ':'); |
373 |
} else while (1) { |
} else while (1) { |
374 |
char old = line[gl->matched_range.rm_eo]; |
unsigned end = gl->matched_range.rm_eo; |
375 |
line[gl->matched_range.rm_eo] = '\0'; |
char old = line[end]; |
376 |
|
line[end] = '\0'; |
377 |
print_line(line + gl->matched_range.rm_so, |
print_line(line + gl->matched_range.rm_so, |
378 |
gl->matched_range.rm_eo - gl->matched_range.rm_so, |
end - gl->matched_range.rm_so, |
379 |
linenum, ':'); |
linenum, ':'); |
380 |
line[gl->matched_range.rm_eo] = old; |
if (old == '\0') |
381 |
|
break; |
382 |
|
line[end] = old; |
383 |
#if !ENABLE_EXTRA_COMPAT |
#if !ENABLE_EXTRA_COMPAT |
384 |
break; |
if (regexec(&gl->compiled_regex, line + end, |
385 |
|
1, &gl->matched_range, REG_NOTBOL) != 0) |
386 |
|
break; |
387 |
|
gl->matched_range.rm_so += end; |
388 |
|
gl->matched_range.rm_eo += end; |
389 |
#else |
#else |
390 |
if (re_search(&gl->compiled_regex, line, line_len, |
if (re_search(&gl->compiled_regex, line, line_len, |
391 |
gl->matched_range.rm_eo, line_len - gl->matched_range.rm_eo, |
end, line_len - end, |
392 |
&gl->matched_range) < 0) |
&gl->matched_range) < 0) |
393 |
break; |
break; |
394 |
#endif |
#endif |
395 |
} |
} |
396 |
} else { |
} else { |
397 |
print_line(line, line_len, linenum, ':'); |
print_line(line, line_len, linenum, ':'); |
398 |
} |
} |
408 |
/* Add the line to the circular 'before' buffer */ |
/* Add the line to the circular 'before' buffer */ |
409 |
free(before_buf[curpos]); |
free(before_buf[curpos]); |
410 |
before_buf[curpos] = line; |
before_buf[curpos] = line; |
411 |
USE_EXTRA_COMPAT(before_buf_size[curpos] = line_len;) |
IF_EXTRA_COMPAT(before_buf_size[curpos] = line_len;) |
412 |
curpos = (curpos + 1) % lines_before; |
curpos = (curpos + 1) % lines_before; |
413 |
/* avoid free(line) - we took the line */ |
/* avoid free(line) - we took the line */ |
414 |
line = NULL; |
line = NULL; |
421 |
#endif |
#endif |
422 |
/* Did we print all context after last requested match? */ |
/* Did we print all context after last requested match? */ |
423 |
if ((option_mask32 & OPT_m) |
if ((option_mask32 & OPT_m) |
424 |
&& !print_n_lines_after && nmatches == max_matches) |
&& !print_n_lines_after |
425 |
|
&& nmatches == max_matches |
426 |
|
) { |
427 |
break; |
break; |
428 |
|
} |
429 |
} /* while (read line) */ |
} /* while (read line) */ |
430 |
|
|
431 |
/* special-case file post-processing for options where we don't print line |
/* special-case file post-processing for options where we don't print line |
519 |
} |
} |
520 |
|
|
521 |
int grep_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
int grep_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
522 |
int grep_main(int argc, char **argv) |
int grep_main(int argc UNUSED_PARAM, char **argv) |
523 |
{ |
{ |
524 |
FILE *file; |
FILE *file; |
525 |
int matched; |
int matched; |
552 |
lines_after = 0; |
lines_after = 0; |
553 |
} else if (lines_before > 0) { |
} else if (lines_before > 0) { |
554 |
before_buf = xzalloc(lines_before * sizeof(before_buf[0])); |
before_buf = xzalloc(lines_before * sizeof(before_buf[0])); |
555 |
USE_EXTRA_COMPAT(before_buf_size = xzalloc(lines_before * sizeof(before_buf_size[0]));) |
IF_EXTRA_COMPAT(before_buf_size = xzalloc(lines_before * sizeof(before_buf_size[0]));) |
556 |
} |
} |
557 |
#else |
#else |
558 |
/* with auto sanity checks */ |
/* with auto sanity checks */ |
606 |
} |
} |
607 |
|
|
608 |
argv += optind; |
argv += optind; |
|
argc -= optind; |
|
609 |
|
|
610 |
/* if we didn't get a pattern from -e and no command file was specified, |
/* if we didn't get a pattern from -e and no command file was specified, |
611 |
* first parameter should be the pattern. no pattern, no worky */ |
* first parameter should be the pattern. no pattern, no worky */ |
615 |
bb_show_usage(); |
bb_show_usage(); |
616 |
pattern = new_grep_list_data(*argv++, 0); |
pattern = new_grep_list_data(*argv++, 0); |
617 |
llist_add_to(&pattern_head, pattern); |
llist_add_to(&pattern_head, pattern); |
|
argc--; |
|
618 |
} |
} |
619 |
|
|
620 |
/* argv[0..(argc-1)] should be names of file to grep through. If |
/* argv[0..(argc-1)] should be names of file to grep through. If |
621 |
* 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. */ |
622 |
if (argc > 1) |
if (argv[0] && argv[1]) |
623 |
print_filename = 1; |
print_filename = 1; |
624 |
/* -H / -h of course override */ |
/* -H / -h of course override */ |
625 |
if (option_mask32 & OPT_H) |
if (option_mask32 & OPT_H) |
631 |
* stdin. Otherwise, we grep through all the files specified. */ |
* stdin. Otherwise, we grep through all the files specified. */ |
632 |
matched = 0; |
matched = 0; |
633 |
do { |
do { |
634 |
cur_file = *argv++; |
cur_file = *argv; |
635 |
file = stdin; |
file = stdin; |
636 |
if (!cur_file || LONE_DASH(cur_file)) { |
if (!cur_file || LONE_DASH(cur_file)) { |
637 |
cur_file = "(standard input)"; |
cur_file = "(standard input)"; |
657 |
matched += grep_file(file); |
matched += grep_file(file); |
658 |
fclose_if_not_stdin(file); |
fclose_if_not_stdin(file); |
659 |
grep_done: ; |
grep_done: ; |
660 |
} while (--argc > 0); |
} while (*argv && *++argv); |
661 |
|
|
662 |
/* destroy all the elments in the pattern list */ |
/* destroy all the elments in the pattern list */ |
663 |
if (ENABLE_FEATURE_CLEAN_UP) { |
if (ENABLE_FEATURE_CLEAN_UP) { |