|
|
|
@ -34,7 +34,7 @@ static void compile_regexp(struct grep_pat *p, struct grep_opt *opt)
@@ -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) |
|
|
|
|
{ |
|
|
|
|
struct grep_pat *p; |
|
|
|
@ -52,7 +52,7 @@ static struct grep_expr *compile_pattern_atom(struct grep_pat **list)
@@ -52,7 +52,7 @@ static struct grep_expr *compile_pattern_atom(struct grep_pat **list)
|
|
|
|
|
return x; |
|
|
|
|
case GREP_OPEN_PAREN: |
|
|
|
|
*list = p->next; |
|
|
|
|
x = compile_pattern_expr(list); |
|
|
|
|
x = compile_pattern_or(list); |
|
|
|
|
if (!x) |
|
|
|
|
return NULL; |
|
|
|
|
if (!*list || (*list)->token != GREP_CLOSE_PAREN) |
|
|
|
@ -138,6 +138,9 @@ void compile_grep_patterns(struct grep_opt *opt)
@@ -138,6 +138,9 @@ void compile_grep_patterns(struct grep_opt *opt)
|
|
|
|
|
{ |
|
|
|
|
struct grep_pat *p; |
|
|
|
|
|
|
|
|
|
if (opt->all_match) |
|
|
|
|
opt->extended = 1; |
|
|
|
|
|
|
|
|
|
for (p = opt->pattern_list; p; p = p->next) { |
|
|
|
|
switch (p->token) { |
|
|
|
|
case GREP_PATTERN: /* atom */ |
|
|
|
@ -309,40 +312,63 @@ static int match_one_pattern(struct grep_opt *opt, struct grep_pat *p, char *bol
@@ -309,40 +312,63 @@ static int match_one_pattern(struct grep_opt *opt, struct grep_pat *p, char *bol
|
|
|
|
|
return hit; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int match_expr_eval(struct grep_opt *opt, |
|
|
|
|
static int match_expr_eval(struct grep_opt *o, |
|
|
|
|
struct grep_expr *x, |
|
|
|
|
char *bol, char *eol, |
|
|
|
|
enum grep_context ctx) |
|
|
|
|
enum grep_context ctx, |
|
|
|
|
int collect_hits) |
|
|
|
|
{ |
|
|
|
|
int h = 0; |
|
|
|
|
|
|
|
|
|
switch (x->node) { |
|
|
|
|
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; |
|
|
|
|
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: |
|
|
|
|
return (match_expr_eval(opt, x->u.binary.left, bol, eol, ctx) && |
|
|
|
|
match_expr_eval(opt, x->u.binary.right, bol, eol, ctx)); |
|
|
|
|
if (!collect_hits) |
|
|
|
|
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: |
|
|
|
|
return (match_expr_eval(opt, x->u.binary.left, bol, eol, ctx) || |
|
|
|
|
match_expr_eval(opt, x->u.binary.right, bol, eol, ctx)); |
|
|
|
|
} |
|
|
|
|
if (!collect_hits) |
|
|
|
|
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); |
|
|
|
|
} |
|
|
|
|
if (collect_hits) |
|
|
|
|
x->hit |= h; |
|
|
|
|
return h; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
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; |
|
|
|
|
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, |
|
|
|
|
enum grep_context ctx) |
|
|
|
|
enum grep_context ctx, int collect_hits) |
|
|
|
|
{ |
|
|
|
|
struct grep_pat *p; |
|
|
|
|
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) { |
|
|
|
|
if (match_one_pattern(opt, p, bol, eol, ctx)) |
|
|
|
|
return 1; |
|
|
|
@ -350,7 +376,8 @@ static int match_line(struct grep_opt *opt, char *bol, char *eol,
@@ -350,7 +376,8 @@ static int match_line(struct grep_opt *opt, char *bol, char *eol,
|
|
|
|
|
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; |
|
|
|
|
unsigned long left = size; |
|
|
|
@ -386,7 +413,7 @@ int grep_buffer(struct grep_opt *opt, const char *name, char *buf, unsigned long
@@ -386,7 +413,7 @@ int grep_buffer(struct grep_opt *opt, const char *name, char *buf, unsigned long
|
|
|
|
|
|
|
|
|
|
while (left) { |
|
|
|
|
char *eol, ch; |
|
|
|
|
int hit = 0; |
|
|
|
|
int hit; |
|
|
|
|
|
|
|
|
|
eol = end_of_line(bol, &left); |
|
|
|
|
ch = *eol; |
|
|
|
@ -395,9 +422,12 @@ int grep_buffer(struct grep_opt *opt, const char *name, char *buf, unsigned long
@@ -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)) |
|
|
|
|
ctx = GREP_CONTEXT_BODY; |
|
|
|
|
|
|
|
|
|
hit = match_line(opt, bol, eol, ctx); |
|
|
|
|
hit = match_line(opt, bol, eol, ctx, collect_hits); |
|
|
|
|
*eol = ch; |
|
|
|
|
|
|
|
|
|
if (collect_hits) |
|
|
|
|
goto next_line; |
|
|
|
|
|
|
|
|
|
/* "grep -v -e foo -e bla" should list lines |
|
|
|
|
* that do not have either, so inversion should |
|
|
|
|
* be done outside. |
|
|
|
@ -477,6 +507,8 @@ int grep_buffer(struct grep_opt *opt, const char *name, char *buf, unsigned long
@@ -477,6 +507,8 @@ int grep_buffer(struct grep_opt *opt, const char *name, char *buf, unsigned long
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
free(prev); |
|
|
|
|
if (collect_hits) |
|
|
|
|
return 0; |
|
|
|
|
|
|
|
|
|
if (opt->status_only) |
|
|
|
|
return 0; |
|
|
|
@ -496,3 +528,49 @@ int grep_buffer(struct grep_opt *opt, const char *name, char *buf, unsigned long
@@ -496,3 +528,49 @@ int grep_buffer(struct grep_opt *opt, const char *name, char *buf, unsigned long
|
|
|
|
|
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); |
|
|
|
|
} |
|
|
|
|