]> git.ipfire.org Git - thirdparty/git.git/blobdiff - grep.c
grep: remove overly paranoid BUG(...) code
[thirdparty/git.git] / grep.c
diff --git a/grep.c b/grep.c
index 0d50598acda6f1c41951d1d656ea701114473239..95af88cb74db5413a1472cbe5284ec0bfcf546fe 100644 (file)
--- a/grep.c
+++ b/grep.c
@@ -368,18 +368,6 @@ static int is_fixed(const char *s, size_t len)
        return 1;
 }
 
-static int has_null(const char *s, size_t len)
-{
-       /*
-        * regcomp cannot accept patterns with NULs so when using it
-        * we consider any pattern containing a NUL fixed.
-        */
-       if (memchr(s, 0, len))
-               return 1;
-
-       return 0;
-}
-
 #ifdef USE_LIBPCRE1
 static void compile_pcre1_regexp(struct grep_pat *p, const struct grep_opt *opt)
 {
@@ -388,11 +376,11 @@ static void compile_pcre1_regexp(struct grep_pat *p, const struct grep_opt *opt)
        int options = PCRE_MULTILINE;
 
        if (opt->ignore_case) {
-               if (has_non_ascii(p->pattern))
+               if (!opt->ignore_locale && has_non_ascii(p->pattern))
                        p->pcre1_tables = pcre_maketables();
                options |= PCRE_CASELESS;
        }
-       if (is_utf8_locale() && has_non_ascii(p->pattern))
+       if (!opt->ignore_locale && is_utf8_locale() && has_non_ascii(p->pattern))
                options |= PCRE_UTF8;
 
        p->pcre1_regexp = pcre_compile(p->pattern, options, &error, &erroffset,
@@ -406,14 +394,11 @@ static void compile_pcre1_regexp(struct grep_pat *p, const struct grep_opt *opt)
 
 #ifdef GIT_PCRE1_USE_JIT
        pcre_config(PCRE_CONFIG_JIT, &p->pcre1_jit_on);
-       if (p->pcre1_jit_on == 1) {
+       if (p->pcre1_jit_on) {
                p->pcre1_jit_stack = pcre_jit_stack_alloc(1, 1024 * 1024);
                if (!p->pcre1_jit_stack)
                        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) {
-               BUG("The pcre1_jit_on variable should be 0 or 1, not %d",
-                   p->pcre1_jit_on);
        }
 #endif
 }
@@ -498,14 +483,14 @@ static void compile_pcre2_pattern(struct grep_pat *p, const struct grep_opt *opt
        p->pcre2_compile_context = NULL;
 
        if (opt->ignore_case) {
-               if (has_non_ascii(p->pattern)) {
+               if (!opt->ignore_locale && has_non_ascii(p->pattern)) {
                        character_tables = pcre2_maketables(NULL);
                        p->pcre2_compile_context = pcre2_compile_context_create(NULL);
                        pcre2_set_character_tables(p->pcre2_compile_context, character_tables);
                }
                options |= PCRE2_CASELESS;
        }
-       if (is_utf8_locale() && has_non_ascii(p->pattern))
+       if (!opt->ignore_locale && is_utf8_locale() && has_non_ascii(p->pattern))
                options |= PCRE2_UTF;
 
        p->pcre2_pattern = pcre2_compile((PCRE2_SPTR)p->pattern,
@@ -522,7 +507,7 @@ static void compile_pcre2_pattern(struct grep_pat *p, const struct grep_opt *opt
        }
 
        pcre2_config(PCRE2_CONFIG_JIT, &p->pcre2_jit_on);
-       if (p->pcre2_jit_on == 1) {
+       if (p->pcre2_jit_on) {
                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);
@@ -557,9 +542,6 @@ static void compile_pcre2_pattern(struct grep_pat *p, const struct grep_opt *opt
                if (!p->pcre2_match_context)
                        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) {
-               BUG("The pcre2_jit_on variable should be 0 or 1, not %d",
-                   p->pcre1_jit_on);
        }
 }
 
@@ -626,7 +608,6 @@ static int pcre2match(struct grep_pat *p, const char *line, const char *eol,
 static void free_pcre2_pattern(struct grep_pat *p)
 {
 }
-#endif /* !USE_LIBPCRE2 */
 
 static void compile_fixed_regexp(struct grep_pat *p, struct grep_opt *opt)
 {
@@ -647,46 +628,57 @@ static void compile_fixed_regexp(struct grep_pat *p, struct grep_opt *opt)
                compile_regexp_failed(p, errbuf);
        }
 }
+#endif /* !USE_LIBPCRE2 */
 
 static void compile_regexp(struct grep_pat *p, struct grep_opt *opt)
 {
-       int ascii_only;
        int err;
        int regflags = REG_NEWLINE;
+       int pat_is_fixed;
 
        p->word_regexp = opt->word_regexp;
        p->ignore_case = opt->ignore_case;
-       ascii_only     = !has_non_ascii(p->pattern);
+       p->fixed = opt->fixed;
 
-       /*
-        * Even when -F (fixed) asks us to do a non-regexp search, we
-        * may not be able to correctly case-fold when -i
-        * (ignore-case) is asked (in which case, we'll synthesize a
-        * regexp to match the pattern that matches regexp special
-        * characters literally, while ignoring case differences).  On
-        * the other hand, even without -F, if the pattern does not
-        * have any regexp special characters and there is no need for
-        * case-folding search, we can internally turn it into a
-        * simple string match using kws.  p->fixed tells us if we
-        * want to use kws.
-        */
-       if (opt->fixed ||
-           has_null(p->pattern, p->patternlen) ||
-           is_fixed(p->pattern, p->patternlen))
-               p->fixed = !p->ignore_case || ascii_only;
-
-       if (p->fixed) {
-               p->kws = kwsalloc(p->ignore_case ? tolower_trans_tbl : NULL);
-               kwsincr(p->kws, p->pattern, p->patternlen);
-               kwsprep(p->kws);
-               return;
-       } else if (opt->fixed) {
-               /*
-                * We come here when the pattern has the non-ascii
-                * characters we cannot case-fold, and asked to
-                * ignore-case.
-                */
+       if (memchr(p->pattern, 0, p->patternlen) && !opt->pcre2)
+               die(_("given pattern contains NULL byte (via -f <file>). This is only supported with -P under PCRE v2"));
+
+       pat_is_fixed = is_fixed(p->pattern, p->patternlen);
+       if (opt->fixed || pat_is_fixed) {
+#ifdef USE_LIBPCRE2
+               opt->pcre2 = 1;
+               if (pat_is_fixed) {
+                       compile_pcre2_pattern(p, opt);
+               } else {
+                       /*
+                        * E.g. t7811-grep-open.sh relies on the
+                        * pattern being restored.
+                        */
+                       char *old_pattern = p->pattern;
+                       size_t old_patternlen = p->patternlen;
+                       struct strbuf sb = STRBUF_INIT;
+
+                       /*
+                        * There is the PCRE2_LITERAL flag, but it's
+                        * only in PCRE v2 10.30 and later. Needing to
+                        * ifdef our way around that and dealing with
+                        * it + PCRE2_MULTILINE being an error is more
+                        * complex than just quoting this ourselves.
+                       */
+                       strbuf_add(&sb, "\\Q", 2);
+                       strbuf_add(&sb, p->pattern, p->patternlen);
+                       strbuf_add(&sb, "\\E", 2);
+
+                       p->pattern = sb.buf;
+                       p->patternlen = sb.len;
+                       compile_pcre2_pattern(p, opt);
+                       p->pattern = old_pattern;
+                       p->patternlen = old_patternlen;
+                       strbuf_release(&sb);
+               }
+#else /* !USE_LIBPCRE2 */
                compile_fixed_regexp(p, opt);
+#endif /* !USE_LIBPCRE2 */
                return;
        }
 
@@ -1053,9 +1045,7 @@ void free_grep_patterns(struct grep_opt *opt)
                case GREP_PATTERN: /* atom */
                case GREP_PATTERN_HEAD:
                case GREP_PATTERN_BODY:
-                       if (p->kws)
-                               kwsfree(p->kws);
-                       else if (p->pcre1_regexp)
+                       if (p->pcre1_regexp)
                                free_pcre1_regexp(p);
                        else if (p->pcre2_pattern)
                                free_pcre2_pattern(p);
@@ -1115,29 +1105,12 @@ static void show_name(struct grep_opt *opt, const char *name)
        opt->output(opt, opt->null_following_name ? "\0" : "\n", 1);
 }
 
-static int fixmatch(struct grep_pat *p, char *line, char *eol,
-                   regmatch_t *match)
-{
-       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 = offset;
-               match->rm_eo = match->rm_so + kwsm.size[0];
-               return 0;
-       }
-}
-
 static int patmatch(struct grep_pat *p, char *line, char *eol,
                    regmatch_t *match, int eflags)
 {
        int hit;
 
-       if (p->fixed)
-               hit = !fixmatch(p, line, eol, match);
-       else if (p->pcre1_regexp)
+       if (p->pcre1_regexp)
                hit = !pcre1match(p, line, eol, match, eflags);
        else if (p->pcre2_pattern)
                hit = !pcre2match(p, line, eol, match, eflags);
@@ -1780,6 +1753,10 @@ static int grep_source_1(struct grep_opt *opt, struct grep_source *gs, int colle
        enum grep_context ctx = GREP_CONTEXT_HEAD;
        xdemitconf_t xecfg;
 
+       if (!opt->status_only && gs->name == NULL)
+               BUG("grep call which could print a name requires "
+                   "grep_source.name be non-NULL");
+
        if (!opt->output)
                opt->output = std_output;