diff options
Diffstat (limited to 'builtin-grep.c')
-rw-r--r-- | builtin-grep.c | 66 |
1 files changed, 66 insertions, 0 deletions
diff --git a/builtin-grep.c b/builtin-grep.c index 2124fa62e8..c89ee33a1e 100644 --- a/builtin-grep.c +++ b/builtin-grep.c @@ -93,8 +93,13 @@ struct grep_opt { unsigned linenum:1; unsigned invert:1; unsigned name_only:1; + unsigned unmatch_name_only:1; unsigned count:1; unsigned word_regexp:1; +#define GREP_BINARY_DEFAULT 0 +#define GREP_BINARY_NOMATCH 1 +#define GREP_BINARY_TEXT 2 + unsigned binary:2; int regflags; unsigned pre_context; unsigned post_context; @@ -148,6 +153,19 @@ static void show_line(struct grep_opt *opt, const char *bol, const char *eol, printf("%.*s\n", (int)(eol-bol), bol); } +/* + * NEEDSWORK: share code with diff.c + */ +#define FIRST_FEW_BYTES 8000 +static int buffer_is_binary(const char *ptr, unsigned long size) +{ + if (FIRST_FEW_BYTES < size) + size = FIRST_FEW_BYTES; + if (memchr(ptr, 0, size)) + return 1; + return 0; +} + static int grep_buffer(struct grep_opt *opt, const char *name, char *buf, unsigned long size) { @@ -160,9 +178,23 @@ static int grep_buffer(struct grep_opt *opt, const char *name, } *prev = NULL, *pcl; unsigned last_hit = 0; unsigned last_shown = 0; + int binary_match_only = 0; const char *hunk_mark = ""; unsigned count = 0; + if (buffer_is_binary(buf, size)) { + switch (opt->binary) { + case GREP_BINARY_DEFAULT: + binary_match_only = 1; + break; + case GREP_BINARY_NOMATCH: + return 0; /* Assume unmatch */ + break; + default: + break; + } + } + if (opt->pre_context) prev = xcalloc(opt->pre_context, sizeof(*prev)); if (opt->pre_context || opt->post_context) @@ -210,8 +242,17 @@ static int grep_buffer(struct grep_opt *opt, const char *name, */ if (opt->invert) hit = !hit; + if (opt->unmatch_name_only) { + if (hit) + return 0; + goto next_line; + } if (hit) { count++; + if (binary_match_only) { + printf("Binary file %s matches\n", name); + return 1; + } if (opt->name_only) { printf("%s\n", name); return 1; @@ -262,11 +303,22 @@ static int grep_buffer(struct grep_opt *opt, const char *name, prev->bol = bol; prev->eol = eol; } + + next_line: *eol = ch; bol = eol + 1; + if (!left) + break; left--; lno++; } + + if (opt->unmatch_name_only) { + /* We did not see any hit, so we want to show this */ + printf("%s\n", name); + return 1; + } + /* NEEDSWORK: * The real "grep -c foo *.c" gives many "bar.c:0" lines, * which feels mostly useless but sometimes useful. Maybe @@ -451,11 +503,20 @@ int cmd_grep(int argc, const char **argv, char **envp) cached = 1; continue; } + if (!strcmp("-a", arg) || + !strcmp("--text", arg)) { + opt.binary = GREP_BINARY_TEXT; + continue; + } if (!strcmp("-i", arg) || !strcmp("--ignore-case", arg)) { opt.regflags |= REG_ICASE; continue; } + if (!strcmp("-I", arg)) { + opt.binary = GREP_BINARY_NOMATCH; + continue; + } if (!strcmp("-v", arg) || !strcmp("--invert-match", arg)) { opt.invert = 1; @@ -486,6 +547,11 @@ int cmd_grep(int argc, const char **argv, char **envp) opt.name_only = 1; continue; } + if (!strcmp("-L", arg) || + !strcmp("--files-without-match", arg)) { + opt.unmatch_name_only = 1; + continue; + } if (!strcmp("-c", arg) || !strcmp("--count", arg)) { opt.count = 1; |