summaryrefslogtreecommitdiff
path: root/setup.c
diff options
context:
space:
mode:
authorJunio C Hamano <gitster@pobox.com>2011-05-23 09:58:35 -0700
committerJunio C Hamano <gitster@pobox.com>2011-05-23 09:58:35 -0700
commitbe5ab43566a7f9ea663349dbb9d7e83e270b3396 (patch)
treecc2d48f22dcfe9969c7ab2be2a6fbf596431347b /setup.c
parentb7aba2ef3450832828148e1a71b6a7198614b43d (diff)
parent488201c87e284ae06323b534c31e354811fb0d51 (diff)
downloadgit-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.c115
1 files changed, 111 insertions, 4 deletions
diff --git a/setup.c b/setup.c
index b6e6b5ae27..013ad11275 100644
--- a/setup.c
+++ b/setup.c
@@ -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;