]> git.ipfire.org Git - thirdparty/git.git/blobdiff - grep.c
Git 2.24
[thirdparty/git.git] / grep.c
diff --git a/grep.c b/grep.c
index 5d268b13d9f7dabc938be838229983233cf28f0a..b7ae5a442a624810471cc4dc8ab84cd1a35c963a 100644 (file)
--- a/grep.c
+++ b/grep.c
@@ -16,6 +16,20 @@ static int grep_source_is_binary(struct grep_source *gs,
 
 static struct grep_opt grep_defaults;
 
+#ifdef USE_LIBPCRE2
+static pcre2_general_context *pcre2_global_context;
+
+static void *pcre2_malloc(PCRE2_SIZE size, MAYBE_UNUSED void *memory_data)
+{
+       return malloc(size);
+}
+
+static void pcre2_free(void *pointer, MAYBE_UNUSED void *memory_data)
+{
+       return free(pointer);
+}
+#endif
+
 static const char *color_grep_slots[] = {
        [GREP_COLOR_CONTEXT]        = "context",
        [GREP_COLOR_FILENAME]       = "filename",
@@ -150,12 +164,28 @@ int grep_config(const char *var, const char *value, void *cb)
  * Initialize one instance of grep_opt and copy the
  * default values from the template we read the configuration
  * information in an earlier call to git_config(grep_config).
+ *
+ * If using PCRE, make sure that the library is configured
+ * to use the same allocator as Git (e.g. nedmalloc on Windows).
+ *
+ * Any allocated memory needs to be released in grep_destroy().
  */
 void grep_init(struct grep_opt *opt, struct repository *repo, const char *prefix)
 {
        struct grep_opt *def = &grep_defaults;
        int i;
 
+#if defined(USE_LIBPCRE2)
+       if (!pcre2_global_context)
+               pcre2_global_context = pcre2_general_context_create(
+                                       pcre2_malloc, pcre2_free, NULL);
+#endif
+
+#ifdef USE_LIBPCRE1
+       pcre_malloc = malloc;
+       pcre_free = free;
+#endif
+
        memset(opt, 0, sizeof(*opt));
        opt->repo = repo;
        opt->prefix = prefix;
@@ -178,6 +208,13 @@ void grep_init(struct grep_opt *opt, struct repository *repo, const char *prefix
                color_set(opt->colors[i], def->colors[i]);
 }
 
+void grep_destroy(void)
+{
+#ifdef USE_LIBPCRE2
+       pcre2_general_context_free(pcre2_global_context);
+#endif
+}
+
 static void grep_set_pattern_type_option(enum grep_pattern_type pattern_type, struct grep_opt *opt)
 {
        /*
@@ -374,6 +411,7 @@ static void compile_pcre1_regexp(struct grep_pat *p, const struct grep_opt *opt)
        const char *error;
        int erroffset;
        int options = PCRE_MULTILINE;
+       int study_options = 0;
 
        if (opt->ignore_case) {
                if (!opt->ignore_locale && has_non_ascii(p->pattern))
@@ -388,15 +426,18 @@ static void compile_pcre1_regexp(struct grep_pat *p, const struct grep_opt *opt)
        if (!p->pcre1_regexp)
                compile_regexp_failed(p, error);
 
-       p->pcre1_extra_info = pcre_study(p->pcre1_regexp, GIT_PCRE_STUDY_JIT_COMPILE, &error);
-       if (!p->pcre1_extra_info && error)
-               die("%s", error);
-
-#ifdef GIT_PCRE1_USE_JIT
+#if defined(PCRE_CONFIG_JIT) && !defined(NO_LIBPCRE1_JIT)
        pcre_config(PCRE_CONFIG_JIT, &p->pcre1_jit_on);
        if (opt->debug)
                fprintf(stderr, "pcre1_jit_on=%d\n", p->pcre1_jit_on);
+
+       if (p->pcre1_jit_on)
+               study_options = PCRE_STUDY_JIT_COMPILE;
 #endif
+
+       p->pcre1_extra_info = pcre_study(p->pcre1_regexp, study_options, &error);
+       if (!p->pcre1_extra_info && error)
+               die("%s", error);
 }
 
 static int pcre1match(struct grep_pat *p, const char *line, const char *eol,
@@ -425,7 +466,7 @@ static int pcre1match(struct grep_pat *p, const char *line, const char *eol,
 static void free_pcre1_regexp(struct grep_pat *p)
 {
        pcre_free(p->pcre1_regexp);
-#ifdef GIT_PCRE1_USE_JIT
+#ifdef PCRE_CONFIG_JIT
        if (p->pcre1_jit_on)
                pcre_free_study(p->pcre1_extra_info);
        else
@@ -457,7 +498,6 @@ static void compile_pcre2_pattern(struct grep_pat *p, const struct grep_opt *opt
        PCRE2_UCHAR errbuf[256];
        PCRE2_SIZE erroffset;
        int options = PCRE2_MULTILINE;
-       const uint8_t *character_tables = NULL;
        int jitret;
        int patinforet;
        size_t jitsizearg;
@@ -466,11 +506,15 @@ static void compile_pcre2_pattern(struct grep_pat *p, const struct grep_opt *opt
 
        p->pcre2_compile_context = NULL;
 
+       /* pcre2_global_context is initialized in append_grep_pattern */
        if (opt->ignore_case) {
                if (!opt->ignore_locale && has_non_ascii(p->pattern)) {
-                       character_tables = pcre2_maketables(NULL);
+                       if (!pcre2_global_context)
+                               BUG("pcre2_global_context uninitialized");
+                       p->pcre2_tables = pcre2_maketables(pcre2_global_context);
                        p->pcre2_compile_context = pcre2_compile_context_create(NULL);
-                       pcre2_set_character_tables(p->pcre2_compile_context, character_tables);
+                       pcre2_set_character_tables(p->pcre2_compile_context,
+                                                       p->pcre2_tables);
                }
                options |= PCRE2_CASELESS;
        }
@@ -567,6 +611,7 @@ static void free_pcre2_pattern(struct grep_pat *p)
        pcre2_compile_context_free(p->pcre2_compile_context);
        pcre2_code_free(p->pcre2_pattern);
        pcre2_match_data_free(p->pcre2_match_data);
+       free((void *)p->pcre2_tables);
 }
 #else /* !USE_LIBPCRE2 */
 static void compile_pcre2_pattern(struct grep_pat *p, const struct grep_opt *opt)