X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=grep.c;h=9c5e1cd950c8d1d97290a047fb3780482f8eb8b7;hb=39af78961d8e7f4c0aee73e77e9eb5b6033f79c2;hp=d03d9e24c23eff2d60ae7226a412f3ccf66670fd;hpb=6d1cdadbeeb03f40250526e29b1f1a91582911d8;p=git.git diff --git a/grep.c b/grep.c index d03d9e24c..9c5e1cd95 100644 --- a/grep.c +++ b/grep.c @@ -79,7 +79,7 @@ static void compile_pcre_regexp(struct grep_pat *p, const struct grep_opt *opt) { const char *error; int erroffset; - int options = 0; + int options = PCRE_MULTILINE; if (opt->ignore_case) options |= PCRE_CASELESS; @@ -137,16 +137,50 @@ static void free_pcre_regexp(struct grep_pat *p) } #endif /* !USE_LIBPCRE */ +static int is_fixed(const char *s, size_t len) +{ + size_t i; + + /* regcomp cannot accept patterns with NULs so we + * consider any pattern containing a NUL fixed. + */ + if (memchr(s, 0, len)) + return 1; + + for (i = 0; i < len; i++) { + if (is_regex_special(s[i])) + return 0; + } + + return 1; +} + static void compile_regexp(struct grep_pat *p, struct grep_opt *opt) { int err; p->word_regexp = opt->word_regexp; p->ignore_case = opt->ignore_case; - p->fixed = opt->fixed; - if (p->fixed) + if (opt->fixed || is_fixed(p->pattern, p->patternlen)) + p->fixed = 1; + else + p->fixed = 0; + + if (p->fixed) { + if (opt->regflags & REG_ICASE || p->ignore_case) { + static char trans[256]; + int i; + for (i = 0; i < 256; i++) + trans[i] = tolower(i); + p->kws = kwsalloc(trans); + } else { + p->kws = kwsalloc(NULL); + } + kwsincr(p->kws, p->pattern, p->patternlen); + kwsprep(p->kws); return; + } if (opt->pcre) { compile_pcre_regexp(p, opt); @@ -395,7 +429,9 @@ void free_grep_patterns(struct grep_opt *opt) case GREP_PATTERN: /* atom */ case GREP_PATTERN_HEAD: case GREP_PATTERN_BODY: - if (p->pcre_regexp) + if (p->kws) + kwsfree(p->kws); + else if (p->pcre_regexp) free_pcre_regexp(p); else regfree(&p->regexp); @@ -430,7 +466,7 @@ static int word_char(char ch) static void output_color(struct grep_opt *opt, const void *data, size_t size, const char *color) { - if (opt->color && color && color[0]) { + if (want_color(opt->color) && color && color[0]) { opt->output(opt, color, strlen(color)); opt->output(opt, data, size); opt->output(opt, GIT_COLOR_RESET, strlen(GIT_COLOR_RESET)); @@ -455,26 +491,14 @@ static void show_name(struct grep_opt *opt, const char *name) static int fixmatch(struct grep_pat *p, char *line, char *eol, regmatch_t *match) { - char *hit; - - if (p->ignore_case) { - char *s = line; - do { - hit = strcasestr(s, p->pattern); - if (hit) - break; - s += strlen(s) + 1; - } while (s < eol); - } else - hit = memmem(line, eol - line, p->pattern, p->patternlen); - - if (!hit) { + struct kwsmatch kwsm; + size_t offset = kwsexec(p->kws, line, eol - line, &kwsm); + if (offset == -1) { match->rm_so = match->rm_eo = -1; return REG_NOMATCH; - } - else { - match->rm_so = hit - line; - match->rm_eo = match->rm_so + p->patternlen; + } else { + match->rm_so = offset; + match->rm_eo = match->rm_so + kwsm.size[0]; return 0; } } @@ -721,7 +745,10 @@ static void show_line(struct grep_opt *opt, char *bol, char *eol, int rest = eol - bol; char *line_color = NULL; - if (opt->pre_context || opt->post_context) { + if (opt->file_break && opt->last_shown == 0) { + if (opt->show_hunk_mark) + opt->output(opt, "\n", 1); + } else if (opt->pre_context || opt->post_context || opt->funcbody) { if (opt->last_shown == 0) { if (opt->show_hunk_mark) { output_color(opt, "--", 2, opt->color_sep); @@ -732,9 +759,13 @@ static void show_line(struct grep_opt *opt, char *bol, char *eol, opt->output(opt, "\n", 1); } } + if (opt->heading && opt->last_shown == 0) { + output_color(opt, name, strlen(name), opt->color_filename); + opt->output(opt, "\n", 1); + } opt->last_shown = lno; - if (opt->pathname) { + if (!opt->heading && opt->pathname) { output_color(opt, name, strlen(name), opt->color_filename); output_sep(opt, sign); } @@ -812,10 +843,13 @@ static void show_funcname_line(struct grep_opt *opt, const char *name, } static void show_pre_context(struct grep_opt *opt, const char *name, char *buf, - char *bol, unsigned lno) + char *bol, char *end, unsigned lno) { unsigned cur = lno, from = 1, funcname_lno = 0; - int funcname_needed = opt->funcname; + int funcname_needed = !!opt->funcname; + + if (opt->funcbody && !match_funcname(opt, bol, end)) + funcname_needed = 2; if (opt->pre_context < lno) from = lno - opt->pre_context; @@ -823,7 +857,8 @@ static void show_pre_context(struct grep_opt *opt, const char *name, char *buf, from = opt->last_shown + 1; /* Rewind. */ - while (bol > buf && cur > from) { + while (bol > buf && + cur > (funcname_needed == 2 ? opt->last_shown + 1 : from)) { char *eol = --bol; while (bol > buf && bol[-1] != '\n') @@ -935,15 +970,26 @@ static int grep_buffer_1(struct grep_opt *opt, const char *name, int binary_match_only = 0; unsigned count = 0; int try_lookahead = 0; + int show_function = 0; enum grep_context ctx = GREP_CONTEXT_HEAD; xdemitconf_t xecfg; if (!opt->output) opt->output = std_output; - if (opt->last_shown && (opt->pre_context || opt->post_context) && - opt->output == std_output) - opt->show_hunk_mark = 1; + if (opt->pre_context || opt->post_context || opt->file_break || + opt->funcbody) { + /* Show hunk marks, except for the first file. */ + if (opt->last_shown) + opt->show_hunk_mark = 1; + /* + * If we're using threads then we can't easily identify + * the first file. Always put hunk marks in that case + * and skip the very first one later in work_done(). + */ + if (opt->output != std_output) + opt->show_hunk_mark = 1; + } opt->last_shown = 0; switch (opt->binary) { @@ -988,7 +1034,8 @@ static int grep_buffer_1(struct grep_opt *opt, const char *name, */ if (try_lookahead && !(last_hit - && lno <= last_hit + opt->post_context) + && (show_function || + lno <= last_hit + opt->post_context)) && look_ahead(opt, &left, &lno, &bol)) break; eol = end_of_line(bol, &left); @@ -1035,15 +1082,20 @@ static int grep_buffer_1(struct grep_opt *opt, const char *name, /* Hit at this line. If we haven't shown the * pre-context lines, we would need to show them. */ - if (opt->pre_context) - show_pre_context(opt, name, buf, bol, lno); + if (opt->pre_context || opt->funcbody) + show_pre_context(opt, name, buf, bol, eol, lno); else if (opt->funcname) show_funcname_line(opt, name, buf, bol, lno); show_line(opt, bol, eol, name, lno, ':'); last_hit = lno; + if (opt->funcbody) + show_function = 1; + goto next_line; } - else if (last_hit && - lno <= last_hit + opt->post_context) { + if (show_function && match_funcname(opt, bol, eol)) + show_function = 0; + if (show_function || + (last_hit && lno <= last_hit + opt->post_context)) { /* If the last hit is within the post context, * we need to show this line. */