summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--builtin/commit.c5
-rw-r--r--builtin/ls-files.c2
-rw-r--r--cache.h1
-rw-r--r--dir.c63
-rw-r--r--dir.h1
-rw-r--r--setup.c32
6 files changed, 40 insertions, 64 deletions
diff --git a/builtin/commit.c b/builtin/commit.c
index cbc9613..b9ab5ef 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -255,8 +255,9 @@ static int list_paths(struct string_list *list, const char *with_tree,
m = xcalloc(1, i);
if (with_tree) {
- const char *max_prefix = pathspec_prefix(prefix, pattern);
- overlay_tree_on_cache(with_tree, max_prefix);
+ char *max_prefix = common_prefix(pattern);
+ overlay_tree_on_cache(with_tree, max_prefix ? max_prefix : prefix);
+ free(max_prefix);
}
for (i = 0; i < active_nr; i++) {
diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index e8a800d..7cff175 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -545,7 +545,7 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
strip_trailing_slash_from_submodules();
/* Find common prefix for all pathspec's */
- max_prefix = pathspec_prefix(prefix, pathspec);
+ max_prefix = common_prefix(pathspec);
max_prefix_len = max_prefix ? strlen(max_prefix) : 0;
/* Treat unmatching pathspec elements as errors */
diff --git a/cache.h b/cache.h
index c989f79..1aa682d 100644
--- a/cache.h
+++ b/cache.h
@@ -445,7 +445,6 @@ extern void set_git_work_tree(const char *tree);
#define ALTERNATE_DB_ENVIRONMENT "GIT_ALTERNATE_OBJECT_DIRECTORIES"
extern const char **get_pathspec(const char *prefix, const char **pathspec);
-extern const char *pathspec_prefix(const char *prefix, const char **pathspec);
extern void setup_work_tree(void);
extern const char *setup_git_directory_gently(int *);
extern const char *setup_git_directory(void);
diff --git a/dir.c b/dir.c
index 08281d2..6c0d782 100644
--- a/dir.c
+++ b/dir.c
@@ -34,49 +34,54 @@ int fnmatch_icase(const char *pattern, const char *string, int flags)
return fnmatch(pattern, string, flags | (ignore_case ? FNM_CASEFOLD : 0));
}
-static int common_prefix(const char **pathspec)
+static size_t common_prefix_len(const char **pathspec)
{
- const char *path, *slash, *next;
- int prefix;
+ const char *n, *first;
+ size_t max = 0;
if (!pathspec)
- return 0;
+ return max;
+
+ first = *pathspec;
+ while ((n = *pathspec++)) {
+ size_t i, len = 0;
+ for (i = 0; first == n || i < max; i++) {
+ char c = n[i];
+ if (!c || c != first[i] || is_glob_special(c))
+ break;
+ if (c == '/')
+ len = i + 1;
+ }
+ if (first == n || len < max) {
+ max = len;
+ if (!max)
+ break;
+ }
+ }
+ return max;
+}
- path = *pathspec;
- slash = strrchr(path, '/');
- if (!slash)
- return 0;
+/*
+ * Returns a copy of the longest leading path common among all
+ * pathspecs.
+ */
+char *common_prefix(const char **pathspec)
+{
+ unsigned long len = common_prefix_len(pathspec);
- /*
- * The first 'prefix' characters of 'path' are common leading
- * path components among the pathspecs we have seen so far,
- * including the trailing slash.
- */
- prefix = slash - path + 1;
- while ((next = *++pathspec) != NULL) {
- int len, last_matching_slash = -1;
- for (len = 0; len < prefix && next[len] == path[len]; len++)
- if (next[len] == '/')
- last_matching_slash = len;
- if (len == prefix)
- continue;
- if (last_matching_slash < 0)
- return 0;
- prefix = last_matching_slash + 1;
- }
- return prefix;
+ return len ? xmemdupz(*pathspec, len) : NULL;
}
int fill_directory(struct dir_struct *dir, const char **pathspec)
{
const char *path;
- int len;
+ size_t len;
/*
* Calculate common prefix for the pathspec, and
* use that to optimize the directory walk
*/
- len = common_prefix(pathspec);
+ len = common_prefix_len(pathspec);
path = "";
if (len)
@@ -84,6 +89,8 @@ int fill_directory(struct dir_struct *dir, const char **pathspec)
/* Read the directory and prune it */
read_directory(dir, path, len, pathspec);
+ if (*path)
+ free((char *)path);
return len;
}
diff --git a/dir.h b/dir.h
index 433b5b4..dd6947e 100644
--- a/dir.h
+++ b/dir.h
@@ -64,6 +64,7 @@ struct dir_struct {
#define MATCHED_RECURSIVELY 1
#define MATCHED_FNMATCH 2
#define MATCHED_EXACTLY 3
+extern char *common_prefix(const char **pathspec);
extern int match_pathspec(const char **pathspec, const char *name, int namelen, int prefix, char *seen);
extern int match_pathspec_depth(const struct pathspec *pathspec,
const char *name, int namelen,
diff --git a/setup.c b/setup.c
index b2b4872..61c22e6 100644
--- a/setup.c
+++ b/setup.c
@@ -236,38 +236,6 @@ const char **get_pathspec(const char *prefix, const char **pathspec)
return pathspec;
}
-const char *pathspec_prefix(const char *prefix, const char **pathspec)
-{
- const char **p, *n, *prev;
- unsigned long max;
-
- if (!pathspec)
- return prefix ? xmemdupz(prefix, strlen(prefix)) : NULL;
-
- prev = NULL;
- max = PATH_MAX;
- for (p = pathspec; (n = *p) != NULL; p++) {
- int i, len = 0;
- for (i = 0; i < max; i++) {
- char c = n[i];
- if (prev && prev[i] != c)
- break;
- if (!c || c == '*' || c == '?')
- break;
- if (c == '/')
- len = i+1;
- }
- prev = n;
- if (len < max) {
- max = len;
- if (!max)
- break;
- }
- }
-
- return max ? xmemdupz(prev, max) : NULL;
-}
-
/*
* Test if it looks like we're at a git directory.
* We want to see: