consolidate pathspec_prefix and common_prefix
The implementation from pathspec_prefix (slightly modified) replaces the current common_prefix, because it also respects glob characters. Based on a patch by Clemens Buchacher. Signed-off-by: Junio C Hamano <gitster@pobox.com>
Junio C Hamano committed
Sep 6, 2011 at 12:32 UTC
4a085b16f430bcfe1b6e2e84e7a569f4e191e906
3 files changed
+28
-56
dir.c
+25
-29
@@ -34,49 +34,43 @@ int fnmatch_icase(const char *pattern, const char *string, int flags)
34
return fnmatch(pattern, string, flags | (ignore_case ? FNM_CASEFOLD : 0));
35
}
36
37
-static int common_prefix(const char **pathspec)
37
+size_t common_prefix_len(const char **pathspec)
38
{
39
- const char *path, *slash, *next;
40
- int prefix;
39
+ const char *n, *first;
40
+ size_t max = 0;
41
42
if (!pathspec)
43
- return 0;
44
-
45
- path = *pathspec;
46
- slash = strrchr(path, '/');
47
- if (!slash)
48
- return 0;
49
-
50
- /*
51
- * The first 'prefix' characters of 'path' are common leading
52
- * path components among the pathspecs we have seen so far,
53
- * including the trailing slash.
54
- */
55
- prefix = slash - path + 1;
56
- while ((next = *++pathspec) != NULL) {
57
- int len, last_matching_slash = -1;
58
- for (len = 0; len < prefix && next[len] == path[len]; len++)
59
- if (next[len] == '/')
60
- last_matching_slash = len;
61
- if (len == prefix)
62
- continue;
63
- if (last_matching_slash < 0)
64
- return 0;
65
- prefix = last_matching_slash + 1;
43
+ return max;
44
+
45
+ first = *pathspec;
46
+ while ((n = *pathspec++)) {
47
+ size_t i, len = 0;
48
+ for (i = 0; first == n || i < max; i++) {
49
+ char c = n[i];
50
+ if (!c || c != first[i] || is_glob_special(c))
51
+ break;
52
+ if (c == '/')
53
+ len = i + 1;
54
+ }
55
+ if (first == n || len < max) {
56
+ max = len;
57
+ if (!max)
58
+ break;
59
+ }
60
}
67
- return prefix;
61
+ return max;
62
}
63
64
int fill_directory(struct dir_struct *dir, const char **pathspec)
65
{
66
const char *path;
73
- int len;
67
+ size_t len;
68
69
/*
70
* Calculate common prefix for the pathspec, and
71
* use that to optimize the directory walk
72
*/
79
- len = common_prefix(pathspec);
73
+ len = common_prefix_len(pathspec);
74
path = "";
75
76
if (len)
@@ -84,6 +78,8 @@ int fill_directory(struct dir_struct *dir, const char **pathspec)
78
79
/* Read the directory and prune it */
80
read_directory(dir, path, len, pathspec);
81
+ if (*path)
82
+ free((char *)path);
83
return len;
84
}
85
dir.h
+1
@@ -64,6 +64,7 @@ struct dir_struct {
64
#define MATCHED_RECURSIVELY 1
65
#define MATCHED_FNMATCH 2
66
#define MATCHED_EXACTLY 3
67
+extern size_t common_prefix_len(const char **pathspec);
68
extern int match_pathspec(const char **pathspec, const char *name, int namelen, int prefix, char *seen);
69
extern int match_pathspec_depth(const struct pathspec *pathspec,
70
const char *name, int namelen,
setup.c
+2
-27
@@ -266,34 +266,9 @@ const char **get_pathspec(const char *prefix, const char **pathspec)
266
267
char *pathspec_prefix(const char **pathspec)
268
{
269
- const char **p, *n, *prev;
270
- unsigned long max;
269
+ size_t len = common_prefix_len(pathspec);
270
272
- if (!pathspec)
273
- return NULL;
274
-
275
- prev = NULL;
276
- max = PATH_MAX;
277
- for (p = pathspec; (n = *p) != NULL; p++) {
278
- int i, len = 0;
279
- for (i = 0; i < max; i++) {
280
- char c = n[i];
281
- if (prev && prev[i] != c)
282
- break;
283
- if (!c || c == '*' || c == '?')
284
- break;
285
- if (c == '/')
286
- len = i+1;
287
- }
288
- prev = n;
289
- if (len < max) {
290
- max = len;
291
- if (!max)
292
- break;
293
- }
294
- }
295
-
296
- return max ? xmemdupz(prev, max) : NULL;
271
+ return len ? xmemdupz(*pathspec, len) : NULL;
272
}
273
274
/*