git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH 2/3] consolidate pathspec_prefix and common_prefix

From
Clemens Buchacher <drizzd@aon.at>
Date
Sep 4, 2011, 10:42 UTC
Message-ID
<1315132921-26949-3-git-send-email-drizzd@aon.at>
In-Reply-To
<1315132921-26949-1-git-send-email-drizzd@aon.at>

The implementation from pathspec_prefix (slightly modified) replaces the current common_prefix, because it also respects glob characters.

Signed-off-by: Clemens Buchacher <drizzd@aon.at>
---

I wonder if PATH_MAX is needed and respected everywhere. Do we have any previous experience with very long paths?

Clemens
 dir.c   |   52 ++++++++++++++++++++++++++--------------------------
 dir.h   |    1 +
 setup.c |   29 ++---------------------------
 3 files changed, 29 insertions(+), 53 deletions(-)
diff --git a/dir.c b/dir.c
index 08281d2..7099fb3 100644
--- a/dir.c
+++ b/dir.c
@@ -34,37 +34,37 @@ 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)
+unsigned long common_prefix_len(const char **pathspec)
 {
-	const char *path, *slash, *next;
-	int prefix;
+	const char *n, *first;
+	unsigned long max;
 
 	if (!pathspec)
 		return 0;
 
-	path = *pathspec;
-	slash = strrchr(path, '/');
-	if (!slash)
-		return 0;
-
-	/*
-	 * 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;
+	first = *pathspec;
+	max = PATH_MAX;
+	while ((n = *pathspec++)) {
+		int i, len = 0;
+		for (i = 0; i < max; i++) {
+			char c = n[i];
+			if (!c || c != first[i] || is_glob_special(c))
+				break;
+			if (c == '/')
+				len = i+1;
+		}
+		if (len < max) {
+			max = len;
+			if (!max)
+				break;
+		}
 	}
-	return prefix;
+
+	/* Nothing in the first PATH_MAX characters? */
+	if (max > 0 && first[max-1] != '/')
+		max = 0;
+
+	return max;
 }
 
 int fill_directory(struct dir_struct *dir, const char **pathspec)
@@ -76,7 +76,7 @@ int fill_directory(struct dir_struct *dir, const char **pathspec)
 	 * 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)
diff --git a/dir.h b/dir.h
index 433b5b4..0e55b71 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 unsigned long common_prefix_len(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 0906790..0c60dbd 100644
--- a/setup.c
+++ b/setup.c
@@ -238,34 +238,9 @@ const char **get_pathspec(const char *prefix, const char **pathspec)
 
 char *pathspec_prefix(const char **pathspec)
 {
-	const char **p, *n, *prev;
-	unsigned long max;
+	unsigned long len = common_prefix_len(pathspec);
 
-	if (!pathspec)
-		return 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;
+	return len ? xmemdupz(prefix, len) : NULL;
 }
 
 /*
-- 
1.7.6.1
Previous: Junio C HamanoNext: Clemens Buchacher
Message 36 of 37 in “Possible bug”
  1. Reuben ThomasJul 23, 2011
  2. commit: allow partial commits with relative pathsMichael J Gruber, Jul 25, 2011
  3. Junio C HamanoJul 25, 2011
  4. Junio C HamanoJul 25, 2011
  5. Michael J GruberJul 27, 2011
  6. Reuben ThomasJul 27, 2011
  7. Michael J GruberJul 27, 2011
  8. Reuben ThomasJul 27, 2011
  9. John SzakmeisterJul 27, 2011
  10. ls-files: fix pathspec display on errorMichael J Gruber, Jul 27, 2011
  11. Clemens BuchacherJul 29, 2011
  12. Junio C HamanoAug 1, 2011
  13. test ls-files with relative pathsClemens Buchacher, Aug 1, 2011
  14. Junio C HamanoAug 1, 2011
  15. ls-files: fix pathspec display on errorClemens Buchacher, Aug 1, 2011
  16. Junio C HamanoAug 1, 2011
  17. Erik Faye-LundJul 28, 2011
  18. Junio C HamanoJul 27, 2011
  19. Junio C HamanoJul 27, 2011
  20. Michael J GruberJul 27, 2011
  21. commit: allow partial commits with relative pathsClemens Buchacher, Jul 29, 2011
  22. Michael J GruberJul 30, 2011
  23. Clemens BuchacherJul 30, 2011
  24. Michael J GruberJul 30, 2011
  25. commit: allow partial commits with relative pathsClemens Buchacher, Jul 30, 2011
  26. Junio C HamanoAug 1, 2011
  27. Junio C HamanoAug 2, 2011
  28. Clemens BuchacherAug 3, 2011
  29. Junio C HamanoAug 3, 2011
  30. renaming pathspec_prefix (was: Re: [PATCH v2] commit: allow partial commits with relative paths)Clemens Buchacher, Sep 4, 2011
  31. 1/3 remove prefix argument from pathspec_prefixClemens Buchacher, Sep 4, 2011
  32. Junio C HamanoSep 6, 2011
  33. Junio C HamanoSep 6, 2011
  34. Clemens BuchacherSep 8, 2011
  35. Junio C HamanoSep 8, 2011
  36. 2/3 consolidate pathspec_prefix and common_prefixClemens Buchacher, Sep 4, 2011
  37. 3/3 rename pathspec_prefix -> common_prefix and move to dir.[ch]Clemens Buchacher, Sep 4, 2011

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.