diff options
Diffstat (limited to 'grep.c')
-rw-r--r-- | grep.c | 108 |
1 files changed, 93 insertions, 15 deletions
@@ -2,6 +2,19 @@ #include "grep.h" #include "xdiff-interface.h" +void append_header_grep_pattern(struct grep_opt *opt, enum grep_header_field field, const char *pat) +{ + struct grep_pat *p = xcalloc(1, sizeof(*p)); + p->pattern = pat; + p->origin = "header"; + p->no = 0; + p->token = GREP_PATTERN_HEAD; + p->field = field; + *opt->pattern_tail = p; + opt->pattern_tail = &p->next; + p->next = NULL; +} + void append_grep_pattern(struct grep_opt *opt, const char *pat, const char *origin, int no, enum grep_pat_token t) { @@ -15,9 +28,25 @@ void append_grep_pattern(struct grep_opt *opt, const char *pat, p->next = NULL; } +static int is_fixed(const char *s) +{ + while (*s && !is_regex_special(*s)) + s++; + return !*s; +} + static void compile_regexp(struct grep_pat *p, struct grep_opt *opt) { - int err = regcomp(&p->regexp, p->pattern, opt->regflags); + int err; + + if (opt->fixed || is_fixed(p->pattern)) + p->fixed = 1; + if (opt->regflags & REG_ICASE) + p->fixed = 0; + if (p->fixed) + return; + + err = regcomp(&p->regexp, p->pattern, opt->regflags); if (err) { char errbuf[1024]; char where[1024]; @@ -146,8 +175,7 @@ void compile_grep_patterns(struct grep_opt *opt) case GREP_PATTERN: /* atom */ case GREP_PATTERN_HEAD: case GREP_PATTERN_BODY: - if (!opt->fixed) - compile_regexp(p, opt); + compile_regexp(p, opt); break; default: opt->extended = 1; @@ -226,6 +254,8 @@ static int word_char(char ch) static void show_line(struct grep_opt *opt, const char *bol, const char *eol, const char *name, unsigned lno, char sign) { + if (opt->null_following_name) + sign = '\0'; if (opt->pathname) printf("%s%c", name, sign); if (opt->linenum) @@ -233,6 +263,11 @@ static void show_line(struct grep_opt *opt, const char *bol, const char *eol, printf("%.*s\n", (int)(eol-bol), bol); } +static void show_name(struct grep_opt *opt, const char *name) +{ + printf("%s%c", name, opt->null_following_name ? '\0' : '\n'); +} + static int fixmatch(const char *pattern, char *line, regmatch_t *match) { char *hit = strstr(line, pattern); @@ -247,18 +282,54 @@ static int fixmatch(const char *pattern, char *line, regmatch_t *match) } } +static int strip_timestamp(char *bol, char **eol_p) +{ + char *eol = *eol_p; + int ch; + + while (bol < --eol) { + if (*eol != '>') + continue; + *eol_p = ++eol; + ch = *eol; + *eol = '\0'; + return ch; + } + return 0; +} + +static struct { + const char *field; + size_t len; +} header_field[] = { + { "author ", 7 }, + { "committer ", 10 }, +}; + static int match_one_pattern(struct grep_opt *opt, struct grep_pat *p, char *bol, char *eol, enum grep_context ctx) { int hit = 0; - int at_true_bol = 1; + int saved_ch = 0; regmatch_t pmatch[10]; if ((p->token != GREP_PATTERN) && ((p->token == GREP_PATTERN_HEAD) != (ctx == GREP_CONTEXT_HEAD))) return 0; + if (p->token == GREP_PATTERN_HEAD) { + const char *field; + size_t len; + assert(p->field < ARRAY_SIZE(header_field)); + field = header_field[p->field].field; + len = header_field[p->field].len; + if (strncmp(bol, field, len)) + return 0; + bol += len; + saved_ch = strip_timestamp(bol, &eol); + } + again: - if (!opt->fixed) { + if (!p->fixed) { regex_t *exp = &p->regexp; hit = !regexec(exp, bol, ARRAY_SIZE(pmatch), pmatch, 0); @@ -280,7 +351,7 @@ static int match_one_pattern(struct grep_opt *opt, struct grep_pat *p, char *bol * either end of the line, or at word boundary * (i.e. the next char must not be a word char). */ - if ( ((pmatch[0].rm_so == 0 && at_true_bol) || + if ( ((pmatch[0].rm_so == 0) || !word_char(bol[pmatch[0].rm_so-1])) && ((pmatch[0].rm_eo == (eol-bol)) || !word_char(bol[pmatch[0].rm_eo])) ) @@ -292,12 +363,18 @@ static int match_one_pattern(struct grep_opt *opt, struct grep_pat *p, char *bol /* There could be more than one match on the * line, and the first match might not be * strict word match. But later ones could be! + * Forward to the next possible start, i.e. the + * next position following a non-word char. */ bol = pmatch[0].rm_so + bol + 1; - at_true_bol = 0; - goto again; + while (word_char(bol[-1]) && bol < eol) + bol++; + if (bol < eol) + goto again; } } + if (p->token == GREP_PATTERN_HEAD && saved_ch) + *eol = saved_ch; return hit; } @@ -336,7 +413,7 @@ static int match_expr_eval(struct grep_opt *o, 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", x->node); } if (collect_hits) x->hit |= h; @@ -437,7 +514,7 @@ static int grep_buffer_1(struct grep_opt *opt, const char *name, return 1; } if (opt->name_only) { - printf("%s\n", name); + show_name(opt, name); return 1; } /* Hit at this line. If we haven't shown the @@ -455,7 +532,7 @@ static int grep_buffer_1(struct grep_opt *opt, const char *name, if (from <= last_shown) from = last_shown + 1; if (last_shown && from != last_shown + 1) - printf(hunk_mark); + fputs(hunk_mark, stdout); while (from < lno) { pcl = &prev[lno-from-1]; show_line(opt, pcl->bol, pcl->eol, @@ -465,7 +542,7 @@ static int grep_buffer_1(struct grep_opt *opt, const char *name, last_shown = lno-1; } if (last_shown && lno != last_shown + 1) - printf(hunk_mark); + fputs(hunk_mark, stdout); if (!opt->count) show_line(opt, bol, eol, name, lno, ':'); last_shown = last_hit = lno; @@ -476,7 +553,7 @@ static int grep_buffer_1(struct grep_opt *opt, const char *name, * we need to show this line. */ if (last_shown && lno != last_shown + 1) - printf(hunk_mark); + fputs(hunk_mark, stdout); show_line(opt, bol, eol, name, lno, '-'); last_shown = lno; } @@ -503,7 +580,7 @@ static int grep_buffer_1(struct grep_opt *opt, const char *name, return 0; if (opt->unmatch_name_only) { /* We did not see any hit, so we want to show this */ - printf("%s\n", name); + show_name(opt, name); return 1; } @@ -513,7 +590,8 @@ static int grep_buffer_1(struct grep_opt *opt, const char *name, * make it another option? For now suppress them. */ if (opt->count && count) - printf("%s:%u\n", name, count); + printf("%s%c%u\n", name, + opt->null_following_name ? '\0' : ':', count); return !!last_hit; } |