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

[PATCH v2 02/21] Add parse_pathspec() that converts cmdline args to struct pathspec

From
Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Date
Jan 11, 2013, 11:20 UTC
Message-ID
<1357903275-16804-3-git-send-email-pclouds@gmail.com>
In-Reply-To
<1357903275-16804-1-git-send-email-pclouds@gmail.com>
Currently to fill a struct pathspec, we do:
   const char **paths;
   paths = get_pathspec(prefix, argv);
   ...
   init_pathspec(&pathspec, paths);

"paths" can only carry bare strings, which loses information from command line arguments such as pathspec magic or the prefix part's length for each argument.

parse_pathspec() is introduced to combine the two calls into one. The plan is gradually replace all get_pathspec() and init_pathspec() with parse_pathspec(). get_pathspec() now becomes a thin wrapper of parse_pathspec().

parse_pathspec() allows the caller to reject the pathspec magics that it does not support. When a new pathspec magic is introduced, we can enable it per command after making sure that all underlying code has no problem with the new magic.

"flags" parameter is currently unused. But it would allow callers to pass certain instructions to parse_pathspec, for example forcing literal pathspec when no magic is used.

With the introduction of parse_pathspec, there are now two functions that can initialize struct pathspec: init_pathspec and parse_pathspec. Any semantic changes in struct pathspec must be reflected in both functions. init_pathspec() will be phased out in favor of parse_pathspec().

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 dir.c   |  2 +-
 dir.h   |  1 +
 setup.c | 99 +++++++++++++++++++++++++++++++++++++++++++++++++----------------
 3 files changed, 77 insertions(+), 25 deletions(-)
diff --git a/dir.c b/dir.c
index c391d46..31f0995 100644
--- a/dir.c
+++ b/dir.c
@@ -291,7 +291,7 @@ int match_pathspec_depth(const struct pathspec *ps,
 /*
  * Return the length of the "simple" part of a path match limiter.
  */
-static int simple_length(const char *match)
+int simple_length(const char *match)
 {
 	int len = -1;
 
diff --git a/dir.h b/dir.h
index f5c89e3..1d4888b 100644
--- a/dir.h
+++ b/dir.h
@@ -66,6 +66,7 @@ struct dir_struct {
 #define MATCHED_RECURSIVELY 1
 #define MATCHED_FNMATCH 2
 #define MATCHED_EXACTLY 3
+extern int simple_length(const char *match);
 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,
diff --git a/setup.c b/setup.c
index f108c4b..4fcdae6 100644
--- a/setup.c
+++ b/setup.c
@@ -174,7 +174,7 @@ static struct pathspec_magic {
 
 /*
  * Take an element of a pathspec and check for magic signatures.
- * Append the result to the prefix.
+ * Append the result to the prefix. Return the magic bitmap.
  *
  * For now, we only parse the syntax and throw out anything other than
  * "top" magic.
@@ -185,7 +185,10 @@ static struct pathspec_magic {
  * the prefix part must always match literally, and a single stupid
  * string cannot express such a case.
  */
-static const char *prefix_pathspec(const char *prefix, int prefixlen, const char *elt)
+static unsigned prefix_pathspec(struct pathspec_item *item,
+				const char **raw,
+				const char *prefix, int prefixlen,
+				const char *elt)
 {
 	unsigned magic = 0;
 	const char *copyfrom = elt;
@@ -241,39 +244,87 @@ static const char *prefix_pathspec(const char *prefix, int prefixlen, const char
 	}
 
 	if (magic & PATHSPEC_FROMTOP)
-		return xstrdup(copyfrom);
+		item->match = xstrdup(copyfrom);
 	else
-		return prefix_path(prefix, prefixlen, copyfrom);
+		item->match = prefix_path(prefix, prefixlen, copyfrom);
+	*raw = item->match;
+	item->len = strlen(item->match);
+	item->nowildcard_len = simple_length(item->match);
+	return magic;
 }
 
-const char **get_pathspec(const char *prefix, const char **pathspec)
+static int pathspec_item_cmp(const void *a_, const void *b_)
 {
-	const char *entry = *pathspec;
-	const char **src, **dst;
-	int prefixlen;
+	struct pathspec_item *a, *b;
 
-	if (!prefix && !entry)
-		return NULL;
+	a = (struct pathspec_item *)a_;
+	b = (struct pathspec_item *)b_;
+	return strcmp(a->match, b->match);
+}
+
+/*
+ * Given command line arguments and a prefix, convert the input to
+ * pathspec. die() if any magic other than ones in magic_mask.
+ */
+static void parse_pathspec(struct pathspec *pathspec,
+			   unsigned magic_mask, unsigned flags,
+			   const char *prefix, const char **argv)
+{
+	struct pathspec_item *item;
+	const char *entry = *argv;
+	int i, n, prefixlen;
+
+	memset(pathspec, 0, sizeof(*pathspec));
+
+	/* No arguments, no prefix -> no pathspec */
+	if (!entry && !prefix)
+		return;
 
+	/* No arguments with prefix -> prefix pathspec */
 	if (!entry) {
-		static const char *spec[2];
-		spec[0] = prefix;
-		spec[1] = NULL;
-		return spec;
+		static const char *raw[2];
+
+		pathspec->items = item = xmalloc(sizeof(*item));
+		item->match = prefix;
+		item->nowildcard_len = item->len = strlen(prefix);
+		raw[0] = prefix;
+		raw[1] = NULL;
+		pathspec->nr = 1;
+		pathspec->raw = raw;
+		return;
 	}
 
-	/* Otherwise we have to re-write the entries.. */
-	src = pathspec;
-	dst = pathspec;
+	n = 0;
+	while (argv[n])
+		n++;
+
+	pathspec->nr = n;
+	pathspec->items = item = xmalloc(sizeof(*item) * n);
+	pathspec->raw = argv;
 	prefixlen = prefix ? strlen(prefix) : 0;
-	while (*src) {
-		*(dst++) = prefix_pathspec(prefix, prefixlen, *src);
-		src++;
+
+	for (i = 0; i < n; i++) {
+		unsigned applied_magic;
+		const char *arg = argv[i];
+
+		applied_magic = prefix_pathspec(item + i, argv + i,
+						prefix, prefixlen, arg);
+		if (applied_magic & ~magic_mask)
+			die(_("pathspec magic in '%s' is not supported"
+			      " by this command"), arg);
+		if (item[i].nowildcard_len < item[i].len)
+			pathspec->has_wildcard = 1;
 	}
-	*dst = NULL;
-	if (!*pathspec)
-		return NULL;
-	return pathspec;
+
+	qsort(pathspec->items, pathspec->nr,
+	      sizeof(struct pathspec_item), pathspec_item_cmp);
+}
+
+const char **get_pathspec(const char *prefix, const char **pathspec)
+{
+	struct pathspec ps;
+	parse_pathspec(&ps, PATHSPEC_FROMTOP, 0, prefix, pathspec);
+	return ps.raw;
 }
 
 /*
-- 
1.8.0.rc2.23.g1fb49df
Previous: Nguyễn Thái Ngọc DuyNext: Nguyễn Thái Ngọc Duy
Message 3 of 27 in “nd/parse-pathspec reroll”
  1. 00/21 nd/parse-pathspec rerollNguyễn Thái Ngọc Duy, Jan 11, 2013
  2. 01/21 pathspec: save the non-wildcard length partNguyễn Thái Ngọc Duy, Jan 11, 2013
  3. 02/21 Add parse_pathspec() that converts cmdline args to struct pathspecNguyễn Thái Ngọc Duy, Jan 11, 2013
  4. 03/21 Export parse_pathspec() and convert some get_pathspec() callsNguyễn Thái Ngọc Duy, Jan 11, 2013
  5. Matt KraaiJan 11, 2013
  6. Duy NguyenJan 12, 2013
  7. 04/21 clean: convert to use parse_pathspecNguyễn Thái Ngọc Duy, Jan 11, 2013
  8. 05/21 commit: convert to use parse_pathspecNguyễn Thái Ngọc Duy, Jan 11, 2013
  9. Martin von ZweigbergkJan 12, 2013
  10. 06/21 status: convert to use parse_pathspecNguyễn Thái Ngọc Duy, Jan 11, 2013
  11. 07/21 rerere: convert to use parse_pathspecNguyễn Thái Ngọc Duy, Jan 11, 2013
  12. 08/21 checkout: convert to use parse_pathspecNguyễn Thái Ngọc Duy, Jan 11, 2013
  13. 09/21 rm: convert to use parse_pathspecNguyễn Thái Ngọc Duy, Jan 11, 2013
  14. 10/21 ls-files: convert to use parse_pathspecNguyễn Thái Ngọc Duy, Jan 11, 2013
  15. 11/21 archive: convert to use parse_pathspecNguyễn Thái Ngọc Duy, Jan 11, 2013
  16. 12/21 add: convert to use parse_pathspecNguyễn Thái Ngọc Duy, Jan 11, 2013
  17. 13/21 Convert read_cache_preload() to take struct pathspecNguyễn Thái Ngọc Duy, Jan 11, 2013
  18. 14/21 Convert unmerge_cache to take struct pathspecNguyễn Thái Ngọc Duy, Jan 11, 2013
  19. 15/21 checkout: convert read_tree_some to take struct pathspecNguyễn Thái Ngọc Duy, Jan 11, 2013
  20. 16/21 Convert report_path_error to take struct pathspecNguyễn Thái Ngọc Duy, Jan 11, 2013
  21. 17/21 Convert refresh_index to take struct pathspecNguyễn Thái Ngọc Duy, Jan 11, 2013
  22. Nguyen Thai Ngoc DuyJan 11, 2013
  23. 18/21 Convert {read,fill}_directory to take struct pathspecNguyễn Thái Ngọc Duy, Jan 11, 2013
  24. 19/21 Convert add_files_to_cache to take struct pathspecNguyễn Thái Ngọc Duy, Jan 11, 2013
  25. 20/21 Convert more init_pathspec() to parse_pathspec()Nguyễn Thái Ngọc Duy, Jan 11, 2013
  26. 21/21 Rename field "raw" to "_raw" in struct pathspecNguyễn Thái Ngọc Duy, Jan 11, 2013
  27. 22/21 Convert the last use of match_pathspec() and remove itNguyễn Thái Ngọc Duy, Jan 11, 2013

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.