Browse Source

Merge branch 'jc/grep'

* jc/grep:
  teach revision walker about --all-match.
  grep --all-match
maint
Junio C Hamano 19 years ago
parent
commit
9100c9dce1
  1. 11
      Documentation/git-grep.txt
  2. 4
      builtin-grep.c
  3. 114
      grep.c
  4. 2
      grep.h
  5. 9
      revision.c

11
Documentation/git-grep.txt

@ -14,7 +14,7 @@ SYNOPSIS
[-v | --invert-match] [-h|-H] [--full-name] [-v | --invert-match] [-h|-H] [--full-name]
[-E | --extended-regexp] [-G | --basic-regexp] [-F | --fixed-strings] [-E | --extended-regexp] [-G | --basic-regexp] [-F | --fixed-strings]
[-n] [-l | --files-with-matches] [-L | --files-without-match] [-n] [-l | --files-with-matches] [-L | --files-without-match]
[-c | --count] [-c | --count] [--all-match]
[-A <post-context>] [-B <pre-context>] [-C <context>] [-A <post-context>] [-B <pre-context>] [-C <context>]
[-f <file>] [-e] <pattern> [--and|--or|--not|(|)|-e <pattern>...] [-f <file>] [-e] <pattern> [--and|--or|--not|(|)|-e <pattern>...]
[<tree>...] [<tree>...]
@ -96,6 +96,11 @@ OPTIONS
higher precedence than `--or`. `-e` has to be used for all higher precedence than `--or`. `-e` has to be used for all
patterns. patterns.


--all-match::
When giving multiple pattern expressions combined with `--or`,
this flag is specified to limit the match to files that
have lines to match all of them.

`<tree>...`:: `<tree>...`::
Search blobs in the trees for specified patterns. Search blobs in the trees for specified patterns.


@ -111,6 +116,10 @@ git grep -e \'#define\' --and \( -e MAX_PATH -e PATH_MAX \)::
Looks for a line that has `#define` and either `MAX_PATH` or Looks for a line that has `#define` and either `MAX_PATH` or
`PATH_MAX`. `PATH_MAX`.


git grep --all-match -e NODE -e Unexpected::
Looks for a line that has `NODE` or `Unexpected` in
files that have lines that match both.

Author Author
------ ------
Originally written by Linus Torvalds <torvalds@osdl.org>, later Originally written by Linus Torvalds <torvalds@osdl.org>, later

4
builtin-grep.c

@ -596,6 +596,10 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
GREP_CLOSE_PAREN); GREP_CLOSE_PAREN);
continue; continue;
} }
if (!strcmp("--all-match", arg)) {
opt.all_match = 1;
continue;
}
if (!strcmp("-e", arg)) { if (!strcmp("-e", arg)) {
if (1 < argc) { if (1 < argc) {
append_grep_pattern(&opt, argv[1], append_grep_pattern(&opt, argv[1],

114
grep.c

@ -34,7 +34,7 @@ static void compile_regexp(struct grep_pat *p, struct grep_opt *opt)
} }
} }


static struct grep_expr *compile_pattern_expr(struct grep_pat **); static struct grep_expr *compile_pattern_or(struct grep_pat **);
static struct grep_expr *compile_pattern_atom(struct grep_pat **list) static struct grep_expr *compile_pattern_atom(struct grep_pat **list)
{ {
struct grep_pat *p; struct grep_pat *p;
@ -52,7 +52,7 @@ static struct grep_expr *compile_pattern_atom(struct grep_pat **list)
return x; return x;
case GREP_OPEN_PAREN: case GREP_OPEN_PAREN:
*list = p->next; *list = p->next;
x = compile_pattern_expr(list); x = compile_pattern_or(list);
if (!x) if (!x)
return NULL; return NULL;
if (!*list || (*list)->token != GREP_CLOSE_PAREN) if (!*list || (*list)->token != GREP_CLOSE_PAREN)
@ -138,6 +138,9 @@ void compile_grep_patterns(struct grep_opt *opt)
{ {
struct grep_pat *p; struct grep_pat *p;


if (opt->all_match)
opt->extended = 1;

for (p = opt->pattern_list; p; p = p->next) { for (p = opt->pattern_list; p; p = p->next) {
switch (p->token) { switch (p->token) {
case GREP_PATTERN: /* atom */ case GREP_PATTERN: /* atom */
@ -309,40 +312,63 @@ static int match_one_pattern(struct grep_opt *opt, struct grep_pat *p, char *bol
return hit; return hit;
} }


static int match_expr_eval(struct grep_opt *opt, static int match_expr_eval(struct grep_opt *o,
struct grep_expr *x, struct grep_expr *x,
char *bol, char *eol, char *bol, char *eol,
enum grep_context ctx) enum grep_context ctx,
int collect_hits)
{ {
int h = 0;

switch (x->node) { switch (x->node) {
case GREP_NODE_ATOM: case GREP_NODE_ATOM:
return match_one_pattern(opt, x->u.atom, bol, eol, ctx); h = match_one_pattern(o, x->u.atom, bol, eol, ctx);
break; break;
case GREP_NODE_NOT: case GREP_NODE_NOT:
return !match_expr_eval(opt, x->u.unary, bol, eol, ctx); h = !match_expr_eval(o, x->u.unary, bol, eol, ctx, 0);
break;
case GREP_NODE_AND: case GREP_NODE_AND:
return (match_expr_eval(opt, x->u.binary.left, bol, eol, ctx) && if (!collect_hits)
match_expr_eval(opt, x->u.binary.right, bol, eol, ctx)); return (match_expr_eval(o, x->u.binary.left,
bol, eol, ctx, 0) &&
match_expr_eval(o, x->u.binary.right,
bol, eol, ctx, 0));
h = match_expr_eval(o, x->u.binary.left, bol, eol, ctx, 0);
h &= match_expr_eval(o, x->u.binary.right, bol, eol, ctx, 0);
break;
case GREP_NODE_OR: case GREP_NODE_OR:
return (match_expr_eval(opt, x->u.binary.left, bol, eol, ctx) || if (!collect_hits)
match_expr_eval(opt, x->u.binary.right, bol, eol, ctx)); return (match_expr_eval(o, x->u.binary.left,
} bol, eol, ctx, 0) ||
match_expr_eval(o, x->u.binary.right,
bol, eol, ctx, 0));
h = match_expr_eval(o, x->u.binary.left, bol, eol, ctx, 0);
x->u.binary.left->hit |= h;
h |= match_expr_eval(o, x->u.binary.right, bol, eol, ctx, 1);
break;
default:
die("Unexpected node type (internal error) %d\n", x->node); die("Unexpected node type (internal error) %d\n", x->node);
} }
if (collect_hits)
x->hit |= h;
return h;
}


static int match_expr(struct grep_opt *opt, char *bol, char *eol, static int match_expr(struct grep_opt *opt, char *bol, char *eol,
enum grep_context ctx) enum grep_context ctx, int collect_hits)
{ {
struct grep_expr *x = opt->pattern_expression; struct grep_expr *x = opt->pattern_expression;
return match_expr_eval(opt, x, bol, eol, ctx); return match_expr_eval(opt, x, bol, eol, ctx, collect_hits);
} }


static int match_line(struct grep_opt *opt, char *bol, char *eol, static int match_line(struct grep_opt *opt, char *bol, char *eol,
enum grep_context ctx) enum grep_context ctx, int collect_hits)
{ {
struct grep_pat *p; struct grep_pat *p;
if (opt->extended) if (opt->extended)
return match_expr(opt, bol, eol, ctx); return match_expr(opt, bol, eol, ctx, collect_hits);

/* we do not call with collect_hits without being extended */
for (p = opt->pattern_list; p; p = p->next) { for (p = opt->pattern_list; p; p = p->next) {
if (match_one_pattern(opt, p, bol, eol, ctx)) if (match_one_pattern(opt, p, bol, eol, ctx))
return 1; return 1;
@ -350,7 +376,8 @@ static int match_line(struct grep_opt *opt, char *bol, char *eol,
return 0; return 0;
} }


int grep_buffer(struct grep_opt *opt, const char *name, char *buf, unsigned long size) static int grep_buffer_1(struct grep_opt *opt, const char *name,
char *buf, unsigned long size, int collect_hits)
{ {
char *bol = buf; char *bol = buf;
unsigned long left = size; unsigned long left = size;
@ -386,7 +413,7 @@ int grep_buffer(struct grep_opt *opt, const char *name, char *buf, unsigned long


while (left) { while (left) {
char *eol, ch; char *eol, ch;
int hit = 0; int hit;


eol = end_of_line(bol, &left); eol = end_of_line(bol, &left);
ch = *eol; ch = *eol;
@ -395,9 +422,12 @@ int grep_buffer(struct grep_opt *opt, const char *name, char *buf, unsigned long
if ((ctx == GREP_CONTEXT_HEAD) && (eol == bol)) if ((ctx == GREP_CONTEXT_HEAD) && (eol == bol))
ctx = GREP_CONTEXT_BODY; ctx = GREP_CONTEXT_BODY;


hit = match_line(opt, bol, eol, ctx); hit = match_line(opt, bol, eol, ctx, collect_hits);
*eol = ch; *eol = ch;


if (collect_hits)
goto next_line;

/* "grep -v -e foo -e bla" should list lines /* "grep -v -e foo -e bla" should list lines
* that do not have either, so inversion should * that do not have either, so inversion should
* be done outside. * be done outside.
@ -477,6 +507,8 @@ int grep_buffer(struct grep_opt *opt, const char *name, char *buf, unsigned long
} }


free(prev); free(prev);
if (collect_hits)
return 0;


if (opt->status_only) if (opt->status_only)
return 0; return 0;
@ -496,3 +528,49 @@ int grep_buffer(struct grep_opt *opt, const char *name, char *buf, unsigned long
return !!last_hit; return !!last_hit;
} }


static void clr_hit_marker(struct grep_expr *x)
{
/* All-hit markers are meaningful only at the very top level
* OR node.
*/
while (1) {
x->hit = 0;
if (x->node != GREP_NODE_OR)
return;
x->u.binary.left->hit = 0;
x = x->u.binary.right;
}
}

static int chk_hit_marker(struct grep_expr *x)
{
/* Top level nodes have hit markers. See if they all are hits */
while (1) {
if (x->node != GREP_NODE_OR)
return x->hit;
if (!x->u.binary.left->hit)
return 0;
x = x->u.binary.right;
}
}

int grep_buffer(struct grep_opt *opt, const char *name, char *buf, unsigned long size)
{
/*
* we do not have to do the two-pass grep when we do not check
* buffer-wide "all-match".
*/
if (!opt->all_match)
return grep_buffer_1(opt, name, buf, size, 0);

/* Otherwise the toplevel "or" terms hit a bit differently.
* We first clear hit markers from them.
*/
clr_hit_marker(opt->pattern_expression);
grep_buffer_1(opt, name, buf, size, 1);

if (!chk_hit_marker(opt->pattern_expression))
return 0;

return grep_buffer_1(opt, name, buf, size, 0);
}

2
grep.h

@ -35,6 +35,7 @@ enum grep_expr_node {


struct grep_expr { struct grep_expr {
enum grep_expr_node node; enum grep_expr_node node;
unsigned hit;
union { union {
struct grep_pat *atom; struct grep_pat *atom;
struct grep_expr *unary; struct grep_expr *unary;
@ -59,6 +60,7 @@ struct grep_opt {
unsigned count:1; unsigned count:1;
unsigned word_regexp:1; unsigned word_regexp:1;
unsigned fixed:1; unsigned fixed:1;
unsigned all_match:1;
#define GREP_BINARY_DEFAULT 0 #define GREP_BINARY_DEFAULT 0
#define GREP_BINARY_NOMATCH 1 #define GREP_BINARY_NOMATCH 1
#define GREP_BINARY_TEXT 2 #define GREP_BINARY_TEXT 2

9
revision.c

@ -732,6 +732,7 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch
int i, flags, seen_dashdash, show_merge; int i, flags, seen_dashdash, show_merge;
const char **unrecognized = argv + 1; const char **unrecognized = argv + 1;
int left = 1; int left = 1;
int all_match = 0;


/* First, search for "--" */ /* First, search for "--" */
seen_dashdash = 0; seen_dashdash = 0;
@ -967,6 +968,10 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch
add_message_grep(revs, arg+7); add_message_grep(revs, arg+7);
continue; continue;
} }
if (!strcmp(arg, "--all-match")) {
all_match = 1;
continue;
}


opts = diff_opt_parse(&revs->diffopt, argv+i, argc-i); opts = diff_opt_parse(&revs->diffopt, argv+i, argc-i);
if (opts > 0) { if (opts > 0) {
@ -1028,8 +1033,10 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch
if (diff_setup_done(&revs->diffopt) < 0) if (diff_setup_done(&revs->diffopt) < 0)
die("diff_setup_done failed"); die("diff_setup_done failed");


if (revs->grep_filter) if (revs->grep_filter) {
revs->grep_filter->all_match = all_match;
compile_grep_patterns(revs->grep_filter); compile_grep_patterns(revs->grep_filter);
}


return left; return left;
} }

Loading…
Cancel
Save