]> git.ipfire.org Git - thirdparty/git.git/blobdiff - dir.c
Merge branch 'jk/diff-honor-wserrhighlight-in-plumbing'
[thirdparty/git.git] / dir.c
diff --git a/dir.c b/dir.c
index b460211e6149707b813d9354154233272cdfd87d..014741d1bacec90ad48a3125d0a71e0f47f2ab91 100644 (file)
--- a/dir.c
+++ b/dir.c
@@ -636,11 +636,42 @@ int pl_hashmap_cmp(const void *unused_cmp_data,
        return strncmp(ee1->pattern, ee2->pattern, min_len);
 }
 
+static char *dup_and_filter_pattern(const char *pattern)
+{
+       char *set, *read;
+       size_t count  = 0;
+       char *result = xstrdup(pattern);
+
+       set = result;
+       read = result;
+
+       while (*read) {
+               /* skip escape characters (once) */
+               if (*read == '\\')
+                       read++;
+
+               *set = *read;
+
+               set++;
+               read++;
+               count++;
+       }
+       *set = 0;
+
+       if (count > 2 &&
+           *(set - 1) == '*' &&
+           *(set - 2) == '/')
+               *(set - 2) = 0;
+
+       return result;
+}
+
 static void add_pattern_to_hashsets(struct pattern_list *pl, struct path_pattern *given)
 {
        struct pattern_entry *translated;
        char *truncated;
        char *data = NULL;
+       const char *prev, *cur, *next;
 
        if (!pl->use_cone_patterns)
                return;
@@ -657,17 +688,57 @@ static void add_pattern_to_hashsets(struct pattern_list *pl, struct path_pattern
                return;
        }
 
+       if (given->patternlen <= 2 ||
+           *given->pattern == '*' ||
+           strstr(given->pattern, "**")) {
+               /* Not a cone pattern. */
+               warning(_("unrecognized pattern: '%s'"), given->pattern);
+               goto clear_hashmaps;
+       }
+
+       prev = given->pattern;
+       cur = given->pattern + 1;
+       next = given->pattern + 2;
+
+       while (*cur) {
+               /* Watch for glob characters '*', '\', '[', '?' */
+               if (!is_glob_special(*cur))
+                       goto increment;
+
+               /* But only if *prev != '\\' */
+               if (*prev == '\\')
+                       goto increment;
+
+               /* But allow the initial '\' */
+               if (*cur == '\\' &&
+                   is_glob_special(*next))
+                       goto increment;
+
+               /* But a trailing '/' then '*' is fine */
+               if (*prev == '/' &&
+                   *cur == '*' &&
+                   *next == 0)
+                       goto increment;
+
+               /* Not a cone pattern. */
+               warning(_("unrecognized pattern: '%s'"), given->pattern);
+               goto clear_hashmaps;
+
+       increment:
+               prev++;
+               cur++;
+               next++;
+       }
+
        if (given->patternlen > 2 &&
            !strcmp(given->pattern + given->patternlen - 2, "/*")) {
                if (!(given->flags & PATTERN_FLAG_NEGATIVE)) {
                        /* Not a cone pattern. */
-                       pl->use_cone_patterns = 0;
                        warning(_("unrecognized pattern: '%s'"), given->pattern);
                        goto clear_hashmaps;
                }
 
-               truncated = xstrdup(given->pattern);
-               truncated[given->patternlen - 2] = 0;
+               truncated = dup_and_filter_pattern(given->pattern);
 
                translated = xmalloc(sizeof(struct pattern_entry));
                translated->pattern = truncated;
@@ -701,7 +772,7 @@ static void add_pattern_to_hashsets(struct pattern_list *pl, struct path_pattern
 
        translated = xmalloc(sizeof(struct pattern_entry));
 
-       translated->pattern = xstrdup(given->pattern);
+       translated->pattern = dup_and_filter_pattern(given->pattern);
        translated->patternlen = given->patternlen;
        hashmap_entry_init(&translated->ent,
                           ignore_case ?