diff options
author | Junio C Hamano <gitster@pobox.com> | 2011-05-23 09:58:35 -0700 |
---|---|---|
committer | Junio C Hamano <gitster@pobox.com> | 2011-05-23 09:58:35 -0700 |
commit | be5ab43566a7f9ea663349dbb9d7e83e270b3396 (patch) | |
tree | cc2d48f22dcfe9969c7ab2be2a6fbf596431347b /setup.c | |
parent | b7aba2ef3450832828148e1a71b6a7198614b43d (diff) | |
parent | 488201c87e284ae06323b534c31e354811fb0d51 (diff) | |
download | git-be5ab43566a7f9ea663349dbb9d7e83e270b3396.tar.gz |
Merge branch 'jc/magic-pathspec'
* jc/magic-pathspec:
setup.c: Fix some "symbol not declared" sparse warnings
t3703: Skip tests using directory name ":" on Windows
revision.c: leave a note for "a lone :" enhancement
t3703, t4208: add test cases for magic pathspec
rev/path disambiguation: further restrict "misspelled index entry" diag
fix overslow :/no-such-string-ever-existed diagnostics
fix overstrict :<path> diagnosis
grep: use get_pathspec() correctly
pathspec: drop "lone : means no pathspec" from get_pathspec()
Revert "magic pathspec: add ":(icase)path" to match case insensitively"
magic pathspec: add ":(icase)path" to match case insensitively
magic pathspec: futureproof shorthand form
magic pathspec: add tentative ":/path/from/top/level" pathspec support
Diffstat (limited to 'setup.c')
-rw-r--r-- | setup.c | 115 |
1 files changed, 111 insertions, 4 deletions
@@ -85,8 +85,17 @@ static void NORETURN die_verify_filename(const char *prefix, const char *arg) { unsigned char sha1[20]; unsigned mode; - /* try a detailed diagnostic ... */ - get_sha1_with_mode_1(arg, sha1, &mode, 0, prefix); + + /* + * Saying "'(icase)foo' does not exist in the index" when the + * user gave us ":(icase)foo" is just stupid. A magic pathspec + * begins with a colon and is followed by a non-alnum; do not + * let get_sha1_with_mode_1(only_to_die=1) to even trigger. + */ + if (!(arg[0] == ':' && !isalnum(arg[1]))) + /* try a detailed diagnostic ... */ + get_sha1_with_mode_1(arg, sha1, &mode, 1, prefix); + /* ... or fall back the most general message. */ die("ambiguous argument '%s': unknown revision or path not in the working tree.\n" "Use '--' to separate paths from revisions", arg); @@ -126,6 +135,105 @@ 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. + * + * Possible future magic semantics include stuff like: + * + * { PATHSPEC_NOGLOB, '!', "noglob" }, + * { PATHSPEC_ICASE, '\0', "icase" }, + * { PATHSPEC_RECURSIVE, '*', "recursive" }, + * { PATHSPEC_REGEXP, '\0', "regexp" }, + * + */ +#define PATHSPEC_FROMTOP (1<<0) + +static struct pathspec_magic { + unsigned bit; + char mnemonic; /* this cannot be ':'! */ + const char *name; +} pathspec_magic[] = { + { PATHSPEC_FROMTOP, '/', "top" }, +}; + +/* + * 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. + */ +static 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; + + if (!is_pathspec_magic(ch)) + break; + 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) + die("Unimplemented pathspec magic '%c' in '%s'", + ch, elt); + } + if (*copyfrom == ':') + copyfrom++; + } + + 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 +255,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; |