{"thread":{"id":"33187","subject":"[PATCH v1 00/45] nd/parse-pathspec and :(glob) pathspec magic","startedAt":"2013-03-15T06:06:15Z","lastAt":"2013-04-15T16:17:32Z","messageCount":88,"participants":["Nguyễn Thái Ngọc Duy","Junio C Hamano","Eric Sunshine","Duy Nguyen","John Keeping","Adam Spiers"],"isPatch":true,"patchVersion":1,"patchTotal":45},"messages":[{"id":"211344","messageId":"1363327620-29017-1-git-send-email-pclouds@gmail.com","threadId":"33187","inReplyTo":null,"subject":"[PATCH v1 00/45] nd/parse-pathspec and :(glob) pathspec magic","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2013-03-15T06:06:15Z","receivedAt":"2013-03-15T06:06:15Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Probably not much to say. A big portion of this series is the\nconversion to struct pathspec, which enables more use of pathspec\nmagic. :(glob) magic is added to verify that the conversion makes\nsense.\n\nAndrew Wong (1):\n  setup.c: check that the pathspec magic ends with \")\"\n\nNguyễn Thái Ngọc Duy (44):\n  clean: remove unused variable \"seen\"\n  Move struct pathspec and related functions to pathspec.[ch]\n  pathspec: i18n-ize error strings in pathspec parsing code\n  pathspec: add copy_pathspec\n  Add parse_pathspec() that converts cmdline args to struct pathspec\n  parse_pathspec: save original pathspec for reporting\n  parse_pathspec: add PATHSPEC_PREFER_{CWD,FULL}\n  Convert some get_pathspec() calls to parse_pathspec()\n  parse_pathspec: a special flag for max_depth feature\n  parse_pathspec: support stripping submodule trailing slashes\n  parse_pathspec: support stripping/checking submodule paths\n  parse_pathspec: support prefixing original patterns\n  Guard against new pathspec magic in pathspec matching code\n  clean: convert to use parse_pathspec\n  commit: convert to use parse_pathspec\n  status: convert to use parse_pathspec\n  rerere: convert to use parse_pathspec\n  checkout: convert to use parse_pathspec\n  rm: convert to use parse_pathspec\n  ls-files: convert to use parse_pathspec\n  archive: convert to use parse_pathspec\n  check-ignore: convert to use parse_pathspec\n  add: convert to use parse_pathspec\n  reset: convert to use parse_pathspec\n  Convert read_cache_preload() to take struct pathspec\n  Convert run_add_interactive to use struct pathspec\n  Convert unmerge_cache to take struct pathspec\n  checkout: convert read_tree_some to take struct pathspec\n  Convert report_path_error to take struct pathspec\n  Convert refresh_index to take struct pathspec\n  Convert {read,fill}_directory to take struct pathspec\n  Convert add_files_to_cache to take struct pathspec\n  Convert common_prefix() to use struct pathspec\n  Remove diff_tree_{setup,release}_paths\n  Remove init_pathspec() in favor of parse_pathspec()\n  Remove match_pathspec() in favor of match_pathspec_depth()\n  tree-diff: remove the use of pathspec's raw[] in follow-rename codepath\n  parse_pathspec: make sure the prefix part is wildcard-free\n  parse_pathspec: preserve prefix length via PATHSPEC_PREFIX_ORIGIN\n  Kill limit_pathspec_to_literal() as it's only used by parse_pathspec()\n  pathspec: support :(literal) syntax for noglob pathspec\n  pathspec: make --literal-pathspecs disable pathspec magic\n  pathspec: support :(glob) syntax\n  Rename field \"raw\" to \"_raw\" in struct pathspec\n\n Documentation/git.txt              |  23 +-\n Documentation/glossary-content.txt |  33 +++\n archive.c                          |  18 +-\n archive.h                          |   4 +-\n builtin/add.c                      | 156 ++++++--------\n builtin/blame.c                    |  14 +-\n builtin/check-ignore.c             |  34 +--\n builtin/checkout.c                 |  46 ++--\n builtin/clean.c                    |  24 +--\n builtin/commit.c                   |  37 ++--\n builtin/diff-files.c               |   2 +-\n builtin/diff-index.c               |   2 +-\n builtin/diff.c                     |   6 +-\n builtin/grep.c                     |  10 +-\n builtin/log.c                      |   2 +-\n builtin/ls-files.c                 |  75 +++----\n builtin/ls-tree.c                  |  13 +-\n builtin/mv.c                       |  13 +-\n builtin/rerere.c                   |   8 +-\n builtin/reset.c                    |  33 +--\n builtin/rm.c                       |  24 +--\n builtin/update-index.c             |   6 +-\n cache.h                            |  34 +--\n commit.h                           |   2 +-\n diff-lib.c                         |   3 +-\n diff.h                             |   3 +-\n dir.c                              | 261 +++++-----------------\n dir.h                              |  18 +-\n git.c                              |   8 +\n merge-recursive.c                  |   2 +-\n notes-merge.c                      |   4 +-\n path.c                             |  15 +-\n pathspec.c                         | 431 +++++++++++++++++++++++++++++++++----\n pathspec.h                         |  59 ++++-\n preload-index.c                    |  21 +-\n read-cache.c                       |   5 +-\n rerere.c                           |   7 +-\n rerere.h                           |   4 +-\n resolve-undo.c                     |   4 +-\n resolve-undo.h                     |   2 +-\n revision.c                         |  11 +-\n setup.c                            | 157 +-------------\n t/t0008-ignores.sh                 |   8 +-\n t/t6130-pathspec-noglob.sh         |  18 ++\n tree-diff.c                        |  48 +++--\n tree-walk.c                        |  21 +-\n tree.c                             |   4 +-\n tree.h                             |   2 +-\n wt-status.c                        |  18 +-\n wt-status.h                        |   2 +-\n 50 files changed, 983 insertions(+), 772 deletions(-)\n\n-- \n1.8.0.rc0.19.g7bbb31d\n"},{"id":"211345","messageId":"1363327620-29017-2-git-send-email-pclouds@gmail.com","threadId":"33187","inReplyTo":"1363327620-29017-1-git-send-email-pclouds@gmail.com","subject":"[PATCH v1 01/45] setup.c: check that the pathspec magic ends with \")\"","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2013-03-15T06:06:16Z","receivedAt":"2013-03-15T06:06:16Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"From: Andrew Wong <andrew.kw.w@gmail.com>\n\nThe previous code did not diagnose an incorrectly spelled \":(top\"\nas an error.\n\nSigned-off-by: Andrew Wong <andrew.kw.w@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n setup.c | 5 +++--\n 1 file changed, 3 insertions(+), 2 deletions(-)\n\ndiff --git a/setup.c b/setup.c\nindex 1dee47e..d0cd784 100644\n--- a/setup.c\n+++ b/setup.c\n@@ -223,8 +223,9 @@ static const char *prefix_pathspec(const char *prefix, int prefixlen, const char\n \t\t\t\tdie(\"Invalid pathspec magic '%.*s' in '%s'\",\n \t\t\t\t    (int) len, copyfrom, elt);\n \t\t}\n-\t\tif (*copyfrom == ')')\n-\t\t\tcopyfrom++;\n+\t\tif (*copyfrom != ')')\n+\t\t\tdie(\"Missing ')' at the end of pathspec magic in '%s'\", elt);\n+\t\tcopyfrom++;\n \t} else {\n \t\t/* shorthand */\n \t\tfor (copyfrom = elt + 1;\n-- \n1.8.0.rc0.19.g7bbb31d\n"},{"id":"211346","messageId":"1363327620-29017-3-git-send-email-pclouds@gmail.com","threadId":"33187","inReplyTo":"1363327620-29017-1-git-send-email-pclouds@gmail.com","subject":"[PATCH v1 02/45] clean: remove unused variable \"seen\"","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2013-03-15T06:06:17Z","receivedAt":"2013-03-15T06:06:17Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n builtin/clean.c | 11 ++---------\n 1 file changed, 2 insertions(+), 9 deletions(-)\n\ndiff --git a/builtin/clean.c b/builtin/clean.c\nindex 04e396b..f955a40 100644\n--- a/builtin/clean.c\n+++ b/builtin/clean.c\n@@ -155,7 +155,6 @@ int cmd_clean(int argc, const char **argv, const char *prefix)\n \tstruct string_list exclude_list = STRING_LIST_INIT_NODUP;\n \tstruct exclude_list *el;\n \tconst char *qname;\n-\tchar *seen = NULL;\n \tstruct option options[] = {\n \t\tOPT__QUIET(&quiet, N_(\"do not print names of files removed\")),\n \t\tOPT__DRY_RUN(&dry_run, N_(\"dry run\")),\n@@ -214,9 +213,6 @@ int cmd_clean(int argc, const char **argv, const char *prefix)\n \n \tfill_directory(&dir, pathspec);\n \n-\tif (pathspec)\n-\t\tseen = xmalloc(argc > 0 ? argc : 1);\n-\n \tfor (i = 0; i < dir.nr; i++) {\n \t\tstruct dir_entry *ent = dir.entries[i];\n \t\tint len, pos;\n@@ -250,11 +246,9 @@ int cmd_clean(int argc, const char **argv, const char *prefix)\n \t\tif (lstat(ent->name, &st))\n \t\t\tcontinue;\n \n-\t\tif (pathspec) {\n-\t\t\tmemset(seen, 0, argc > 0 ? argc : 1);\n+\t\tif (pathspec)\n \t\t\tmatches = match_pathspec(pathspec, ent->name, len,\n-\t\t\t\t\t\t 0, seen);\n-\t\t}\n+\t\t\t\t\t\t 0, NULL);\n \n \t\tif (S_ISDIR(st.st_mode)) {\n \t\t\tstrbuf_addstr(&directory, ent->name);\n@@ -281,7 +275,6 @@ int cmd_clean(int argc, const char **argv, const char *prefix)\n \t\t\t}\n \t\t}\n \t}\n-\tfree(seen);\n \n \tstrbuf_release(&directory);\n \tstring_list_clear(&exclude_list, 0);\n-- \n1.8.0.rc0.19.g7bbb31d\n"},{"id":"211347","messageId":"1363327620-29017-4-git-send-email-pclouds@gmail.com","threadId":"33187","inReplyTo":"1363327620-29017-1-git-send-email-pclouds@gmail.com","subject":"[PATCH v1 03/45] Move struct pathspec and related functions to pathspec.[ch]","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2013-03-15T06:06:18Z","receivedAt":"2013-03-15T06:06:18Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n archive.c              |   1 +\n builtin/grep.c         |   1 +\n builtin/ls-files.c     |   1 +\n builtin/ls-tree.c      |   1 +\n builtin/update-index.c |   1 +\n cache.h                |  22 +-------\n diff.h                 |   1 +\n dir.c                  |   1 +\n pathspec.c             | 149 +++++++++++++++++++++++++++++++++++++++++++++++++\n pathspec.h             |  21 +++++++\n preload-index.c        |   1 +\n setup.c                | 149 -------------------------------------------------\n tree-walk.c            |   1 +\n 13 files changed, 181 insertions(+), 169 deletions(-)\n\ndiff --git a/archive.c b/archive.c\nindex 93e00bb..72c6b0f 100644\n--- a/archive.c\n+++ b/archive.c\n@@ -5,6 +5,7 @@\n #include \"archive.h\"\n #include \"parse-options.h\"\n #include \"unpack-trees.h\"\n+#include \"pathspec.h\"\n \n static char const * const archive_usage[] = {\n \tN_(\"git archive [options] <tree-ish> [<path>...]\"),\ndiff --git a/builtin/grep.c b/builtin/grep.c\nindex 8025964..3701c2e 100644\n--- a/builtin/grep.c\n+++ b/builtin/grep.c\n@@ -17,6 +17,7 @@\n #include \"grep.h\"\n #include \"quote.h\"\n #include \"dir.h\"\n+#include \"pathspec.h\"\n \n static char const * const grep_usage[] = {\n \tN_(\"git grep [options] [-e] <pattern> [<rev>...] [[--] <path>...]\"),\ndiff --git a/builtin/ls-files.c b/builtin/ls-files.c\nindex 175e6e3..752570b 100644\n--- a/builtin/ls-files.c\n+++ b/builtin/ls-files.c\n@@ -13,6 +13,7 @@\n #include \"parse-options.h\"\n #include \"resolve-undo.h\"\n #include \"string-list.h\"\n+#include \"pathspec.h\"\n \n static int abbrev;\n static int show_deleted;\ndiff --git a/builtin/ls-tree.c b/builtin/ls-tree.c\nindex fb76e38..93fc3a0 100644\n--- a/builtin/ls-tree.c\n+++ b/builtin/ls-tree.c\n@@ -10,6 +10,7 @@\n #include \"quote.h\"\n #include \"builtin.h\"\n #include \"parse-options.h\"\n+#include \"pathspec.h\"\n \n static int line_termination = '\\n';\n #define LS_RECURSIVE 1\ndiff --git a/builtin/update-index.c b/builtin/update-index.c\nindex ada1dff..ffae585 100644\n--- a/builtin/update-index.c\n+++ b/builtin/update-index.c\n@@ -11,6 +11,7 @@\n #include \"refs.h\"\n #include \"resolve-undo.h\"\n #include \"parse-options.h\"\n+#include \"pathspec.h\"\n \n /*\n  * Default to not allowing changes to the list of files. The\ndiff --git a/cache.h b/cache.h\nindex e493563..5115c1b 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -182,6 +182,8 @@ struct cache_entry {\n #error \"CE_EXTENDED_FLAGS out of range\"\n #endif\n \n+struct pathspec;\n+\n /*\n  * Copy the sha1 and stat state of a cache entry from one to\n  * another. But we never change the name, or the hash state!\n@@ -474,28 +476,8 @@ extern int index_name_is_other(const struct index_state *, const char *, int);\n extern int ie_match_stat(const struct index_state *, struct cache_entry *, struct stat *, unsigned int);\n extern int ie_modified(const struct index_state *, struct cache_entry *, struct stat *, unsigned int);\n \n-#define PATHSPEC_ONESTAR 1\t/* the pathspec pattern sastisfies GFNM_ONESTAR */\n-\n-struct pathspec {\n-\tconst char **raw; /* get_pathspec() result, not freed by free_pathspec() */\n-\tint nr;\n-\tunsigned int has_wildcard:1;\n-\tunsigned int recursive:1;\n-\tint max_depth;\n-\tstruct pathspec_item {\n-\t\tconst char *match;\n-\t\tint len;\n-\t\tint nowildcard_len;\n-\t\tint flags;\n-\t} *items;\n-};\n-\n-extern int init_pathspec(struct pathspec *, const char **);\n-extern void free_pathspec(struct pathspec *);\n extern int ce_path_match(const struct cache_entry *ce, const struct pathspec *pathspec);\n \n-extern int limit_pathspec_to_literal(void);\n-\n #define HASH_WRITE_OBJECT 1\n #define HASH_FORMAT_CHECK 2\n extern int index_fd(unsigned char *sha1, int fd, struct stat *st, enum object_type type, const char *path, unsigned flags);\ndiff --git a/diff.h b/diff.h\nindex 78b4091..d1bc914 100644\n--- a/diff.h\n+++ b/diff.h\n@@ -5,6 +5,7 @@\n #define DIFF_H\n \n #include \"tree-walk.h\"\n+#include \"pathspec.h\"\n \n struct rev_info;\n struct diff_options;\ndiff --git a/dir.c b/dir.c\nindex 57394e4..97ad45b 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -11,6 +11,7 @@\n #include \"dir.h\"\n #include \"refs.h\"\n #include \"wildmatch.h\"\n+#include \"pathspec.h\"\n \n struct path_simplify {\n \tint len;\ndiff --git a/pathspec.c b/pathspec.c\nindex 284f397..aa3e4d0 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -99,3 +99,152 @@ void die_if_path_beyond_symlink(const char *path, const char *prefix)\n \t\tdie(_(\"'%s' is beyond a symbolic link\"), path + len);\n \t}\n }\n+\n+/*\n+ * Magic pathspec\n+ *\n+ * NEEDSWORK: These need to be moved to dir.h or even to a new\n+ * pathspec.h when we restructure get_pathspec() users to use the\n+ * \"struct pathspec\" interface.\n+ *\n+ * Possible future magic semantics include stuff like:\n+ *\n+ *\t{ PATHSPEC_NOGLOB, '!', \"noglob\" },\n+ *\t{ PATHSPEC_ICASE, '\\0', \"icase\" },\n+ *\t{ PATHSPEC_RECURSIVE, '*', \"recursive\" },\n+ *\t{ PATHSPEC_REGEXP, '\\0', \"regexp\" },\n+ *\n+ */\n+#define PATHSPEC_FROMTOP    (1<<0)\n+\n+static struct pathspec_magic {\n+\tunsigned bit;\n+\tchar mnemonic; /* this cannot be ':'! */\n+\tconst char *name;\n+} pathspec_magic[] = {\n+\t{ PATHSPEC_FROMTOP, '/', \"top\" },\n+};\n+\n+/*\n+ * Take an element of a pathspec and check for magic signatures.\n+ * Append the result to the prefix.\n+ *\n+ * For now, we only parse the syntax and throw out anything other than\n+ * \"top\" magic.\n+ *\n+ * NEEDSWORK: This needs to be rewritten when we start migrating\n+ * get_pathspec() users to use the \"struct pathspec\" interface.  For\n+ * example, a pathspec element may be marked as case-insensitive, but\n+ * the prefix part must always match literally, and a single stupid\n+ * string cannot express such a case.\n+ */\n+static const char *prefix_pathspec(const char *prefix, int prefixlen, const char *elt)\n+{\n+\tunsigned magic = 0;\n+\tconst char *copyfrom = elt;\n+\tint i;\n+\n+\tif (elt[0] != ':') {\n+\t\t; /* nothing to do */\n+\t} else if (elt[1] == '(') {\n+\t\t/* longhand */\n+\t\tconst char *nextat;\n+\t\tfor (copyfrom = elt + 2;\n+\t\t     *copyfrom && *copyfrom != ')';\n+\t\t     copyfrom = nextat) {\n+\t\t\tsize_t len = strcspn(copyfrom, \",)\");\n+\t\t\tif (copyfrom[len] == ')')\n+\t\t\t\tnextat = copyfrom + len;\n+\t\t\telse\n+\t\t\t\tnextat = copyfrom + len + 1;\n+\t\t\tif (!len)\n+\t\t\t\tcontinue;\n+\t\t\tfor (i = 0; i < ARRAY_SIZE(pathspec_magic); i++)\n+\t\t\t\tif (strlen(pathspec_magic[i].name) == len &&\n+\t\t\t\t    !strncmp(pathspec_magic[i].name, copyfrom, len)) {\n+\t\t\t\t\tmagic |= pathspec_magic[i].bit;\n+\t\t\t\t\tbreak;\n+\t\t\t\t}\n+\t\t\tif (ARRAY_SIZE(pathspec_magic) <= i)\n+\t\t\t\tdie(\"Invalid pathspec magic '%.*s' in '%s'\",\n+\t\t\t\t    (int) len, copyfrom, elt);\n+\t\t}\n+\t\tif (*copyfrom != ')')\n+\t\t\tdie(\"Missing ')' at the end of pathspec magic in '%s'\", elt);\n+\t\tcopyfrom++;\n+\t} else {\n+\t\t/* shorthand */\n+\t\tfor (copyfrom = elt + 1;\n+\t\t     *copyfrom && *copyfrom != ':';\n+\t\t     copyfrom++) {\n+\t\t\tchar ch = *copyfrom;\n+\n+\t\t\tif (!is_pathspec_magic(ch))\n+\t\t\t\tbreak;\n+\t\t\tfor (i = 0; i < ARRAY_SIZE(pathspec_magic); i++)\n+\t\t\t\tif (pathspec_magic[i].mnemonic == ch) {\n+\t\t\t\t\tmagic |= pathspec_magic[i].bit;\n+\t\t\t\t\tbreak;\n+\t\t\t\t}\n+\t\t\tif (ARRAY_SIZE(pathspec_magic) <= i)\n+\t\t\t\tdie(\"Unimplemented pathspec magic '%c' in '%s'\",\n+\t\t\t\t    ch, elt);\n+\t\t}\n+\t\tif (*copyfrom == ':')\n+\t\t\tcopyfrom++;\n+\t}\n+\n+\tif (magic & PATHSPEC_FROMTOP)\n+\t\treturn xstrdup(copyfrom);\n+\telse\n+\t\treturn prefix_path(prefix, prefixlen, copyfrom);\n+}\n+\n+/*\n+ * N.B. get_pathspec() is deprecated in favor of the \"struct pathspec\"\n+ * based interface - see pathspec_magic above.\n+ *\n+ * Arguments:\n+ *  - prefix - a path relative to the root of the working tree\n+ *  - pathspec - a list of paths underneath the prefix path\n+ *\n+ * Iterates over pathspec, prepending each path with prefix,\n+ * and return the resulting list.\n+ *\n+ * If pathspec is empty, return a singleton list containing prefix.\n+ *\n+ * If pathspec and prefix are both empty, return an empty list.\n+ *\n+ * This is typically used by built-in commands such as add.c, in order\n+ * to normalize argv arguments provided to the built-in into a list of\n+ * paths to process, all relative to the root of the working tree.\n+ */\n+const char **get_pathspec(const char *prefix, const char **pathspec)\n+{\n+\tconst char *entry = *pathspec;\n+\tconst char **src, **dst;\n+\tint prefixlen;\n+\n+\tif (!prefix && !entry)\n+\t\treturn NULL;\n+\n+\tif (!entry) {\n+\t\tstatic const char *spec[2];\n+\t\tspec[0] = prefix;\n+\t\tspec[1] = NULL;\n+\t\treturn spec;\n+\t}\n+\n+\t/* Otherwise we have to re-write the entries.. */\n+\tsrc = pathspec;\n+\tdst = pathspec;\n+\tprefixlen = prefix ? strlen(prefix) : 0;\n+\twhile (*src) {\n+\t\t*(dst++) = prefix_pathspec(prefix, prefixlen, *src);\n+\t\tsrc++;\n+\t}\n+\t*dst = NULL;\n+\tif (!*pathspec)\n+\t\treturn NULL;\n+\treturn pathspec;\n+}\ndiff --git a/pathspec.h b/pathspec.h\nindex db0184a..7884068 100644\n--- a/pathspec.h\n+++ b/pathspec.h\n@@ -1,6 +1,27 @@\n #ifndef PATHSPEC_H\n #define PATHSPEC_H\n \n+#define PATHSPEC_ONESTAR 1\t/* the pathspec pattern sastisfies GFNM_ONESTAR */\n+\n+struct pathspec {\n+\tconst char **raw; /* get_pathspec() result, not freed by free_pathspec() */\n+\tint nr;\n+\tunsigned int has_wildcard:1;\n+\tunsigned int recursive:1;\n+\tint max_depth;\n+\tstruct pathspec_item {\n+\t\tconst char *match;\n+\t\tint len;\n+\t\tint nowildcard_len;\n+\t\tint flags;\n+\t} *items;\n+};\n+\n+extern int init_pathspec(struct pathspec *, const char **);\n+extern void free_pathspec(struct pathspec *);\n+\n+extern int limit_pathspec_to_literal(void);\n+\n extern char *find_pathspecs_matching_against_index(const char **pathspec);\n extern void add_pathspec_matches_against_index(const char **pathspec, char *seen, int specs);\n extern const char *check_path_for_gitlink(const char *path);\ndiff --git a/preload-index.c b/preload-index.c\nindex 49cb08d..cddfffa 100644\n--- a/preload-index.c\n+++ b/preload-index.c\n@@ -2,6 +2,7 @@\n  * Copyright (C) 2008 Linus Torvalds\n  */\n #include \"cache.h\"\n+#include \"pathspec.h\"\n \n #ifdef NO_PTHREADS\n static void preload_index(struct index_state *index, const char **pathspec)\ndiff --git a/setup.c b/setup.c\nindex d0cd784..acdc634 100644\n--- a/setup.c\n+++ b/setup.c\n@@ -155,155 +155,6 @@ void verify_non_filename(const char *prefix, const char *arg)\n }\n \n /*\n- * Magic pathspec\n- *\n- * NEEDSWORK: These need to be moved to dir.h or even to a new\n- * pathspec.h when we restructure get_pathspec() users to use the\n- * \"struct pathspec\" interface.\n- *\n- * Possible future magic semantics include stuff like:\n- *\n- *\t{ PATHSPEC_NOGLOB, '!', \"noglob\" },\n- *\t{ PATHSPEC_ICASE, '\\0', \"icase\" },\n- *\t{ PATHSPEC_RECURSIVE, '*', \"recursive\" },\n- *\t{ PATHSPEC_REGEXP, '\\0', \"regexp\" },\n- *\n- */\n-#define PATHSPEC_FROMTOP    (1<<0)\n-\n-static struct pathspec_magic {\n-\tunsigned bit;\n-\tchar mnemonic; /* this cannot be ':'! */\n-\tconst char *name;\n-} pathspec_magic[] = {\n-\t{ PATHSPEC_FROMTOP, '/', \"top\" },\n-};\n-\n-/*\n- * Take an element of a pathspec and check for magic signatures.\n- * Append the result to the prefix.\n- *\n- * For now, we only parse the syntax and throw out anything other than\n- * \"top\" magic.\n- *\n- * NEEDSWORK: This needs to be rewritten when we start migrating\n- * get_pathspec() users to use the \"struct pathspec\" interface.  For\n- * example, a pathspec element may be marked as case-insensitive, but\n- * the prefix part must always match literally, and a single stupid\n- * string cannot express such a case.\n- */\n-static const char *prefix_pathspec(const char *prefix, int prefixlen, const char *elt)\n-{\n-\tunsigned magic = 0;\n-\tconst char *copyfrom = elt;\n-\tint i;\n-\n-\tif (elt[0] != ':') {\n-\t\t; /* nothing to do */\n-\t} else if (elt[1] == '(') {\n-\t\t/* longhand */\n-\t\tconst char *nextat;\n-\t\tfor (copyfrom = elt + 2;\n-\t\t     *copyfrom && *copyfrom != ')';\n-\t\t     copyfrom = nextat) {\n-\t\t\tsize_t len = strcspn(copyfrom, \",)\");\n-\t\t\tif (copyfrom[len] == ')')\n-\t\t\t\tnextat = copyfrom + len;\n-\t\t\telse\n-\t\t\t\tnextat = copyfrom + len + 1;\n-\t\t\tif (!len)\n-\t\t\t\tcontinue;\n-\t\t\tfor (i = 0; i < ARRAY_SIZE(pathspec_magic); i++)\n-\t\t\t\tif (strlen(pathspec_magic[i].name) == len &&\n-\t\t\t\t    !strncmp(pathspec_magic[i].name, copyfrom, len)) {\n-\t\t\t\t\tmagic |= pathspec_magic[i].bit;\n-\t\t\t\t\tbreak;\n-\t\t\t\t}\n-\t\t\tif (ARRAY_SIZE(pathspec_magic) <= i)\n-\t\t\t\tdie(\"Invalid pathspec magic '%.*s' in '%s'\",\n-\t\t\t\t    (int) len, copyfrom, elt);\n-\t\t}\n-\t\tif (*copyfrom != ')')\n-\t\t\tdie(\"Missing ')' at the end of pathspec magic in '%s'\", elt);\n-\t\tcopyfrom++;\n-\t} else {\n-\t\t/* shorthand */\n-\t\tfor (copyfrom = elt + 1;\n-\t\t     *copyfrom && *copyfrom != ':';\n-\t\t     copyfrom++) {\n-\t\t\tchar ch = *copyfrom;\n-\n-\t\t\tif (!is_pathspec_magic(ch))\n-\t\t\t\tbreak;\n-\t\t\tfor (i = 0; i < ARRAY_SIZE(pathspec_magic); i++)\n-\t\t\t\tif (pathspec_magic[i].mnemonic == ch) {\n-\t\t\t\t\tmagic |= pathspec_magic[i].bit;\n-\t\t\t\t\tbreak;\n-\t\t\t\t}\n-\t\t\tif (ARRAY_SIZE(pathspec_magic) <= i)\n-\t\t\t\tdie(\"Unimplemented pathspec magic '%c' in '%s'\",\n-\t\t\t\t    ch, elt);\n-\t\t}\n-\t\tif (*copyfrom == ':')\n-\t\t\tcopyfrom++;\n-\t}\n-\n-\tif (magic & PATHSPEC_FROMTOP)\n-\t\treturn xstrdup(copyfrom);\n-\telse\n-\t\treturn prefix_path(prefix, prefixlen, copyfrom);\n-}\n-\n-/*\n- * N.B. get_pathspec() is deprecated in favor of the \"struct pathspec\"\n- * based interface - see pathspec_magic above.\n- *\n- * Arguments:\n- *  - prefix - a path relative to the root of the working tree\n- *  - pathspec - a list of paths underneath the prefix path\n- *\n- * Iterates over pathspec, prepending each path with prefix,\n- * and return the resulting list.\n- *\n- * If pathspec is empty, return a singleton list containing prefix.\n- *\n- * If pathspec and prefix are both empty, return an empty list.\n- *\n- * This is typically used by built-in commands such as add.c, in order\n- * to normalize argv arguments provided to the built-in into a list of\n- * paths to process, all relative to the root of the working tree.\n- */\n-const char **get_pathspec(const char *prefix, const char **pathspec)\n-{\n-\tconst char *entry = *pathspec;\n-\tconst char **src, **dst;\n-\tint prefixlen;\n-\n-\tif (!prefix && !entry)\n-\t\treturn NULL;\n-\n-\tif (!entry) {\n-\t\tstatic const char *spec[2];\n-\t\tspec[0] = prefix;\n-\t\tspec[1] = NULL;\n-\t\treturn spec;\n-\t}\n-\n-\t/* Otherwise we have to re-write the entries.. */\n-\tsrc = pathspec;\n-\tdst = pathspec;\n-\tprefixlen = prefix ? strlen(prefix) : 0;\n-\twhile (*src) {\n-\t\t*(dst++) = prefix_pathspec(prefix, prefixlen, *src);\n-\t\tsrc++;\n-\t}\n-\t*dst = NULL;\n-\tif (!*pathspec)\n-\t\treturn NULL;\n-\treturn pathspec;\n-}\n-\n-/*\n  * Test if it looks like we're at a git directory.\n  * We want to see:\n  *\ndiff --git a/tree-walk.c b/tree-walk.c\nindex 6e30ef9..72a9613 100644\n--- a/tree-walk.c\n+++ b/tree-walk.c\n@@ -3,6 +3,7 @@\n #include \"unpack-trees.h\"\n #include \"dir.h\"\n #include \"tree.h\"\n+#include \"pathspec.h\"\n \n static const char *get_mode(const char *str, unsigned int *modep)\n {\n-- \n1.8.0.rc0.19.g7bbb31d\n"},{"id":"211348","messageId":"1363327620-29017-5-git-send-email-pclouds@gmail.com","threadId":"33187","inReplyTo":"1363327620-29017-1-git-send-email-pclouds@gmail.com","subject":"[PATCH v1 04/45] pathspec: i18n-ize error strings in pathspec parsing code","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2013-03-15T06:06:19Z","receivedAt":"2013-03-15T06:06:19Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n pathspec.c | 6 +++---\n 1 file changed, 3 insertions(+), 3 deletions(-)\n\ndiff --git a/pathspec.c b/pathspec.c\nindex aa3e4d0..94d64d2 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -166,11 +166,11 @@ static const char *prefix_pathspec(const char *prefix, int prefixlen, const char\n \t\t\t\t\tbreak;\n \t\t\t\t}\n \t\t\tif (ARRAY_SIZE(pathspec_magic) <= i)\n-\t\t\t\tdie(\"Invalid pathspec magic '%.*s' in '%s'\",\n+\t\t\t\tdie(_(\"Invalid pathspec magic '%.*s' in '%s'\"),\n \t\t\t\t    (int) len, copyfrom, elt);\n \t\t}\n \t\tif (*copyfrom != ')')\n-\t\t\tdie(\"Missing ')' at the end of pathspec magic in '%s'\", elt);\n+\t\t\tdie(_(\"Missing ')' at the end of pathspec magic in '%s'\"), elt);\n \t\tcopyfrom++;\n \t} else {\n \t\t/* shorthand */\n@@ -187,7 +187,7 @@ static const char *prefix_pathspec(const char *prefix, int prefixlen, const char\n \t\t\t\t\tbreak;\n \t\t\t\t}\n \t\t\tif (ARRAY_SIZE(pathspec_magic) <= i)\n-\t\t\t\tdie(\"Unimplemented pathspec magic '%c' in '%s'\",\n+\t\t\t\tdie(_(\"Unimplemented pathspec magic '%c' in '%s'\"),\n \t\t\t\t    ch, elt);\n \t\t}\n \t\tif (*copyfrom == ':')\n-- \n1.8.0.rc0.19.g7bbb31d\n"},{"id":"211349","messageId":"1363327620-29017-6-git-send-email-pclouds@gmail.com","threadId":"33187","inReplyTo":"1363327620-29017-1-git-send-email-pclouds@gmail.com","subject":"[PATCH v1 05/45] pathspec: add copy_pathspec","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2013-03-15T06:06:20Z","receivedAt":"2013-03-15T06:06:20Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"The function is made to use with free_pathspec() because a simple\nstruct assignment is not enough (free_pathspec wants to free \"items\"\npointer).\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n builtin/mv.c | 13 +++++++------\n pathspec.c   |  8 ++++++++\n pathspec.h   |  1 +\n 3 files changed, 16 insertions(+), 6 deletions(-)\n\ndiff --git a/builtin/mv.c b/builtin/mv.c\nindex 034fec9..16ce99b 100644\n--- a/builtin/mv.c\n+++ b/builtin/mv.c\n@@ -15,8 +15,9 @@ static const char * const builtin_mv_usage[] = {\n \tNULL\n };\n \n-static const char **copy_pathspec(const char *prefix, const char **pathspec,\n-\t\t\t\t  int count, int base_name)\n+static const char **internal_copy_pathspec(const char *prefix,\n+\t\t\t\t\t   const char **pathspec,\n+\t\t\t\t\t   int count, int base_name)\n {\n \tint i;\n \tconst char **result = xmalloc((count + 1) * sizeof(const char *));\n@@ -81,17 +82,17 @@ int cmd_mv(int argc, const char **argv, const char *prefix)\n \tif (read_cache() < 0)\n \t\tdie(_(\"index file corrupt\"));\n \n-\tsource = copy_pathspec(prefix, argv, argc, 0);\n+\tsource = internal_copy_pathspec(prefix, argv, argc, 0);\n \tmodes = xcalloc(argc, sizeof(enum update_mode));\n-\tdest_path = copy_pathspec(prefix, argv + argc, 1, 0);\n+\tdest_path = internal_copy_pathspec(prefix, argv + argc, 1, 0);\n \n \tif (dest_path[0][0] == '\\0')\n \t\t/* special case: \".\" was normalized to \"\" */\n-\t\tdestination = copy_pathspec(dest_path[0], argv, argc, 1);\n+\t\tdestination = internal_copy_pathspec(dest_path[0], argv, argc, 1);\n \telse if (!lstat(dest_path[0], &st) &&\n \t\t\tS_ISDIR(st.st_mode)) {\n \t\tdest_path[0] = add_slash(dest_path[0]);\n-\t\tdestination = copy_pathspec(dest_path[0], argv, argc, 1);\n+\t\tdestination = internal_copy_pathspec(dest_path[0], argv, argc, 1);\n \t} else {\n \t\tif (argc != 1)\n \t\t\tdie(\"destination '%s' is not a directory\", dest_path[0]);\ndiff --git a/pathspec.c b/pathspec.c\nindex 94d64d2..ab53b8a 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -248,3 +248,11 @@ const char **get_pathspec(const char *prefix, const char **pathspec)\n \t\treturn NULL;\n \treturn pathspec;\n }\n+\n+void copy_pathspec(struct pathspec *dst, const struct pathspec *src)\n+{\n+\t*dst = *src;\n+\tdst->items = xmalloc(sizeof(struct pathspec_item) * dst->nr);\n+\tmemcpy(dst->items, src->items,\n+\t       sizeof(struct pathspec_item) * dst->nr);\n+}\ndiff --git a/pathspec.h b/pathspec.h\nindex 7884068..a621676 100644\n--- a/pathspec.h\n+++ b/pathspec.h\n@@ -18,6 +18,7 @@ struct pathspec {\n };\n \n extern int init_pathspec(struct pathspec *, const char **);\n+extern void copy_pathspec(struct pathspec *dst, const struct pathspec *src);\n extern void free_pathspec(struct pathspec *);\n \n extern int limit_pathspec_to_literal(void);\n-- \n1.8.0.rc0.19.g7bbb31d\n"},{"id":"211351","messageId":"1363327620-29017-7-git-send-email-pclouds@gmail.com","threadId":"33187","inReplyTo":"1363327620-29017-1-git-send-email-pclouds@gmail.com","subject":"[PATCH v1 06/45] Add parse_pathspec() that converts cmdline args to struct pathspec","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2013-03-15T06:06:21Z","receivedAt":"2013-03-15T06:06:21Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Currently to fill a struct pathspec, we do:\n\n   const char **paths;\n   paths = get_pathspec(prefix, argv);\n   ...\n   init_pathspec(&pathspec, paths);\n\n\"paths\" can only carry bare strings, which loses information from\ncommand line arguments such as pathspec magic or the prefix part's\nlength for each argument.\n\nparse_pathspec() is introduced to combine the two calls into one. The\nplan is gradually replace all get_pathspec() and init_pathspec() with\nparse_pathspec(). get_pathspec() now becomes a thin wrapper of\nparse_pathspec().\n\nparse_pathspec() allows the caller to reject the pathspec magics that\nit does not support. When a new pathspec magic is introduced, we can\nenable it per command after making sure that all underlying code has no\nproblem with the new magic.\n\n\"flags\" parameter is currently unused. But it would allow callers to\npass certain instructions to parse_pathspec, for example forcing\nliteral pathspec when no magic is used.\n\nWith the introduction of parse_pathspec, there are now two functions\nthat can initialize struct pathspec: init_pathspec and\nparse_pathspec. Any semantic changes in struct pathspec must be\nreflected in both functions. init_pathspec() will be phased out in\nfavor of parse_pathspec().\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n dir.c      |   4 +-\n dir.h      |   2 +\n pathspec.c | 167 +++++++++++++++++++++++++++++++++++++++++++++++--------------\n pathspec.h |  11 ++++\n 4 files changed, 144 insertions(+), 40 deletions(-)\n\ndiff --git a/dir.c b/dir.c\nindex 97ad45b..a442467 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -338,7 +338,7 @@ int match_pathspec_depth(const struct pathspec *ps,\n /*\n  * Return the length of the \"simple\" part of a path match limiter.\n  */\n-static int simple_length(const char *match)\n+int simple_length(const char *match)\n {\n \tint len = -1;\n \n@@ -350,7 +350,7 @@ static int simple_length(const char *match)\n \t}\n }\n \n-static int no_wildcard(const char *string)\n+int no_wildcard(const char *string)\n {\n \treturn string[simple_length(string)] == '\\0';\n }\ndiff --git a/dir.h b/dir.h\nindex c3eb4b5..89427fd 100644\n--- a/dir.h\n+++ b/dir.h\n@@ -125,6 +125,8 @@ struct dir_struct {\n #define MATCHED_RECURSIVELY 1\n #define MATCHED_FNMATCH 2\n #define MATCHED_EXACTLY 3\n+extern int simple_length(const char *match);\n+extern int no_wildcard(const char *string);\n extern char *common_prefix(const char **pathspec);\n extern int match_pathspec(const char **pathspec, const char *name, int namelen, int prefix, char *seen);\n extern int match_pathspec_depth(const struct pathspec *pathspec,\ndiff --git a/pathspec.c b/pathspec.c\nindex ab53b8a..bc9d9ac 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -103,10 +103,6 @@ void die_if_path_beyond_symlink(const char *path, const char *prefix)\n /*\n  * Magic pathspec\n  *\n- * NEEDSWORK: These need to be moved to dir.h or even to a new\n- * pathspec.h when we restructure get_pathspec() users to use the\n- * \"struct pathspec\" interface.\n- *\n  * Possible future magic semantics include stuff like:\n  *\n  *\t{ PATHSPEC_NOGLOB, '!', \"noglob\" },\n@@ -115,7 +111,6 @@ void die_if_path_beyond_symlink(const char *path, const char *prefix)\n  *\t{ PATHSPEC_REGEXP, '\\0', \"regexp\" },\n  *\n  */\n-#define PATHSPEC_FROMTOP    (1<<0)\n \n static struct pathspec_magic {\n \tunsigned bit;\n@@ -127,7 +122,7 @@ static struct pathspec_magic {\n \n /*\n  * Take an element of a pathspec and check for magic signatures.\n- * Append the result to the prefix.\n+ * Append the result to the prefix. Return the magic bitmap.\n  *\n  * For now, we only parse the syntax and throw out anything other than\n  * \"top\" magic.\n@@ -138,10 +133,15 @@ static struct pathspec_magic {\n  * the prefix part must always match literally, and a single stupid\n  * string cannot express such a case.\n  */\n-static const char *prefix_pathspec(const char *prefix, int prefixlen, const char *elt)\n+static unsigned prefix_pathspec(struct pathspec_item *item,\n+\t\t\t\tunsigned *p_short_magic,\n+\t\t\t\tconst char **raw, unsigned flags,\n+\t\t\t\tconst char *prefix, int prefixlen,\n+\t\t\t\tconst char *elt)\n {\n-\tunsigned magic = 0;\n+\tunsigned magic = 0, short_magic = 0;\n \tconst char *copyfrom = elt;\n+\tchar *match;\n \tint i;\n \n \tif (elt[0] != ':') {\n@@ -183,7 +183,7 @@ static const char *prefix_pathspec(const char *prefix, int prefixlen, const char\n \t\t\t\tbreak;\n \t\t\tfor (i = 0; i < ARRAY_SIZE(pathspec_magic); i++)\n \t\t\t\tif (pathspec_magic[i].mnemonic == ch) {\n-\t\t\t\t\tmagic |= pathspec_magic[i].bit;\n+\t\t\t\t\tshort_magic |= pathspec_magic[i].bit;\n \t\t\t\t\tbreak;\n \t\t\t\t}\n \t\t\tif (ARRAY_SIZE(pathspec_magic) <= i)\n@@ -194,15 +194,127 @@ static const char *prefix_pathspec(const char *prefix, int prefixlen, const char\n \t\t\tcopyfrom++;\n \t}\n \n+\tmagic |= short_magic;\n+\t*p_short_magic = short_magic;\n+\n \tif (magic & PATHSPEC_FROMTOP)\n-\t\treturn xstrdup(copyfrom);\n+\t\tmatch = xstrdup(copyfrom);\n \telse\n-\t\treturn prefix_path(prefix, prefixlen, copyfrom);\n+\t\tmatch = prefix_path(prefix, prefixlen, copyfrom);\n+\t*raw = item->match = match;\n+\titem->len = strlen(item->match);\n+\tif (limit_pathspec_to_literal())\n+\t\titem->nowildcard_len = item->len;\n+\telse\n+\t\titem->nowildcard_len = simple_length(item->match);\n+\titem->flags = 0;\n+\tif (item->nowildcard_len < item->len &&\n+\t    item->match[item->nowildcard_len] == '*' &&\n+\t    no_wildcard(item->match + item->nowildcard_len + 1))\n+\t\titem->flags |= PATHSPEC_ONESTAR;\n+\treturn magic;\n+}\n+\n+static int pathspec_item_cmp(const void *a_, const void *b_)\n+{\n+\tstruct pathspec_item *a, *b;\n+\n+\ta = (struct pathspec_item *)a_;\n+\tb = (struct pathspec_item *)b_;\n+\treturn strcmp(a->match, b->match);\n+}\n+\n+static void NORETURN unsupported_magic(const char *pattern,\n+\t\t\t\t       unsigned magic,\n+\t\t\t\t       unsigned short_magic)\n+{\n+\tstruct strbuf sb = STRBUF_INIT;\n+\tint i, n;\n+\tfor (n = i = 0; i < ARRAY_SIZE(pathspec_magic); i++) {\n+\t\tconst struct pathspec_magic *m = pathspec_magic + i;\n+\t\tif (!(magic & m->bit))\n+\t\t\tcontinue;\n+\t\tif (sb.len)\n+\t\t\tstrbuf_addstr(&sb, \" \");\n+\t\tif (short_magic & m->bit)\n+\t\t\tstrbuf_addf(&sb, \"'%c'\", m->mnemonic);\n+\t\telse\n+\t\t\tstrbuf_addf(&sb, \"'%s'\", m->name);\n+\t\tn++;\n+\t}\n+\t/*\n+\t * We may want to substitue \"this command\" with a command\n+\t * name. E.g. when add--interactive dies when running\n+\t * \"checkout -p\"\n+\t */\n+\tdie(_(\"%s: pathspec magic not supported by this command: %s\"),\n+\t    pattern, sb.buf);\n+}\n+\n+/*\n+ * Given command line arguments and a prefix, convert the input to\n+ * pathspec. die() any magic in magic_mask is used.\n+ */\n+void parse_pathspec(struct pathspec *pathspec,\n+\t\t    unsigned magic_mask, unsigned flags,\n+\t\t    const char *prefix, const char **argv)\n+{\n+\tstruct pathspec_item *item;\n+\tconst char *entry = argv ? *argv : NULL;\n+\tint i, n, prefixlen;\n+\n+\tmemset(pathspec, 0, sizeof(*pathspec));\n+\n+\t/* No arguments, no prefix -> no pathspec */\n+\tif (!entry && !prefix)\n+\t\treturn;\n+\n+\t/* No arguments with prefix -> prefix pathspec */\n+\tif (!entry) {\n+\t\tstatic const char *raw[2];\n+\n+\t\tpathspec->items = item = xmalloc(sizeof(*item));\n+\t\titem->match = prefix;\n+\t\titem->nowildcard_len = item->len = strlen(prefix);\n+\t\traw[0] = prefix;\n+\t\traw[1] = NULL;\n+\t\tpathspec->nr = 1;\n+\t\tpathspec->raw = raw;\n+\t\treturn;\n+\t}\n+\n+\tn = 0;\n+\twhile (argv[n])\n+\t\tn++;\n+\n+\tpathspec->nr = n;\n+\tpathspec->items = item = xmalloc(sizeof(*item) * n);\n+\tpathspec->raw = argv;\n+\tprefixlen = prefix ? strlen(prefix) : 0;\n+\n+\tfor (i = 0; i < n; i++) {\n+\t\tunsigned short_magic;\n+\t\tentry = argv[i];\n+\n+\t\titem[i].magic = prefix_pathspec(item + i, &short_magic,\n+\t\t\t\t\t\targv + i, flags,\n+\t\t\t\t\t\tprefix, prefixlen, entry);\n+\t\tif (item[i].magic & magic_mask)\n+\t\t\tunsupported_magic(entry,\n+\t\t\t\t\t  item[i].magic & magic_mask,\n+\t\t\t\t\t  short_magic);\n+\t\tif (item[i].nowildcard_len < item[i].len)\n+\t\t\tpathspec->has_wildcard = 1;\n+\t\tpathspec->magic |= item[i].magic;\n+\t}\n+\n+\tqsort(pathspec->items, pathspec->nr,\n+\t      sizeof(struct pathspec_item), pathspec_item_cmp);\n }\n \n /*\n  * N.B. get_pathspec() is deprecated in favor of the \"struct pathspec\"\n- * based interface - see pathspec_magic above.\n+ * based interface - see pathspec.c:parse_pathspec().\n  *\n  * Arguments:\n  *  - prefix - a path relative to the root of the working tree\n@@ -221,32 +333,11 @@ static const char *prefix_pathspec(const char *prefix, int prefixlen, const char\n  */\n const char **get_pathspec(const char *prefix, const char **pathspec)\n {\n-\tconst char *entry = *pathspec;\n-\tconst char **src, **dst;\n-\tint prefixlen;\n-\n-\tif (!prefix && !entry)\n-\t\treturn NULL;\n-\n-\tif (!entry) {\n-\t\tstatic const char *spec[2];\n-\t\tspec[0] = prefix;\n-\t\tspec[1] = NULL;\n-\t\treturn spec;\n-\t}\n-\n-\t/* Otherwise we have to re-write the entries.. */\n-\tsrc = pathspec;\n-\tdst = pathspec;\n-\tprefixlen = prefix ? strlen(prefix) : 0;\n-\twhile (*src) {\n-\t\t*(dst++) = prefix_pathspec(prefix, prefixlen, *src);\n-\t\tsrc++;\n-\t}\n-\t*dst = NULL;\n-\tif (!*pathspec)\n-\t\treturn NULL;\n-\treturn pathspec;\n+\tstruct pathspec ps;\n+\tparse_pathspec(&ps,\n+\t\t       PATHSPEC_ALL_MAGIC & ~PATHSPEC_FROMTOP,\n+\t\t       0, prefix, pathspec);\n+\treturn ps.raw;\n }\n \n void copy_pathspec(struct pathspec *dst, const struct pathspec *src)\ndiff --git a/pathspec.h b/pathspec.h\nindex a621676..937ec91 100644\n--- a/pathspec.h\n+++ b/pathspec.h\n@@ -1,6 +1,10 @@\n #ifndef PATHSPEC_H\n #define PATHSPEC_H\n \n+/* Pathspec magic */\n+#define PATHSPEC_FROMTOP\t(1<<0)\n+#define PATHSPEC_ALL_MAGIC PATHSPEC_FROMTOP\n+\n #define PATHSPEC_ONESTAR 1\t/* the pathspec pattern sastisfies GFNM_ONESTAR */\n \n struct pathspec {\n@@ -8,9 +12,11 @@ struct pathspec {\n \tint nr;\n \tunsigned int has_wildcard:1;\n \tunsigned int recursive:1;\n+\tunsigned magic;\n \tint max_depth;\n \tstruct pathspec_item {\n \t\tconst char *match;\n+\t\tunsigned magic;\n \t\tint len;\n \t\tint nowildcard_len;\n \t\tint flags;\n@@ -18,6 +24,11 @@ struct pathspec {\n };\n \n extern int init_pathspec(struct pathspec *, const char **);\n+extern void parse_pathspec(struct pathspec *pathspec,\n+\t\t\t   unsigned magic_mask,\n+\t\t\t   unsigned flags,\n+\t\t\t   const char *prefix,\n+\t\t\t   const char **args);\n extern void copy_pathspec(struct pathspec *dst, const struct pathspec *src);\n extern void free_pathspec(struct pathspec *);\n \n-- \n1.8.0.rc0.19.g7bbb31d\n"},{"id":"211350","messageId":"1363327620-29017-8-git-send-email-pclouds@gmail.com","threadId":"33187","inReplyTo":"1363327620-29017-1-git-send-email-pclouds@gmail.com","subject":"[PATCH v1 07/45] parse_pathspec: save original pathspec for reporting","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2013-03-15T06:06:22Z","receivedAt":"2013-03-15T06:06:22Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"We usually use pathspec_item's match field for pathspec error\nreporting. However \"match\" (or \"raw\") does not show the magic part,\nwhich will play more important role later on. Preserve exact user\ninput for reporting.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n dir.c      | 1 +\n pathspec.c | 2 ++\n pathspec.h | 1 +\n 3 files changed, 4 insertions(+)\n\ndiff --git a/dir.c b/dir.c\nindex a442467..8541ea7 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -1649,6 +1649,7 @@ int init_pathspec(struct pathspec *pathspec, const char **paths)\n \t\tconst char *path = paths[i];\n \n \t\titem->match = path;\n+\t\titem->original = path;\n \t\titem->len = strlen(path);\n \t\titem->flags = 0;\n \t\tif (limit_pathspec_to_literal()) {\ndiff --git a/pathspec.c b/pathspec.c\nindex bc9d9ac..2bda633 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -202,6 +202,7 @@ static unsigned prefix_pathspec(struct pathspec_item *item,\n \telse\n \t\tmatch = prefix_path(prefix, prefixlen, copyfrom);\n \t*raw = item->match = match;\n+\titem->original = elt;\n \titem->len = strlen(item->match);\n \tif (limit_pathspec_to_literal())\n \t\titem->nowildcard_len = item->len;\n@@ -275,6 +276,7 @@ void parse_pathspec(struct pathspec *pathspec,\n \n \t\tpathspec->items = item = xmalloc(sizeof(*item));\n \t\titem->match = prefix;\n+\t\titem->original = prefix;\n \t\titem->nowildcard_len = item->len = strlen(prefix);\n \t\traw[0] = prefix;\n \t\traw[1] = NULL;\ndiff --git a/pathspec.h b/pathspec.h\nindex 937ec91..cc5841b 100644\n--- a/pathspec.h\n+++ b/pathspec.h\n@@ -16,6 +16,7 @@ struct pathspec {\n \tint max_depth;\n \tstruct pathspec_item {\n \t\tconst char *match;\n+\t\tconst char *original;\n \t\tunsigned magic;\n \t\tint len;\n \t\tint nowildcard_len;\n-- \n1.8.0.rc0.19.g7bbb31d\n"},{"id":"211352","messageId":"1363327620-29017-9-git-send-email-pclouds@gmail.com","threadId":"33187","inReplyTo":"1363327620-29017-1-git-send-email-pclouds@gmail.com","subject":"[PATCH v1 08/45] parse_pathspec: add PATHSPEC_PREFER_{CWD,FULL}","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2013-03-15T06:06:23Z","receivedAt":"2013-03-15T06:06:23Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"We have two ways of dealing with empty pathspec:\n\n1. limit it to current prefix\n2. match the entire working directory\n\nSome commands go with #1, some #2. get_pathspec() and parse_pathspec()\nonly support #1. Make parse_pathspec() reject empty pathspec by\ndefault. #1 and #2 can be specified via new flags. This makes it more\nexpressive about default behavior at command level.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n pathspec.c | 13 ++++++++++++-\n pathspec.h |  4 ++++\n 2 files changed, 16 insertions(+), 1 deletion(-)\n\ndiff --git a/pathspec.c b/pathspec.c\nindex 2bda633..6dd944a 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -270,10 +270,20 @@ void parse_pathspec(struct pathspec *pathspec,\n \tif (!entry && !prefix)\n \t\treturn;\n \n+\tif ((flags & PATHSPEC_PREFER_CWD) &&\n+\t    (flags & PATHSPEC_PREFER_FULL))\n+\t\tdie(\"BUG: PATHSPEC_PREFER_CWD and PATHSPEC_PREFER_FULL are incompatible\");\n+\n \t/* No arguments with prefix -> prefix pathspec */\n \tif (!entry) {\n \t\tstatic const char *raw[2];\n \n+\t\tif (flags & PATHSPEC_PREFER_FULL)\n+\t\t\treturn;\n+\n+\t\tif (!(flags & PATHSPEC_PREFER_CWD))\n+\t\t\tdie(\"BUG: parse_pathspec cannot take no arguments in this case\");\n+\n \t\tpathspec->items = item = xmalloc(sizeof(*item));\n \t\titem->match = prefix;\n \t\titem->original = prefix;\n@@ -338,7 +348,8 @@ const char **get_pathspec(const char *prefix, const char **pathspec)\n \tstruct pathspec ps;\n \tparse_pathspec(&ps,\n \t\t       PATHSPEC_ALL_MAGIC & ~PATHSPEC_FROMTOP,\n-\t\t       0, prefix, pathspec);\n+\t\t       PATHSPEC_PREFER_CWD,\n+\t\t       prefix, pathspec);\n \treturn ps.raw;\n }\n \ndiff --git a/pathspec.h b/pathspec.h\nindex cc5841b..d630e8b 100644\n--- a/pathspec.h\n+++ b/pathspec.h\n@@ -24,6 +24,10 @@ struct pathspec {\n \t} *items;\n };\n \n+/* parse_pathspec flags */\n+#define PATHSPEC_PREFER_CWD (1<<0) /* No args means match cwd */\n+#define PATHSPEC_PREFER_FULL (1<<1) /* No args means match everything */\n+\n extern int init_pathspec(struct pathspec *, const char **);\n extern void parse_pathspec(struct pathspec *pathspec,\n \t\t\t   unsigned magic_mask,\n-- \n1.8.0.rc0.19.g7bbb31d\n"},{"id":"211353","messageId":"1363327620-29017-10-git-send-email-pclouds@gmail.com","threadId":"33187","inReplyTo":"1363327620-29017-1-git-send-email-pclouds@gmail.com","subject":"[PATCH v1 09/45] Convert some get_pathspec() calls to parse_pathspec()","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2013-03-15T06:06:24Z","receivedAt":"2013-03-15T06:06:24Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"These call sites follow the pattern:\n\n   paths = get_pathspec(prefix, argv);\n   init_pathspec(&pathspec, paths);\n\nwhich can be converted into a single parse_pathspec() call.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n builtin/grep.c         |  6 +++---\n builtin/ls-tree.c      | 10 +++++++++-\n builtin/update-index.c |  5 +++--\n revision.c             |  4 ++--\n 4 files changed, 17 insertions(+), 8 deletions(-)\n\ndiff --git a/builtin/grep.c b/builtin/grep.c\nindex 3701c2e..54b089e 100644\n--- a/builtin/grep.c\n+++ b/builtin/grep.c\n@@ -631,7 +631,6 @@ int cmd_grep(int argc, const char **argv, const char *prefix)\n \tconst char *show_in_pager = NULL, *default_pager = \"dummy\";\n \tstruct grep_opt opt;\n \tstruct object_array list = OBJECT_ARRAY_INIT;\n-\tconst char **paths = NULL;\n \tstruct pathspec pathspec;\n \tstruct string_list path_list = STRING_LIST_INIT_NODUP;\n \tint i;\n@@ -860,8 +859,9 @@ int cmd_grep(int argc, const char **argv, const char *prefix)\n \t\t\tverify_filename(prefix, argv[j], j == i);\n \t}\n \n-\tpaths = get_pathspec(prefix, argv + i);\n-\tinit_pathspec(&pathspec, paths);\n+\tparse_pathspec(&pathspec, 0,\n+\t\t       PATHSPEC_PREFER_CWD,\n+\t\t       prefix, argv + i);\n \tpathspec.max_depth = opt.max_depth;\n \tpathspec.recursive = 1;\n \ndiff --git a/builtin/ls-tree.c b/builtin/ls-tree.c\nindex 93fc3a0..bdb03f3 100644\n--- a/builtin/ls-tree.c\n+++ b/builtin/ls-tree.c\n@@ -167,7 +167,15 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)\n \tif (get_sha1(argv[0], sha1))\n \t\tdie(\"Not a valid object name %s\", argv[0]);\n \n-\tinit_pathspec(&pathspec, get_pathspec(prefix, argv + 1));\n+\t/*\n+\t * show_recursive() rolls its own matching code and is\n+\t * generally ignorant of 'struct pathspec'. The magic mask\n+\t * cannot be lifted until it is converted to use\n+\t * match_pathspec_depth() or tree_entry_interesting()\n+\t */\n+\tparse_pathspec(&pathspec, 0,\n+\t\t       PATHSPEC_PREFER_CWD,\n+\t\t       prefix, argv + 1);\n \tfor (i = 0; i < pathspec.nr; i++)\n \t\tpathspec.items[i].nowildcard_len = pathspec.items[i].len;\n \tpathspec.has_wildcard = 0;\ndiff --git a/builtin/update-index.c b/builtin/update-index.c\nindex ffae585..3c6905d 100644\n--- a/builtin/update-index.c\n+++ b/builtin/update-index.c\n@@ -547,10 +547,11 @@ static int do_reupdate(int ac, const char **av,\n \t */\n \tint pos;\n \tint has_head = 1;\n-\tconst char **paths = get_pathspec(prefix, av + 1);\n \tstruct pathspec pathspec;\n \n-\tinit_pathspec(&pathspec, paths);\n+\tparse_pathspec(&pathspec, 0,\n+\t\t       PATHSPEC_PREFER_CWD,\n+\t\t       prefix, av + 1);\n \n \tif (read_ref(\"HEAD\", head_sha1))\n \t\t/* If there is no HEAD, that means it is an initial\ndiff --git a/revision.c b/revision.c\nindex ef60205..e257614 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -1852,8 +1852,8 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s\n \t\t */\n \t\tALLOC_GROW(prune_data.path, prune_data.nr+1, prune_data.alloc);\n \t\tprune_data.path[prune_data.nr++] = NULL;\n-\t\tinit_pathspec(&revs->prune_data,\n-\t\t\t      get_pathspec(revs->prefix, prune_data.path));\n+\t\tparse_pathspec(&revs->prune_data, 0, 0,\n+\t\t\t       revs->prefix, prune_data.path);\n \t}\n \n \tif (revs->def == NULL)\n-- \n1.8.0.rc0.19.g7bbb31d\n"},{"id":"211354","messageId":"1363327620-29017-11-git-send-email-pclouds@gmail.com","threadId":"33187","inReplyTo":"1363327620-29017-1-git-send-email-pclouds@gmail.com","subject":"[PATCH v1 10/45] parse_pathspec: a special flag for max_depth feature","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2013-03-15T06:06:25Z","receivedAt":"2013-03-15T06:06:25Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"match_pathspec_depth() and tree_entry_interesting() check max_depth\nfield in order to support \"git grep --max-depth\". The feature\nactivation is tied to \"recursive\" field, which led to some unwated\nactivation, e.g. 5c8eeb8 (diff-index: enable recursive pathspec\nmatching in unpack_trees - 2012-01-15).\n\nThis patch decouples the activation from \"recursive\" field, puts it in\n\"magic\" field instead. This makes sure that only \"git grep\" can\nactivate this feature. And because parse_pathspec knows when the\nfeature is not used, it does not need to sort pathspec (required for\nmax_depth to work correctly). A small win for non-grep cases.\n\nEven though a new magic flag is introduced, no magic syntax is. The\nmagic can be only enabled by parse_pathspec() caller. We might someday\nwant to support \":(maxdepth:10)src.\" It all depends on actual use\ncases.\n\nmax_depth feature cannot be enabled via init_pathspec() anymore. But\nthat's ok because init_pathspec() is on its way to /dev/null.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n builtin/grep.c | 3 ++-\n diff-lib.c     | 1 -\n dir.c          | 8 ++++++--\n pathspec.c     | 8 ++++++--\n pathspec.h     | 6 +++++-\n tree-diff.c    | 1 -\n tree-walk.c    | 8 ++++++--\n 7 files changed, 25 insertions(+), 10 deletions(-)\n\ndiff --git a/builtin/grep.c b/builtin/grep.c\nindex 54b089e..1c7397a 100644\n--- a/builtin/grep.c\n+++ b/builtin/grep.c\n@@ -860,7 +860,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix)\n \t}\n \n \tparse_pathspec(&pathspec, 0,\n-\t\t       PATHSPEC_PREFER_CWD,\n+\t\t       PATHSPEC_PREFER_CWD |\n+\t\t       (opt.max_depth != -1 ? PATHSPEC_MAXDEPTH_VALID : 0),\n \t\t       prefix, argv + i);\n \tpathspec.max_depth = opt.max_depth;\n \tpathspec.recursive = 1;\ndiff --git a/diff-lib.c b/diff-lib.c\nindex f35de0f..4729157 100644\n--- a/diff-lib.c\n+++ b/diff-lib.c\n@@ -474,7 +474,6 @@ static int diff_cache(struct rev_info *revs,\n \topts.dst_index = NULL;\n \topts.pathspec = &revs->diffopt.pathspec;\n \topts.pathspec->recursive = 1;\n-\topts.pathspec->max_depth = -1;\n \n \tinit_tree_desc(&t, tree->buffer, tree->size);\n \treturn unpack_trees(1, &t, &opts);\ndiff --git a/dir.c b/dir.c\nindex 8541ea7..1e9db41 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -298,7 +298,9 @@ int match_pathspec_depth(const struct pathspec *ps,\n \tint i, retval = 0;\n \n \tif (!ps->nr) {\n-\t\tif (!ps->recursive || ps->max_depth == -1)\n+\t\tif (!ps->recursive ||\n+\t\t    !(ps->magic & PATHSPEC_MAXDEPTH) ||\n+\t\t    ps->max_depth == -1)\n \t\t\treturn MATCHED_RECURSIVELY;\n \n \t\tif (within_depth(name, namelen, 0, ps->max_depth))\n@@ -315,7 +317,9 @@ int match_pathspec_depth(const struct pathspec *ps,\n \t\tif (seen && seen[i] == MATCHED_EXACTLY)\n \t\t\tcontinue;\n \t\thow = match_pathspec_item(ps->items+i, prefix, name, namelen);\n-\t\tif (ps->recursive && ps->max_depth != -1 &&\n+\t\tif (ps->recursive &&\n+\t\t    (ps->magic & PATHSPEC_MAXDEPTH) &&\n+\t\t    ps->max_depth != -1 &&\n \t\t    how && how != MATCHED_FNMATCH) {\n \t\t\tint len = ps->items[i].len;\n \t\t\tif (name[len] == '/')\ndiff --git a/pathspec.c b/pathspec.c\nindex 6dd944a..b2446c3 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -266,6 +266,9 @@ void parse_pathspec(struct pathspec *pathspec,\n \n \tmemset(pathspec, 0, sizeof(*pathspec));\n \n+\tif (flags & PATHSPEC_MAXDEPTH_VALID)\n+\t\tpathspec->magic |= PATHSPEC_MAXDEPTH;\n+\n \t/* No arguments, no prefix -> no pathspec */\n \tif (!entry && !prefix)\n \t\treturn;\n@@ -320,8 +323,9 @@ void parse_pathspec(struct pathspec *pathspec,\n \t\tpathspec->magic |= item[i].magic;\n \t}\n \n-\tqsort(pathspec->items, pathspec->nr,\n-\t      sizeof(struct pathspec_item), pathspec_item_cmp);\n+\tif (pathspec->magic & PATHSPEC_MAXDEPTH)\n+\t\tqsort(pathspec->items, pathspec->nr,\n+\t\t      sizeof(struct pathspec_item), pathspec_item_cmp);\n }\n \n /*\ndiff --git a/pathspec.h b/pathspec.h\nindex d630e8b..aa98597 100644\n--- a/pathspec.h\n+++ b/pathspec.h\n@@ -3,7 +3,10 @@\n \n /* Pathspec magic */\n #define PATHSPEC_FROMTOP\t(1<<0)\n-#define PATHSPEC_ALL_MAGIC PATHSPEC_FROMTOP\n+#define PATHSPEC_MAXDEPTH\t(1<<1)\n+#define PATHSPEC_ALL_MAGIC\t  \\\n+\t(PATHSPEC_FROMTOP\t| \\\n+\t PATHSPEC_MAXDEPTH)\n \n #define PATHSPEC_ONESTAR 1\t/* the pathspec pattern sastisfies GFNM_ONESTAR */\n \n@@ -27,6 +30,7 @@ struct pathspec {\n /* parse_pathspec flags */\n #define PATHSPEC_PREFER_CWD (1<<0) /* No args means match cwd */\n #define PATHSPEC_PREFER_FULL (1<<1) /* No args means match everything */\n+#define PATHSPEC_MAXDEPTH_VALID (1<<2) /* max_depth field is valid */\n \n extern int init_pathspec(struct pathspec *, const char **);\n extern void parse_pathspec(struct pathspec *pathspec,\ndiff --git a/tree-diff.c b/tree-diff.c\nindex ba01563..826512e 100644\n--- a/tree-diff.c\n+++ b/tree-diff.c\n@@ -138,7 +138,6 @@ int diff_tree(struct tree_desc *t1, struct tree_desc *t2,\n \n \t/* Enable recursion indefinitely */\n \topt->pathspec.recursive = DIFF_OPT_TST(opt, RECURSIVE);\n-\topt->pathspec.max_depth = -1;\n \n \tstrbuf_init(&base, PATH_MAX);\n \tstrbuf_add(&base, base_str, baselen);\ndiff --git a/tree-walk.c b/tree-walk.c\nindex 72a9613..d399ca9 100644\n--- a/tree-walk.c\n+++ b/tree-walk.c\n@@ -637,7 +637,9 @@ enum interesting tree_entry_interesting(const struct name_entry *entry,\n \t\tentry_not_interesting : all_entries_not_interesting;\n \n \tif (!ps->nr) {\n-\t\tif (!ps->recursive || ps->max_depth == -1)\n+\t\tif (!ps->recursive ||\n+\t\t    !(ps->magic & PATHSPEC_MAXDEPTH) ||\n+\t\t    ps->max_depth == -1)\n \t\t\treturn all_entries_interesting;\n \t\treturn within_depth(base->buf + base_offset, baselen,\n \t\t\t\t    !!S_ISDIR(entry->mode),\n@@ -658,7 +660,9 @@ enum interesting tree_entry_interesting(const struct name_entry *entry,\n \t\t\tif (!match_dir_prefix(base_str, match, matchlen))\n \t\t\t\tgoto match_wildcards;\n \n-\t\t\tif (!ps->recursive || ps->max_depth == -1)\n+\t\t\tif (!ps->recursive ||\n+\t\t\t    !(ps->magic & PATHSPEC_MAXDEPTH) ||\n+\t\t\t    ps->max_depth == -1)\n \t\t\t\treturn all_entries_interesting;\n \n \t\t\treturn within_depth(base_str + matchlen + 1,\n-- \n1.8.0.rc0.19.g7bbb31d\n"},{"id":"211355","messageId":"1363327620-29017-12-git-send-email-pclouds@gmail.com","threadId":"33187","inReplyTo":"1363327620-29017-1-git-send-email-pclouds@gmail.com","subject":"[PATCH v1 11/45] parse_pathspec: support stripping submodule trailing slashes","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2013-03-15T06:06:26Z","receivedAt":"2013-03-15T06:06:26Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"This flag is equivalent to builtin/ls-files.c:strip_trailing_slashes()\nand is intended to replace that function when ls-files is converted to\nuse parse_pathspec.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n pathspec.c | 9 +++++++++\n pathspec.h | 1 +\n 2 files changed, 10 insertions(+)\n\ndiff --git a/pathspec.c b/pathspec.c\nindex b2446c3..2da8bc9 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -204,6 +204,15 @@ static unsigned prefix_pathspec(struct pathspec_item *item,\n \t*raw = item->match = match;\n \titem->original = elt;\n \titem->len = strlen(item->match);\n+\n+\tif ((flags & PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP) &&\n+\t    (item->len >= 1 && item->match[item->len - 1] == '/') &&\n+\t    (i = cache_name_pos(item->match, item->len - 1)) >= 0 &&\n+\t    S_ISGITLINK(active_cache[i]->ce_mode)) {\n+\t\titem->len--;\n+\t\tmatch[item->len] = '\\0';\n+\t}\n+\n \tif (limit_pathspec_to_literal())\n \t\titem->nowildcard_len = item->len;\n \telse\ndiff --git a/pathspec.h b/pathspec.h\nindex aa98597..f24b07b 100644\n--- a/pathspec.h\n+++ b/pathspec.h\n@@ -31,6 +31,7 @@ struct pathspec {\n #define PATHSPEC_PREFER_CWD (1<<0) /* No args means match cwd */\n #define PATHSPEC_PREFER_FULL (1<<1) /* No args means match everything */\n #define PATHSPEC_MAXDEPTH_VALID (1<<2) /* max_depth field is valid */\n+#define PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP (1<<3)\n \n extern int init_pathspec(struct pathspec *, const char **);\n extern void parse_pathspec(struct pathspec *pathspec,\n-- \n1.8.0.rc0.19.g7bbb31d\n"},{"id":"211356","messageId":"1363327620-29017-13-git-send-email-pclouds@gmail.com","threadId":"33187","inReplyTo":"1363327620-29017-1-git-send-email-pclouds@gmail.com","subject":"[PATCH v1 12/45] parse_pathspec: support stripping/checking submodule paths","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2013-03-15T06:06:27Z","receivedAt":"2013-03-15T06:06:27Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"PATHSPEC_SYMLINK_LEADING_PATH and _STRIP_SUBMODULE_SLASH_EXPENSIVE are\nrespectively the alternate implementation of\npathspec.c:die_if_path_beyond_symlink() and\npathspec.c:check_path_for_gitlink(). They are intended to replace\nthose functions when builtin/add.c and builtin/check-ignore.c are\nconverted to use parse_pathspec.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n pathspec.c | 26 ++++++++++++++++++++++++++\n pathspec.h |  2 ++\n 2 files changed, 28 insertions(+)\n\ndiff --git a/pathspec.c b/pathspec.c\nindex 2da8bc9..834db80 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -213,6 +213,26 @@ static unsigned prefix_pathspec(struct pathspec_item *item,\n \t\tmatch[item->len] = '\\0';\n \t}\n \n+\tif (flags & PATHSPEC_STRIP_SUBMODULE_SLASH_EXPENSIVE)\n+\t\tfor (i = 0; i < active_nr; i++) {\n+\t\t\tstruct cache_entry *ce = active_cache[i];\n+\t\t\tint ce_len = ce_namelen(ce);\n+\n+\t\t\tif (!S_ISGITLINK(ce->ce_mode))\n+\t\t\t\tcontinue;\n+\n+\t\t\tif (item->len <= ce_len || match[ce_len] != '/' ||\n+\t\t\t    memcmp(ce->name, match, ce_len))\n+\t\t\t\tcontinue;\n+\t\t\tif (item->len == ce_len + 1) {\n+\t\t\t\t/* strip trailing slash */\n+\t\t\t\titem->len--;\n+\t\t\t\tmatch[item->len] = '\\0';\n+\t\t\t} else\n+\t\t\t\tdie (_(\"Pathspec '%s' is in submodule '%.*s'\"),\n+\t\t\t\t     elt, ce_len, ce->name);\n+\t\t}\n+\n \tif (limit_pathspec_to_literal())\n \t\titem->nowildcard_len = item->len;\n \telse\n@@ -327,6 +347,12 @@ void parse_pathspec(struct pathspec *pathspec,\n \t\t\tunsupported_magic(entry,\n \t\t\t\t\t  item[i].magic & magic_mask,\n \t\t\t\t\t  short_magic);\n+\n+\t\tif ((flags & PATHSPEC_SYMLINK_LEADING_PATH) &&\n+\t\t    has_symlink_leading_path(item[i].match, item[i].len)) {\n+\t\t\tdie(_(\"pathspec '%s' is beyond a symbolic link\"), entry);\n+\t\t}\n+\n \t\tif (item[i].nowildcard_len < item[i].len)\n \t\t\tpathspec->has_wildcard = 1;\n \t\tpathspec->magic |= item[i].magic;\ndiff --git a/pathspec.h b/pathspec.h\nindex f24b07b..6ffd09d 100644\n--- a/pathspec.h\n+++ b/pathspec.h\n@@ -32,6 +32,8 @@ struct pathspec {\n #define PATHSPEC_PREFER_FULL (1<<1) /* No args means match everything */\n #define PATHSPEC_MAXDEPTH_VALID (1<<2) /* max_depth field is valid */\n #define PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP (1<<3)\n+#define PATHSPEC_SYMLINK_LEADING_PATH (1<<4)\n+#define PATHSPEC_STRIP_SUBMODULE_SLASH_EXPENSIVE (1<<5)\n \n extern int init_pathspec(struct pathspec *, const char **);\n extern void parse_pathspec(struct pathspec *pathspec,\n-- \n1.8.0.rc0.19.g7bbb31d\n"},{"id":"211357","messageId":"1363327620-29017-14-git-send-email-pclouds@gmail.com","threadId":"33187","inReplyTo":"1363327620-29017-1-git-send-email-pclouds@gmail.com","subject":"[PATCH v1 13/45] parse_pathspec: support prefixing original patterns","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2013-03-15T06:06:28Z","receivedAt":"2013-03-15T06:06:28Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"This makes 'original' suitable for passing to an external command\nbecause all pathspec magic is left in place, provided that the\nexternal command understands pathspec. The prefixing is needed because\nwe usually launch a subcommand at worktree's top directory and the\nsubcommand can no longer calculate the prefix itself.\n\nThis slightly affects the original purpose of 'original'\n(i.e. reporting). We should report without prefixing. So only turn\nthis flag on when you know you are about to pass the result straight\naway to an external command.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n pathspec.c | 12 +++++++++++-\n pathspec.h |  1 +\n 2 files changed, 12 insertions(+), 1 deletion(-)\n\ndiff --git a/pathspec.c b/pathspec.c\nindex 834db80..9a57c0c 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -202,7 +202,17 @@ static unsigned prefix_pathspec(struct pathspec_item *item,\n \telse\n \t\tmatch = prefix_path(prefix, prefixlen, copyfrom);\n \t*raw = item->match = match;\n-\titem->original = elt;\n+\t/*\n+\t * Prefix the pathspec (keep all magic) and put to\n+\t * original. Useful for passing to another command.\n+\t */\n+\tif (flags & PATHSPEC_PREFIX_ORIGIN) {\n+\t\tstruct strbuf sb = STRBUF_INIT;\n+\t\tstrbuf_add(&sb, elt, copyfrom - elt);\n+\t\tstrbuf_addstr(&sb, match);\n+\t\titem->original = strbuf_detach(&sb, NULL);\n+\t} else\n+\t\titem->original = elt;\n \titem->len = strlen(item->match);\n \n \tif ((flags & PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP) &&\ndiff --git a/pathspec.h b/pathspec.h\nindex 6ffd09d..1cef9c6 100644\n--- a/pathspec.h\n+++ b/pathspec.h\n@@ -34,6 +34,7 @@ struct pathspec {\n #define PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP (1<<3)\n #define PATHSPEC_SYMLINK_LEADING_PATH (1<<4)\n #define PATHSPEC_STRIP_SUBMODULE_SLASH_EXPENSIVE (1<<5)\n+#define PATHSPEC_PREFIX_ORIGIN (1<<6)\n \n extern int init_pathspec(struct pathspec *, const char **);\n extern void parse_pathspec(struct pathspec *pathspec,\n-- \n1.8.0.rc0.19.g7bbb31d\n"},{"id":"211358","messageId":"1363327620-29017-15-git-send-email-pclouds@gmail.com","threadId":"33187","inReplyTo":"1363327620-29017-1-git-send-email-pclouds@gmail.com","subject":"[PATCH v1 14/45] Guard against new pathspec magic in pathspec matching code","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2013-03-15T06:06:29Z","receivedAt":"2013-03-15T06:06:29Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"GUARD_PATHSPEC() marks pathspec-sensitive code (basically anything in\n'struct pathspec' except fields \"nr\" and \"original\"). GUARD_PATHSPEC()\nis not supposed to fail. The steps for a new pathspec magic or\noptimization would be:\n\n - update parse_pathspec, add extra information to struct pathspec\n\n - grep GUARD_PATHSPEC() and update all relevant code (or note those\n   that won't work with your new stuff). Update GUARD_PATHSPEC mask\n   accordingly.\n\n - update parse_pathspec calls to disable new magic early at command\n   parsing level. Make sure parse_pathspec() catches unsupported\n   syntax, not until GUARD_PATHSPEC catches it.\n\n - add tests to verify supported/unsupported commands both work as\n   expected.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n builtin/diff.c |  2 ++\n dir.c          |  2 ++\n pathspec.h     |  7 +++++++\n tree-diff.c    | 19 +++++++++++++++++++\n tree-walk.c    |  2 ++\n 5 files changed, 32 insertions(+)\n\ndiff --git a/builtin/diff.c b/builtin/diff.c\nindex 8c2af6c..d237e0a 100644\n--- a/builtin/diff.c\n+++ b/builtin/diff.c\n@@ -371,6 +371,8 @@ int cmd_diff(int argc, const char **argv, const char *prefix)\n \t\tdie(_(\"unhandled object '%s' given.\"), name);\n \t}\n \tif (rev.prune_data.nr) {\n+\t\t/* builtin_diff_b_f() */\n+\t\tGUARD_PATHSPEC(&rev.prune_data, PATHSPEC_FROMTOP);\n \t\tif (!path)\n \t\t\tpath = rev.prune_data.items[0].match;\n \t\tpaths += rev.prune_data.nr;\ndiff --git a/dir.c b/dir.c\nindex 1e9db41..6094ba8 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -297,6 +297,8 @@ int match_pathspec_depth(const struct pathspec *ps,\n {\n \tint i, retval = 0;\n \n+\tGUARD_PATHSPEC(ps, PATHSPEC_FROMTOP | PATHSPEC_MAXDEPTH);\n+\n \tif (!ps->nr) {\n \t\tif (!ps->recursive ||\n \t\t    !(ps->magic & PATHSPEC_MAXDEPTH) ||\ndiff --git a/pathspec.h b/pathspec.h\nindex 1cef9c6..ed5d3a6 100644\n--- a/pathspec.h\n+++ b/pathspec.h\n@@ -27,6 +27,13 @@ struct pathspec {\n \t} *items;\n };\n \n+#define GUARD_PATHSPEC(ps, mask) \\\n+\tdo { \\\n+\t\tif ((ps)->magic & ~(mask))\t       \\\n+\t\t\tdie(\"BUG:%s:%d: unsupported magic %x\",\t\\\n+\t\t\t    __FILE__, __LINE__, (ps)->magic & ~(mask)); \\\n+\t} while (0)\n+\n /* parse_pathspec flags */\n #define PATHSPEC_PREFER_CWD (1<<0) /* No args means match cwd */\n #define PATHSPEC_PREFER_FULL (1<<1) /* No args means match everything */\ndiff --git a/tree-diff.c b/tree-diff.c\nindex 826512e..5a87614 100644\n--- a/tree-diff.c\n+++ b/tree-diff.c\n@@ -198,6 +198,25 @@ static void try_to_follow_renames(struct tree_desc *t1, struct tree_desc *t2, co\n \tconst char *paths[1];\n \tint i;\n \n+\t/*\n+\t * follow-rename code is very specific, we need exactly one\n+\t * path. Magic that matches more than one path is not\n+\t * supported.\n+\t */\n+\tGUARD_PATHSPEC(&opt->pathspec, PATHSPEC_FROMTOP);\n+#if 0\n+\t/*\n+\t * We should reject wildcards as well. Unfortunately we\n+\t * haven't got a reliable way to detect that 'foo\\*bar' in\n+\t * fact has no wildcards. nowildcard_len is merely a hint for\n+\t * optimization. Let it slip for now until wildmatch is taught\n+\t * about dry-run mode and returns wildcard info.\n+\t */\n+\tif (opt->pathspec.has_wildcard)\n+\t\tdie(\"BUG:%s:%d: wildcards are not supported\",\n+\t\t    __FILE__, __LINE__);\n+#endif\n+\n \t/* Remove the file creation entry from the diff queue, and remember it */\n \tchoice = q->queue[0];\n \tq->nr = 0;\ndiff --git a/tree-walk.c b/tree-walk.c\nindex d399ca9..37b157e 100644\n--- a/tree-walk.c\n+++ b/tree-walk.c\n@@ -636,6 +636,8 @@ enum interesting tree_entry_interesting(const struct name_entry *entry,\n \tenum interesting never_interesting = ps->has_wildcard ?\n \t\tentry_not_interesting : all_entries_not_interesting;\n \n+\tGUARD_PATHSPEC(ps, PATHSPEC_FROMTOP | PATHSPEC_MAXDEPTH);\n+\n \tif (!ps->nr) {\n \t\tif (!ps->recursive ||\n \t\t    !(ps->magic & PATHSPEC_MAXDEPTH) ||\n-- \n1.8.0.rc0.19.g7bbb31d\n"},{"id":"211359","messageId":"1363327620-29017-16-git-send-email-pclouds@gmail.com","threadId":"33187","inReplyTo":"1363327620-29017-1-git-send-email-pclouds@gmail.com","subject":"[PATCH v1 15/45] clean: convert to use parse_pathspec","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2013-03-15T06:06:30Z","receivedAt":"2013-03-15T06:06:30Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n builtin/clean.c | 17 ++++++++++-------\n 1 file changed, 10 insertions(+), 7 deletions(-)\n\ndiff --git a/builtin/clean.c b/builtin/clean.c\nindex f955a40..fdd4980 100644\n--- a/builtin/clean.c\n+++ b/builtin/clean.c\n@@ -13,6 +13,7 @@\n #include \"refs.h\"\n #include \"string-list.h\"\n #include \"quote.h\"\n+#include \"pathspec.h\"\n \n static int force = -1; /* unset */\n \n@@ -150,7 +151,7 @@ int cmd_clean(int argc, const char **argv, const char *prefix)\n \tint rm_flags = REMOVE_DIR_KEEP_NESTED_GIT;\n \tstruct strbuf directory = STRBUF_INIT;\n \tstruct dir_struct dir;\n-\tstatic const char **pathspec;\n+\tstruct pathspec pathspec;\n \tstruct strbuf buf = STRBUF_INIT;\n \tstruct string_list exclude_list = STRING_LIST_INIT_NODUP;\n \tstruct exclude_list *el;\n@@ -209,9 +210,11 @@ int cmd_clean(int argc, const char **argv, const char *prefix)\n \tfor (i = 0; i < exclude_list.nr; i++)\n \t\tadd_exclude(exclude_list.items[i].string, \"\", 0, el, -(i+1));\n \n-\tpathspec = get_pathspec(prefix, argv);\n+\tparse_pathspec(&pathspec, 0,\n+\t\t       PATHSPEC_PREFER_CWD,\n+\t\t       prefix, argv);\n \n-\tfill_directory(&dir, pathspec);\n+\tfill_directory(&dir, pathspec.raw);\n \n \tfor (i = 0; i < dir.nr; i++) {\n \t\tstruct dir_entry *ent = dir.entries[i];\n@@ -246,9 +249,9 @@ int cmd_clean(int argc, const char **argv, const char *prefix)\n \t\tif (lstat(ent->name, &st))\n \t\t\tcontinue;\n \n-\t\tif (pathspec)\n-\t\t\tmatches = match_pathspec(pathspec, ent->name, len,\n-\t\t\t\t\t\t 0, NULL);\n+\t\tif (pathspec.nr)\n+\t\t\tmatches = match_pathspec_depth(&pathspec, ent->name,\n+\t\t\t\t\t\t       len, 0, NULL);\n \n \t\tif (S_ISDIR(st.st_mode)) {\n \t\t\tstrbuf_addstr(&directory, ent->name);\n@@ -262,7 +265,7 @@ int cmd_clean(int argc, const char **argv, const char *prefix)\n \t\t\t}\n \t\t\tstrbuf_reset(&directory);\n \t\t} else {\n-\t\t\tif (pathspec && !matches)\n+\t\t\tif (pathspec.nr && !matches)\n \t\t\t\tcontinue;\n \t\t\tres = dry_run ? 0 : unlink(ent->name);\n \t\t\tif (res) {\n-- \n1.8.0.rc0.19.g7bbb31d\n"},{"id":"211360","messageId":"1363327620-29017-17-git-send-email-pclouds@gmail.com","threadId":"33187","inReplyTo":"1363327620-29017-1-git-send-email-pclouds@gmail.com","subject":"[PATCH v1 16/45] commit: convert to use parse_pathspec","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2013-03-15T06:06:31Z","receivedAt":"2013-03-15T06:06:31Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n builtin/commit.c | 18 +++++++++---------\n 1 file changed, 9 insertions(+), 9 deletions(-)\n\ndiff --git a/builtin/commit.c b/builtin/commit.c\nindex 3348aa1..ba6731b 100644\n--- a/builtin/commit.c\n+++ b/builtin/commit.c\n@@ -277,17 +277,17 @@ static char *prepare_index(int argc, const char **argv, const char *prefix,\n {\n \tint fd;\n \tstruct string_list partial;\n-\tconst char **pathspec = NULL;\n+\tstruct pathspec pathspec;\n \tchar *old_index_env = NULL;\n \tint refresh_flags = REFRESH_QUIET;\n \n \tif (is_status)\n \t\trefresh_flags |= REFRESH_UNMERGED;\n+\tparse_pathspec(&pathspec, 0,\n+\t\t       PATHSPEC_PREFER_FULL,\n+\t\t       prefix, argv);\n \n-\tif (*argv)\n-\t\tpathspec = get_pathspec(prefix, argv);\n-\n-\tif (read_cache_preload(pathspec) < 0)\n+\tif (read_cache_preload(pathspec.raw) < 0)\n \t\tdie(_(\"index file corrupt\"));\n \n \tif (interactive) {\n@@ -329,9 +329,9 @@ static char *prepare_index(int argc, const char **argv, const char *prefix,\n \t * (A) if all goes well, commit the real index;\n \t * (B) on failure, rollback the real index.\n \t */\n-\tif (all || (also && pathspec && *pathspec)) {\n+\tif (all || (also && pathspec.nr)) {\n \t\tfd = hold_locked_index(&index_lock, 1);\n-\t\tadd_files_to_cache(also ? prefix : NULL, pathspec, 0);\n+\t\tadd_files_to_cache(also ? prefix : NULL, pathspec.raw, 0);\n \t\trefresh_cache_or_die(refresh_flags);\n \t\tupdate_main_cache_tree(WRITE_TREE_SILENT);\n \t\tif (write_cache(fd, active_cache, active_nr) ||\n@@ -350,7 +350,7 @@ static char *prepare_index(int argc, const char **argv, const char *prefix,\n \t * and create commit from the_index.\n \t * We still need to refresh the index here.\n \t */\n-\tif (!only && (!pathspec || !*pathspec)) {\n+\tif (!only && !pathspec.nr) {\n \t\tfd = hold_locked_index(&index_lock, 1);\n \t\trefresh_cache_or_die(refresh_flags);\n \t\tif (active_cache_changed) {\n@@ -395,7 +395,7 @@ static char *prepare_index(int argc, const char **argv, const char *prefix,\n \n \tmemset(&partial, 0, sizeof(partial));\n \tpartial.strdup_strings = 1;\n-\tif (list_paths(&partial, !current_head ? NULL : \"HEAD\", prefix, pathspec))\n+\tif (list_paths(&partial, !current_head ? NULL : \"HEAD\", prefix, pathspec.raw))\n \t\texit(1);\n \n \tdiscard_cache();\n-- \n1.8.0.rc0.19.g7bbb31d\n"},{"id":"211361","messageId":"1363327620-29017-18-git-send-email-pclouds@gmail.com","threadId":"33187","inReplyTo":"1363327620-29017-1-git-send-email-pclouds@gmail.com","subject":"[PATCH v1 17/45] status: convert to use parse_pathspec","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2013-03-15T06:06:32Z","receivedAt":"2013-03-15T06:06:32Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n builtin/commit.c |  9 +++++----\n wt-status.c      | 18 ++++++++----------\n wt-status.h      |  2 +-\n 3 files changed, 14 insertions(+), 15 deletions(-)\n\ndiff --git a/builtin/commit.c b/builtin/commit.c\nindex ba6731b..d8e6b28 100644\n--- a/builtin/commit.c\n+++ b/builtin/commit.c\n@@ -1195,11 +1195,12 @@ int cmd_status(int argc, const char **argv, const char *prefix)\n \thandle_untracked_files_arg(&s);\n \tif (show_ignored_in_status)\n \t\ts.show_ignored_files = 1;\n-\tif (*argv)\n-\t\ts.pathspec = get_pathspec(prefix, argv);\n+\tparse_pathspec(&s.pathspec, 0,\n+\t\t       PATHSPEC_PREFER_FULL,\n+\t\t       prefix, argv);\n \n-\tread_cache_preload(s.pathspec);\n-\trefresh_index(&the_index, REFRESH_QUIET|REFRESH_UNMERGED, s.pathspec, NULL, NULL);\n+\tread_cache_preload(s.pathspec.raw);\n+\trefresh_index(&the_index, REFRESH_QUIET|REFRESH_UNMERGED, s.pathspec.raw, NULL, NULL);\n \n \tfd = hold_locked_index(&index_lock, 0);\n \tif (0 <= fd)\ndiff --git a/wt-status.c b/wt-status.c\nindex ef405d0..5dec9af 100644\n--- a/wt-status.c\n+++ b/wt-status.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"pathspec.h\"\n #include \"wt-status.h\"\n #include \"object.h\"\n #include \"dir.h\"\n@@ -434,7 +435,7 @@ static void wt_status_collect_changes_worktree(struct wt_status *s)\n \t}\n \trev.diffopt.format_callback = wt_status_collect_changed_cb;\n \trev.diffopt.format_callback_data = s;\n-\tinit_pathspec(&rev.prune_data, s->pathspec);\n+\tcopy_pathspec(&rev.prune_data, &s->pathspec);\n \trun_diff_files(&rev, 0);\n }\n \n@@ -459,22 +460,20 @@ static void wt_status_collect_changes_index(struct wt_status *s)\n \trev.diffopt.detect_rename = 1;\n \trev.diffopt.rename_limit = 200;\n \trev.diffopt.break_opt = 0;\n-\tinit_pathspec(&rev.prune_data, s->pathspec);\n+\tcopy_pathspec(&rev.prune_data, &s->pathspec);\n \trun_diff_index(&rev, 1);\n }\n \n static void wt_status_collect_changes_initial(struct wt_status *s)\n {\n-\tstruct pathspec pathspec;\n \tint i;\n \n-\tinit_pathspec(&pathspec, s->pathspec);\n \tfor (i = 0; i < active_nr; i++) {\n \t\tstruct string_list_item *it;\n \t\tstruct wt_status_change_data *d;\n \t\tstruct cache_entry *ce = active_cache[i];\n \n-\t\tif (!ce_path_match(ce, &pathspec))\n+\t\tif (!ce_path_match(ce, &s->pathspec))\n \t\t\tcontinue;\n \t\tit = string_list_insert(&s->change, ce->name);\n \t\td = it->util;\n@@ -489,7 +488,6 @@ static void wt_status_collect_changes_initial(struct wt_status *s)\n \t\telse\n \t\t\td->index_status = DIFF_STATUS_ADDED;\n \t}\n-\tfree_pathspec(&pathspec);\n }\n \n static void wt_status_collect_untracked(struct wt_status *s)\n@@ -505,11 +503,11 @@ static void wt_status_collect_untracked(struct wt_status *s)\n \t\t\tDIR_SHOW_OTHER_DIRECTORIES | DIR_HIDE_EMPTY_DIRECTORIES;\n \tsetup_standard_excludes(&dir);\n \n-\tfill_directory(&dir, s->pathspec);\n+\tfill_directory(&dir, s->pathspec.raw);\n \tfor (i = 0; i < dir.nr; i++) {\n \t\tstruct dir_entry *ent = dir.entries[i];\n \t\tif (cache_name_is_other(ent->name, ent->len) &&\n-\t\t    match_pathspec(s->pathspec, ent->name, ent->len, 0, NULL))\n+\t\t    match_pathspec_depth(&s->pathspec, ent->name, ent->len, 0, NULL))\n \t\t\tstring_list_insert(&s->untracked, ent->name);\n \t\tfree(ent);\n \t}\n@@ -519,11 +517,11 @@ static void wt_status_collect_untracked(struct wt_status *s)\n \t\tdir.flags = DIR_SHOW_IGNORED;\n \t\tif (s->show_untracked_files != SHOW_ALL_UNTRACKED_FILES)\n \t\t\tdir.flags |= DIR_SHOW_OTHER_DIRECTORIES;\n-\t\tfill_directory(&dir, s->pathspec);\n+\t\tfill_directory(&dir, s->pathspec.raw);\n \t\tfor (i = 0; i < dir.nr; i++) {\n \t\t\tstruct dir_entry *ent = dir.entries[i];\n \t\t\tif (cache_name_is_other(ent->name, ent->len) &&\n-\t\t\t    match_pathspec(s->pathspec, ent->name, ent->len, 0, NULL))\n+\t\t\t    match_pathspec_depth(&s->pathspec, ent->name, ent->len, 0, NULL))\n \t\t\t\tstring_list_insert(&s->ignored, ent->name);\n \t\t\tfree(ent);\n \t\t}\ndiff --git a/wt-status.h b/wt-status.h\nindex 81e1dcf..bb01c23 100644\n--- a/wt-status.h\n+++ b/wt-status.h\n@@ -44,7 +44,7 @@ struct wt_status {\n \tint is_initial;\n \tchar *branch;\n \tconst char *reference;\n-\tconst char **pathspec;\n+\tstruct pathspec pathspec;\n \tint verbose;\n \tint amend;\n \tenum commit_whence whence;\n-- \n1.8.0.rc0.19.g7bbb31d\n"},{"id":"211362","messageId":"1363327620-29017-19-git-send-email-pclouds@gmail.com","threadId":"33187","inReplyTo":"1363327620-29017-1-git-send-email-pclouds@gmail.com","subject":"[PATCH v1 18/45] rerere: convert to use parse_pathspec","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2013-03-15T06:06:33Z","receivedAt":"2013-03-15T06:06:33Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n builtin/rerere.c | 8 +++++---\n rerere.c         | 9 +++++----\n rerere.h         | 4 +++-\n 3 files changed, 13 insertions(+), 8 deletions(-)\n\ndiff --git a/builtin/rerere.c b/builtin/rerere.c\nindex dc1708e..4e51add 100644\n--- a/builtin/rerere.c\n+++ b/builtin/rerere.c\n@@ -6,6 +6,7 @@\n #include \"rerere.h\"\n #include \"xdiff/xdiff.h\"\n #include \"xdiff-interface.h\"\n+#include \"pathspec.h\"\n \n static const char * const rerere_usage[] = {\n \tN_(\"git rerere [clear | forget path... | status | remaining | diff | gc]\"),\n@@ -68,11 +69,12 @@ int cmd_rerere(int argc, const char **argv, const char *prefix)\n \t\treturn rerere(flags);\n \n \tif (!strcmp(argv[0], \"forget\")) {\n-\t\tconst char **pathspec;\n+\t\tstruct pathspec pathspec;\n \t\tif (argc < 2)\n \t\t\twarning(\"'git rerere forget' without paths is deprecated\");\n-\t\tpathspec = get_pathspec(prefix, argv + 1);\n-\t\treturn rerere_forget(pathspec);\n+\t\tparse_pathspec(&pathspec, 0, PATHSPEC_PREFER_CWD,\n+\t\t\t       prefix, argv + 1);\n+\t\treturn rerere_forget(&pathspec);\n \t}\n \n \tfd = setup_rerere(&merge_rr, flags);\ndiff --git a/rerere.c b/rerere.c\nindex a6a5cd5..c52c1f2 100644\n--- a/rerere.c\n+++ b/rerere.c\n@@ -6,6 +6,7 @@\n #include \"resolve-undo.h\"\n #include \"ll-merge.h\"\n #include \"attr.h\"\n+#include \"pathspec.h\"\n \n #define RESOLVED 0\n #define PUNTED 1\n@@ -655,7 +656,7 @@ static int rerere_forget_one_path(const char *path, struct string_list *rr)\n \treturn 0;\n }\n \n-int rerere_forget(const char **pathspec)\n+int rerere_forget(struct pathspec *pathspec)\n {\n \tint i, fd;\n \tstruct string_list conflict = STRING_LIST_INIT_DUP;\n@@ -666,12 +667,12 @@ int rerere_forget(const char **pathspec)\n \n \tfd = setup_rerere(&merge_rr, RERERE_NOAUTOUPDATE);\n \n-\tunmerge_cache(pathspec);\n+\tunmerge_cache(pathspec->raw);\n \tfind_conflict(&conflict);\n \tfor (i = 0; i < conflict.nr; i++) {\n \t\tstruct string_list_item *it = &conflict.items[i];\n-\t\tif (!match_pathspec(pathspec, it->string, strlen(it->string),\n-\t\t\t\t    0, NULL))\n+\t\tif (!match_pathspec_depth(pathspec, it->string, strlen(it->string),\n+\t\t\t\t\t  0, NULL))\n \t\t\tcontinue;\n \t\trerere_forget_one_path(it->string, &merge_rr);\n \t}\ndiff --git a/rerere.h b/rerere.h\nindex 156d2aa..4aa06c9 100644\n--- a/rerere.h\n+++ b/rerere.h\n@@ -3,6 +3,8 @@\n \n #include \"string-list.h\"\n \n+struct pathspec;\n+\n #define RERERE_AUTOUPDATE   01\n #define RERERE_NOAUTOUPDATE 02\n \n@@ -16,7 +18,7 @@ extern void *RERERE_RESOLVED;\n extern int setup_rerere(struct string_list *, int);\n extern int rerere(int);\n extern const char *rerere_path(const char *hex, const char *file);\n-extern int rerere_forget(const char **);\n+extern int rerere_forget(struct pathspec *);\n extern int rerere_remaining(struct string_list *);\n extern void rerere_clear(struct string_list *);\n extern void rerere_gc(struct string_list *);\n-- \n1.8.0.rc0.19.g7bbb31d\n"},{"id":"211363","messageId":"1363327620-29017-20-git-send-email-pclouds@gmail.com","threadId":"33187","inReplyTo":"1363327620-29017-1-git-send-email-pclouds@gmail.com","subject":"[PATCH v1 19/45] checkout: convert to use parse_pathspec","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2013-03-15T06:06:34Z","receivedAt":"2013-03-15T06:06:34Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n builtin/checkout.c | 40 ++++++++++++++++++++++++----------------\n 1 file changed, 24 insertions(+), 16 deletions(-)\n\ndiff --git a/builtin/checkout.c b/builtin/checkout.c\nindex a9c1b5a..8dc5f51 100644\n--- a/builtin/checkout.c\n+++ b/builtin/checkout.c\n@@ -45,7 +45,7 @@ struct checkout_opts {\n \n \tint branch_exists;\n \tconst char *prefix;\n-\tconst char **pathspec;\n+\tstruct pathspec pathspec;\n \tstruct tree *source_tree;\n };\n \n@@ -256,39 +256,37 @@ static int checkout_paths(const struct checkout_opts *opts,\n \n \tif (opts->patch_mode)\n \t\treturn run_add_interactive(revision, \"--patch=checkout\",\n-\t\t\t\t\t   opts->pathspec);\n+\t\t\t\t\t   opts->pathspec.raw);\n \n \tlock_file = xcalloc(1, sizeof(struct lock_file));\n \n \tnewfd = hold_locked_index(lock_file, 1);\n-\tif (read_cache_preload(opts->pathspec) < 0)\n+\tif (read_cache_preload(opts->pathspec.raw) < 0)\n \t\treturn error(_(\"corrupt index file\"));\n \n \tif (opts->source_tree)\n-\t\tread_tree_some(opts->source_tree, opts->pathspec);\n+\t\tread_tree_some(opts->source_tree, opts->pathspec.raw);\n \n-\tfor (pos = 0; opts->pathspec[pos]; pos++)\n-\t\t;\n-\tps_matched = xcalloc(1, pos);\n+\tps_matched = xcalloc(1, opts->pathspec.nr);\n \n \tfor (pos = 0; pos < active_nr; pos++) {\n \t\tstruct cache_entry *ce = active_cache[pos];\n \t\tif (opts->source_tree && !(ce->ce_flags & CE_UPDATE))\n \t\t\tcontinue;\n-\t\tmatch_pathspec(opts->pathspec, ce->name, ce_namelen(ce), 0, ps_matched);\n+\t\tmatch_pathspec_depth(&opts->pathspec, ce->name, ce_namelen(ce), 0, ps_matched);\n \t}\n \n-\tif (report_path_error(ps_matched, opts->pathspec, opts->prefix))\n+\tif (report_path_error(ps_matched, opts->pathspec.raw, opts->prefix))\n \t\treturn 1;\n \n \t/* \"checkout -m path\" to recreate conflicted state */\n \tif (opts->merge)\n-\t\tunmerge_cache(opts->pathspec);\n+\t\tunmerge_cache(opts->pathspec.raw);\n \n \t/* Any unmerged paths? */\n \tfor (pos = 0; pos < active_nr; pos++) {\n \t\tstruct cache_entry *ce = active_cache[pos];\n-\t\tif (match_pathspec(opts->pathspec, ce->name, ce_namelen(ce), 0, NULL)) {\n+\t\tif (match_pathspec_depth(&opts->pathspec, ce->name, ce_namelen(ce), 0, NULL)) {\n \t\t\tif (!ce_stage(ce))\n \t\t\t\tcontinue;\n \t\t\tif (opts->force) {\n@@ -315,7 +313,7 @@ static int checkout_paths(const struct checkout_opts *opts,\n \t\tstruct cache_entry *ce = active_cache[pos];\n \t\tif (opts->source_tree && !(ce->ce_flags & CE_UPDATE))\n \t\t\tcontinue;\n-\t\tif (match_pathspec(opts->pathspec, ce->name, ce_namelen(ce), 0, NULL)) {\n+\t\tif (match_pathspec_depth(&opts->pathspec, ce->name, ce_namelen(ce), 0, NULL)) {\n \t\t\tif (!ce_stage(ce)) {\n \t\t\t\terrs |= checkout_entry(ce, &state, NULL);\n \t\t\t\tcontinue;\n@@ -960,7 +958,7 @@ static int switch_unborn_to_new_branch(const struct checkout_opts *opts)\n static int checkout_branch(struct checkout_opts *opts,\n \t\t\t   struct branch_info *new)\n {\n-\tif (opts->pathspec)\n+\tif (opts->pathspec.nr)\n \t\tdie(_(\"paths cannot be used with switching branches\"));\n \n \tif (opts->patch_mode)\n@@ -1110,9 +1108,19 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)\n \t}\n \n \tif (argc) {\n-\t\topts.pathspec = get_pathspec(prefix, argv);\n+\t\t/*\n+\t\t * In patch mode (opts.patch_mode != 0), we pass the\n+\t\t * pathspec to an external program, git-add--interactive.\n+\t\t * Do not accept any kind of magic that that program\n+\t\t * cannot handle. Magic mask is pretty safe to be\n+\t\t * lifted for new magic when opts.patch_mode == 0.\n+\t\t */\n+\t\tparse_pathspec(&opts.pathspec,\n+\t\t\t       opts.patch_mode == 0 ? 0 :\n+\t\t\t       (PATHSPEC_ALL_MAGIC & ~PATHSPEC_FROMTOP),\n+\t\t\t       0, prefix, argv);\n \n-\t\tif (!opts.pathspec)\n+\t\tif (!opts.pathspec.nr)\n \t\t\tdie(_(\"invalid path specification\"));\n \n \t\t/*\n@@ -1144,7 +1152,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)\n \t\tstrbuf_release(&buf);\n \t}\n \n-\tif (opts.patch_mode || opts.pathspec)\n+\tif (opts.patch_mode || opts.pathspec.nr)\n \t\treturn checkout_paths(&opts, new.name);\n \telse\n \t\treturn checkout_branch(&opts, &new);\n-- \n1.8.0.rc0.19.g7bbb31d\n"},{"id":"211364","messageId":"1363327620-29017-21-git-send-email-pclouds@gmail.com","threadId":"33187","inReplyTo":"1363327620-29017-1-git-send-email-pclouds@gmail.com","subject":"[PATCH v1 20/45] rm: convert to use parse_pathspec","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2013-03-15T06:06:35Z","receivedAt":"2013-03-15T06:06:35Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n builtin/rm.c | 24 ++++++++++++------------\n 1 file changed, 12 insertions(+), 12 deletions(-)\n\ndiff --git a/builtin/rm.c b/builtin/rm.c\nindex dabfcf6..eb1b745 100644\n--- a/builtin/rm.c\n+++ b/builtin/rm.c\n@@ -10,6 +10,7 @@\n #include \"tree-walk.h\"\n #include \"parse-options.h\"\n #include \"submodule.h\"\n+#include \"pathspec.h\"\n \n static const char * const builtin_rm_usage[] = {\n \tN_(\"git rm [options] [--] <file>...\"),\n@@ -216,7 +217,7 @@ static struct option builtin_rm_options[] = {\n int cmd_rm(int argc, const char **argv, const char *prefix)\n {\n \tint i, newfd;\n-\tconst char **pathspec;\n+\tstruct pathspec pathspec;\n \tchar *seen;\n \n \tgit_config(git_default_config, NULL);\n@@ -249,31 +250,30 @@ int cmd_rm(int argc, const char **argv, const char *prefix)\n \t\t}\n \t}\n \n-\tpathspec = get_pathspec(prefix, argv);\n-\trefresh_index(&the_index, REFRESH_QUIET, pathspec, NULL, NULL);\n+\tparse_pathspec(&pathspec, 0, PATHSPEC_PREFER_CWD, prefix, argv);\n+\trefresh_index(&the_index, REFRESH_QUIET, pathspec.raw, NULL, NULL);\n \n \tseen = NULL;\n-\tfor (i = 0; pathspec[i] ; i++)\n-\t\t/* nothing */;\n-\tseen = xcalloc(i, 1);\n+\tseen = xcalloc(pathspec.nr, 1);\n \n \tfor (i = 0; i < active_nr; i++) {\n \t\tstruct cache_entry *ce = active_cache[i];\n-\t\tif (!match_pathspec(pathspec, ce->name, ce_namelen(ce), 0, seen))\n+\t\tif (!match_pathspec_depth(&pathspec, ce->name, ce_namelen(ce), 0, seen))\n \t\t\tcontinue;\n \t\tALLOC_GROW(list.entry, list.nr + 1, list.alloc);\n \t\tlist.entry[list.nr].name = ce->name;\n \t\tlist.entry[list.nr++].is_submodule = S_ISGITLINK(ce->ce_mode);\n \t}\n \n-\tif (pathspec) {\n-\t\tconst char *match;\n+\tif (pathspec.nr) {\n+\t\tconst char *original;\n \t\tint seen_any = 0;\n-\t\tfor (i = 0; (match = pathspec[i]) != NULL ; i++) {\n+\t\tfor (i = 0; i < pathspec.nr; i++) {\n+\t\t\toriginal = pathspec.items[i].original;\n \t\t\tif (!seen[i]) {\n \t\t\t\tif (!ignore_unmatch) {\n \t\t\t\t\tdie(_(\"pathspec '%s' did not match any files\"),\n-\t\t\t\t\t    match);\n+\t\t\t\t\t    original);\n \t\t\t\t}\n \t\t\t}\n \t\t\telse {\n@@ -281,7 +281,7 @@ int cmd_rm(int argc, const char **argv, const char *prefix)\n \t\t\t}\n \t\t\tif (!recursive && seen[i] == MATCHED_RECURSIVELY)\n \t\t\t\tdie(_(\"not removing '%s' recursively without -r\"),\n-\t\t\t\t    *match ? match : \".\");\n+\t\t\t\t    *original ? original : \".\");\n \t\t}\n \n \t\tif (! seen_any)\n-- \n1.8.0.rc0.19.g7bbb31d\n"},{"id":"211365","messageId":"1363327620-29017-22-git-send-email-pclouds@gmail.com","threadId":"33187","inReplyTo":"1363327620-29017-1-git-send-email-pclouds@gmail.com","subject":"[PATCH v1 21/45] ls-files: convert to use parse_pathspec","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2013-03-15T06:06:36Z","receivedAt":"2013-03-15T06:06:36Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n builtin/ls-files.c | 46 +++++++++++++---------------------------------\n 1 file changed, 13 insertions(+), 33 deletions(-)\n\ndiff --git a/builtin/ls-files.c b/builtin/ls-files.c\nindex 752570b..bd64829 100644\n--- a/builtin/ls-files.c\n+++ b/builtin/ls-files.c\n@@ -31,7 +31,7 @@ static int debug_mode;\n static const char *prefix;\n static int max_prefix_len;\n static int prefix_len;\n-static const char **pathspec;\n+static struct pathspec pathspec;\n static int error_unmatch;\n static char *ps_matched;\n static const char *with_tree;\n@@ -60,7 +60,7 @@ static void show_dir_entry(const char *tag, struct dir_entry *ent)\n \tif (len >= ent->len)\n \t\tdie(\"git ls-files: internal error - directory entry not superset of prefix\");\n \n-\tif (!match_pathspec(pathspec, ent->name, ent->len, len, ps_matched))\n+\tif (!match_pathspec_depth(&pathspec, ent->name, ent->len, len, ps_matched))\n \t\treturn;\n \n \tfputs(tag, stdout);\n@@ -135,7 +135,7 @@ static void show_ce_entry(const char *tag, struct cache_entry *ce)\n \tif (len >= ce_namelen(ce))\n \t\tdie(\"git ls-files: internal error - cache entry not superset of prefix\");\n \n-\tif (!match_pathspec(pathspec, ce->name, ce_namelen(ce), len, ps_matched))\n+\tif (!match_pathspec_depth(&pathspec, ce->name, ce_namelen(ce), len, ps_matched))\n \t\treturn;\n \n \tif (tag && *tag && show_valid_bit &&\n@@ -189,7 +189,7 @@ static void show_ru_info(void)\n \t\tlen = strlen(path);\n \t\tif (len < max_prefix_len)\n \t\t\tcontinue; /* outside of the prefix */\n-\t\tif (!match_pathspec(pathspec, path, len, max_prefix_len, ps_matched))\n+\t\tif (!match_pathspec_depth(&pathspec, path, len, max_prefix_len, ps_matched))\n \t\t\tcontinue; /* uninterested */\n \t\tfor (i = 0; i < 3; i++) {\n \t\t\tif (!ui->mode[i])\n@@ -218,7 +218,7 @@ static void show_files(struct dir_struct *dir)\n \n \t/* For cached/deleted files we don't need to even do the readdir */\n \tif (show_others || show_killed) {\n-\t\tfill_directory(dir, pathspec);\n+\t\tfill_directory(dir, pathspec.raw);\n \t\tif (show_others)\n \t\t\tshow_other_files(dir);\n \t\tif (show_killed)\n@@ -289,21 +289,6 @@ static void prune_cache(const char *prefix)\n \tactive_nr = last;\n }\n \n-static void strip_trailing_slash_from_submodules(void)\n-{\n-\tconst char **p;\n-\n-\tfor (p = pathspec; *p != NULL; p++) {\n-\t\tint len = strlen(*p), pos;\n-\n-\t\tif (len < 1 || (*p)[len - 1] != '/')\n-\t\t\tcontinue;\n-\t\tpos = cache_name_pos(*p, len - 1);\n-\t\tif (pos >= 0 && S_ISGITLINK(active_cache[pos]->ce_mode))\n-\t\t\t*p = xstrndup(*p, len - 1);\n-\t}\n-}\n-\n /*\n  * Read the tree specified with --with-tree option\n  * (typically, HEAD) into stage #1 and then\n@@ -557,23 +542,18 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)\n \tif (require_work_tree && !is_inside_work_tree())\n \t\tsetup_work_tree();\n \n-\tpathspec = get_pathspec(prefix, argv);\n-\n-\t/* be nice with submodule paths ending in a slash */\n-\tif (pathspec)\n-\t\tstrip_trailing_slash_from_submodules();\n+\tparse_pathspec(&pathspec, 0,\n+\t\t       PATHSPEC_PREFER_CWD |\n+\t\t       PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP,\n+\t\t       prefix, argv);\n \n \t/* Find common prefix for all pathspec's */\n-\tmax_prefix = common_prefix(pathspec);\n+\tmax_prefix = common_prefix(pathspec.raw);\n \tmax_prefix_len = max_prefix ? strlen(max_prefix) : 0;\n \n \t/* Treat unmatching pathspec elements as errors */\n-\tif (pathspec && error_unmatch) {\n-\t\tint num;\n-\t\tfor (num = 0; pathspec[num]; num++)\n-\t\t\t;\n-\t\tps_matched = xcalloc(1, num);\n-\t}\n+\tif (pathspec.nr && error_unmatch)\n+\t\tps_matched = xcalloc(1, pathspec.nr);\n \n \tif ((dir.flags & DIR_SHOW_IGNORED) && !exc_given)\n \t\tdie(\"ls-files --ignored needs some exclude pattern\");\n@@ -600,7 +580,7 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)\n \n \tif (ps_matched) {\n \t\tint bad;\n-\t\tbad = report_path_error(ps_matched, pathspec, prefix);\n+\t\tbad = report_path_error(ps_matched, pathspec.raw, prefix);\n \t\tif (bad)\n \t\t\tfprintf(stderr, \"Did you forget to 'git add'?\\n\");\n \n-- \n1.8.0.rc0.19.g7bbb31d\n"},{"id":"211366","messageId":"1363327620-29017-23-git-send-email-pclouds@gmail.com","threadId":"33187","inReplyTo":"1363327620-29017-1-git-send-email-pclouds@gmail.com","subject":"[PATCH v1 22/45] archive: convert to use parse_pathspec","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2013-03-15T06:06:37Z","receivedAt":"2013-03-15T06:06:37Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n archive.c | 19 +++++++++++--------\n archive.h |  4 +++-\n 2 files changed, 14 insertions(+), 9 deletions(-)\n\ndiff --git a/archive.c b/archive.c\nindex 72c6b0f..95cd174 100644\n--- a/archive.c\n+++ b/archive.c\n@@ -5,7 +5,6 @@\n #include \"archive.h\"\n #include \"parse-options.h\"\n #include \"unpack-trees.h\"\n-#include \"pathspec.h\"\n \n static char const * const archive_usage[] = {\n \tN_(\"git archive [options] <tree-ish> [<path>...]\"),\n@@ -152,7 +151,6 @@ int write_archive_entries(struct archiver_args *args,\n \tstruct archiver_context context;\n \tstruct unpack_trees_options opts;\n \tstruct tree_desc t;\n-\tstruct pathspec pathspec;\n \tint err;\n \n \tif (args->baselen > 0 && args->base[args->baselen - 1] == '/') {\n@@ -187,10 +185,8 @@ int write_archive_entries(struct archiver_args *args,\n \t\tgit_attr_set_direction(GIT_ATTR_INDEX, &the_index);\n \t}\n \n-\tinit_pathspec(&pathspec, args->pathspec);\n-\terr = read_tree_recursive(args->tree, \"\", 0, 0, &pathspec,\n+\terr = read_tree_recursive(args->tree, \"\", 0, 0, &args->pathspec,\n \t\t\t\t  write_archive_entry, &context);\n-\tfree_pathspec(&pathspec);\n \tif (err == READ_TREE_RECURSIVE)\n \t\terr = 0;\n \treturn err;\n@@ -223,7 +219,7 @@ static int path_exists(struct tree *tree, const char *path)\n \tstruct pathspec pathspec;\n \tint ret;\n \n-\tinit_pathspec(&pathspec, paths);\n+\tparse_pathspec(&pathspec, 0, 0, \"\", paths);\n \tret = read_tree_recursive(tree, \"\", 0, 0, &pathspec, reject_entry, NULL);\n \tfree_pathspec(&pathspec);\n \treturn ret != 0;\n@@ -232,11 +228,18 @@ static int path_exists(struct tree *tree, const char *path)\n static void parse_pathspec_arg(const char **pathspec,\n \t\tstruct archiver_args *ar_args)\n {\n-\tar_args->pathspec = pathspec = get_pathspec(\"\", pathspec);\n+\t/*\n+\t * must be consistent with parse_pathspec in path_exists()\n+\t * Also if pathspec patterns are dependent, we're in big\n+\t * trouble as we test each one separately\n+\t */\n+\tparse_pathspec(&ar_args->pathspec, 0,\n+\t\t       PATHSPEC_PREFER_FULL,\n+\t\t       \"\", pathspec);\n \tif (pathspec) {\n \t\twhile (*pathspec) {\n \t\t\tif (!path_exists(ar_args->tree, *pathspec))\n-\t\t\t\tdie(\"path not found: %s\", *pathspec);\n+\t\t\t\tdie(_(\"pathspec '%s' did not match any files\"), *pathspec);\n \t\t\tpathspec++;\n \t\t}\n \t}\ndiff --git a/archive.h b/archive.h\nindex 895afcd..4a791e1 100644\n--- a/archive.h\n+++ b/archive.h\n@@ -1,6 +1,8 @@\n #ifndef ARCHIVE_H\n #define ARCHIVE_H\n \n+#include \"pathspec.h\"\n+\n struct archiver_args {\n \tconst char *base;\n \tsize_t baselen;\n@@ -8,7 +10,7 @@ struct archiver_args {\n \tconst unsigned char *commit_sha1;\n \tconst struct commit *commit;\n \ttime_t time;\n-\tconst char **pathspec;\n+\tstruct pathspec pathspec;\n \tunsigned int verbose : 1;\n \tunsigned int worktree_attributes : 1;\n \tunsigned int convert : 1;\n-- \n1.8.0.rc0.19.g7bbb31d\n"},{"id":"211367","messageId":"1363327620-29017-24-git-send-email-pclouds@gmail.com","threadId":"33187","inReplyTo":"1363327620-29017-1-git-send-email-pclouds@gmail.com","subject":"[PATCH v1 23/45] check-ignore: convert to use parse_pathspec","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2013-03-15T06:06:38Z","receivedAt":"2013-03-15T06:06:38Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"check-ignore (at least the test suite) seems to rely on the pattern\norder. PATHSPEC_KEEP_ORDER is introduced to explictly express this.\nThe lack of PATHSPEC_MAXDEPTH_VALID is sufficient because it's the\nonly flag that reorders pathspecs, but it's less obvious that way.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n builtin/check-ignore.c | 34 +++++++++++++++++++++-------------\n pathspec.c             |  6 +++++-\n pathspec.h             |  1 +\n t/t0008-ignores.sh     |  8 ++++----\n 4 files changed, 31 insertions(+), 18 deletions(-)\n\ndiff --git a/builtin/check-ignore.c b/builtin/check-ignore.c\nindex 0240f99..6e55f06 100644\n--- a/builtin/check-ignore.c\n+++ b/builtin/check-ignore.c\n@@ -53,14 +53,14 @@ static void output_exclude(const char *path, struct exclude *exclude)\n \t}\n }\n \n-static int check_ignore(const char *prefix, const char **pathspec)\n+static int check_ignore(int argc, const char **argv, const char *prefix)\n {\n \tstruct dir_struct dir;\n-\tconst char *path, *full_path;\n \tchar *seen;\n \tint num_ignored = 0, dtype = DT_UNKNOWN, i;\n \tstruct path_exclude_check check;\n \tstruct exclude *exclude;\n+\tstruct pathspec pathspec;\n \n \t/* read_cache() is only necessary so we can watch out for submodules. */\n \tif (read_cache() < 0)\n@@ -70,31 +70,39 @@ static int check_ignore(const char *prefix, const char **pathspec)\n \tdir.flags |= DIR_COLLECT_IGNORED;\n \tsetup_standard_excludes(&dir);\n \n-\tif (!pathspec || !*pathspec) {\n+\tif (!argc) {\n \t\tif (!quiet)\n \t\t\tfprintf(stderr, \"no pathspec given.\\n\");\n \t\treturn 0;\n \t}\n \n+\t/*\n+\t * check-ignore just needs paths. Magic beyond :/ is really\n+\t * irrelevant.\n+\t */\n+\tparse_pathspec(&pathspec,\n+\t\t       PATHSPEC_ALL_MAGIC & ~PATHSPEC_FROMTOP,\n+\t\t       PATHSPEC_SYMLINK_LEADING_PATH |\n+\t\t       PATHSPEC_STRIP_SUBMODULE_SLASH_EXPENSIVE |\n+\t\t       PATHSPEC_KEEP_ORDER,\n+\t\t       prefix, argv);\n+\n \tpath_exclude_check_init(&check, &dir);\n \t/*\n \t * look for pathspecs matching entries in the index, since these\n \t * should not be ignored, in order to be consistent with\n \t * 'git status', 'git add' etc.\n \t */\n-\tseen = find_pathspecs_matching_against_index(pathspec);\n-\tfor (i = 0; pathspec[i]; i++) {\n-\t\tpath = pathspec[i];\n-\t\tfull_path = prefix_path(prefix, prefix\n-\t\t\t\t\t? strlen(prefix) : 0, path);\n-\t\tfull_path = check_path_for_gitlink(full_path);\n-\t\tdie_if_path_beyond_symlink(full_path, prefix);\n+\tseen = find_pathspecs_matching_against_index(pathspec.raw);\n+\tfor (i = 0; i < pathspec.nr; i++) {\n+\t\tconst char *full_path = pathspec.raw[i];\n \t\tif (!seen[i]) {\n \t\t\texclude = last_exclude_matching_path(&check, full_path,\n \t\t\t\t\t\t\t     -1, &dtype);\n \t\t\tif (exclude) {\n \t\t\t\tif (!quiet)\n-\t\t\t\t\toutput_exclude(path, exclude);\n+\t\t\t\t\toutput_exclude(pathspec.items[i].original,\n+\t\t\t\t\t\t       exclude);\n \t\t\t\tnum_ignored++;\n \t\t\t}\n \t\t}\n@@ -129,7 +137,7 @@ static int check_ignore_stdin_paths(const char *prefix)\n \t}\n \tALLOC_GROW(pathspec, nr + 1, alloc);\n \tpathspec[nr] = NULL;\n-\tnum_ignored = check_ignore(prefix, (const char **)pathspec);\n+\tnum_ignored = check_ignore(nr, (const char **)pathspec, prefix);\n \tmaybe_flush_or_die(stdout, \"attribute to stdout\");\n \tstrbuf_release(&buf);\n \tstrbuf_release(&nbuf);\n@@ -165,7 +173,7 @@ int cmd_check_ignore(int argc, const char **argv, const char *prefix)\n \tif (stdin_paths) {\n \t\tnum_ignored = check_ignore_stdin_paths(prefix);\n \t} else {\n-\t\tnum_ignored = check_ignore(prefix, argv);\n+\t\tnum_ignored = check_ignore(argc, argv, prefix);\n \t\tmaybe_flush_or_die(stdout, \"ignore to stdout\");\n \t}\n \ndiff --git a/pathspec.c b/pathspec.c\nindex 9a57c0c..f531038 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -368,9 +368,13 @@ void parse_pathspec(struct pathspec *pathspec,\n \t\tpathspec->magic |= item[i].magic;\n \t}\n \n-\tif (pathspec->magic & PATHSPEC_MAXDEPTH)\n+\n+\tif (pathspec->magic & PATHSPEC_MAXDEPTH) {\n+\t\tif (flags & PATHSPEC_KEEP_ORDER)\n+\t\t\tdie(\"BUG: PATHSPEC_MAXDEPTH_VALID and PATHSPEC_KEEP_ORDER are incompatible\");\n \t\tqsort(pathspec->items, pathspec->nr,\n \t\t      sizeof(struct pathspec_item), pathspec_item_cmp);\n+\t}\n }\n \n /*\ndiff --git a/pathspec.h b/pathspec.h\nindex ed5d3a6..44253c8 100644\n--- a/pathspec.h\n+++ b/pathspec.h\n@@ -42,6 +42,7 @@ struct pathspec {\n #define PATHSPEC_SYMLINK_LEADING_PATH (1<<4)\n #define PATHSPEC_STRIP_SUBMODULE_SLASH_EXPENSIVE (1<<5)\n #define PATHSPEC_PREFIX_ORIGIN (1<<6)\n+#define PATHSPEC_KEEP_ORDER (1<<7)\n \n extern int init_pathspec(struct pathspec *, const char **);\n extern void parse_pathspec(struct pathspec *pathspec,\ndiff --git a/t/t0008-ignores.sh b/t/t0008-ignores.sh\nindex 9c1bde1..c41f60b 100755\n--- a/t/t0008-ignores.sh\n+++ b/t/t0008-ignores.sh\n@@ -397,7 +397,7 @@ test_expect_success_multi SYMLINKS 'symlink' '' '\n \n test_expect_success_multi SYMLINKS 'beyond a symlink' '' '\n \ttest_check_ignore \"a/symlink/foo\" 128 &&\n-\ttest_stderr \"fatal: '\\''a/symlink/foo'\\'' is beyond a symbolic link\"\n+\ttest_stderr \"fatal: pathspec '\\''a/symlink/foo'\\'' is beyond a symbolic link\"\n '\n \n test_expect_success_multi SYMLINKS 'beyond a symlink from subdirectory' '' '\n@@ -405,7 +405,7 @@ test_expect_success_multi SYMLINKS 'beyond a symlink from subdirectory' '' '\n \t\tcd a &&\n \t\ttest_check_ignore \"symlink/foo\" 128\n \t) &&\n-\ttest_stderr \"fatal: '\\''symlink/foo'\\'' is beyond a symbolic link\"\n+\ttest_stderr \"fatal: pathspec '\\''symlink/foo'\\'' is beyond a symbolic link\"\n '\n \n ############################################################################\n@@ -414,7 +414,7 @@ test_expect_success_multi SYMLINKS 'beyond a symlink from subdirectory' '' '\n \n test_expect_success_multi 'submodule' '' '\n \ttest_check_ignore \"a/submodule/one\" 128 &&\n-\ttest_stderr \"fatal: Path '\\''a/submodule/one'\\'' is in submodule '\\''a/submodule'\\''\"\n+\ttest_stderr \"fatal: Pathspec '\\''a/submodule/one'\\'' is in submodule '\\''a/submodule'\\''\"\n '\n \n test_expect_success_multi 'submodule from subdirectory' '' '\n@@ -422,7 +422,7 @@ test_expect_success_multi 'submodule from subdirectory' '' '\n \t\tcd a &&\n \t\ttest_check_ignore \"submodule/one\" 128\n \t) &&\n-\ttest_stderr \"fatal: Path '\\''a/submodule/one'\\'' is in submodule '\\''a/submodule'\\''\"\n+\ttest_stderr \"fatal: Pathspec '\\''submodule/one'\\'' is in submodule '\\''a/submodule'\\''\"\n '\n \n ############################################################################\n-- \n1.8.0.rc0.19.g7bbb31d\n"},{"id":"211369","messageId":"1363327620-29017-25-git-send-email-pclouds@gmail.com","threadId":"33187","inReplyTo":"1363327620-29017-1-git-send-email-pclouds@gmail.com","subject":"[PATCH v1 24/45] add: convert to use parse_pathspec","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2013-03-15T06:06:39Z","receivedAt":"2013-03-15T06:06:39Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n builtin/add.c | 100 +++++++++++++++++++++++++---------------------------------\n pathspec.c    |  43 -------------------------\n 2 files changed, 43 insertions(+), 100 deletions(-)\n\ndiff --git a/builtin/add.c b/builtin/add.c\nindex ab1c9e8..ec6fbe3 100644\n--- a/builtin/add.c\n+++ b/builtin/add.c\n@@ -121,21 +121,6 @@ static char *prune_directory(struct dir_struct *dir, const char **pathspec, int\n \treturn seen;\n }\n \n-/*\n- * Checks the index to see whether any path in pathspec refers to\n- * something inside a submodule.  If so, dies with an error message.\n- */\n-static void treat_gitlinks(const char **pathspec)\n-{\n-\tint i;\n-\n-\tif (!pathspec || !*pathspec)\n-\t\treturn;\n-\n-\tfor (i = 0; pathspec[i]; i++)\n-\t\tpathspec[i] = check_path_for_gitlink(pathspec[i]);\n-}\n-\n static void refresh(int verbose, const char **pathspec)\n {\n \tchar *seen;\n@@ -153,25 +138,6 @@ static void refresh(int verbose, const char **pathspec)\n         free(seen);\n }\n \n-/*\n- * Normalizes argv relative to prefix, via get_pathspec(), and then\n- * runs die_if_path_beyond_symlink() on each path in the normalized\n- * list.\n- */\n-static const char **validate_pathspec(const char **argv, const char *prefix)\n-{\n-\tconst char **pathspec = get_pathspec(prefix, argv);\n-\n-\tif (pathspec) {\n-\t\tconst char **p;\n-\t\tfor (p = pathspec; *p; p++) {\n-\t\t\tdie_if_path_beyond_symlink(*p, prefix);\n-\t\t}\n-\t}\n-\n-\treturn pathspec;\n-}\n-\n int run_add_interactive(const char *revision, const char *patch_mode,\n \t\t\tconst char **pathspec)\n {\n@@ -203,17 +169,23 @@ int run_add_interactive(const char *revision, const char *patch_mode,\n \n int interactive_add(int argc, const char **argv, const char *prefix, int patch)\n {\n-\tconst char **pathspec = NULL;\n+\tstruct pathspec pathspec;\n \n-\tif (argc) {\n-\t\tpathspec = validate_pathspec(argv, prefix);\n-\t\tif (!pathspec)\n-\t\t\treturn -1;\n-\t}\n+\t/*\n+\t * git-add--interactive itself does not parse pathspec. It\n+\t * simply passes the pathspec to other builtin commands. Let's\n+\t * hope all of them support all magic, or we'll need to limit\n+\t * the magic here. There is still a problem with prefix. But\n+\t * that'll be worked on later on.\n+\t */\n+\tparse_pathspec(&pathspec, PATHSPEC_ALL_MAGIC & ~PATHSPEC_FROMTOP,\n+\t\t       PATHSPEC_PREFER_FULL |\n+\t\t       PATHSPEC_SYMLINK_LEADING_PATH,\n+\t\t       prefix, argv);\n \n \treturn run_add_interactive(NULL,\n \t\t\t\t   patch ? \"--patch\" : NULL,\n-\t\t\t\t   pathspec);\n+\t\t\t\t   pathspec.raw);\n }\n \n static int edit_patch(int argc, const char **argv, const char *prefix)\n@@ -354,7 +326,7 @@ int cmd_add(int argc, const char **argv, const char *prefix)\n {\n \tint exit_status = 0;\n \tint newfd;\n-\tconst char **pathspec;\n+\tstruct pathspec pathspec;\n \tstruct dir_struct dir;\n \tint flags;\n \tint add_new_files;\n@@ -415,11 +387,19 @@ int cmd_add(int argc, const char **argv, const char *prefix)\n \t\tfprintf(stderr, _(\"Maybe you wanted to say 'git add .'?\\n\"));\n \t\treturn 0;\n \t}\n-\tpathspec = validate_pathspec(argv, prefix);\n \n \tif (read_cache() < 0)\n \t\tdie(_(\"index file corrupt\"));\n-\ttreat_gitlinks(pathspec);\n+\n+\t/*\n+\t * Check the \"pathspec '%s' did not match any files\" block\n+\t * below before enabling new magic.\n+\t */\n+\tparse_pathspec(&pathspec, 0,\n+\t\t       PATHSPEC_PREFER_FULL |\n+\t\t       PATHSPEC_SYMLINK_LEADING_PATH |\n+\t\t       PATHSPEC_STRIP_SUBMODULE_SLASH_EXPENSIVE,\n+\t\t       prefix, argv);\n \n \tif (add_new_files) {\n \t\tint baselen;\n@@ -432,33 +412,39 @@ int cmd_add(int argc, const char **argv, const char *prefix)\n \t\t}\n \n \t\t/* This picks up the paths that are not tracked */\n-\t\tbaselen = fill_directory(&dir, pathspec);\n-\t\tif (pathspec)\n-\t\t\tseen = prune_directory(&dir, pathspec, baselen);\n+\t\tbaselen = fill_directory(&dir, pathspec.raw);\n+\t\tif (pathspec.nr)\n+\t\t\tseen = prune_directory(&dir, pathspec.raw, baselen);\n \t}\n \n \tif (refresh_only) {\n-\t\trefresh(verbose, pathspec);\n+\t\trefresh(verbose, pathspec.raw);\n \t\tgoto finish;\n \t}\n \n-\tif (pathspec) {\n+\tif (pathspec.nr) {\n \t\tint i;\n \t\tstruct path_exclude_check check;\n \n \t\tpath_exclude_check_init(&check, &dir);\n \t\tif (!seen)\n-\t\t\tseen = find_pathspecs_matching_against_index(pathspec);\n-\t\tfor (i = 0; pathspec[i]; i++) {\n-\t\t\tif (!seen[i] && pathspec[i][0]\n-\t\t\t    && !file_exists(pathspec[i])) {\n+\t\t\tseen = find_pathspecs_matching_against_index(pathspec.raw);\n+\n+\t\t/*\n+\t\t * file_exists() assumes exact match\n+\t\t */\n+\t\tGUARD_PATHSPEC(&pathspec, PATHSPEC_FROMTOP);\n+\n+\t\tfor (i = 0; pathspec.raw[i]; i++) {\n+\t\t\tif (!seen[i] && pathspec.raw[i][0]\n+\t\t\t    && !file_exists(pathspec.raw[i])) {\n \t\t\t\tif (ignore_missing) {\n \t\t\t\t\tint dtype = DT_UNKNOWN;\n-\t\t\t\t\tif (is_path_excluded(&check, pathspec[i], -1, &dtype))\n-\t\t\t\t\t\tdir_add_ignored(&dir, pathspec[i], strlen(pathspec[i]));\n+\t\t\t\t\tif (is_path_excluded(&check, pathspec.raw[i], -1, &dtype))\n+\t\t\t\t\t\tdir_add_ignored(&dir, pathspec.raw[i], strlen(pathspec.raw[i]));\n \t\t\t\t} else\n \t\t\t\t\tdie(_(\"pathspec '%s' did not match any files\"),\n-\t\t\t\t\t    pathspec[i]);\n+\t\t\t\t\t    pathspec.raw[i]);\n \t\t\t}\n \t\t}\n \t\tfree(seen);\n@@ -467,7 +453,7 @@ int cmd_add(int argc, const char **argv, const char *prefix)\n \n \tplug_bulk_checkin();\n \n-\texit_status |= add_files_to_cache(prefix, pathspec, flags);\n+\texit_status |= add_files_to_cache(prefix, pathspec.raw, flags);\n \n \tif (add_new_files)\n \t\texit_status |= add_files(&dir, flags);\ndiff --git a/pathspec.c b/pathspec.c\nindex f531038..0b658cb 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -58,49 +58,6 @@ char *find_pathspecs_matching_against_index(const char **pathspec)\n }\n \n /*\n- * Check the index to see whether path refers to a submodule, or\n- * something inside a submodule.  If the former, returns the path with\n- * any trailing slash stripped.  If the latter, dies with an error\n- * message.\n- */\n-const char *check_path_for_gitlink(const char *path)\n-{\n-\tint i, path_len = strlen(path);\n-\tfor (i = 0; i < active_nr; i++) {\n-\t\tstruct cache_entry *ce = active_cache[i];\n-\t\tif (S_ISGITLINK(ce->ce_mode)) {\n-\t\t\tint ce_len = ce_namelen(ce);\n-\t\t\tif (path_len <= ce_len || path[ce_len] != '/' ||\n-\t\t\t    memcmp(ce->name, path, ce_len))\n-\t\t\t\t/* path does not refer to this\n-\t\t\t\t * submodule or anything inside it */\n-\t\t\t\tcontinue;\n-\t\t\tif (path_len == ce_len + 1) {\n-\t\t\t\t/* path refers to submodule;\n-\t\t\t\t * strip trailing slash */\n-\t\t\t\treturn xstrndup(ce->name, ce_len);\n-\t\t\t} else {\n-\t\t\t\tdie (_(\"Path '%s' is in submodule '%.*s'\"),\n-\t\t\t\t     path, ce_len, ce->name);\n-\t\t\t}\n-\t\t}\n-\t}\n-\treturn path;\n-}\n-\n-/*\n- * Dies if the given path refers to a file inside a symlinked\n- * directory in the index.\n- */\n-void die_if_path_beyond_symlink(const char *path, const char *prefix)\n-{\n-\tif (has_symlink_leading_path(path, strlen(path))) {\n-\t\tint len = prefix ? strlen(prefix) : 0;\n-\t\tdie(_(\"'%s' is beyond a symbolic link\"), path + len);\n-\t}\n-}\n-\n-/*\n  * Magic pathspec\n  *\n  * Possible future magic semantics include stuff like:\n-- \n1.8.0.rc0.19.g7bbb31d\n"},{"id":"211368","messageId":"1363327620-29017-26-git-send-email-pclouds@gmail.com","threadId":"33187","inReplyTo":"1363327620-29017-1-git-send-email-pclouds@gmail.com","subject":"[PATCH v1 25/45] reset: convert to use parse_pathspec","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2013-03-15T06:06:40Z","receivedAt":"2013-03-15T06:06:40Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n builtin/reset.c | 26 ++++++++++++++++----------\n 1 file changed, 16 insertions(+), 10 deletions(-)\n\ndiff --git a/builtin/reset.c b/builtin/reset.c\nindex 6032131..da7282e 100644\n--- a/builtin/reset.c\n+++ b/builtin/reset.c\n@@ -171,7 +171,10 @@ static void die_if_unmerged_cache(int reset_type)\n \n }\n \n-static const char **parse_args(const char **argv, const char *prefix, const char **rev_ret)\n+static void parse_args(struct pathspec *pathspec,\n+\t\t       const char **argv, const char *prefix,\n+\t\t       int patch_mode,\n+\t\t       const char **rev_ret)\n {\n \tconst char *rev = \"HEAD\";\n \tunsigned char unused[20];\n@@ -213,7 +216,10 @@ static const char **parse_args(const char **argv, const char *prefix, const char\n \t\t}\n \t}\n \t*rev_ret = rev;\n-\treturn argv[0] ? get_pathspec(prefix, argv) : NULL;\n+\tparse_pathspec(pathspec,\n+\t\t       patch_mode ? PATHSPEC_ALL_MAGIC & ~PATHSPEC_FROMTOP : 0,\n+\t\t       PATHSPEC_PREFER_FULL,\n+\t\t       prefix, argv);\n }\n \n static int update_refs(const char *rev, const unsigned char *sha1)\n@@ -243,7 +249,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix)\n \tint patch_mode = 0, unborn;\n \tconst char *rev;\n \tunsigned char sha1[20];\n-\tconst char **pathspec = NULL;\n+\tstruct pathspec pathspec;\n \tconst struct option options[] = {\n \t\tOPT__QUIET(&quiet, N_(\"be quiet, only report errors\")),\n \t\tOPT_SET_INT(0, \"mixed\", &reset_type,\n@@ -263,13 +269,13 @@ int cmd_reset(int argc, const char **argv, const char *prefix)\n \n \targc = parse_options(argc, argv, prefix, options, git_reset_usage,\n \t\t\t\t\t\tPARSE_OPT_KEEP_DASHDASH);\n-\tpathspec = parse_args(argv, prefix, &rev);\n+\tparse_args(&pathspec, argv, prefix, patch_mode, &rev);\n \n \tunborn = !strcmp(rev, \"HEAD\") && get_sha1(\"HEAD\", sha1);\n \tif (unborn) {\n \t\t/* reset on unborn branch: treat as reset to empty tree */\n \t\thashcpy(sha1, EMPTY_TREE_SHA1_BIN);\n-\t} else if (!pathspec) {\n+\t} else if (!pathspec.nr) {\n \t\tstruct commit *commit;\n \t\tif (get_sha1_committish(rev, sha1))\n \t\t\tdie(_(\"Failed to resolve '%s' as a valid revision.\"), rev);\n@@ -290,13 +296,13 @@ int cmd_reset(int argc, const char **argv, const char *prefix)\n \tif (patch_mode) {\n \t\tif (reset_type != NONE)\n \t\t\tdie(_(\"--patch is incompatible with --{hard,mixed,soft}\"));\n-\t\treturn run_add_interactive(sha1_to_hex(sha1), \"--patch=reset\", pathspec);\n+\t\treturn run_add_interactive(sha1_to_hex(sha1), \"--patch=reset\", pathspec.raw);\n \t}\n \n \t/* git reset tree [--] paths... can be used to\n \t * load chosen paths from the tree into the index without\n \t * affecting the working tree nor HEAD. */\n-\tif (pathspec) {\n+\tif (pathspec.nr) {\n \t\tif (reset_type == MIXED)\n \t\t\twarning(_(\"--mixed with paths is deprecated; use 'git reset -- <paths>' instead.\"));\n \t\telse if (reset_type != NONE)\n@@ -323,7 +329,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix)\n \t\tstruct lock_file *lock = xcalloc(1, sizeof(struct lock_file));\n \t\tint newfd = hold_locked_index(lock, 1);\n \t\tif (reset_type == MIXED) {\n-\t\t\tif (read_from_tree(pathspec, sha1))\n+\t\t\tif (read_from_tree(pathspec.raw, sha1))\n \t\t\t\treturn 1;\n \t\t} else {\n \t\t\tint err = reset_index(sha1, reset_type, quiet);\n@@ -344,7 +350,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix)\n \t\t\tdie(_(\"Could not write new index file.\"));\n \t}\n \n-\tif (!pathspec && !unborn) {\n+\tif (!pathspec.nr && !unborn) {\n \t\t/* Any resets without paths update HEAD to the head being\n \t\t * switched to, saving the previous head in ORIG_HEAD before. */\n \t\tupdate_ref_status = update_refs(rev, sha1);\n@@ -352,7 +358,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix)\n \t\tif (reset_type == HARD && !update_ref_status && !quiet)\n \t\t\tprint_new_head_line(lookup_commit_reference(sha1));\n \t}\n-\tif (!pathspec)\n+\tif (!pathspec.nr)\n \t\tremove_branch_state();\n \n \treturn update_ref_status;\n-- \n1.8.0.rc0.19.g7bbb31d\n"},{"id":"211370","messageId":"1363327620-29017-27-git-send-email-pclouds@gmail.com","threadId":"33187","inReplyTo":"1363327620-29017-1-git-send-email-pclouds@gmail.com","subject":"[PATCH v1 26/45] Convert read_cache_preload() to take struct pathspec","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2013-03-15T06:06:41Z","receivedAt":"2013-03-15T06:06:41Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n builtin/checkout.c   |  2 +-\n builtin/commit.c     |  4 ++--\n builtin/diff-files.c |  2 +-\n builtin/diff-index.c |  2 +-\n builtin/diff.c       |  4 ++--\n cache.h              |  2 +-\n preload-index.c      | 20 +++++++++++---------\n 7 files changed, 19 insertions(+), 17 deletions(-)\n\ndiff --git a/builtin/checkout.c b/builtin/checkout.c\nindex 8dc5f51..3c19cb4 100644\n--- a/builtin/checkout.c\n+++ b/builtin/checkout.c\n@@ -261,7 +261,7 @@ static int checkout_paths(const struct checkout_opts *opts,\n \tlock_file = xcalloc(1, sizeof(struct lock_file));\n \n \tnewfd = hold_locked_index(lock_file, 1);\n-\tif (read_cache_preload(opts->pathspec.raw) < 0)\n+\tif (read_cache_preload(&opts->pathspec) < 0)\n \t\treturn error(_(\"corrupt index file\"));\n \n \tif (opts->source_tree)\ndiff --git a/builtin/commit.c b/builtin/commit.c\nindex d8e6b28..564f359 100644\n--- a/builtin/commit.c\n+++ b/builtin/commit.c\n@@ -287,7 +287,7 @@ static char *prepare_index(int argc, const char **argv, const char *prefix,\n \t\t       PATHSPEC_PREFER_FULL,\n \t\t       prefix, argv);\n \n-\tif (read_cache_preload(pathspec.raw) < 0)\n+\tif (read_cache_preload(&pathspec) < 0)\n \t\tdie(_(\"index file corrupt\"));\n \n \tif (interactive) {\n@@ -1199,7 +1199,7 @@ int cmd_status(int argc, const char **argv, const char *prefix)\n \t\t       PATHSPEC_PREFER_FULL,\n \t\t       prefix, argv);\n \n-\tread_cache_preload(s.pathspec.raw);\n+\tread_cache_preload(&s.pathspec);\n \trefresh_index(&the_index, REFRESH_QUIET|REFRESH_UNMERGED, s.pathspec.raw, NULL, NULL);\n \n \tfd = hold_locked_index(&index_lock, 0);\ndiff --git a/builtin/diff-files.c b/builtin/diff-files.c\nindex 46085f8..9200069 100644\n--- a/builtin/diff-files.c\n+++ b/builtin/diff-files.c\n@@ -61,7 +61,7 @@ int cmd_diff_files(int argc, const char **argv, const char *prefix)\n \t    (rev.diffopt.output_format & DIFF_FORMAT_PATCH))\n \t\trev.combine_merges = rev.dense_combined_merges = 1;\n \n-\tif (read_cache_preload(rev.diffopt.pathspec.raw) < 0) {\n+\tif (read_cache_preload(&rev.diffopt.pathspec) < 0) {\n \t\tperror(\"read_cache_preload\");\n \t\treturn -1;\n \t}\ndiff --git a/builtin/diff-index.c b/builtin/diff-index.c\nindex 1c737f7..ce15b23 100644\n--- a/builtin/diff-index.c\n+++ b/builtin/diff-index.c\n@@ -43,7 +43,7 @@ int cmd_diff_index(int argc, const char **argv, const char *prefix)\n \t\tusage(diff_cache_usage);\n \tif (!cached) {\n \t\tsetup_work_tree();\n-\t\tif (read_cache_preload(rev.diffopt.pathspec.raw) < 0) {\n+\t\tif (read_cache_preload(&rev.diffopt.pathspec) < 0) {\n \t\t\tperror(\"read_cache_preload\");\n \t\t\treturn -1;\n \t\t}\ndiff --git a/builtin/diff.c b/builtin/diff.c\nindex d237e0a..6b4e3f9 100644\n--- a/builtin/diff.c\n+++ b/builtin/diff.c\n@@ -140,7 +140,7 @@ static int builtin_diff_index(struct rev_info *revs,\n \t\tusage(builtin_diff_usage);\n \tif (!cached) {\n \t\tsetup_work_tree();\n-\t\tif (read_cache_preload(revs->diffopt.pathspec.raw) < 0) {\n+\t\tif (read_cache_preload(&revs->diffopt.pathspec) < 0) {\n \t\t\tperror(\"read_cache_preload\");\n \t\t\treturn -1;\n \t\t}\n@@ -240,7 +240,7 @@ static int builtin_diff_files(struct rev_info *revs, int argc, const char **argv\n \t\trevs->combine_merges = revs->dense_combined_merges = 1;\n \n \tsetup_work_tree();\n-\tif (read_cache_preload(revs->diffopt.pathspec.raw) < 0) {\n+\tif (read_cache_preload(&revs->diffopt.pathspec) < 0) {\n \t\tperror(\"read_cache_preload\");\n \t\treturn -1;\n \t}\ndiff --git a/cache.h b/cache.h\nindex 5115c1b..cc90d7b 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -436,7 +436,7 @@ extern int init_db(const char *template_dir, unsigned int flags);\n \n /* Initialize and use the cache information */\n extern int read_index(struct index_state *);\n-extern int read_index_preload(struct index_state *, const char **pathspec);\n+extern int read_index_preload(struct index_state *, const struct pathspec *pathspec);\n extern int read_index_from(struct index_state *, const char *path);\n extern int is_index_unborn(struct index_state *);\n extern int read_index_unmerged(struct index_state *);\ndiff --git a/preload-index.c b/preload-index.c\nindex cddfffa..8c44ceb 100644\n--- a/preload-index.c\n+++ b/preload-index.c\n@@ -5,7 +5,8 @@\n #include \"pathspec.h\"\n \n #ifdef NO_PTHREADS\n-static void preload_index(struct index_state *index, const char **pathspec)\n+static void preload_index(struct index_state *index,\n+\t\t\t  const struct pathspec *pathspec)\n {\n \t; /* nothing */\n }\n@@ -25,7 +26,7 @@ static void preload_index(struct index_state *index, const char **pathspec)\n struct thread_data {\n \tpthread_t pthread;\n \tstruct index_state *index;\n-\tconst char **pathspec;\n+\tstruct pathspec pathspec;\n \tint offset, nr;\n };\n \n@@ -36,9 +37,7 @@ static void *preload_thread(void *_data)\n \tstruct index_state *index = p->index;\n \tstruct cache_entry **cep = index->cache + p->offset;\n \tstruct cache_def cache;\n-\tstruct pathspec pathspec;\n \n-\tinit_pathspec(&pathspec, p->pathspec);\n \tmemset(&cache, 0, sizeof(cache));\n \tnr = p->nr;\n \tif (nr + p->offset > index->cache_nr)\n@@ -54,7 +53,7 @@ static void *preload_thread(void *_data)\n \t\t\tcontinue;\n \t\tif (ce_uptodate(ce))\n \t\t\tcontinue;\n-\t\tif (!ce_path_match(ce, &pathspec))\n+\t\tif (!ce_path_match(ce, &p->pathspec))\n \t\t\tcontinue;\n \t\tif (threaded_has_symlink_leading_path(&cache, ce->name, ce_namelen(ce)))\n \t\t\tcontinue;\n@@ -64,11 +63,11 @@ static void *preload_thread(void *_data)\n \t\t\tcontinue;\n \t\tce_mark_uptodate(ce);\n \t} while (--nr > 0);\n-\tfree_pathspec(&pathspec);\n \treturn NULL;\n }\n \n-static void preload_index(struct index_state *index, const char **pathspec)\n+static void preload_index(struct index_state *index,\n+\t\t\t  const struct pathspec *pathspec)\n {\n \tint threads, i, work, offset;\n \tstruct thread_data data[MAX_PARALLEL];\n@@ -83,10 +82,12 @@ static void preload_index(struct index_state *index, const char **pathspec)\n \t\tthreads = MAX_PARALLEL;\n \toffset = 0;\n \twork = DIV_ROUND_UP(index->cache_nr, threads);\n+\tmemset(&data, 0, sizeof(data));\n \tfor (i = 0; i < threads; i++) {\n \t\tstruct thread_data *p = data+i;\n \t\tp->index = index;\n-\t\tp->pathspec = pathspec;\n+\t\tif (pathspec)\n+\t\t\tcopy_pathspec(&p->pathspec, pathspec);\n \t\tp->offset = offset;\n \t\tp->nr = work;\n \t\toffset += work;\n@@ -101,7 +102,8 @@ static void preload_index(struct index_state *index, const char **pathspec)\n }\n #endif\n \n-int read_index_preload(struct index_state *index, const char **pathspec)\n+int read_index_preload(struct index_state *index,\n+\t\t       const struct pathspec *pathspec)\n {\n \tint retval = read_index(index);\n \n-- \n1.8.0.rc0.19.g7bbb31d\n"},{"id":"211371","messageId":"1363327620-29017-28-git-send-email-pclouds@gmail.com","threadId":"33187","inReplyTo":"1363327620-29017-1-git-send-email-pclouds@gmail.com","subject":"[PATCH v1 27/45] Convert run_add_interactive to use struct pathspec","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2013-03-15T06:06:42Z","receivedAt":"2013-03-15T06:06:42Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"This passes the pathspec, more or less unmodified, to\ngit-add--interactive. The command itself does not process pathspec. It\nsimply passes the pathspec to other builtin commands. So if all those\ncommands support pathspec, we're good.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n builtin/add.c      | 26 ++++++++++----------------\n builtin/checkout.c |  9 ++++-----\n builtin/reset.c    |  8 ++++----\n commit.h           |  2 +-\n 4 files changed, 19 insertions(+), 26 deletions(-)\n\ndiff --git a/builtin/add.c b/builtin/add.c\nindex ec6fbe3..2b20d7d 100644\n--- a/builtin/add.c\n+++ b/builtin/add.c\n@@ -139,16 +139,12 @@ static void refresh(int verbose, const char **pathspec)\n }\n \n int run_add_interactive(const char *revision, const char *patch_mode,\n-\t\t\tconst char **pathspec)\n+\t\t\tconst struct pathspec *pathspec)\n {\n-\tint status, ac, pc = 0;\n+\tint status, ac, i;\n \tconst char **args;\n \n-\tif (pathspec)\n-\t\twhile (pathspec[pc])\n-\t\t\tpc++;\n-\n-\targs = xcalloc(sizeof(const char *), (pc + 5));\n+\targs = xcalloc(sizeof(const char *), (pathspec->nr + 6));\n \tac = 0;\n \targs[ac++] = \"add--interactive\";\n \tif (patch_mode)\n@@ -156,11 +152,9 @@ int run_add_interactive(const char *revision, const char *patch_mode,\n \tif (revision)\n \t\targs[ac++] = revision;\n \targs[ac++] = \"--\";\n-\tif (pc) {\n-\t\tmemcpy(&(args[ac]), pathspec, sizeof(const char *) * pc);\n-\t\tac += pc;\n-\t}\n-\targs[ac] = NULL;\n+\tfor (i = 0; i < pathspec->nr; i++)\n+\t\t/* pass original pathspec, to be re-parsed */\n+\t\targs[ac++] = pathspec->items[i].original;\n \n \tstatus = run_command_v_opt(args, RUN_GIT_CMD);\n \tfree(args);\n@@ -175,17 +169,17 @@ int interactive_add(int argc, const char **argv, const char *prefix, int patch)\n \t * git-add--interactive itself does not parse pathspec. It\n \t * simply passes the pathspec to other builtin commands. Let's\n \t * hope all of them support all magic, or we'll need to limit\n-\t * the magic here. There is still a problem with prefix. But\n-\t * that'll be worked on later on.\n+\t * the magic here.\n \t */\n \tparse_pathspec(&pathspec, PATHSPEC_ALL_MAGIC & ~PATHSPEC_FROMTOP,\n \t\t       PATHSPEC_PREFER_FULL |\n-\t\t       PATHSPEC_SYMLINK_LEADING_PATH,\n+\t\t       PATHSPEC_SYMLINK_LEADING_PATH |\n+\t\t       PATHSPEC_PREFIX_ORIGIN,\n \t\t       prefix, argv);\n \n \treturn run_add_interactive(NULL,\n \t\t\t\t   patch ? \"--patch\" : NULL,\n-\t\t\t\t   pathspec.raw);\n+\t\t\t\t   &pathspec);\n }\n \n static int edit_patch(int argc, const char **argv, const char *prefix)\ndiff --git a/builtin/checkout.c b/builtin/checkout.c\nindex 3c19cb4..2ddff95 100644\n--- a/builtin/checkout.c\n+++ b/builtin/checkout.c\n@@ -256,7 +256,7 @@ static int checkout_paths(const struct checkout_opts *opts,\n \n \tif (opts->patch_mode)\n \t\treturn run_add_interactive(revision, \"--patch=checkout\",\n-\t\t\t\t\t   opts->pathspec.raw);\n+\t\t\t\t\t   &opts->pathspec);\n \n \tlock_file = xcalloc(1, sizeof(struct lock_file));\n \n@@ -1115,10 +1115,9 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)\n \t\t * cannot handle. Magic mask is pretty safe to be\n \t\t * lifted for new magic when opts.patch_mode == 0.\n \t\t */\n-\t\tparse_pathspec(&opts.pathspec,\n-\t\t\t       opts.patch_mode == 0 ? 0 :\n-\t\t\t       (PATHSPEC_ALL_MAGIC & ~PATHSPEC_FROMTOP),\n-\t\t\t       0, prefix, argv);\n+\t\tparse_pathspec(&opts.pathspec, 0,\n+\t\t\t       opts.patch_mode ? PATHSPEC_PREFIX_ORIGIN : 0,\n+\t\t\t       prefix, argv);\n \n \t\tif (!opts.pathspec.nr)\n \t\t\tdie(_(\"invalid path specification\"));\ndiff --git a/builtin/reset.c b/builtin/reset.c\nindex da7282e..7c6e8b6 100644\n--- a/builtin/reset.c\n+++ b/builtin/reset.c\n@@ -216,9 +216,9 @@ static void parse_args(struct pathspec *pathspec,\n \t\t}\n \t}\n \t*rev_ret = rev;\n-\tparse_pathspec(pathspec,\n-\t\t       patch_mode ? PATHSPEC_ALL_MAGIC & ~PATHSPEC_FROMTOP : 0,\n-\t\t       PATHSPEC_PREFER_FULL,\n+\tparse_pathspec(pathspec, 0,\n+\t\t       PATHSPEC_PREFER_FULL |\n+\t\t       patch_mode ? PATHSPEC_PREFIX_ORIGIN : 0,\n \t\t       prefix, argv);\n }\n \n@@ -296,7 +296,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix)\n \tif (patch_mode) {\n \t\tif (reset_type != NONE)\n \t\t\tdie(_(\"--patch is incompatible with --{hard,mixed,soft}\"));\n-\t\treturn run_add_interactive(sha1_to_hex(sha1), \"--patch=reset\", pathspec.raw);\n+\t\treturn run_add_interactive(sha1_to_hex(sha1), \"--patch=reset\", &pathspec);\n \t}\n \n \t/* git reset tree [--] paths... can be used to\ndiff --git a/commit.h b/commit.h\nindex 4138bb4..9448fda 100644\n--- a/commit.h\n+++ b/commit.h\n@@ -179,7 +179,7 @@ int in_merge_bases(struct commit *, struct commit *);\n \n extern int interactive_add(int argc, const char **argv, const char *prefix, int patch);\n extern int run_add_interactive(const char *revision, const char *patch_mode,\n-\t\t\t       const char **pathspec);\n+\t\t\t       const struct pathspec *pathspec);\n \n static inline int single_parent(struct commit *commit)\n {\n-- \n1.8.0.rc0.19.g7bbb31d\n"},{"id":"211372","messageId":"1363327620-29017-29-git-send-email-pclouds@gmail.com","threadId":"33187","inReplyTo":"1363327620-29017-1-git-send-email-pclouds@gmail.com","subject":"[PATCH v1 28/45] Convert unmerge_cache to take struct pathspec","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2013-03-15T06:06:43Z","receivedAt":"2013-03-15T06:06:43Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n builtin/checkout.c | 2 +-\n rerere.c           | 2 +-\n resolve-undo.c     | 4 ++--\n resolve-undo.h     | 2 +-\n 4 files changed, 5 insertions(+), 5 deletions(-)\n\ndiff --git a/builtin/checkout.c b/builtin/checkout.c\nindex 2ddff95..ba5a5c0 100644\n--- a/builtin/checkout.c\n+++ b/builtin/checkout.c\n@@ -281,7 +281,7 @@ static int checkout_paths(const struct checkout_opts *opts,\n \n \t/* \"checkout -m path\" to recreate conflicted state */\n \tif (opts->merge)\n-\t\tunmerge_cache(opts->pathspec.raw);\n+\t\tunmerge_cache(&opts->pathspec);\n \n \t/* Any unmerged paths? */\n \tfor (pos = 0; pos < active_nr; pos++) {\ndiff --git a/rerere.c b/rerere.c\nindex c52c1f2..ac02eb8 100644\n--- a/rerere.c\n+++ b/rerere.c\n@@ -667,7 +667,7 @@ int rerere_forget(struct pathspec *pathspec)\n \n \tfd = setup_rerere(&merge_rr, RERERE_NOAUTOUPDATE);\n \n-\tunmerge_cache(pathspec->raw);\n+\tunmerge_cache(pathspec);\n \tfind_conflict(&conflict);\n \tfor (i = 0; i < conflict.nr; i++) {\n \t\tstruct string_list_item *it = &conflict.items[i];\ndiff --git a/resolve-undo.c b/resolve-undo.c\nindex 72b4612..1bfece2 100644\n--- a/resolve-undo.c\n+++ b/resolve-undo.c\n@@ -156,7 +156,7 @@ int unmerge_index_entry_at(struct index_state *istate, int pos)\n \treturn unmerge_index_entry_at(istate, pos);\n }\n \n-void unmerge_index(struct index_state *istate, const char **pathspec)\n+void unmerge_index(struct index_state *istate, const struct pathspec *pathspec)\n {\n \tint i;\n \n@@ -165,7 +165,7 @@ void unmerge_index(struct index_state *istate, const char **pathspec)\n \n \tfor (i = 0; i < istate->cache_nr; i++) {\n \t\tstruct cache_entry *ce = istate->cache[i];\n-\t\tif (!match_pathspec(pathspec, ce->name, ce_namelen(ce), 0, NULL))\n+\t\tif (!match_pathspec_depth(pathspec, ce->name, ce_namelen(ce), 0, NULL))\n \t\t\tcontinue;\n \t\ti = unmerge_index_entry_at(istate, i);\n \t}\ndiff --git a/resolve-undo.h b/resolve-undo.h\nindex 8458769..81e8803 100644\n--- a/resolve-undo.h\n+++ b/resolve-undo.h\n@@ -11,6 +11,6 @@ extern void resolve_undo_write(struct strbuf *, struct string_list *);\n extern struct string_list *resolve_undo_read(const char *, unsigned long);\n extern void resolve_undo_clear_index(struct index_state *);\n extern int unmerge_index_entry_at(struct index_state *, int);\n-extern void unmerge_index(struct index_state *, const char **);\n+extern void unmerge_index(struct index_state *, const struct pathspec *);\n \n #endif\n-- \n1.8.0.rc0.19.g7bbb31d\n"},{"id":"211373","messageId":"1363327620-29017-30-git-send-email-pclouds@gmail.com","threadId":"33187","inReplyTo":"1363327620-29017-1-git-send-email-pclouds@gmail.com","subject":"[PATCH v1 29/45] checkout: convert read_tree_some to take struct pathspec","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2013-03-15T06:06:44Z","receivedAt":"2013-03-15T06:06:44Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n builtin/checkout.c | 9 +++------\n tree.c             | 4 ++--\n tree.h             | 2 +-\n 3 files changed, 6 insertions(+), 9 deletions(-)\n\ndiff --git a/builtin/checkout.c b/builtin/checkout.c\nindex ba5a5c0..132bfe6 100644\n--- a/builtin/checkout.c\n+++ b/builtin/checkout.c\n@@ -82,12 +82,9 @@ static int update_some(const unsigned char *sha1, const char *base, int baselen,\n \treturn 0;\n }\n \n-static int read_tree_some(struct tree *tree, const char **pathspec)\n+static int read_tree_some(struct tree *tree, const struct pathspec *pathspec)\n {\n-\tstruct pathspec ps;\n-\tinit_pathspec(&ps, pathspec);\n-\tread_tree_recursive(tree, \"\", 0, 0, &ps, update_some, NULL);\n-\tfree_pathspec(&ps);\n+\tread_tree_recursive(tree, \"\", 0, 0, pathspec, update_some, NULL);\n \n \t/* update the index with the given tree's info\n \t * for all args, expanding wildcards, and exit\n@@ -265,7 +262,7 @@ static int checkout_paths(const struct checkout_opts *opts,\n \t\treturn error(_(\"corrupt index file\"));\n \n \tif (opts->source_tree)\n-\t\tread_tree_some(opts->source_tree, opts->pathspec.raw);\n+\t\tread_tree_some(opts->source_tree, &opts->pathspec);\n \n \tps_matched = xcalloc(1, opts->pathspec.nr);\n \ndiff --git a/tree.c b/tree.c\nindex 62fed63..ff72f67 100644\n--- a/tree.c\n+++ b/tree.c\n@@ -47,7 +47,7 @@ static int read_one_entry_quick(const unsigned char *sha1, const char *base, int\n }\n \n static int read_tree_1(struct tree *tree, struct strbuf *base,\n-\t\t       int stage, struct pathspec *pathspec,\n+\t\t       int stage, const struct pathspec *pathspec,\n \t\t       read_tree_fn_t fn, void *context)\n {\n \tstruct tree_desc desc;\n@@ -116,7 +116,7 @@ static int read_tree_1(struct tree *tree, struct strbuf *base,\n \n int read_tree_recursive(struct tree *tree,\n \t\t\tconst char *base, int baselen,\n-\t\t\tint stage, struct pathspec *pathspec,\n+\t\t\tint stage, const struct pathspec *pathspec,\n \t\t\tread_tree_fn_t fn, void *context)\n {\n \tstruct strbuf sb = STRBUF_INIT;\ndiff --git a/tree.h b/tree.h\nindex 69bcb5e..9dc90ba 100644\n--- a/tree.h\n+++ b/tree.h\n@@ -25,7 +25,7 @@ typedef int (*read_tree_fn_t)(const unsigned char *, const char *, int, const ch\n \n extern int read_tree_recursive(struct tree *tree,\n \t\t\t       const char *base, int baselen,\n-\t\t\t       int stage, struct pathspec *pathspec,\n+\t\t\t       int stage, const struct pathspec *pathspec,\n \t\t\t       read_tree_fn_t fn, void *context);\n \n extern int read_tree(struct tree *tree, int stage, struct pathspec *pathspec);\n-- \n1.8.0.rc0.19.g7bbb31d\n"},{"id":"211374","messageId":"1363327620-29017-31-git-send-email-pclouds@gmail.com","threadId":"33187","inReplyTo":"1363327620-29017-1-git-send-email-pclouds@gmail.com","subject":"[PATCH v1 30/45] Convert report_path_error to take struct pathspec","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2013-03-15T06:06:45Z","receivedAt":"2013-03-15T06:06:45Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n builtin/checkout.c |  2 +-\n builtin/commit.c   | 14 ++++++--------\n builtin/ls-files.c | 19 +++++++++++--------\n cache.h            |  2 +-\n 4 files changed, 19 insertions(+), 18 deletions(-)\n\ndiff --git a/builtin/checkout.c b/builtin/checkout.c\nindex 132bfe6..cd459e1 100644\n--- a/builtin/checkout.c\n+++ b/builtin/checkout.c\n@@ -273,7 +273,7 @@ static int checkout_paths(const struct checkout_opts *opts,\n \t\tmatch_pathspec_depth(&opts->pathspec, ce->name, ce_namelen(ce), 0, ps_matched);\n \t}\n \n-\tif (report_path_error(ps_matched, opts->pathspec.raw, opts->prefix))\n+\tif (report_path_error(ps_matched, &opts->pathspec, opts->prefix))\n \t\treturn 1;\n \n \t/* \"checkout -m path\" to recreate conflicted state */\ndiff --git a/builtin/commit.c b/builtin/commit.c\nindex 564f359..eba53af 100644\n--- a/builtin/commit.c\n+++ b/builtin/commit.c\n@@ -181,20 +181,18 @@ static int commit_index_files(void)\n  * and return the paths that match the given pattern in list.\n  */\n static int list_paths(struct string_list *list, const char *with_tree,\n-\t\t      const char *prefix, const char **pattern)\n+\t\t      const char *prefix, const struct pathspec *pattern)\n {\n \tint i;\n \tchar *m;\n \n-\tif (!pattern)\n+\tif (!pattern->nr)\n \t\treturn 0;\n \n-\tfor (i = 0; pattern[i]; i++)\n-\t\t;\n-\tm = xcalloc(1, i);\n+\tm = xcalloc(1, pattern->nr);\n \n \tif (with_tree) {\n-\t\tchar *max_prefix = common_prefix(pattern);\n+\t\tchar *max_prefix = common_prefix(pattern->raw);\n \t\toverlay_tree_on_cache(with_tree, max_prefix ? max_prefix : prefix);\n \t\tfree(max_prefix);\n \t}\n@@ -205,7 +203,7 @@ static int list_paths(struct string_list *list, const char *with_tree,\n \n \t\tif (ce->ce_flags & CE_UPDATE)\n \t\t\tcontinue;\n-\t\tif (!match_pathspec(pattern, ce->name, ce_namelen(ce), 0, m))\n+\t\tif (!match_pathspec_depth(pattern, ce->name, ce_namelen(ce), 0, m))\n \t\t\tcontinue;\n \t\titem = string_list_insert(list, ce->name);\n \t\tif (ce_skip_worktree(ce))\n@@ -395,7 +393,7 @@ static char *prepare_index(int argc, const char **argv, const char *prefix,\n \n \tmemset(&partial, 0, sizeof(partial));\n \tpartial.strdup_strings = 1;\n-\tif (list_paths(&partial, !current_head ? NULL : \"HEAD\", prefix, pathspec.raw))\n+\tif (list_paths(&partial, !current_head ? NULL : \"HEAD\", prefix, &pathspec))\n \t\texit(1);\n \n \tdiscard_cache();\ndiff --git a/builtin/ls-files.c b/builtin/ls-files.c\nindex bd64829..a33ea18 100644\n--- a/builtin/ls-files.c\n+++ b/builtin/ls-files.c\n@@ -351,15 +351,16 @@ void overlay_tree_on_cache(const char *tree_name, const char *prefix)\n \t}\n }\n \n-int report_path_error(const char *ps_matched, const char **pathspec, const char *prefix)\n+int report_path_error(const char *ps_matched,\n+\t\t      const struct pathspec *pathspec,\n+\t\t      const char *prefix)\n {\n \t/*\n \t * Make sure all pathspec matched; otherwise it is an error.\n \t */\n \tstruct strbuf sb = STRBUF_INIT;\n-\tconst char *name;\n \tint num, errors = 0;\n-\tfor (num = 0; pathspec[num]; num++) {\n+\tfor (num = 0; num < pathspec->nr; num++) {\n \t\tint other, found_dup;\n \n \t\tif (ps_matched[num])\n@@ -367,13 +368,16 @@ int report_path_error(const char *ps_matched, const char **pathspec, const char\n \t\t/*\n \t\t * The caller might have fed identical pathspec\n \t\t * twice.  Do not barf on such a mistake.\n+\t\t * FIXME: parse_pathspec should have eliminated\n+\t\t * duplicate pathspec.\n \t\t */\n \t\tfor (found_dup = other = 0;\n-\t\t     !found_dup && pathspec[other];\n+\t\t     !found_dup && other < pathspec->nr;\n \t\t     other++) {\n \t\t\tif (other == num || !ps_matched[other])\n \t\t\t\tcontinue;\n-\t\t\tif (!strcmp(pathspec[other], pathspec[num]))\n+\t\t\tif (!strcmp(pathspec->items[other].original,\n+\t\t\t\t    pathspec->items[num].original))\n \t\t\t\t/*\n \t\t\t\t * Ok, we have a match already.\n \t\t\t\t */\n@@ -382,9 +386,8 @@ int report_path_error(const char *ps_matched, const char **pathspec, const char\n \t\tif (found_dup)\n \t\t\tcontinue;\n \n-\t\tname = quote_path_relative(pathspec[num], -1, &sb, prefix);\n \t\terror(\"pathspec '%s' did not match any file(s) known to git.\",\n-\t\t      name);\n+\t\t      pathspec->items[num].original);\n \t\terrors++;\n \t}\n \tstrbuf_release(&sb);\n@@ -580,7 +583,7 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)\n \n \tif (ps_matched) {\n \t\tint bad;\n-\t\tbad = report_path_error(ps_matched, pathspec.raw, prefix);\n+\t\tbad = report_path_error(ps_matched, &pathspec, prefix);\n \t\tif (bad)\n \t\t\tfprintf(stderr, \"Did you forget to 'git add'?\\n\");\n \ndiff --git a/cache.h b/cache.h\nindex cc90d7b..e5c3e26 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -1267,7 +1267,7 @@ extern int ws_blank_line(const char *line, int len, unsigned ws_rule);\n #define ws_tab_width(rule)     ((rule) & WS_TAB_WIDTH_MASK)\n \n /* ls-files */\n-int report_path_error(const char *ps_matched, const char **pathspec, const char *prefix);\n+int report_path_error(const char *ps_matched, const struct pathspec *pathspec, const char *prefix);\n void overlay_tree_on_cache(const char *tree_name, const char *prefix);\n \n char *alias_lookup(const char *alias);\n-- \n1.8.0.rc0.19.g7bbb31d\n"},{"id":"211375","messageId":"1363327620-29017-32-git-send-email-pclouds@gmail.com","threadId":"33187","inReplyTo":"1363327620-29017-1-git-send-email-pclouds@gmail.com","subject":"[PATCH v1 31/45] Convert refresh_index to take struct pathspec","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2013-03-15T06:06:46Z","receivedAt":"2013-03-15T06:06:46Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n builtin/add.c    | 15 +++++++--------\n builtin/commit.c |  2 +-\n builtin/rm.c     |  2 +-\n cache.h          |  2 +-\n read-cache.c     |  5 +++--\n 5 files changed, 13 insertions(+), 13 deletions(-)\n\ndiff --git a/builtin/add.c b/builtin/add.c\nindex 2b20d7d..cae002d 100644\n--- a/builtin/add.c\n+++ b/builtin/add.c\n@@ -121,19 +121,18 @@ static char *prune_directory(struct dir_struct *dir, const char **pathspec, int\n \treturn seen;\n }\n \n-static void refresh(int verbose, const char **pathspec)\n+static void refresh(int verbose, const struct pathspec *pathspec)\n {\n \tchar *seen;\n-\tint i, specs;\n+\tint i;\n \n-\tfor (specs = 0; pathspec[specs];  specs++)\n-\t\t/* nothing */;\n-\tseen = xcalloc(specs, 1);\n+\tseen = xcalloc(pathspec->nr, 1);\n \trefresh_index(&the_index, verbose ? REFRESH_IN_PORCELAIN : REFRESH_QUIET,\n \t\t      pathspec, seen, _(\"Unstaged changes after refreshing the index:\"));\n-\tfor (i = 0; i < specs; i++) {\n+\tfor (i = 0; i < pathspec->nr; i++) {\n \t\tif (!seen[i])\n-\t\t\tdie(_(\"pathspec '%s' did not match any files\"), pathspec[i]);\n+\t\t\tdie(_(\"pathspec '%s' did not match any files\"),\n+\t\t\t    pathspec->items[i].match);\n \t}\n         free(seen);\n }\n@@ -412,7 +411,7 @@ int cmd_add(int argc, const char **argv, const char *prefix)\n \t}\n \n \tif (refresh_only) {\n-\t\trefresh(verbose, pathspec.raw);\n+\t\trefresh(verbose, &pathspec);\n \t\tgoto finish;\n \t}\n \ndiff --git a/builtin/commit.c b/builtin/commit.c\nindex eba53af..75ce807 100644\n--- a/builtin/commit.c\n+++ b/builtin/commit.c\n@@ -1198,7 +1198,7 @@ int cmd_status(int argc, const char **argv, const char *prefix)\n \t\t       prefix, argv);\n \n \tread_cache_preload(&s.pathspec);\n-\trefresh_index(&the_index, REFRESH_QUIET|REFRESH_UNMERGED, s.pathspec.raw, NULL, NULL);\n+\trefresh_index(&the_index, REFRESH_QUIET|REFRESH_UNMERGED, &s.pathspec, NULL, NULL);\n \n \tfd = hold_locked_index(&index_lock, 0);\n \tif (0 <= fd)\ndiff --git a/builtin/rm.c b/builtin/rm.c\nindex eb1b745..b84d6c7 100644\n--- a/builtin/rm.c\n+++ b/builtin/rm.c\n@@ -251,7 +251,7 @@ int cmd_rm(int argc, const char **argv, const char *prefix)\n \t}\n \n \tparse_pathspec(&pathspec, 0, PATHSPEC_PREFER_CWD, prefix, argv);\n-\trefresh_index(&the_index, REFRESH_QUIET, pathspec.raw, NULL, NULL);\n+\trefresh_index(&the_index, REFRESH_QUIET, &pathspec, NULL, NULL);\n \n \tseen = NULL;\n \tseen = xcalloc(pathspec.nr, 1);\ndiff --git a/cache.h b/cache.h\nindex e5c3e26..26d0f98 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -490,7 +490,7 @@ extern void fill_stat_cache_info(struct cache_entry *ce, struct stat *st);\n #define REFRESH_IGNORE_MISSING\t0x0008\t/* ignore non-existent */\n #define REFRESH_IGNORE_SUBMODULES\t0x0010\t/* ignore submodules */\n #define REFRESH_IN_PORCELAIN\t0x0020\t/* user friendly output, not \"needs update\" */\n-extern int refresh_index(struct index_state *, unsigned int flags, const char **pathspec, char *seen, const char *header_msg);\n+extern int refresh_index(struct index_state *, unsigned int flags, const struct pathspec *pathspec, char *seen, const char *header_msg);\n \n struct lock_file {\n \tstruct lock_file *next;\ndiff --git a/read-cache.c b/read-cache.c\nindex 827ae55..9715af0 100644\n--- a/read-cache.c\n+++ b/read-cache.c\n@@ -1097,7 +1097,8 @@ static void show_file(const char * fmt, const char * name, int in_porcelain,\n \tprintf(fmt, name);\n }\n \n-int refresh_index(struct index_state *istate, unsigned int flags, const char **pathspec,\n+int refresh_index(struct index_state *istate, unsigned int flags,\n+\t\t  const struct pathspec *pathspec,\n \t\t  char *seen, const char *header_msg)\n {\n \tint i;\n@@ -1132,7 +1133,7 @@ int refresh_index(struct index_state *istate, unsigned int flags, const char **p\n \t\t\tcontinue;\n \n \t\tif (pathspec &&\n-\t\t    !match_pathspec(pathspec, ce->name, ce_namelen(ce), 0, seen))\n+\t\t    !match_pathspec_depth(pathspec, ce->name, ce_namelen(ce), 0, seen))\n \t\t\tfiltered = 1;\n \n \t\tif (ce_stage(ce)) {\n-- \n1.8.0.rc0.19.g7bbb31d\n"},{"id":"211376","messageId":"1363327620-29017-33-git-send-email-pclouds@gmail.com","threadId":"33187","inReplyTo":"1363327620-29017-1-git-send-email-pclouds@gmail.com","subject":"[PATCH v1 32/45] Convert {read,fill}_directory to take struct pathspec","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2013-03-15T06:06:47Z","receivedAt":"2013-03-15T06:06:47Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n builtin/add.c      |  2 +-\n builtin/clean.c    |  2 +-\n builtin/grep.c     |  2 +-\n builtin/ls-files.c |  2 +-\n dir.c              | 16 +++++++++++-----\n dir.h              |  4 ++--\n wt-status.c        |  4 ++--\n 7 files changed, 19 insertions(+), 13 deletions(-)\n\ndiff --git a/builtin/add.c b/builtin/add.c\nindex cae002d..7b9e50c 100644\n--- a/builtin/add.c\n+++ b/builtin/add.c\n@@ -405,7 +405,7 @@ int cmd_add(int argc, const char **argv, const char *prefix)\n \t\t}\n \n \t\t/* This picks up the paths that are not tracked */\n-\t\tbaselen = fill_directory(&dir, pathspec.raw);\n+\t\tbaselen = fill_directory(&dir, &pathspec);\n \t\tif (pathspec.nr)\n \t\t\tseen = prune_directory(&dir, pathspec.raw, baselen);\n \t}\ndiff --git a/builtin/clean.c b/builtin/clean.c\nindex fdd4980..d540ca4 100644\n--- a/builtin/clean.c\n+++ b/builtin/clean.c\n@@ -214,7 +214,7 @@ int cmd_clean(int argc, const char **argv, const char *prefix)\n \t\t       PATHSPEC_PREFER_CWD,\n \t\t       prefix, argv);\n \n-\tfill_directory(&dir, pathspec.raw);\n+\tfill_directory(&dir, &pathspec);\n \n \tfor (i = 0; i < dir.nr; i++) {\n \t\tstruct dir_entry *ent = dir.entries[i];\ndiff --git a/builtin/grep.c b/builtin/grep.c\nindex 1c7397a..301d280 100644\n--- a/builtin/grep.c\n+++ b/builtin/grep.c\n@@ -523,7 +523,7 @@ static int grep_directory(struct grep_opt *opt, const struct pathspec *pathspec,\n \tif (exc_std)\n \t\tsetup_standard_excludes(&dir);\n \n-\tfill_directory(&dir, pathspec->raw);\n+\tfill_directory(&dir, pathspec);\n \tfor (i = 0; i < dir.nr; i++) {\n \t\tconst char *name = dir.entries[i]->name;\n \t\tint namelen = strlen(name);\ndiff --git a/builtin/ls-files.c b/builtin/ls-files.c\nindex a33ea18..37f0392 100644\n--- a/builtin/ls-files.c\n+++ b/builtin/ls-files.c\n@@ -218,7 +218,7 @@ static void show_files(struct dir_struct *dir)\n \n \t/* For cached/deleted files we don't need to even do the readdir */\n \tif (show_others || show_killed) {\n-\t\tfill_directory(dir, pathspec.raw);\n+\t\tfill_directory(dir, &pathspec);\n \t\tif (show_others)\n \t\t\tshow_other_files(dir);\n \t\tif (show_killed)\ndiff --git a/dir.c b/dir.c\nindex 6094ba8..20e6a3e 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -99,7 +99,7 @@ char *common_prefix(const char **pathspec)\n \treturn len ? xmemdupz(*pathspec, len) : NULL;\n }\n \n-int fill_directory(struct dir_struct *dir, const char **pathspec)\n+int fill_directory(struct dir_struct *dir, const struct pathspec *pathspec)\n {\n \tsize_t len;\n \n@@ -107,10 +107,10 @@ int fill_directory(struct dir_struct *dir, const char **pathspec)\n \t * Calculate common prefix for the pathspec, and\n \t * use that to optimize the directory walk\n \t */\n-\tlen = common_prefix_len(pathspec);\n+\tlen = common_prefix_len(pathspec->raw);\n \n \t/* Read the directory and prune it */\n-\tread_directory(dir, pathspec ? *pathspec : \"\", len, pathspec);\n+\tread_directory(dir, pathspec->nr ? pathspec->raw[0] : \"\", len, pathspec);\n \treturn len;\n }\n \n@@ -1438,14 +1438,20 @@ static int treat_leading_path(struct dir_struct *dir,\n \treturn rc;\n }\n \n-int read_directory(struct dir_struct *dir, const char *path, int len, const char **pathspec)\n+int read_directory(struct dir_struct *dir, const char *path, int len, const struct pathspec *pathspec)\n {\n \tstruct path_simplify *simplify;\n \n+\t/*\n+\t * Check out create_simplify()\n+\t */\n+\tif (pathspec)\n+\t\tGUARD_PATHSPEC(pathspec, PATHSPEC_FROMTOP | PATHSPEC_MAXDEPTH);\n+\n \tif (has_symlink_leading_path(path, len))\n \t\treturn dir->nr;\n \n-\tsimplify = create_simplify(pathspec);\n+\tsimplify = create_simplify(pathspec ? pathspec->raw : NULL);\n \tif (!len || treat_leading_path(dir, path, len, simplify))\n \t\tread_directory_recursive(dir, path, len, 0, simplify);\n \tfree_simplify(simplify);\ndiff --git a/dir.h b/dir.h\nindex 89427fd..70fdc98 100644\n--- a/dir.h\n+++ b/dir.h\n@@ -134,8 +134,8 @@ extern int match_pathspec_depth(const struct pathspec *pathspec,\n \t\t\t\tint prefix, char *seen);\n extern int within_depth(const char *name, int namelen, int depth, int max_depth);\n \n-extern int fill_directory(struct dir_struct *dir, const char **pathspec);\n-extern int read_directory(struct dir_struct *, const char *path, int len, const char **pathspec);\n+extern int fill_directory(struct dir_struct *dir, const struct pathspec *pathspec);\n+extern int read_directory(struct dir_struct *, const char *path, int len, const struct pathspec *pathspec);\n \n extern int is_excluded_from_list(const char *pathname, int pathlen, const char *basename,\n \t\t\t\t int *dtype, struct exclude_list *el);\ndiff --git a/wt-status.c b/wt-status.c\nindex 5dec9af..1105fdd 100644\n--- a/wt-status.c\n+++ b/wt-status.c\n@@ -503,7 +503,7 @@ static void wt_status_collect_untracked(struct wt_status *s)\n \t\t\tDIR_SHOW_OTHER_DIRECTORIES | DIR_HIDE_EMPTY_DIRECTORIES;\n \tsetup_standard_excludes(&dir);\n \n-\tfill_directory(&dir, s->pathspec.raw);\n+\tfill_directory(&dir, &s->pathspec);\n \tfor (i = 0; i < dir.nr; i++) {\n \t\tstruct dir_entry *ent = dir.entries[i];\n \t\tif (cache_name_is_other(ent->name, ent->len) &&\n@@ -517,7 +517,7 @@ static void wt_status_collect_untracked(struct wt_status *s)\n \t\tdir.flags = DIR_SHOW_IGNORED;\n \t\tif (s->show_untracked_files != SHOW_ALL_UNTRACKED_FILES)\n \t\t\tdir.flags |= DIR_SHOW_OTHER_DIRECTORIES;\n-\t\tfill_directory(&dir, s->pathspec.raw);\n+\t\tfill_directory(&dir, &s->pathspec);\n \t\tfor (i = 0; i < dir.nr; i++) {\n \t\t\tstruct dir_entry *ent = dir.entries[i];\n \t\t\tif (cache_name_is_other(ent->name, ent->len) &&\n-- \n1.8.0.rc0.19.g7bbb31d\n"},{"id":"211377","messageId":"1363327620-29017-34-git-send-email-pclouds@gmail.com","threadId":"33187","inReplyTo":"1363327620-29017-1-git-send-email-pclouds@gmail.com","subject":"[PATCH v1 33/45] Convert add_files_to_cache to take struct pathspec","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2013-03-15T06:06:48Z","receivedAt":"2013-03-15T06:06:48Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n builtin/add.c    | 8 +++++---\n builtin/commit.c | 2 +-\n cache.h          | 2 +-\n 3 files changed, 7 insertions(+), 5 deletions(-)\n\ndiff --git a/builtin/add.c b/builtin/add.c\nindex 7b9e50c..70bfc05 100644\n--- a/builtin/add.c\n+++ b/builtin/add.c\n@@ -81,13 +81,15 @@ static void update_callback(struct diff_queue_struct *q,\n \t}\n }\n \n-int add_files_to_cache(const char *prefix, const char **pathspec, int flags)\n+int add_files_to_cache(const char *prefix,\n+\t\t       const struct pathspec *pathspec, int flags)\n {\n \tstruct update_callback_data data;\n \tstruct rev_info rev;\n \tinit_revisions(&rev, prefix);\n \tsetup_revisions(0, NULL, &rev, NULL);\n-\tinit_pathspec(&rev.prune_data, pathspec);\n+\tif (pathspec)\n+\t\tcopy_pathspec(&rev.prune_data, pathspec);\n \trev.diffopt.output_format = DIFF_FORMAT_CALLBACK;\n \trev.diffopt.format_callback = update_callback;\n \tdata.flags = flags;\n@@ -446,7 +448,7 @@ int cmd_add(int argc, const char **argv, const char *prefix)\n \n \tplug_bulk_checkin();\n \n-\texit_status |= add_files_to_cache(prefix, pathspec.raw, flags);\n+\texit_status |= add_files_to_cache(prefix, &pathspec, flags);\n \n \tif (add_new_files)\n \t\texit_status |= add_files(&dir, flags);\ndiff --git a/builtin/commit.c b/builtin/commit.c\nindex 75ce807..b5a92fa 100644\n--- a/builtin/commit.c\n+++ b/builtin/commit.c\n@@ -329,7 +329,7 @@ static char *prepare_index(int argc, const char **argv, const char *prefix,\n \t */\n \tif (all || (also && pathspec.nr)) {\n \t\tfd = hold_locked_index(&index_lock, 1);\n-\t\tadd_files_to_cache(also ? prefix : NULL, pathspec.raw, 0);\n+\t\tadd_files_to_cache(also ? prefix : NULL, &pathspec, 0);\n \t\trefresh_cache_or_die(refresh_flags);\n \t\tupdate_main_cache_tree(WRITE_TREE_SILENT);\n \t\tif (write_cache(fd, active_cache, active_nr) ||\ndiff --git a/cache.h b/cache.h\nindex 26d0f98..6297783 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -1233,7 +1233,7 @@ void packet_trace_identity(const char *prog);\n  * return 0 if success, 1 - if addition of a file failed and\n  * ADD_FILES_IGNORE_ERRORS was specified in flags\n  */\n-int add_files_to_cache(const char *prefix, const char **pathspec, int flags);\n+int add_files_to_cache(const char *prefix, const struct pathspec *pathspec, int flags);\n \n /* diff.c */\n extern int diff_auto_refresh_index;\n-- \n1.8.0.rc0.19.g7bbb31d\n"},{"id":"211378","messageId":"1363327620-29017-35-git-send-email-pclouds@gmail.com","threadId":"33187","inReplyTo":"1363327620-29017-1-git-send-email-pclouds@gmail.com","subject":"[PATCH v1 34/45] Convert common_prefix() to use struct pathspec","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2013-03-15T06:06:49Z","receivedAt":"2013-03-15T06:06:49Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"The code now takes advantage of nowildcard_len field.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n builtin/commit.c   |  2 +-\n builtin/ls-files.c |  2 +-\n dir.c              | 31 +++++++++++++++----------------\n dir.h              |  2 +-\n 4 files changed, 18 insertions(+), 19 deletions(-)\n\ndiff --git a/builtin/commit.c b/builtin/commit.c\nindex b5a92fa..1c4b73a 100644\n--- a/builtin/commit.c\n+++ b/builtin/commit.c\n@@ -192,7 +192,7 @@ static int list_paths(struct string_list *list, const char *with_tree,\n \tm = xcalloc(1, pattern->nr);\n \n \tif (with_tree) {\n-\t\tchar *max_prefix = common_prefix(pattern->raw);\n+\t\tchar *max_prefix = common_prefix(pattern);\n \t\toverlay_tree_on_cache(with_tree, max_prefix ? max_prefix : prefix);\n \t\tfree(max_prefix);\n \t}\ndiff --git a/builtin/ls-files.c b/builtin/ls-files.c\nindex 37f0392..f211539 100644\n--- a/builtin/ls-files.c\n+++ b/builtin/ls-files.c\n@@ -551,7 +551,7 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)\n \t\t       prefix, argv);\n \n \t/* Find common prefix for all pathspec's */\n-\tmax_prefix = common_prefix(pathspec.raw);\n+\tmax_prefix = common_prefix(&pathspec);\n \tmax_prefix_len = max_prefix ? strlen(max_prefix) : 0;\n \n \t/* Treat unmatching pathspec elements as errors */\ndiff --git a/dir.c b/dir.c\nindex 20e6a3e..a646e55 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -60,26 +60,25 @@ inline int git_fnmatch(const char *pattern, const char *string,\n \treturn fnmatch(pattern, string, fnm_flags);\n }\n \n-static size_t common_prefix_len(const char **pathspec)\n+static size_t common_prefix_len(const struct pathspec *pathspec)\n {\n-\tconst char *n, *first;\n+\tint n;\n \tsize_t max = 0;\n-\tint literal = limit_pathspec_to_literal();\n \n-\tif (!pathspec)\n-\t\treturn max;\n-\n-\tfirst = *pathspec;\n-\twhile ((n = *pathspec++)) {\n-\t\tsize_t i, len = 0;\n-\t\tfor (i = 0; first == n || i < max; i++) {\n-\t\t\tchar c = n[i];\n-\t\t\tif (!c || c != first[i] || (!literal && is_glob_special(c)))\n+\tGUARD_PATHSPEC(pathspec, PATHSPEC_FROMTOP | PATHSPEC_MAXDEPTH);\n+\n+\tfor (n = 0; n < pathspec->nr; n++) {\n+\t\tsize_t i = 0, len = 0;\n+\t\twhile (i < pathspec->items[n].nowildcard_len &&\n+\t\t       (n == 0 || i < max)) {\n+\t\t\tchar c = pathspec->items[n].match[i];\n+\t\t\tif (c != pathspec->items[0].match[i])\n \t\t\t\tbreak;\n \t\t\tif (c == '/')\n \t\t\t\tlen = i + 1;\n+\t\t\ti++;\n \t\t}\n-\t\tif (first == n || len < max) {\n+\t\tif (n == 0 || len < max) {\n \t\t\tmax = len;\n \t\t\tif (!max)\n \t\t\t\tbreak;\n@@ -92,11 +91,11 @@ static size_t common_prefix_len(const char **pathspec)\n  * Returns a copy of the longest leading path common among all\n  * pathspecs.\n  */\n-char *common_prefix(const char **pathspec)\n+char *common_prefix(const struct pathspec *pathspec)\n {\n \tunsigned long len = common_prefix_len(pathspec);\n \n-\treturn len ? xmemdupz(*pathspec, len) : NULL;\n+\treturn len ? xmemdupz(pathspec->items[0].match, len) : NULL;\n }\n \n int fill_directory(struct dir_struct *dir, const struct pathspec *pathspec)\n@@ -107,7 +106,7 @@ int fill_directory(struct dir_struct *dir, const struct pathspec *pathspec)\n \t * Calculate common prefix for the pathspec, and\n \t * use that to optimize the directory walk\n \t */\n-\tlen = common_prefix_len(pathspec->raw);\n+\tlen = common_prefix_len(pathspec);\n \n \t/* Read the directory and prune it */\n \tread_directory(dir, pathspec->nr ? pathspec->raw[0] : \"\", len, pathspec);\ndiff --git a/dir.h b/dir.h\nindex 70fdc98..d3f76df 100644\n--- a/dir.h\n+++ b/dir.h\n@@ -127,7 +127,7 @@ struct dir_struct {\n #define MATCHED_EXACTLY 3\n extern int simple_length(const char *match);\n extern int no_wildcard(const char *string);\n-extern char *common_prefix(const char **pathspec);\n+extern char *common_prefix(const struct pathspec *pathspec);\n extern int match_pathspec(const char **pathspec, const char *name, int namelen, int prefix, char *seen);\n extern int match_pathspec_depth(const struct pathspec *pathspec,\n \t\t\t\tconst char *name, int namelen,\n-- \n1.8.0.rc0.19.g7bbb31d\n"},{"id":"211379","messageId":"1363327620-29017-36-git-send-email-pclouds@gmail.com","threadId":"33187","inReplyTo":"1363327620-29017-1-git-send-email-pclouds@gmail.com","subject":"[PATCH v1 35/45] Remove diff_tree_{setup,release}_paths","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2013-03-15T06:06:50Z","receivedAt":"2013-03-15T06:06:50Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n builtin/blame.c | 12 ++++++------\n builtin/reset.c |  9 +++++----\n diff.h          |  2 --\n notes-merge.c   |  4 ++--\n revision.c      |  5 +++--\n tree-diff.c     | 18 ++++--------------\n 6 files changed, 20 insertions(+), 30 deletions(-)\n\ndiff --git a/builtin/blame.c b/builtin/blame.c\nindex 86100e9..da2dc4c 100644\n--- a/builtin/blame.c\n+++ b/builtin/blame.c\n@@ -407,7 +407,7 @@ static struct origin *find_origin(struct scoreboard *sb,\n \tpaths[0] = origin->path;\n \tpaths[1] = NULL;\n \n-\tdiff_tree_setup_paths(paths, &diff_opts);\n+\tinit_pathspec(&diff_opts.pathspec, paths);\n \tdiff_setup_done(&diff_opts);\n \n \tif (is_null_sha1(origin->commit->object.sha1))\n@@ -457,7 +457,7 @@ static struct origin *find_origin(struct scoreboard *sb,\n \t\t}\n \t}\n \tdiff_flush(&diff_opts);\n-\tdiff_tree_release_paths(&diff_opts);\n+\tfree_pathspec(&diff_opts.pathspec);\n \tif (porigin) {\n \t\t/*\n \t\t * Create a freestanding copy that is not part of\n@@ -493,7 +493,7 @@ static struct origin *find_rename(struct scoreboard *sb,\n \tdiff_opts.output_format = DIFF_FORMAT_NO_OUTPUT;\n \tdiff_opts.single_follow = origin->path;\n \tpaths[0] = NULL;\n-\tdiff_tree_setup_paths(paths, &diff_opts);\n+\tinit_pathspec(&diff_opts.pathspec, paths);\n \tdiff_setup_done(&diff_opts);\n \n \tif (is_null_sha1(origin->commit->object.sha1))\n@@ -515,7 +515,7 @@ static struct origin *find_rename(struct scoreboard *sb,\n \t\t}\n \t}\n \tdiff_flush(&diff_opts);\n-\tdiff_tree_release_paths(&diff_opts);\n+\tfree_pathspec(&diff_opts.pathspec);\n \treturn porigin;\n }\n \n@@ -1073,7 +1073,7 @@ static int find_copy_in_parent(struct scoreboard *sb,\n \tdiff_opts.output_format = DIFF_FORMAT_NO_OUTPUT;\n \n \tpaths[0] = NULL;\n-\tdiff_tree_setup_paths(paths, &diff_opts);\n+\tinit_pathspec(&diff_opts.pathspec, paths);\n \tdiff_setup_done(&diff_opts);\n \n \t/* Try \"find copies harder\" on new path if requested;\n@@ -1156,7 +1156,7 @@ static int find_copy_in_parent(struct scoreboard *sb,\n \t}\n \treset_scanned_flag(sb);\n \tdiff_flush(&diff_opts);\n-\tdiff_tree_release_paths(&diff_opts);\n+\tfree_pathspec(&diff_opts.pathspec);\n \treturn retval;\n }\n \ndiff --git a/builtin/reset.c b/builtin/reset.c\nindex 7c6e8b6..ab3917d 100644\n--- a/builtin/reset.c\n+++ b/builtin/reset.c\n@@ -130,12 +130,13 @@ static void update_index_from_diff(struct diff_queue_struct *q,\n \t}\n }\n \n-static int read_from_tree(const char **pathspec, unsigned char *tree_sha1)\n+static int read_from_tree(const struct pathspec *pathspec,\n+\t\t\t  unsigned char *tree_sha1)\n {\n \tstruct diff_options opt;\n \n \tmemset(&opt, 0, sizeof(opt));\n-\tdiff_tree_setup_paths(pathspec, &opt);\n+\tcopy_pathspec(&opt.pathspec, pathspec);\n \topt.output_format = DIFF_FORMAT_CALLBACK;\n \topt.format_callback = update_index_from_diff;\n \n@@ -144,7 +145,7 @@ static int read_from_tree(const char **pathspec, unsigned char *tree_sha1)\n \t\treturn 1;\n \tdiffcore_std(&opt);\n \tdiff_flush(&opt);\n-\tdiff_tree_release_paths(&opt);\n+\tfree_pathspec(&opt.pathspec);\n \n \treturn 0;\n }\n@@ -329,7 +330,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix)\n \t\tstruct lock_file *lock = xcalloc(1, sizeof(struct lock_file));\n \t\tint newfd = hold_locked_index(lock, 1);\n \t\tif (reset_type == MIXED) {\n-\t\t\tif (read_from_tree(pathspec.raw, sha1))\n+\t\t\tif (read_from_tree(&pathspec, sha1))\n \t\t\t\treturn 1;\n \t\t} else {\n \t\t\tint err = reset_index(sha1, reset_type, quiet);\ndiff --git a/diff.h b/diff.h\nindex d1bc914..b8df245 100644\n--- a/diff.h\n+++ b/diff.h\n@@ -180,8 +180,6 @@ const char *diff_line_prefix(struct diff_options *);\n \n extern const char mime_boundary_leader[];\n \n-extern void diff_tree_setup_paths(const char **paths, struct diff_options *);\n-extern void diff_tree_release_paths(struct diff_options *);\n extern int diff_tree(struct tree_desc *t1, struct tree_desc *t2,\n \t\t     const char *base, struct diff_options *opt);\n extern int diff_tree_sha1(const unsigned char *old, const unsigned char *new,\ndiff --git a/notes-merge.c b/notes-merge.c\nindex 0f67bd3..f1a3b39 100644\n--- a/notes-merge.c\n+++ b/notes-merge.c\n@@ -169,7 +169,7 @@ static struct notes_merge_pair *diff_tree_remote(struct notes_merge_options *o,\n \t\t       sha1_to_hex(mp->remote));\n \t}\n \tdiff_flush(&opt);\n-\tdiff_tree_release_paths(&opt);\n+\tfree_pathspec(&opt.pathspec);\n \n \t*num_changes = len;\n \treturn changes;\n@@ -255,7 +255,7 @@ static void diff_tree_local(struct notes_merge_options *o,\n \t\t       sha1_to_hex(mp->local));\n \t}\n \tdiff_flush(&opt);\n-\tdiff_tree_release_paths(&opt);\n+\tfree_pathspec(&opt.pathspec);\n }\n \n static void check_notes_merge_worktree(struct notes_merge_options *o)\ndiff --git a/revision.c b/revision.c\nindex e257614..c0ced84 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -1886,12 +1886,13 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s\n \t\trevs->limited = 1;\n \n \tif (revs->prune_data.nr) {\n-\t\tdiff_tree_setup_paths(revs->prune_data.raw, &revs->pruning);\n+\t\tcopy_pathspec(&revs->pruning.pathspec, &revs->prune_data);\n \t\t/* Can't prune commits with rename following: the paths change.. */\n \t\tif (!DIFF_OPT_TST(&revs->diffopt, FOLLOW_RENAMES))\n \t\t\trevs->prune = 1;\n \t\tif (!revs->full_diff)\n-\t\t\tdiff_tree_setup_paths(revs->prune_data.raw, &revs->diffopt);\n+\t\t\tcopy_pathspec(&revs->diffopt.pathspec,\n+\t\t\t\t      &revs->prune_data);\n \t}\n \tif (revs->combine_merges)\n \t\trevs->ignore_merges = 0;\ndiff --git a/tree-diff.c b/tree-diff.c\nindex 5a87614..f4c92f6 100644\n--- a/tree-diff.c\n+++ b/tree-diff.c\n@@ -229,11 +229,11 @@ static void try_to_follow_renames(struct tree_desc *t1, struct tree_desc *t2, co\n \tdiff_opts.break_opt = opt->break_opt;\n \tdiff_opts.rename_score = opt->rename_score;\n \tpaths[0] = NULL;\n-\tdiff_tree_setup_paths(paths, &diff_opts);\n+\tinit_pathspec(&diff_opts.pathspec, paths);\n \tdiff_setup_done(&diff_opts);\n \tdiff_tree(t1, t2, base, &diff_opts);\n \tdiffcore_std(&diff_opts);\n-\tdiff_tree_release_paths(&diff_opts);\n+\tfree_pathspec(&diff_opts.pathspec);\n \n \t/* Go through the new set of filepairing, and see if we find a more interesting one */\n \topt->found_follow = 0;\n@@ -252,9 +252,9 @@ static void try_to_follow_renames(struct tree_desc *t1, struct tree_desc *t2, co\n \t\t\tchoice = p;\n \n \t\t\t/* Update the path we use from now on.. */\n-\t\t\tdiff_tree_release_paths(opt);\n+\t\t\tfree_pathspec(&opt->pathspec);\n \t\t\topt->pathspec.raw[0] = xstrdup(p->one->path);\n-\t\t\tdiff_tree_setup_paths(opt->pathspec.raw, opt);\n+\t\t\tinit_pathspec(&opt->pathspec, opt->pathspec.raw);\n \n \t\t\t/*\n \t\t\t * The caller expects us to return a set of vanilla\n@@ -328,13 +328,3 @@ int diff_root_tree_sha1(const unsigned char *new, const char *base, struct diff_\n \tfree(tree);\n \treturn retval;\n }\n-\n-void diff_tree_release_paths(struct diff_options *opt)\n-{\n-\tfree_pathspec(&opt->pathspec);\n-}\n-\n-void diff_tree_setup_paths(const char **p, struct diff_options *opt)\n-{\n-\tinit_pathspec(&opt->pathspec, p);\n-}\n-- \n1.8.0.rc0.19.g7bbb31d\n"},{"id":"211380","messageId":"1363327620-29017-37-git-send-email-pclouds@gmail.com","threadId":"33187","inReplyTo":"1363327620-29017-1-git-send-email-pclouds@gmail.com","subject":"[PATCH v1 36/45] Remove init_pathspec() in favor of parse_pathspec()","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2013-03-15T06:06:51Z","receivedAt":"2013-03-15T06:06:51Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"While at there, move free_pathspec() to pathspec.c\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n builtin/blame.c    |  8 +-------\n builtin/log.c      |  2 +-\n builtin/ls-files.c | 11 +++++------\n diff-lib.c         |  2 +-\n dir.c              | 58 ------------------------------------------------------\n merge-recursive.c  |  2 +-\n pathspec.c         |  6 ++++++\n pathspec.h         |  1 -\n revision.c         |  2 +-\n tree-diff.c        | 10 +++++-----\n 10 files changed, 21 insertions(+), 81 deletions(-)\n\ndiff --git a/builtin/blame.c b/builtin/blame.c\nindex da2dc4c..5b91e94 100644\n--- a/builtin/blame.c\n+++ b/builtin/blame.c\n@@ -407,7 +407,7 @@ static struct origin *find_origin(struct scoreboard *sb,\n \tpaths[0] = origin->path;\n \tpaths[1] = NULL;\n \n-\tinit_pathspec(&diff_opts.pathspec, paths);\n+\tparse_pathspec(&diff_opts.pathspec, PATHSPEC_ALL_MAGIC, 0, \"\", paths);\n \tdiff_setup_done(&diff_opts);\n \n \tif (is_null_sha1(origin->commit->object.sha1))\n@@ -485,15 +485,12 @@ static struct origin *find_rename(struct scoreboard *sb,\n \tstruct origin *porigin = NULL;\n \tstruct diff_options diff_opts;\n \tint i;\n-\tconst char *paths[2];\n \n \tdiff_setup(&diff_opts);\n \tDIFF_OPT_SET(&diff_opts, RECURSIVE);\n \tdiff_opts.detect_rename = DIFF_DETECT_RENAME;\n \tdiff_opts.output_format = DIFF_FORMAT_NO_OUTPUT;\n \tdiff_opts.single_follow = origin->path;\n-\tpaths[0] = NULL;\n-\tinit_pathspec(&diff_opts.pathspec, paths);\n \tdiff_setup_done(&diff_opts);\n \n \tif (is_null_sha1(origin->commit->object.sha1))\n@@ -1058,7 +1055,6 @@ static int find_copy_in_parent(struct scoreboard *sb,\n \t\t\t       int opt)\n {\n \tstruct diff_options diff_opts;\n-\tconst char *paths[1];\n \tint i, j;\n \tint retval;\n \tstruct blame_list *blame_list;\n@@ -1072,8 +1068,6 @@ static int find_copy_in_parent(struct scoreboard *sb,\n \tDIFF_OPT_SET(&diff_opts, RECURSIVE);\n \tdiff_opts.output_format = DIFF_FORMAT_NO_OUTPUT;\n \n-\tpaths[0] = NULL;\n-\tinit_pathspec(&diff_opts.pathspec, paths);\n \tdiff_setup_done(&diff_opts);\n \n \t/* Try \"find copies harder\" on new path if requested;\ndiff --git a/builtin/log.c b/builtin/log.c\nindex 8f0b2e8..812bcb9 100644\n--- a/builtin/log.c\n+++ b/builtin/log.c\n@@ -469,7 +469,7 @@ int cmd_show(int argc, const char **argv, const char *prefix)\n \tinit_grep_defaults();\n \tgit_config(git_log_config, NULL);\n \n-\tinit_pathspec(&match_all, NULL);\n+\tmemset(&match_all, 0, sizeof(match_all));\n \tinit_revisions(&rev, prefix);\n \trev.diff = 1;\n \trev.always_show_header = 1;\ndiff --git a/builtin/ls-files.c b/builtin/ls-files.c\nindex f211539..50842ba 100644\n--- a/builtin/ls-files.c\n+++ b/builtin/ls-files.c\n@@ -320,13 +320,12 @@ void overlay_tree_on_cache(const char *tree_name, const char *prefix)\n \t}\n \n \tif (prefix) {\n-\t\tstatic const char *(matchbuf[2]);\n-\t\tmatchbuf[0] = prefix;\n-\t\tmatchbuf[1] = NULL;\n-\t\tinit_pathspec(&pathspec, matchbuf);\n-\t\tpathspec.items[0].nowildcard_len = pathspec.items[0].len;\n+\t\tstatic const char *(matchbuf[1]);\n+\t\tmatchbuf[0] = NULL;\n+\t\tparse_pathspec(&pathspec, PATHSPEC_ALL_MAGIC,\n+\t\t\t       PATHSPEC_PREFER_CWD, prefix, matchbuf);\n \t} else\n-\t\tinit_pathspec(&pathspec, NULL);\n+\t\tmemset(&pathspec, 0, sizeof(pathspec));\n \tif (read_tree(tree, 1, &pathspec))\n \t\tdie(\"unable to read tree entries %s\", tree_name);\n \ndiff --git a/diff-lib.c b/diff-lib.c\nindex 4729157..68fc991 100644\n--- a/diff-lib.c\n+++ b/diff-lib.c\n@@ -499,7 +499,7 @@ int do_diff_cache(const unsigned char *tree_sha1, struct diff_options *opt)\n \tstruct rev_info revs;\n \n \tinit_revisions(&revs, NULL);\n-\tinit_pathspec(&revs.prune_data, opt->pathspec.raw);\n+\tcopy_pathspec(&revs.prune_data, &opt->pathspec);\n \trevs.diffopt = *opt;\n \n \tif (diff_cache(&revs, tree_sha1, NULL, 1))\ndiff --git a/dir.c b/dir.c\nindex a646e55..e354abb 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -1630,64 +1630,6 @@ int remove_path(const char *name)\n \treturn 0;\n }\n \n-static int pathspec_item_cmp(const void *a_, const void *b_)\n-{\n-\tstruct pathspec_item *a, *b;\n-\n-\ta = (struct pathspec_item *)a_;\n-\tb = (struct pathspec_item *)b_;\n-\treturn strcmp(a->match, b->match);\n-}\n-\n-int init_pathspec(struct pathspec *pathspec, const char **paths)\n-{\n-\tconst char **p = paths;\n-\tint i;\n-\n-\tmemset(pathspec, 0, sizeof(*pathspec));\n-\tif (!p)\n-\t\treturn 0;\n-\twhile (*p)\n-\t\tp++;\n-\tpathspec->raw = paths;\n-\tpathspec->nr = p - paths;\n-\tif (!pathspec->nr)\n-\t\treturn 0;\n-\n-\tpathspec->items = xmalloc(sizeof(struct pathspec_item)*pathspec->nr);\n-\tfor (i = 0; i < pathspec->nr; i++) {\n-\t\tstruct pathspec_item *item = pathspec->items+i;\n-\t\tconst char *path = paths[i];\n-\n-\t\titem->match = path;\n-\t\titem->original = path;\n-\t\titem->len = strlen(path);\n-\t\titem->flags = 0;\n-\t\tif (limit_pathspec_to_literal()) {\n-\t\t\titem->nowildcard_len = item->len;\n-\t\t} else {\n-\t\t\titem->nowildcard_len = simple_length(path);\n-\t\t\tif (item->nowildcard_len < item->len) {\n-\t\t\t\tpathspec->has_wildcard = 1;\n-\t\t\t\tif (path[item->nowildcard_len] == '*' &&\n-\t\t\t\t    no_wildcard(path + item->nowildcard_len + 1))\n-\t\t\t\t\titem->flags |= PATHSPEC_ONESTAR;\n-\t\t\t}\n-\t\t}\n-\t}\n-\n-\tqsort(pathspec->items, pathspec->nr,\n-\t      sizeof(struct pathspec_item), pathspec_item_cmp);\n-\n-\treturn 0;\n-}\n-\n-void free_pathspec(struct pathspec *pathspec)\n-{\n-\tfree(pathspec->items);\n-\tpathspec->items = NULL;\n-}\n-\n int limit_pathspec_to_literal(void)\n {\n \tstatic int flag = -1;\ndiff --git a/merge-recursive.c b/merge-recursive.c\nindex ea9dbd3..8395b9b 100644\n--- a/merge-recursive.c\n+++ b/merge-recursive.c\n@@ -297,7 +297,7 @@ static int get_files_dirs(struct merge_options *o, struct tree *tree)\n {\n \tint n;\n \tstruct pathspec match_all;\n-\tinit_pathspec(&match_all, NULL);\n+\tmemset(&match_all, 0, sizeof(match_all));\n \tif (read_tree_recursive(tree, \"\", 0, 0, &match_all, save_files_dirs, o))\n \t\treturn 0;\n \tn = o->current_file_set.nr + o->current_directory_set.nr;\ndiff --git a/pathspec.c b/pathspec.c\nindex 0b658cb..767ce65 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -370,3 +370,9 @@ void copy_pathspec(struct pathspec *dst, const struct pathspec *src)\n \tmemcpy(dst->items, src->items,\n \t       sizeof(struct pathspec_item) * dst->nr);\n }\n+\n+void free_pathspec(struct pathspec *pathspec)\n+{\n+\tfree(pathspec->items);\n+\tpathspec->items = NULL;\n+}\ndiff --git a/pathspec.h b/pathspec.h\nindex 44253c8..9e9e442 100644\n--- a/pathspec.h\n+++ b/pathspec.h\n@@ -44,7 +44,6 @@ struct pathspec {\n #define PATHSPEC_PREFIX_ORIGIN (1<<6)\n #define PATHSPEC_KEEP_ORDER (1<<7)\n \n-extern int init_pathspec(struct pathspec *, const char **);\n extern void parse_pathspec(struct pathspec *pathspec,\n \t\t\t   unsigned magic_mask,\n \t\t\t   unsigned flags,\ndiff --git a/revision.c b/revision.c\nindex c0ced84..56ada54 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -1113,7 +1113,7 @@ static void prepare_show_merge(struct rev_info *revs)\n \t\t\ti++;\n \t}\n \tfree_pathspec(&revs->prune_data);\n-\tinit_pathspec(&revs->prune_data, prune);\n+\tparse_pathspec(&revs->prune_data, PATHSPEC_ALL_MAGIC, 0, \"\", prune);\n \trevs->limited = 1;\n }\n \ndiff --git a/tree-diff.c b/tree-diff.c\nindex f4c92f6..e1145c6 100644\n--- a/tree-diff.c\n+++ b/tree-diff.c\n@@ -195,7 +195,6 @@ static void try_to_follow_renames(struct tree_desc *t1, struct tree_desc *t2, co\n \tstruct diff_options diff_opts;\n \tstruct diff_queue_struct *q = &diff_queued_diff;\n \tstruct diff_filepair *choice;\n-\tconst char *paths[1];\n \tint i;\n \n \t/*\n@@ -228,8 +227,6 @@ static void try_to_follow_renames(struct tree_desc *t1, struct tree_desc *t2, co\n \tdiff_opts.single_follow = opt->pathspec.raw[0];\n \tdiff_opts.break_opt = opt->break_opt;\n \tdiff_opts.rename_score = opt->rename_score;\n-\tpaths[0] = NULL;\n-\tinit_pathspec(&diff_opts.pathspec, paths);\n \tdiff_setup_done(&diff_opts);\n \tdiff_tree(t1, t2, base, &diff_opts);\n \tdiffcore_std(&diff_opts);\n@@ -247,14 +244,17 @@ static void try_to_follow_renames(struct tree_desc *t1, struct tree_desc *t2, co\n \t\t */\n \t\tif ((p->status == 'R' || p->status == 'C') &&\n \t\t    !strcmp(p->two->path, opt->pathspec.raw[0])) {\n+\t\t\tconst char *path[2];\n+\n \t\t\t/* Switch the file-pairs around */\n \t\t\tq->queue[i] = choice;\n \t\t\tchoice = p;\n \n \t\t\t/* Update the path we use from now on.. */\n+\t\t\tpath[0] = p->one->path;\n+\t\t\tpath[1] = NULL;\n \t\t\tfree_pathspec(&opt->pathspec);\n-\t\t\topt->pathspec.raw[0] = xstrdup(p->one->path);\n-\t\t\tinit_pathspec(&opt->pathspec, opt->pathspec.raw);\n+\t\t\tparse_pathspec(&opt->pathspec, PATHSPEC_ALL_MAGIC, 0, \"\", path);\n \n \t\t\t/*\n \t\t\t * The caller expects us to return a set of vanilla\n-- \n1.8.0.rc0.19.g7bbb31d\n"},{"id":"211381","messageId":"1363327620-29017-38-git-send-email-pclouds@gmail.com","threadId":"33187","inReplyTo":"1363327620-29017-1-git-send-email-pclouds@gmail.com","subject":"[PATCH v1 37/45] Remove match_pathspec() in favor of match_pathspec_depth()","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2013-03-15T06:06:52Z","receivedAt":"2013-03-15T06:06:52Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"match_pathspec_depth was created to replace match_pathspec (see\n61cf282 (pathspec: add match_pathspec_depth() - 2010-12-15). It took\nmore than two years, but the replacement finally happens :-)\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n builtin/add.c          |  30 +++++++-------\n builtin/check-ignore.c |   4 +-\n dir.c                  | 107 -------------------------------------------------\n dir.h                  |   1 -\n pathspec.c             |  19 ++++-----\n pathspec.h             |   4 +-\n 6 files changed, 25 insertions(+), 140 deletions(-)\n\ndiff --git a/builtin/add.c b/builtin/add.c\nindex 70bfc05..aa0709e 100644\n--- a/builtin/add.c\n+++ b/builtin/add.c\n@@ -100,26 +100,24 @@ int add_files_to_cache(const char *prefix,\n \treturn !!data.add_errors;\n }\n \n-static char *prune_directory(struct dir_struct *dir, const char **pathspec, int prefix)\n+static char *prune_directory(struct dir_struct *dir, struct pathspec *pathspec, int prefix)\n {\n \tchar *seen;\n-\tint i, specs;\n+\tint i;\n \tstruct dir_entry **src, **dst;\n \n-\tfor (specs = 0; pathspec[specs];  specs++)\n-\t\t/* nothing */;\n-\tseen = xcalloc(specs, 1);\n+\tseen = xcalloc(pathspec->nr, 1);\n \n \tsrc = dst = dir->entries;\n \ti = dir->nr;\n \twhile (--i >= 0) {\n \t\tstruct dir_entry *entry = *src++;\n-\t\tif (match_pathspec(pathspec, entry->name, entry->len,\n-\t\t\t\t   prefix, seen))\n+\t\tif (match_pathspec_depth(pathspec, entry->name, entry->len,\n+\t\t\t\t\t prefix, seen))\n \t\t\t*dst++ = entry;\n \t}\n \tdir->nr = dst - dir->entries;\n-\tadd_pathspec_matches_against_index(pathspec, seen, specs);\n+\tadd_pathspec_matches_against_index(pathspec, seen);\n \treturn seen;\n }\n \n@@ -409,7 +407,7 @@ int cmd_add(int argc, const char **argv, const char *prefix)\n \t\t/* This picks up the paths that are not tracked */\n \t\tbaselen = fill_directory(&dir, &pathspec);\n \t\tif (pathspec.nr)\n-\t\t\tseen = prune_directory(&dir, pathspec.raw, baselen);\n+\t\t\tseen = prune_directory(&dir, &pathspec, baselen);\n \t}\n \n \tif (refresh_only) {\n@@ -423,23 +421,23 @@ int cmd_add(int argc, const char **argv, const char *prefix)\n \n \t\tpath_exclude_check_init(&check, &dir);\n \t\tif (!seen)\n-\t\t\tseen = find_pathspecs_matching_against_index(pathspec.raw);\n+\t\t\tseen = find_pathspecs_matching_against_index(&pathspec);\n \n \t\t/*\n \t\t * file_exists() assumes exact match\n \t\t */\n \t\tGUARD_PATHSPEC(&pathspec, PATHSPEC_FROMTOP);\n \n-\t\tfor (i = 0; pathspec.raw[i]; i++) {\n-\t\t\tif (!seen[i] && pathspec.raw[i][0]\n-\t\t\t    && !file_exists(pathspec.raw[i])) {\n+\t\tfor (i = 0; i < pathspec.nr; i++) {\n+\t\t\tconst char *path = pathspec.items[i].match;\n+\t\t\tif (!seen[i] && !file_exists(path)) {\n \t\t\t\tif (ignore_missing) {\n \t\t\t\t\tint dtype = DT_UNKNOWN;\n-\t\t\t\t\tif (is_path_excluded(&check, pathspec.raw[i], -1, &dtype))\n-\t\t\t\t\t\tdir_add_ignored(&dir, pathspec.raw[i], strlen(pathspec.raw[i]));\n+\t\t\t\t\tif (is_path_excluded(&check, path, -1, &dtype))\n+\t\t\t\t\t\tdir_add_ignored(&dir, path, pathspec.items[i].len);\n \t\t\t\t} else\n \t\t\t\t\tdie(_(\"pathspec '%s' did not match any files\"),\n-\t\t\t\t\t    pathspec.raw[i]);\n+\t\t\t\t\t    pathspec.items[i].original);\n \t\t\t}\n \t\t}\n \t\tfree(seen);\ndiff --git a/builtin/check-ignore.c b/builtin/check-ignore.c\nindex 6e55f06..80e6bf7 100644\n--- a/builtin/check-ignore.c\n+++ b/builtin/check-ignore.c\n@@ -93,9 +93,9 @@ static int check_ignore(int argc, const char **argv, const char *prefix)\n \t * should not be ignored, in order to be consistent with\n \t * 'git status', 'git add' etc.\n \t */\n-\tseen = find_pathspecs_matching_against_index(pathspec.raw);\n+\tseen = find_pathspecs_matching_against_index(&pathspec);\n \tfor (i = 0; i < pathspec.nr; i++) {\n-\t\tconst char *full_path = pathspec.raw[i];\n+\t\tconst char *full_path = pathspec.items[i].match;\n \t\tif (!seen[i]) {\n \t\t\texclude = last_exclude_matching_path(&check, full_path,\n \t\t\t\t\t\t\t     -1, &dtype);\ndiff --git a/dir.c b/dir.c\nindex e354abb..9627d7e 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -140,113 +140,6 @@ int within_depth(const char *name, int namelen,\n  *\n  * It returns 0 when there is no match.\n  */\n-static int match_one(const char *match, const char *name, int namelen)\n-{\n-\tint matchlen;\n-\tint literal = limit_pathspec_to_literal();\n-\n-\t/* If the match was just the prefix, we matched */\n-\tif (!*match)\n-\t\treturn MATCHED_RECURSIVELY;\n-\n-\tif (ignore_case) {\n-\t\tfor (;;) {\n-\t\t\tunsigned char c1 = tolower(*match);\n-\t\t\tunsigned char c2 = tolower(*name);\n-\t\t\tif (c1 == '\\0' || (!literal && is_glob_special(c1)))\n-\t\t\t\tbreak;\n-\t\t\tif (c1 != c2)\n-\t\t\t\treturn 0;\n-\t\t\tmatch++;\n-\t\t\tname++;\n-\t\t\tnamelen--;\n-\t\t}\n-\t} else {\n-\t\tfor (;;) {\n-\t\t\tunsigned char c1 = *match;\n-\t\t\tunsigned char c2 = *name;\n-\t\t\tif (c1 == '\\0' || (!literal && is_glob_special(c1)))\n-\t\t\t\tbreak;\n-\t\t\tif (c1 != c2)\n-\t\t\t\treturn 0;\n-\t\t\tmatch++;\n-\t\t\tname++;\n-\t\t\tnamelen--;\n-\t\t}\n-\t}\n-\n-\t/*\n-\t * If we don't match the matchstring exactly,\n-\t * we need to match by fnmatch\n-\t */\n-\tmatchlen = strlen(match);\n-\tif (strncmp_icase(match, name, matchlen)) {\n-\t\tif (literal)\n-\t\t\treturn 0;\n-\t\treturn !fnmatch_icase(match, name, 0) ? MATCHED_FNMATCH : 0;\n-\t}\n-\n-\tif (namelen == matchlen)\n-\t\treturn MATCHED_EXACTLY;\n-\tif (match[matchlen-1] == '/' || name[matchlen] == '/')\n-\t\treturn MATCHED_RECURSIVELY;\n-\treturn 0;\n-}\n-\n-/*\n- * Given a name and a list of pathspecs, returns the nature of the\n- * closest (i.e. most specific) match of the name to any of the\n- * pathspecs.\n- *\n- * The caller typically calls this multiple times with the same\n- * pathspec and seen[] array but with different name/namelen\n- * (e.g. entries from the index) and is interested in seeing if and\n- * how each pathspec matches all the names it calls this function\n- * with.  A mark is left in the seen[] array for each pathspec element\n- * indicating the closest type of match that element achieved, so if\n- * seen[n] remains zero after multiple invocations, that means the nth\n- * pathspec did not match any names, which could indicate that the\n- * user mistyped the nth pathspec.\n- */\n-int match_pathspec(const char **pathspec, const char *name, int namelen,\n-\t\tint prefix, char *seen)\n-{\n-\tint i, retval = 0;\n-\n-\tif (!pathspec)\n-\t\treturn 1;\n-\n-\tname += prefix;\n-\tnamelen -= prefix;\n-\n-\tfor (i = 0; pathspec[i] != NULL; i++) {\n-\t\tint how;\n-\t\tconst char *match = pathspec[i] + prefix;\n-\t\tif (seen && seen[i] == MATCHED_EXACTLY)\n-\t\t\tcontinue;\n-\t\thow = match_one(match, name, namelen);\n-\t\tif (how) {\n-\t\t\tif (retval < how)\n-\t\t\t\tretval = how;\n-\t\t\tif (seen && seen[i] < how)\n-\t\t\t\tseen[i] = how;\n-\t\t}\n-\t}\n-\treturn retval;\n-}\n-\n-/*\n- * Does 'match' match the given name?\n- * A match is found if\n- *\n- * (1) the 'match' string is leading directory of 'name', or\n- * (2) the 'match' string is a wildcard and matches 'name', or\n- * (3) the 'match' string is exactly the same as 'name'.\n- *\n- * and the return value tells which case it was.\n- *\n- * It returns 0 when there is no match.\n- */\n static int match_pathspec_item(const struct pathspec_item *item, int prefix,\n \t\t\t       const char *name, int namelen)\n {\ndiff --git a/dir.h b/dir.h\nindex d3f76df..13da62c 100644\n--- a/dir.h\n+++ b/dir.h\n@@ -128,7 +128,6 @@ struct dir_struct {\n extern int simple_length(const char *match);\n extern int no_wildcard(const char *string);\n extern char *common_prefix(const struct pathspec *pathspec);\n-extern int match_pathspec(const char **pathspec, const char *name, int namelen, int prefix, char *seen);\n extern int match_pathspec_depth(const struct pathspec *pathspec,\n \t\t\t\tconst char *name, int namelen,\n \t\t\t\tint prefix, char *seen);\ndiff --git a/pathspec.c b/pathspec.c\nindex 767ce65..1ea1c4c 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -15,8 +15,8 @@\n  * If seen[] has not already been written to, it may make sense\n  * to use find_pathspecs_matching_against_index() instead.\n  */\n-void add_pathspec_matches_against_index(const char **pathspec,\n-\t\t\t\t\tchar *seen, int specs)\n+void add_pathspec_matches_against_index(const struct pathspec *pathspec,\n+\t\t\t\t\tchar *seen)\n {\n \tint num_unmatched = 0, i;\n \n@@ -26,14 +26,14 @@ void add_pathspec_matches_against_index(const char **pathspec,\n \t * mistakenly think that the user gave a pathspec that did not match\n \t * anything.\n \t */\n-\tfor (i = 0; i < specs; i++)\n+\tfor (i = 0; i < pathspec->nr; i++)\n \t\tif (!seen[i])\n \t\t\tnum_unmatched++;\n \tif (!num_unmatched)\n \t\treturn;\n \tfor (i = 0; i < active_nr; i++) {\n \t\tstruct cache_entry *ce = active_cache[i];\n-\t\tmatch_pathspec(pathspec, ce->name, ce_namelen(ce), 0, seen);\n+\t\tmatch_pathspec_depth(pathspec, ce->name, ce_namelen(ce), 0, seen);\n \t}\n }\n \n@@ -45,15 +45,10 @@ void add_pathspec_matches_against_index(const char **pathspec,\n  * nature of the \"closest\" (i.e. most specific) matches which each of the\n  * given pathspecs achieves against all items in the index.\n  */\n-char *find_pathspecs_matching_against_index(const char **pathspec)\n+char *find_pathspecs_matching_against_index(const struct pathspec *pathspec)\n {\n-\tchar *seen;\n-\tint i;\n-\n-\tfor (i = 0; pathspec[i];  i++)\n-\t\t; /* just counting */\n-\tseen = xcalloc(i, 1);\n-\tadd_pathspec_matches_against_index(pathspec, seen, i);\n+\tchar *seen = xcalloc(pathspec->nr, 1);\n+\tadd_pathspec_matches_against_index(pathspec, seen);\n \treturn seen;\n }\n \ndiff --git a/pathspec.h b/pathspec.h\nindex 9e9e442..30aea46 100644\n--- a/pathspec.h\n+++ b/pathspec.h\n@@ -54,8 +54,8 @@ extern void free_pathspec(struct pathspec *);\n \n extern int limit_pathspec_to_literal(void);\n \n-extern char *find_pathspecs_matching_against_index(const char **pathspec);\n-extern void add_pathspec_matches_against_index(const char **pathspec, char *seen, int specs);\n+extern char *find_pathspecs_matching_against_index(const struct pathspec *pathspec);\n+extern void add_pathspec_matches_against_index(const struct pathspec *pathspec, char *seen);\n extern const char *check_path_for_gitlink(const char *path);\n extern void die_if_path_beyond_symlink(const char *path, const char *prefix);\n \n-- \n1.8.0.rc0.19.g7bbb31d\n"},{"id":"211382","messageId":"1363327620-29017-39-git-send-email-pclouds@gmail.com","threadId":"33187","inReplyTo":"1363327620-29017-1-git-send-email-pclouds@gmail.com","subject":"[PATCH v1 38/45] tree-diff: remove the use of pathspec's raw[] in follow-rename codepath","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2013-03-15T06:06:53Z","receivedAt":"2013-03-15T06:06:53Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Put a checkpoint to guard unsupported pathspec features in future.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n tree-diff.c | 4 ++--\n 1 file changed, 2 insertions(+), 2 deletions(-)\n\ndiff --git a/tree-diff.c b/tree-diff.c\nindex e1145c6..21a50d8 100644\n--- a/tree-diff.c\n+++ b/tree-diff.c\n@@ -224,7 +224,7 @@ static void try_to_follow_renames(struct tree_desc *t1, struct tree_desc *t2, co\n \tDIFF_OPT_SET(&diff_opts, RECURSIVE);\n \tDIFF_OPT_SET(&diff_opts, FIND_COPIES_HARDER);\n \tdiff_opts.output_format = DIFF_FORMAT_NO_OUTPUT;\n-\tdiff_opts.single_follow = opt->pathspec.raw[0];\n+\tdiff_opts.single_follow = opt->pathspec.items[0].match;\n \tdiff_opts.break_opt = opt->break_opt;\n \tdiff_opts.rename_score = opt->rename_score;\n \tdiff_setup_done(&diff_opts);\n@@ -243,7 +243,7 @@ static void try_to_follow_renames(struct tree_desc *t1, struct tree_desc *t2, co\n \t\t * the future!\n \t\t */\n \t\tif ((p->status == 'R' || p->status == 'C') &&\n-\t\t    !strcmp(p->two->path, opt->pathspec.raw[0])) {\n+\t\t    !strcmp(p->two->path, opt->pathspec.items[0].match)) {\n \t\t\tconst char *path[2];\n \n \t\t\t/* Switch the file-pairs around */\n-- \n1.8.0.rc0.19.g7bbb31d\n"},{"id":"211383","messageId":"1363327620-29017-40-git-send-email-pclouds@gmail.com","threadId":"33187","inReplyTo":"1363327620-29017-1-git-send-email-pclouds@gmail.com","subject":"[PATCH v1 39/45] parse_pathspec: make sure the prefix part is wildcard-free","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2013-03-15T06:06:54Z","receivedAt":"2013-03-15T06:06:54Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Prepending prefix to pathspec is a trick to workaround the fact that\ncommands can be executed in a subdirectory, but all git commands run\nat worktree's root. The prefix part should always be treated as\nliteral string. Make it so.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n cache.h    |  2 ++\n path.c     | 15 ++++++++++++++-\n pathspec.c | 16 ++++++++++++----\n pathspec.h |  2 +-\n setup.c    |  9 +++++----\n 5 files changed, 34 insertions(+), 10 deletions(-)\n\ndiff --git a/cache.h b/cache.h\nindex 6297783..17e0b26 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -401,6 +401,7 @@ extern void setup_work_tree(void);\n extern const char *setup_git_directory_gently(int *);\n extern const char *setup_git_directory(void);\n extern char *prefix_path(const char *prefix, int len, const char *path);\n+extern char *prefix_path_gently(const char *prefix, int *p_len, const char *path);\n extern const char *prefix_filename(const char *prefix, int len, const char *path);\n extern int check_filename(const char *prefix, const char *name);\n extern void verify_filename(const char *prefix,\n@@ -712,6 +713,7 @@ const char *real_path(const char *path);\n const char *real_path_if_valid(const char *path);\n const char *absolute_path(const char *path);\n const char *relative_path(const char *abs, const char *base);\n+int normalize_path_copy_len(char *dst, const char *src, int *prefix_len);\n int normalize_path_copy(char *dst, const char *src);\n int longest_ancestor_length(const char *path, struct string_list *prefixes);\n char *strip_path_suffix(const char *path, const char *suffix);\ndiff --git a/path.c b/path.c\nindex d3d3f8b..7baf334 100644\n--- a/path.c\n+++ b/path.c\n@@ -487,8 +487,14 @@ const char *relative_path(const char *abs, const char *base)\n  *\n  * Note that this function is purely textual.  It does not follow symlinks,\n  * verify the existence of the path, or make any system calls.\n+ *\n+ * prefix_len != NULL is for a specific case of prefix_pathspec():\n+ * assume that src == dst and src[0..prefix_len-1] is already\n+ * normalized, any time \"../\" eats up to the prefix_len part,\n+ * prefix_len is reduced. In the end prefix_len is the remaining\n+ * prefix that has not been overridden by user pathspec.\n  */\n-int normalize_path_copy(char *dst, const char *src)\n+int normalize_path_copy_len(char *dst, const char *src, int *prefix_len)\n {\n \tchar *dst0;\n \n@@ -563,11 +569,18 @@ int normalize_path_copy(char *dst, const char *src)\n \t\t/* Windows: dst[-1] cannot be backslash anymore */\n \t\twhile (dst0 < dst && dst[-1] != '/')\n \t\t\tdst--;\n+\t\tif (prefix_len && *prefix_len > dst - dst0)\n+\t\t\t*prefix_len = dst - dst0;\n \t}\n \t*dst = '\\0';\n \treturn 0;\n }\n \n+int normalize_path_copy(char *dst, const char *src)\n+{\n+\treturn normalize_path_copy_len(dst, src, NULL);\n+}\n+\n /*\n  * path = Canonical absolute path\n  * prefixes = string_list containing normalized, absolute paths without\ndiff --git a/pathspec.c b/pathspec.c\nindex 1ea1c4c..bc27692 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -149,10 +149,14 @@ static unsigned prefix_pathspec(struct pathspec_item *item,\n \tmagic |= short_magic;\n \t*p_short_magic = short_magic;\n \n-\tif (magic & PATHSPEC_FROMTOP)\n+\tif (magic & PATHSPEC_FROMTOP) {\n \t\tmatch = xstrdup(copyfrom);\n-\telse\n-\t\tmatch = prefix_path(prefix, prefixlen, copyfrom);\n+\t\tprefixlen = 0;\n+\t} else {\n+\t\tmatch = prefix_path_gently(prefix, &prefixlen, copyfrom);\n+\t\tif (!match)\n+\t\t\tdie(\"%s: '%s' is outside repository\", elt, copyfrom);\n+\t}\n \t*raw = item->match = match;\n \t/*\n \t * Prefix the pathspec (keep all magic) and put to\n@@ -166,6 +170,7 @@ static unsigned prefix_pathspec(struct pathspec_item *item,\n \t} else\n \t\titem->original = elt;\n \titem->len = strlen(item->match);\n+\titem->prefix = prefixlen;\n \n \tif ((flags & PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP) &&\n \t    (item->len >= 1 && item->match[item->len - 1] == '/') &&\n@@ -197,8 +202,11 @@ static unsigned prefix_pathspec(struct pathspec_item *item,\n \n \tif (limit_pathspec_to_literal())\n \t\titem->nowildcard_len = item->len;\n-\telse\n+\telse {\n \t\titem->nowildcard_len = simple_length(item->match);\n+\t\tif (item->nowildcard_len < prefixlen)\n+\t\t\titem->nowildcard_len = prefixlen;\n+\t}\n \titem->flags = 0;\n \tif (item->nowildcard_len < item->len &&\n \t    item->match[item->nowildcard_len] == '*' &&\ndiff --git a/pathspec.h b/pathspec.h\nindex 30aea46..9f9ecd2 100644\n--- a/pathspec.h\n+++ b/pathspec.h\n@@ -21,7 +21,7 @@ struct pathspec {\n \t\tconst char *match;\n \t\tconst char *original;\n \t\tunsigned magic;\n-\t\tint len;\n+\t\tint len, prefix;\n \t\tint nowildcard_len;\n \t\tint flags;\n \t} *items;\ndiff --git a/setup.c b/setup.c\nindex acdc634..e661a71 100644\n--- a/setup.c\n+++ b/setup.c\n@@ -5,10 +5,11 @@\n static int inside_git_dir = -1;\n static int inside_work_tree = -1;\n \n-static char *prefix_path_gently(const char *prefix, int len, const char *path)\n+char *prefix_path_gently(const char *prefix, int *p_len, const char *path)\n {\n \tconst char *orig = path;\n \tchar *sanitized;\n+\tint len = *p_len;\n \tif (is_absolute_path(orig)) {\n \t\tconst char *temp = real_path(path);\n \t\tsanitized = xmalloc(len + strlen(temp) + 1);\n@@ -19,7 +20,7 @@ static char *prefix_path_gently(const char *prefix, int len, const char *path)\n \t\t\tmemcpy(sanitized, prefix, len);\n \t\tstrcpy(sanitized + len, path);\n \t}\n-\tif (normalize_path_copy(sanitized, sanitized))\n+\tif (normalize_path_copy_len(sanitized, sanitized, p_len))\n \t\tgoto error_out;\n \tif (is_absolute_path(orig)) {\n \t\tsize_t root_len, len, total;\n@@ -44,7 +45,7 @@ static char *prefix_path_gently(const char *prefix, int len, const char *path)\n \n char *prefix_path(const char *prefix, int len, const char *path)\n {\n-\tchar *r = prefix_path_gently(prefix, len, path);\n+\tchar *r = prefix_path_gently(prefix, &len, path);\n \tif (!r)\n \t\tdie(\"'%s' is outside repository\", path);\n \treturn r;\n@@ -53,7 +54,7 @@ char *prefix_path(const char *prefix, int len, const char *path)\n int path_inside_repo(const char *prefix, const char *path)\n {\n \tint len = prefix ? strlen(prefix) : 0;\n-\tchar *r = prefix_path_gently(prefix, len, path);\n+\tchar *r = prefix_path_gently(prefix, &len, path);\n \tif (r) {\n \t\tfree(r);\n \t\treturn 1;\n-- \n1.8.0.rc0.19.g7bbb31d\n"},{"id":"211384","messageId":"1363327620-29017-41-git-send-email-pclouds@gmail.com","threadId":"33187","inReplyTo":"1363327620-29017-1-git-send-email-pclouds@gmail.com","subject":"[PATCH v1 40/45] parse_pathspec: preserve prefix length via PATHSPEC_PREFIX_ORIGIN","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2013-03-15T06:06:55Z","receivedAt":"2013-03-15T06:06:55Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"The prefix length is passed from one command to another via the new\nmagic 'prefix'. The magic is for parse_pathspec's internal use only,\nnot visible to parse_pathspec's callers.\n\nPrefix length is not preserved across commands when --literal-pathspecs\nis specified (no magic is allowed, including 'prefix'). That's OK\nbecause we all paths are literal. No magic, no special treatment\nregarding prefix. (This may be no longer true if we make :(glob)\ndefault)\n\nOther options to preserve the prefix include saving it to env variable\nor quoting. Env var way (at least _one_ env var) is not suitable\nbecause the prefix is not the same for all pathspecs. Pathspecs\nstarting with \"../\" will eat into the prefix part.\n\nWe could also preserve 'prefix' across commands is quote the prefix\npart, then dequote on receiving. But it may not be 100% accurate, we\nmay dequote longer than the original prefix part, for example. That\nmay be good or not, but it's not the purpose.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n pathspec.c | 41 ++++++++++++++++++++++++++++++++++++-----\n 1 file changed, 36 insertions(+), 5 deletions(-)\n\ndiff --git a/pathspec.c b/pathspec.c\nindex bc27692..3291b58 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -92,9 +92,9 @@ static unsigned prefix_pathspec(struct pathspec_item *item,\n \t\t\t\tconst char *elt)\n {\n \tunsigned magic = 0, short_magic = 0;\n-\tconst char *copyfrom = elt;\n+\tconst char *copyfrom = elt, *long_magic_end = NULL;\n \tchar *match;\n-\tint i;\n+\tint i, pathspec_prefix = -1;\n \n \tif (elt[0] != ':') {\n \t\t; /* nothing to do */\n@@ -111,18 +111,29 @@ static unsigned prefix_pathspec(struct pathspec_item *item,\n \t\t\t\tnextat = copyfrom + len + 1;\n \t\t\tif (!len)\n \t\t\t\tcontinue;\n-\t\t\tfor (i = 0; i < ARRAY_SIZE(pathspec_magic); i++)\n+\t\t\tfor (i = 0; i < ARRAY_SIZE(pathspec_magic); i++) {\n \t\t\t\tif (strlen(pathspec_magic[i].name) == len &&\n \t\t\t\t    !strncmp(pathspec_magic[i].name, copyfrom, len)) {\n \t\t\t\t\tmagic |= pathspec_magic[i].bit;\n \t\t\t\t\tbreak;\n \t\t\t\t}\n+\t\t\t\tif (!prefixcmp(copyfrom, \"prefix:\")) {\n+\t\t\t\t\tchar *endptr;\n+\t\t\t\t\tpathspec_prefix = strtol(copyfrom + 7,\n+\t\t\t\t\t\t\t\t &endptr, 10);\n+\t\t\t\t\tif (endptr - copyfrom != len)\n+\t\t\t\t\t\tdie(\"invalid parameter for pathspec magic 'prefix'\");\n+\t\t\t\t\t/* \"i\" would be wrong, but it does not matter */\n+\t\t\t\t\tbreak;\n+\t\t\t\t}\n+\t\t\t}\n \t\t\tif (ARRAY_SIZE(pathspec_magic) <= i)\n \t\t\t\tdie(_(\"Invalid pathspec magic '%.*s' in '%s'\"),\n \t\t\t\t    (int) len, copyfrom, elt);\n \t\t}\n \t\tif (*copyfrom != ')')\n \t\t\tdie(_(\"Missing ')' at the end of pathspec magic in '%s'\"), elt);\n+\t\tlong_magic_end = copyfrom;\n \t\tcopyfrom++;\n \t} else {\n \t\t/* shorthand */\n@@ -149,7 +160,14 @@ static unsigned prefix_pathspec(struct pathspec_item *item,\n \tmagic |= short_magic;\n \t*p_short_magic = short_magic;\n \n-\tif (magic & PATHSPEC_FROMTOP) {\n+\tif (pathspec_prefix >= 0 &&\n+\t    (prefixlen || (prefix && *prefix)))\n+\t\tdie(\"BUG: 'prefix' magic is supposed to be used at worktree's root\");\n+\n+\tif (pathspec_prefix >= 0) {\n+\t\tmatch = xstrdup(copyfrom);\n+\t\tprefixlen = pathspec_prefix;\n+\t} else if (magic & PATHSPEC_FROMTOP) {\n \t\tmatch = xstrdup(copyfrom);\n \t\tprefixlen = 0;\n \t} else {\n@@ -164,7 +182,20 @@ static unsigned prefix_pathspec(struct pathspec_item *item,\n \t */\n \tif (flags & PATHSPEC_PREFIX_ORIGIN) {\n \t\tstruct strbuf sb = STRBUF_INIT;\n-\t\tstrbuf_add(&sb, elt, copyfrom - elt);\n+\t\tconst char *start = elt;\n+\t\tif (prefixlen && !limit_pathspec_to_literal()) {\n+\t\t\t/* Preserve the actual prefix length of each pattern */\n+\t\t\tif (long_magic_end) {\n+\t\t\t\tstrbuf_add(&sb, start, long_magic_end - start);\n+\t\t\t\tstrbuf_addf(&sb, \",prefix:%d\", prefixlen);\n+\t\t\t\tstart = long_magic_end;\n+\t\t\t} else {\n+\t\t\t\tif (*start == ':')\n+\t\t\t\t\tstart++;\n+\t\t\t\tstrbuf_addf(&sb, \":(prefix:%d)\", prefixlen);\n+\t\t\t}\n+\t\t}\n+\t\tstrbuf_add(&sb, start, copyfrom - start);\n \t\tstrbuf_addstr(&sb, match);\n \t\titem->original = strbuf_detach(&sb, NULL);\n \t} else\n-- \n1.8.0.rc0.19.g7bbb31d\n"},{"id":"211385","messageId":"1363327620-29017-42-git-send-email-pclouds@gmail.com","threadId":"33187","inReplyTo":"1363327620-29017-1-git-send-email-pclouds@gmail.com","subject":"[PATCH v1 41/45] Kill limit_pathspec_to_literal() as it's only used by parse_pathspec()","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2013-03-15T06:06:56Z","receivedAt":"2013-03-15T06:06:56Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n dir.c      | 8 --------\n pathspec.c | 8 ++++++--\n pathspec.h | 2 --\n 3 files changed, 6 insertions(+), 12 deletions(-)\n\ndiff --git a/dir.c b/dir.c\nindex 9627d7e..4f5a2c9 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -1523,14 +1523,6 @@ int remove_path(const char *name)\n \treturn 0;\n }\n \n-int limit_pathspec_to_literal(void)\n-{\n-\tstatic int flag = -1;\n-\tif (flag < 0)\n-\t\tflag = git_env_bool(GIT_LITERAL_PATHSPECS_ENVIRONMENT, 0);\n-\treturn flag;\n-}\n-\n /*\n  * Frees memory within dir which was allocated for exclude lists and\n  * the exclude_stack.  Does not free dir itself.\ndiff --git a/pathspec.c b/pathspec.c\nindex 3291b58..7b3dfc0 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -91,11 +91,15 @@ static unsigned prefix_pathspec(struct pathspec_item *item,\n \t\t\t\tconst char *prefix, int prefixlen,\n \t\t\t\tconst char *elt)\n {\n+\tstatic int literal_global = -1;\n \tunsigned magic = 0, short_magic = 0;\n \tconst char *copyfrom = elt, *long_magic_end = NULL;\n \tchar *match;\n \tint i, pathspec_prefix = -1;\n \n+\tif (literal_global < 0)\n+\t\tliteral_global = git_env_bool(GIT_LITERAL_PATHSPECS_ENVIRONMENT, 0);\n+\n \tif (elt[0] != ':') {\n \t\t; /* nothing to do */\n \t} else if (elt[1] == '(') {\n@@ -183,7 +187,7 @@ static unsigned prefix_pathspec(struct pathspec_item *item,\n \tif (flags & PATHSPEC_PREFIX_ORIGIN) {\n \t\tstruct strbuf sb = STRBUF_INIT;\n \t\tconst char *start = elt;\n-\t\tif (prefixlen && !limit_pathspec_to_literal()) {\n+\t\tif (prefixlen && !literal_global) {\n \t\t\t/* Preserve the actual prefix length of each pattern */\n \t\t\tif (long_magic_end) {\n \t\t\t\tstrbuf_add(&sb, start, long_magic_end - start);\n@@ -231,7 +235,7 @@ static unsigned prefix_pathspec(struct pathspec_item *item,\n \t\t\t\t     elt, ce_len, ce->name);\n \t\t}\n \n-\tif (limit_pathspec_to_literal())\n+\tif (literal_global)\n \t\titem->nowildcard_len = item->len;\n \telse {\n \t\titem->nowildcard_len = simple_length(item->match);\ndiff --git a/pathspec.h b/pathspec.h\nindex 9f9ecd2..8f339a5 100644\n--- a/pathspec.h\n+++ b/pathspec.h\n@@ -52,8 +52,6 @@ extern void parse_pathspec(struct pathspec *pathspec,\n extern void copy_pathspec(struct pathspec *dst, const struct pathspec *src);\n extern void free_pathspec(struct pathspec *);\n \n-extern int limit_pathspec_to_literal(void);\n-\n extern char *find_pathspecs_matching_against_index(const struct pathspec *pathspec);\n extern void add_pathspec_matches_against_index(const struct pathspec *pathspec, char *seen);\n extern const char *check_path_for_gitlink(const char *path);\n-- \n1.8.0.rc0.19.g7bbb31d\n"},{"id":"211386","messageId":"1363327620-29017-43-git-send-email-pclouds@gmail.com","threadId":"33187","inReplyTo":"1363327620-29017-1-git-send-email-pclouds@gmail.com","subject":"[PATCH v1 42/45] pathspec: support :(literal) syntax for noglob pathspec","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2013-03-15T06:06:57Z","receivedAt":"2013-03-15T06:06:57Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n Documentation/glossary-content.txt |  4 ++++\n builtin/add.c                      |  2 +-\n builtin/diff.c                     |  2 +-\n dir.c                              | 15 ++++++++++++---\n pathspec.c                         | 11 ++++++++---\n pathspec.h                         |  4 +++-\n t/t6130-pathspec-noglob.sh         | 18 ++++++++++++++++++\n tree-diff.c                        |  2 +-\n tree-walk.c                        |  5 ++++-\n 9 files changed, 52 insertions(+), 11 deletions(-)\n\ndiff --git a/Documentation/glossary-content.txt b/Documentation/glossary-content.txt\nindex eb7ba84..8b91aeb 100644\n--- a/Documentation/glossary-content.txt\n+++ b/Documentation/glossary-content.txt\n@@ -323,6 +323,10 @@ top `/`;;\n \tThe magic word `top` (mnemonic: `/`) makes the pattern match\n \tfrom the root of the working tree, even when you are running\n \tthe command from inside a subdirectory.\n+\n+literal;;\n+\tWildcards in the pattern such as `*` or `?` are treated\n+\tas literal characters.\n --\n +\n Currently only the slash `/` is recognized as the \"magic signature\",\ndiff --git a/builtin/add.c b/builtin/add.c\nindex aa0709e..8bc6b45 100644\n--- a/builtin/add.c\n+++ b/builtin/add.c\n@@ -426,7 +426,7 @@ int cmd_add(int argc, const char **argv, const char *prefix)\n \t\t/*\n \t\t * file_exists() assumes exact match\n \t\t */\n-\t\tGUARD_PATHSPEC(&pathspec, PATHSPEC_FROMTOP);\n+\t\tGUARD_PATHSPEC(&pathspec, PATHSPEC_FROMTOP | PATHSPEC_LITERAL);\n \n \t\tfor (i = 0; i < pathspec.nr; i++) {\n \t\t\tconst char *path = pathspec.items[i].match;\ndiff --git a/builtin/diff.c b/builtin/diff.c\nindex 6b4e3f9..b78435f 100644\n--- a/builtin/diff.c\n+++ b/builtin/diff.c\n@@ -372,7 +372,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix)\n \t}\n \tif (rev.prune_data.nr) {\n \t\t/* builtin_diff_b_f() */\n-\t\tGUARD_PATHSPEC(&rev.prune_data, PATHSPEC_FROMTOP);\n+\t\tGUARD_PATHSPEC(&rev.prune_data, PATHSPEC_FROMTOP | PATHSPEC_LITERAL);\n \t\tif (!path)\n \t\t\tpath = rev.prune_data.items[0].match;\n \t\tpaths += rev.prune_data.nr;\ndiff --git a/dir.c b/dir.c\nindex 4f5a2c9..8d9ed24 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -65,7 +65,10 @@ static size_t common_prefix_len(const struct pathspec *pathspec)\n \tint n;\n \tsize_t max = 0;\n \n-\tGUARD_PATHSPEC(pathspec, PATHSPEC_FROMTOP | PATHSPEC_MAXDEPTH);\n+\tGUARD_PATHSPEC(pathspec,\n+\t\t       PATHSPEC_FROMTOP |\n+\t\t       PATHSPEC_MAXDEPTH |\n+\t\t       PATHSPEC_LITERAL);\n \n \tfor (n = 0; n < pathspec->nr; n++) {\n \t\tsize_t i = 0, len = 0;\n@@ -189,7 +192,10 @@ int match_pathspec_depth(const struct pathspec *ps,\n {\n \tint i, retval = 0;\n \n-\tGUARD_PATHSPEC(ps, PATHSPEC_FROMTOP | PATHSPEC_MAXDEPTH);\n+\tGUARD_PATHSPEC(ps,\n+\t\t       PATHSPEC_FROMTOP |\n+\t\t       PATHSPEC_MAXDEPTH |\n+\t\t       PATHSPEC_LITERAL);\n \n \tif (!ps->nr) {\n \t\tif (!ps->recursive ||\n@@ -1338,7 +1344,10 @@ int read_directory(struct dir_struct *dir, const char *path, int len, const stru\n \t * Check out create_simplify()\n \t */\n \tif (pathspec)\n-\t\tGUARD_PATHSPEC(pathspec, PATHSPEC_FROMTOP | PATHSPEC_MAXDEPTH);\n+\t\tGUARD_PATHSPEC(pathspec,\n+\t\t\t       PATHSPEC_FROMTOP |\n+\t\t\t       PATHSPEC_MAXDEPTH |\n+\t\t\t       PATHSPEC_LITERAL);\n \n \tif (has_symlink_leading_path(path, len))\n \t\treturn dir->nr;\ndiff --git a/pathspec.c b/pathspec.c\nindex 7b3dfc0..e57196d 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -70,6 +70,7 @@ static struct pathspec_magic {\n \tconst char *name;\n } pathspec_magic[] = {\n \t{ PATHSPEC_FROMTOP, '/', \"top\" },\n+\t{ PATHSPEC_LITERAL,   0, \"literal\" },\n };\n \n /*\n@@ -92,13 +93,15 @@ static unsigned prefix_pathspec(struct pathspec_item *item,\n \t\t\t\tconst char *elt)\n {\n \tstatic int literal_global = -1;\n-\tunsigned magic = 0, short_magic = 0;\n+\tunsigned magic = 0, short_magic = 0, global_magic = 0;\n \tconst char *copyfrom = elt, *long_magic_end = NULL;\n \tchar *match;\n \tint i, pathspec_prefix = -1;\n \n \tif (literal_global < 0)\n \t\tliteral_global = git_env_bool(GIT_LITERAL_PATHSPECS_ENVIRONMENT, 0);\n+\tif (literal_global)\n+\t\tglobal_magic |= PATHSPEC_LITERAL;\n \n \tif (elt[0] != ':') {\n \t\t; /* nothing to do */\n@@ -163,6 +166,7 @@ static unsigned prefix_pathspec(struct pathspec_item *item,\n \n \tmagic |= short_magic;\n \t*p_short_magic = short_magic;\n+\tmagic |= global_magic;\n \n \tif (pathspec_prefix >= 0 &&\n \t    (prefixlen || (prefix && *prefix)))\n@@ -235,7 +239,7 @@ static unsigned prefix_pathspec(struct pathspec_item *item,\n \t\t\t\t     elt, ce_len, ce->name);\n \t\t}\n \n-\tif (literal_global)\n+\tif (magic & PATHSPEC_LITERAL)\n \t\titem->nowildcard_len = item->len;\n \telse {\n \t\titem->nowildcard_len = simple_length(item->match);\n@@ -395,7 +399,8 @@ const char **get_pathspec(const char *prefix, const char **pathspec)\n {\n \tstruct pathspec ps;\n \tparse_pathspec(&ps,\n-\t\t       PATHSPEC_ALL_MAGIC & ~PATHSPEC_FROMTOP,\n+\t\t       PATHSPEC_ALL_MAGIC &\n+\t\t       ~(PATHSPEC_FROMTOP | PATHSPEC_LITERAL),\n \t\t       PATHSPEC_PREFER_CWD,\n \t\t       prefix, pathspec);\n \treturn ps.raw;\ndiff --git a/pathspec.h b/pathspec.h\nindex 8f339a5..d5db7d5 100644\n--- a/pathspec.h\n+++ b/pathspec.h\n@@ -4,9 +4,11 @@\n /* Pathspec magic */\n #define PATHSPEC_FROMTOP\t(1<<0)\n #define PATHSPEC_MAXDEPTH\t(1<<1)\n+#define PATHSPEC_LITERAL\t(1<<2)\n #define PATHSPEC_ALL_MAGIC\t  \\\n \t(PATHSPEC_FROMTOP\t| \\\n-\t PATHSPEC_MAXDEPTH)\n+\t PATHSPEC_MAXDEPTH\t| \\\n+\t PATHSPEC_LITERAL)\n \n #define PATHSPEC_ONESTAR 1\t/* the pathspec pattern sastisfies GFNM_ONESTAR */\n \ndiff --git a/t/t6130-pathspec-noglob.sh b/t/t6130-pathspec-noglob.sh\nindex 39ef619..49c148e 100755\n--- a/t/t6130-pathspec-noglob.sh\n+++ b/t/t6130-pathspec-noglob.sh\n@@ -47,18 +47,36 @@ test_expect_success 'no-glob option matches literally (vanilla)' '\n \ttest_cmp expect actual\n '\n \n+test_expect_success 'no-glob option matches literally (vanilla)' '\n+\techo vanilla >expect &&\n+\tgit log --format=%s -- \":(literal)foo\" >actual &&\n+\ttest_cmp expect actual\n+'\n+\n test_expect_success 'no-glob option matches literally (star)' '\n \techo star >expect &&\n \tgit --literal-pathspecs log --format=%s -- \"f*\" >actual &&\n \ttest_cmp expect actual\n '\n \n+test_expect_success 'no-glob option matches literally (star)' '\n+\techo star >expect &&\n+\tgit log --format=%s -- \":(literal)f*\" >actual &&\n+\ttest_cmp expect actual\n+'\n+\n test_expect_success 'no-glob option matches literally (bracket)' '\n \techo bracket >expect &&\n \tgit --literal-pathspecs log --format=%s -- \"f[o][o]\" >actual &&\n \ttest_cmp expect actual\n '\n \n+test_expect_success 'no-glob option matches literally (bracket)' '\n+\techo bracket >expect &&\n+\tgit log --format=%s -- \":(literal)f[o][o]\" >actual &&\n+\ttest_cmp expect actual\n+'\n+\n test_expect_success 'no-glob environment variable works' '\n \techo star >expect &&\n \tGIT_LITERAL_PATHSPECS=1 git log --format=%s -- \"f*\" >actual &&\ndiff --git a/tree-diff.c b/tree-diff.c\nindex 21a50d8..ccf9d7c 100644\n--- a/tree-diff.c\n+++ b/tree-diff.c\n@@ -202,7 +202,7 @@ static void try_to_follow_renames(struct tree_desc *t1, struct tree_desc *t2, co\n \t * path. Magic that matches more than one path is not\n \t * supported.\n \t */\n-\tGUARD_PATHSPEC(&opt->pathspec, PATHSPEC_FROMTOP);\n+\tGUARD_PATHSPEC(&opt->pathspec, PATHSPEC_FROMTOP | PATHSPEC_LITERAL);\n #if 0\n \t/*\n \t * We should reject wildcards as well. Unfortunately we\ndiff --git a/tree-walk.c b/tree-walk.c\nindex 37b157e..676bd7f 100644\n--- a/tree-walk.c\n+++ b/tree-walk.c\n@@ -636,7 +636,10 @@ enum interesting tree_entry_interesting(const struct name_entry *entry,\n \tenum interesting never_interesting = ps->has_wildcard ?\n \t\tentry_not_interesting : all_entries_not_interesting;\n \n-\tGUARD_PATHSPEC(ps, PATHSPEC_FROMTOP | PATHSPEC_MAXDEPTH);\n+\tGUARD_PATHSPEC(ps,\n+\t\t       PATHSPEC_FROMTOP |\n+\t\t       PATHSPEC_MAXDEPTH |\n+\t\t       PATHSPEC_LITERAL);\n \n \tif (!ps->nr) {\n \t\tif (!ps->recursive ||\n-- \n1.8.0.rc0.19.g7bbb31d\n"},{"id":"211387","messageId":"1363327620-29017-44-git-send-email-pclouds@gmail.com","threadId":"33187","inReplyTo":"1363327620-29017-1-git-send-email-pclouds@gmail.com","subject":"[PATCH v1 43/45] pathspec: make --literal-pathspecs disable pathspec magic","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2013-03-15T06:06:58Z","receivedAt":"2013-03-15T06:06:58Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"--literal-pathspecs and its equivalent environment variable are\nprobably used for scripting. In that setting, pathspec magic may be\nunwanted. Disabling globbing in individual pathspec can be done via\n:(literal) magic.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n Documentation/git.txt | 4 ++--\n pathspec.c            | 2 +-\n 2 files changed, 3 insertions(+), 3 deletions(-)\n\ndiff --git a/Documentation/git.txt b/Documentation/git.txt\nindex 7efaa59..3bbbbdc 100644\n--- a/Documentation/git.txt\n+++ b/Documentation/git.txt\n@@ -439,8 +439,8 @@ help ...`.\n \tlinkgit:git-replace[1] for more information.\n \n --literal-pathspecs::\n-\tTreat pathspecs literally, rather than as glob patterns. This is\n-\tequivalent to setting the `GIT_LITERAL_PATHSPECS` environment\n+\tTreat pathspecs literally (i.e. no globbing, no pathspec magic).\n+\tThis is equivalent to setting the `GIT_LITERAL_PATHSPECS` environment\n \tvariable to `1`.\n \n \ndiff --git a/pathspec.c b/pathspec.c\nindex e57196d..61a47b8 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -103,7 +103,7 @@ static unsigned prefix_pathspec(struct pathspec_item *item,\n \tif (literal_global)\n \t\tglobal_magic |= PATHSPEC_LITERAL;\n \n-\tif (elt[0] != ':') {\n+\tif (elt[0] != ':' || literal_global) {\n \t\t; /* nothing to do */\n \t} else if (elt[1] == '(') {\n \t\t/* longhand */\n-- \n1.8.0.rc0.19.g7bbb31d\n"},{"id":"211388","messageId":"1363327620-29017-45-git-send-email-pclouds@gmail.com","threadId":"33187","inReplyTo":"1363327620-29017-1-git-send-email-pclouds@gmail.com","subject":"[PATCH v1 44/45] pathspec: support :(glob) syntax","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2013-03-15T06:06:59Z","receivedAt":"2013-03-15T06:06:59Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":":(glob)path differs from plain pathspec that it uses wildmatch with\nWM_PATHNAME while the other uses fnmatch without FNM_PATHNAME. The\ndifference lies in how '*' (and '**') is processed.\n\nWith the introduction of :(glob) and :(literal) and their global\noptions --[no]glob-pathspecs, the user can:\n\n - make everything literal by default via --noglob-pathspecs\n   --literal-pathspecs cannot be used for this purpose as it\n   disables _all_ pathspec magic.\n\n - individually turn on globbing with :(glob)\n\n - make everything globbing by default via --glob-pathspecs\n\n - individually turn off globbing with :(literal)\n\nThe implication behind this is, there is no way to gain the default\nmatching behavior (i.e. fnmatch without FNM_PATHNAME). You either get\nnew globbing or literal. The old fnmatch behavior is considered\ndeprecated and discouraged to use.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n Documentation/git.txt              | 19 +++++++++++++++++\n Documentation/glossary-content.txt | 29 +++++++++++++++++++++++++\n builtin/add.c                      |  9 ++++++--\n builtin/ls-tree.c                  |  2 +-\n cache.h                            |  2 ++\n dir.c                              | 28 ++++++++++++++-----------\n dir.h                              |  9 ++++----\n git.c                              |  8 +++++++\n pathspec.c                         | 43 +++++++++++++++++++++++++++++++++-----\n pathspec.h                         |  4 +++-\n tree-walk.c                        |  9 ++++----\n 11 files changed, 131 insertions(+), 31 deletions(-)\n\ndiff --git a/Documentation/git.txt b/Documentation/git.txt\nindex 3bbbbdc..d96df8d 100644\n--- a/Documentation/git.txt\n+++ b/Documentation/git.txt\n@@ -443,6 +443,17 @@ help ...`.\n \tThis is equivalent to setting the `GIT_LITERAL_PATHSPECS` environment\n \tvariable to `1`.\n \n+--glob-pathspecs:\n+\tAdd \"glob\" magic to all pathspec. This is equivalent to setting\n+\tthe `GIT_GLOB_PATHSPECS` environment variable to `1`. Disabling\n+\tglobbing on individual pathspecs can be done using pathspec\n+\tmagic \":(literal)\"\n+\n+--noglob-pathspecs:\n+\tAdd \"literal\" magic to all pathspec. This is equivalent to setting\n+\tthe `GIT_NOGLOB_PATHSPECS` environment variable to `1`. Enabling\n+\tglobbing on individual pathspecs can be done using pathspec\n+\tmagic \":(glob)\"\n \n GIT COMMANDS\n ------------\n@@ -834,6 +845,14 @@ GIT_LITERAL_PATHSPECS::\n \tliteral paths to Git (e.g., paths previously given to you by\n \t`git ls-tree`, `--raw` diff output, etc).\n \n+GIT_GLOB_PATHSPECS::\n+\tSetting this variable to `1` will cause git to treat all\n+\tpathspecs as glob patterns (aka \"glob\" magic).\n+\n+GIT_NOGLOB_PATHSPECS::\n+\tSetting this variable to `1` will cause git to treat all\n+\tpathspecs as literal (aka \"literal\" magic).\n+\n \n Discussion[[Discussion]]\n ------------------------\ndiff --git a/Documentation/glossary-content.txt b/Documentation/glossary-content.txt\nindex 8b91aeb..40f2d29 100644\n--- a/Documentation/glossary-content.txt\n+++ b/Documentation/glossary-content.txt\n@@ -327,6 +327,35 @@ top `/`;;\n literal;;\n \tWildcards in the pattern such as `*` or `?` are treated\n \tas literal characters.\n+\n+glob;;\n+\tGit treats the pattern as a shell glob suitable for\n+\tconsumption by fnmatch(3) with the FNM_PATHNAME flag:\n+\twildcards in the pattern will not match a / in the pathname.\n+\tFor example, \"Documentation/{asterisk}.html\" matches\n+\t\"Documentation/git.html\" but not \"Documentation/ppc/ppc.html\"\n+\tor \"tools/perf/Documentation/perf.html\".\n++\n+Two consecutive asterisks (\"`**`\") in patterns matched against\n+full pathname may have special meaning:\n+\n+ - A leading \"`**`\" followed by a slash means match in all\n+   directories. For example, \"`**/foo`\" matches file or directory\n+   \"`foo`\" anywhere, the same as pattern \"`foo`\". \"**/foo/bar\"\n+   matches file or directory \"`bar`\" anywhere that is directly\n+   under directory \"`foo`\".\n+\n+ - A trailing \"/**\" matches everything inside. For example,\n+   \"abc/**\" matches all files inside directory \"abc\", relative\n+   to the location of the `.gitignore` file, with infinite depth.\n+\n+ - A slash followed by two consecutive asterisks then a slash\n+   matches zero or more directories. For example, \"`a/**/b`\"\n+   matches \"`a/b`\", \"`a/x/b`\", \"`a/x/y/b`\" and so on.\n+\n+ - Other consecutive asterisks are considered invalid.\n++\n+Glob magic is incompatible with literal magic.\n --\n +\n Currently only the slash `/` is recognized as the \"magic signature\",\ndiff --git a/builtin/add.c b/builtin/add.c\nindex 8bc6b45..d07cd1b 100644\n--- a/builtin/add.c\n+++ b/builtin/add.c\n@@ -426,11 +426,16 @@ int cmd_add(int argc, const char **argv, const char *prefix)\n \t\t/*\n \t\t * file_exists() assumes exact match\n \t\t */\n-\t\tGUARD_PATHSPEC(&pathspec, PATHSPEC_FROMTOP | PATHSPEC_LITERAL);\n+\t\tGUARD_PATHSPEC(&pathspec,\n+\t\t\t       PATHSPEC_FROMTOP |\n+\t\t\t       PATHSPEC_LITERAL |\n+\t\t\t       PATHSPEC_GLOB);\n \n \t\tfor (i = 0; i < pathspec.nr; i++) {\n \t\t\tconst char *path = pathspec.items[i].match;\n-\t\t\tif (!seen[i] && !file_exists(path)) {\n+\t\t\tif (!seen[i] &&\n+\t\t\t    ((pathspec.items[i].magic & PATHSPEC_GLOB) ||\n+\t\t\t     !file_exists(path))) {\n \t\t\t\tif (ignore_missing) {\n \t\t\t\t\tint dtype = DT_UNKNOWN;\n \t\t\t\t\tif (is_path_excluded(&check, path, -1, &dtype))\ndiff --git a/builtin/ls-tree.c b/builtin/ls-tree.c\nindex bdb03f3..1056634 100644\n--- a/builtin/ls-tree.c\n+++ b/builtin/ls-tree.c\n@@ -173,7 +173,7 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)\n \t * cannot be lifted until it is converted to use\n \t * match_pathspec_depth() or tree_entry_interesting()\n \t */\n-\tparse_pathspec(&pathspec, 0,\n+\tparse_pathspec(&pathspec, PATHSPEC_GLOB,\n \t\t       PATHSPEC_PREFER_CWD,\n \t\t       prefix, argv + 1);\n \tfor (i = 0; i < pathspec.nr; i++)\ndiff --git a/cache.h b/cache.h\nindex 17e0b26..bdc98e2 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -365,6 +365,8 @@ static inline enum object_type object_type(unsigned int mode)\n #define GIT_NOTES_REWRITE_REF_ENVIRONMENT \"GIT_NOTES_REWRITE_REF\"\n #define GIT_NOTES_REWRITE_MODE_ENVIRONMENT \"GIT_NOTES_REWRITE_MODE\"\n #define GIT_LITERAL_PATHSPECS_ENVIRONMENT \"GIT_LITERAL_PATHSPECS\"\n+#define GIT_GLOB_PATHSPECS_ENVIRONMENT \"GIT_GLOB_PATHSPECS\"\n+#define GIT_NOGLOB_PATHSPECS_ENVIRONMENT \"GIT_NOGLOB_PATHSPECS\"\n \n /*\n  * Repository-local GIT_* environment variables\ndiff --git a/dir.c b/dir.c\nindex 8d9ed24..77cd427 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -38,26 +38,28 @@ int fnmatch_icase(const char *pattern, const char *string, int flags)\n \treturn fnmatch(pattern, string, flags | (ignore_case ? FNM_CASEFOLD : 0));\n }\n \n-inline int git_fnmatch(const char *pattern, const char *string,\n-\t\t       int flags, int prefix)\n+inline int git_fnmatch(const struct pathspec_item *item,\n+\t\t       const char *pattern, const char *string,\n+\t\t       int prefix)\n {\n-\tint fnm_flags = 0;\n-\tif (flags & GFNM_PATHNAME)\n-\t\tfnm_flags |= FNM_PATHNAME;\n \tif (prefix > 0) {\n \t\tif (strncmp(pattern, string, prefix))\n \t\t\treturn FNM_NOMATCH;\n \t\tpattern += prefix;\n \t\tstring += prefix;\n \t}\n-\tif (flags & GFNM_ONESTAR) {\n+\tif (item->flags & PATHSPEC_ONESTAR) {\n \t\tint pattern_len = strlen(++pattern);\n \t\tint string_len = strlen(string);\n \t\treturn string_len < pattern_len ||\n \t\t       strcmp(pattern,\n \t\t\t      string + string_len - pattern_len);\n \t}\n-\treturn fnmatch(pattern, string, fnm_flags);\n+\tif (item->magic & PATHSPEC_GLOB)\n+\t\treturn wildmatch(pattern, string, WM_PATHNAME, NULL);\n+\telse\n+\t\t/* wildmatch has not learned no FNM_PATHNAME mode yet */\n+\t\treturn fnmatch(pattern, string, 0);\n }\n \n static size_t common_prefix_len(const struct pathspec *pathspec)\n@@ -68,7 +70,8 @@ static size_t common_prefix_len(const struct pathspec *pathspec)\n \tGUARD_PATHSPEC(pathspec,\n \t\t       PATHSPEC_FROMTOP |\n \t\t       PATHSPEC_MAXDEPTH |\n-\t\t       PATHSPEC_LITERAL);\n+\t\t       PATHSPEC_LITERAL |\n+\t\t       PATHSPEC_GLOB);\n \n \tfor (n = 0; n < pathspec->nr; n++) {\n \t\tsize_t i = 0, len = 0;\n@@ -163,8 +166,7 @@ static int match_pathspec_item(const struct pathspec_item *item, int prefix,\n \t}\n \n \tif (item->nowildcard_len < item->len &&\n-\t    !git_fnmatch(match, name,\n-\t\t\t item->flags & PATHSPEC_ONESTAR ? GFNM_ONESTAR : 0,\n+\t    !git_fnmatch(item, match, name,\n \t\t\t item->nowildcard_len - prefix))\n \t\treturn MATCHED_FNMATCH;\n \n@@ -195,7 +197,8 @@ int match_pathspec_depth(const struct pathspec *ps,\n \tGUARD_PATHSPEC(ps,\n \t\t       PATHSPEC_FROMTOP |\n \t\t       PATHSPEC_MAXDEPTH |\n-\t\t       PATHSPEC_LITERAL);\n+\t\t       PATHSPEC_LITERAL |\n+\t\t       PATHSPEC_GLOB);\n \n \tif (!ps->nr) {\n \t\tif (!ps->recursive ||\n@@ -1347,7 +1350,8 @@ int read_directory(struct dir_struct *dir, const char *path, int len, const stru\n \t\tGUARD_PATHSPEC(pathspec,\n \t\t\t       PATHSPEC_FROMTOP |\n \t\t\t       PATHSPEC_MAXDEPTH |\n-\t\t\t       PATHSPEC_LITERAL);\n+\t\t\t       PATHSPEC_LITERAL |\n+\t\t\t       PATHSPEC_GLOB);\n \n \tif (has_symlink_leading_path(path, len))\n \t\treturn dir->nr;\ndiff --git a/dir.h b/dir.h\nindex 13da62c..da67237 100644\n--- a/dir.h\n+++ b/dir.h\n@@ -208,10 +208,9 @@ extern int fnmatch_icase(const char *pattern, const char *string, int flags);\n /*\n  * The prefix part of pattern must not contains wildcards.\n  */\n-#define GFNM_PATHNAME 1\t\t/* similar to FNM_PATHNAME */\n-#define GFNM_ONESTAR  2\t\t/* there is only _one_ wildcard, a star */\n-\n-extern int git_fnmatch(const char *pattern, const char *string,\n-\t\t       int flags, int prefix);\n+struct pathspec_item;\n+extern int git_fnmatch(const struct pathspec_item *item,\n+\t\t       const char *pattern, const char *string,\n+\t\t       int prefix);\n \n #endif\ndiff --git a/git.c b/git.c\nindex 39ba6b1..65c386a 100644\n--- a/git.c\n+++ b/git.c\n@@ -143,6 +143,14 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)\n \t\t\tsetenv(GIT_LITERAL_PATHSPECS_ENVIRONMENT, \"0\", 1);\n \t\t\tif (envchanged)\n \t\t\t\t*envchanged = 1;\n+\t\t} else if (!strcmp(cmd, \"--glob-pathspecs\")) {\n+\t\t\tsetenv(GIT_GLOB_PATHSPECS_ENVIRONMENT, \"1\", 1);\n+\t\t\tif (envchanged)\n+\t\t\t\t*envchanged = 1;\n+\t\t} else if (!strcmp(cmd, \"--noglob-pathspecs\")) {\n+\t\t\tsetenv(GIT_NOGLOB_PATHSPECS_ENVIRONMENT, \"1\", 1);\n+\t\t\tif (envchanged)\n+\t\t\t\t*envchanged = 1;\n \t\t} else {\n \t\t\tfprintf(stderr, \"Unknown option: %s\\n\", cmd);\n \t\t\tusage(git_usage_string);\ndiff --git a/pathspec.c b/pathspec.c\nindex 61a47b8..7ddcf55 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -57,7 +57,6 @@ char *find_pathspecs_matching_against_index(const struct pathspec *pathspec)\n  *\n  * Possible future magic semantics include stuff like:\n  *\n- *\t{ PATHSPEC_NOGLOB, '!', \"noglob\" },\n  *\t{ PATHSPEC_ICASE, '\\0', \"icase\" },\n  *\t{ PATHSPEC_RECURSIVE, '*', \"recursive\" },\n  *\t{ PATHSPEC_REGEXP, '\\0', \"regexp\" },\n@@ -71,6 +70,7 @@ static struct pathspec_magic {\n } pathspec_magic[] = {\n \t{ PATHSPEC_FROMTOP, '/', \"top\" },\n \t{ PATHSPEC_LITERAL,   0, \"literal\" },\n+\t{ PATHSPEC_GLOB,   '\\0', \"glob\" },\n };\n \n /*\n@@ -93,6 +93,8 @@ static unsigned prefix_pathspec(struct pathspec_item *item,\n \t\t\t\tconst char *elt)\n {\n \tstatic int literal_global = -1;\n+\tstatic int glob_global = -1;\n+\tstatic int noglob_global = -1;\n \tunsigned magic = 0, short_magic = 0, global_magic = 0;\n \tconst char *copyfrom = elt, *long_magic_end = NULL;\n \tchar *match;\n@@ -103,6 +105,22 @@ static unsigned prefix_pathspec(struct pathspec_item *item,\n \tif (literal_global)\n \t\tglobal_magic |= PATHSPEC_LITERAL;\n \n+\tif (glob_global < 0)\n+\t\tglob_global = git_env_bool(GIT_GLOB_PATHSPECS_ENVIRONMENT, 0);\n+\tif (glob_global)\n+\t\tglobal_magic |= PATHSPEC_GLOB;\n+\n+\tif (noglob_global < 0)\n+\t\tnoglob_global = git_env_bool(GIT_NOGLOB_PATHSPECS_ENVIRONMENT, 0);\n+\n+\tif (glob_global && noglob_global)\n+\t\tdie(_(\"global 'glob' and 'noglob' pathspec settings are incompatible\"));\n+\n+\tif ((global_magic & PATHSPEC_LITERAL) &&\n+\t    (global_magic & ~PATHSPEC_LITERAL))\n+\t\tdie(_(\"global 'literal' pathspec setting is incompatiable \"\n+\t\t      \"with all other global pathspec settings\"));\n+\n \tif (elt[0] != ':' || literal_global) {\n \t\t; /* nothing to do */\n \t} else if (elt[1] == '(') {\n@@ -166,12 +184,20 @@ static unsigned prefix_pathspec(struct pathspec_item *item,\n \n \tmagic |= short_magic;\n \t*p_short_magic = short_magic;\n+\n+\t/* --noglob-pathspec adds :(literal) _unless_ :(glob) is specifed */\n+\tif (noglob_global && !(magic & PATHSPEC_GLOB))\n+\t\tglobal_magic |= PATHSPEC_LITERAL;\n+\n \tmagic |= global_magic;\n \n \tif (pathspec_prefix >= 0 &&\n \t    (prefixlen || (prefix && *prefix)))\n \t\tdie(\"BUG: 'prefix' magic is supposed to be used at worktree's root\");\n \n+\tif ((magic & PATHSPEC_LITERAL) && (magic & PATHSPEC_GLOB))\n+\t\tdie(\"%s: 'literal' and 'glob' are incompatible\", elt);\n+\n \tif (pathspec_prefix >= 0) {\n \t\tmatch = xstrdup(copyfrom);\n \t\tprefixlen = pathspec_prefix;\n@@ -247,10 +273,17 @@ static unsigned prefix_pathspec(struct pathspec_item *item,\n \t\t\titem->nowildcard_len = prefixlen;\n \t}\n \titem->flags = 0;\n-\tif (item->nowildcard_len < item->len &&\n-\t    item->match[item->nowildcard_len] == '*' &&\n-\t    no_wildcard(item->match + item->nowildcard_len + 1))\n-\t\titem->flags |= PATHSPEC_ONESTAR;\n+\tif (magic & PATHSPEC_GLOB) {\n+\t\t/*\n+\t\t * FIXME: should we enable ONESTAR in _GLOB for\n+\t\t * pattern \"* * / * . c\"?\n+\t\t */\n+\t} else {\n+\t\tif (item->nowildcard_len < item->len &&\n+\t\t    item->match[item->nowildcard_len] == '*' &&\n+\t\t    no_wildcard(item->match + item->nowildcard_len + 1))\n+\t\t\titem->flags |= PATHSPEC_ONESTAR;\n+\t}\n \treturn magic;\n }\n \ndiff --git a/pathspec.h b/pathspec.h\nindex d5db7d5..9a0c5d5 100644\n--- a/pathspec.h\n+++ b/pathspec.h\n@@ -5,10 +5,12 @@\n #define PATHSPEC_FROMTOP\t(1<<0)\n #define PATHSPEC_MAXDEPTH\t(1<<1)\n #define PATHSPEC_LITERAL\t(1<<2)\n+#define PATHSPEC_GLOB\t\t(1<<3)\n #define PATHSPEC_ALL_MAGIC\t  \\\n \t(PATHSPEC_FROMTOP\t| \\\n \t PATHSPEC_MAXDEPTH\t| \\\n-\t PATHSPEC_LITERAL)\n+\t PATHSPEC_LITERAL\t| \\\n+\t PATHSPEC_GLOB)\n \n #define PATHSPEC_ONESTAR 1\t/* the pathspec pattern sastisfies GFNM_ONESTAR */\n \ndiff --git a/tree-walk.c b/tree-walk.c\nindex 676bd7f..a44f528 100644\n--- a/tree-walk.c\n+++ b/tree-walk.c\n@@ -639,7 +639,8 @@ enum interesting tree_entry_interesting(const struct name_entry *entry,\n \tGUARD_PATHSPEC(ps,\n \t\t       PATHSPEC_FROMTOP |\n \t\t       PATHSPEC_MAXDEPTH |\n-\t\t       PATHSPEC_LITERAL);\n+\t\t       PATHSPEC_LITERAL |\n+\t\t       PATHSPEC_GLOB);\n \n \tif (!ps->nr) {\n \t\tif (!ps->recursive ||\n@@ -685,8 +686,7 @@ enum interesting tree_entry_interesting(const struct name_entry *entry,\n \t\t\t\treturn entry_interesting;\n \n \t\t\tif (item->nowildcard_len < item->len) {\n-\t\t\t\tif (!git_fnmatch(match + baselen, entry->path,\n-\t\t\t\t\t\t item->flags & PATHSPEC_ONESTAR ? GFNM_ONESTAR : 0,\n+\t\t\t\tif (!git_fnmatch(item, match + baselen, entry->path,\n \t\t\t\t\t\t item->nowildcard_len - baselen))\n \t\t\t\t\treturn entry_interesting;\n \n@@ -727,8 +727,7 @@ match_wildcards:\n \n \t\tstrbuf_add(base, entry->path, pathlen);\n \n-\t\tif (!git_fnmatch(match, base->buf + base_offset,\n-\t\t\t\t item->flags & PATHSPEC_ONESTAR ? GFNM_ONESTAR : 0,\n+\t\tif (!git_fnmatch(item, match, base->buf + base_offset,\n \t\t\t\t item->nowildcard_len)) {\n \t\t\tstrbuf_setlen(base, base_offset + baselen);\n \t\t\treturn entry_interesting;\n-- \n1.8.0.rc0.19.g7bbb31d\n"},{"id":"211389","messageId":"1363327620-29017-46-git-send-email-pclouds@gmail.com","threadId":"33187","inReplyTo":"1363327620-29017-1-git-send-email-pclouds@gmail.com","subject":"[PATCH v1 45/45] Rename field \"raw\" to \"_raw\" in struct pathspec","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2013-03-15T06:07:00Z","receivedAt":"2013-03-15T06:07:00Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"This patch is essentially no-op. It helps catching new use of this\nfield though. This field is introduced as an intermediate step for the\npathspec conversion and will be removed eventually. At this stage no\nmore access sites should be introduced.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n builtin/ls-tree.c | 2 +-\n dir.c             | 4 ++--\n pathspec.c        | 6 +++---\n pathspec.h        | 2 +-\n 4 files changed, 7 insertions(+), 7 deletions(-)\n\ndiff --git a/builtin/ls-tree.c b/builtin/ls-tree.c\nindex 1056634..7882352 100644\n--- a/builtin/ls-tree.c\n+++ b/builtin/ls-tree.c\n@@ -36,7 +36,7 @@ static int show_recursive(const char *base, int baselen, const char *pathname)\n \tif (ls_options & LS_RECURSIVE)\n \t\treturn 1;\n \n-\ts = pathspec.raw;\n+\ts = pathspec._raw;\n \tif (!s)\n \t\treturn 0;\n \ndiff --git a/dir.c b/dir.c\nindex 77cd427..e52c899 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -115,7 +115,7 @@ int fill_directory(struct dir_struct *dir, const struct pathspec *pathspec)\n \tlen = common_prefix_len(pathspec);\n \n \t/* Read the directory and prune it */\n-\tread_directory(dir, pathspec->nr ? pathspec->raw[0] : \"\", len, pathspec);\n+\tread_directory(dir, pathspec->nr ? pathspec->_raw[0] : \"\", len, pathspec);\n \treturn len;\n }\n \n@@ -1356,7 +1356,7 @@ int read_directory(struct dir_struct *dir, const char *path, int len, const stru\n \tif (has_symlink_leading_path(path, len))\n \t\treturn dir->nr;\n \n-\tsimplify = create_simplify(pathspec ? pathspec->raw : NULL);\n+\tsimplify = create_simplify(pathspec ? pathspec->_raw : NULL);\n \tif (!len || treat_leading_path(dir, path, len, simplify))\n \t\tread_directory_recursive(dir, path, len, 0, simplify);\n \tfree_simplify(simplify);\ndiff --git a/pathspec.c b/pathspec.c\nindex 7ddcf55..9640d88 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -365,7 +365,7 @@ void parse_pathspec(struct pathspec *pathspec,\n \t\traw[0] = prefix;\n \t\traw[1] = NULL;\n \t\tpathspec->nr = 1;\n-\t\tpathspec->raw = raw;\n+\t\tpathspec->_raw = raw;\n \t\treturn;\n \t}\n \n@@ -375,7 +375,7 @@ void parse_pathspec(struct pathspec *pathspec,\n \n \tpathspec->nr = n;\n \tpathspec->items = item = xmalloc(sizeof(*item) * n);\n-\tpathspec->raw = argv;\n+\tpathspec->_raw = argv;\n \tprefixlen = prefix ? strlen(prefix) : 0;\n \n \tfor (i = 0; i < n; i++) {\n@@ -436,7 +436,7 @@ const char **get_pathspec(const char *prefix, const char **pathspec)\n \t\t       ~(PATHSPEC_FROMTOP | PATHSPEC_LITERAL),\n \t\t       PATHSPEC_PREFER_CWD,\n \t\t       prefix, pathspec);\n-\treturn ps.raw;\n+\treturn ps._raw;\n }\n \n void copy_pathspec(struct pathspec *dst, const struct pathspec *src)\ndiff --git a/pathspec.h b/pathspec.h\nindex 9a0c5d5..84f279d 100644\n--- a/pathspec.h\n+++ b/pathspec.h\n@@ -15,7 +15,7 @@\n #define PATHSPEC_ONESTAR 1\t/* the pathspec pattern sastisfies GFNM_ONESTAR */\n \n struct pathspec {\n-\tconst char **raw; /* get_pathspec() result, not freed by free_pathspec() */\n+\tconst char **_raw; /* get_pathspec() result, not freed by free_pathspec() */\n \tint nr;\n \tunsigned int has_wildcard:1;\n \tunsigned int recursive:1;\n-- \n1.8.0.rc0.19.g7bbb31d\n"},{"id":"211411","messageId":"7vk3p8v9k7.fsf@alter.siamese.dyndns.org","threadId":"33187","inReplyTo":"1363327620-29017-1-git-send-email-pclouds@gmail.com","subject":"Re: [PATCH v1 00/45] nd/parse-pathspec and :(glob) pathspec magic","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2013-03-15T17:48:08Z","receivedAt":"2013-03-15T17:48:08Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Nguyễn Thái Ngọc Duy  <pclouds@gmail.com> writes:\n\n> Probably not much to say. A big portion of this series is the\n> conversion to struct pathspec, which enables more use of pathspec\n> magic. :(glob) magic is added to verify that the conversion makes\n> sense.\n\nI haven't read any of these patches, but there remains only one user\nof the _raw field in dir.c (read_directory) and get_pathspec() is\ncalled by nobody other than builtin/mv.c after this series.\n\nVery encouraging.\n\n> Andrew Wong (1):\n>   setup.c: check that the pathspec magic ends with \")\"\n>\n> Nguyễn Thái Ngọc Duy (44):\n>   clean: remove unused variable \"seen\"\n>   Move struct pathspec and related functions to pathspec.[ch]\n>   pathspec: i18n-ize error strings in pathspec parsing code\n>   pathspec: add copy_pathspec\n>   Add parse_pathspec() that converts cmdline args to struct pathspec\n>   parse_pathspec: save original pathspec for reporting\n>   parse_pathspec: add PATHSPEC_PREFER_{CWD,FULL}\n>   Convert some get_pathspec() calls to parse_pathspec()\n>   parse_pathspec: a special flag for max_depth feature\n>   parse_pathspec: support stripping submodule trailing slashes\n>   parse_pathspec: support stripping/checking submodule paths\n>   parse_pathspec: support prefixing original patterns\n>   Guard against new pathspec magic in pathspec matching code\n>   clean: convert to use parse_pathspec\n>   commit: convert to use parse_pathspec\n>   status: convert to use parse_pathspec\n>   rerere: convert to use parse_pathspec\n>   checkout: convert to use parse_pathspec\n>   rm: convert to use parse_pathspec\n>   ls-files: convert to use parse_pathspec\n>   archive: convert to use parse_pathspec\n>   check-ignore: convert to use parse_pathspec\n>   add: convert to use parse_pathspec\n>   reset: convert to use parse_pathspec\n>   Convert read_cache_preload() to take struct pathspec\n>   Convert run_add_interactive to use struct pathspec\n>   Convert unmerge_cache to take struct pathspec\n>   checkout: convert read_tree_some to take struct pathspec\n>   Convert report_path_error to take struct pathspec\n>   Convert refresh_index to take struct pathspec\n>   Convert {read,fill}_directory to take struct pathspec\n>   Convert add_files_to_cache to take struct pathspec\n>   Convert common_prefix() to use struct pathspec\n>   Remove diff_tree_{setup,release}_paths\n>   Remove init_pathspec() in favor of parse_pathspec()\n>   Remove match_pathspec() in favor of match_pathspec_depth()\n>   tree-diff: remove the use of pathspec's raw[] in follow-rename codepath\n>   parse_pathspec: make sure the prefix part is wildcard-free\n>   parse_pathspec: preserve prefix length via PATHSPEC_PREFIX_ORIGIN\n>   Kill limit_pathspec_to_literal() as it's only used by parse_pathspec()\n>   pathspec: support :(literal) syntax for noglob pathspec\n>   pathspec: make --literal-pathspecs disable pathspec magic\n>   pathspec: support :(glob) syntax\n>   Rename field \"raw\" to \"_raw\" in struct pathspec\n>\n>  Documentation/git.txt              |  23 +-\n>  Documentation/glossary-content.txt |  33 +++\n>  archive.c                          |  18 +-\n>  archive.h                          |   4 +-\n>  builtin/add.c                      | 156 ++++++--------\n>  builtin/blame.c                    |  14 +-\n>  builtin/check-ignore.c             |  34 +--\n>  builtin/checkout.c                 |  46 ++--\n>  builtin/clean.c                    |  24 +--\n>  builtin/commit.c                   |  37 ++--\n>  builtin/diff-files.c               |   2 +-\n>  builtin/diff-index.c               |   2 +-\n>  builtin/diff.c                     |   6 +-\n>  builtin/grep.c                     |  10 +-\n>  builtin/log.c                      |   2 +-\n>  builtin/ls-files.c                 |  75 +++----\n>  builtin/ls-tree.c                  |  13 +-\n>  builtin/mv.c                       |  13 +-\n>  builtin/rerere.c                   |   8 +-\n>  builtin/reset.c                    |  33 +--\n>  builtin/rm.c                       |  24 +--\n>  builtin/update-index.c             |   6 +-\n>  cache.h                            |  34 +--\n>  commit.h                           |   2 +-\n>  diff-lib.c                         |   3 +-\n>  diff.h                             |   3 +-\n>  dir.c                              | 261 +++++-----------------\n>  dir.h                              |  18 +-\n>  git.c                              |   8 +\n>  merge-recursive.c                  |   2 +-\n>  notes-merge.c                      |   4 +-\n>  path.c                             |  15 +-\n>  pathspec.c                         | 431 +++++++++++++++++++++++++++++++++----\n>  pathspec.h                         |  59 ++++-\n>  preload-index.c                    |  21 +-\n>  read-cache.c                       |   5 +-\n>  rerere.c                           |   7 +-\n>  rerere.h                           |   4 +-\n>  resolve-undo.c                     |   4 +-\n>  resolve-undo.h                     |   2 +-\n>  revision.c                         |  11 +-\n>  setup.c                            | 157 +-------------\n>  t/t0008-ignores.sh                 |   8 +-\n>  t/t6130-pathspec-noglob.sh         |  18 ++\n>  tree-diff.c                        |  48 +++--\n>  tree-walk.c                        |  21 +-\n>  tree.c                             |   4 +-\n>  tree.h                             |   2 +-\n>  wt-status.c                        |  18 +-\n>  wt-status.h                        |   2 +-\n>  50 files changed, 983 insertions(+), 772 deletions(-)\n"},{"id":"211412","messageId":"7vfvzwv96b.fsf@alter.siamese.dyndns.org","threadId":"33187","inReplyTo":"1363327620-29017-23-git-send-email-pclouds@gmail.com","subject":"Re: [PATCH v1 22/45] archive: convert to use parse_pathspec","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2013-03-15T17:56:28Z","receivedAt":"2013-03-15T17:56:28Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Nguyễn Thái Ngọc Duy  <pclouds@gmail.com> writes:\n\n> @@ -232,11 +228,18 @@ static int path_exists(struct tree *tree, const char *path)\n>  static void parse_pathspec_arg(const char **pathspec,\n>  \t\tstruct archiver_args *ar_args)\n>  {\n> -\tar_args->pathspec = pathspec = get_pathspec(\"\", pathspec);\n> +\t/*\n> +\t * must be consistent with parse_pathspec in path_exists()\n> +\t * Also if pathspec patterns are dependent, we're in big\n> +\t * trouble as we test each one separately\n> +\t */\n> +\tparse_pathspec(&ar_args->pathspec, 0,\n> +\t\t       PATHSPEC_PREFER_FULL,\n> +\t\t       \"\", pathspec);\n>  \tif (pathspec) {\n>  \t\twhile (*pathspec) {\n>  \t\t\tif (!path_exists(ar_args->tree, *pathspec))\n> -\t\t\t\tdie(\"path not found: %s\", *pathspec);\n> +\t\t\t\tdie(_(\"pathspec '%s' did not match any files\"), *pathspec);\n>  \t\t\tpathspec++;\n>  \t\t}\n\nYou do not use ar_args->pathspec even though you used parse_pathspec()\nto grok it?  What's the point of this change?\n\n>  \t}\n> diff --git a/archive.h b/archive.h\n> index 895afcd..4a791e1 100644\n> --- a/archive.h\n> +++ b/archive.h\n> @@ -1,6 +1,8 @@\n>  #ifndef ARCHIVE_H\n>  #define ARCHIVE_H\n>  \n> +#include \"pathspec.h\"\n> +\n>  struct archiver_args {\n>  \tconst char *base;\n>  \tsize_t baselen;\n> @@ -8,7 +10,7 @@ struct archiver_args {\n>  \tconst unsigned char *commit_sha1;\n>  \tconst struct commit *commit;\n>  \ttime_t time;\n> -\tconst char **pathspec;\n> +\tstruct pathspec pathspec;\n>  \tunsigned int verbose : 1;\n>  \tunsigned int worktree_attributes : 1;\n>  \tunsigned int convert : 1;\n"},{"id":"211417","messageId":"CAPig+cQi6p=cbQzLFhauy-0ccknpVyV-uF6pZURvObPyS2w6OQ@mail.gmail.com","threadId":"33187","inReplyTo":"1363327620-29017-11-git-send-email-pclouds@gmail.com","subject":"Re: [PATCH v1 10/45] parse_pathspec: a special flag for max_depth feature","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2013-03-15T21:28:59Z","receivedAt":"2013-03-15T21:28:59Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Fri, Mar 15, 2013 at 2:06 AM, Nguyễn Thái Ngọc Duy <pclouds@gmail.com> wrote:\n> match_pathspec_depth() and tree_entry_interesting() check max_depth\n> field in order to support \"git grep --max-depth\". The feature\n> activation is tied to \"recursive\" field, which led to some unwated\n\ns/unwated/unwanted/\n\n> activation, e.g. 5c8eeb8 (diff-index: enable recursive pathspec\n> matching in unpack_trees - 2012-01-15).\n"},{"id":"211419","messageId":"CAPig+cSbb7hz2PMyOegqGRofQ8nUsVL7JboWobVviyy0spy=9w@mail.gmail.com","threadId":"33187","inReplyTo":"1363327620-29017-41-git-send-email-pclouds@gmail.com","subject":"Re: [PATCH v1 40/45] parse_pathspec: preserve prefix length via PATHSPEC_PREFIX_ORIGIN","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2013-03-15T22:00:56Z","receivedAt":"2013-03-15T22:00:56Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Fri, Mar 15, 2013 at 2:06 AM, Nguyễn Thái Ngọc Duy <pclouds@gmail.com> wrote:\n> Prefix length is not preserved across commands when --literal-pathspecs\n> is specified (no magic is allowed, including 'prefix'). That's OK\n> because we all paths are literal. No magic, no special treatment\n\ns/we all/we know all/\n...or...\ns/we all/all/\n\n> We could also preserve 'prefix' across commands is quote the prefix\n> part, then dequote on receiving. But it may not be 100% accurate, we\n\ns/is quote/by quoting/\ns/dequote/dequoting/\n\n> may dequote longer than the original prefix part, for example. That\n> may be good or not, but it's not the purpose.\n"},{"id":"211420","messageId":"CAPig+cTsP2TmoO0MHPZAUB1RZQO3iVAEA11zxxCvcjbGqNeQuQ@mail.gmail.com","threadId":"33187","inReplyTo":"1363327620-29017-45-git-send-email-pclouds@gmail.com","subject":"Re: [PATCH v1 44/45] pathspec: support :(glob) syntax","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2013-03-15T22:11:31Z","receivedAt":"2013-03-15T22:11:31Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Fri, Mar 15, 2013 at 2:06 AM, Nguyễn Thái Ngọc Duy <pclouds@gmail.com> wrote:\n> +GIT_GLOB_PATHSPECS::\n> +       Setting this variable to `1` will cause git to treat all\n> +       pathspecs as glob patterns (aka \"glob\" magic).\n\nPer recent git -> Git normalization, probably: s/git/Git/\n\n> +\n> +GIT_NOGLOB_PATHSPECS::\n> +       Setting this variable to `1` will cause git to treat all\n> +       pathspecs as literal (aka \"literal\" magic).\n\nDitto: s/git/Git/\n\n> @@ -103,6 +105,22 @@ static unsigned prefix_pathspec(struct pathspec_item *item,\n>         if (literal_global)\n>                 global_magic |= PATHSPEC_LITERAL;\n>\n> +       if (glob_global < 0)\n> +               glob_global = git_env_bool(GIT_GLOB_PATHSPECS_ENVIRONMENT, 0);\n> +       if (glob_global)\n> +               global_magic |= PATHSPEC_GLOB;\n> +\n> +       if (noglob_global < 0)\n> +               noglob_global = git_env_bool(GIT_NOGLOB_PATHSPECS_ENVIRONMENT, 0);\n> +\n> +       if (glob_global && noglob_global)\n> +               die(_(\"global 'glob' and 'noglob' pathspec settings are incompatible\"));\n> +\n> +       if ((global_magic & PATHSPEC_LITERAL) &&\n> +           (global_magic & ~PATHSPEC_LITERAL))\n> +               die(_(\"global 'literal' pathspec setting is incompatiable \"\n> +                     \"with all other global pathspec settings\"));\n\ns/incompatiable/incompatible/\n\n-- ES\n"},{"id":"211423","messageId":"CACsJy8DUb5j0of=cuQje5cRWLwyi-MiH-d-RsyBiPOjaD1Tntg@mail.gmail.com","threadId":"33187","inReplyTo":"7vfvzwv96b.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH v1 22/45] archive: convert to use parse_pathspec","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2013-03-16T01:08:29Z","receivedAt":"2013-03-16T01:08:29Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Sat, Mar 16, 2013 at 12:56 AM, Junio C Hamano <gitster@pobox.com> wrote:\n> Nguyễn Thái Ngọc Duy  <pclouds@gmail.com> writes:\n>\n>> @@ -232,11 +228,18 @@ static int path_exists(struct tree *tree, const char *path)\n>>  static void parse_pathspec_arg(const char **pathspec,\n>>               struct archiver_args *ar_args)\n>>  {\n>> -     ar_args->pathspec = pathspec = get_pathspec(\"\", pathspec);\n>> +     /*\n>> +      * must be consistent with parse_pathspec in path_exists()\n>> +      * Also if pathspec patterns are dependent, we're in big\n>> +      * trouble as we test each one separately\n>> +      */\n>> +     parse_pathspec(&ar_args->pathspec, 0,\n>> +                    PATHSPEC_PREFER_FULL,\n>> +                    \"\", pathspec);\n>>       if (pathspec) {\n>>               while (*pathspec) {\n>>                       if (!path_exists(ar_args->tree, *pathspec))\n>> -                             die(\"path not found: %s\", *pathspec);\n>> +                             die(_(\"pathspec '%s' did not match any files\"), *pathspec);\n>>                       pathspec++;\n>>               }\n>\n> You do not use ar_args->pathspec even though you used parse_pathspec()\n> to grok it?  What's the point of this change?\n\nparse_pathspec() here is needed because write_archive_entries needs it\nlater. tree_entry_interesting() has not supported \"seen\" feature like\nmatch_pathspec_depth() to detect unused pathspecs. For simplicity,\njust check each pathspec individually. We can revisit this when we add\n\"seen\" feature to tree_entry_interesting.\n-- \nDuy\n"},{"id":"211483","messageId":"7vehfetycj.fsf@alter.siamese.dyndns.org","threadId":"33187","inReplyTo":"CACsJy8DUb5j0of=cuQje5cRWLwyi-MiH-d-RsyBiPOjaD1Tntg@mail.gmail.com","subject":"Re: [PATCH v1 22/45] archive: convert to use parse_pathspec","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2013-03-17T05:00:12Z","receivedAt":"2013-03-17T05:00:12Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Duy Nguyen <pclouds@gmail.com> writes:\n\n> On Sat, Mar 16, 2013 at 12:56 AM, Junio C Hamano <gitster@pobox.com> wrote:\n>> Nguyễn Thái Ngọc Duy  <pclouds@gmail.com> writes:\n>>\n>>> @@ -232,11 +228,18 @@ static int path_exists(struct tree *tree, const char *path)\n>>>  static void parse_pathspec_arg(const char **pathspec,\n>>>               struct archiver_args *ar_args)\n>>>  {\n>>> -     ar_args->pathspec = pathspec = get_pathspec(\"\", pathspec);\n>>> +     /*\n>>> +      * must be consistent with parse_pathspec in path_exists()\n>>> +      * Also if pathspec patterns are dependent, we're in big\n>>> +      * trouble as we test each one separately\n>>> +      */\n>>> +     parse_pathspec(&ar_args->pathspec, 0,\n>>> +                    PATHSPEC_PREFER_FULL,\n>>> +                    \"\", pathspec);\n>>>       if (pathspec) {\n>>>               while (*pathspec) {\n>>>                       if (!path_exists(ar_args->tree, *pathspec))\n>>> -                             die(\"path not found: %s\", *pathspec);\n>>> +                             die(_(\"pathspec '%s' did not match any files\"), *pathspec);\n>>>                       pathspec++;\n>>>               }\n>>\n>> You do not use ar_args->pathspec even though you used parse_pathspec()\n>> to grok it?  What's the point of this change?\n>\n> parse_pathspec() here is needed because write_archive_entries needs it\n> later.\n\nThat is not the issue I was pointing out.  Even though you parse the\npathspec into args->pathspec, the \"if() { while () {} }\" here still\nuses strings contained in **pathspec, as if they are literal strings\nand not \":(glob)Documentation\" and such, and will not match the named\ndirectory.\n\nTechnically, erroring out saying \"':(glob)Documentation' does not exist\nas a path in the tree\" is correct, but it would be nicer to have the\ncode inspect parse_pathspec() result and independently barf, saying\n\"this command does not support magic pathspecs, give me leading paths\nand nothing else\", until we do support magic pathspecs, no?\n"},{"id":"211485","messageId":"CACsJy8A3NaA=faQoGhCDWNB7CKHQ2WF_5T0tf9z7mGTYFdreEg@mail.gmail.com","threadId":"33187","inReplyTo":"7vehfetycj.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH v1 22/45] archive: convert to use parse_pathspec","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2013-03-17T05:31:01Z","receivedAt":"2013-03-17T05:31:01Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Sun, Mar 17, 2013 at 12:00 PM, Junio C Hamano <gitster@pobox.com> wrote:\n> Duy Nguyen <pclouds@gmail.com> writes:\n>\n>> On Sat, Mar 16, 2013 at 12:56 AM, Junio C Hamano <gitster@pobox.com> wrote:\n>>> Nguyễn Thái Ngọc Duy  <pclouds@gmail.com> writes:\n>>>\n>>>> @@ -232,11 +228,18 @@ static int path_exists(struct tree *tree, const char *path)\n>>>>  static void parse_pathspec_arg(const char **pathspec,\n>>>>               struct archiver_args *ar_args)\n>>>>  {\n>>>> -     ar_args->pathspec = pathspec = get_pathspec(\"\", pathspec);\n>>>> +     /*\n>>>> +      * must be consistent with parse_pathspec in path_exists()\n>>>> +      * Also if pathspec patterns are dependent, we're in big\n>>>> +      * trouble as we test each one separately\n>>>> +      */\n>>>> +     parse_pathspec(&ar_args->pathspec, 0,\n>>>> +                    PATHSPEC_PREFER_FULL,\n>>>> +                    \"\", pathspec);\n>>>>       if (pathspec) {\n>>>>               while (*pathspec) {\n>>>>                       if (!path_exists(ar_args->tree, *pathspec))\n>>>> -                             die(\"path not found: %s\", *pathspec);\n>>>> +                             die(_(\"pathspec '%s' did not match any files\"), *pathspec);\n>>>>                       pathspec++;\n>>>>               }\n>>>\n>>> You do not use ar_args->pathspec even though you used parse_pathspec()\n>>> to grok it?  What's the point of this change?\n>>\n>> parse_pathspec() here is needed because write_archive_entries needs it\n>> later.\n>\n> That is not the issue I was pointing out.  Even though you parse the\n> pathspec into args->pathspec, the \"if() { while () {} }\" here still\n> uses strings contained in **pathspec, as if they are literal strings\n> and not \":(glob)Documentation\" and such, and will not match the named\n> directory.\n\nNo, the literal strings are reparsed in path_exists() before being fed\nto read_tree_recursive. So \":(glob)Documentation\" should match the\ntree \"Documentation\".\n\n> Technically, erroring out saying \"':(glob)Documentation' does not exist\n> as a path in the tree\" is correct, but it would be nicer to have the\n> code inspect parse_pathspec() result and independently barf, saying\n> \"this command does not support magic pathspecs, give me leading paths\n> and nothing else\", until we do support magic pathspecs, no?\n-- \nDuy\n"},{"id":"211497","messageId":"7vboaisfyy.fsf@alter.siamese.dyndns.org","threadId":"33187","inReplyTo":"CACsJy8A3NaA=faQoGhCDWNB7CKHQ2WF_5T0tf9z7mGTYFdreEg@mail.gmail.com","subject":"Re: [PATCH v1 22/45] archive: convert to use parse_pathspec","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2013-03-17T06:22:29Z","receivedAt":"2013-03-17T06:22:29Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Duy Nguyen <pclouds@gmail.com> writes:\n\n> No, the literal strings are reparsed in path_exists() before being fed\n> to read_tree_recursive.\n\nYuck.  OK.  Thanks.\n"},{"id":"211530","messageId":"7vy5dlpu7i.fsf@alter.siamese.dyndns.org","threadId":"33187","inReplyTo":"1363327620-29017-12-git-send-email-pclouds@gmail.com","subject":"Re: [PATCH v1 11/45] parse_pathspec: support stripping submodule trailing slashes","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2013-03-17T21:55:29Z","receivedAt":"2013-03-17T21:55:29Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Nguyễn Thái Ngọc Duy  <pclouds@gmail.com> writes:\n\n> This flag is equivalent to builtin/ls-files.c:strip_trailing_slashes()\n> and is intended to replace that function when ls-files is converted to\n> use parse_pathspec.\n>\n> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n> ---\n>  pathspec.c | 9 +++++++++\n>  pathspec.h | 1 +\n>  2 files changed, 10 insertions(+)\n>\n> diff --git a/pathspec.c b/pathspec.c\n> index b2446c3..2da8bc9 100644\n> --- a/pathspec.c\n> +++ b/pathspec.c\n> @@ -204,6 +204,15 @@ static unsigned prefix_pathspec(struct pathspec_item *item,\n>  \t*raw = item->match = match;\n>  \titem->original = elt;\n>  \titem->len = strlen(item->match);\n> +\n> +\tif ((flags & PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP) &&\n\nI see that having cheap and expensive variant at these steps is a\nway to achieve a bug-for-bug compatible rewrite of the existing\ncode, but in the longer term should we lose one of them?  After all,\na path that points at the working tree of another repository that is\nbeyond a symlink cannot be added to us as a submodule, so CHEAP can\nbe used only when we know that any intermediate component on the\npath is not a symlink pointing elsewhere, and the user in the\ncodepath of ls-files may know it.\n\nTo put it differently, shouldn't CHEAP and EXPENSIVE be accompanied\nby in-code comment and updates to Documentation/technical/api-*.txt\nto help users of the API to decide which one to use?\n"},{"id":"211531","messageId":"7vtxo9ptz1.fsf@alter.siamese.dyndns.org","threadId":"33187","inReplyTo":"1363327620-29017-15-git-send-email-pclouds@gmail.com","subject":"Re: [PATCH v1 14/45] Guard against new pathspec magic in pathspec matching code","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2013-03-17T22:00:34Z","receivedAt":"2013-03-17T22:00:34Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Nguyễn Thái Ngọc Duy  <pclouds@gmail.com> writes:\n\n> GUARD_PATHSPEC() marks pathspec-sensitive code (basically anything in\n> 'struct pathspec' except fields \"nr\" and \"original\"). GUARD_PATHSPEC()\n> is not supposed to fail. The steps for a new pathspec magic or\n> optimization would be:\n>\n>  - update parse_pathspec, add extra information to struct pathspec\n>\n>  - grep GUARD_PATHSPEC() and update all relevant code (or note those\n>    that won't work with your new stuff). Update GUARD_PATHSPEC mask\n>    accordingly.\n>\n>  - update parse_pathspec calls to disable new magic early at command\n>    parsing level. Make sure parse_pathspec() catches unsupported\n>    syntax, not until GUARD_PATHSPEC catches it.\n>\n>  - add tests to verify supported/unsupported commands both work as\n>    expected.\n\nI think Documentation/technical/api-*.txt wants to have all of the\nabove.  It is not clear from the description what the second bitmask\nis supposed to mean, without reading the implementation; I am guessing\nthat you are supposed to list the kinds of magic that are supported\nin the codepath?\n\n> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n> ---\n>  builtin/diff.c |  2 ++\n>  dir.c          |  2 ++\n>  pathspec.h     |  7 +++++++\n>  tree-diff.c    | 19 +++++++++++++++++++\n>  tree-walk.c    |  2 ++\n>  5 files changed, 32 insertions(+)\n>\n> diff --git a/builtin/diff.c b/builtin/diff.c\n> index 8c2af6c..d237e0a 100644\n> --- a/builtin/diff.c\n> +++ b/builtin/diff.c\n> @@ -371,6 +371,8 @@ int cmd_diff(int argc, const char **argv, const char *prefix)\n>  \t\tdie(_(\"unhandled object '%s' given.\"), name);\n>  \t}\n>  \tif (rev.prune_data.nr) {\n> +\t\t/* builtin_diff_b_f() */\n> +\t\tGUARD_PATHSPEC(&rev.prune_data, PATHSPEC_FROMTOP);\n>  \t\tif (!path)\n>  \t\t\tpath = rev.prune_data.items[0].match;\n>  \t\tpaths += rev.prune_data.nr;\n> diff --git a/dir.c b/dir.c\n> index 1e9db41..6094ba8 100644\n> --- a/dir.c\n> +++ b/dir.c\n> @@ -297,6 +297,8 @@ int match_pathspec_depth(const struct pathspec *ps,\n>  {\n>  \tint i, retval = 0;\n>  \n> +\tGUARD_PATHSPEC(ps, PATHSPEC_FROMTOP | PATHSPEC_MAXDEPTH);\n> +\n>  \tif (!ps->nr) {\n>  \t\tif (!ps->recursive ||\n>  \t\t    !(ps->magic & PATHSPEC_MAXDEPTH) ||\n> diff --git a/pathspec.h b/pathspec.h\n> index 1cef9c6..ed5d3a6 100644\n> --- a/pathspec.h\n> +++ b/pathspec.h\n> @@ -27,6 +27,13 @@ struct pathspec {\n>  \t} *items;\n>  };\n>  \n> +#define GUARD_PATHSPEC(ps, mask) \\\n> +\tdo { \\\n> +\t\tif ((ps)->magic & ~(mask))\t       \\\n> +\t\t\tdie(\"BUG:%s:%d: unsupported magic %x\",\t\\\n> +\t\t\t    __FILE__, __LINE__, (ps)->magic & ~(mask)); \\\n> +\t} while (0)\n> +\n>  /* parse_pathspec flags */\n>  #define PATHSPEC_PREFER_CWD (1<<0) /* No args means match cwd */\n>  #define PATHSPEC_PREFER_FULL (1<<1) /* No args means match everything */\n> diff --git a/tree-diff.c b/tree-diff.c\n> index 826512e..5a87614 100644\n> --- a/tree-diff.c\n> +++ b/tree-diff.c\n> @@ -198,6 +198,25 @@ static void try_to_follow_renames(struct tree_desc *t1, struct tree_desc *t2, co\n>  \tconst char *paths[1];\n>  \tint i;\n>  \n> +\t/*\n> +\t * follow-rename code is very specific, we need exactly one\n> +\t * path. Magic that matches more than one path is not\n> +\t * supported.\n> +\t */\n> +\tGUARD_PATHSPEC(&opt->pathspec, PATHSPEC_FROMTOP);\n> +#if 0\n> +\t/*\n> +\t * We should reject wildcards as well. Unfortunately we\n> +\t * haven't got a reliable way to detect that 'foo\\*bar' in\n> +\t * fact has no wildcards. nowildcard_len is merely a hint for\n> +\t * optimization. Let it slip for now until wildmatch is taught\n> +\t * about dry-run mode and returns wildcard info.\n> +\t */\n> +\tif (opt->pathspec.has_wildcard)\n> +\t\tdie(\"BUG:%s:%d: wildcards are not supported\",\n> +\t\t    __FILE__, __LINE__);\n> +#endif\n> +\n>  \t/* Remove the file creation entry from the diff queue, and remember it */\n>  \tchoice = q->queue[0];\n>  \tq->nr = 0;\n> diff --git a/tree-walk.c b/tree-walk.c\n> index d399ca9..37b157e 100644\n> --- a/tree-walk.c\n> +++ b/tree-walk.c\n> @@ -636,6 +636,8 @@ enum interesting tree_entry_interesting(const struct name_entry *entry,\n>  \tenum interesting never_interesting = ps->has_wildcard ?\n>  \t\tentry_not_interesting : all_entries_not_interesting;\n>  \n> +\tGUARD_PATHSPEC(ps, PATHSPEC_FROMTOP | PATHSPEC_MAXDEPTH);\n> +\n>  \tif (!ps->nr) {\n>  \t\tif (!ps->recursive ||\n>  \t\t    !(ps->magic & PATHSPEC_MAXDEPTH) ||\n"},{"id":"211540","messageId":"CACsJy8BzLtzLKut+2W6Uyf5ESaq+Ek8owe6-yHF7_3BNLowCPA@mail.gmail.com","threadId":"33187","inReplyTo":"7vy5dlpu7i.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH v1 11/45] parse_pathspec: support stripping submodule trailing slashes","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2013-03-18T00:53:51Z","receivedAt":"2013-03-18T00:53:51Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Mon, Mar 18, 2013 at 4:55 AM, Junio C Hamano <gitster@pobox.com> wrote:\n> Nguyễn Thái Ngọc Duy  <pclouds@gmail.com> writes:\n>\n>> This flag is equivalent to builtin/ls-files.c:strip_trailing_slashes()\n>> and is intended to replace that function when ls-files is converted to\n>> use parse_pathspec.\n>>\n>> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n>> ---\n>>  pathspec.c | 9 +++++++++\n>>  pathspec.h | 1 +\n>>  2 files changed, 10 insertions(+)\n>>\n>> diff --git a/pathspec.c b/pathspec.c\n>> index b2446c3..2da8bc9 100644\n>> --- a/pathspec.c\n>> +++ b/pathspec.c\n>> @@ -204,6 +204,15 @@ static unsigned prefix_pathspec(struct pathspec_item *item,\n>>       *raw = item->match = match;\n>>       item->original = elt;\n>>       item->len = strlen(item->match);\n>> +\n>> +     if ((flags & PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP) &&\n>\n> I see that having cheap and expensive variant at these steps is a\n> way to achieve a bug-for-bug compatible rewrite of the existing\n> code, but in the longer term should we lose one of them?  After all,\n> a path that points at the working tree of another repository that is\n> beyond a symlink cannot be added to us as a submodule, so CHEAP can\n> be used only when we know that any intermediate component on the\n> path is not a symlink pointing elsewhere, and the user in the\n> codepath of ls-files may know it.\n\nI did not concentrate on the future part. But yes only one should\nremain in long term. Cheap vs expensive does not say much.\n\n> To put it differently, shouldn't CHEAP and EXPENSIVE be accompanied\n> by in-code comment and updates to Documentation/technical/api-*.txt\n> to help users of the API to decide which one to use?\n\nWill do (also for the comment on 14/45)\n-- \nDuy\n"},{"id":"211589","messageId":"20130318182602.GA2164@serenity.lan","threadId":"33187","inReplyTo":"1363327620-29017-28-git-send-email-pclouds@gmail.com","subject":"Re: [PATCH v1 27/45] Convert run_add_interactive to use struct pathspec","fromName":"John Keeping","fromEmail":"john@keeping.me.uk","sentAt":"2013-03-18T18:26:03Z","receivedAt":"2013-03-18T18:26:03Z","isPatch":true,"sender":{"key":"john@keeping.me.uk","avatar":"https://avatars.githubusercontent.com/u/1702081?v=4"},"body":"On Fri, Mar 15, 2013 at 01:06:42PM +0700, Nguyễn Thái Ngọc Duy wrote:\n> This passes the pathspec, more or less unmodified, to\n> git-add--interactive. The command itself does not process pathspec. It\n> simply passes the pathspec to other builtin commands. So if all those\n> commands support pathspec, we're good.\n\nThis breaks \"git reset --keep\" in a subdirectory for me.\n\nI ran \"git reset --keep <branch>\" in a subdirectory and got:\n\n    fatal: BUG: parse_pathspec cannot take no argument in this case\n\nBisecting points to this commit.\n\nThe simplest test case is:\n\n    ( cd t && ../bin-wrappers/git reset --keep HEAD )\n\nwhich works on master but not pu.\n\n> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n> ---\n>  builtin/add.c      | 26 ++++++++++----------------\n>  builtin/checkout.c |  9 ++++-----\n>  builtin/reset.c    |  8 ++++----\n>  commit.h           |  2 +-\n>  4 files changed, 19 insertions(+), 26 deletions(-)\n> \n> diff --git a/builtin/add.c b/builtin/add.c\n> index ec6fbe3..2b20d7d 100644\n> --- a/builtin/add.c\n> +++ b/builtin/add.c\n> @@ -139,16 +139,12 @@ static void refresh(int verbose, const char **pathspec)\n>  }\n>  \n>  int run_add_interactive(const char *revision, const char *patch_mode,\n> -\t\t\tconst char **pathspec)\n> +\t\t\tconst struct pathspec *pathspec)\n>  {\n> -\tint status, ac, pc = 0;\n> +\tint status, ac, i;\n>  \tconst char **args;\n>  \n> -\tif (pathspec)\n> -\t\twhile (pathspec[pc])\n> -\t\t\tpc++;\n> -\n> -\targs = xcalloc(sizeof(const char *), (pc + 5));\n> +\targs = xcalloc(sizeof(const char *), (pathspec->nr + 6));\n>  \tac = 0;\n>  \targs[ac++] = \"add--interactive\";\n>  \tif (patch_mode)\n> @@ -156,11 +152,9 @@ int run_add_interactive(const char *revision, const char *patch_mode,\n>  \tif (revision)\n>  \t\targs[ac++] = revision;\n>  \targs[ac++] = \"--\";\n> -\tif (pc) {\n> -\t\tmemcpy(&(args[ac]), pathspec, sizeof(const char *) * pc);\n> -\t\tac += pc;\n> -\t}\n> -\targs[ac] = NULL;\n> +\tfor (i = 0; i < pathspec->nr; i++)\n> +\t\t/* pass original pathspec, to be re-parsed */\n> +\t\targs[ac++] = pathspec->items[i].original;\n>  \n>  \tstatus = run_command_v_opt(args, RUN_GIT_CMD);\n>  \tfree(args);\n> @@ -175,17 +169,17 @@ int interactive_add(int argc, const char **argv, const char *prefix, int patch)\n>  \t * git-add--interactive itself does not parse pathspec. It\n>  \t * simply passes the pathspec to other builtin commands. Let's\n>  \t * hope all of them support all magic, or we'll need to limit\n> -\t * the magic here. There is still a problem with prefix. But\n> -\t * that'll be worked on later on.\n> +\t * the magic here.\n>  \t */\n>  \tparse_pathspec(&pathspec, PATHSPEC_ALL_MAGIC & ~PATHSPEC_FROMTOP,\n>  \t\t       PATHSPEC_PREFER_FULL |\n> -\t\t       PATHSPEC_SYMLINK_LEADING_PATH,\n> +\t\t       PATHSPEC_SYMLINK_LEADING_PATH |\n> +\t\t       PATHSPEC_PREFIX_ORIGIN,\n>  \t\t       prefix, argv);\n>  \n>  \treturn run_add_interactive(NULL,\n>  \t\t\t\t   patch ? \"--patch\" : NULL,\n> -\t\t\t\t   pathspec.raw);\n> +\t\t\t\t   &pathspec);\n>  }\n>  \n>  static int edit_patch(int argc, const char **argv, const char *prefix)\n> diff --git a/builtin/checkout.c b/builtin/checkout.c\n> index 3c19cb4..2ddff95 100644\n> --- a/builtin/checkout.c\n> +++ b/builtin/checkout.c\n> @@ -256,7 +256,7 @@ static int checkout_paths(const struct checkout_opts *opts,\n>  \n>  \tif (opts->patch_mode)\n>  \t\treturn run_add_interactive(revision, \"--patch=checkout\",\n> -\t\t\t\t\t   opts->pathspec.raw);\n> +\t\t\t\t\t   &opts->pathspec);\n>  \n>  \tlock_file = xcalloc(1, sizeof(struct lock_file));\n>  \n> @@ -1115,10 +1115,9 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)\n>  \t\t * cannot handle. Magic mask is pretty safe to be\n>  \t\t * lifted for new magic when opts.patch_mode == 0.\n>  \t\t */\n> -\t\tparse_pathspec(&opts.pathspec,\n> -\t\t\t       opts.patch_mode == 0 ? 0 :\n> -\t\t\t       (PATHSPEC_ALL_MAGIC & ~PATHSPEC_FROMTOP),\n> -\t\t\t       0, prefix, argv);\n> +\t\tparse_pathspec(&opts.pathspec, 0,\n> +\t\t\t       opts.patch_mode ? PATHSPEC_PREFIX_ORIGIN : 0,\n> +\t\t\t       prefix, argv);\n>  \n>  \t\tif (!opts.pathspec.nr)\n>  \t\t\tdie(_(\"invalid path specification\"));\n> diff --git a/builtin/reset.c b/builtin/reset.c\n> index da7282e..7c6e8b6 100644\n> --- a/builtin/reset.c\n> +++ b/builtin/reset.c\n> @@ -216,9 +216,9 @@ static void parse_args(struct pathspec *pathspec,\n>  \t\t}\n>  \t}\n>  \t*rev_ret = rev;\n> -\tparse_pathspec(pathspec,\n> -\t\t       patch_mode ? PATHSPEC_ALL_MAGIC & ~PATHSPEC_FROMTOP : 0,\n> -\t\t       PATHSPEC_PREFER_FULL,\n> +\tparse_pathspec(pathspec, 0,\n> +\t\t       PATHSPEC_PREFER_FULL |\n> +\t\t       patch_mode ? PATHSPEC_PREFIX_ORIGIN : 0,\n>  \t\t       prefix, argv);\n>  }\n>  \n> @@ -296,7 +296,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix)\n>  \tif (patch_mode) {\n>  \t\tif (reset_type != NONE)\n>  \t\t\tdie(_(\"--patch is incompatible with --{hard,mixed,soft}\"));\n> -\t\treturn run_add_interactive(sha1_to_hex(sha1), \"--patch=reset\", pathspec.raw);\n> +\t\treturn run_add_interactive(sha1_to_hex(sha1), \"--patch=reset\", &pathspec);\n>  \t}\n>  \n>  \t/* git reset tree [--] paths... can be used to\n> diff --git a/commit.h b/commit.h\n> index 4138bb4..9448fda 100644\n> --- a/commit.h\n> +++ b/commit.h\n> @@ -179,7 +179,7 @@ int in_merge_bases(struct commit *, struct commit *);\n>  \n>  extern int interactive_add(int argc, const char **argv, const char *prefix, int patch);\n>  extern int run_add_interactive(const char *revision, const char *patch_mode,\n> -\t\t\t       const char **pathspec);\n> +\t\t\t       const struct pathspec *pathspec);\n>  \n>  static inline int single_parent(struct commit *commit)\n>  {\n> -- \n> 1.8.0.rc0.19.g7bbb31d\n"},{"id":"211625","messageId":"CACsJy8AMcfwx5UurNQs1-uJLw_Xt+PAHFU_Tjizf2zOsYECyvg@mail.gmail.com","threadId":"33187","inReplyTo":"20130318182602.GA2164@serenity.lan","subject":"Re: [PATCH v1 27/45] Convert run_add_interactive to use struct pathspec","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2013-03-19T01:58:23Z","receivedAt":"2013-03-19T01:58:23Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Tue, Mar 19, 2013 at 1:26 AM, John Keeping <john@keeping.me.uk> wrote:\n> On Fri, Mar 15, 2013 at 01:06:42PM +0700, Nguyễn Thái Ngọc Duy wrote:\n>> This passes the pathspec, more or less unmodified, to\n>> git-add--interactive. The command itself does not process pathspec. It\n>> simply passes the pathspec to other builtin commands. So if all those\n>> commands support pathspec, we're good.\n>\n> This breaks \"git reset --keep\" in a subdirectory for me.\n>\n> I ran \"git reset --keep <branch>\" in a subdirectory and got:\n>\n>     fatal: BUG: parse_pathspec cannot take no argument in this case\n>\n> Bisecting points to this commit.\n>\n> The simplest test case is:\n>\n>     ( cd t && ../bin-wrappers/git reset --keep HEAD )\n>\n> which works on master but not pu.\n\nBeautiful. I got messed up with C operator precedence. This should fix\nit. I'll check the rest of parse_pathspec calls later.\n\ndiff --git a/builtin/reset.c b/builtin/reset.c\nindex ab3917d..b665218 100644\n--- a/builtin/reset.c\n+++ b/builtin/reset.c\n@@ -219,7 +219,7 @@ static void parse_args(struct pathspec *pathspec,\n        *rev_ret = rev;\n        parse_pathspec(pathspec, 0,\n                       PATHSPEC_PREFER_FULL |\n-                      patch_mode ? PATHSPEC_PREFIX_ORIGIN : 0,\n+                      (patch_mode ? PATHSPEC_PREFIX_ORIGIN : 0),\n                       prefix, argv);\n }\n\n-- \nDuy\n"},{"id":"211657","messageId":"20130319105823.GB2283@serenity.lan","threadId":"33187","inReplyTo":"CACsJy8AMcfwx5UurNQs1-uJLw_Xt+PAHFU_Tjizf2zOsYECyvg@mail.gmail.com","subject":"Re: [PATCH v1 27/45] Convert run_add_interactive to use struct pathspec","fromName":"John Keeping","fromEmail":"john@keeping.me.uk","sentAt":"2013-03-19T10:58:23Z","receivedAt":"2013-03-19T10:58:23Z","isPatch":true,"sender":{"key":"john@keeping.me.uk","avatar":"https://avatars.githubusercontent.com/u/1702081?v=4"},"body":"On Tue, Mar 19, 2013 at 08:58:23AM +0700, Duy Nguyen wrote:\n> On Tue, Mar 19, 2013 at 1:26 AM, John Keeping <john@keeping.me.uk> wrote:\n> > On Fri, Mar 15, 2013 at 01:06:42PM +0700, Nguyễn Thái Ngọc Duy wrote:\n> >> This passes the pathspec, more or less unmodified, to\n> >> git-add--interactive. The command itself does not process pathspec. It\n> >> simply passes the pathspec to other builtin commands. So if all those\n> >> commands support pathspec, we're good.\n> >\n> > This breaks \"git reset --keep\" in a subdirectory for me.\n> >\n> > I ran \"git reset --keep <branch>\" in a subdirectory and got:\n> >\n> >     fatal: BUG: parse_pathspec cannot take no argument in this case\n> >\n> > Bisecting points to this commit.\n> >\n> > The simplest test case is:\n> >\n> >     ( cd t && ../bin-wrappers/git reset --keep HEAD )\n> >\n> > which works on master but not pu.\n> \n> Beautiful. I got messed up with C operator precedence. This should fix\n> it. I'll check the rest of parse_pathspec calls later.\n\nYes, this fixes it.  Thanks.\n\n> diff --git a/builtin/reset.c b/builtin/reset.c\n> index ab3917d..b665218 100644\n> --- a/builtin/reset.c\n> +++ b/builtin/reset.c\n> @@ -219,7 +219,7 @@ static void parse_args(struct pathspec *pathspec,\n>         *rev_ret = rev;\n>         parse_pathspec(pathspec, 0,\n>                        PATHSPEC_PREFER_FULL |\n> -                      patch_mode ? PATHSPEC_PREFIX_ORIGIN : 0,\n> +                      (patch_mode ? PATHSPEC_PREFIX_ORIGIN : 0),\n>                        prefix, argv);\n>  }\n> \n> -- \n> Duy\n"},{"id":"211700","messageId":"7vli9ji6gu.fsf@alter.siamese.dyndns.org","threadId":"33187","inReplyTo":"1363327620-29017-40-git-send-email-pclouds@gmail.com","subject":"Re: [PATCH v1 39/45] parse_pathspec: make sure the prefix part is wildcard-free","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2013-03-19T18:34:41Z","receivedAt":"2013-03-19T18:34:41Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"This seems to break t7300-clean.sh #8\n"},{"id":"211722","messageId":"CACsJy8DjrB45kDRiOs9b=VS5Z5=_sdh37Z3Q20sT6iDacLmM+Q@mail.gmail.com","threadId":"33187","inReplyTo":"7vli9ji6gu.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH v1 39/45] parse_pathspec: make sure the prefix part is wildcard-free","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2013-03-20T01:32:00Z","receivedAt":"2013-03-20T01:32:00Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Wed, Mar 20, 2013 at 1:34 AM, Junio C Hamano <gitster@pobox.com> wrote:\n> This seems to break t7300-clean.sh #8\n\nRepeatedly? I saw some t7300-clean.sh failures when running tests in\nparallel, but never been able to reproduce it alone.\n-- \nDuy\n"},{"id":"211731","messageId":"CACsJy8C_vDZPh9C2zFxnS+rz+YJdAPhk6F9wvt+=ge3j=t9txw@mail.gmail.com","threadId":"33187","inReplyTo":"CACsJy8DjrB45kDRiOs9b=VS5Z5=_sdh37Z3Q20sT6iDacLmM+Q@mail.gmail.com","subject":"Re: [PATCH v1 39/45] parse_pathspec: make sure the prefix part is wildcard-free","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2013-03-20T10:54:41Z","receivedAt":"2013-03-20T10:54:41Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Wed, Mar 20, 2013 at 8:32 AM, Duy Nguyen <pclouds@gmail.com> wrote:\n> On Wed, Mar 20, 2013 at 1:34 AM, Junio C Hamano <gitster@pobox.com> wrote:\n>> This seems to break t7300-clean.sh #8\n>\n> Repeatedly? I saw some t7300-clean.sh failures when running tests in\n> parallel, but never been able to reproduce it alone.\n\nNever mind. There is a codepath that does not initialize the new field\n\"prefix\" properly. Fixing it now..\n-- \nDuy\n"},{"id":"211735","messageId":"1363781779-14947-1-git-send-email-pclouds@gmail.com","threadId":"33187","inReplyTo":"1363327620-29017-1-git-send-email-pclouds@gmail.com","subject":"[PATCH v2 00/45] parse_pathspec and :(glob) magic","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2013-03-20T12:16:13Z","receivedAt":"2013-03-20T12:16:13Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Junio please pull the series from github [1]. I don't want to spam the\nlist with 45 patches again so I only send patches that are substantially\ndifferent from v1:\n\n - documentation for parse_pathspec\n - fix wrong operator precendence in git-reset\n - fix initialization that may lead to crashes in git-grep (and\n   probably the failure in t7300-clean.sh)\n\nTypos found by Eric are also fixed, just not sent here.\n\n[1] https://github.com/pclouds/git/commits/parse-pathspec\n\nNguyễn Thái Ngọc Duy (6):\n  Add parse_pathspec() that converts cmdline args to struct pathspec\n  parse_pathspec: support stripping submodule trailing slashes\n  parse_pathspec: support stripping/checking submodule paths\n  Guard against new pathspec magic in pathspec matching code\n  Convert run_add_interactive to use struct pathspec\n  parse_pathspec: make sure the prefix part is wildcard-free\n-- \n1.8.0.rc0.19.g7bbb31d\n"},{"id":"211736","messageId":"1363781779-14947-2-git-send-email-pclouds@gmail.com","threadId":"33187","inReplyTo":"1363781779-14947-1-git-send-email-pclouds@gmail.com","subject":"[PATCH v2 06/45] Add parse_pathspec() that converts cmdline args to struct pathspec","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2013-03-20T12:16:14Z","receivedAt":"2013-03-20T12:16:14Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Currently to fill a struct pathspec, we do:\n\n   const char **paths;\n   paths = get_pathspec(prefix, argv);\n   ...\n   init_pathspec(&pathspec, paths);\n\n\"paths\" can only carry bare strings, which loses information from\ncommand line arguments such as pathspec magic or the prefix part's\nlength for each argument.\n\nparse_pathspec() is introduced to combine the two calls into one. The\nplan is gradually replace all get_pathspec() and init_pathspec() with\nparse_pathspec(). get_pathspec() now becomes a thin wrapper of\nparse_pathspec().\n\nparse_pathspec() allows the caller to reject the pathspec magics that\nit does not support. When a new pathspec magic is introduced, we can\nenable it per command after making sure that all underlying code has no\nproblem with the new magic.\n\n\"flags\" parameter is currently unused. But it would allow callers to\npass certain instructions to parse_pathspec, for example forcing\nliteral pathspec when no magic is used.\n\nWith the introduction of parse_pathspec, there are now two functions\nthat can initialize struct pathspec: init_pathspec and\nparse_pathspec. Any semantic changes in struct pathspec must be\nreflected in both functions. init_pathspec() will be phased out in\nfavor of parse_pathspec().\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n Documentation/technical/api-setup.txt |  19 +++-\n dir.c                                 |   4 +-\n dir.h                                 |   2 +\n pathspec.c                            | 168 ++++++++++++++++++++++++++--------\n pathspec.h                            |  11 +++\n 5 files changed, 163 insertions(+), 41 deletions(-)\n\ndiff --git a/Documentation/technical/api-setup.txt b/Documentation/technical/api-setup.txt\nindex 4f63a04..59a947e 100644\n--- a/Documentation/technical/api-setup.txt\n+++ b/Documentation/technical/api-setup.txt\n@@ -8,6 +8,23 @@ Talk about\n * is_inside_git_dir()\n * is_inside_work_tree()\n * setup_work_tree()\n-* get_pathspec()\n \n (Dscho)\n+\n+Pathspec\n+========\n+\n+See glossary-context.txt for the syntax of pathspec. In memory, a\n+pathspec set is represented by \"struct pathspec\" and is prepared by\n+parse_pathspec(). This function takes several arguments:\n+\n+- magic_mask specifies what features that are NOT supported by the\n+  following code. If a user attempts to use such a feature,\n+  parse_pathspec() can reject it early.\n+\n+- flags specifies other things that the caller wants parse_pathspec to\n+  perform.\n+\n+- prefix and args come from cmd_* functions\n+\n+get_pathspec() is obsolete and should never be used in new code.\ndiff --git a/dir.c b/dir.c\nindex 97ad45b..a442467 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -338,7 +338,7 @@ int match_pathspec_depth(const struct pathspec *ps,\n /*\n  * Return the length of the \"simple\" part of a path match limiter.\n  */\n-static int simple_length(const char *match)\n+int simple_length(const char *match)\n {\n \tint len = -1;\n \n@@ -350,7 +350,7 @@ static int simple_length(const char *match)\n \t}\n }\n \n-static int no_wildcard(const char *string)\n+int no_wildcard(const char *string)\n {\n \treturn string[simple_length(string)] == '\\0';\n }\ndiff --git a/dir.h b/dir.h\nindex c3eb4b5..89427fd 100644\n--- a/dir.h\n+++ b/dir.h\n@@ -125,6 +125,8 @@ struct dir_struct {\n #define MATCHED_RECURSIVELY 1\n #define MATCHED_FNMATCH 2\n #define MATCHED_EXACTLY 3\n+extern int simple_length(const char *match);\n+extern int no_wildcard(const char *string);\n extern char *common_prefix(const char **pathspec);\n extern int match_pathspec(const char **pathspec, const char *name, int namelen, int prefix, char *seen);\n extern int match_pathspec_depth(const struct pathspec *pathspec,\ndiff --git a/pathspec.c b/pathspec.c\nindex ab53b8a..ebe9844 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -103,10 +103,6 @@ void die_if_path_beyond_symlink(const char *path, const char *prefix)\n /*\n  * Magic pathspec\n  *\n- * NEEDSWORK: These need to be moved to dir.h or even to a new\n- * pathspec.h when we restructure get_pathspec() users to use the\n- * \"struct pathspec\" interface.\n- *\n  * Possible future magic semantics include stuff like:\n  *\n  *\t{ PATHSPEC_NOGLOB, '!', \"noglob\" },\n@@ -115,7 +111,6 @@ void die_if_path_beyond_symlink(const char *path, const char *prefix)\n  *\t{ PATHSPEC_REGEXP, '\\0', \"regexp\" },\n  *\n  */\n-#define PATHSPEC_FROMTOP    (1<<0)\n \n static struct pathspec_magic {\n \tunsigned bit;\n@@ -127,7 +122,7 @@ static struct pathspec_magic {\n \n /*\n  * Take an element of a pathspec and check for magic signatures.\n- * Append the result to the prefix.\n+ * Append the result to the prefix. Return the magic bitmap.\n  *\n  * For now, we only parse the syntax and throw out anything other than\n  * \"top\" magic.\n@@ -138,10 +133,15 @@ static struct pathspec_magic {\n  * the prefix part must always match literally, and a single stupid\n  * string cannot express such a case.\n  */\n-static const char *prefix_pathspec(const char *prefix, int prefixlen, const char *elt)\n+static unsigned prefix_pathspec(struct pathspec_item *item,\n+\t\t\t\tunsigned *p_short_magic,\n+\t\t\t\tconst char **raw, unsigned flags,\n+\t\t\t\tconst char *prefix, int prefixlen,\n+\t\t\t\tconst char *elt)\n {\n-\tunsigned magic = 0;\n+\tunsigned magic = 0, short_magic = 0;\n \tconst char *copyfrom = elt;\n+\tchar *match;\n \tint i;\n \n \tif (elt[0] != ':') {\n@@ -183,7 +183,7 @@ static const char *prefix_pathspec(const char *prefix, int prefixlen, const char\n \t\t\t\tbreak;\n \t\t\tfor (i = 0; i < ARRAY_SIZE(pathspec_magic); i++)\n \t\t\t\tif (pathspec_magic[i].mnemonic == ch) {\n-\t\t\t\t\tmagic |= pathspec_magic[i].bit;\n+\t\t\t\t\tshort_magic |= pathspec_magic[i].bit;\n \t\t\t\t\tbreak;\n \t\t\t\t}\n \t\t\tif (ARRAY_SIZE(pathspec_magic) <= i)\n@@ -194,15 +194,128 @@ static const char *prefix_pathspec(const char *prefix, int prefixlen, const char\n \t\t\tcopyfrom++;\n \t}\n \n+\tmagic |= short_magic;\n+\t*p_short_magic = short_magic;\n+\n \tif (magic & PATHSPEC_FROMTOP)\n-\t\treturn xstrdup(copyfrom);\n+\t\tmatch = xstrdup(copyfrom);\n \telse\n-\t\treturn prefix_path(prefix, prefixlen, copyfrom);\n+\t\tmatch = prefix_path(prefix, prefixlen, copyfrom);\n+\t*raw = item->match = match;\n+\titem->len = strlen(item->match);\n+\tif (limit_pathspec_to_literal())\n+\t\titem->nowildcard_len = item->len;\n+\telse\n+\t\titem->nowildcard_len = simple_length(item->match);\n+\titem->flags = 0;\n+\tif (item->nowildcard_len < item->len &&\n+\t    item->match[item->nowildcard_len] == '*' &&\n+\t    no_wildcard(item->match + item->nowildcard_len + 1))\n+\t\titem->flags |= PATHSPEC_ONESTAR;\n+\treturn magic;\n+}\n+\n+static int pathspec_item_cmp(const void *a_, const void *b_)\n+{\n+\tstruct pathspec_item *a, *b;\n+\n+\ta = (struct pathspec_item *)a_;\n+\tb = (struct pathspec_item *)b_;\n+\treturn strcmp(a->match, b->match);\n+}\n+\n+static void NORETURN unsupported_magic(const char *pattern,\n+\t\t\t\t       unsigned magic,\n+\t\t\t\t       unsigned short_magic)\n+{\n+\tstruct strbuf sb = STRBUF_INIT;\n+\tint i, n;\n+\tfor (n = i = 0; i < ARRAY_SIZE(pathspec_magic); i++) {\n+\t\tconst struct pathspec_magic *m = pathspec_magic + i;\n+\t\tif (!(magic & m->bit))\n+\t\t\tcontinue;\n+\t\tif (sb.len)\n+\t\t\tstrbuf_addstr(&sb, \" \");\n+\t\tif (short_magic & m->bit)\n+\t\t\tstrbuf_addf(&sb, \"'%c'\", m->mnemonic);\n+\t\telse\n+\t\t\tstrbuf_addf(&sb, \"'%s'\", m->name);\n+\t\tn++;\n+\t}\n+\t/*\n+\t * We may want to substitue \"this command\" with a command\n+\t * name. E.g. when add--interactive dies when running\n+\t * \"checkout -p\"\n+\t */\n+\tdie(_(\"%s: pathspec magic not supported by this command: %s\"),\n+\t    pattern, sb.buf);\n+}\n+\n+/*\n+ * Given command line arguments and a prefix, convert the input to\n+ * pathspec. die() any magic in magic_mask is used.\n+ */\n+void parse_pathspec(struct pathspec *pathspec,\n+\t\t    unsigned magic_mask, unsigned flags,\n+\t\t    const char *prefix, const char **argv)\n+{\n+\tstruct pathspec_item *item;\n+\tconst char *entry = argv ? *argv : NULL;\n+\tint i, n, prefixlen;\n+\n+\tmemset(pathspec, 0, sizeof(*pathspec));\n+\n+\t/* No arguments, no prefix -> no pathspec */\n+\tif (!entry && !prefix)\n+\t\treturn;\n+\n+\t/* No arguments with prefix -> prefix pathspec */\n+\tif (!entry) {\n+\t\tstatic const char *raw[2];\n+\n+\t\tpathspec->items = item = xmalloc(sizeof(*item));\n+\t\tmemset(item, 0, sizeof(*item));\n+\t\titem->match = prefix;\n+\t\titem->nowildcard_len = item->len = strlen(prefix);\n+\t\traw[0] = prefix;\n+\t\traw[1] = NULL;\n+\t\tpathspec->nr = 1;\n+\t\tpathspec->raw = raw;\n+\t\treturn;\n+\t}\n+\n+\tn = 0;\n+\twhile (argv[n])\n+\t\tn++;\n+\n+\tpathspec->nr = n;\n+\tpathspec->items = item = xmalloc(sizeof(*item) * n);\n+\tpathspec->raw = argv;\n+\tprefixlen = prefix ? strlen(prefix) : 0;\n+\n+\tfor (i = 0; i < n; i++) {\n+\t\tunsigned short_magic;\n+\t\tentry = argv[i];\n+\n+\t\titem[i].magic = prefix_pathspec(item + i, &short_magic,\n+\t\t\t\t\t\targv + i, flags,\n+\t\t\t\t\t\tprefix, prefixlen, entry);\n+\t\tif (item[i].magic & magic_mask)\n+\t\t\tunsupported_magic(entry,\n+\t\t\t\t\t  item[i].magic & magic_mask,\n+\t\t\t\t\t  short_magic);\n+\t\tif (item[i].nowildcard_len < item[i].len)\n+\t\t\tpathspec->has_wildcard = 1;\n+\t\tpathspec->magic |= item[i].magic;\n+\t}\n+\n+\tqsort(pathspec->items, pathspec->nr,\n+\t      sizeof(struct pathspec_item), pathspec_item_cmp);\n }\n \n /*\n  * N.B. get_pathspec() is deprecated in favor of the \"struct pathspec\"\n- * based interface - see pathspec_magic above.\n+ * based interface - see pathspec.c:parse_pathspec().\n  *\n  * Arguments:\n  *  - prefix - a path relative to the root of the working tree\n@@ -221,32 +334,11 @@ static const char *prefix_pathspec(const char *prefix, int prefixlen, const char\n  */\n const char **get_pathspec(const char *prefix, const char **pathspec)\n {\n-\tconst char *entry = *pathspec;\n-\tconst char **src, **dst;\n-\tint prefixlen;\n-\n-\tif (!prefix && !entry)\n-\t\treturn NULL;\n-\n-\tif (!entry) {\n-\t\tstatic const char *spec[2];\n-\t\tspec[0] = prefix;\n-\t\tspec[1] = NULL;\n-\t\treturn spec;\n-\t}\n-\n-\t/* Otherwise we have to re-write the entries.. */\n-\tsrc = pathspec;\n-\tdst = pathspec;\n-\tprefixlen = prefix ? strlen(prefix) : 0;\n-\twhile (*src) {\n-\t\t*(dst++) = prefix_pathspec(prefix, prefixlen, *src);\n-\t\tsrc++;\n-\t}\n-\t*dst = NULL;\n-\tif (!*pathspec)\n-\t\treturn NULL;\n-\treturn pathspec;\n+\tstruct pathspec ps;\n+\tparse_pathspec(&ps,\n+\t\t       PATHSPEC_ALL_MAGIC & ~PATHSPEC_FROMTOP,\n+\t\t       0, prefix, pathspec);\n+\treturn ps.raw;\n }\n \n void copy_pathspec(struct pathspec *dst, const struct pathspec *src)\ndiff --git a/pathspec.h b/pathspec.h\nindex a621676..937ec91 100644\n--- a/pathspec.h\n+++ b/pathspec.h\n@@ -1,6 +1,10 @@\n #ifndef PATHSPEC_H\n #define PATHSPEC_H\n \n+/* Pathspec magic */\n+#define PATHSPEC_FROMTOP\t(1<<0)\n+#define PATHSPEC_ALL_MAGIC PATHSPEC_FROMTOP\n+\n #define PATHSPEC_ONESTAR 1\t/* the pathspec pattern sastisfies GFNM_ONESTAR */\n \n struct pathspec {\n@@ -8,9 +12,11 @@ struct pathspec {\n \tint nr;\n \tunsigned int has_wildcard:1;\n \tunsigned int recursive:1;\n+\tunsigned magic;\n \tint max_depth;\n \tstruct pathspec_item {\n \t\tconst char *match;\n+\t\tunsigned magic;\n \t\tint len;\n \t\tint nowildcard_len;\n \t\tint flags;\n@@ -18,6 +24,11 @@ struct pathspec {\n };\n \n extern int init_pathspec(struct pathspec *, const char **);\n+extern void parse_pathspec(struct pathspec *pathspec,\n+\t\t\t   unsigned magic_mask,\n+\t\t\t   unsigned flags,\n+\t\t\t   const char *prefix,\n+\t\t\t   const char **args);\n extern void copy_pathspec(struct pathspec *dst, const struct pathspec *src);\n extern void free_pathspec(struct pathspec *);\n \n-- \n1.8.0.rc0.19.g7bbb31d\n"},{"id":"211737","messageId":"1363781779-14947-3-git-send-email-pclouds@gmail.com","threadId":"33187","inReplyTo":"1363781779-14947-1-git-send-email-pclouds@gmail.com","subject":"[PATCH v2 11/45] parse_pathspec: support stripping submodule trailing slashes","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2013-03-20T12:16:15Z","receivedAt":"2013-03-20T12:16:15Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"This flag is equivalent to builtin/ls-files.c:strip_trailing_slashes()\nand is intended to replace that function when ls-files is converted to\nuse parse_pathspec.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n pathspec.c | 9 +++++++++\n pathspec.h | 2 ++\n 2 files changed, 11 insertions(+)\n\ndiff --git a/pathspec.c b/pathspec.c\nindex fb5443c..57ad9ba 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -204,6 +204,15 @@ static unsigned prefix_pathspec(struct pathspec_item *item,\n \t*raw = item->match = match;\n \titem->original = elt;\n \titem->len = strlen(item->match);\n+\n+\tif ((flags & PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP) &&\n+\t    (item->len >= 1 && item->match[item->len - 1] == '/') &&\n+\t    (i = cache_name_pos(item->match, item->len - 1)) >= 0 &&\n+\t    S_ISGITLINK(active_cache[i]->ce_mode)) {\n+\t\titem->len--;\n+\t\tmatch[item->len] = '\\0';\n+\t}\n+\n \tif (limit_pathspec_to_literal())\n \t\titem->nowildcard_len = item->len;\n \telse\ndiff --git a/pathspec.h b/pathspec.h\nindex aa98597..7935b26 100644\n--- a/pathspec.h\n+++ b/pathspec.h\n@@ -31,6 +31,8 @@ struct pathspec {\n #define PATHSPEC_PREFER_CWD (1<<0) /* No args means match cwd */\n #define PATHSPEC_PREFER_FULL (1<<1) /* No args means match everything */\n #define PATHSPEC_MAXDEPTH_VALID (1<<2) /* max_depth field is valid */\n+/* stripping the trailing slash if the given path is a gitlink */\n+#define PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP (1<<3)\n \n extern int init_pathspec(struct pathspec *, const char **);\n extern void parse_pathspec(struct pathspec *pathspec,\n-- \n1.8.0.rc0.19.g7bbb31d\n"},{"id":"211738","messageId":"1363781779-14947-4-git-send-email-pclouds@gmail.com","threadId":"33187","inReplyTo":"1363781779-14947-1-git-send-email-pclouds@gmail.com","subject":"[PATCH v2 12/45] parse_pathspec: support stripping/checking submodule paths","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2013-03-20T12:16:16Z","receivedAt":"2013-03-20T12:16:16Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"PATHSPEC_SYMLINK_LEADING_PATH and _STRIP_SUBMODULE_SLASH_EXPENSIVE are\nrespectively the alternate implementation of\npathspec.c:die_if_path_beyond_symlink() and\npathspec.c:check_path_for_gitlink(). They are intended to replace\nthose functions when builtin/add.c and builtin/check-ignore.c are\nconverted to use parse_pathspec.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n pathspec.c | 26 ++++++++++++++++++++++++++\n pathspec.h | 10 ++++++++++\n 2 files changed, 36 insertions(+)\n\ndiff --git a/pathspec.c b/pathspec.c\nindex 57ad9ba..40bf178 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -213,6 +213,26 @@ static unsigned prefix_pathspec(struct pathspec_item *item,\n \t\tmatch[item->len] = '\\0';\n \t}\n \n+\tif (flags & PATHSPEC_STRIP_SUBMODULE_SLASH_EXPENSIVE)\n+\t\tfor (i = 0; i < active_nr; i++) {\n+\t\t\tstruct cache_entry *ce = active_cache[i];\n+\t\t\tint ce_len = ce_namelen(ce);\n+\n+\t\t\tif (!S_ISGITLINK(ce->ce_mode))\n+\t\t\t\tcontinue;\n+\n+\t\t\tif (item->len <= ce_len || match[ce_len] != '/' ||\n+\t\t\t    memcmp(ce->name, match, ce_len))\n+\t\t\t\tcontinue;\n+\t\t\tif (item->len == ce_len + 1) {\n+\t\t\t\t/* strip trailing slash */\n+\t\t\t\titem->len--;\n+\t\t\t\tmatch[item->len] = '\\0';\n+\t\t\t} else\n+\t\t\t\tdie (_(\"Pathspec '%s' is in submodule '%.*s'\"),\n+\t\t\t\t     elt, ce_len, ce->name);\n+\t\t}\n+\n \tif (limit_pathspec_to_literal())\n \t\titem->nowildcard_len = item->len;\n \telse\n@@ -328,6 +348,12 @@ void parse_pathspec(struct pathspec *pathspec,\n \t\t\tunsupported_magic(entry,\n \t\t\t\t\t  item[i].magic & magic_mask,\n \t\t\t\t\t  short_magic);\n+\n+\t\tif ((flags & PATHSPEC_SYMLINK_LEADING_PATH) &&\n+\t\t    has_symlink_leading_path(item[i].match, item[i].len)) {\n+\t\t\tdie(_(\"pathspec '%s' is beyond a symbolic link\"), entry);\n+\t\t}\n+\n \t\tif (item[i].nowildcard_len < item[i].len)\n \t\t\tpathspec->has_wildcard = 1;\n \t\tpathspec->magic |= item[i].magic;\ndiff --git a/pathspec.h b/pathspec.h\nindex 7935b26..b631514 100644\n--- a/pathspec.h\n+++ b/pathspec.h\n@@ -33,6 +33,16 @@ struct pathspec {\n #define PATHSPEC_MAXDEPTH_VALID (1<<2) /* max_depth field is valid */\n /* stripping the trailing slash if the given path is a gitlink */\n #define PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP (1<<3)\n+/* die if a symlink is part of the given path's directory */\n+#define PATHSPEC_SYMLINK_LEADING_PATH (1<<4)\n+/*\n+ * This is like a combination of ..LEADING_PATH and .._SLASH_CHEAP\n+ * (but not the same): it strips the trailing slash if the given path\n+ * is a gitlink but also checks and dies if gitlink is part of the\n+ * leading path (i.e. the given path goes beyond a submodule). It's\n+ * safer than _SLASH_CHEAP and also more expensive.\n+ */\n+#define PATHSPEC_STRIP_SUBMODULE_SLASH_EXPENSIVE (1<<5)\n \n extern int init_pathspec(struct pathspec *, const char **);\n extern void parse_pathspec(struct pathspec *pathspec,\n-- \n1.8.0.rc0.19.g7bbb31d\n"},{"id":"211739","messageId":"1363781779-14947-5-git-send-email-pclouds@gmail.com","threadId":"33187","inReplyTo":"1363781779-14947-1-git-send-email-pclouds@gmail.com","subject":"[PATCH v2 14/45] Guard against new pathspec magic in pathspec matching code","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2013-03-20T12:16:17Z","receivedAt":"2013-03-20T12:16:17Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"GUARD_PATHSPEC() marks pathspec-sensitive code, basically all those\nthat touch anything in 'struct pathspec' except fields \"nr\" and\n\"original\". GUARD_PATHSPEC() is not supposed to fail. It's mainly to\nhelp the designers to catch unsupported codepaths.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n Documentation/technical/api-setup.txt | 19 +++++++++++++++++++\n builtin/diff.c                        |  2 ++\n dir.c                                 |  2 ++\n pathspec.h                            |  7 +++++++\n tree-diff.c                           | 19 +++++++++++++++++++\n tree-walk.c                           |  2 ++\n 6 files changed, 51 insertions(+)\n\ndiff --git a/Documentation/technical/api-setup.txt b/Documentation/technical/api-setup.txt\nindex 59a947e..f62528e 100644\n--- a/Documentation/technical/api-setup.txt\n+++ b/Documentation/technical/api-setup.txt\n@@ -28,3 +28,22 @@ parse_pathspec(). This function takes several arguments:\n - prefix and args come from cmd_* functions\n \n get_pathspec() is obsolete and should never be used in new code.\n+\n+parse_pathspec() helps catch unsupported features and reject it\n+politely. At a lower level, different pathspec-related functions may\n+not support the same set of features. Such pathspec-sensitive\n+functions are guarded with GUARD_PATHSPEC(), which will die in an\n+unfriendly way when an unsupported feature is requested.\n+\n+The command designers are supposed to make sure that GUARD_PATHSPEC()\n+never dies. They have to make sure all unsupported features are caught\n+by parse_pathspec(), not by GUARD_PATHSPEC. grepping GUARD_PATHSPEC()\n+should give the designers all pathspec-sensitive codepaths and what\n+features they support.\n+\n+A similar process is applied when a new pathspec magic is added. The\n+designer lifts the GUARD_PATHSPEC restriction in the functions that\n+support the new magic. At the same time (s)he has to make sure this\n+new feature will be caught at parse_pathspec() in commands that cannot\n+handle the new magic in some cases. grepping parse_pathspec() should\n+help.\ndiff --git a/builtin/diff.c b/builtin/diff.c\nindex 8c2af6c..d237e0a 100644\n--- a/builtin/diff.c\n+++ b/builtin/diff.c\n@@ -371,6 +371,8 @@ int cmd_diff(int argc, const char **argv, const char *prefix)\n \t\tdie(_(\"unhandled object '%s' given.\"), name);\n \t}\n \tif (rev.prune_data.nr) {\n+\t\t/* builtin_diff_b_f() */\n+\t\tGUARD_PATHSPEC(&rev.prune_data, PATHSPEC_FROMTOP);\n \t\tif (!path)\n \t\t\tpath = rev.prune_data.items[0].match;\n \t\tpaths += rev.prune_data.nr;\ndiff --git a/dir.c b/dir.c\nindex 1e9db41..6094ba8 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -297,6 +297,8 @@ int match_pathspec_depth(const struct pathspec *ps,\n {\n \tint i, retval = 0;\n \n+\tGUARD_PATHSPEC(ps, PATHSPEC_FROMTOP | PATHSPEC_MAXDEPTH);\n+\n \tif (!ps->nr) {\n \t\tif (!ps->recursive ||\n \t\t    !(ps->magic & PATHSPEC_MAXDEPTH) ||\ndiff --git a/pathspec.h b/pathspec.h\nindex 3ca6636..7068f7d 100644\n--- a/pathspec.h\n+++ b/pathspec.h\n@@ -27,6 +27,13 @@ struct pathspec {\n \t} *items;\n };\n \n+#define GUARD_PATHSPEC(ps, mask) \\\n+\tdo { \\\n+\t\tif ((ps)->magic & ~(mask))\t       \\\n+\t\t\tdie(\"BUG:%s:%d: unsupported magic %x\",\t\\\n+\t\t\t    __FILE__, __LINE__, (ps)->magic & ~(mask)); \\\n+\t} while (0)\n+\n /* parse_pathspec flags */\n #define PATHSPEC_PREFER_CWD (1<<0) /* No args means match cwd */\n #define PATHSPEC_PREFER_FULL (1<<1) /* No args means match everything */\ndiff --git a/tree-diff.c b/tree-diff.c\nindex 826512e..5a87614 100644\n--- a/tree-diff.c\n+++ b/tree-diff.c\n@@ -198,6 +198,25 @@ static void try_to_follow_renames(struct tree_desc *t1, struct tree_desc *t2, co\n \tconst char *paths[1];\n \tint i;\n \n+\t/*\n+\t * follow-rename code is very specific, we need exactly one\n+\t * path. Magic that matches more than one path is not\n+\t * supported.\n+\t */\n+\tGUARD_PATHSPEC(&opt->pathspec, PATHSPEC_FROMTOP);\n+#if 0\n+\t/*\n+\t * We should reject wildcards as well. Unfortunately we\n+\t * haven't got a reliable way to detect that 'foo\\*bar' in\n+\t * fact has no wildcards. nowildcard_len is merely a hint for\n+\t * optimization. Let it slip for now until wildmatch is taught\n+\t * about dry-run mode and returns wildcard info.\n+\t */\n+\tif (opt->pathspec.has_wildcard)\n+\t\tdie(\"BUG:%s:%d: wildcards are not supported\",\n+\t\t    __FILE__, __LINE__);\n+#endif\n+\n \t/* Remove the file creation entry from the diff queue, and remember it */\n \tchoice = q->queue[0];\n \tq->nr = 0;\ndiff --git a/tree-walk.c b/tree-walk.c\nindex d399ca9..37b157e 100644\n--- a/tree-walk.c\n+++ b/tree-walk.c\n@@ -636,6 +636,8 @@ enum interesting tree_entry_interesting(const struct name_entry *entry,\n \tenum interesting never_interesting = ps->has_wildcard ?\n \t\tentry_not_interesting : all_entries_not_interesting;\n \n+\tGUARD_PATHSPEC(ps, PATHSPEC_FROMTOP | PATHSPEC_MAXDEPTH);\n+\n \tif (!ps->nr) {\n \t\tif (!ps->recursive ||\n \t\t    !(ps->magic & PATHSPEC_MAXDEPTH) ||\n-- \n1.8.0.rc0.19.g7bbb31d\n"},{"id":"211740","messageId":"1363781779-14947-6-git-send-email-pclouds@gmail.com","threadId":"33187","inReplyTo":"1363781779-14947-1-git-send-email-pclouds@gmail.com","subject":"[PATCH v2 27/45] Convert run_add_interactive to use struct pathspec","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2013-03-20T12:16:18Z","receivedAt":"2013-03-20T12:16:18Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"This passes the pathspec, more or less unmodified, to\ngit-add--interactive. The command itself does not process pathspec. It\nsimply passes the pathspec to other builtin commands. So if all those\ncommands support pathspec, we're good.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n builtin/add.c      | 26 ++++++++++----------------\n builtin/checkout.c |  9 ++++-----\n builtin/reset.c    |  8 ++++----\n commit.h           |  2 +-\n 4 files changed, 19 insertions(+), 26 deletions(-)\n\ndiff --git a/builtin/add.c b/builtin/add.c\nindex ec6fbe3..2b20d7d 100644\n--- a/builtin/add.c\n+++ b/builtin/add.c\n@@ -139,16 +139,12 @@ static void refresh(int verbose, const char **pathspec)\n }\n \n int run_add_interactive(const char *revision, const char *patch_mode,\n-\t\t\tconst char **pathspec)\n+\t\t\tconst struct pathspec *pathspec)\n {\n-\tint status, ac, pc = 0;\n+\tint status, ac, i;\n \tconst char **args;\n \n-\tif (pathspec)\n-\t\twhile (pathspec[pc])\n-\t\t\tpc++;\n-\n-\targs = xcalloc(sizeof(const char *), (pc + 5));\n+\targs = xcalloc(sizeof(const char *), (pathspec->nr + 6));\n \tac = 0;\n \targs[ac++] = \"add--interactive\";\n \tif (patch_mode)\n@@ -156,11 +152,9 @@ int run_add_interactive(const char *revision, const char *patch_mode,\n \tif (revision)\n \t\targs[ac++] = revision;\n \targs[ac++] = \"--\";\n-\tif (pc) {\n-\t\tmemcpy(&(args[ac]), pathspec, sizeof(const char *) * pc);\n-\t\tac += pc;\n-\t}\n-\targs[ac] = NULL;\n+\tfor (i = 0; i < pathspec->nr; i++)\n+\t\t/* pass original pathspec, to be re-parsed */\n+\t\targs[ac++] = pathspec->items[i].original;\n \n \tstatus = run_command_v_opt(args, RUN_GIT_CMD);\n \tfree(args);\n@@ -175,17 +169,17 @@ int interactive_add(int argc, const char **argv, const char *prefix, int patch)\n \t * git-add--interactive itself does not parse pathspec. It\n \t * simply passes the pathspec to other builtin commands. Let's\n \t * hope all of them support all magic, or we'll need to limit\n-\t * the magic here. There is still a problem with prefix. But\n-\t * that'll be worked on later on.\n+\t * the magic here.\n \t */\n \tparse_pathspec(&pathspec, PATHSPEC_ALL_MAGIC & ~PATHSPEC_FROMTOP,\n \t\t       PATHSPEC_PREFER_FULL |\n-\t\t       PATHSPEC_SYMLINK_LEADING_PATH,\n+\t\t       PATHSPEC_SYMLINK_LEADING_PATH |\n+\t\t       PATHSPEC_PREFIX_ORIGIN,\n \t\t       prefix, argv);\n \n \treturn run_add_interactive(NULL,\n \t\t\t\t   patch ? \"--patch\" : NULL,\n-\t\t\t\t   pathspec.raw);\n+\t\t\t\t   &pathspec);\n }\n \n static int edit_patch(int argc, const char **argv, const char *prefix)\ndiff --git a/builtin/checkout.c b/builtin/checkout.c\nindex 3c19cb4..2ddff95 100644\n--- a/builtin/checkout.c\n+++ b/builtin/checkout.c\n@@ -256,7 +256,7 @@ static int checkout_paths(const struct checkout_opts *opts,\n \n \tif (opts->patch_mode)\n \t\treturn run_add_interactive(revision, \"--patch=checkout\",\n-\t\t\t\t\t   opts->pathspec.raw);\n+\t\t\t\t\t   &opts->pathspec);\n \n \tlock_file = xcalloc(1, sizeof(struct lock_file));\n \n@@ -1115,10 +1115,9 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)\n \t\t * cannot handle. Magic mask is pretty safe to be\n \t\t * lifted for new magic when opts.patch_mode == 0.\n \t\t */\n-\t\tparse_pathspec(&opts.pathspec,\n-\t\t\t       opts.patch_mode == 0 ? 0 :\n-\t\t\t       (PATHSPEC_ALL_MAGIC & ~PATHSPEC_FROMTOP),\n-\t\t\t       0, prefix, argv);\n+\t\tparse_pathspec(&opts.pathspec, 0,\n+\t\t\t       opts.patch_mode ? PATHSPEC_PREFIX_ORIGIN : 0,\n+\t\t\t       prefix, argv);\n \n \t\tif (!opts.pathspec.nr)\n \t\t\tdie(_(\"invalid path specification\"));\ndiff --git a/builtin/reset.c b/builtin/reset.c\nindex da7282e..1c8e4a5 100644\n--- a/builtin/reset.c\n+++ b/builtin/reset.c\n@@ -216,9 +216,9 @@ static void parse_args(struct pathspec *pathspec,\n \t\t}\n \t}\n \t*rev_ret = rev;\n-\tparse_pathspec(pathspec,\n-\t\t       patch_mode ? PATHSPEC_ALL_MAGIC & ~PATHSPEC_FROMTOP : 0,\n-\t\t       PATHSPEC_PREFER_FULL,\n+\tparse_pathspec(pathspec, 0,\n+\t\t       PATHSPEC_PREFER_FULL |\n+\t\t       (patch_mode ? PATHSPEC_PREFIX_ORIGIN : 0),\n \t\t       prefix, argv);\n }\n \n@@ -296,7 +296,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix)\n \tif (patch_mode) {\n \t\tif (reset_type != NONE)\n \t\t\tdie(_(\"--patch is incompatible with --{hard,mixed,soft}\"));\n-\t\treturn run_add_interactive(sha1_to_hex(sha1), \"--patch=reset\", pathspec.raw);\n+\t\treturn run_add_interactive(sha1_to_hex(sha1), \"--patch=reset\", &pathspec);\n \t}\n \n \t/* git reset tree [--] paths... can be used to\ndiff --git a/commit.h b/commit.h\nindex 4138bb4..9448fda 100644\n--- a/commit.h\n+++ b/commit.h\n@@ -179,7 +179,7 @@ int in_merge_bases(struct commit *, struct commit *);\n \n extern int interactive_add(int argc, const char **argv, const char *prefix, int patch);\n extern int run_add_interactive(const char *revision, const char *patch_mode,\n-\t\t\t       const char **pathspec);\n+\t\t\t       const struct pathspec *pathspec);\n \n static inline int single_parent(struct commit *commit)\n {\n-- \n1.8.0.rc0.19.g7bbb31d\n"},{"id":"211741","messageId":"1363781779-14947-7-git-send-email-pclouds@gmail.com","threadId":"33187","inReplyTo":"1363781779-14947-1-git-send-email-pclouds@gmail.com","subject":"[PATCH v2 39/45] parse_pathspec: make sure the prefix part is wildcard-free","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2013-03-20T12:16:19Z","receivedAt":"2013-03-20T12:16:19Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Prepending prefix to pathspec is a trick to workaround the fact that\ncommands can be executed in a subdirectory, but all git commands run\nat worktree's root. The prefix part should always be treated as\nliteral string. Make it so.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n cache.h    |  2 ++\n path.c     | 15 ++++++++++++++-\n pathspec.c | 17 +++++++++++++----\n pathspec.h |  2 +-\n setup.c    |  9 +++++----\n 5 files changed, 35 insertions(+), 10 deletions(-)\n\ndiff --git a/cache.h b/cache.h\nindex 6297783..17e0b26 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -401,6 +401,7 @@ extern void setup_work_tree(void);\n extern const char *setup_git_directory_gently(int *);\n extern const char *setup_git_directory(void);\n extern char *prefix_path(const char *prefix, int len, const char *path);\n+extern char *prefix_path_gently(const char *prefix, int *p_len, const char *path);\n extern const char *prefix_filename(const char *prefix, int len, const char *path);\n extern int check_filename(const char *prefix, const char *name);\n extern void verify_filename(const char *prefix,\n@@ -712,6 +713,7 @@ const char *real_path(const char *path);\n const char *real_path_if_valid(const char *path);\n const char *absolute_path(const char *path);\n const char *relative_path(const char *abs, const char *base);\n+int normalize_path_copy_len(char *dst, const char *src, int *prefix_len);\n int normalize_path_copy(char *dst, const char *src);\n int longest_ancestor_length(const char *path, struct string_list *prefixes);\n char *strip_path_suffix(const char *path, const char *suffix);\ndiff --git a/path.c b/path.c\nindex d3d3f8b..7baf334 100644\n--- a/path.c\n+++ b/path.c\n@@ -487,8 +487,14 @@ const char *relative_path(const char *abs, const char *base)\n  *\n  * Note that this function is purely textual.  It does not follow symlinks,\n  * verify the existence of the path, or make any system calls.\n+ *\n+ * prefix_len != NULL is for a specific case of prefix_pathspec():\n+ * assume that src == dst and src[0..prefix_len-1] is already\n+ * normalized, any time \"../\" eats up to the prefix_len part,\n+ * prefix_len is reduced. In the end prefix_len is the remaining\n+ * prefix that has not been overridden by user pathspec.\n  */\n-int normalize_path_copy(char *dst, const char *src)\n+int normalize_path_copy_len(char *dst, const char *src, int *prefix_len)\n {\n \tchar *dst0;\n \n@@ -563,11 +569,18 @@ int normalize_path_copy(char *dst, const char *src)\n \t\t/* Windows: dst[-1] cannot be backslash anymore */\n \t\twhile (dst0 < dst && dst[-1] != '/')\n \t\t\tdst--;\n+\t\tif (prefix_len && *prefix_len > dst - dst0)\n+\t\t\t*prefix_len = dst - dst0;\n \t}\n \t*dst = '\\0';\n \treturn 0;\n }\n \n+int normalize_path_copy(char *dst, const char *src)\n+{\n+\treturn normalize_path_copy_len(dst, src, NULL);\n+}\n+\n /*\n  * path = Canonical absolute path\n  * prefixes = string_list containing normalized, absolute paths without\ndiff --git a/pathspec.c b/pathspec.c\nindex 9cd3f2c..01f8844 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -149,10 +149,14 @@ static unsigned prefix_pathspec(struct pathspec_item *item,\n \tmagic |= short_magic;\n \t*p_short_magic = short_magic;\n \n-\tif (magic & PATHSPEC_FROMTOP)\n+\tif (magic & PATHSPEC_FROMTOP) {\n \t\tmatch = xstrdup(copyfrom);\n-\telse\n-\t\tmatch = prefix_path(prefix, prefixlen, copyfrom);\n+\t\tprefixlen = 0;\n+\t} else {\n+\t\tmatch = prefix_path_gently(prefix, &prefixlen, copyfrom);\n+\t\tif (!match)\n+\t\t\tdie(\"%s: '%s' is outside repository\", elt, copyfrom);\n+\t}\n \t*raw = item->match = match;\n \t/*\n \t * Prefix the pathspec (keep all magic) and put to\n@@ -166,6 +170,7 @@ static unsigned prefix_pathspec(struct pathspec_item *item,\n \t} else\n \t\titem->original = elt;\n \titem->len = strlen(item->match);\n+\titem->prefix = prefixlen;\n \n \tif ((flags & PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP) &&\n \t    (item->len >= 1 && item->match[item->len - 1] == '/') &&\n@@ -197,8 +202,11 @@ static unsigned prefix_pathspec(struct pathspec_item *item,\n \n \tif (limit_pathspec_to_literal())\n \t\titem->nowildcard_len = item->len;\n-\telse\n+\telse {\n \t\titem->nowildcard_len = simple_length(item->match);\n+\t\tif (item->nowildcard_len < prefixlen)\n+\t\t\titem->nowildcard_len = prefixlen;\n+\t}\n \titem->flags = 0;\n \tif (item->nowildcard_len < item->len &&\n \t    item->match[item->nowildcard_len] == '*' &&\n@@ -283,6 +291,7 @@ void parse_pathspec(struct pathspec *pathspec,\n \t\titem->match = prefix;\n \t\titem->original = prefix;\n \t\titem->nowildcard_len = item->len = strlen(prefix);\n+\t\titem->prefix = item->len;\n \t\traw[0] = prefix;\n \t\traw[1] = NULL;\n \t\tpathspec->nr = 1;\ndiff --git a/pathspec.h b/pathspec.h\nindex 16bbb7b..bbcfa74 100644\n--- a/pathspec.h\n+++ b/pathspec.h\n@@ -21,7 +21,7 @@ struct pathspec {\n \t\tconst char *match;\n \t\tconst char *original;\n \t\tunsigned magic;\n-\t\tint len;\n+\t\tint len, prefix;\n \t\tint nowildcard_len;\n \t\tint flags;\n \t} *items;\ndiff --git a/setup.c b/setup.c\nindex acdc634..e661a71 100644\n--- a/setup.c\n+++ b/setup.c\n@@ -5,10 +5,11 @@\n static int inside_git_dir = -1;\n static int inside_work_tree = -1;\n \n-static char *prefix_path_gently(const char *prefix, int len, const char *path)\n+char *prefix_path_gently(const char *prefix, int *p_len, const char *path)\n {\n \tconst char *orig = path;\n \tchar *sanitized;\n+\tint len = *p_len;\n \tif (is_absolute_path(orig)) {\n \t\tconst char *temp = real_path(path);\n \t\tsanitized = xmalloc(len + strlen(temp) + 1);\n@@ -19,7 +20,7 @@ static char *prefix_path_gently(const char *prefix, int len, const char *path)\n \t\t\tmemcpy(sanitized, prefix, len);\n \t\tstrcpy(sanitized + len, path);\n \t}\n-\tif (normalize_path_copy(sanitized, sanitized))\n+\tif (normalize_path_copy_len(sanitized, sanitized, p_len))\n \t\tgoto error_out;\n \tif (is_absolute_path(orig)) {\n \t\tsize_t root_len, len, total;\n@@ -44,7 +45,7 @@ static char *prefix_path_gently(const char *prefix, int len, const char *path)\n \n char *prefix_path(const char *prefix, int len, const char *path)\n {\n-\tchar *r = prefix_path_gently(prefix, len, path);\n+\tchar *r = prefix_path_gently(prefix, &len, path);\n \tif (!r)\n \t\tdie(\"'%s' is outside repository\", path);\n \treturn r;\n@@ -53,7 +54,7 @@ char *prefix_path(const char *prefix, int len, const char *path)\n int path_inside_repo(const char *prefix, const char *path)\n {\n \tint len = prefix ? strlen(prefix) : 0;\n-\tchar *r = prefix_path_gently(prefix, len, path);\n+\tchar *r = prefix_path_gently(prefix, &len, path);\n \tif (r) {\n \t\tfree(r);\n \t\treturn 1;\n-- \n1.8.0.rc0.19.g7bbb31d\n"},{"id":"211778","messageId":"7v1ubaeyph.fsf@alter.siamese.dyndns.org","threadId":"33187","inReplyTo":"1363781779-14947-1-git-send-email-pclouds@gmail.com","subject":"Re: [PATCH v2 00/45] parse_pathspec and :(glob) magic","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2013-03-20T18:02:50Z","receivedAt":"2013-03-20T18:02:50Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Nguyễn Thái Ngọc Duy  <pclouds@gmail.com> writes:\n\n> Junio please pull the series from github [1]....\n> [1] https://github.com/pclouds/git/commits/parse-pathspec\n\nPlease write it like this:\n\n    https://github.com/pclouds/git parse-pathspec\n\nso that I can just say\n\n\tgit fetch <<that thing>>\n        git diff nd/magic-pathspecs FETCH_HEAD\n\nI am still getting this out of 7300, though.\n\nexpecting success: \n\n        mkdir -p build docs &&\n        touch a.out src/part3.c docs/manual.txt obj.o build/lib.so &&\n        would_clean=$(\n                cd docs &&\n                git clean -n \"$(pwd)/../src\" |\n                sed -n -e \"s|^Would remove ||p\"\n        ) &&\n        test \"$would_clean\" = ../src/part3.c || {\n                echo \"OOps <$would_clean>\"\n                false\n        }\n\nOOps <>\nnot ok 8 - git clean with absolute path\n#\n#\n#               mkdir -p build docs &&\n#               touch a.out src/part3.c docs/manual.txt obj.o build/lib.so &&\n#               would_clean=$(\n#                       cd docs &&\n#                       git clean -n \"$(pwd)/../src\" |\n#                       sed -n -e \"s|^Would remove ||p\"\n#               ) &&\n#               test \"$would_clean\" = ../src/part3.c || {\n#                       echo \"OOps <$would_clean>\"\n#                       false\n#               }\n#\n"},{"id":"211809","messageId":"CAPig+cSkxq=3dhgeYNKa9VjqMZkxrpLZEqKP63mAwjziz6m-LA@mail.gmail.com","threadId":"33187","inReplyTo":"1363781779-14947-2-git-send-email-pclouds@gmail.com","subject":"Re: [PATCH v2 06/45] Add parse_pathspec() that converts cmdline args to struct pathspec","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2013-03-20T19:40:41Z","receivedAt":"2013-03-20T19:40:41Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Wed, Mar 20, 2013 at 8:16 AM, Nguyễn Thái Ngọc Duy <pclouds@gmail.com> wrote:\n> +static void NORETURN unsupported_magic(const char *pattern,\n> +                                      unsigned magic,\n> +                                      unsigned short_magic)\n> +{\n> +       struct strbuf sb = STRBUF_INIT;\n> +       int i, n;\n> +       for (n = i = 0; i < ARRAY_SIZE(pathspec_magic); i++) {\n> +               const struct pathspec_magic *m = pathspec_magic + i;\n> +               if (!(magic & m->bit))\n> +                       continue;\n> +               if (sb.len)\n> +                       strbuf_addstr(&sb, \" \");\n> +               if (short_magic & m->bit)\n> +                       strbuf_addf(&sb, \"'%c'\", m->mnemonic);\n> +               else\n> +                       strbuf_addf(&sb, \"'%s'\", m->name);\n> +               n++;\n> +       }\n> +       /*\n> +        * We may want to substitue \"this command\" with a command\n\ns/substitue/substitute/\n\n> +        * name. E.g. when add--interactive dies when running\n> +        * \"checkout -p\"\n> +        */\n> +       die(_(\"%s: pathspec magic not supported by this command: %s\"),\n> +           pattern, sb.buf);\n> +}\n"},{"id":"211811","messageId":"CAPig+cT37VY7JaMxirQYs7R9V-7E=tur6+Veu+SyLLm-SFj8EQ@mail.gmail.com","threadId":"33187","inReplyTo":"1363781779-14947-5-git-send-email-pclouds@gmail.com","subject":"Re: [PATCH v2 14/45] Guard against new pathspec magic in pathspec matching code","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2013-03-20T19:45:32Z","receivedAt":"2013-03-20T19:45:32Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Wed, Mar 20, 2013 at 8:16 AM, Nguyễn Thái Ngọc Duy <pclouds@gmail.com> wrote:\n> diff --git a/Documentation/technical/api-setup.txt b/Documentation/technical/api-setup.txt\n> index 59a947e..f62528e 100644\n> --- a/Documentation/technical/api-setup.txt\n> +++ b/Documentation/technical/api-setup.txt\n> @@ -28,3 +28,22 @@ parse_pathspec(). This function takes several arguments:\n>  - prefix and args come from cmd_* functions\n>\n>  get_pathspec() is obsolete and should never be used in new code.\n> +\n> +parse_pathspec() helps catch unsupported features and reject it\n\ns/reject it/reject them/\n\n> +politely. At a lower level, different pathspec-related functions may\n> +not support the same set of features. Such pathspec-sensitive\n> +functions are guarded with GUARD_PATHSPEC(), which will die in an\n> +unfriendly way when an unsupported feature is requested.\n"},{"id":"211837","messageId":"20130321053326.GA17446@duynguyen-vnpc.dek-tpc.internal","threadId":"33187","inReplyTo":"7v1ubaeyph.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH v2 00/45] parse_pathspec and :(glob) magic","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2013-03-21T05:33:26Z","receivedAt":"2013-03-21T05:33:26Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Wed, Mar 20, 2013 at 11:02:50AM -0700, Junio C Hamano wrote:\n> Nguyễn Thái Ngọc Duy  <pclouds@gmail.com> writes:\n> \n> > Junio please pull the series from github [1]....\n> > [1] https://github.com/pclouds/git/commits/parse-pathspec\n> \n> Please write it like this:\n> \n>     https://github.com/pclouds/git parse-pathspec\n> \n> so that I can just say\n> \n> \tgit fetch <<that thing>>\n>         git diff nd/magic-pathspecs FETCH_HEAD\n\nOK\n\n> I am still getting this out of 7300, though.\n\nI still can't reproduce it. But I think I found a bug that\nmiscalculates prefix length from absolute paths. Does this \"fix\" your\ntest?\n\n-- 8< --\ndiff --git a/setup.c b/setup.c\nindex 3584f22..6ae147a 100644\n--- a/setup.c\n+++ b/setup.c\n@@ -14,6 +14,7 @@ char *prefix_path_gently(const char *prefix, int *p_len, const char *path)\n \t\tconst char *temp = real_path(path);\n \t\tsanitized = xmalloc(len + strlen(temp) + 1);\n \t\tstrcpy(sanitized, temp);\n+\t\t*p_len = 0;\n \t} else {\n \t\tsanitized = xmalloc(len + strlen(path) + 1);\n \t\tif (len)\n\n-- 8< --\n"},{"id":"211838","messageId":"20130321054349.GA18101@duynguyen-vnpc.dek-tpc.internal","threadId":"33187","inReplyTo":"20130321053326.GA17446@duynguyen-vnpc.dek-tpc.internal","subject":"Re: [PATCH v2 00/45] parse_pathspec and :(glob) magic","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2013-03-21T05:43:49Z","receivedAt":"2013-03-21T05:43:49Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Thu, Mar 21, 2013 at 12:33:26PM +0700, Duy Nguyen wrote:\n> > I am still getting this out of 7300, though.\n> \n> I still can't reproduce it. But I think I found a bug that\n> miscalculates prefix length from absolute paths. Does this \"fix\" your\n> test?\n> \n> -- 8< --\n> diff --git a/setup.c b/setup.c\n> index 3584f22..6ae147a 100644\n> --- a/setup.c\n> +++ b/setup.c\n> @@ -14,6 +14,7 @@ char *prefix_path_gently(const char *prefix, int *p_len, const char *path)\n>  \t\tconst char *temp = real_path(path);\n>  \t\tsanitized = xmalloc(len + strlen(temp) + 1);\n>  \t\tstrcpy(sanitized, temp);\n> +\t\t*p_len = 0;\n>  \t} else {\n>  \t\tsanitized = xmalloc(len + strlen(path) + 1);\n>  \t\tif (len)\n> \n> -- 8< --\n\nNope, that one could cause more crashes. Try this\n\n-- 8< --\ndiff --git a/setup.c b/setup.c\nindex 3584f22..3d8eb97 100644\n--- a/setup.c\n+++ b/setup.c\n@@ -14,6 +14,8 @@ char *prefix_path_gently(const char *prefix, int *p_len, const char *path)\n \t\tconst char *temp = real_path(path);\n \t\tsanitized = xmalloc(len + strlen(temp) + 1);\n \t\tstrcpy(sanitized, temp);\n+\t\tif (p_len)\n+\t\t\t*p_len = 0;\n \t} else {\n \t\tsanitized = xmalloc(len + strlen(path) + 1);\n \t\tif (len)\n-- 8< --\n"},{"id":"211883","messageId":"7v4ng4br1y.fsf@alter.siamese.dyndns.org","threadId":"33187","inReplyTo":"20130321054349.GA18101@duynguyen-vnpc.dek-tpc.internal","subject":"Re: [PATCH v2 00/45] parse_pathspec and :(glob) magic","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2013-03-21T17:28:41Z","receivedAt":"2013-03-21T17:28:41Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Duy Nguyen <pclouds@gmail.com> writes:\n\n>> I still can't reproduce it. But I think I found a bug that\n>> miscalculates prefix length from absolute paths. Does this \"fix\" your\n>> test?\n>>  ...\n> Nope, that one could cause more crashes. Try this\n>\n> -- 8< --\n> diff --git a/setup.c b/setup.c\n> index 3584f22..3d8eb97 100644\n> --- a/setup.c\n> +++ b/setup.c\n> @@ -14,6 +14,8 @@ char *prefix_path_gently(const char *prefix, int *p_len, const char *path)\n>  \t\tconst char *temp = real_path(path);\n>  \t\tsanitized = xmalloc(len + strlen(temp) + 1);\n>  \t\tstrcpy(sanitized, temp);\n> +\t\tif (p_len)\n> +\t\t\t*p_len = 0;\n\nYes, this one seems to. \"$(pwd)/../src\" was not handled correctly.\n\nThe callchain to this locaiton would look like\n\n\tparse_pathspec() with prefix=\"docs/\", prefixlen set to 5\n        -> prefix_pathspec(), &prefixlen passed down\n          -> prefix_path_gently(), p_len points at the above prefixlen\n\t     your \"this should fix\" patch sets *p_len to 0,\n             original leaves *p_len as 5.\n             -> normalize_path_copy_len() with p_len\n\t        *p_len is used here.\n\nWhy could the test pass for you without it?  It doesn't look like a\nbug that depended on uninitialized memory or something from the\nabove observation.\n"},{"id":"211885","messageId":"7vvc8kabhx.fsf@alter.siamese.dyndns.org","threadId":"33187","inReplyTo":"7v4ng4br1y.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH v2 00/45] parse_pathspec and :(glob) magic","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2013-03-21T17:50:02Z","receivedAt":"2013-03-21T17:50:02Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> Duy Nguyen <pclouds@gmail.com> writes:\n>\n>>> I still can't reproduce it. But I think I found a bug that\n>>> miscalculates prefix length from absolute paths. Does this \"fix\" your\n>>> test?\n>>>  ...\n>> Nope, that one could cause more crashes. Try this\n>>\n>> -- 8< --\n>> diff --git a/setup.c b/setup.c\n>> index 3584f22..3d8eb97 100644\n>> --- a/setup.c\n>> +++ b/setup.c\n>> @@ -14,6 +14,8 @@ char *prefix_path_gently(const char *prefix, int *p_len, const char *path)\n>>  \t\tconst char *temp = real_path(path);\n>>  \t\tsanitized = xmalloc(len + strlen(temp) + 1);\n>>  \t\tstrcpy(sanitized, temp);\n>> +\t\tif (p_len)\n>> +\t\t\t*p_len = 0;\n>\n> Yes, this one seems to. \"$(pwd)/../src\" was not handled correctly.\n>\n> The callchain to this locaiton would look like\n>\n> \tparse_pathspec() with prefix=\"docs/\", prefixlen set to 5\n>         -> prefix_pathspec(), &prefixlen passed down\n>           -> prefix_path_gently(), p_len points at the above prefixlen\n> \t     your \"this should fix\" patch sets *p_len to 0,\n>              original leaves *p_len as 5.\n>              -> normalize_path_copy_len() with p_len\n> \t        *p_len is used here.\n>\n> Why could the test pass for you without it?  It doesn't look like a\n> bug that depended on uninitialized memory or something from the\n> above observation.\n\nThe change made to prefix_path_gently() in this series is beyond\n\"disgusting\", especially with the above fix-up.\n\nSometimes it uses the original \"len\", sometimes it uses the fixed-up\n*p_len (e.g. passes it down to normalize_path_copy_len()), and lets\nnormalize_path_copy_len() further update it, and thenit makes the\ncaller use the updated *p_len.\n\nDoes the caller know what the value in *p_len _mean_ after this\nfunction returns?  Can it afford to lose the original length of the\nprefix it saved in a variable, without getting confused?\n\nI think any change that turns a value-passed argument in the\nexisting code into modifiable pointer-to-variable in this series\nshould add in-code comment to describe what the variable mean upon\nentry and after return, just like normalize_path_copy_len() that was\nbuilt out of the original normalize_path_copy().  I didn't look if\nthere are many others, or if this is the only one that is tricky. it\nis tricky that even the original author of the patch got it wrong\nX-<.\n"},{"id":"211991","messageId":"7vppyr5cb5.fsf@alter.siamese.dyndns.org","threadId":"33187","inReplyTo":"1363781779-14947-2-git-send-email-pclouds@gmail.com","subject":"Re: [PATCH v2 06/45] Add parse_pathspec() that converts cmdline args to struct pathspec","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2013-03-22T21:55:58Z","receivedAt":"2013-03-22T21:55:58Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Nguyễn Thái Ngọc Duy  <pclouds@gmail.com> writes:\n\n> diff --git a/Documentation/technical/api-setup.txt b/Documentation/technical/api-setup.txt\n> index 4f63a04..59a947e 100644\n> --- a/Documentation/technical/api-setup.txt\n> +++ b/Documentation/technical/api-setup.txt\n> @@ -8,6 +8,23 @@ Talk about\n>  * is_inside_git_dir()\n>  * is_inside_work_tree()\n>  * setup_work_tree()\n> -* get_pathspec()\n>  \n>  (Dscho)\n> +\n> +Pathspec\n> +========\n\nasciidoc: ERROR: api-setup.txt: line 15: only book doctypes can\ncontain level 0 sections\n\nJust demoting this to \"--------\" should be sufficient, I think.\n\n> +\n> +See glossary-context.txt for the syntax of pathspec. In memory, a\n> +pathspec set is represented by \"struct pathspec\" and is prepared by\n> +parse_pathspec(). This function takes several arguments:\n> +\n> +- magic_mask specifies what features that are NOT supported by the\n> +  following code. If a user attempts to use such a feature,\n> +  parse_pathspec() can reject it early.\n> +\n> +- flags specifies other things that the caller wants parse_pathspec to\n> +  perform.\n> +\n> +- prefix and args come from cmd_* functions\n> +\n> +get_pathspec() is obsolete and should never be used in new code.\n> diff --git a/dir.c b/dir.c\n> index 97ad45b..a442467 100644\n> --- a/dir.c\n> +++ b/dir.c\n> @@ -338,7 +338,7 @@ int match_pathspec_depth(const struct pathspec *ps,\n>  /*\n>   * Return the length of the \"simple\" part of a path match limiter.\n>   */\n> -static int simple_length(const char *match)\n> +int simple_length(const char *match)\n>  {\n>  \tint len = -1;\n>  \n> @@ -350,7 +350,7 @@ static int simple_length(const char *match)\n>  \t}\n>  }\n>  \n> -static int no_wildcard(const char *string)\n> +int no_wildcard(const char *string)\n>  {\n>  \treturn string[simple_length(string)] == '\\0';\n>  }\n> diff --git a/dir.h b/dir.h\n> index c3eb4b5..89427fd 100644\n> --- a/dir.h\n> +++ b/dir.h\n> @@ -125,6 +125,8 @@ struct dir_struct {\n>  #define MATCHED_RECURSIVELY 1\n>  #define MATCHED_FNMATCH 2\n>  #define MATCHED_EXACTLY 3\n> +extern int simple_length(const char *match);\n> +extern int no_wildcard(const char *string);\n>  extern char *common_prefix(const char **pathspec);\n>  extern int match_pathspec(const char **pathspec, const char *name, int namelen, int prefix, char *seen);\n>  extern int match_pathspec_depth(const struct pathspec *pathspec,\n> diff --git a/pathspec.c b/pathspec.c\n> index ab53b8a..ebe9844 100644\n> --- a/pathspec.c\n> +++ b/pathspec.c\n> @@ -103,10 +103,6 @@ void die_if_path_beyond_symlink(const char *path, const char *prefix)\n>  /*\n>   * Magic pathspec\n>   *\n> - * NEEDSWORK: These need to be moved to dir.h or even to a new\n> - * pathspec.h when we restructure get_pathspec() users to use the\n> - * \"struct pathspec\" interface.\n> - *\n>   * Possible future magic semantics include stuff like:\n>   *\n>   *\t{ PATHSPEC_NOGLOB, '!', \"noglob\" },\n> @@ -115,7 +111,6 @@ void die_if_path_beyond_symlink(const char *path, const char *prefix)\n>   *\t{ PATHSPEC_REGEXP, '\\0', \"regexp\" },\n>   *\n>   */\n> -#define PATHSPEC_FROMTOP    (1<<0)\n>  \n>  static struct pathspec_magic {\n>  \tunsigned bit;\n> @@ -127,7 +122,7 @@ static struct pathspec_magic {\n>  \n>  /*\n>   * Take an element of a pathspec and check for magic signatures.\n> - * Append the result to the prefix.\n> + * Append the result to the prefix. Return the magic bitmap.\n>   *\n>   * For now, we only parse the syntax and throw out anything other than\n>   * \"top\" magic.\n> @@ -138,10 +133,15 @@ static struct pathspec_magic {\n>   * the prefix part must always match literally, and a single stupid\n>   * string cannot express such a case.\n>   */\n> -static const char *prefix_pathspec(const char *prefix, int prefixlen, const char *elt)\n> +static unsigned prefix_pathspec(struct pathspec_item *item,\n> +\t\t\t\tunsigned *p_short_magic,\n> +\t\t\t\tconst char **raw, unsigned flags,\n> +\t\t\t\tconst char *prefix, int prefixlen,\n> +\t\t\t\tconst char *elt)\n>  {\n> -\tunsigned magic = 0;\n> +\tunsigned magic = 0, short_magic = 0;\n>  \tconst char *copyfrom = elt;\n> +\tchar *match;\n>  \tint i;\n>  \n>  \tif (elt[0] != ':') {\n> @@ -183,7 +183,7 @@ static const char *prefix_pathspec(const char *prefix, int prefixlen, const char\n>  \t\t\t\tbreak;\n>  \t\t\tfor (i = 0; i < ARRAY_SIZE(pathspec_magic); i++)\n>  \t\t\t\tif (pathspec_magic[i].mnemonic == ch) {\n> -\t\t\t\t\tmagic |= pathspec_magic[i].bit;\n> +\t\t\t\t\tshort_magic |= pathspec_magic[i].bit;\n>  \t\t\t\t\tbreak;\n>  \t\t\t\t}\n>  \t\t\tif (ARRAY_SIZE(pathspec_magic) <= i)\n> @@ -194,15 +194,128 @@ static const char *prefix_pathspec(const char *prefix, int prefixlen, const char\n>  \t\t\tcopyfrom++;\n>  \t}\n>  \n> +\tmagic |= short_magic;\n> +\t*p_short_magic = short_magic;\n> +\n>  \tif (magic & PATHSPEC_FROMTOP)\n> -\t\treturn xstrdup(copyfrom);\n> +\t\tmatch = xstrdup(copyfrom);\n>  \telse\n> -\t\treturn prefix_path(prefix, prefixlen, copyfrom);\n> +\t\tmatch = prefix_path(prefix, prefixlen, copyfrom);\n> +\t*raw = item->match = match;\n> +\titem->len = strlen(item->match);\n> +\tif (limit_pathspec_to_literal())\n> +\t\titem->nowildcard_len = item->len;\n> +\telse\n> +\t\titem->nowildcard_len = simple_length(item->match);\n> +\titem->flags = 0;\n> +\tif (item->nowildcard_len < item->len &&\n> +\t    item->match[item->nowildcard_len] == '*' &&\n> +\t    no_wildcard(item->match + item->nowildcard_len + 1))\n> +\t\titem->flags |= PATHSPEC_ONESTAR;\n> +\treturn magic;\n> +}\n> +\n> +static int pathspec_item_cmp(const void *a_, const void *b_)\n> +{\n> +\tstruct pathspec_item *a, *b;\n> +\n> +\ta = (struct pathspec_item *)a_;\n> +\tb = (struct pathspec_item *)b_;\n> +\treturn strcmp(a->match, b->match);\n> +}\n> +\n> +static void NORETURN unsupported_magic(const char *pattern,\n> +\t\t\t\t       unsigned magic,\n> +\t\t\t\t       unsigned short_magic)\n> +{\n> +\tstruct strbuf sb = STRBUF_INIT;\n> +\tint i, n;\n> +\tfor (n = i = 0; i < ARRAY_SIZE(pathspec_magic); i++) {\n> +\t\tconst struct pathspec_magic *m = pathspec_magic + i;\n> +\t\tif (!(magic & m->bit))\n> +\t\t\tcontinue;\n> +\t\tif (sb.len)\n> +\t\t\tstrbuf_addstr(&sb, \" \");\n> +\t\tif (short_magic & m->bit)\n> +\t\t\tstrbuf_addf(&sb, \"'%c'\", m->mnemonic);\n> +\t\telse\n> +\t\t\tstrbuf_addf(&sb, \"'%s'\", m->name);\n> +\t\tn++;\n> +\t}\n> +\t/*\n> +\t * We may want to substitue \"this command\" with a command\n> +\t * name. E.g. when add--interactive dies when running\n> +\t * \"checkout -p\"\n> +\t */\n> +\tdie(_(\"%s: pathspec magic not supported by this command: %s\"),\n> +\t    pattern, sb.buf);\n> +}\n> +\n> +/*\n> + * Given command line arguments and a prefix, convert the input to\n> + * pathspec. die() any magic in magic_mask is used.\n> + */\n> +void parse_pathspec(struct pathspec *pathspec,\n> +\t\t    unsigned magic_mask, unsigned flags,\n> +\t\t    const char *prefix, const char **argv)\n> +{\n> +\tstruct pathspec_item *item;\n> +\tconst char *entry = argv ? *argv : NULL;\n> +\tint i, n, prefixlen;\n> +\n> +\tmemset(pathspec, 0, sizeof(*pathspec));\n> +\n> +\t/* No arguments, no prefix -> no pathspec */\n> +\tif (!entry && !prefix)\n> +\t\treturn;\n> +\n> +\t/* No arguments with prefix -> prefix pathspec */\n> +\tif (!entry) {\n> +\t\tstatic const char *raw[2];\n> +\n> +\t\tpathspec->items = item = xmalloc(sizeof(*item));\n> +\t\tmemset(item, 0, sizeof(*item));\n> +\t\titem->match = prefix;\n> +\t\titem->nowildcard_len = item->len = strlen(prefix);\n> +\t\traw[0] = prefix;\n> +\t\traw[1] = NULL;\n> +\t\tpathspec->nr = 1;\n> +\t\tpathspec->raw = raw;\n> +\t\treturn;\n> +\t}\n> +\n> +\tn = 0;\n> +\twhile (argv[n])\n> +\t\tn++;\n> +\n> +\tpathspec->nr = n;\n> +\tpathspec->items = item = xmalloc(sizeof(*item) * n);\n> +\tpathspec->raw = argv;\n> +\tprefixlen = prefix ? strlen(prefix) : 0;\n> +\n> +\tfor (i = 0; i < n; i++) {\n> +\t\tunsigned short_magic;\n> +\t\tentry = argv[i];\n> +\n> +\t\titem[i].magic = prefix_pathspec(item + i, &short_magic,\n> +\t\t\t\t\t\targv + i, flags,\n> +\t\t\t\t\t\tprefix, prefixlen, entry);\n> +\t\tif (item[i].magic & magic_mask)\n> +\t\t\tunsupported_magic(entry,\n> +\t\t\t\t\t  item[i].magic & magic_mask,\n> +\t\t\t\t\t  short_magic);\n> +\t\tif (item[i].nowildcard_len < item[i].len)\n> +\t\t\tpathspec->has_wildcard = 1;\n> +\t\tpathspec->magic |= item[i].magic;\n> +\t}\n> +\n> +\tqsort(pathspec->items, pathspec->nr,\n> +\t      sizeof(struct pathspec_item), pathspec_item_cmp);\n>  }\n>  \n>  /*\n>   * N.B. get_pathspec() is deprecated in favor of the \"struct pathspec\"\n> - * based interface - see pathspec_magic above.\n> + * based interface - see pathspec.c:parse_pathspec().\n>   *\n>   * Arguments:\n>   *  - prefix - a path relative to the root of the working tree\n> @@ -221,32 +334,11 @@ static const char *prefix_pathspec(const char *prefix, int prefixlen, const char\n>   */\n>  const char **get_pathspec(const char *prefix, const char **pathspec)\n>  {\n> -\tconst char *entry = *pathspec;\n> -\tconst char **src, **dst;\n> -\tint prefixlen;\n> -\n> -\tif (!prefix && !entry)\n> -\t\treturn NULL;\n> -\n> -\tif (!entry) {\n> -\t\tstatic const char *spec[2];\n> -\t\tspec[0] = prefix;\n> -\t\tspec[1] = NULL;\n> -\t\treturn spec;\n> -\t}\n> -\n> -\t/* Otherwise we have to re-write the entries.. */\n> -\tsrc = pathspec;\n> -\tdst = pathspec;\n> -\tprefixlen = prefix ? strlen(prefix) : 0;\n> -\twhile (*src) {\n> -\t\t*(dst++) = prefix_pathspec(prefix, prefixlen, *src);\n> -\t\tsrc++;\n> -\t}\n> -\t*dst = NULL;\n> -\tif (!*pathspec)\n> -\t\treturn NULL;\n> -\treturn pathspec;\n> +\tstruct pathspec ps;\n> +\tparse_pathspec(&ps,\n> +\t\t       PATHSPEC_ALL_MAGIC & ~PATHSPEC_FROMTOP,\n> +\t\t       0, prefix, pathspec);\n> +\treturn ps.raw;\n>  }\n>  \n>  void copy_pathspec(struct pathspec *dst, const struct pathspec *src)\n> diff --git a/pathspec.h b/pathspec.h\n> index a621676..937ec91 100644\n> --- a/pathspec.h\n> +++ b/pathspec.h\n> @@ -1,6 +1,10 @@\n>  #ifndef PATHSPEC_H\n>  #define PATHSPEC_H\n>  \n> +/* Pathspec magic */\n> +#define PATHSPEC_FROMTOP\t(1<<0)\n> +#define PATHSPEC_ALL_MAGIC PATHSPEC_FROMTOP\n> +\n>  #define PATHSPEC_ONESTAR 1\t/* the pathspec pattern sastisfies GFNM_ONESTAR */\n>  \n>  struct pathspec {\n> @@ -8,9 +12,11 @@ struct pathspec {\n>  \tint nr;\n>  \tunsigned int has_wildcard:1;\n>  \tunsigned int recursive:1;\n> +\tunsigned magic;\n>  \tint max_depth;\n>  \tstruct pathspec_item {\n>  \t\tconst char *match;\n> +\t\tunsigned magic;\n>  \t\tint len;\n>  \t\tint nowildcard_len;\n>  \t\tint flags;\n> @@ -18,6 +24,11 @@ struct pathspec {\n>  };\n>  \n>  extern int init_pathspec(struct pathspec *, const char **);\n> +extern void parse_pathspec(struct pathspec *pathspec,\n> +\t\t\t   unsigned magic_mask,\n> +\t\t\t   unsigned flags,\n> +\t\t\t   const char *prefix,\n> +\t\t\t   const char **args);\n>  extern void copy_pathspec(struct pathspec *dst, const struct pathspec *src);\n>  extern void free_pathspec(struct pathspec *);\n"},{"id":"212016","messageId":"20130323031334.GA10484@lanh","threadId":"33187","inReplyTo":"7vvc8kabhx.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH v2 00/45] parse_pathspec and :(glob) magic","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2013-03-23T03:13:34Z","receivedAt":"2013-03-23T03:13:34Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Thu, Mar 21, 2013 at 10:50:02AM -0700, Junio C Hamano wrote:\n> > Why could the test pass for you without it?  It doesn't look like a\n> > bug that depended on uninitialized memory or something from the\n> > above observation.\n\nIt depends on uninitialized memory. For absolute paths, prefix is\nuseless and I should have set the useful prefix length to zero, but I\ndid not. Later in prefix_pathspec, I rely on this value to set\nnowildcard_len without checking if it's sane. The actual pathspec\nafter prefix_pathspec is \"src\" (length of 3) but nowildcard_len is 5.\n\nIn common_prefix_len(), I use nowildcard_len without sanity checks. So\nthe code examines 's', 'r', 'c', '\\0', '<random>'. In my case,\n'<random>' has never been '/'. I guess yours is '/' (which leads to\nwrong common prefix length).\n\nI've added an assert() to make sure nowildcard_len and prefix have\nsane values before exiting prefix_pathspec. This assert() chokes at\nt7300.8 for me.\n\n> The change made to prefix_path_gently() in this series is beyond\n> \"disgusting\", especially with the above fix-up.\n> \n> Sometimes it uses the original \"len\", sometimes it uses the fixed-up\n> *p_len (e.g. passes it down to normalize_path_copy_len()), and lets\n> normalize_path_copy_len() further update it, and thenit makes the\n> caller use the updated *p_len.\n> \n> Does the caller know what the value in *p_len _mean_ after this\n> function returns?  Can it afford to lose the original length of the\n> prefix it saved in a variable, without getting confused?\n> \n> I think any change that turns a value-passed argument in the\n> existing code into modifiable pointer-to-variable in this series\n> should add in-code comment to describe what the variable mean upon\n> entry and after return, just like normalize_path_copy_len() that was\n> built out of the original normalize_path_copy().  I didn't look if\n> there are many others, or if this is the only one that is tricky. it\n> is tricky that even the original author of the patch got it wrong\n> X-<.\n> \n\nThe author of the patch totally forgot that prefix has nothing to do\nwith prefix. How about this? The prefix length is passed as value as\nbefore. A separate pointer is for passing back the actual prefix\nlength. You can pull the actual patch from\n\nhttps://github.com/pclouds/git parse-pathspec\n\nwhich also includes all document bugs reported so far.\n\n-- 8< --\ndiff --git a/pathspec.c b/pathspec.c\nindex 0771e48..126771c 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -205,7 +205,7 @@ static unsigned prefix_pathspec(struct pathspec_item *item,\n \t\tmatch = xstrdup(copyfrom);\n \t\tprefixlen = 0;\n \t} else {\n-\t\tmatch = prefix_path_gently(prefix, &prefixlen, copyfrom);\n+\t\tmatch = prefix_path_gently(prefix, prefixlen, &prefixlen, copyfrom);\n \t\tif (!match)\n \t\t\tdie(\"%s: '%s' is outside repository\", elt, copyfrom);\n \t}\n@@ -284,6 +284,10 @@ static unsigned prefix_pathspec(struct pathspec_item *item,\n \t\t    no_wildcard(item->match + item->nowildcard_len + 1))\n \t\t\titem->flags |= PATHSPEC_ONESTAR;\n \t}\n+\n+\t/* sanity checks, pathspec matchers assume these are sane */\n+\tassert(item->nowildcard_len <= item->len &&\n+\t       item->prefix         <= item->len);\n \treturn magic;\n }\n \n@@ -315,7 +319,7 @@ static void NORETURN unsupported_magic(const char *pattern,\n \t\tn++;\n \t}\n \t/*\n-\t * We may want to substitue \"this command\" with a command\n+\t * We may want to substitute \"this command\" with a command\n \t * name. E.g. when add--interactive dies when running\n \t * \"checkout -p\"\n \t */\ndiff --git a/setup.c b/setup.c\nindex e59146b..6cf2bc6 100644\n--- a/setup.c\n+++ b/setup.c\n@@ -5,24 +5,37 @@\n static int inside_git_dir = -1;\n static int inside_work_tree = -1;\n \n-char *prefix_path_gently(const char *prefix, int *p_len, const char *path)\n+/*\n+ * Normalize \"path\", prepending the \"prefix\" for relative paths. If\n+ * remaining_prefix is not NULL, return the actual prefix still\n+ * remains in the path. For example, prefix = sub1/sub2/ and path is\n+ *\n+ *  foo          -> sub1/sub2/foo  (full prefix)\n+ *  ../foo       -> sub1/foo       (remaining prefix is sub1/)\n+ *  ../../bar    -> bar            (no remaining prefix)\n+ *  ../../sub1/sub2/foo -> sub1/sub2/foo (but no remaining prefix)\n+ *  `pwd`/../bar -> sub1/bar       (no remaining prefix)\n+ */\n+char *prefix_path_gently(const char *prefix, int len,\n+\t\t\t int *remaining_prefix, const char *path)\n {\n \tconst char *orig = path;\n \tchar *sanitized;\n-\tint len = *p_len;\n \tif (is_absolute_path(orig)) {\n \t\tconst char *temp = real_path(path);\n \t\tsanitized = xmalloc(len + strlen(temp) + 1);\n \t\tstrcpy(sanitized, temp);\n-\t\tif (p_len)\n-\t\t\t*p_len = 0;\n+\t\tif (remaining_prefix)\n+\t\t\t*remaining_prefix = 0;\n \t} else {\n \t\tsanitized = xmalloc(len + strlen(path) + 1);\n \t\tif (len)\n \t\t\tmemcpy(sanitized, prefix, len);\n \t\tstrcpy(sanitized + len, path);\n+\t\tif (remaining_prefix)\n+\t\t\t*remaining_prefix = len;\n \t}\n-\tif (normalize_path_copy_len(sanitized, sanitized, p_len))\n+\tif (normalize_path_copy_len(sanitized, sanitized, remaining_prefix))\n \t\tgoto error_out;\n \tif (is_absolute_path(orig)) {\n \t\tsize_t root_len, len, total;\n@@ -47,7 +60,7 @@ char *prefix_path_gently(const char *prefix, int *p_len, const char *path)\n \n char *prefix_path(const char *prefix, int len, const char *path)\n {\n-\tchar *r = prefix_path_gently(prefix, &len, path);\n+\tchar *r = prefix_path_gently(prefix, len, NULL, path);\n \tif (!r)\n \t\tdie(\"'%s' is outside repository\", path);\n \treturn r;\n@@ -56,7 +69,7 @@ char *prefix_path(const char *prefix, int len, const char *path)\n int path_inside_repo(const char *prefix, const char *path)\n {\n \tint len = prefix ? strlen(prefix) : 0;\n-\tchar *r = prefix_path_gently(prefix, &len, path);\n+\tchar *r = prefix_path_gently(prefix, len, NULL, path);\n \tif (r) {\n \t\tfree(r);\n \t\treturn 1;\n-- 8< --\n"},{"id":"212017","messageId":"CACsJy8AAyV9FyZ3ff1=FQtHB60Kpz57jrNVuxSVdSaoRO=BCzA@mail.gmail.com","threadId":"33187","inReplyTo":"20130323031334.GA10484@lanh","subject":"Re: [PATCH v2 00/45] parse_pathspec and :(glob) magic","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2013-03-23T03:15:28Z","receivedAt":"2013-03-23T03:15:28Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Sat, Mar 23, 2013 at 10:13 AM, Duy Nguyen <pclouds@gmail.com> wrote:\n> which also includes all document bugs reported so far.\n\ns/all/fixes for all/\n-- \nDuy\n"},{"id":"212064","messageId":"CAPig+cT+MgTmhqUXpSGEtiqjgerFA6asUMg7wg=-Vee85MVKoQ@mail.gmail.com","threadId":"33187","inReplyTo":"20130323031334.GA10484@lanh","subject":"Re: [PATCH v2 00/45] parse_pathspec and :(glob) magic","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2013-03-24T00:57:27Z","receivedAt":"2013-03-24T00:57:27Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Fri, Mar 22, 2013 at 11:13 PM, Duy Nguyen <pclouds@gmail.com> wrote:\n> diff --git a/setup.c b/setup.c\n> index e59146b..6cf2bc6 100644\n> --- a/setup.c\n> +++ b/setup.c\n> @@ -5,24 +5,37 @@\n>  static int inside_git_dir = -1;\n>  static int inside_work_tree = -1;\n>\n> -char *prefix_path_gently(const char *prefix, int *p_len, const char *path)\n> +/*\n> + * Normalize \"path\", prepending the \"prefix\" for relative paths. If\n> + * remaining_prefix is not NULL, return the actual prefix still\n> + * remains in the path. For example, prefix = sub1/sub2/ and path is\n\ns/still remains/still remaining/\n...or...\ns/still remains/which still remains/\n...or...\ns/still remains/which remains/\n"},{"id":"212385","messageId":"7vboa4q2c1.fsf@alter.siamese.dyndns.org","threadId":"33187","inReplyTo":"CACsJy8AAyV9FyZ3ff1=FQtHB60Kpz57jrNVuxSVdSaoRO=BCzA@mail.gmail.com","subject":"Re: [PATCH v2 00/45] parse_pathspec and :(glob) magic","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2013-03-27T15:39:26Z","receivedAt":"2013-03-27T15:39:26Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Duy Nguyen <pclouds@gmail.com> writes:\n\n> On Sat, Mar 23, 2013 at 10:13 AM, Duy Nguyen <pclouds@gmail.com> wrote:\n>> which also includes all document bugs reported so far.\n>\n> s/all/fixes for all/\n\nSlurped from your github repository and didn't find anything\nquestionable relative to the original series that was posted here.\n\nThanks.  Will requeue.\n"},{"id":"214061","messageId":"20130412150304.GH26949@pacific.linksys.moosehall","threadId":"33187","inReplyTo":"1363327620-29017-24-git-send-email-pclouds@gmail.com","subject":"Re: [PATCH v1 23/45] check-ignore: convert to use parse_pathspec","fromName":"Adam Spiers","fromEmail":"git@adamspiers.org","sentAt":"2013-04-12T15:03:05Z","receivedAt":"2013-04-12T15:03:05Z","isPatch":true,"sender":{"key":"git@adamspiers.org","avatar":"https://avatars.githubusercontent.com/u/100738?v=4"},"body":"On Fri, Mar 15, 2013 at 01:06:38PM +0700, Nguyễn Thái Ngọc Duy wrote:\n> check-ignore (at least the test suite) seems to rely on the pattern\n> order. PATHSPEC_KEEP_ORDER is introduced to explictly express this.\n> The lack of PATHSPEC_MAXDEPTH_VALID is sufficient because it's the\n> only flag that reorders pathspecs, but it's less obvious that way.\n\nSorry for the slow response - I only just noticed this today.  (It\nwould be useful if any future patches to check-ignore Cc: me\nexplicitly, to catch my mail filters.)\n\n> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n> ---\n>  builtin/check-ignore.c | 34 +++++++++++++++++++++-------------\n>  pathspec.c             |  6 +++++-\n>  pathspec.h             |  1 +\n>  t/t0008-ignores.sh     |  8 ++++----\n>  4 files changed, 31 insertions(+), 18 deletions(-)\n> \n> diff --git a/builtin/check-ignore.c b/builtin/check-ignore.c\n> index 0240f99..6e55f06 100644\n> --- a/builtin/check-ignore.c\n> +++ b/builtin/check-ignore.c\n> @@ -53,14 +53,14 @@ static void output_exclude(const char *path, struct exclude *exclude)\n>  \t}\n>  }\n>  \n> -static int check_ignore(const char *prefix, const char **pathspec)\n> +static int check_ignore(int argc, const char **argv, const char *prefix)\n>  {\n>  \tstruct dir_struct dir;\n> -\tconst char *path, *full_path;\n>  \tchar *seen;\n>  \tint num_ignored = 0, dtype = DT_UNKNOWN, i;\n>  \tstruct path_exclude_check check;\n>  \tstruct exclude *exclude;\n> +\tstruct pathspec pathspec;\n>  \n>  \t/* read_cache() is only necessary so we can watch out for submodules. */\n>  \tif (read_cache() < 0)\n> @@ -70,31 +70,39 @@ static int check_ignore(const char *prefix, const char **pathspec)\n>  \tdir.flags |= DIR_COLLECT_IGNORED;\n>  \tsetup_standard_excludes(&dir);\n>  \n> -\tif (!pathspec || !*pathspec) {\n> +\tif (!argc) {\n\nIs there a compelling reason for introducing argc as a new parameter\nto check_ignore(), other than simplifying the above line?  And why\nrename the pathspec parameter to argv?  Both these changes are\nmisleading AFAICS, since paths provided to check_ignore() can come\nfrom sources other than CLI arguments (i.e. via --stdin).  \n\nThe introduction of argc also makes it possible to invoke\ncheck_ignore() with arguments which are not self-consistent.\n\nI haven't been following your pathspec work, but FWIW the other\nchanges in this patch look reasonable at a glance.\n\nThanks,\nAdam\n"},{"id":"214112","messageId":"CACsJy8Au4KL7msPr62bvSgGdseWFF=cUJSuB2JzGUXehDD6hng@mail.gmail.com","threadId":"33187","inReplyTo":"20130412150304.GH26949@pacific.linksys.moosehall","subject":"Re: [PATCH v1 23/45] check-ignore: convert to use parse_pathspec","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2013-04-12T23:09:33Z","receivedAt":"2013-04-12T23:09:33Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Sat, Apr 13, 2013 at 1:03 AM, Adam Spiers <git@adamspiers.org> wrote:\n>> -static int check_ignore(const char *prefix, const char **pathspec)\n>> +static int check_ignore(int argc, const char **argv, const char *prefix)\n>>  {\n>>       struct dir_struct dir;\n>> -     const char *path, *full_path;\n>>       char *seen;\n>>       int num_ignored = 0, dtype = DT_UNKNOWN, i;\n>>       struct path_exclude_check check;\n>>       struct exclude *exclude;\n>> +     struct pathspec pathspec;\n>>\n>>       /* read_cache() is only necessary so we can watch out for submodules. */\n>>       if (read_cache() < 0)\n>> @@ -70,31 +70,39 @@ static int check_ignore(const char *prefix, const char **pathspec)\n>>       dir.flags |= DIR_COLLECT_IGNORED;\n>>       setup_standard_excludes(&dir);\n>>\n>> -     if (!pathspec || !*pathspec) {\n>> +     if (!argc) {\n>\n> Is there a compelling reason for introducing argc as a new parameter\n> to check_ignore(), other than simplifying the above line?  And why\n> rename the pathspec parameter to argv?  Both these changes are\n> misleading AFAICS, since paths provided to check_ignore() can come\n> from sources other than CLI arguments (i.e. via --stdin).\n\nBecause I introduced \"struct pathspec pathspec;\" I need to rename the\nargument \"pathspec\" to something else. Maybe we could rename the\nargument to \"paths\"?\n\n> The introduction of argc also makes it possible to invoke\n> check_ignore() with arguments which are not self-consistent.\n\nThis is the same problem with main() and other places that follow this\nconvention. But I don't mind dropping argc either.\n-- \nDuy\n"},{"id":"214237","messageId":"20130414232542.GB21564@indian.linksys.moosehall","threadId":"33187","inReplyTo":"CACsJy8Au4KL7msPr62bvSgGdseWFF=cUJSuB2JzGUXehDD6hng@mail.gmail.com","subject":"Re: [PATCH v1 23/45] check-ignore: convert to use parse_pathspec","fromName":"Adam Spiers","fromEmail":"git@adamspiers.org","sentAt":"2013-04-14T23:25:42Z","receivedAt":"2013-04-14T23:25:42Z","isPatch":true,"sender":{"key":"git@adamspiers.org","avatar":"https://avatars.githubusercontent.com/u/100738?v=4"},"body":"On Sat, Apr 13, 2013 at 09:09:33AM +1000, Duy Nguyen wrote:\n> On Sat, Apr 13, 2013 at 1:03 AM, Adam Spiers <git@adamspiers.org> wrote:\n> >> -static int check_ignore(const char *prefix, const char **pathspec)\n> >> +static int check_ignore(int argc, const char **argv, const char *prefix)\n> >>  {\n> >>       struct dir_struct dir;\n> >> -     const char *path, *full_path;\n> >>       char *seen;\n> >>       int num_ignored = 0, dtype = DT_UNKNOWN, i;\n> >>       struct path_exclude_check check;\n> >>       struct exclude *exclude;\n> >> +     struct pathspec pathspec;\n> >>\n> >>       /* read_cache() is only necessary so we can watch out for submodules. */\n> >>       if (read_cache() < 0)\n> >> @@ -70,31 +70,39 @@ static int check_ignore(const char *prefix, const char **pathspec)\n> >>       dir.flags |= DIR_COLLECT_IGNORED;\n> >>       setup_standard_excludes(&dir);\n> >>\n> >> -     if (!pathspec || !*pathspec) {\n> >> +     if (!argc) {\n> >\n> > Is there a compelling reason for introducing argc as a new parameter\n> > to check_ignore(), other than simplifying the above line?  And why\n> > rename the pathspec parameter to argv?  Both these changes are\n> > misleading AFAICS, since paths provided to check_ignore() can come\n> > from sources other than CLI arguments (i.e. via --stdin).\n> \n> Because I introduced \"struct pathspec pathspec;\" I need to rename the\n> argument \"pathspec\" to something else.\n\nAh, I see - that makes sense :-)\n\n> Maybe we could rename the argument to \"paths\"?\n\nSounds fine to me.\n\n> > The introduction of argc also makes it possible to invoke\n> > check_ignore() with arguments which are not self-consistent.\n> \n> This is the same problem with main()\n\nHow could main() be invoked with argc inconsistent with argv?\n\n> and other places that follow this convention.  But I don't mind\n> dropping argc either.\n\nWhat is the reason for that convention?  I'm willing to be persuaded\neither way.\n"},{"id":"214240","messageId":"CACsJy8CTZPZV6BKhLey-EZgu2gFhpNdkNVVoRALT0PyO0RS+_Q@mail.gmail.com","threadId":"33187","inReplyTo":"20130414232542.GB21564@indian.linksys.moosehall","subject":"Re: [PATCH v1 23/45] check-ignore: convert to use parse_pathspec","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2013-04-14T23:48:22Z","receivedAt":"2013-04-14T23:48:22Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Mon, Apr 15, 2013 at 9:25 AM, Adam Spiers <git@adamspiers.org> wrote:\n>> > The introduction of argc also makes it possible to invoke\n>> > check_ignore() with arguments which are not self-consistent.\n>>\n>> This is the same problem with main()\n>\n> How could main() be invoked with argc inconsistent with argv?\n\nThe point is main's caller has to maintain the consistency. So do\ncheck_ignore's callers.\n-- \nDuy\n"},{"id":"214316","messageId":"20130415161732.GA5459@indian.linksys.moosehall","threadId":"33187","inReplyTo":"CACsJy8CTZPZV6BKhLey-EZgu2gFhpNdkNVVoRALT0PyO0RS+_Q@mail.gmail.com","subject":"Re: [PATCH v1 23/45] check-ignore: convert to use parse_pathspec","fromName":"Adam Spiers","fromEmail":"git@adamspiers.org","sentAt":"2013-04-15T16:17:32Z","receivedAt":"2013-04-15T16:17:32Z","isPatch":true,"sender":{"key":"git@adamspiers.org","avatar":"https://avatars.githubusercontent.com/u/100738?v=4"},"body":"On Mon, Apr 15, 2013 at 09:48:22AM +1000, Duy Nguyen wrote:\n> On Mon, Apr 15, 2013 at 9:25 AM, Adam Spiers <git@adamspiers.org> wrote:\n> >> > The introduction of argc also makes it possible to invoke\n> >> > check_ignore() with arguments which are not self-consistent.\n> >>\n> >> This is the same problem with main()\n> >\n> > How could main() be invoked with argc inconsistent with argv?\n> \n> The point is main's caller has to maintain the consistency. So do\n> check_ignore's callers.\n\nBut only the system runtime calls main(), right?  So we can probably\nrely on it being called in a consistent manner ;-)\n"}]}