diff options
Diffstat (limited to 'grep.c')
-rw-r--r-- | grep.c | 102 |
1 files changed, 71 insertions, 31 deletions
@@ -189,30 +189,74 @@ static struct grep_expr *compile_pattern_expr(struct grep_pat **list) return compile_pattern_or(list); } -void compile_grep_patterns(struct grep_opt *opt) +static struct grep_expr *grep_true_expr(void) +{ + struct grep_expr *z = xcalloc(1, sizeof(*z)); + z->node = GREP_NODE_TRUE; + return z; +} + +static struct grep_expr *grep_or_expr(struct grep_expr *left, struct grep_expr *right) +{ + struct grep_expr *z = xcalloc(1, sizeof(*z)); + z->node = GREP_NODE_OR; + z->u.binary.left = left; + z->u.binary.right = right; + return z; +} + +static struct grep_expr *prep_header_patterns(struct grep_opt *opt) { struct grep_pat *p; - struct grep_expr *header_expr = NULL; - - if (opt->header_list) { - p = opt->header_list; - header_expr = compile_pattern_expr(&p); - if (p) - die("incomplete pattern expression: %s", p->pattern); - for (p = opt->header_list; p; p = p->next) { - switch (p->token) { - case GREP_PATTERN: /* atom */ - case GREP_PATTERN_HEAD: - case GREP_PATTERN_BODY: - compile_regexp(p, opt); - break; - default: - opt->extended = 1; - break; - } + struct grep_expr *header_expr; + struct grep_expr *(header_group[GREP_HEADER_FIELD_MAX]); + enum grep_header_field fld; + + if (!opt->header_list) + return NULL; + p = opt->header_list; + for (p = opt->header_list; p; p = p->next) { + if (p->token != GREP_PATTERN_HEAD) + die("bug: a non-header pattern in grep header list."); + if (p->field < 0 || GREP_HEADER_FIELD_MAX <= p->field) + die("bug: unknown header field %d", p->field); + compile_regexp(p, opt); + } + + for (fld = 0; fld < GREP_HEADER_FIELD_MAX; fld++) + header_group[fld] = NULL; + + for (p = opt->header_list; p; p = p->next) { + struct grep_expr *h; + struct grep_pat *pp = p; + + h = compile_pattern_atom(&pp); + if (!h || pp != p->next) + die("bug: malformed header expr"); + if (!header_group[p->field]) { + header_group[p->field] = h; + continue; } + header_group[p->field] = grep_or_expr(h, header_group[p->field]); } + header_expr = NULL; + + for (fld = 0; fld < GREP_HEADER_FIELD_MAX; fld++) { + if (!header_group[fld]) + continue; + if (!header_expr) + header_expr = grep_true_expr(); + header_expr = grep_or_expr(header_group[fld], header_expr); + } + return header_expr; +} + +void compile_grep_patterns(struct grep_opt *opt) +{ + struct grep_pat *p; + struct grep_expr *header_expr = prep_header_patterns(opt); + for (p = opt->pattern_list; p; p = p->next) { switch (p->token) { case GREP_PATTERN: /* atom */ @@ -231,9 +275,6 @@ void compile_grep_patterns(struct grep_opt *opt) else if (!opt->extended) return; - /* Then bundle them up in an expression. - * A classic recursive descent parser would do. - */ p = opt->pattern_list; if (p) opt->pattern_expression = compile_pattern_expr(&p); @@ -243,22 +284,18 @@ void compile_grep_patterns(struct grep_opt *opt) if (!header_expr) return; - if (opt->pattern_expression) { - struct grep_expr *z; - z = xcalloc(1, sizeof(*z)); - z->node = GREP_NODE_OR; - z->u.binary.left = opt->pattern_expression; - z->u.binary.right = header_expr; - opt->pattern_expression = z; - } else { + if (!opt->pattern_expression) opt->pattern_expression = header_expr; - } + else + opt->pattern_expression = grep_or_expr(opt->pattern_expression, + header_expr); opt->all_match = 1; } static void free_pattern_expr(struct grep_expr *x) { switch (x->node) { + case GREP_NODE_TRUE: case GREP_NODE_ATOM: break; case GREP_NODE_NOT: @@ -487,6 +524,9 @@ static int match_expr_eval(struct grep_expr *x, char *bol, char *eol, if (!x) die("Not a valid grep expression"); switch (x->node) { + case GREP_NODE_TRUE: + h = 1; + break; case GREP_NODE_ATOM: h = match_one_pattern(x->u.atom, bol, eol, ctx, &match, 0); break; |