Skip to content

Commit 4a085b1

Browse files
committed
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 <[email protected]>
1 parent 5879f56 commit 4a085b1

File tree

3 files changed

+28
-56
lines changed

3 files changed

+28
-56
lines changed

dir.c

Lines changed: 25 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -34,56 +34,52 @@ int fnmatch_icase(const char *pattern, const char *string, int flags)
3434
return fnmatch(pattern, string, flags | (ignore_case ? FNM_CASEFOLD : 0));
3535
}
3636

37-
static int common_prefix(const char **pathspec)
37+
size_t common_prefix_len(const char **pathspec)
3838
{
39-
const char *path, *slash, *next;
40-
int prefix;
39+
const char *n, *first;
40+
size_t max = 0;
4141

4242
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+
}
6660
}
67-
return prefix;
61+
return max;
6862
}
6963

7064
int fill_directory(struct dir_struct *dir, const char **pathspec)
7165
{
7266
const char *path;
73-
int len;
67+
size_t len;
7468

7569
/*
7670
* Calculate common prefix for the pathspec, and
7771
* use that to optimize the directory walk
7872
*/
79-
len = common_prefix(pathspec);
73+
len = common_prefix_len(pathspec);
8074
path = "";
8175

8276
if (len)
8377
path = xmemdupz(*pathspec, len);
8478

8579
/* Read the directory and prune it */
8680
read_directory(dir, path, len, pathspec);
81+
if (*path)
82+
free((char *)path);
8783
return len;
8884
}
8985

dir.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ struct dir_struct {
6464
#define MATCHED_RECURSIVELY 1
6565
#define MATCHED_FNMATCH 2
6666
#define MATCHED_EXACTLY 3
67+
extern size_t common_prefix_len(const char **pathspec);
6768
extern int match_pathspec(const char **pathspec, const char *name, int namelen, int prefix, char *seen);
6869
extern int match_pathspec_depth(const struct pathspec *pathspec,
6970
const char *name, int namelen,

setup.c

Lines changed: 2 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -266,34 +266,9 @@ const char **get_pathspec(const char *prefix, const char **pathspec)
266266

267267
char *pathspec_prefix(const char **pathspec)
268268
{
269-
const char **p, *n, *prev;
270-
unsigned long max;
269+
size_t len = common_prefix_len(pathspec);
271270

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;
297272
}
298273

299274
/*

0 commit comments

Comments
 (0)