Junio C Hamano <gitster@xxxxxxxxx> writes: > I am actually tempted to add Michael's hack to get_pathspec() only to > support the "from the top" (and error out with any other magic---as the > approach without a proper restructuring will not work with anything but > that particular magic), to get the "add -u" topic going, and let you (or > other people who are interested in the pathspec rationalization) later fix > it up just a small part of existing issues. Just a heads-up; it would look like this (no docs, tests, nor "add -u" message updates yet). The entries other than "top" should not be in the final version but I just wanted to make sure that the extensibility would look sane. setup.c | 101 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 99 insertions(+), 2 deletions(-) diff --git a/setup.c b/setup.c index 03cd84f..704a930 100644 --- a/setup.c +++ b/setup.c @@ -126,6 +126,104 @@ void verify_non_filename(const char *prefix, const char *arg) "Use '--' to separate filenames from revisions", arg); } +/* + * Magic pathspec + * + * NEEDSWORK: These need to be moved to dir.h or even to a new + * pathspec.h when we restructure get_pathspec() users to use the + * "struct pathspec" interface. + */ +#define PATHSPEC_FROMTOP (1<<0) +#define PATHSPEC_NOGLOB (1<<1) +#define PATHSPEC_ICASE (1<<2) +#define PATHSPEC_RECURSIVE (1<<3) +#define PATHSPEC_REGEXP (1<<4) + +struct pathspec_magic { + unsigned bit; + char mnemonic; /* cannot be ':'! */ + const char *name; +} pathspec_magic[] = { + { PATHSPEC_FROMTOP, '/', "top" }, + { PATHSPEC_NOGLOB, '!', "noglob" }, + { PATHSPEC_ICASE, '\0', "icase" }, + { PATHSPEC_RECURSIVE, '*', "recursive" }, + { PATHSPEC_REGEXP, '\0', "regexp" }, +}; + +/* + * Take an element of a pathspec and check for magic signatures. + * Append the result to the prefix. + * + * For now, we only parse the syntax and throw out anything other than + * "top" magic. + * + * NEEDSWORK: This needs to be rewritten when we start migrating + * get_pathspec() users to use the "struct pathspec" interface. For + * example, a pathspec element may be marked as case-insensitive, but + * the prefix part must always match literally, and a single stupid + * string cannot express such a case. + */ +const char *prefix_pathspec(const char *prefix, int prefixlen, const char *elt) +{ + unsigned magic = 0; + const char *copyfrom = elt; + int i; + + if (elt[0] != ':') { + ; /* nothing to do */ + } else if (elt[1] == '(') { + /* longhand */ + const char *nextat; + for (copyfrom = elt + 2; + *copyfrom && *copyfrom != ')'; + copyfrom = nextat) { + size_t len = strcspn(copyfrom, ",)"); + if (copyfrom[len] == ')') + nextat = copyfrom + len; + else + nextat = copyfrom + len + 1; + if (!len) + continue; + for (i = 0; i < ARRAY_SIZE(pathspec_magic); i++) + if (strlen(pathspec_magic[i].name) == len && + !strncmp(pathspec_magic[i].name, copyfrom, len)) { + magic |= pathspec_magic[i].bit; + break; + } + if (ARRAY_SIZE(pathspec_magic) <= i) + die("Invalid pathspec magic '%.*s' in '%s'", + (int) len, copyfrom, elt); + } + if (*copyfrom == ')') + copyfrom++; + } else { + /* shorthand */ + for (copyfrom = elt + 1; + *copyfrom && *copyfrom != ':'; + copyfrom++) { + char ch = *copyfrom; + for (i = 0; i < ARRAY_SIZE(pathspec_magic); i++) + if (pathspec_magic[i].mnemonic == ch) { + magic |= pathspec_magic[i].bit; + break; + } + if (ARRAY_SIZE(pathspec_magic) <= i) + break; + } + if (*copyfrom == ':') + copyfrom++; + } + + if (magic & ~(PATHSPEC_FROMTOP)) + die("Unsupported pathspec magic in '%s'", elt); + + if (magic & PATHSPEC_FROMTOP) + return xstrdup(copyfrom); + else + return prefix_path(prefix, prefixlen, copyfrom); +} + const char **get_pathspec(const char *prefix, const char **pathspec) { const char *entry = *pathspec; @@ -147,8 +245,7 @@ const char **get_pathspec(const char *prefix, const char **pathspec) dst = pathspec; prefixlen = prefix ? strlen(prefix) : 0; while (*src) { - const char *p = prefix_path(prefix, prefixlen, *src); - *(dst++) = p; + *(dst++) = prefix_pathspec(prefix, prefixlen, *src); src++; } *dst = NULL; -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html