dir.c: keep track of where patterns came from

For exclude patterns read in from files, the filename is stored in the exclude list, and the originating line number is stored in the individual exclude (counting starting at 1). For exclude patterns provided on the command line, a string describing the source of the patterns is stored in the exclude list, and the sequence number assigned to each exclude pattern is negative, with counting starting at -1. So for example the 2nd pattern provided via --exclude would be numbered -2. This allows any future consumers of that data to easily distinguish between exclude patterns from files vs. from the CLI. Signed-off-by: Adam Spiers <git@adamspiers.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Adam Spiers committed Jan 6, 2013 at 16:58 UTC c04318e46aae79b8b8df059e2118519d83dfee12
4 files changed +44 -12
builtin/clean.c
+2 -2
@@ -97,10 +97,10 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
97 if (!ignored)
98 setup_standard_excludes(&dir);
99
100 - add_exclude_list(&dir, EXC_CMDL);
100 + add_exclude_list(&dir, EXC_CMDL, "--exclude option");
101 for (i = 0; i < exclude_list.nr; i++)
102 add_exclude(exclude_list.items[i].string, "", 0,
103 - &dir.exclude_list_group[EXC_CMDL].el[0]);
103 + &dir.exclude_list_group[EXC_CMDL].el[0], -(i+1));
104
105 pathspec = get_pathspec(prefix, argv);
106
builtin/ls-files.c
+3 -2
@@ -35,6 +35,7 @@ static int error_unmatch;
35 static char *ps_matched;
36 static const char *with_tree;
37 static int exc_given;
38 +static int exclude_args;
39
40 static const char *tag_cached = "";
41 static const char *tag_unmerged = "";
@@ -423,7 +424,7 @@ static int option_parse_exclude(const struct option *opt,
424 struct exclude_list_group *group = opt->value;
425
426 exc_given = 1;
426 - add_exclude(arg, "", 0, &group->el[0]);
427 + add_exclude(arg, "", 0, &group->el[0], --exclude_args);
428
429 return 0;
430 }
@@ -524,7 +525,7 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
525 if (read_cache() < 0)
526 die("index file corrupt");
527
527 - add_exclude_list(&dir, EXC_CMDL);
528 + add_exclude_list(&dir, EXC_CMDL, "--exclude option");
529 argc = parse_options(argc, argv, prefix, builtin_ls_files_options,
530 ls_files_usage, 0);
531 if (show_tag || show_valid_bit) {
dir.c
+20 -6
@@ -349,7 +349,7 @@ void parse_exclude_pattern(const char **pattern,
349 }
350
351 void add_exclude(const char *string, const char *base,
352 - int baselen, struct exclude_list *el)
352 + int baselen, struct exclude_list *el, int srcpos)
353 {
354 struct exclude *x;
355 int patternlen;
@@ -373,8 +373,10 @@ void add_exclude(const char *string, const char *base,
373 x->base = base;
374 x->baselen = baselen;
375 x->flags = flags;
376 + x->srcpos = srcpos;
377 ALLOC_GROW(el->excludes, el->nr + 1, el->alloc);
378 el->excludes[el->nr++] = x;
379 + x->el = el;
380 }
381
382 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,
427 int check_index)
428 {
429 struct stat st;
428 - int fd, i;
430 + int fd, i, lineno = 1;
431 size_t size = 0;
432 char *buf, *entry;
433
@@ -467,15 +469,17 @@ int add_excludes_from_file_to_list(const char *fname,
469 if (buf[i] == '\n') {
470 if (entry != buf + i && entry[0] != '#') {
471 buf[i - (i && buf[i-1] == '\r')] = 0;
470 - add_exclude(entry, base, baselen, el);
472 + add_exclude(entry, base, baselen, el, lineno);
473 }
474 + lineno++;
475 entry = buf + i + 1;
476 }
477 }
478 return 0;
479 }
480
478 -struct exclude_list *add_exclude_list(struct dir_struct *dir, int group_type)
481 +struct exclude_list *add_exclude_list(struct dir_struct *dir,
482 + int group_type, const char *src)
483 {
484 struct exclude_list *el;
485 struct exclude_list_group *group;
@@ -484,6 +488,7 @@ struct exclude_list *add_exclude_list(struct dir_struct *dir, int group_type)
488 ALLOC_GROW(group->el, group->nr + 1, group->alloc);
489 el = &group->el[group->nr++];
490 memset(el, 0, sizeof(*el));
491 + el->src = src;
492 return el;
493 }
494
@@ -493,7 +498,7 @@ struct exclude_list *add_exclude_list(struct dir_struct *dir, int group_type)
498 void add_excludes_from_file(struct dir_struct *dir, const char *fname)
499 {
500 struct exclude_list *el;
496 - el = add_exclude_list(dir, EXC_FILE);
501 + el = add_exclude_list(dir, EXC_FILE, fname);
502 if (add_excludes_from_file_to_list(fname, "", 0, el, 0) < 0)
503 die("cannot use %s as an exclude file", fname);
504 }
@@ -524,6 +529,7 @@ static void prep_exclude(struct dir_struct *dir, const char *base, int baselen)
529 break;
530 el = &group->el[dir->exclude_stack->exclude_ix];
531 dir->exclude_stack = stk->prev;
532 + free((char *)el->src); /* see strdup() below */
533 clear_exclude_list(el);
534 free(stk);
535 group->nr--;
@@ -550,7 +556,15 @@ static void prep_exclude(struct dir_struct *dir, const char *base, int baselen)
556 memcpy(dir->basebuf + current, base + current,
557 stk->baselen - current);
558 strcpy(dir->basebuf + stk->baselen, dir->exclude_per_dir);
553 - el = add_exclude_list(dir, EXC_DIRS);
559 + /*
560 + * dir->basebuf gets reused by the traversal, but we
561 + * need fname to remain unchanged to ensure the src
562 + * member of each struct exclude correctly
563 + * back-references its source file. Other invocations
564 + * of add_exclude_list provide stable strings, so we
565 + * strdup() and free() here in the caller.
566 + */
567 + el = add_exclude_list(dir, EXC_DIRS, strdup(dir->basebuf));
568 stk->exclude_ix = group->nr - 1;
569 add_excludes_from_file_to_list(dir->basebuf,
570 dir->basebuf, stk->baselen,
dir.h
+19 -2
@@ -25,16 +25,32 @@ struct dir_entry {
25 struct exclude_list {
26 int nr;
27 int alloc;
28 +
29 /* remember pointer to exclude file contents so we can free() */
30 char *filebuf;
31
32 + /* origin of list, e.g. path to filename, or descriptive string */
33 + const char *src;
34 +
35 struct exclude {
36 + /*
37 + * This allows callers of last_exclude_matching() etc.
38 + * to determine the origin of the matching pattern.
39 + */
40 + struct exclude_list *el;
41 +
42 const char *pattern;
43 int patternlen;
44 int nowildcardlen;
45 const char *base;
46 int baselen;
47 int flags;
48 +
49 + /*
50 + * Counting starts from 1 for line numbers in ignore files,
51 + * and from -1 decrementing for patterns from CLI args.
52 + */
53 + int srcpos;
54 } **excludes;
55 };
56
@@ -144,13 +160,14 @@ extern struct exclude *last_exclude_matching_path(struct path_exclude_check *, c
160 extern int is_path_excluded(struct path_exclude_check *, const char *, int namelen, int *dtype);
161
162
147 -extern struct exclude_list *add_exclude_list(struct dir_struct *dir, int group_type);
163 +extern struct exclude_list *add_exclude_list(struct dir_struct *dir,
164 + int group_type, const char *src);
165 extern int add_excludes_from_file_to_list(const char *fname, const char *base, int baselen,
166 struct exclude_list *el, int check_index);
167 extern void add_excludes_from_file(struct dir_struct *, const char *fname);
168 extern void parse_exclude_pattern(const char **string, int *patternlen, int *flags, int *nowildcardlen);
169 extern void add_exclude(const char *string, const char *base,
153 - int baselen, struct exclude_list *el);
170 + int baselen, struct exclude_list *el, int srcpos);
171 extern void clear_exclude_list(struct exclude_list *el);
172 extern int file_exists(const char *);
173