dir.c: keep track of where patterns came from
[gitweb.git] / dir.c
diff --git a/dir.c b/dir.c
index 3a15cb9bc9a6eda78f0aeee185403e2ae63e80cd..d3f462bd155db75be078681dfa9168bdcb8c5d16 100644 (file)
--- a/dir.c
+++ b/dir.c
@@ -349,7 +349,7 @@ void parse_exclude_pattern(const char **pattern,
 }
 
 void add_exclude(const char *string, const char *base,
-                int baselen, struct exclude_list *el)
+                int baselen, struct exclude_list *el, int srcpos)
 {
        struct exclude *x;
        int patternlen;
@@ -373,8 +373,10 @@ void add_exclude(const char *string, const char *base,
        x->base = base;
        x->baselen = baselen;
        x->flags = flags;
+       x->srcpos = srcpos;
        ALLOC_GROW(el->excludes, el->nr + 1, el->alloc);
        el->excludes[el->nr++] = x;
+       x->el = el;
 }
 
 static void *read_skip_worktree_file_from_index(const char *path, size_t *size)
@@ -425,7 +427,7 @@ int add_excludes_from_file_to_list(const char *fname,
                                   int check_index)
 {
        struct stat st;
-       int fd, i;
+       int fd, i, lineno = 1;
        size_t size = 0;
        char *buf, *entry;
 
@@ -467,15 +469,17 @@ int add_excludes_from_file_to_list(const char *fname,
                if (buf[i] == '\n') {
                        if (entry != buf + i && entry[0] != '#') {
                                buf[i - (i && buf[i-1] == '\r')] = 0;
-                               add_exclude(entry, base, baselen, el);
+                               add_exclude(entry, base, baselen, el, lineno);
                        }
+                       lineno++;
                        entry = buf + i + 1;
                }
        }
        return 0;
 }
 
-struct exclude_list *add_exclude_list(struct dir_struct *dir, int group_type)
+struct exclude_list *add_exclude_list(struct dir_struct *dir,
+                                     int group_type, const char *src)
 {
        struct exclude_list *el;
        struct exclude_list_group *group;
@@ -484,6 +488,7 @@ struct exclude_list *add_exclude_list(struct dir_struct *dir, int group_type)
        ALLOC_GROW(group->el, group->nr + 1, group->alloc);
        el = &group->el[group->nr++];
        memset(el, 0, sizeof(*el));
+       el->src = src;
        return el;
 }
 
@@ -493,7 +498,7 @@ struct exclude_list *add_exclude_list(struct dir_struct *dir, int group_type)
 void add_excludes_from_file(struct dir_struct *dir, const char *fname)
 {
        struct exclude_list *el;
-       el = add_exclude_list(dir, EXC_FILE);
+       el = add_exclude_list(dir, EXC_FILE, fname);
        if (add_excludes_from_file_to_list(fname, "", 0, el, 0) < 0)
                die("cannot use %s as an exclude file", fname);
 }
@@ -524,6 +529,7 @@ static void prep_exclude(struct dir_struct *dir, const char *base, int baselen)
                        break;
                el = &group->el[dir->exclude_stack->exclude_ix];
                dir->exclude_stack = stk->prev;
+               free((char *)el->src); /* see strdup() below */
                clear_exclude_list(el);
                free(stk);
                group->nr--;
@@ -550,7 +556,15 @@ static void prep_exclude(struct dir_struct *dir, const char *base, int baselen)
                memcpy(dir->basebuf + current, base + current,
                       stk->baselen - current);
                strcpy(dir->basebuf + stk->baselen, dir->exclude_per_dir);
-               el = add_exclude_list(dir, EXC_DIRS);
+               /*
+                * dir->basebuf gets reused by the traversal, but we
+                * need fname to remain unchanged to ensure the src
+                * member of each struct exclude correctly
+                * back-references its source file.  Other invocations
+                * of add_exclude_list provide stable strings, so we
+                * strdup() and free() here in the caller.
+                */
+               el = add_exclude_list(dir, EXC_DIRS, strdup(dir->basebuf));
                stk->exclude_ix = group->nr - 1;
                add_excludes_from_file_to_list(dir->basebuf,
                                               dir->basebuf, stk->baselen,