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 /*