subtree test: add missing && to &&-chain
[gitweb.git] / grep.c
diff --git a/grep.c b/grep.c
index d0b9b6cdfa74537ed67dcfef4ae486466d7185f8..45ec7e636c004dbd35d4e0d05c243bc1d1479d19 100644 (file)
--- a/grep.c
+++ b/grep.c
@@ -18,6 +18,11 @@ static void std_output(struct grep_opt *opt, const void *buf, size_t size)
        fwrite(buf, size, 1, stdout);
 }
 
+static void color_set(char *dst, const char *color_bytes)
+{
+       xsnprintf(dst, COLOR_MAXLEN, "%s", color_bytes);
+}
+
 /*
  * Initialize the grep_defaults template with hardcoded defaults.
  * We could let the compiler do this, but without C99 initializers
@@ -399,7 +404,7 @@ static void compile_pcre1_regexp(struct grep_pat *p, const struct grep_opt *opt)
                        die("Couldn't allocate PCRE JIT stack");
                pcre_assign_jit_stack(p->pcre1_extra_info, NULL, p->pcre1_jit_stack);
        } else if (p->pcre1_jit_on != 0) {
-               die("BUG: The pcre1_jit_on variable should be 0 or 1, not %d",
+               BUG("The pcre1_jit_on variable should be 0 or 1, not %d",
                    p->pcre1_jit_on);
        }
 #endif
@@ -477,6 +482,8 @@ static void compile_pcre2_pattern(struct grep_pat *p, const struct grep_opt *opt
        int options = PCRE2_MULTILINE;
        const uint8_t *character_tables = NULL;
        int jitret;
+       int patinforet;
+       size_t jitsizearg;
 
        assert(opt->pcre2);
 
@@ -511,6 +518,30 @@ static void compile_pcre2_pattern(struct grep_pat *p, const struct grep_opt *opt
                jitret = pcre2_jit_compile(p->pcre2_pattern, PCRE2_JIT_COMPLETE);
                if (jitret)
                        die("Couldn't JIT the PCRE2 pattern '%s', got '%d'\n", p->pattern, jitret);
+
+               /*
+                * The pcre2_config(PCRE2_CONFIG_JIT, ...) call just
+                * tells us whether the library itself supports JIT,
+                * but to see whether we're going to be actually using
+                * JIT we need to extract PCRE2_INFO_JITSIZE from the
+                * pattern *after* we do pcre2_jit_compile() above.
+                *
+                * This is because if the pattern contains the
+                * (*NO_JIT) verb (see pcre2syntax(3))
+                * pcre2_jit_compile() will exit early with 0. If we
+                * then proceed to call pcre2_jit_match() further down
+                * the line instead of pcre2_match() we'll either
+                * segfault (pre PCRE 10.31) or run into a fatal error
+                * (post PCRE2 10.31)
+                */
+               patinforet = pcre2_pattern_info(p->pcre2_pattern, PCRE2_INFO_JITSIZE, &jitsizearg);
+               if (patinforet)
+                       BUG("pcre2_pattern_info() failed: %d", patinforet);
+               if (jitsizearg == 0) {
+                       p->pcre2_jit_on = 0;
+                       return;
+               }
+
                p->pcre2_jit_stack = pcre2_jit_stack_create(1, 1024 * 1024, NULL);
                if (!p->pcre2_jit_stack)
                        die("Couldn't allocate PCRE2 JIT stack");
@@ -519,7 +550,7 @@ static void compile_pcre2_pattern(struct grep_pat *p, const struct grep_opt *opt
                        die("Couldn't allocate PCRE2 match context");
                pcre2_jit_stack_assign(p->pcre2_match_context, NULL, p->pcre2_jit_stack);
        } else if (p->pcre2_jit_on != 0) {
-               die("BUG: The pcre2_jit_on variable should be 0 or 1, not %d",
+               BUG("The pcre2_jit_on variable should be 0 or 1, not %d",
                    p->pcre1_jit_on);
        }
 }
@@ -605,7 +636,6 @@ static void compile_fixed_regexp(struct grep_pat *p, struct grep_opt *opt)
        if (err) {
                char errbuf[1024];
                regerror(err, &p->regexp, errbuf, sizeof(errbuf));
-               regfree(&p->regexp);
                compile_regexp_failed(p, errbuf);
        }
 }
@@ -670,7 +700,6 @@ static void compile_regexp(struct grep_pat *p, struct grep_opt *opt)
        if (err) {
                char errbuf[1024];
                regerror(err, &p->regexp, errbuf, 1024);
-               regfree(&p->regexp);
                compile_regexp_failed(p, errbuf);
        }
 }
@@ -886,10 +915,10 @@ static struct grep_expr *prep_header_patterns(struct grep_opt *opt)
 
        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.");
+                       BUG("a non-header pattern in grep header list.");
                if (p->field < GREP_HEADER_FIELD_MIN ||
                    GREP_HEADER_FIELD_MAX <= p->field)
-                       die("BUG: unknown header field %d", p->field);
+                       BUG("unknown header field %d", p->field);
                compile_regexp(p, opt);
        }
 
@@ -902,7 +931,7 @@ static struct grep_expr *prep_header_patterns(struct grep_opt *opt)
 
                h = compile_pattern_atom(&pp);
                if (!h || pp != p->next)
-                       die("BUG: malformed header expr");
+                       BUG("malformed header expr");
                if (!header_group[p->field]) {
                        header_group[p->field] = h;
                        continue;
@@ -1476,31 +1505,52 @@ static void show_funcname_line(struct grep_opt *opt, struct grep_source *gs,
        }
 }
 
+static int is_empty_line(const char *bol, const char *eol);
+
 static void show_pre_context(struct grep_opt *opt, struct grep_source *gs,
                             char *bol, char *end, unsigned lno)
 {
-       unsigned cur = lno, from = 1, funcname_lno = 0;
-       int funcname_needed = !!opt->funcname;
-
-       if (opt->funcbody && !match_funcname(opt, gs, bol, end))
-               funcname_needed = 2;
+       unsigned cur = lno, from = 1, funcname_lno = 0, orig_from;
+       int funcname_needed = !!opt->funcname, comment_needed = 0;
 
        if (opt->pre_context < lno)
                from = lno - opt->pre_context;
        if (from <= opt->last_shown)
                from = opt->last_shown + 1;
+       orig_from = from;
+       if (opt->funcbody) {
+               if (match_funcname(opt, gs, bol, end))
+                       comment_needed = 1;
+               else
+                       funcname_needed = 1;
+               from = opt->last_shown + 1;
+       }
 
        /* Rewind. */
-       while (bol > gs->buf &&
-              cur > (funcname_needed == 2 ? opt->last_shown + 1 : from)) {
+       while (bol > gs->buf && cur > from) {
+               char *next_bol = bol;
                char *eol = --bol;
 
                while (bol > gs->buf && bol[-1] != '\n')
                        bol--;
                cur--;
+               if (comment_needed && (is_empty_line(bol, eol) ||
+                                      match_funcname(opt, gs, bol, eol))) {
+                       comment_needed = 0;
+                       from = orig_from;
+                       if (cur < from) {
+                               cur++;
+                               bol = next_bol;
+                               break;
+                       }
+               }
                if (funcname_needed && match_funcname(opt, gs, bol, eol)) {
                        funcname_lno = cur;
                        funcname_needed = 0;
+                       if (opt->funcbody)
+                               comment_needed = 1;
+                       else
+                               from = orig_from;
                }
        }
 
@@ -1600,7 +1650,7 @@ static int fill_textconv_grep(struct userdiff_driver *driver,
                fill_filespec(df, &null_oid, 0, 0100644);
                break;
        default:
-               die("BUG: attempt to textconv something without a path?");
+               BUG("attempt to textconv something without a path?");
        }
 
        /*
@@ -1696,7 +1746,7 @@ static int grep_source_1(struct grep_opt *opt, struct grep_source *gs, int colle
                case GREP_BINARY_TEXT:
                        break;
                default:
-                       die("BUG: unknown binary handling mode");
+                       BUG("unknown binary handling mode");
                }
        }
 
@@ -1963,7 +2013,7 @@ static int grep_source_load_oid(struct grep_source *gs)
        enum object_type type;
 
        grep_read_lock();
-       gs->buf = read_sha1_file(gs->identifier, &type, &gs->size);
+       gs->buf = read_object_file(gs->identifier, &type, &gs->size);
        grep_read_unlock();
 
        if (!gs->buf)
@@ -2020,7 +2070,7 @@ static int grep_source_load(struct grep_source *gs)
        case GREP_SOURCE_BUF:
                return gs->buf ? 0 : -1;
        }
-       die("BUG: invalid grep_source type to load");
+       BUG("invalid grep_source type to load");
 }
 
 void grep_source_load_driver(struct grep_source *gs)