aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--findutils/grep.c83
-rw-r--r--include/usage.h5
2 files changed, 49 insertions, 39 deletions
diff --git a/findutils/grep.c b/findutils/grep.c
index 7bade87cb..e543ee07f 100644
--- a/findutils/grep.c
+++ b/findutils/grep.c
@@ -24,7 +24,7 @@
24 24
25/* options */ 25/* options */
26#define OPTSTR_GREP \ 26#define OPTSTR_GREP \
27 "lnqvscFiHhe:f:Lor" \ 27 "lnqvscFiHhe:f:Lorm:" \
28 USE_FEATURE_GREP_CONTEXT("A:B:C:") \ 28 USE_FEATURE_GREP_CONTEXT("A:B:C:") \
29 USE_FEATURE_GREP_EGREP_ALIAS("E") \ 29 USE_FEATURE_GREP_EGREP_ALIAS("E") \
30 USE_DESKTOP("w") \ 30 USE_DESKTOP("w") \
@@ -33,26 +33,27 @@
33/* ignored: -I "assume binary files have no matches" */ 33/* ignored: -I "assume binary files have no matches" */
34 34
35enum { 35enum {
36 OPTBIT_l, 36 OPTBIT_l, /* list matched file names only */
37 OPTBIT_n, 37 OPTBIT_n, /* print line# */
38 OPTBIT_q, 38 OPTBIT_q, /* quiet - exit(0) of first match */
39 OPTBIT_v, 39 OPTBIT_v, /* invert the match, to select non-matching lines */
40 OPTBIT_s, 40 OPTBIT_s, /* suppress errors about file open errors */
41 OPTBIT_c, 41 OPTBIT_c, /* count matches per file (suppresses normal output) */
42 OPTBIT_F, 42 OPTBIT_F, /* literal match */
43 OPTBIT_i, 43 OPTBIT_i, /* case-insensitive */
44 OPTBIT_H, 44 OPTBIT_H, /* force filename display */
45 OPTBIT_h, 45 OPTBIT_h, /* inhibit filename display */
46 OPTBIT_e, 46 OPTBIT_e, /* -e PATTERN */
47 OPTBIT_f, 47 OPTBIT_f, /* -f FILE_WITH_PATTERNS */
48 OPTBIT_L, 48 OPTBIT_L, /* list unmatched file names only */
49 OPTBIT_o, 49 OPTBIT_o, /* show only matching parts of lines */
50 OPTBIT_r, 50 OPTBIT_r, /* recurse dirs */
51 USE_FEATURE_GREP_CONTEXT( OPTBIT_A ,) 51 OPTBIT_m, /* -m MAX_MATCHES */
52 USE_FEATURE_GREP_CONTEXT( OPTBIT_B ,) 52 USE_FEATURE_GREP_CONTEXT( OPTBIT_A ,) /* -A NUM: after-match context */
53 USE_FEATURE_GREP_CONTEXT( OPTBIT_C ,) 53 USE_FEATURE_GREP_CONTEXT( OPTBIT_B ,) /* -B NUM: before-match context */
54 USE_FEATURE_GREP_EGREP_ALIAS(OPTBIT_E ,) 54 USE_FEATURE_GREP_CONTEXT( OPTBIT_C ,) /* -C NUM: -A and -B combined */
55 USE_DESKTOP( OPTBIT_w ,) 55 USE_FEATURE_GREP_EGREP_ALIAS(OPTBIT_E ,) /* extended regexp */
56 USE_DESKTOP( OPTBIT_w ,) /* whole word match */
56 OPT_l = 1 << OPTBIT_l, 57 OPT_l = 1 << OPTBIT_l,
57 OPT_n = 1 << OPTBIT_n, 58 OPT_n = 1 << OPTBIT_n,
58 OPT_q = 1 << OPTBIT_q, 59 OPT_q = 1 << OPTBIT_q,
@@ -68,6 +69,7 @@ enum {
68 OPT_L = 1 << OPTBIT_L, 69 OPT_L = 1 << OPTBIT_L,
69 OPT_o = 1 << OPTBIT_o, 70 OPT_o = 1 << OPTBIT_o,
70 OPT_r = 1 << OPTBIT_r, 71 OPT_r = 1 << OPTBIT_r,
72 OPT_m = 1 << OPTBIT_m,
71 OPT_A = USE_FEATURE_GREP_CONTEXT( (1 << OPTBIT_A)) + 0, 73 OPT_A = USE_FEATURE_GREP_CONTEXT( (1 << OPTBIT_A)) + 0,
72 OPT_B = USE_FEATURE_GREP_CONTEXT( (1 << OPTBIT_B)) + 0, 74 OPT_B = USE_FEATURE_GREP_CONTEXT( (1 << OPTBIT_B)) + 0,
73 OPT_C = USE_FEATURE_GREP_CONTEXT( (1 << OPTBIT_C)) + 0, 75 OPT_C = USE_FEATURE_GREP_CONTEXT( (1 << OPTBIT_C)) + 0,
@@ -85,6 +87,7 @@ enum {
85 87
86typedef unsigned char byte_t; 88typedef unsigned char byte_t;
87 89
90static int max_matches;
88static int reflags; 91static int reflags;
89static byte_t invert_search; 92static byte_t invert_search;
90static byte_t print_filename; 93static byte_t print_filename;
@@ -97,7 +100,6 @@ static int lines_after;
97static char **before_buf; 100static char **before_buf;
98static int last_line_printed; 101static int last_line_printed;
99#endif /* ENABLE_FEATURE_GREP_CONTEXT */ 102#endif /* ENABLE_FEATURE_GREP_CONTEXT */
100
101/* globals used internally */ 103/* globals used internally */
102static llist_t *pattern_head; /* growable list of patterns to match */ 104static llist_t *pattern_head; /* growable list of patterns to match */
103static const char *cur_file; /* the current file we are reading */ 105static const char *cur_file; /* the current file we are reading */
@@ -146,6 +148,8 @@ static int grep_file(FILE *file)
146 int print_n_lines_after = 0; 148 int print_n_lines_after = 0;
147 int curpos = 0; /* track where we are in the circular 'before' buffer */ 149 int curpos = 0; /* track where we are in the circular 'before' buffer */
148 int idx = 0; /* used for iteration through the circular buffer */ 150 int idx = 0; /* used for iteration through the circular buffer */
151#else
152 enum { print_n_lines_after = 0 };
149#endif /* ENABLE_FEATURE_GREP_CONTEXT */ 153#endif /* ENABLE_FEATURE_GREP_CONTEXT */
150 154
151 while ((line = xmalloc_getline(file)) != NULL) { 155 while ((line = xmalloc_getline(file)) != NULL) {
@@ -212,6 +216,12 @@ static int grep_file(FILE *file)
212 return 1; /* one match */ 216 return 1; /* one match */
213 } 217 }
214 218
219#if ENABLE_FEATURE_GREP_CONTEXT
220 /* Were we printing context and saw next (unwanted) match? */
221 if ((option_mask32 & OPT_m) && nmatches > max_matches)
222 break;
223#endif
224
215 /* print the matched line */ 225 /* print the matched line */
216 if (PRINT_MATCH_COUNTS == 0) { 226 if (PRINT_MATCH_COUNTS == 0) {
217#if ENABLE_FEATURE_GREP_CONTEXT 227#if ENABLE_FEATURE_GREP_CONTEXT
@@ -255,7 +265,7 @@ static int grep_file(FILE *file)
255#if ENABLE_FEATURE_GREP_CONTEXT 265#if ENABLE_FEATURE_GREP_CONTEXT
256 else { /* no match */ 266 else { /* no match */
257 /* if we need to print some context lines after the last match, do so */ 267 /* if we need to print some context lines after the last match, do so */
258 if (print_n_lines_after /* && (last_line_printed != linenum) */ ) { 268 if (print_n_lines_after) {
259 print_line(line, linenum, '-'); 269 print_line(line, linenum, '-');
260 print_n_lines_after--; 270 print_n_lines_after--;
261 } else if (lines_before) { 271 } else if (lines_before) {
@@ -264,12 +274,17 @@ static int grep_file(FILE *file)
264 before_buf[curpos] = line; 274 before_buf[curpos] = line;
265 curpos = (curpos + 1) % lines_before; 275 curpos = (curpos + 1) % lines_before;
266 /* avoid free(line) - we took line */ 276 /* avoid free(line) - we took line */
267 continue; 277 line = NULL;
268 } 278 }
269 } 279 }
270 280
271#endif /* ENABLE_FEATURE_GREP_CONTEXT */ 281#endif /* ENABLE_FEATURE_GREP_CONTEXT */
272 free(line); 282 free(line);
283
284 /* Did we print all context after last requested match? */
285 if ((option_mask32 & OPT_m)
286 && !print_n_lines_after && nmatches == max_matches)
287 break;
273 } 288 }
274 289
275 /* special-case file post-processing for options where we don't print line 290 /* special-case file post-processing for options where we don't print line
@@ -311,7 +326,6 @@ static char * add_grep_list_data(char *pattern)
311 return (char *)gl; 326 return (char *)gl;
312} 327}
313 328
314
315static void load_regexes_from_file(llist_t *fopt) 329static void load_regexes_from_file(llist_t *fopt)
316{ 330{
317 char *line; 331 char *line;
@@ -365,6 +379,7 @@ int grep_main(int argc, char **argv)
365{ 379{
366 FILE *file; 380 FILE *file;
367 int matched; 381 int matched;
382 char *mopt;
368 llist_t *fopt = NULL; 383 llist_t *fopt = NULL;
369 384
370 /* do normal option parsing */ 385 /* do normal option parsing */
@@ -376,7 +391,7 @@ int grep_main(int argc, char **argv)
376 opt_complementary = "H-h:e::f::C-AB"; 391 opt_complementary = "H-h:e::f::C-AB";
377 getopt32(argc, argv, 392 getopt32(argc, argv,
378 OPTSTR_GREP, 393 OPTSTR_GREP,
379 &pattern_head, &fopt, 394 &pattern_head, &fopt, &mopt,
380 &slines_after, &slines_before, &Copt); 395 &slines_after, &slines_before, &Copt);
381 396
382 if (option_mask32 & OPT_C) { 397 if (option_mask32 & OPT_C) {
@@ -405,8 +420,11 @@ int grep_main(int argc, char **argv)
405 /* with auto sanity checks */ 420 /* with auto sanity checks */
406 opt_complementary = "H-h:e::f::c-n:q-n:l-n"; 421 opt_complementary = "H-h:e::f::c-n:q-n:l-n";
407 getopt32(argc, argv, OPTSTR_GREP, 422 getopt32(argc, argv, OPTSTR_GREP,
408 &pattern_head, &fopt); 423 &pattern_head, &fopt, &mopt);
409#endif 424#endif
425 if (option_mask32 & OPT_m) {
426 max_matches = xatoi_u(mopt);
427 }
410 invert_search = ((option_mask32 & OPT_v) != 0); /* 0 | 1 */ 428 invert_search = ((option_mask32 & OPT_v) != 0); /* 0 | 1 */
411 429
412 if (pattern_head != NULL) { 430 if (pattern_head != NULL) {
@@ -487,12 +505,7 @@ int grep_main(int argc, char **argv)
487 } 505 }
488 matched += grep_file(file); 506 matched += grep_file(file);
489 fclose_if_not_stdin(file); 507 fclose_if_not_stdin(file);
490 grep_done: 508 grep_done: ;
491 if (matched < 0) {
492 /* we found a match but were told to be quiet, stop here and
493 * return success */
494 break;
495 }
496 } 509 }
497 510
498 /* destroy all the elments in the pattern list */ 511 /* destroy all the elments in the pattern list */
@@ -512,10 +525,6 @@ int grep_main(int argc, char **argv)
512 } 525 }
513 } 526 }
514 /* 0 = success, 1 = failed, 2 = error */ 527 /* 0 = success, 1 = failed, 2 = error */
515 /* If the -q option is specified, the exit status shall be zero
516 * if an input line is selected, even if an error was detected. */
517 if (BE_QUIET && matched)
518 return 0;
519 if (open_errors) 528 if (open_errors)
520 return 2; 529 return 2;
521 return !matched; /* invert return value 0 = success, 1 = failed */ 530 return !matched; /* invert return value 0 = success, 1 = failed */
diff --git a/include/usage.h b/include/usage.h
index 68325046f..bd9cb9908 100644
--- a/include/usage.h
+++ b/include/usage.h
@@ -1164,14 +1164,15 @@
1164 "\n -v Select non-matching lines" \ 1164 "\n -v Select non-matching lines" \
1165 "\n -s Suppress file open/read error messages" \ 1165 "\n -s Suppress file open/read error messages" \
1166 "\n -c Only print count of matching lines" \ 1166 "\n -c Only print count of matching lines" \
1167 "\n -f Read PATTERN from file" \
1168 "\n -o Show only the part of a line that matches PATTERN" \ 1167 "\n -o Show only the part of a line that matches PATTERN" \
1168 "\n -m MAX Match up to MAX times per file" \
1169 USE_DESKTOP( \ 1169 USE_DESKTOP( \
1170 "\n -w Match whole words only") \ 1170 "\n -w Match whole words only") \
1171 "\n -e PATTERN is a regular expression" \
1172 "\n -F PATTERN is a set of newline-separated strings" \ 1171 "\n -F PATTERN is a set of newline-separated strings" \
1173 USE_FEATURE_GREP_EGREP_ALIAS( \ 1172 USE_FEATURE_GREP_EGREP_ALIAS( \
1174 "\n -E PATTERN is an extended regular expression") \ 1173 "\n -E PATTERN is an extended regular expression") \
1174 "\n -e PTRN Pattern to match" \
1175 "\n -f FILE Read pattern from file" \
1175 USE_FEATURE_GREP_CONTEXT( \ 1176 USE_FEATURE_GREP_CONTEXT( \
1176 "\n -A Print NUM lines of trailing context" \ 1177 "\n -A Print NUM lines of trailing context" \
1177 "\n -B Print NUM lines of leading context" \ 1178 "\n -B Print NUM lines of leading context" \