{"thread":{"id":"44632","subject":"[PATCH 01/17] mv: convert to using pathspec struct interface","startedAt":"2016-12-06T21:53:18Z","lastAt":"2017-01-09T17:58:07Z","messageCount":142,"participants":["Brandon Williams","Stefan Beller","Duy Nguyen","Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":17},"messages":[{"id":"307054","messageId":"1481061106-117775-2-git-send-email-bmwill@google.com","threadId":"44632","inReplyTo":"1481061106-117775-1-git-send-email-bmwill@google.com","subject":"[PATCH 01/17] mv: convert to using pathspec struct interface","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2016-12-06T21:51:30Z","receivedAt":"2016-12-06T21:53:18Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Convert the 'internal_copy_pathspec()' function to use the pathspec\nstruct interface from using the deprecated 'get_pathspec()' interface.\n\nIn addition to this, fix a memory leak caused by only duplicating some\nof the pathspec elements.  Instead always duplicate all of the the\npathspec elements as an intermediate step (with modificationed based on\nthe passed in flags).  This way the intermediate strings can then be\nfreed prior to duplicating the result of parse_pathspec (which contains\neach of the elements with the prefix prepended).\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n builtin/mv.c | 45 ++++++++++++++++++++++++++++++++-------------\n 1 file changed, 32 insertions(+), 13 deletions(-)\n\ndiff --git a/builtin/mv.c b/builtin/mv.c\nindex 2f43877..4df4a12 100644\n--- a/builtin/mv.c\n+++ b/builtin/mv.c\n@@ -4,6 +4,7 @@\n  * Copyright (C) 2006 Johannes Schindelin\n  */\n #include \"builtin.h\"\n+#include \"pathspec.h\"\n #include \"lockfile.h\"\n #include \"dir.h\"\n #include \"cache-tree.h\"\n@@ -25,25 +26,43 @@ static const char **internal_copy_pathspec(const char *prefix,\n {\n \tint i;\n \tconst char **result;\n+\tstruct pathspec ps;\n \tALLOC_ARRAY(result, count + 1);\n-\tCOPY_ARRAY(result, pathspec, count);\n-\tresult[count] = NULL;\n+\n+\t/* Create an intermediate copy of the pathspec based on the flags */\n \tfor (i = 0; i < count; i++) {\n-\t\tint length = strlen(result[i]);\n+\t\tint length = strlen(pathspec[i]);\n \t\tint to_copy = length;\n+\t\tchar *it;\n \t\twhile (!(flags & KEEP_TRAILING_SLASH) &&\n-\t\t       to_copy > 0 && is_dir_sep(result[i][to_copy - 1]))\n+\t\t       to_copy > 0 && is_dir_sep(pathspec[i][to_copy - 1]))\n \t\t\tto_copy--;\n-\t\tif (to_copy != length || flags & DUP_BASENAME) {\n-\t\t\tchar *it = xmemdupz(result[i], to_copy);\n-\t\t\tif (flags & DUP_BASENAME) {\n-\t\t\t\tresult[i] = xstrdup(basename(it));\n-\t\t\t\tfree(it);\n-\t\t\t} else\n-\t\t\t\tresult[i] = it;\n-\t\t}\n+\n+\t\tit = xmemdupz(pathspec[i], to_copy);\n+\t\tif (flags & DUP_BASENAME) {\n+\t\t\tresult[i] = xstrdup(basename(it));\n+\t\t\tfree(it);\n+\t\t} else\n+\t\t\tresult[i] = it;\n+\t}\n+\tresult[count] = NULL;\n+\n+\tparse_pathspec(&ps,\n+\t\t       PATHSPEC_ALL_MAGIC &\n+\t\t       ~(PATHSPEC_FROMTOP | PATHSPEC_LITERAL),\n+\t\t       PATHSPEC_KEEP_ORDER | PATHSPEC_PREFER_CWD,\n+\t\t       prefix, result);\n+\tassert(count == ps.nr);\n+\n+\t/* Copy the pathspec and free the old intermediate strings */\n+\tfor (i = 0; i < count; i++) {\n+\t\tconst char *match = xstrdup(ps.items[i].match);\n+\t\tfree((char *) result[i]);\n+\t\tresult[i] = match;\n \t}\n-\treturn get_pathspec(prefix, result);\n+\n+\tclear_pathspec(&ps);\n+\treturn result;\n }\n \n static const char *add_slash(const char *path)\n-- \n2.8.0.rc3.226.g39d4020\n\n"},{"id":"307055","messageId":"1481061106-117775-1-git-send-email-bmwill@google.com","threadId":"44632","inReplyTo":null,"subject":"[PATCH 00/17] pathspec cleanup","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2016-12-06T21:51:29Z","receivedAt":"2016-12-06T21:53:22Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"The intent of this series is to cleanup some of the pathspec initialization\ncode as well as finally migrating the remaining users of the _raw field or\nget_pathspec() to the pathspec struct interface.  This way both the _raw field\nand get_pathspec() can be removed from the codebase.  This also removes the\nfunctionality where parse_pathspec() modified the const char * argv array that\nwas passed in (which felt kind of odd to me as I wouldn't have expected the\npassed in array to be modified).\n\nI also noticed that there are memory leaks associated with the 'original' and\n'match' strings.  To fix this the pathspec struct needed to take ownership of\nthe memory for these fields so that they can be cleaned up when clearing the\npathspec struct.\n\nMost of the work went to simplifying the prefix_pathspec function.  This\nconsisted of factoring out long sections of code into their own helper\nfunctions.  The overall result is a much more readable function.\n\nBrandon Williams (17):\n  mv: convert to using pathspec struct interface\n  dir: convert create_simplify to use the pathspec struct interface\n  dir: convert fill_directory to use the pathspec struct interface\n  ls-tree: convert show_recursive to use the pathspec struct interface\n  pathspec: remove the deprecated get_pathspec function\n  pathspec: copy and free owned memory\n  mv: small code cleanup\n  pathspec: remove unused variable from unsupported_magic\n  pathspec: always show mnemonic and name in unsupported_magic\n  pathspec: simpler logic to prefix original pathspec elements\n  pathspec: factor global magic into its own function\n  pathspec: create parse_short_magic function\n  pathspec: create parse_long_magic function\n  pathspec: create parse_element_magic helper\n  pathspec: create strip submodule slash helpers\n  pathspec: small readability changes\n  pathspec: remove outdated comment\n\n Documentation/technical/api-setup.txt |   2 -\n builtin/ls-tree.c                     |  12 +-\n builtin/mv.c                          |  44 +++-\n cache.h                               |   1 -\n dir.c                                 |  28 +--\n pathspec.c                            | 449 +++++++++++++++++++---------------\n pathspec.h                            |   5 +-\n 7 files changed, 301 insertions(+), 240 deletions(-)\n\n-- \n2.8.0.rc3.226.g39d4020\n\n"},{"id":"307056","messageId":"1481061106-117775-3-git-send-email-bmwill@google.com","threadId":"44632","inReplyTo":"1481061106-117775-1-git-send-email-bmwill@google.com","subject":"[PATCH 02/17] dir: convert create_simplify to use the pathspec struct interface","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2016-12-06T21:51:31Z","receivedAt":"2016-12-06T21:53:25Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Convert 'create_simplify()' to use the pathspec struct interface from\nusing the '_raw' entry in the pathspec.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n dir.c | 25 ++++++++++++-------------\n 1 file changed, 12 insertions(+), 13 deletions(-)\n\ndiff --git a/dir.c b/dir.c\nindex bfa8c8a..7df292b 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -1787,25 +1787,24 @@ static int cmp_name(const void *p1, const void *p2)\n \treturn name_compare(e1->name, e1->len, e2->name, e2->len);\n }\n \n-static struct path_simplify *create_simplify(const char **pathspec)\n+static struct path_simplify *create_simplify(const struct pathspec *pathspec)\n {\n-\tint nr, alloc = 0;\n+\tint i;\n \tstruct path_simplify *simplify = NULL;\n \n-\tif (!pathspec)\n+\tif (!pathspec || !pathspec->nr)\n \t\treturn NULL;\n \n-\tfor (nr = 0 ; ; nr++) {\n+\tALLOC_ARRAY(simplify, pathspec->nr + 1);\n+\tfor (i = 0; i < pathspec->nr; i++) {\n \t\tconst char *match;\n-\t\tALLOC_GROW(simplify, nr + 1, alloc);\n-\t\tmatch = *pathspec++;\n-\t\tif (!match)\n-\t\t\tbreak;\n-\t\tsimplify[nr].path = match;\n-\t\tsimplify[nr].len = simple_length(match);\n+\t\tmatch = pathspec->items[i].match;\n+\t\tsimplify[i].path = match;\n+\t\tsimplify[i].len = pathspec->items[i].nowildcard_len;\n \t}\n-\tsimplify[nr].path = NULL;\n-\tsimplify[nr].len = 0;\n+\tsimplify[i].path = NULL;\n+\tsimplify[i].len = 0;\n+\n \treturn simplify;\n }\n \n@@ -2036,7 +2035,7 @@ int read_directory(struct dir_struct *dir, const char *path, int len, const stru\n \t * subset of positive ones, which has no impacts on\n \t * create_simplify().\n \t */\n-\tsimplify = create_simplify(pathspec ? pathspec->_raw : NULL);\n+\tsimplify = create_simplify(pathspec);\n \tuntracked = validate_untracked_cache(dir, len, pathspec);\n \tif (!untracked)\n \t\t/*\n-- \n2.8.0.rc3.226.g39d4020\n\n"},{"id":"307057","messageId":"1481061106-117775-4-git-send-email-bmwill@google.com","threadId":"44632","inReplyTo":"1481061106-117775-1-git-send-email-bmwill@google.com","subject":"[PATCH 03/17] dir: convert fill_directory to use the pathspec struct interface","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2016-12-06T21:51:32Z","receivedAt":"2016-12-06T21:53:28Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Convert 'fill_directory()' to use the pathspec struct interface from\nusing the '_raw' entry in the pathspec struct.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n dir.c | 3 ++-\n 1 file changed, 2 insertions(+), 1 deletion(-)\n\ndiff --git a/dir.c b/dir.c\nindex 7df292b..8730a4f 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -188,7 +188,8 @@ 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->items[0].match : \"\",\n+\t\t       len, pathspec);\n \treturn len;\n }\n \n-- \n2.8.0.rc3.226.g39d4020\n\n"},{"id":"307058","messageId":"1481061106-117775-11-git-send-email-bmwill@google.com","threadId":"44632","inReplyTo":"1481061106-117775-1-git-send-email-bmwill@google.com","subject":"[PATCH 10/17] pathspec: simpler logic to prefix original pathspec elements","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2016-12-06T21:51:39Z","receivedAt":"2016-12-06T21:53:30Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"The logic used to prefix an original pathspec element with 'prefix'\nmagic is more general purpose and can be used for more than just short\nmagic.  Remove the extra code paths and rename 'prefix_short_magic' to\n'prefix_magic' to better indicate that it can be used in more general\nsituations.\n\nAlso, slightly change the logic which decides when to prefix the\noriginal element in order to prevent a pathspec of \".\" from getting\nconverted to \"\" (empty string).\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n pathspec.c | 33 +++++++++++++--------------------\n 1 file changed, 13 insertions(+), 20 deletions(-)\n\ndiff --git a/pathspec.c b/pathspec.c\nindex 159f6db..5afebd3 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -74,13 +74,12 @@ static struct pathspec_magic {\n \t{ PATHSPEC_EXCLUDE, '!', \"exclude\" },\n };\n \n-static void prefix_short_magic(struct strbuf *sb, int prefixlen,\n-\t\t\t       unsigned short_magic)\n+static void prefix_magic(struct strbuf *sb, int prefixlen, unsigned magic)\n {\n \tint i;\n \tstrbuf_addstr(sb, \":(\");\n \tfor (i = 0; i < ARRAY_SIZE(pathspec_magic); i++)\n-\t\tif (short_magic & pathspec_magic[i].bit) {\n+\t\tif (magic & pathspec_magic[i].bit) {\n \t\t\tif (sb->buf[sb->len - 1] != '(')\n \t\t\t\tstrbuf_addch(sb, ',');\n \t\t\tstrbuf_addstr(sb, pathspec_magic[i].name);\n@@ -110,8 +109,8 @@ static unsigned prefix_pathspec(struct pathspec_item *item,\n \tstatic int glob_global = -1;\n \tstatic int noglob_global = -1;\n \tstatic int icase_global = -1;\n-\tunsigned magic = 0, short_magic = 0, global_magic = 0;\n-\tconst char *copyfrom = elt, *long_magic_end = NULL;\n+\tunsigned magic = 0, element_magic = 0, global_magic = 0;\n+\tconst char *copyfrom = elt;\n \tchar *match;\n \tint i, pathspec_prefix = -1;\n \n@@ -165,7 +164,7 @@ static unsigned prefix_pathspec(struct pathspec_item *item,\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\telement_magic |= pathspec_magic[i].bit;\n \t\t\t\t\tbreak;\n \t\t\t\t}\n \t\t\t\tif (starts_with(copyfrom, \"prefix:\")) {\n@@ -184,7 +183,6 @@ static unsigned prefix_pathspec(struct pathspec_item *item,\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@@ -197,7 +195,7 @@ static unsigned prefix_pathspec(struct pathspec_item *item,\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\tshort_magic |= pathspec_magic[i].bit;\n+\t\t\t\t\telement_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@@ -208,7 +206,7 @@ static unsigned prefix_pathspec(struct pathspec_item *item,\n \t\t\tcopyfrom++;\n \t}\n \n-\tmagic |= short_magic;\n+\tmagic |= element_magic;\n \n \t/* --noglob-pathspec adds :(literal) _unless_ :(glob) is specified */\n \tif (noglob_global && !(magic & PATHSPEC_GLOB))\n@@ -243,18 +241,13 @@ static unsigned prefix_pathspec(struct pathspec_item *item,\n \t * Prefix the pathspec (keep all magic) and assign to\n \t * original. Useful for passing to another command.\n \t */\n-\tif (flags & PATHSPEC_PREFIX_ORIGIN) {\n+\tif ((flags & PATHSPEC_PREFIX_ORIGIN) &&\n+\t    prefixlen && !literal_global) {\n \t\tstruct strbuf sb = STRBUF_INIT;\n-\t\tif (prefixlen && !literal_global) {\n-\t\t\t/* Preserve the actual prefix length of each pattern */\n-\t\t\tif (short_magic)\n-\t\t\t\tprefix_short_magic(&sb, prefixlen, short_magic);\n-\t\t\telse if (long_magic_end) {\n-\t\t\t\tstrbuf_add(&sb, elt, long_magic_end - elt);\n-\t\t\t\tstrbuf_addf(&sb, \",prefix:%d)\", prefixlen);\n-\t\t\t} else\n-\t\t\t\tstrbuf_addf(&sb, \":(prefix:%d)\", prefixlen);\n-\t\t}\n+\n+\t\t/* Preserve the actual prefix length of each pattern */\n+\t\tprefix_magic(&sb, prefixlen, element_magic);\n+\n \t\tstrbuf_addstr(&sb, match);\n \t\titem->original = strbuf_detach(&sb, NULL);\n \t} else {\n-- \n2.8.0.rc3.226.g39d4020\n\n"},{"id":"307059","messageId":"1481061106-117775-9-git-send-email-bmwill@google.com","threadId":"44632","inReplyTo":"1481061106-117775-1-git-send-email-bmwill@google.com","subject":"[PATCH 08/17] pathspec: remove unused variable from unsupported_magic","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2016-12-06T21:51:37Z","receivedAt":"2016-12-06T21:53:33Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Removed unused variable 'n' from the 'unsupported_magic()' function.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n pathspec.c | 5 ++---\n 1 file changed, 2 insertions(+), 3 deletions(-)\n\ndiff --git a/pathspec.c b/pathspec.c\nindex 8f367f0..ec0d590 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -333,8 +333,8 @@ static void NORETURN unsupported_magic(const char *pattern,\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+\tint i;\n+\tfor (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@@ -344,7 +344,6 @@ static void NORETURN unsupported_magic(const char *pattern,\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 substitute \"this command\" with a command\n-- \n2.8.0.rc3.226.g39d4020\n\n"},{"id":"307060","messageId":"1481061106-117775-10-git-send-email-bmwill@google.com","threadId":"44632","inReplyTo":"1481061106-117775-1-git-send-email-bmwill@google.com","subject":"[PATCH 09/17] pathspec: always show mnemonic and name in unsupported_magic","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2016-12-06T21:51:38Z","receivedAt":"2016-12-06T21:53:34Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"For better clarity, always show the mnemonic and name of the unsupported\nmagic being used.  This lets users have a more clear understanding of\nwhat magic feature isn't supported.  And if they supplied a mnemonic,\nthe user will be told what its corresponding name is which will allow\nthem to more easily search the man pages for that magic type.\n\nThis also avoids passing an extra parameter around the pathspec\ninitialization code.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n pathspec.c | 18 +++++++-----------\n 1 file changed, 7 insertions(+), 11 deletions(-)\n\ndiff --git a/pathspec.c b/pathspec.c\nindex ec0d590..159f6db 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -68,7 +68,7 @@ static struct pathspec_magic {\n \tconst char *name;\n } pathspec_magic[] = {\n \t{ PATHSPEC_FROMTOP, '/', \"top\" },\n-\t{ PATHSPEC_LITERAL,   0, \"literal\" },\n+\t{ PATHSPEC_LITERAL,'\\0', \"literal\" },\n \t{ PATHSPEC_GLOB,   '\\0', \"glob\" },\n \t{ PATHSPEC_ICASE,  '\\0', \"icase\" },\n \t{ PATHSPEC_EXCLUDE, '!', \"exclude\" },\n@@ -102,7 +102,6 @@ static void prefix_short_magic(struct strbuf *sb, int prefixlen,\n  * string cannot express such a case.\n  */\n static unsigned prefix_pathspec(struct pathspec_item *item,\n-\t\t\t\tunsigned *p_short_magic,\n \t\t\t\tunsigned flags,\n \t\t\t\tconst char *prefix, int prefixlen,\n \t\t\t\tconst char *elt)\n@@ -210,7 +209,6 @@ static unsigned prefix_pathspec(struct pathspec_item *item,\n \t}\n \n \tmagic |= short_magic;\n-\t*p_short_magic = short_magic;\n \n \t/* --noglob-pathspec adds :(literal) _unless_ :(glob) is specified */\n \tif (noglob_global && !(magic & PATHSPEC_GLOB))\n@@ -329,8 +327,7 @@ static int pathspec_item_cmp(const void *a_, const void *b_)\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+\t\t\t\t       unsigned magic)\n {\n \tstruct strbuf sb = STRBUF_INIT;\n \tint i;\n@@ -340,8 +337,9 @@ static void NORETURN unsupported_magic(const char *pattern,\n \t\t\tcontinue;\n \t\tif (sb.len)\n \t\t\tstrbuf_addch(&sb, ' ');\n-\t\tif (short_magic & m->bit)\n-\t\t\tstrbuf_addf(&sb, \"'%c'\", m->mnemonic);\n+\n+\t\tif (m->mnemonic)\n+\t\t\tstrbuf_addf(&sb, \"'(%c)%s'\", m->mnemonic, m->name);\n \t\telse\n \t\t\tstrbuf_addf(&sb, \"'%s'\", m->name);\n \t}\n@@ -413,10 +411,9 @@ void parse_pathspec(struct pathspec *pathspec,\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\titem[i].magic = prefix_pathspec(item + i,\n \t\t\t\t\t\tflags,\n \t\t\t\t\t\tprefix, prefixlen, entry);\n \t\tif ((flags & PATHSPEC_LITERAL_PATH) &&\n@@ -426,8 +423,7 @@ void parse_pathspec(struct pathspec *pathspec,\n \t\t\tnr_exclude++;\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\t\t\t\t  item[i].magic & magic_mask);\n \n \t\tif ((flags & PATHSPEC_SYMLINK_LEADING_PATH) &&\n \t\t    has_symlink_leading_path(item[i].match, item[i].len)) {\n-- \n2.8.0.rc3.226.g39d4020\n\n"},{"id":"307061","messageId":"1481061106-117775-17-git-send-email-bmwill@google.com","threadId":"44632","inReplyTo":"1481061106-117775-1-git-send-email-bmwill@google.com","subject":"[PATCH 16/17] pathspec: small readability changes","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2016-12-06T21:51:45Z","receivedAt":"2016-12-06T21:53:37Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"A few small changes to improve readability.  This is done by grouping related\nassignments, adding blank lines, ensuring lines are <80 characters, etc.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n pathspec.c | 15 ++++++++++-----\n 1 file changed, 10 insertions(+), 5 deletions(-)\n\ndiff --git a/pathspec.c b/pathspec.c\nindex 41aa213..8a07b02 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -334,6 +334,7 @@ static unsigned prefix_pathspec(struct pathspec_item *item,\n \tif ((magic & PATHSPEC_LITERAL) && (magic & PATHSPEC_GLOB))\n \t\tdie(_(\"%s: 'literal' and 'glob' are incompatible\"), elt);\n \n+\t/* Create match string which will be used for pathspec matching */\n \tif (pathspec_prefix >= 0) {\n \t\tmatch = xstrdup(copyfrom);\n \t\tprefixlen = pathspec_prefix;\n@@ -341,11 +342,16 @@ 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, &prefixlen, copyfrom);\n+\t\tmatch = prefix_path_gently(prefix, prefixlen,\n+\t\t\t\t\t   &prefixlen, copyfrom);\n \t\tif (!match)\n \t\t\tdie(_(\"%s: '%s' is outside repository\"), elt, copyfrom);\n \t}\n+\n \titem->match = match;\n+\titem->len = strlen(item->match);\n+\titem->prefix = prefixlen;\n+\n \t/*\n \t * Prefix the pathspec (keep all magic) and assign to\n \t * original. Useful for passing to another command.\n@@ -362,8 +368,6 @@ static unsigned prefix_pathspec(struct pathspec_item *item,\n \t} else {\n \t\titem->original = xstrdup(elt);\n \t}\n-\titem->len = strlen(item->match);\n-\titem->prefix = prefixlen;\n \n \tif (flags & PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP)\n \t    strip_submodule_slash_cheap(item);\n@@ -371,13 +375,14 @@ static unsigned prefix_pathspec(struct pathspec_item *item,\n \tif (flags & PATHSPEC_STRIP_SUBMODULE_SLASH_EXPENSIVE)\n \t    strip_submodule_slash_expensive(item);\n \n-\tif (magic & PATHSPEC_LITERAL)\n+\tif (magic & PATHSPEC_LITERAL) {\n \t\titem->nowildcard_len = item->len;\n-\telse {\n+\t} else {\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+\n \titem->flags = 0;\n \tif (magic & PATHSPEC_GLOB) {\n \t\t/*\n-- \n2.8.0.rc3.226.g39d4020\n\n"},{"id":"307062","messageId":"1481061106-117775-14-git-send-email-bmwill@google.com","threadId":"44632","inReplyTo":"1481061106-117775-1-git-send-email-bmwill@google.com","subject":"[PATCH 13/17] pathspec: create parse_long_magic function","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2016-12-06T21:51:42Z","receivedAt":"2016-12-06T21:53:41Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Factor out the logic responsible for parsing long magic into its own\nfunction.  As well as hoist the prefix check logic outside of the inner\nloop as there isn't anything that needs to be done after matching\n\"prefix:\".\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n pathspec.c | 92 ++++++++++++++++++++++++++++++++++++++------------------------\n 1 file changed, 57 insertions(+), 35 deletions(-)\n\ndiff --git a/pathspec.c b/pathspec.c\nindex d4d4839..1d28679 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -156,6 +156,60 @@ static int get_global_magic(int element_magic)\n }\n \n /*\n+ * Parse the pathspec element looking for long magic\n+ *\n+ * saves all magic in 'magic'\n+ * if prefix magic is used, save the prefix length in 'prefix_len'\n+ * returns the position in 'elem' after all magic has been parsed\n+ */\n+static const char *parse_long_magic(unsigned *magic, int *prefix_len,\n+\t\t\t\t    const char *elem)\n+{\n+\tconst char *pos;\n+\tconst char *nextat;\n+\n+\tfor (pos = elem + 2; *pos && *pos != ')'; pos = nextat) {\n+\t\tsize_t len = strcspn(pos, \",)\");\n+\t\tint i;\n+\n+\t\tif (pos[len] == ',')\n+\t\t\tnextat = pos + len + 1; /* handle ',' */\n+\t\telse\n+\t\t\tnextat = pos + len; /* handle ')' and '\\0' */\n+\n+\t\tif (!len)\n+\t\t\tcontinue;\n+\n+\t\tif (starts_with(pos, \"prefix:\")) {\n+\t\t\tchar *endptr;\n+\t\t\t*prefix_len = strtol(pos + 7, &endptr, 10);\n+\t\t\tif (endptr - pos != len)\n+\t\t\t\tdie(_(\"invalid parameter for pathspec magic 'prefix'\"));\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\tfor (i = 0; i < ARRAY_SIZE(pathspec_magic); i++) {\n+\t\t\tif (strlen(pathspec_magic[i].name) == len &&\n+\t\t\t    !strncmp(pathspec_magic[i].name, pos, len)) {\n+\t\t\t\t*magic |= pathspec_magic[i].bit;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t}\n+\n+\t\tif (ARRAY_SIZE(pathspec_magic) <= i)\n+\t\t\tdie(_(\"Invalid pathspec magic '%.*s' in '%s'\"),\n+\t\t\t    (int) len, pos, elem);\n+\t}\n+\n+\tif (*pos != ')')\n+\t\tdie(_(\"Missing ')' at the end of pathspec magic in '%s'\"),\n+\t\t    elem);\n+\tpos++;\n+\n+\treturn pos;\n+}\n+\n+/*\n  * Parse the pathspec element looking for short magic\n  *\n  * saves all magic in 'magic'\n@@ -218,41 +272,9 @@ static unsigned prefix_pathspec(struct pathspec_item *item,\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 + 1;\n-\t\t\telse\n-\t\t\t\t/* handle ')' and '\\0' */\n-\t\t\t\tnextat = copyfrom + len;\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\telement_magic |= pathspec_magic[i].bit;\n-\t\t\t\t\tbreak;\n-\t\t\t\t}\n-\t\t\t\tif (starts_with(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\tcopyfrom++;\n+\t\tcopyfrom = parse_long_magic(&element_magic,\n+\t\t\t\t\t    &pathspec_prefix,\n+\t\t\t\t\t    elt);\n \t} else {\n \t\t/* shorthand */\n \t\tcopyfrom = parse_short_magic(&element_magic, elt);\n-- \n2.8.0.rc3.226.g39d4020\n\n"},{"id":"307063","messageId":"1481061106-117775-15-git-send-email-bmwill@google.com","threadId":"44632","inReplyTo":"1481061106-117775-1-git-send-email-bmwill@google.com","subject":"[PATCH 14/17] pathspec: create parse_element_magic helper","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2016-12-06T21:51:43Z","receivedAt":"2016-12-06T21:53:47Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Factor out the logic responsible for the magic in a pathspec element\ninto its own function.\n\nAlso avoid calling into the parsing functions when\n`PATHSPEC_LITERAL_PATH` is specified since it causes magic to be\nignored and all paths to be treated as literals.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n pathspec.c | 35 +++++++++++++++++++----------------\n 1 file changed, 19 insertions(+), 16 deletions(-)\n\ndiff --git a/pathspec.c b/pathspec.c\nindex 1d28679..793caf1 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -244,6 +244,19 @@ static const char *parse_short_magic(unsigned *magic, const char *elem)\n \treturn pos;\n }\n \n+static const char *parse_element_magic(unsigned *magic, int *prefix_len,\n+\t\t\t\t       const char *elem)\n+{\n+\tif (elem[0] != ':' || get_literal_global())\n+\t\treturn elem; /* nothing to do */\n+\telse if (elem[1] == '(')\n+\t\t/* longhand */\n+\t\treturn parse_long_magic(magic, prefix_len, elem);\n+\telse\n+\t\t/* shorthand */\n+\t\treturn parse_short_magic(magic, elem);\n+}\n+\n /*\n  * Take an element of a pathspec and check for magic signatures.\n  * Append the result to the prefix. Return the magic bitmap.\n@@ -267,24 +280,14 @@ static unsigned prefix_pathspec(struct pathspec_item *item,\n \tchar *match;\n \tint i, pathspec_prefix = -1;\n \n-\tif (elt[0] != ':' || get_literal_global() ||\n-\t    (flags & PATHSPEC_LITERAL_PATH)) {\n-\t\t; /* nothing to do */\n-\t} else if (elt[1] == '(') {\n-\t\t/* longhand */\n-\t\tcopyfrom = parse_long_magic(&element_magic,\n-\t\t\t\t\t    &pathspec_prefix,\n-\t\t\t\t\t    elt);\n-\t} else {\n-\t\t/* shorthand */\n-\t\tcopyfrom = parse_short_magic(&element_magic, elt);\n-\t}\n-\n-\tmagic |= element_magic;\n-\n \t/* PATHSPEC_LITERAL_PATH ignores magic */\n-\tif (!(flags & PATHSPEC_LITERAL_PATH))\n+\tif (!(flags & PATHSPEC_LITERAL_PATH)) {\n+\t\tcopyfrom = parse_element_magic(&element_magic,\n+\t\t\t\t\t       &pathspec_prefix,\n+\t\t\t\t\t       elt);\n+\t\tmagic |= element_magic;\n \t\tmagic |= get_global_magic(element_magic);\n+\t}\n \n \tif (pathspec_prefix >= 0 &&\n \t    (prefixlen || (prefix && *prefix)))\n-- \n2.8.0.rc3.226.g39d4020\n\n"},{"id":"307064","messageId":"1481061106-117775-12-git-send-email-bmwill@google.com","threadId":"44632","inReplyTo":"1481061106-117775-1-git-send-email-bmwill@google.com","subject":"[PATCH 11/17] pathspec: factor global magic into its own function","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2016-12-06T21:51:40Z","receivedAt":"2016-12-06T21:53:49Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Create helper functions to read the global magic environment variables\nin additon to factoring out the global magic gathering logic into its\nown function.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n pathspec.c | 120 +++++++++++++++++++++++++++++++++++++------------------------\n 1 file changed, 74 insertions(+), 46 deletions(-)\n\ndiff --git a/pathspec.c b/pathspec.c\nindex 5afebd3..08e76f6 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -87,6 +87,74 @@ static void prefix_magic(struct strbuf *sb, int prefixlen, unsigned magic)\n \tstrbuf_addf(sb, \",prefix:%d)\", prefixlen);\n }\n \n+static inline int get_literal_global(void)\n+{\n+\tstatic int literal_global = -1;\n+\n+\tif (literal_global < 0)\n+\t\tliteral_global = git_env_bool(GIT_LITERAL_PATHSPECS_ENVIRONMENT,\n+\t\t\t\t\t      0);\n+\treturn literal_global;\n+}\n+\n+static inline int get_glob_global(void)\n+{\n+\tstatic int glob_global = -1;\n+\n+\tif (glob_global < 0)\n+\t\tglob_global = git_env_bool(GIT_GLOB_PATHSPECS_ENVIRONMENT, 0);\n+\treturn glob_global;\n+}\n+\n+static inline int get_noglob_global(void)\n+{\n+\tstatic int noglob_global = -1;\n+\n+\tif (noglob_global < 0)\n+\t\tnoglob_global = git_env_bool(GIT_NOGLOB_PATHSPECS_ENVIRONMENT,\n+\t\t\t\t\t     0);\n+\treturn noglob_global;\n+}\n+\n+static inline int get_icase_global(void)\n+{\n+\tstatic int icase_global = -1;\n+\n+\tif (icase_global < 0)\n+\t\ticase_global = git_env_bool(GIT_ICASE_PATHSPECS_ENVIRONMENT, 0);\n+\n+\treturn icase_global;\n+}\n+\n+static int get_global_magic(int element_magic)\n+{\n+\tint global_magic = 0;\n+\n+\tif (get_literal_global())\n+\t\tglobal_magic |= PATHSPEC_LITERAL;\n+\n+\t/* --glob-pathspec is overridden by :(literal) */\n+\tif (get_glob_global() && !(element_magic & PATHSPEC_LITERAL))\n+\t\tglobal_magic |= PATHSPEC_GLOB;\n+\n+\tif (get_glob_global() && get_noglob_global())\n+\t\tdie(_(\"global 'glob' and 'noglob' pathspec settings are incompatible\"));\n+\n+\tif (get_icase_global())\n+\t\tglobal_magic |= PATHSPEC_ICASE;\n+\n+\tif ((global_magic & PATHSPEC_LITERAL) &&\n+\t    (global_magic & ~PATHSPEC_LITERAL))\n+\t\tdie(_(\"global 'literal' pathspec setting is incompatible \"\n+\t\t      \"with all other global pathspec settings\"));\n+\n+\t/* --noglob-pathspec adds :(literal) _unless_ :(glob) is specified */\n+\tif (get_noglob_global() && !(element_magic & PATHSPEC_GLOB))\n+\t\tglobal_magic |= PATHSPEC_LITERAL;\n+\n+\treturn global_magic;\n+}\n+\n /*\n  * Take an element of a pathspec and check for magic signatures.\n  * Append the result to the prefix. Return the magic bitmap.\n@@ -105,46 +173,12 @@ 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-\tstatic int glob_global = -1;\n-\tstatic int noglob_global = -1;\n-\tstatic int icase_global = -1;\n-\tunsigned magic = 0, element_magic = 0, global_magic = 0;\n+\tunsigned magic = 0, element_magic = 0;\n \tconst char *copyfrom = elt;\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 (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-\n-\tif (icase_global < 0)\n-\t\ticase_global = git_env_bool(GIT_ICASE_PATHSPECS_ENVIRONMENT, 0);\n-\tif (icase_global)\n-\t\tglobal_magic |= PATHSPEC_ICASE;\n-\n-\tif ((global_magic & PATHSPEC_LITERAL) &&\n-\t    (global_magic & ~PATHSPEC_LITERAL))\n-\t\tdie(_(\"global 'literal' pathspec setting is incompatible \"\n-\t\t      \"with all other global pathspec settings\"));\n-\n-\tif (flags & PATHSPEC_LITERAL_PATH)\n-\t\tglobal_magic = 0;\n-\n-\tif (elt[0] != ':' || literal_global ||\n+\tif (elt[0] != ':' || get_literal_global() ||\n \t    (flags & PATHSPEC_LITERAL_PATH)) {\n \t\t; /* nothing to do */\n \t} else if (elt[1] == '(') {\n@@ -208,15 +242,9 @@ static unsigned prefix_pathspec(struct pathspec_item *item,\n \n \tmagic |= element_magic;\n \n-\t/* --noglob-pathspec adds :(literal) _unless_ :(glob) is specified */\n-\tif (noglob_global && !(magic & PATHSPEC_GLOB))\n-\t\tglobal_magic |= PATHSPEC_LITERAL;\n-\n-\t/* --glob-pathspec is overridden by :(literal) */\n-\tif ((global_magic & PATHSPEC_GLOB) && (magic & PATHSPEC_LITERAL))\n-\t\tglobal_magic &= ~PATHSPEC_GLOB;\n-\n-\tmagic |= global_magic;\n+\t/* PATHSPEC_LITERAL_PATH ignores magic */\n+\tif (!(flags & PATHSPEC_LITERAL_PATH))\n+\t\tmagic |= get_global_magic(element_magic);\n \n \tif (pathspec_prefix >= 0 &&\n \t    (prefixlen || (prefix && *prefix)))\n@@ -242,7 +270,7 @@ static unsigned prefix_pathspec(struct pathspec_item *item,\n \t * original. Useful for passing to another command.\n \t */\n \tif ((flags & PATHSPEC_PREFIX_ORIGIN) &&\n-\t    prefixlen && !literal_global) {\n+\t    prefixlen && !get_literal_global()) {\n \t\tstruct strbuf sb = STRBUF_INIT;\n \n \t\t/* Preserve the actual prefix length of each pattern */\n-- \n2.8.0.rc3.226.g39d4020\n\n"},{"id":"307065","messageId":"1481061106-117775-13-git-send-email-bmwill@google.com","threadId":"44632","inReplyTo":"1481061106-117775-1-git-send-email-bmwill@google.com","subject":"[PATCH 12/17] pathspec: create parse_short_magic function","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2016-12-06T21:51:41Z","receivedAt":"2016-12-06T21:53:50Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Factor out the logic responsible for parsing short magic into its own\nfunction.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n pathspec.c | 54 ++++++++++++++++++++++++++++++++++++------------------\n 1 file changed, 36 insertions(+), 18 deletions(-)\n\ndiff --git a/pathspec.c b/pathspec.c\nindex 08e76f6..d4d4839 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -156,6 +156,41 @@ static int get_global_magic(int element_magic)\n }\n \n /*\n+ * Parse the pathspec element looking for short magic\n+ *\n+ * saves all magic in 'magic'\n+ * returns the position in 'elem' after all magic has been parsed\n+ */\n+static const char *parse_short_magic(unsigned *magic, const char *elem)\n+{\n+\tconst char *pos;\n+\n+\tfor (pos = elem + 1; *pos && *pos != ':'; pos++) {\n+\t\tchar ch = *pos;\n+\t\tint i;\n+\n+\t\tif (!is_pathspec_magic(ch))\n+\t\t\tbreak;\n+\n+\t\tfor (i = 0; i < ARRAY_SIZE(pathspec_magic); i++) {\n+\t\t\tif (pathspec_magic[i].mnemonic == ch) {\n+\t\t\t\t*magic |= pathspec_magic[i].bit;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t}\n+\n+\t\tif (ARRAY_SIZE(pathspec_magic) <= i)\n+\t\t\tdie(_(\"Unimplemented pathspec magic '%c' in '%s'\"),\n+\t\t\t    ch, elem);\n+\t}\n+\n+\tif (*pos == ':')\n+\t\tpos++;\n+\n+\treturn pos;\n+}\n+\n+/*\n  * Take an element of a pathspec and check for magic signatures.\n  * Append the result to the prefix. Return the magic bitmap.\n  *\n@@ -220,24 +255,7 @@ static unsigned prefix_pathspec(struct pathspec_item *item,\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\telement_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-\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\tcopyfrom = parse_short_magic(&element_magic, elt);\n \t}\n \n \tmagic |= element_magic;\n-- \n2.8.0.rc3.226.g39d4020\n\n"},{"id":"307066","messageId":"1481061106-117775-8-git-send-email-bmwill@google.com","threadId":"44632","inReplyTo":"1481061106-117775-1-git-send-email-bmwill@google.com","subject":"[PATCH 07/17] mv: small code cleanup","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2016-12-06T21:51:36Z","receivedAt":"2016-12-06T21:53:52Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Now that the call to 'parse_pathspec()' doesn't modify the passed in\nconst char **array there isn't a need to duplicate the pathspec element\nprior to freeing the intermediate strings.  This small cleanup just\nmakes the code a bit easier to read.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n builtin/mv.c | 3 +--\n 1 file changed, 1 insertion(+), 2 deletions(-)\n\ndiff --git a/builtin/mv.c b/builtin/mv.c\nindex 4df4a12..b7cceb6 100644\n--- a/builtin/mv.c\n+++ b/builtin/mv.c\n@@ -56,9 +56,8 @@ static const char **internal_copy_pathspec(const char *prefix,\n \n \t/* Copy the pathspec and free the old intermediate strings */\n \tfor (i = 0; i < count; i++) {\n-\t\tconst char *match = xstrdup(ps.items[i].match);\n \t\tfree((char *) result[i]);\n-\t\tresult[i] = match;\n+\t\tresult[i] = xstrdup(ps.items[i].match);\n \t}\n \n \tclear_pathspec(&ps);\n-- \n2.8.0.rc3.226.g39d4020\n\n"},{"id":"307067","messageId":"1481061106-117775-7-git-send-email-bmwill@google.com","threadId":"44632","inReplyTo":"1481061106-117775-1-git-send-email-bmwill@google.com","subject":"[PATCH 06/17] pathspec: copy and free owned memory","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2016-12-06T21:51:35Z","receivedAt":"2016-12-06T21:53:53Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"The 'original' string entry in a pathspec_item is only duplicated some\nof the time, instead always make a copy of the original and take\nownership of the memory.\n\nSince both 'match' and 'original' string entries in a pathspec_item are\nowned by the pathspec struct, they need to be freed when clearing the\npathspec struct (in 'clear_pathspec()') and duplicated when copying the\npathspec struct (in 'copy_pathspec()').\n\nAlso change the type of 'match' and 'original' to 'char *' in order to\nmore explicitly show the ownership of the memory.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n pathspec.c | 22 ++++++++++++++++++----\n pathspec.h |  4 ++--\n 2 files changed, 20 insertions(+), 6 deletions(-)\n\ndiff --git a/pathspec.c b/pathspec.c\nindex 1f918cb..8f367f0 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -259,8 +259,9 @@ static unsigned prefix_pathspec(struct pathspec_item *item,\n \t\t}\n \t\tstrbuf_addstr(&sb, match);\n \t\titem->original = strbuf_detach(&sb, NULL);\n-\t} else\n-\t\titem->original = elt;\n+\t} else {\n+\t\titem->original = xstrdup(elt);\n+\t}\n \titem->len = strlen(item->match);\n \titem->prefix = prefixlen;\n \n@@ -388,8 +389,8 @@ void parse_pathspec(struct pathspec *pathspec,\n \t\t\tdie(\"BUG: PATHSPEC_PREFER_CWD requires arguments\");\n \n \t\tpathspec->items = item = xcalloc(1, sizeof(*item));\n-\t\titem->match = prefix;\n-\t\titem->original = prefix;\n+\t\titem->match = xstrdup(prefix);\n+\t\titem->original = xstrdup(prefix);\n \t\titem->nowildcard_len = item->len = strlen(prefix);\n \t\titem->prefix = item->len;\n \t\tpathspec->nr = 1;\n@@ -453,13 +454,26 @@ void parse_pathspec(struct pathspec *pathspec,\n \n void copy_pathspec(struct pathspec *dst, const struct pathspec *src)\n {\n+\tint i;\n+\n \t*dst = *src;\n \tALLOC_ARRAY(dst->items, dst->nr);\n \tCOPY_ARRAY(dst->items, src->items, dst->nr);\n+\n+\tfor (i = 0; i < dst->nr; i++) {\n+\t\tdst->items[i].match = xstrdup(src->items[i].match);\n+\t\tdst->items[i].original = xstrdup(src->items[i].original);\n+\t}\n }\n \n void clear_pathspec(struct pathspec *pathspec)\n {\n+\tint i;\n+\n+\tfor (i = 0; i < pathspec->nr; i++) {\n+\t\tfree(pathspec->items[i].match);\n+\t\tfree(pathspec->items[i].original);\n+\t}\n \tfree(pathspec->items);\n \tpathspec->items = NULL;\n }\ndiff --git a/pathspec.h b/pathspec.h\nindex 70a592e..49fd823 100644\n--- a/pathspec.h\n+++ b/pathspec.h\n@@ -25,8 +25,8 @@ struct pathspec {\n \tunsigned magic;\n \tint max_depth;\n \tstruct pathspec_item {\n-\t\tconst char *match;\n-\t\tconst char *original;\n+\t\tchar *match;\n+\t\tchar *original;\n \t\tunsigned magic;\n \t\tint len, prefix;\n \t\tint nowildcard_len;\n-- \n2.8.0.rc3.226.g39d4020\n\n"},{"id":"307068","messageId":"1481061106-117775-5-git-send-email-bmwill@google.com","threadId":"44632","inReplyTo":"1481061106-117775-1-git-send-email-bmwill@google.com","subject":"[PATCH 04/17] ls-tree: convert show_recursive to use the pathspec struct interface","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2016-12-06T21:51:33Z","receivedAt":"2016-12-06T21:53:56Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Convert 'show_recursive()' to use the pathspec struct interface from\nusing the '_raw' entry in the pathspec struct.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n builtin/ls-tree.c | 12 +++++-------\n 1 file changed, 5 insertions(+), 7 deletions(-)\n\ndiff --git a/builtin/ls-tree.c b/builtin/ls-tree.c\nindex 0e30d86..e0f4307 100644\n--- a/builtin/ls-tree.c\n+++ b/builtin/ls-tree.c\n@@ -31,21 +31,18 @@ static const  char * const ls_tree_usage[] = {\n \n static int show_recursive(const char *base, int baselen, const char *pathname)\n {\n-\tconst char **s;\n+\tint i;\n \n \tif (ls_options & LS_RECURSIVE)\n \t\treturn 1;\n \n-\ts = pathspec._raw;\n-\tif (!s)\n+\tif (!pathspec.nr)\n \t\treturn 0;\n \n-\tfor (;;) {\n-\t\tconst char *spec = *s++;\n+\tfor (i = 0; i < pathspec.nr; i++) {\n+\t\tconst char *spec = pathspec.items[i].match;\n \t\tint len, speclen;\n \n-\t\tif (!spec)\n-\t\t\treturn 0;\n \t\tif (strncmp(base, spec, baselen))\n \t\t\tcontinue;\n \t\tlen = strlen(pathname);\n@@ -59,6 +56,7 @@ static int show_recursive(const char *base, int baselen, const char *pathname)\n \t\t\tcontinue;\n \t\treturn 1;\n \t}\n+\treturn 0;\n }\n \n static int show_tree(const unsigned char *sha1, struct strbuf *base,\n-- \n2.8.0.rc3.226.g39d4020\n\n"},{"id":"307069","messageId":"1481061106-117775-6-git-send-email-bmwill@google.com","threadId":"44632","inReplyTo":"1481061106-117775-1-git-send-email-bmwill@google.com","subject":"[PATCH 05/17] pathspec: remove the deprecated get_pathspec function","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2016-12-06T21:51:34Z","receivedAt":"2016-12-06T21:53:58Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Now that all callers of the old 'get_pathspec' interface have been\nmigrated to use the new pathspec struct interface it can be removed\nfrom the codebase.\n\nSince there are no more users of the '_raw' field in the pathspec struct\nit can also be removed.  This patch also removes the old functionality\nof modifying the const char **argv array that was passed into\nparse_pathspec.  Instead the constructed 'match' string (which is a\npathspec element with the prefix prepended) is only stored in its\ncorresponding pathspec_item entry.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n Documentation/technical/api-setup.txt |  2 --\n cache.h                               |  1 -\n pathspec.c                            | 42 +++--------------------------------\n pathspec.h                            |  1 -\n 4 files changed, 3 insertions(+), 43 deletions(-)\n\ndiff --git a/Documentation/technical/api-setup.txt b/Documentation/technical/api-setup.txt\nindex 540e455..eb1fa98 100644\n--- a/Documentation/technical/api-setup.txt\n+++ b/Documentation/technical/api-setup.txt\n@@ -27,8 +27,6 @@ parse_pathspec(). This function takes several arguments:\n \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 them\n politely. At a lower level, different pathspec-related functions may\n not support the same set of features. Such pathspec-sensitive\ndiff --git a/cache.h b/cache.h\nindex a50a61a..0f80e01 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -514,7 +514,6 @@ extern void set_git_work_tree(const char *tree);\n \n #define ALTERNATE_DB_ENVIRONMENT \"GIT_ALTERNATE_OBJECT_DIRECTORIES\"\n \n-extern const char **get_pathspec(const char *prefix, const char **pathspec);\n extern void setup_work_tree(void);\n extern const char *setup_git_directory_gently(int *);\n extern const char *setup_git_directory(void);\ndiff --git a/pathspec.c b/pathspec.c\nindex 22ca74a..1f918cb 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -103,7 +103,7 @@ static void prefix_short_magic(struct strbuf *sb, int prefixlen,\n  */\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\tunsigned flags,\n \t\t\t\tconst char *prefix, int prefixlen,\n \t\t\t\tconst char *elt)\n {\n@@ -240,7 +240,7 @@ static unsigned prefix_pathspec(struct pathspec_item *item,\n \t\tif (!match)\n \t\t\tdie(_(\"%s: '%s' is outside repository\"), elt, copyfrom);\n \t}\n-\t*raw = item->match = match;\n+\titem->match = match;\n \t/*\n \t * Prefix the pathspec (keep all magic) and assign to\n \t * original. Useful for passing to another command.\n@@ -381,8 +381,6 @@ void parse_pathspec(struct pathspec *pathspec,\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@@ -394,10 +392,7 @@ void parse_pathspec(struct pathspec *pathspec,\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;\n-\t\tpathspec->_raw = raw;\n \t\treturn;\n \t}\n \n@@ -415,7 +410,6 @@ void parse_pathspec(struct pathspec *pathspec,\n \tpathspec->nr = n;\n \tALLOC_ARRAY(pathspec->items, n);\n \titem = pathspec->items;\n-\tpathspec->_raw = argv;\n \tprefixlen = prefix ? strlen(prefix) : 0;\n \n \tfor (i = 0; i < n; i++) {\n@@ -423,7 +417,7 @@ void parse_pathspec(struct pathspec *pathspec,\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\tflags,\n \t\t\t\t\t\tprefix, prefixlen, entry);\n \t\tif ((flags & PATHSPEC_LITERAL_PATH) &&\n \t\t    !(magic_mask & PATHSPEC_LITERAL))\n@@ -457,36 +451,6 @@ void parse_pathspec(struct pathspec *pathspec,\n \t}\n }\n \n-/*\n- * N.B. get_pathspec() is deprecated in favor of the \"struct pathspec\"\n- * based interface - see pathspec.c:parse_pathspec().\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-\tstruct pathspec ps;\n-\tparse_pathspec(&ps,\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;\n-}\n-\n void copy_pathspec(struct pathspec *dst, const struct pathspec *src)\n {\n \t*dst = *src;\ndiff --git a/pathspec.h b/pathspec.h\nindex 59809e4..70a592e 100644\n--- a/pathspec.h\n+++ b/pathspec.h\n@@ -19,7 +19,6 @@\n #define PATHSPEC_ONESTAR 1\t/* the pathspec pattern satisfies GFNM_ONESTAR */\n \n struct pathspec {\n-\tconst char **_raw; /* get_pathspec() result, not freed by clear_pathspec() */\n \tint nr;\n \tunsigned int has_wildcard:1;\n \tunsigned int recursive:1;\n-- \n2.8.0.rc3.226.g39d4020\n\n"},{"id":"307070","messageId":"1481061106-117775-18-git-send-email-bmwill@google.com","threadId":"44632","inReplyTo":"1481061106-117775-1-git-send-email-bmwill@google.com","subject":"[PATCH 17/17] pathspec: remove outdated comment","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2016-12-06T21:51:46Z","receivedAt":"2016-12-06T21:54:16Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Remove part of the function header comment to prefix_pathspec as it is\nno longer relevant.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n pathspec.c | 9 ---------\n 1 file changed, 9 deletions(-)\n\ndiff --git a/pathspec.c b/pathspec.c\nindex 8a07b02..66db257 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -298,15 +298,6 @@ static void strip_submodule_slash_expensive(struct pathspec_item *item)\n /*\n  * Take an element of a pathspec and check for magic signatures.\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- *\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 unsigned prefix_pathspec(struct pathspec_item *item,\n \t\t\t\tunsigned flags,\n-- \n2.8.0.rc3.226.g39d4020\n\n"},{"id":"307071","messageId":"1481061106-117775-16-git-send-email-bmwill@google.com","threadId":"44632","inReplyTo":"1481061106-117775-1-git-send-email-bmwill@google.com","subject":"[PATCH 15/17] pathspec: create strip submodule slash helpers","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2016-12-06T21:51:44Z","receivedAt":"2016-12-06T21:54:18Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Factor out the logic responsible for stripping the trailing slash on\npathspecs referencing submodules into its own function.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n pathspec.c | 68 ++++++++++++++++++++++++++++++++++++++------------------------\n 1 file changed, 42 insertions(+), 26 deletions(-)\n\ndiff --git a/pathspec.c b/pathspec.c\nindex 793caf1..41aa213 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -257,6 +257,44 @@ static const char *parse_element_magic(unsigned *magic, int *prefix_len,\n \t\treturn parse_short_magic(magic, elem);\n }\n \n+static void strip_submodule_slash_cheap(struct pathspec_item *item)\n+{\n+\tint i;\n+\n+\tif ((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\titem->match[item->len] = '\\0';\n+\t}\n+}\n+\n+static void strip_submodule_slash_expensive(struct pathspec_item *item)\n+{\n+\tint i;\n+\n+\tfor (i = 0; i < active_nr; i++) {\n+\t\tstruct cache_entry *ce = active_cache[i];\n+\t\tint ce_len = ce_namelen(ce);\n+\n+\t\tif (!S_ISGITLINK(ce->ce_mode))\n+\t\t\tcontinue;\n+\n+\t\tif (item->len <= ce_len || item->match[ce_len] != '/' ||\n+\t\t    memcmp(ce->name, item->match, ce_len))\n+\t\t\tcontinue;\n+\n+\t\tif (item->len == ce_len + 1) {\n+\t\t\t/* strip trailing slash */\n+\t\t\titem->len--;\n+\t\t\titem->match[item->len] = '\\0';\n+\t\t} else {\n+\t\t\tdie (_(\"Pathspec '%s' is in submodule '%.*s'\"),\n+\t\t\t     item->original, ce_len, ce->name);\n+\t\t}\n+\t}\n+}\n+\n /*\n  * Take an element of a pathspec and check for magic signatures.\n  * Append the result to the prefix. Return the magic bitmap.\n@@ -278,7 +316,7 @@ static unsigned prefix_pathspec(struct pathspec_item *item,\n \tunsigned magic = 0, element_magic = 0;\n \tconst char *copyfrom = elt;\n \tchar *match;\n-\tint i, pathspec_prefix = -1;\n+\tint pathspec_prefix = -1;\n \n \t/* PATHSPEC_LITERAL_PATH ignores magic */\n \tif (!(flags & PATHSPEC_LITERAL_PATH)) {\n@@ -327,33 +365,11 @@ static unsigned prefix_pathspec(struct pathspec_item *item,\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-\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+\tif (flags & PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP)\n+\t    strip_submodule_slash_cheap(item);\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+\t    strip_submodule_slash_expensive(item);\n \n \tif (magic & PATHSPEC_LITERAL)\n \t\titem->nowildcard_len = item->len;\n-- \n2.8.0.rc3.226.g39d4020\n\n"},{"id":"307075","messageId":"CAGZ79kausxZMinZymG8mE4jQ1pi4yJ80WRBUGFhUK7mmfOBCvg@mail.gmail.com","threadId":"44632","inReplyTo":"1481061106-117775-11-git-send-email-bmwill@google.com","subject":"Re: [PATCH 10/17] pathspec: simpler logic to prefix original pathspec elements","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2016-12-06T22:20:19Z","receivedAt":"2016-12-06T22:26:46Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"On Tue, Dec 6, 2016 at 1:51 PM, Brandon Williams <bmwill@google.com> wrote:\n\n>                 struct strbuf sb = STRBUF_INIT;\n> -               if (prefixlen && !literal_global) {\n> -                       /* Preserve the actual prefix length of each pattern */\n> -                       if (short_magic)\n> -                               prefix_short_magic(&sb, prefixlen, short_magic);\n> -                       else if (long_magic_end) {\n> -                               strbuf_add(&sb, elt, long_magic_end - elt);\n> -                               strbuf_addf(&sb, \",prefix:%d)\", prefixlen);\n> -                       } else\n> -                               strbuf_addf(&sb, \":(prefix:%d)\", prefixlen);\n\nThis fixes the issue with add -p . mentioned somewhere else on the mailing list.\n\n> -               }\n> +\n> +               /* Preserve the actual prefix length of each pattern */\n> +               prefix_magic(&sb, prefixlen, element_magic);\n> +\n\nDid you find a reason why we passed magic literally, i.e. short magic\nwas passed as short magic and long magic as long magic before?\n\nI cannot think of any reason why that would have been the case,\nbut I assume there had to be a reason for that.\n\n\nAnother note: This collides with the attr system refactoring, which I\npostpone redoing until the submodule checkout is done, so maybe\nyou want to pickup this patch:\nhttps://public-inbox.org/git/20161110203428.30512-31-sbeller@google.com/\nwhich only relies on one patch prior\nhttps://public-inbox.org/git/20161110203428.30512-30-sbeller@google.com/\n"},{"id":"307076","messageId":"CAGZ79kaQNQPYudRLEz8-7NoggsM+um2mmhX+9CZQohdUfmp2tQ@mail.gmail.com","threadId":"44632","inReplyTo":"1481061106-117775-17-git-send-email-bmwill@google.com","subject":"Re: [PATCH 16/17] pathspec: small readability changes","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2016-12-06T22:30:09Z","receivedAt":"2016-12-06T22:30:14Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"On Tue, Dec 6, 2016 at 1:51 PM, Brandon Williams <bmwill@google.com> wrote:\n> A few small changes to improve readability.  This is done by grouping related\n> assignments, adding blank lines, ensuring lines are <80 characters, etc.\n\nThe 'etc' sounds a bit sloppy in the commit message.\nMaybe s/etc/and adding proper comments/ ?\n\nCode looks good.\n"},{"id":"307077","messageId":"20161206223757.GC103573@google.com","threadId":"44632","inReplyTo":"CAGZ79kausxZMinZymG8mE4jQ1pi4yJ80WRBUGFhUK7mmfOBCvg@mail.gmail.com","subject":"Re: [PATCH 10/17] pathspec: simpler logic to prefix original pathspec elements","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2016-12-06T22:37:57Z","receivedAt":"2016-12-06T22:38:13Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"On 12/06, Stefan Beller wrote:\n> On Tue, Dec 6, 2016 at 1:51 PM, Brandon Williams <bmwill@google.com> wrote:\n> \n> >                 struct strbuf sb = STRBUF_INIT;\n> > -               if (prefixlen && !literal_global) {\n> > -                       /* Preserve the actual prefix length of each pattern */\n> > -                       if (short_magic)\n> > -                               prefix_short_magic(&sb, prefixlen, short_magic);\n> > -                       else if (long_magic_end) {\n> > -                               strbuf_add(&sb, elt, long_magic_end - elt);\n> > -                               strbuf_addf(&sb, \",prefix:%d)\", prefixlen);\n> > -                       } else\n> > -                               strbuf_addf(&sb, \":(prefix:%d)\", prefixlen);\n> \n> This fixes the issue with add -p . mentioned somewhere else on the mailing list.\n>\n> > -               }\n> > +\n> > +               /* Preserve the actual prefix length of each pattern */\n> > +               prefix_magic(&sb, prefixlen, element_magic);\n> > +\n> \n> Did you find a reason why we passed magic literally, i.e. short magic\n> was passed as short magic and long magic as long magic before?\n> \n> I cannot think of any reason why that would have been the case,\n> but I assume there had to be a reason for that.\n\nnope, perhaps it was because we technically already have the long magic\nstring and the short magic needs to be converted to long magic (as you\ncan't mix short and long magic).\n\n> Another note: This collides with the attr system refactoring, which I\n> postpone redoing until the submodule checkout is done, so maybe\n> you want to pickup this patch:\n> https://public-inbox.org/git/20161110203428.30512-31-sbeller@google.com/\n> which only relies on one patch prior\n> https://public-inbox.org/git/20161110203428.30512-30-sbeller@google.com/\n\nAfter looking at those patches I think I do something extremely similar\nin a future patch in this series, the parse_long_magic patch.\n\n-- \nBrandon Williams\n"},{"id":"307099","messageId":"CACsJy8Bm+Nif_PL1=BzTYLKGrnz94rjKOB=_PXz6OB47Js6v2A@mail.gmail.com","threadId":"44632","inReplyTo":"1481061106-117775-2-git-send-email-bmwill@google.com","subject":"Re: [PATCH 01/17] mv: convert to using pathspec struct interface","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2016-12-07T10:07:24Z","receivedAt":"2016-12-07T10:08:00Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Wed, Dec 7, 2016 at 4:51 AM, Brandon Williams <bmwill@google.com> wrote:\n> Convert the 'internal_copy_pathspec()' function to use the pathspec\n> struct interface from using the deprecated 'get_pathspec()' interface.\n>\n> In addition to this, fix a memory leak caused by only duplicating some\n> of the pathspec elements.  Instead always duplicate all of the the\n> pathspec elements as an intermediate step (with modificationed based on\n> the passed in flags).  This way the intermediate strings can then be\n> freed prior to duplicating the result of parse_pathspec (which contains\n> each of the elements with the prefix prepended).\n>\n> Signed-off-by: Brandon Williams <bmwill@google.com>\n> ---\n>  builtin/mv.c | 45 ++++++++++++++++++++++++++++++++-------------\n>  1 file changed, 32 insertions(+), 13 deletions(-)\n\nStefan did something similar last year [1] but I couldn't find why it\ndid not get merged. Not sure if the reasons are still relevant or\nnot...\n\n[1] http://public-inbox.org/git/%3C1438885632-26470-1-git-send-email-sbeller@google.com%3E/\n\n> diff --git a/builtin/mv.c b/builtin/mv.c\n> index 2f43877..4df4a12 100644\n> --- a/builtin/mv.c\n> +++ b/builtin/mv.c\n> @@ -4,6 +4,7 @@\n>   * Copyright (C) 2006 Johannes Schindelin\n>   */\n>  #include \"builtin.h\"\n> +#include \"pathspec.h\"\n>  #include \"lockfile.h\"\n>  #include \"dir.h\"\n>  #include \"cache-tree.h\"\n> @@ -25,25 +26,43 @@ static const char **internal_copy_pathspec(const char *prefix,\n>  {\n>         int i;\n>         const char **result;\n> +       struct pathspec ps;\n>         ALLOC_ARRAY(result, count + 1);\n> -       COPY_ARRAY(result, pathspec, count);\n> -       result[count] = NULL;\n> +\n> +       /* Create an intermediate copy of the pathspec based on the flags */\n>         for (i = 0; i < count; i++) {\n> -               int length = strlen(result[i]);\n> +               int length = strlen(pathspec[i]);\n>                 int to_copy = length;\n> +               char *it;\n>                 while (!(flags & KEEP_TRAILING_SLASH) &&\n> -                      to_copy > 0 && is_dir_sep(result[i][to_copy - 1]))\n> +                      to_copy > 0 && is_dir_sep(pathspec[i][to_copy - 1]))\n>                         to_copy--;\n> -               if (to_copy != length || flags & DUP_BASENAME) {\n> -                       char *it = xmemdupz(result[i], to_copy);\n> -                       if (flags & DUP_BASENAME) {\n> -                               result[i] = xstrdup(basename(it));\n> -                               free(it);\n> -                       } else\n> -                               result[i] = it;\n> -               }\n> +\n> +               it = xmemdupz(pathspec[i], to_copy);\n> +               if (flags & DUP_BASENAME) {\n> +                       result[i] = xstrdup(basename(it));\n> +                       free(it);\n> +               } else\n> +                       result[i] = it;\n> +       }\n> +       result[count] = NULL;\n> +\n> +       parse_pathspec(&ps,\n> +                      PATHSPEC_ALL_MAGIC &\n> +                      ~(PATHSPEC_FROMTOP | PATHSPEC_LITERAL),\n> +                      PATHSPEC_KEEP_ORDER | PATHSPEC_PREFER_CWD,\n> +                      prefix, result);\n> +       assert(count == ps.nr);\n> +\n> +       /* Copy the pathspec and free the old intermediate strings */\n> +       for (i = 0; i < count; i++) {\n> +               const char *match = xstrdup(ps.items[i].match);\n> +               free((char *) result[i]);\n> +               result[i] = match;\n\nSigh.. it looks so weird that we do all the parsing (in a _copy_\npathspec function) then remove struct pathspec and return the plain\nstring. I guess we can't do anything more until we rework cmd_mv code\nto handle pathspec natively.\n\nAt the least I think we should rename this function to something else.\nBut if you have time I really wish we could kill this function. I\nhaven't stared at cmd_mv() long and hard, but it looks to me that we\ncombining two separate functionalities in the same function here.\n\nIf \"mv\" takes n arguments, then the first <n-1> arguments may be\npathspec, the last one is always a plain path. The \"dest_path =\ninternal_copy_pathspec...\" could be as simple as \"dest_path =\nprefix_path(argv[argc - 1])\". the special treatment for this last\nargument [1] can live here. Then, we can do parse_pathspec for the\n<n-1> arguments in cmd_mv(). It's still far from perfect, because\ncmd_mv can't handle pathspec properly, but it reduces the messy mess\nin internal_copy_pathspec a bit, I hope.\n\n[1] c57f628 (mv: let 'git mv file no-such-dir/' error out - 2013-12-03)\n\n>         }\n> -       return get_pathspec(prefix, result);\n> +\n> +       clear_pathspec(&ps);\n> +       return result;\n>  }\n>\n>  static const char *add_slash(const char *path)\n> --\n> 2.8.0.rc3.226.g39d4020\n>\n\n\n\n-- \nDuy\n"},{"id":"307101","messageId":"CACsJy8AX09pxkyUkLU905v1MpXocLzV5bK0APuNmMUNb50Lavg@mail.gmail.com","threadId":"44632","inReplyTo":"1481061106-117775-3-git-send-email-bmwill@google.com","subject":"Re: [PATCH 02/17] dir: convert create_simplify to use the pathspec struct interface","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2016-12-07T10:17:42Z","receivedAt":"2016-12-07T10:18:18Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Wed, Dec 7, 2016 at 4:51 AM, Brandon Williams <bmwill@google.com> wrote:\n> Convert 'create_simplify()' to use the pathspec struct interface from\n> using the '_raw' entry in the pathspec.\n\nIt would be even better to kill this create_simplify() and let\nsimplify_away() handle struct pathspec directly.\n\nThere is a bug in this code, that might have been found if we\nsimpify_away() handled pathspec directly: the memcmp() in\nsimplify_away() will not play well with :(icase) magic. My bad. If\n:(icase) is used, the easiest/safe way is simplify nothing. Later on\nmaybe we can teach simplify_away() to do strncasecmp instead. We could\nignore exclude patterns there too (although not excluding is not a\nbug).\n-- \nDuy\n"},{"id":"307102","messageId":"CACsJy8BsGVrUoFFFEqdLS-h4XYCkFg-gbx+BeWmGd8srupNWqw@mail.gmail.com","threadId":"44632","inReplyTo":"1481061106-117775-4-git-send-email-bmwill@google.com","subject":"Re: [PATCH 03/17] dir: convert fill_directory to use the pathspec struct interface","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2016-12-07T10:24:05Z","receivedAt":"2016-12-07T10:39:10Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Wed, Dec 7, 2016 at 4:51 AM, Brandon Williams <bmwill@google.com> wrote:\n> Convert 'fill_directory()' to use the pathspec struct interface from\n> using the '_raw' entry in the pathspec struct.\n>\n> Signed-off-by: Brandon Williams <bmwill@google.com>\n> ---\n>  dir.c | 3 ++-\n>  1 file changed, 2 insertions(+), 1 deletion(-)\n>\n> diff --git a/dir.c b/dir.c\n> index 7df292b..8730a4f 100644\n> --- a/dir.c\n> +++ b/dir.c\n> @@ -188,7 +188,8 @@ int fill_directory(struct dir_struct *dir, const struct pathspec *pathspec)\n>         len = common_prefix_len(pathspec);\n>\n>         /* Read the directory and prune it */\n> -       read_directory(dir, pathspec->nr ? pathspec->_raw[0] : \"\", len, pathspec);\n> +       read_directory(dir, pathspec->nr ? pathspec->items[0].match : \"\",\n> +                      len, pathspec);\n\nOr even better, use common_prefix()'s return value here. I took me a\nwhile to realize this code was not buggy. It is fine to just pick the\nfirst item because the first <len> characters of _all_ pathspec items\nmust be the same. Something like this\n\nprefix = common_prefix(..)\nread_directory(..., prefix, strlen(prefix), pathspec);\n\nexpresses it much better. Yeah one extra mem allocation, no big deal\nsince fill_directory() is not called very often.\n\n>         return len;\n>  }\n>\n> --\n> 2.8.0.rc3.226.g39d4020\n>\n-- \nDuy\n"},{"id":"307103","messageId":"CACsJy8DELy5JsJmcyDtwT-O9qGa9+hR1UfcKWRY1cmCnTALixA@mail.gmail.com","threadId":"44632","inReplyTo":"1481061106-117775-5-git-send-email-bmwill@google.com","subject":"Re: [PATCH 04/17] ls-tree: convert show_recursive to use the pathspec struct interface","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2016-12-07T10:38:52Z","receivedAt":"2016-12-07T10:39:34Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Wed, Dec 7, 2016 at 4:51 AM, Brandon Williams <bmwill@google.com> wrote:\n> Convert 'show_recursive()' to use the pathspec struct interface from\n> using the '_raw' entry in the pathspec struct.\n\nSlightly off-topic (sorry, but you made me look at this code! :D),\ncould you update the magic_mask argument of parse_pathspec() in this\nfile to PATHSPEC_ALL_MAGIC & ~(PATHSPEC_FROMTOP | PATHSPEC_LITERAL)?\nIt makes sure all future magic will be caught as unsupported (and I\nthink Stefan is adding one, but understandably he did not find this\ncode).\n\nI think it's in the spirit of renaming _raw to match too. By limiting\nmagic to fromtop and literal, we are sure match can only be path and\nnothing else, which is good because this show_recursive can't handle\nanything else either.\n\n>\n> Signed-off-by: Brandon Williams <bmwill@google.com>\n> ---\n>  builtin/ls-tree.c | 12 +++++-------\n>  1 file changed, 5 insertions(+), 7 deletions(-)\n>\n> diff --git a/builtin/ls-tree.c b/builtin/ls-tree.c\n> index 0e30d86..e0f4307 100644\n> --- a/builtin/ls-tree.c\n> +++ b/builtin/ls-tree.c\n> @@ -31,21 +31,18 @@ static const  char * const ls_tree_usage[] = {\n>\n>  static int show_recursive(const char *base, int baselen, const char *pathname)\n>  {\n> -       const char **s;\n> +       int i;\n>\n>         if (ls_options & LS_RECURSIVE)\n>                 return 1;\n>\n> -       s = pathspec._raw;\n> -       if (!s)\n> +       if (!pathspec.nr)\n>                 return 0;\n>\n> -       for (;;) {\n> -               const char *spec = *s++;\n> +       for (i = 0; i < pathspec.nr; i++) {\n> +               const char *spec = pathspec.items[i].match;\n>                 int len, speclen;\n>\n> -               if (!spec)\n> -                       return 0;\n>                 if (strncmp(base, spec, baselen))\n>                         continue;\n>                 len = strlen(pathname);\n> @@ -59,6 +56,7 @@ static int show_recursive(const char *base, int baselen, const char *pathname)\n>                         continue;\n>                 return 1;\n>         }\n> +       return 0;\n>  }\n>\n>  static int show_tree(const unsigned char *sha1, struct strbuf *base,\n> --\n> 2.8.0.rc3.226.g39d4020\n>\n\n\n\n-- \nDuy\n"},{"id":"307104","messageId":"CACsJy8CKY5wb+0KzpincHLiYwC0za9Wexo9QvNedcQTGc+ZRDw@mail.gmail.com","threadId":"44632","inReplyTo":"1481061106-117775-10-git-send-email-bmwill@google.com","subject":"Re: [PATCH 09/17] pathspec: always show mnemonic and name in unsupported_magic","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2016-12-07T10:44:52Z","receivedAt":"2016-12-07T10:45:35Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Wed, Dec 7, 2016 at 4:51 AM, Brandon Williams <bmwill@google.com> wrote:\n> @@ -413,10 +411,9 @@ void parse_pathspec(struct pathspec *pathspec,\n>         prefixlen = prefix ? strlen(prefix) : 0;\n>\n>         for (i = 0; i < n; i++) {\n> -               unsigned short_magic;\n>                 entry = argv[i];\n>\n> -               item[i].magic = prefix_pathspec(item + i, &short_magic,\n> +               item[i].magic = prefix_pathspec(item + i,\n>                                                 flags,\n>                                                 prefix, prefixlen, entry);\n\nThe final output looks a bit ...um.. strangely tall, with the first\ntwo lines that have one argument each, then the last line comes with\nthree arguments. Maybe put 'flags' in the same line as 'item + i'?\n\n>                 if ((flags & PATHSPEC_LITERAL_PATH) &&\n>\n\n\n\n-- \nDuy\n"},{"id":"307105","messageId":"CACsJy8Du5XUzcKpWfSKy8iknF01C-RWCgPeh73W3E0VkPJ9sog@mail.gmail.com","threadId":"44632","inReplyTo":"1481061106-117775-10-git-send-email-bmwill@google.com","subject":"Re: [PATCH 09/17] pathspec: always show mnemonic and name in unsupported_magic","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2016-12-07T10:47:46Z","receivedAt":"2016-12-07T10:48:31Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Wed, Dec 7, 2016 at 4:51 AM, Brandon Williams <bmwill@google.com> wrote:\n> @@ -426,8 +423,7 @@ void parse_pathspec(struct pathspec *pathspec,\n>                         nr_exclude++;\n>                 if (item[i].magic & magic_mask)\n>                         unsupported_magic(entry,\n> -                                         item[i].magic & magic_mask,\n> -                                         short_magic);\n> +                                         item[i].magic & magic_mask);\n\nSame here. Maybe put both arguments in the same line. It looks a bit\nbetter. (sorry for two mails on the same patch, I'm reading the final\noutput first before going through individual patches that breaks this\nfunction down)\n\n>\n>                 if ((flags & PATHSPEC_SYMLINK_LEADING_PATH) &&\n>                     has_symlink_leading_path(item[i].match, item[i].len)) {\n-- \nDuy\n"},{"id":"307110","messageId":"CACsJy8ChJ_H3gDOuKVYGAKYumG0u2WkBVpNr_3ePyAJ9NojvEg@mail.gmail.com","threadId":"44632","inReplyTo":"1481061106-117775-17-git-send-email-bmwill@google.com","subject":"Re: [PATCH 16/17] pathspec: small readability changes","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2016-12-07T13:00:06Z","receivedAt":"2016-12-07T13:00:44Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Wed, Dec 7, 2016 at 4:51 AM, Brandon Williams <bmwill@google.com> wrote:\n> A few small changes to improve readability.  This is done by grouping related\n> assignments, adding blank lines, ensuring lines are <80 characters, etc.\n>\n> Signed-off-by: Brandon Williams <bmwill@google.com>\n> ---\n>  pathspec.c | 15 ++++++++++-----\n>  1 file changed, 10 insertions(+), 5 deletions(-)\n>\n> diff --git a/pathspec.c b/pathspec.c\n> index 41aa213..8a07b02 100644\n> --- a/pathspec.c\n> +++ b/pathspec.c\n> @@ -334,6 +334,7 @@ static unsigned prefix_pathspec(struct pathspec_item *item,\n>         if ((magic & PATHSPEC_LITERAL) && (magic & PATHSPEC_GLOB))\n>                 die(_(\"%s: 'literal' and 'glob' are incompatible\"), elt);\n>\n> +       /* Create match string which will be used for pathspec matching */\n>         if (pathspec_prefix >= 0) {\n>                 match = xstrdup(copyfrom);\n>                 prefixlen = pathspec_prefix;\n> @@ -341,11 +342,16 @@ static unsigned prefix_pathspec(struct pathspec_item *item,\n>                 match = xstrdup(copyfrom);\n>                 prefixlen = 0;\n>         } else {\n> -               match = prefix_path_gently(prefix, prefixlen, &prefixlen, copyfrom);\n> +               match = prefix_path_gently(prefix, prefixlen,\n> +                                          &prefixlen, copyfrom);\n>                 if (!match)\n>                         die(_(\"%s: '%s' is outside repository\"), elt, copyfrom);\n>         }\n> +\n>         item->match = match;\n> +       item->len = strlen(item->match);\n> +       item->prefix = prefixlen;\n> +\n>         /*\n>          * Prefix the pathspec (keep all magic) and assign to\n>          * original. Useful for passing to another command.\n> @@ -362,8 +368,6 @@ static unsigned prefix_pathspec(struct pathspec_item *item,\n>         } else {\n>                 item->original = xstrdup(elt);\n>         }\n> -       item->len = strlen(item->match);\n> -       item->prefix = prefixlen;\n>\n>         if (flags & PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP)\n>             strip_submodule_slash_cheap(item);\n> @@ -371,13 +375,14 @@ static unsigned prefix_pathspec(struct pathspec_item *item,\n>         if (flags & PATHSPEC_STRIP_SUBMODULE_SLASH_EXPENSIVE)\n>             strip_submodule_slash_expensive(item);\n>\n> -       if (magic & PATHSPEC_LITERAL)\n> +       if (magic & PATHSPEC_LITERAL) {\n>                 item->nowildcard_len = item->len;\n> -       else {\n> +       } else {\n>                 item->nowildcard_len = simple_length(item->match);\n>                 if (item->nowildcard_len < prefixlen)\n>                         item->nowildcard_len = prefixlen;\n>         }\n> +\n>         item->flags = 0;\n\nYou probably can move this line up with the others too.\n\nAnd since you have broken this function down so nicely, it made me see\nthat we could do\n\nitem->magic = magic instead of returning \"magic\" at the end, which is\nassigned to item->magic anyway by the caller.\n-- \nDuy\n"},{"id":"307111","messageId":"CACsJy8D9SAOYtzPTuGnst3J7qCUjMuGMrZ=KNH0MLSxMrq4krw@mail.gmail.com","threadId":"44632","inReplyTo":"1481061106-117775-12-git-send-email-bmwill@google.com","subject":"Re: [PATCH 11/17] pathspec: factor global magic into its own function","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2016-12-07T12:53:26Z","receivedAt":"2016-12-07T13:12:39Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Wed, Dec 7, 2016 at 4:51 AM, Brandon Williams <bmwill@google.com> wrote:\n> Create helper functions to read the global magic environment variables\n> in additon to factoring out the global magic gathering logic into its\n> own function.\n>\n> Signed-off-by: Brandon Williams <bmwill@google.com>\n> ---\n>  pathspec.c | 120 +++++++++++++++++++++++++++++++++++++------------------------\n>  1 file changed, 74 insertions(+), 46 deletions(-)\n>\n> diff --git a/pathspec.c b/pathspec.c\n> index 5afebd3..08e76f6 100644\n> --- a/pathspec.c\n> +++ b/pathspec.c\n> @@ -87,6 +87,74 @@ static void prefix_magic(struct strbuf *sb, int prefixlen, unsigned magic)\n>         strbuf_addf(sb, \",prefix:%d)\", prefixlen);\n>  }\n>\n> +static inline int get_literal_global(void)\n> +{\n> +       static int literal_global = -1;\n> +\n> +       if (literal_global < 0)\n> +               literal_global = git_env_bool(GIT_LITERAL_PATHSPECS_ENVIRONMENT,\n> +                                             0);\n\nThese zeros look so lonely. I know it would exceed 80 columns if we\nput it on the previous line. But I think it's ok for occasional\nexceptions. Or you could rename noglob_global to noglob.\n-- \nDuy\n"},{"id":"307113","messageId":"CACsJy8B6Mj-L1t-CETY5DWRyABHZsYZszwXD3dgUqChfXRB6FA@mail.gmail.com","threadId":"44632","inReplyTo":"1481061106-117775-17-git-send-email-bmwill@google.com","subject":"Re: [PATCH 16/17] pathspec: small readability changes","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2016-12-07T13:04:52Z","receivedAt":"2016-12-07T13:24:29Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Wed, Dec 7, 2016 at 4:51 AM, Brandon Williams <bmwill@google.com> wrote:\n> A few small changes to improve readability.  This is done by grouping related\n> assignments, adding blank lines, ensuring lines are <80 characters, etc.\n>\n> Signed-off-by: Brandon Williams <bmwill@google.com>\n> ---\n>  pathspec.c | 15 ++++++++++-----\n>  1 file changed, 10 insertions(+), 5 deletions(-)\n>\n> diff --git a/pathspec.c b/pathspec.c\n> index 41aa213..8a07b02 100644\n> --- a/pathspec.c\n> +++ b/pathspec.c\n> @@ -334,6 +334,7 @@ static unsigned prefix_pathspec(struct pathspec_item *item,\n\nbtw, since this function has stopped being \"just prefix pathspec\" for\na long time, perhaps rename it to parse_pathspec_item, or something.\n-- \nDuy\n"},{"id":"307174","messageId":"xmqqinqvwg4k.fsf@gitster.mtv.corp.google.com","threadId":"44632","inReplyTo":"CACsJy8B6Mj-L1t-CETY5DWRyABHZsYZszwXD3dgUqChfXRB6FA@mail.gmail.com","subject":"Re: [PATCH 16/17] pathspec: small readability changes","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-12-07T22:04:11Z","receivedAt":"2016-12-07T22:04:24Z","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 Wed, Dec 7, 2016 at 4:51 AM, Brandon Williams <bmwill@google.com> wrote:\n>> A few small changes to improve readability.  This is done by grouping related\n>> assignments, adding blank lines, ensuring lines are <80 characters, etc.\n>>\n>> Signed-off-by: Brandon Williams <bmwill@google.com>\n>> ---\n>>  pathspec.c | 15 ++++++++++-----\n>>  1 file changed, 10 insertions(+), 5 deletions(-)\n>>\n>> diff --git a/pathspec.c b/pathspec.c\n>> index 41aa213..8a07b02 100644\n>> --- a/pathspec.c\n>> +++ b/pathspec.c\n>> @@ -334,6 +334,7 @@ static unsigned prefix_pathspec(struct pathspec_item *item,\n>\n> btw, since this function has stopped being \"just prefix pathspec\" for\n> a long time, perhaps rename it to parse_pathspec_item, or something.\n\nNot specifically responding to this comment, but thanks for all the\nconstructive feedback messages.\n"},{"id":"307175","messageId":"xmqqeg1jwg3b.fsf@gitster.mtv.corp.google.com","threadId":"44632","inReplyTo":"1481061106-117775-1-git-send-email-bmwill@google.com","subject":"Re: [PATCH 00/17] pathspec cleanup","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-12-07T22:04:56Z","receivedAt":"2016-12-07T22:05:03Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Brandon Williams <bmwill@google.com> writes:\n\n> The intent of this series is to cleanup some of the pathspec initialization\n> code as well as finally migrating the remaining users of the _raw field or\n> get_pathspec() to the pathspec struct interface.  This way both the _raw field\n> and get_pathspec() can be removed from the codebase.  This also removes the\n> functionality where parse_pathspec() modified the const char * argv array that\n> was passed in (which felt kind of odd to me as I wouldn't have expected the\n> passed in array to be modified).\n>\n> I also noticed that there are memory leaks associated with the 'original' and\n> 'match' strings.  To fix this the pathspec struct needed to take ownership of\n> the memory for these fields so that they can be cleaned up when clearing the\n> pathspec struct.\n\nBoth good goals.  Thanks for working on this.\n"},{"id":"307182","messageId":"20161207223644.GC116201@google.com","threadId":"44632","inReplyTo":"CACsJy8B6Mj-L1t-CETY5DWRyABHZsYZszwXD3dgUqChfXRB6FA@mail.gmail.com","subject":"Re: [PATCH 16/17] pathspec: small readability changes","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2016-12-07T22:36:44Z","receivedAt":"2016-12-07T22:37:05Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"On 12/07, Duy Nguyen wrote:\n> On Wed, Dec 7, 2016 at 4:51 AM, Brandon Williams <bmwill@google.com> wrote:\n> > A few small changes to improve readability.  This is done by grouping related\n> > assignments, adding blank lines, ensuring lines are <80 characters, etc.\n> >\n> > Signed-off-by: Brandon Williams <bmwill@google.com>\n> > ---\n> >  pathspec.c | 15 ++++++++++-----\n> >  1 file changed, 10 insertions(+), 5 deletions(-)\n> >\n> > diff --git a/pathspec.c b/pathspec.c\n> > index 41aa213..8a07b02 100644\n> > --- a/pathspec.c\n> > +++ b/pathspec.c\n> > @@ -334,6 +334,7 @@ static unsigned prefix_pathspec(struct pathspec_item *item,\n> \n> btw, since this function has stopped being \"just prefix pathspec\" for\n> a long time, perhaps rename it to parse_pathspec_item, or something.\n\nI was thinking about doing that after I sent this out.  Glad you also\npointed that out.\n\n-- \nBrandon Williams\n"},{"id":"307183","messageId":"20161207223936.GD116201@google.com","threadId":"44632","inReplyTo":"CACsJy8D9SAOYtzPTuGnst3J7qCUjMuGMrZ=KNH0MLSxMrq4krw@mail.gmail.com","subject":"Re: [PATCH 11/17] pathspec: factor global magic into its own function","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2016-12-07T22:39:36Z","receivedAt":"2016-12-07T22:39:44Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"On 12/07, Duy Nguyen wrote:\n> On Wed, Dec 7, 2016 at 4:51 AM, Brandon Williams <bmwill@google.com> wrote:\n> > Create helper functions to read the global magic environment variables\n> > in additon to factoring out the global magic gathering logic into its\n> > own function.\n> >\n> > Signed-off-by: Brandon Williams <bmwill@google.com>\n> > ---\n> >  pathspec.c | 120 +++++++++++++++++++++++++++++++++++++------------------------\n> >  1 file changed, 74 insertions(+), 46 deletions(-)\n> >\n> > diff --git a/pathspec.c b/pathspec.c\n> > index 5afebd3..08e76f6 100644\n> > --- a/pathspec.c\n> > +++ b/pathspec.c\n> > @@ -87,6 +87,74 @@ static void prefix_magic(struct strbuf *sb, int prefixlen, unsigned magic)\n> >         strbuf_addf(sb, \",prefix:%d)\", prefixlen);\n> >  }\n> >\n> > +static inline int get_literal_global(void)\n> > +{\n> > +       static int literal_global = -1;\n> > +\n> > +       if (literal_global < 0)\n> > +               literal_global = git_env_bool(GIT_LITERAL_PATHSPECS_ENVIRONMENT,\n> > +                                             0);\n> \n> These zeros look so lonely. I know it would exceed 80 columns if we\n> put it on the previous line. But I think it's ok for occasional\n> exceptions. Or you could rename noglob_global to noglob.\n\nI was thinking the same thing but was so torn between the char limit.  I\nthink it's probably ok to rename these vars by drooping the global since\nthe function name themselves indicate they are global.\n-- \nBrandon Williams\n"},{"id":"307184","messageId":"20161207224114.GE116201@google.com","threadId":"44632","inReplyTo":"CACsJy8Du5XUzcKpWfSKy8iknF01C-RWCgPeh73W3E0VkPJ9sog@mail.gmail.com","subject":"Re: [PATCH 09/17] pathspec: always show mnemonic and name in unsupported_magic","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2016-12-07T22:41:14Z","receivedAt":"2016-12-07T22:41:21Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"On 12/07, Duy Nguyen wrote:\n> On Wed, Dec 7, 2016 at 4:51 AM, Brandon Williams <bmwill@google.com> wrote:\n> > @@ -426,8 +423,7 @@ void parse_pathspec(struct pathspec *pathspec,\n> >                         nr_exclude++;\n> >                 if (item[i].magic & magic_mask)\n> >                         unsupported_magic(entry,\n> > -                                         item[i].magic & magic_mask,\n> > -                                         short_magic);\n> > +                                         item[i].magic & magic_mask);\n> \n> Same here. Maybe put both arguments in the same line. It looks a bit\n> better. (sorry for two mails on the same patch, I'm reading the final\n> output first before going through individual patches that breaks this\n> function down)\n\nAll good.  Sometimes its easier to parse comments if they are in\nmultiple small emails.  I don't mind getting lots of mail :)\n\n> \n> >\n> >                 if ((flags & PATHSPEC_SYMLINK_LEADING_PATH) &&\n> >                     has_symlink_leading_path(item[i].match, item[i].len)) {\n> -- \n> Duy\n\n-- \nBrandon Williams\n"},{"id":"307185","messageId":"20161207224155.GF116201@google.com","threadId":"44632","inReplyTo":"CACsJy8CKY5wb+0KzpincHLiYwC0za9Wexo9QvNedcQTGc+ZRDw@mail.gmail.com","subject":"Re: [PATCH 09/17] pathspec: always show mnemonic and name in unsupported_magic","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2016-12-07T22:41:55Z","receivedAt":"2016-12-07T22:42:03Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"On 12/07, Duy Nguyen wrote:\n> On Wed, Dec 7, 2016 at 4:51 AM, Brandon Williams <bmwill@google.com> wrote:\n> > @@ -413,10 +411,9 @@ void parse_pathspec(struct pathspec *pathspec,\n> >         prefixlen = prefix ? strlen(prefix) : 0;\n> >\n> >         for (i = 0; i < n; i++) {\n> > -               unsigned short_magic;\n> >                 entry = argv[i];\n> >\n> > -               item[i].magic = prefix_pathspec(item + i, &short_magic,\n> > +               item[i].magic = prefix_pathspec(item + i,\n> >                                                 flags,\n> >                                                 prefix, prefixlen, entry);\n> \n> The final output looks a bit ...um.. strangely tall, with the first\n> two lines that have one argument each, then the last line comes with\n> three arguments. Maybe put 'flags' in the same line as 'item + i'?\n\nYep you're right, it does look a bit funny.\n\n-- \nBrandon Williams\n"},{"id":"307186","messageId":"20161207224317.GG116201@google.com","threadId":"44632","inReplyTo":"CACsJy8DELy5JsJmcyDtwT-O9qGa9+hR1UfcKWRY1cmCnTALixA@mail.gmail.com","subject":"Re: [PATCH 04/17] ls-tree: convert show_recursive to use the pathspec struct interface","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2016-12-07T22:43:17Z","receivedAt":"2016-12-07T22:43:30Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"On 12/07, Duy Nguyen wrote:\n> On Wed, Dec 7, 2016 at 4:51 AM, Brandon Williams <bmwill@google.com> wrote:\n> > Convert 'show_recursive()' to use the pathspec struct interface from\n> > using the '_raw' entry in the pathspec struct.\n> \n> Slightly off-topic (sorry, but you made me look at this code! :D),\n> could you update the magic_mask argument of parse_pathspec() in this\n> file to PATHSPEC_ALL_MAGIC & ~(PATHSPEC_FROMTOP | PATHSPEC_LITERAL)?\n> It makes sure all future magic will be caught as unsupported (and I\n> think Stefan is adding one, but understandably he did not find this\n> code).\n> \n> I think it's in the spirit of renaming _raw to match too. By limiting\n> magic to fromtop and literal, we are sure match can only be path and\n> nothing else, which is good because this show_recursive can't handle\n> anything else either.\n\nCan do.\n\n-- \nBrandon Williams\n"},{"id":"307188","messageId":"20161207224616.GH116201@google.com","threadId":"44632","inReplyTo":"CACsJy8BsGVrUoFFFEqdLS-h4XYCkFg-gbx+BeWmGd8srupNWqw@mail.gmail.com","subject":"Re: [PATCH 03/17] dir: convert fill_directory to use the pathspec struct interface","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2016-12-07T22:46:16Z","receivedAt":"2016-12-07T22:46:39Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"On 12/07, Duy Nguyen wrote:\n> On Wed, Dec 7, 2016 at 4:51 AM, Brandon Williams <bmwill@google.com> wrote:\n> > Convert 'fill_directory()' to use the pathspec struct interface from\n> > using the '_raw' entry in the pathspec struct.\n> >\n> > Signed-off-by: Brandon Williams <bmwill@google.com>\n> > ---\n> >  dir.c | 3 ++-\n> >  1 file changed, 2 insertions(+), 1 deletion(-)\n> >\n> > diff --git a/dir.c b/dir.c\n> > index 7df292b..8730a4f 100644\n> > --- a/dir.c\n> > +++ b/dir.c\n> > @@ -188,7 +188,8 @@ int fill_directory(struct dir_struct *dir, const struct pathspec *pathspec)\n> >         len = common_prefix_len(pathspec);\n> >\n> >         /* Read the directory and prune it */\n> > -       read_directory(dir, pathspec->nr ? pathspec->_raw[0] : \"\", len, pathspec);\n> > +       read_directory(dir, pathspec->nr ? pathspec->items[0].match : \"\",\n> > +                      len, pathspec);\n> \n> Or even better, use common_prefix()'s return value here. I took me a\n> while to realize this code was not buggy. It is fine to just pick the\n> first item because the first <len> characters of _all_ pathspec items\n> must be the same. Something like this\n> \n> prefix = common_prefix(..)\n> read_directory(..., prefix, strlen(prefix), pathspec);\n> \n> expresses it much better. Yeah one extra mem allocation, no big deal\n> since fill_directory() is not called very often.\n\nI didn't even notice that.  Now looking at this you're right that its\nnot immediately obvious that what's there is correct.  I'll change this.\n\n> \n> >         return len;\n> >  }\n> >\n> > --\n> > 2.8.0.rc3.226.g39d4020\n> >\n> -- \n> Duy\n\n-- \nBrandon Williams\n"},{"id":"307194","messageId":"20161207232724.GI116201@google.com","threadId":"44632","inReplyTo":"CACsJy8ChJ_H3gDOuKVYGAKYumG0u2WkBVpNr_3ePyAJ9NojvEg@mail.gmail.com","subject":"Re: [PATCH 16/17] pathspec: small readability changes","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2016-12-07T23:27:24Z","receivedAt":"2016-12-07T23:27:31Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"On 12/07, Duy Nguyen wrote:\n> On Wed, Dec 7, 2016 at 4:51 AM, Brandon Williams <bmwill@google.com> wrote:\n> > A few small changes to improve readability.  This is done by grouping related\n> > assignments, adding blank lines, ensuring lines are <80 characters, etc.\n> >\n> > Signed-off-by: Brandon Williams <bmwill@google.com>\n> > ---\n> >  pathspec.c | 15 ++++++++++-----\n> >  1 file changed, 10 insertions(+), 5 deletions(-)\n> >\n> > diff --git a/pathspec.c b/pathspec.c\n> > index 41aa213..8a07b02 100644\n> > --- a/pathspec.c\n> > +++ b/pathspec.c\n> > @@ -334,6 +334,7 @@ static unsigned prefix_pathspec(struct pathspec_item *item,\n> >         if ((magic & PATHSPEC_LITERAL) && (magic & PATHSPEC_GLOB))\n> >                 die(_(\"%s: 'literal' and 'glob' are incompatible\"), elt);\n> >\n> > +       /* Create match string which will be used for pathspec matching */\n> >         if (pathspec_prefix >= 0) {\n> >                 match = xstrdup(copyfrom);\n> >                 prefixlen = pathspec_prefix;\n> > @@ -341,11 +342,16 @@ static unsigned prefix_pathspec(struct pathspec_item *item,\n> >                 match = xstrdup(copyfrom);\n> >                 prefixlen = 0;\n> >         } else {\n> > -               match = prefix_path_gently(prefix, prefixlen, &prefixlen, copyfrom);\n> > +               match = prefix_path_gently(prefix, prefixlen,\n> > +                                          &prefixlen, copyfrom);\n> >                 if (!match)\n> >                         die(_(\"%s: '%s' is outside repository\"), elt, copyfrom);\n> >         }\n> > +\n> >         item->match = match;\n> > +       item->len = strlen(item->match);\n> > +       item->prefix = prefixlen;\n> > +\n> >         /*\n> >          * Prefix the pathspec (keep all magic) and assign to\n> >          * original. Useful for passing to another command.\n> > @@ -362,8 +368,6 @@ static unsigned prefix_pathspec(struct pathspec_item *item,\n> >         } else {\n> >                 item->original = xstrdup(elt);\n> >         }\n> > -       item->len = strlen(item->match);\n> > -       item->prefix = prefixlen;\n> >\n> >         if (flags & PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP)\n> >             strip_submodule_slash_cheap(item);\n> > @@ -371,13 +375,14 @@ static unsigned prefix_pathspec(struct pathspec_item *item,\n> >         if (flags & PATHSPEC_STRIP_SUBMODULE_SLASH_EXPENSIVE)\n> >             strip_submodule_slash_expensive(item);\n> >\n> > -       if (magic & PATHSPEC_LITERAL)\n> > +       if (magic & PATHSPEC_LITERAL) {\n> >                 item->nowildcard_len = item->len;\n> > -       else {\n> > +       } else {\n> >                 item->nowildcard_len = simple_length(item->match);\n> >                 if (item->nowildcard_len < prefixlen)\n> >                         item->nowildcard_len = prefixlen;\n> >         }\n> > +\n> >         item->flags = 0;\n> \n> You probably can move this line up with the others too.\n\nI didn't move the item->flags assignment up since the code immediately\nfollowing this assignment deal with setting item->flags.  I made more\nsense to keep them grouped.\n\n-- \nBrandon Williams\n"},{"id":"307202","messageId":"20161208000357.GJ116201@google.com","threadId":"44632","inReplyTo":"CACsJy8AX09pxkyUkLU905v1MpXocLzV5bK0APuNmMUNb50Lavg@mail.gmail.com","subject":"Re: [PATCH 02/17] dir: convert create_simplify to use the pathspec struct interface","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2016-12-08T00:03:57Z","receivedAt":"2016-12-08T00:04:04Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"On 12/07, Duy Nguyen wrote:\n> On Wed, Dec 7, 2016 at 4:51 AM, Brandon Williams <bmwill@google.com> wrote:\n> > Convert 'create_simplify()' to use the pathspec struct interface from\n> > using the '_raw' entry in the pathspec.\n> \n> It would be even better to kill this create_simplify() and let\n> simplify_away() handle struct pathspec directly.\n> \n> There is a bug in this code, that might have been found if we\n> simpify_away() handled pathspec directly: the memcmp() in\n> simplify_away() will not play well with :(icase) magic. My bad. If\n> :(icase) is used, the easiest/safe way is simplify nothing. Later on\n> maybe we can teach simplify_away() to do strncasecmp instead. We could\n> ignore exclude patterns there too (although not excluding is not a\n> bug).\n\nSo are you implying that the simplify struct needs to be killed?  That\nway the pathspec struct itself is being passed around instead?\n\n-- \nBrandon Williams\n"},{"id":"307204","messageId":"20161208003604.GK116201@google.com","threadId":"44632","inReplyTo":"CACsJy8Bm+Nif_PL1=BzTYLKGrnz94rjKOB=_PXz6OB47Js6v2A@mail.gmail.com","subject":"Re: [PATCH 01/17] mv: convert to using pathspec struct interface","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2016-12-08T00:36:04Z","receivedAt":"2016-12-08T00:36:12Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"On 12/07, Duy Nguyen wrote:\n> On Wed, Dec 7, 2016 at 4:51 AM, Brandon Williams <bmwill@google.com> wrote:\n> > Convert the 'internal_copy_pathspec()' function to use the pathspec\n> > struct interface from using the deprecated 'get_pathspec()' interface.\n> >\n> > In addition to this, fix a memory leak caused by only duplicating some\n> > of the pathspec elements.  Instead always duplicate all of the the\n> > pathspec elements as an intermediate step (with modificationed based on\n> > the passed in flags).  This way the intermediate strings can then be\n> > freed prior to duplicating the result of parse_pathspec (which contains\n> > each of the elements with the prefix prepended).\n> >\n> > Signed-off-by: Brandon Williams <bmwill@google.com>\n> > ---\n> >  builtin/mv.c | 45 ++++++++++++++++++++++++++++++++-------------\n> >  1 file changed, 32 insertions(+), 13 deletions(-)\n> \n> Stefan did something similar last year [1] but I couldn't find why it\n> did not get merged. Not sure if the reasons are still relevant or\n> not...\n> \n> [1] http://public-inbox.org/git/%3C1438885632-26470-1-git-send-email-sbeller@google.com%3E/\n> \n> > diff --git a/builtin/mv.c b/builtin/mv.c\n> > index 2f43877..4df4a12 100644\n> > --- a/builtin/mv.c\n> > +++ b/builtin/mv.c\n> > @@ -4,6 +4,7 @@\n> >   * Copyright (C) 2006 Johannes Schindelin\n> >   */\n> >  #include \"builtin.h\"\n> > +#include \"pathspec.h\"\n> >  #include \"lockfile.h\"\n> >  #include \"dir.h\"\n> >  #include \"cache-tree.h\"\n> > @@ -25,25 +26,43 @@ static const char **internal_copy_pathspec(const char *prefix,\n> >  {\n> >         int i;\n> >         const char **result;\n> > +       struct pathspec ps;\n> >         ALLOC_ARRAY(result, count + 1);\n> > -       COPY_ARRAY(result, pathspec, count);\n> > -       result[count] = NULL;\n> > +\n> > +       /* Create an intermediate copy of the pathspec based on the flags */\n> >         for (i = 0; i < count; i++) {\n> > -               int length = strlen(result[i]);\n> > +               int length = strlen(pathspec[i]);\n> >                 int to_copy = length;\n> > +               char *it;\n> >                 while (!(flags & KEEP_TRAILING_SLASH) &&\n> > -                      to_copy > 0 && is_dir_sep(result[i][to_copy - 1]))\n> > +                      to_copy > 0 && is_dir_sep(pathspec[i][to_copy - 1]))\n> >                         to_copy--;\n> > -               if (to_copy != length || flags & DUP_BASENAME) {\n> > -                       char *it = xmemdupz(result[i], to_copy);\n> > -                       if (flags & DUP_BASENAME) {\n> > -                               result[i] = xstrdup(basename(it));\n> > -                               free(it);\n> > -                       } else\n> > -                               result[i] = it;\n> > -               }\n> > +\n> > +               it = xmemdupz(pathspec[i], to_copy);\n> > +               if (flags & DUP_BASENAME) {\n> > +                       result[i] = xstrdup(basename(it));\n> > +                       free(it);\n> > +               } else\n> > +                       result[i] = it;\n> > +       }\n> > +       result[count] = NULL;\n> > +\n> > +       parse_pathspec(&ps,\n> > +                      PATHSPEC_ALL_MAGIC &\n> > +                      ~(PATHSPEC_FROMTOP | PATHSPEC_LITERAL),\n> > +                      PATHSPEC_KEEP_ORDER | PATHSPEC_PREFER_CWD,\n> > +                      prefix, result);\n> > +       assert(count == ps.nr);\n> > +\n> > +       /* Copy the pathspec and free the old intermediate strings */\n> > +       for (i = 0; i < count; i++) {\n> > +               const char *match = xstrdup(ps.items[i].match);\n> > +               free((char *) result[i]);\n> > +               result[i] = match;\n> \n> Sigh.. it looks so weird that we do all the parsing (in a _copy_\n> pathspec function) then remove struct pathspec and return the plain\n> string. I guess we can't do anything more until we rework cmd_mv code\n> to handle pathspec natively.\n> \n> At the least I think we should rename this function to something else.\n> But if you have time I really wish we could kill this function. I\n> haven't stared at cmd_mv() long and hard, but it looks to me that we\n> combining two separate functionalities in the same function here.\n> \n> If \"mv\" takes n arguments, then the first <n-1> arguments may be\n> pathspec, the last one is always a plain path. The \"dest_path =\n> internal_copy_pathspec...\" could be as simple as \"dest_path =\n> prefix_path(argv[argc - 1])\". the special treatment for this last\n> argument [1] can live here. Then, we can do parse_pathspec for the\n> <n-1> arguments in cmd_mv(). It's still far from perfect, because\n> cmd_mv can't handle pathspec properly, but it reduces the messy mess\n> in internal_copy_pathspec a bit, I hope.\n> \n> [1] c57f628 (mv: let 'git mv file no-such-dir/' error out - 2013-12-03)\n> \n> >         }\n> > -       return get_pathspec(prefix, result);\n> > +\n> > +       clear_pathspec(&ps);\n> > +       return result;\n> >  }\n> >\n> >  static const char *add_slash(const char *path)\n> > --\n> > 2.8.0.rc3.226.g39d4020\n> >\n> \n> \n> \n> -- \n> Duy\n\nActually, after looking at this a bit more it seems like we could\ntechnically use prefix_path for both source and dest (based on how the\ncurrent code is structured) since the source's provied must all exist (as\nin no wildcards are allowed).  We could drop using the pathspec struct\ncompletely in addition to renaming the function (to what I'm still\nunsure).  I agree that this code should probably be rewritten and made a\nbit cleaner, I don't know if that fits in the scope of this series or\nshould be done as a followup patch.  If you think it fits here then I\ncan try and find some time to do the rework.\n\n-- \nBrandon Williams\n"},{"id":"307222","messageId":"CACsJy8AUKNgPBo6aJ=FsLcMLVEWZ6hXWZ8M7qmvdiUZKjuv-CA@mail.gmail.com","threadId":"44632","inReplyTo":"20161207223936.GD116201@google.com","subject":"Re: [PATCH 11/17] pathspec: factor global magic into its own function","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2016-12-08T09:20:54Z","receivedAt":"2016-12-08T09:21:32Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Thu, Dec 8, 2016 at 5:39 AM, Brandon Williams <bmwill@google.com> wrote:\n> On 12/07, Duy Nguyen wrote:\n>> On Wed, Dec 7, 2016 at 4:51 AM, Brandon Williams <bmwill@google.com> wrote:\n>> > Create helper functions to read the global magic environment variables\n>> > in additon to factoring out the global magic gathering logic into its\n>> > own function.\n>> >\n>> > Signed-off-by: Brandon Williams <bmwill@google.com>\n>> > ---\n>> >  pathspec.c | 120 +++++++++++++++++++++++++++++++++++++------------------------\n>> >  1 file changed, 74 insertions(+), 46 deletions(-)\n>> >\n>> > diff --git a/pathspec.c b/pathspec.c\n>> > index 5afebd3..08e76f6 100644\n>> > --- a/pathspec.c\n>> > +++ b/pathspec.c\n>> > @@ -87,6 +87,74 @@ static void prefix_magic(struct strbuf *sb, int prefixlen, unsigned magic)\n>> >         strbuf_addf(sb, \",prefix:%d)\", prefixlen);\n>> >  }\n>> >\n>> > +static inline int get_literal_global(void)\n>> > +{\n>> > +       static int literal_global = -1;\n>> > +\n>> > +       if (literal_global < 0)\n>> > +               literal_global = git_env_bool(GIT_LITERAL_PATHSPECS_ENVIRONMENT,\n>> > +                                             0);\n>>\n>> These zeros look so lonely. I know it would exceed 80 columns if we\n>> put it on the previous line. But I think it's ok for occasional\n>> exceptions. Or you could rename noglob_global to noglob.\n>\n> I was thinking the same thing but was so torn between the char limit.  I\n> think it's probably ok to rename these vars by drooping the global since\n> the function name themselves indicate they are global.\n\nExactly. I almost suggested just \"ret\" for that reason, but it was a\nbit on the extreme side, relying entirely on the function's name for\ncontext.\n-- \nDuy\n"},{"id":"307223","messageId":"CACsJy8BFkB1Ga3PJ-QccVUoE2L14CB2g4MoapVu-QFi3c9CQQw@mail.gmail.com","threadId":"44632","inReplyTo":"20161207232724.GI116201@google.com","subject":"Re: [PATCH 16/17] pathspec: small readability changes","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2016-12-08T09:23:49Z","receivedAt":"2016-12-08T09:24:28Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Thu, Dec 8, 2016 at 6:27 AM, Brandon Williams <bmwill@google.com> wrote:\n>> On Wed, Dec 7, 2016 at 4:51 AM, Brandon Williams <bmwill@google.com> wrote:\n>> > @@ -362,8 +368,6 @@ static unsigned prefix_pathspec(struct pathspec_item *item,\n>> >         } else {\n>> >                 item->original = xstrdup(elt);\n>> >         }\n>> > -       item->len = strlen(item->match);\n>> > -       item->prefix = prefixlen;\n>> >\n>> >         if (flags & PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP)\n>> >             strip_submodule_slash_cheap(item);\n>> > @@ -371,13 +375,14 @@ static unsigned prefix_pathspec(struct pathspec_item *item,\n>> >         if (flags & PATHSPEC_STRIP_SUBMODULE_SLASH_EXPENSIVE)\n>> >             strip_submodule_slash_expensive(item);\n>> >\n>> > -       if (magic & PATHSPEC_LITERAL)\n>> > +       if (magic & PATHSPEC_LITERAL) {\n>> >                 item->nowildcard_len = item->len;\n>> > -       else {\n>> > +       } else {\n>> >                 item->nowildcard_len = simple_length(item->match);\n>> >                 if (item->nowildcard_len < prefixlen)\n>> >                         item->nowildcard_len = prefixlen;\n>> >         }\n>> > +\n>> >         item->flags = 0;\n>>\n>> You probably can move this line up with the others too.\n>\n> I didn't move the item->flags assignment up since the code immediately\n> following this assignment deal with setting item->flags.  I made more\n> sense to keep them grouped.\n\nIt's probably why I put it there in the beginning :) Yes let's leave\nit where it is then.\n-- \nDuy\n"},{"id":"307234","messageId":"CACsJy8DVuOdRsu4x9iFTwweSVn=RRJYzBTm43ufBevTWMf4Qmg@mail.gmail.com","threadId":"44632","inReplyTo":"20161208003604.GK116201@google.com","subject":"Re: [PATCH 01/17] mv: convert to using pathspec struct interface","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2016-12-08T11:04:24Z","receivedAt":"2016-12-08T11:06:02Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Thu, Dec 8, 2016 at 7:36 AM, Brandon Williams <bmwill@google.com> wrote:\n>> > @@ -25,25 +26,43 @@ static const char **internal_copy_pathspec(const char *prefix,\n>> >  {\n>> >         int i;\n>> >         const char **result;\n>> > +       struct pathspec ps;\n>> >         ALLOC_ARRAY(result, count + 1);\n>> > -       COPY_ARRAY(result, pathspec, count);\n>> > -       result[count] = NULL;\n>> > +\n>> > +       /* Create an intermediate copy of the pathspec based on the flags */\n>> >         for (i = 0; i < count; i++) {\n>> > -               int length = strlen(result[i]);\n>> > +               int length = strlen(pathspec[i]);\n>> >                 int to_copy = length;\n>> > +               char *it;\n>> >                 while (!(flags & KEEP_TRAILING_SLASH) &&\n>> > -                      to_copy > 0 && is_dir_sep(result[i][to_copy - 1]))\n>> > +                      to_copy > 0 && is_dir_sep(pathspec[i][to_copy - 1]))\n>> >                         to_copy--;\n>> > -               if (to_copy != length || flags & DUP_BASENAME) {\n>> > -                       char *it = xmemdupz(result[i], to_copy);\n>> > -                       if (flags & DUP_BASENAME) {\n>> > -                               result[i] = xstrdup(basename(it));\n>> > -                               free(it);\n>> > -                       } else\n>> > -                               result[i] = it;\n>> > -               }\n>> > +\n>> > +               it = xmemdupz(pathspec[i], to_copy);\n>> > +               if (flags & DUP_BASENAME) {\n>> > +                       result[i] = xstrdup(basename(it));\n>> > +                       free(it);\n>> > +               } else\n>> > +                       result[i] = it;\n>> > +       }\n>> > +       result[count] = NULL;\n>> > +\n>> > +       parse_pathspec(&ps,\n>> > +                      PATHSPEC_ALL_MAGIC &\n>> > +                      ~(PATHSPEC_FROMTOP | PATHSPEC_LITERAL),\n>> > +                      PATHSPEC_KEEP_ORDER | PATHSPEC_PREFER_CWD,\n>> > +                      prefix, result);\n>> > +       assert(count == ps.nr);\n>> > +\n>> > +       /* Copy the pathspec and free the old intermediate strings */\n>> > +       for (i = 0; i < count; i++) {\n>> > +               const char *match = xstrdup(ps.items[i].match);\n>> > +               free((char *) result[i]);\n>> > +               result[i] = match;\n>>\n>> Sigh.. it looks so weird that we do all the parsing (in a _copy_\n>> pathspec function) then remove struct pathspec and return the plain\n>> string. I guess we can't do anything more until we rework cmd_mv code\n>> to handle pathspec natively.\n>>\n>> At the least I think we should rename this function to something else.\n>> But if you have time I really wish we could kill this function. I\n>> haven't stared at cmd_mv() long and hard, but it looks to me that we\n>> combining two separate functionalities in the same function here.\n>>\n>> If \"mv\" takes n arguments, then the first <n-1> arguments may be\n>> pathspec, the last one is always a plain path. The \"dest_path =\n>> internal_copy_pathspec...\" could be as simple as \"dest_path =\n>> prefix_path(argv[argc - 1])\". the special treatment for this last\n>> argument [1] can live here. Then, we can do parse_pathspec for the\n>> <n-1> arguments in cmd_mv(). It's still far from perfect, because\n>> cmd_mv can't handle pathspec properly, but it reduces the messy mess\n>> in internal_copy_pathspec a bit, I hope.\n>>\n>\n> Actually, after looking at this a bit more it seems like we could\n> technically use prefix_path for both source and dest (based on how the\n> current code is structured) since the source's provied must all exist (as\n> in no wildcards are allowed).  We could drop using the pathspec struct\n> completely in addition to renaming the function (to what I'm still\n> unsure).\n\nYeah that sounds good too (with a caveat: I'm not a heavy user of\ngit-mv nor touching this code a lot, I might be missing something).\nIt'll take some looong time before somebody starts converting it to\nuse pathspec properly, I guess. prefix_path() would keep the code\nclean meanwhile.\n\n> I agree that this code should probably be rewritten and made a\n> bit cleaner, I don't know if that fits in the scope of this series or\n> should be done as a followup patch.  If you think it fits here then I\n> can try and find some time to do the rework.\n-- \nDuy\n"},{"id":"307235","messageId":"CACsJy8DtUwnOjBV49navkfgqPzEsNuX2LVaeVU=Ap2PWLpGFdA@mail.gmail.com","threadId":"44632","inReplyTo":"20161208000357.GJ116201@google.com","subject":"Re: [PATCH 02/17] dir: convert create_simplify to use the pathspec struct interface","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2016-12-08T11:05:44Z","receivedAt":"2016-12-08T11:06:19Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Thu, Dec 8, 2016 at 7:03 AM, Brandon Williams <bmwill@google.com> wrote:\n> On 12/07, Duy Nguyen wrote:\n>> On Wed, Dec 7, 2016 at 4:51 AM, Brandon Williams <bmwill@google.com> wrote:\n>> > Convert 'create_simplify()' to use the pathspec struct interface from\n>> > using the '_raw' entry in the pathspec.\n>>\n>> It would be even better to kill this create_simplify() and let\n>> simplify_away() handle struct pathspec directly.\n>>\n>> There is a bug in this code, that might have been found if we\n>> simpify_away() handled pathspec directly: the memcmp() in\n>> simplify_away() will not play well with :(icase) magic. My bad. If\n>> :(icase) is used, the easiest/safe way is simplify nothing. Later on\n>> maybe we can teach simplify_away() to do strncasecmp instead. We could\n>> ignore exclude patterns there too (although not excluding is not a\n>> bug).\n>\n> So are you implying that the simplify struct needs to be killed?  That\n> way the pathspec struct itself is being passed around instead?\n\nYes. simplify struct was a thing when pathspec was an array of char *.\nAt this point I think it can retire (when we have time to retire it)\n-- \nDuy\n"},{"id":"307272","messageId":"20161208180614.GO116201@google.com","threadId":"44632","inReplyTo":"CACsJy8DVuOdRsu4x9iFTwweSVn=RRJYzBTm43ufBevTWMf4Qmg@mail.gmail.com","subject":"Re: [PATCH 01/17] mv: convert to using pathspec struct interface","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2016-12-08T18:06:14Z","receivedAt":"2016-12-08T18:06:22Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"On 12/08, Duy Nguyen wrote:\n> On Thu, Dec 8, 2016 at 7:36 AM, Brandon Williams <bmwill@google.com> wrote:\n> >> > @@ -25,25 +26,43 @@ static const char **internal_copy_pathspec(const char *prefix,\n> >> >  {\n> >> >         int i;\n> >> >         const char **result;\n> >> > +       struct pathspec ps;\n> >> >         ALLOC_ARRAY(result, count + 1);\n> >> > -       COPY_ARRAY(result, pathspec, count);\n> >> > -       result[count] = NULL;\n> >> > +\n> >> > +       /* Create an intermediate copy of the pathspec based on the flags */\n> >> >         for (i = 0; i < count; i++) {\n> >> > -               int length = strlen(result[i]);\n> >> > +               int length = strlen(pathspec[i]);\n> >> >                 int to_copy = length;\n> >> > +               char *it;\n> >> >                 while (!(flags & KEEP_TRAILING_SLASH) &&\n> >> > -                      to_copy > 0 && is_dir_sep(result[i][to_copy - 1]))\n> >> > +                      to_copy > 0 && is_dir_sep(pathspec[i][to_copy - 1]))\n> >> >                         to_copy--;\n> >> > -               if (to_copy != length || flags & DUP_BASENAME) {\n> >> > -                       char *it = xmemdupz(result[i], to_copy);\n> >> > -                       if (flags & DUP_BASENAME) {\n> >> > -                               result[i] = xstrdup(basename(it));\n> >> > -                               free(it);\n> >> > -                       } else\n> >> > -                               result[i] = it;\n> >> > -               }\n> >> > +\n> >> > +               it = xmemdupz(pathspec[i], to_copy);\n> >> > +               if (flags & DUP_BASENAME) {\n> >> > +                       result[i] = xstrdup(basename(it));\n> >> > +                       free(it);\n> >> > +               } else\n> >> > +                       result[i] = it;\n> >> > +       }\n> >> > +       result[count] = NULL;\n> >> > +\n> >> > +       parse_pathspec(&ps,\n> >> > +                      PATHSPEC_ALL_MAGIC &\n> >> > +                      ~(PATHSPEC_FROMTOP | PATHSPEC_LITERAL),\n> >> > +                      PATHSPEC_KEEP_ORDER | PATHSPEC_PREFER_CWD,\n> >> > +                      prefix, result);\n> >> > +       assert(count == ps.nr);\n> >> > +\n> >> > +       /* Copy the pathspec and free the old intermediate strings */\n> >> > +       for (i = 0; i < count; i++) {\n> >> > +               const char *match = xstrdup(ps.items[i].match);\n> >> > +               free((char *) result[i]);\n> >> > +               result[i] = match;\n> >>\n> >> Sigh.. it looks so weird that we do all the parsing (in a _copy_\n> >> pathspec function) then remove struct pathspec and return the plain\n> >> string. I guess we can't do anything more until we rework cmd_mv code\n> >> to handle pathspec natively.\n> >>\n> >> At the least I think we should rename this function to something else.\n> >> But if you have time I really wish we could kill this function. I\n> >> haven't stared at cmd_mv() long and hard, but it looks to me that we\n> >> combining two separate functionalities in the same function here.\n> >>\n> >> If \"mv\" takes n arguments, then the first <n-1> arguments may be\n> >> pathspec, the last one is always a plain path. The \"dest_path =\n> >> internal_copy_pathspec...\" could be as simple as \"dest_path =\n> >> prefix_path(argv[argc - 1])\". the special treatment for this last\n> >> argument [1] can live here. Then, we can do parse_pathspec for the\n> >> <n-1> arguments in cmd_mv(). It's still far from perfect, because\n> >> cmd_mv can't handle pathspec properly, but it reduces the messy mess\n> >> in internal_copy_pathspec a bit, I hope.\n> >>\n> >\n> > Actually, after looking at this a bit more it seems like we could\n> > technically use prefix_path for both source and dest (based on how the\n> > current code is structured) since the source's provied must all exist (as\n> > in no wildcards are allowed).  We could drop using the pathspec struct\n> > completely in addition to renaming the function (to what I'm still\n> > unsure).\n> \n> Yeah that sounds good too (with a caveat: I'm not a heavy user of\n> git-mv nor touching this code a lot, I might be missing something).\n> It'll take some looong time before somebody starts converting it to\n> use pathspec properly, I guess. prefix_path() would keep the code\n> clean meanwhile.\n\nK for now I'll switch to using prefix_path() and rename the function\n`internal_prefix_pathspec()` as that is a bit more descriptive.\n\n-- \nBrandon Williams\n"},{"id":"307274","messageId":"20161208181957.GP116201@google.com","threadId":"44632","inReplyTo":"CACsJy8DtUwnOjBV49navkfgqPzEsNuX2LVaeVU=Ap2PWLpGFdA@mail.gmail.com","subject":"Re: [PATCH 02/17] dir: convert create_simplify to use the pathspec struct interface","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2016-12-08T18:19:57Z","receivedAt":"2016-12-08T18:20:05Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"On 12/08, Duy Nguyen wrote:\n> On Thu, Dec 8, 2016 at 7:03 AM, Brandon Williams <bmwill@google.com> wrote:\n> > On 12/07, Duy Nguyen wrote:\n> >> On Wed, Dec 7, 2016 at 4:51 AM, Brandon Williams <bmwill@google.com> wrote:\n> >> > Convert 'create_simplify()' to use the pathspec struct interface from\n> >> > using the '_raw' entry in the pathspec.\n> >>\n> >> It would be even better to kill this create_simplify() and let\n> >> simplify_away() handle struct pathspec directly.\n> >>\n> >> There is a bug in this code, that might have been found if we\n> >> simpify_away() handled pathspec directly: the memcmp() in\n> >> simplify_away() will not play well with :(icase) magic. My bad. If\n> >> :(icase) is used, the easiest/safe way is simplify nothing. Later on\n> >> maybe we can teach simplify_away() to do strncasecmp instead. We could\n> >> ignore exclude patterns there too (although not excluding is not a\n> >> bug).\n> >\n> > So are you implying that the simplify struct needs to be killed?  That\n> > way the pathspec struct itself is being passed around instead?\n> \n> Yes. simplify struct was a thing when pathspec was an array of char *.\n> At this point I think it can retire (when we have time to retire it)\n\nAlright, then for now I can leave this change as is and have a follow up\nseries that kills the simplify struct.\n\n-- \nBrandon Williams\n"},{"id":"307282","messageId":"1481223550-65277-1-git-send-email-bmwill@google.com","threadId":"44632","inReplyTo":"1481061106-117775-1-git-send-email-bmwill@google.com","subject":"[PATCH v2 00/16] pathspec cleanup","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2016-12-08T18:58:54Z","receivedAt":"2016-12-08T18:59:31Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"v2 of this series addresses the comments brought up in v1, most of which were\nsmall cosmetic changes (since this is mostly a cosmetic series to begin with).\n\nBrandon Williams (16):\n  mv: remove use of deprecated 'get_pathspec()'\n  dir: convert create_simplify to use the pathspec struct interface\n  dir: convert fill_directory to use the pathspec struct interface\n  ls-tree: convert show_recursive to use the pathspec struct interface\n  pathspec: remove the deprecated get_pathspec function\n  pathspec: copy and free owned memory\n  pathspec: remove unused variable from unsupported_magic\n  pathspec: always show mnemonic and name in unsupported_magic\n  pathspec: simpler logic to prefix original pathspec elements\n  pathspec: factor global magic into its own function\n  pathspec: create parse_short_magic function\n  pathspec: create parse_long_magic function\n  pathspec: create parse_element_magic helper\n  pathspec: create strip submodule slash helpers\n  pathspec: small readability changes\n  pathspec: rename prefix_pathspec to init_pathspec_item\n\n Documentation/technical/api-setup.txt |   2 -\n builtin/ls-tree.c                     |  16 +-\n builtin/mv.c                          |  50 ++--\n cache.h                               |   1 -\n dir.c                                 |  37 +--\n pathspec.c                            | 468 +++++++++++++++++++---------------\n pathspec.h                            |   5 +-\n 7 files changed, 317 insertions(+), 262 deletions(-)\n\n--- interdiff from v1\n\ndiff --git a/builtin/ls-tree.c b/builtin/ls-tree.c\nindex e0f4307..d7ebeb4 100644\n--- a/builtin/ls-tree.c\n+++ b/builtin/ls-tree.c\n@@ -173,8 +173,8 @@ 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() or tree_entry_interesting()\n \t */\n-\tparse_pathspec(&pathspec, PATHSPEC_GLOB | PATHSPEC_ICASE |\n-\t\t\t\t  PATHSPEC_EXCLUDE,\n+\tparse_pathspec(&pathspec, PATHSPEC_ALL_MAGIC &\n+\t\t\t\t  ~(PATHSPEC_FROMTOP | PATHSPEC_LITERAL),\n \t\t       PATHSPEC_PREFER_CWD,\n \t\t       prefix, argv + 1);\n \tfor (i = 0; i < pathspec.nr; i++)\ndiff --git a/builtin/mv.c b/builtin/mv.c\nindex b7cceb6..4e86dc5 100644\n--- a/builtin/mv.c\n+++ b/builtin/mv.c\n@@ -20,13 +20,13 @@ static const char * const builtin_mv_usage[] = {\n #define DUP_BASENAME 1\n #define KEEP_TRAILING_SLASH 2\n \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, unsigned flags)\n+static const char **internal_prefix_pathspec(const char *prefix,\n+\t\t\t\t\t     const char **pathspec,\n+\t\t\t\t\t     int count, unsigned flags)\n {\n \tint i;\n \tconst char **result;\n-\tstruct pathspec ps;\n+\tint prefixlen = prefix ? strlen(prefix) : 0;\n \tALLOC_ARRAY(result, count + 1);\n \n \t/* Create an intermediate copy of the pathspec based on the flags */\n@@ -42,25 +42,19 @@ static const char **internal_copy_pathspec(const char *prefix,\n \t\tif (flags & DUP_BASENAME) {\n \t\t\tresult[i] = xstrdup(basename(it));\n \t\t\tfree(it);\n-\t\t} else\n+\t\t} else {\n \t\t\tresult[i] = it;\n+\t\t}\n \t}\n \tresult[count] = NULL;\n \n-\tparse_pathspec(&ps,\n-\t\t       PATHSPEC_ALL_MAGIC &\n-\t\t       ~(PATHSPEC_FROMTOP | PATHSPEC_LITERAL),\n-\t\t       PATHSPEC_KEEP_ORDER | PATHSPEC_PREFER_CWD,\n-\t\t       prefix, result);\n-\tassert(count == ps.nr);\n-\n-\t/* Copy the pathspec and free the old intermediate strings */\n+\t/* Prefix the pathspec and free the old intermediate strings */\n \tfor (i = 0; i < count; i++) {\n+\t\tconst char *match = prefix_path(prefix, prefixlen, result[i]);\n \t\tfree((char *) result[i]);\n-\t\tresult[i] = xstrdup(ps.items[i].match);\n+\t\tresult[i] = match;\n \t}\n \n-\tclear_pathspec(&ps);\n \treturn result;\n }\n \n@@ -148,7 +142,7 @@ 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 = internal_copy_pathspec(prefix, argv, argc, 0);\n+\tsource = internal_prefix_pathspec(prefix, argv, argc, 0);\n \tmodes = xcalloc(argc, sizeof(enum update_mode));\n \t/*\n \t * Keep trailing slash, needed to let\n@@ -158,16 +152,16 @@ int cmd_mv(int argc, const char **argv, const char *prefix)\n \tflags = KEEP_TRAILING_SLASH;\n \tif (argc == 1 && is_directory(argv[0]) && !is_directory(argv[1]))\n \t\tflags = 0;\n-\tdest_path = internal_copy_pathspec(prefix, argv + argc, 1, flags);\n+\tdest_path = internal_prefix_pathspec(prefix, argv + argc, 1, flags);\n \tsubmodule_gitfile = xcalloc(argc, sizeof(char *));\n \n \tif (dest_path[0][0] == '\\0')\n \t\t/* special case: \".\" was normalized to \"\" */\n-\t\tdestination = internal_copy_pathspec(dest_path[0], argv, argc, DUP_BASENAME);\n+\t\tdestination = internal_prefix_pathspec(dest_path[0], argv, argc, DUP_BASENAME);\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 = internal_copy_pathspec(dest_path[0], argv, argc, DUP_BASENAME);\n+\t\tdestination = internal_prefix_pathspec(dest_path[0], argv, argc, DUP_BASENAME);\n \t} else {\n \t\tif (argc != 1)\n \t\t\tdie(_(\"destination '%s' is not a directory\"), dest_path[0]);\ndiff --git a/dir.c b/dir.c\nindex 8730a4f..a50b6f0 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -179,18 +179,21 @@ char *common_prefix(const struct pathspec *pathspec)\n \n int fill_directory(struct dir_struct *dir, const struct pathspec *pathspec)\n {\n-\tsize_t len;\n+\tchar *prefix;\n+\tsize_t prefix_len;\n \n \t/*\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+\tprefix = common_prefix(pathspec);\n+\tprefix_len = prefix ? strlen(prefix) : 0;\n \n \t/* Read the directory and prune it */\n-\tread_directory(dir, pathspec->nr ? pathspec->items[0].match : \"\",\n-\t\t       len, pathspec);\n-\treturn len;\n+\tread_directory(dir, prefix, prefix_len, pathspec);\n+\n+\tfree(prefix);\n+\treturn prefix_len;\n }\n \n int within_depth(const char *name, int namelen,\ndiff --git a/pathspec.c b/pathspec.c\nindex 66db257..08abdd3 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -89,41 +89,42 @@ static void prefix_magic(struct strbuf *sb, int prefixlen, unsigned magic)\n \n static inline int get_literal_global(void)\n {\n-\tstatic int literal_global = -1;\n+\tstatic int literal = -1;\n \n-\tif (literal_global < 0)\n-\t\tliteral_global = git_env_bool(GIT_LITERAL_PATHSPECS_ENVIRONMENT,\n-\t\t\t\t\t      0);\n-\treturn literal_global;\n+\tif (literal < 0)\n+\t\tliteral = git_env_bool(GIT_LITERAL_PATHSPECS_ENVIRONMENT, 0);\n+\n+\treturn literal;\n }\n \n static inline int get_glob_global(void)\n {\n-\tstatic int glob_global = -1;\n+\tstatic int glob = -1;\n+\n+\tif (glob < 0)\n+\t\tglob = git_env_bool(GIT_GLOB_PATHSPECS_ENVIRONMENT, 0);\n \n-\tif (glob_global < 0)\n-\t\tglob_global = git_env_bool(GIT_GLOB_PATHSPECS_ENVIRONMENT, 0);\n-\treturn glob_global;\n+\treturn glob;\n }\n \n static inline int get_noglob_global(void)\n {\n-\tstatic int noglob_global = -1;\n+\tstatic int noglob = -1;\n+\n+\tif (noglob < 0)\n+\t\tnoglob = git_env_bool(GIT_NOGLOB_PATHSPECS_ENVIRONMENT, 0);\n \n-\tif (noglob_global < 0)\n-\t\tnoglob_global = git_env_bool(GIT_NOGLOB_PATHSPECS_ENVIRONMENT,\n-\t\t\t\t\t     0);\n-\treturn noglob_global;\n+\treturn noglob;\n }\n \n static inline int get_icase_global(void)\n {\n-\tstatic int icase_global = -1;\n+\tstatic int icase = -1;\n \n-\tif (icase_global < 0)\n-\t\ticase_global = git_env_bool(GIT_ICASE_PATHSPECS_ENVIRONMENT, 0);\n+\tif (icase < 0)\n+\t\ticase = git_env_bool(GIT_ICASE_PATHSPECS_ENVIRONMENT, 0);\n \n-\treturn icase_global;\n+\treturn icase;\n }\n \n static int get_global_magic(int element_magic)\n@@ -296,13 +297,11 @@ static void strip_submodule_slash_expensive(struct pathspec_item *item)\n }\n \n /*\n- * Take an element of a pathspec and check for magic signatures.\n- * Append the result to the prefix. Return the magic bitmap.\n+ * Perform the initialization of a pathspec_item based on a pathspec element.\n  */\n-static unsigned prefix_pathspec(struct pathspec_item *item,\n-\t\t\t\tunsigned flags,\n-\t\t\t\tconst char *prefix, int prefixlen,\n-\t\t\t\tconst char *elt)\n+static void init_pathspec_item(struct pathspec_item *item, unsigned flags,\n+\t\t\t       const char *prefix, int prefixlen,\n+\t\t\t       const char *elt)\n {\n \tunsigned magic = 0, element_magic = 0;\n \tconst char *copyfrom = elt;\n@@ -310,7 +309,9 @@ static unsigned prefix_pathspec(struct pathspec_item *item,\n \tint pathspec_prefix = -1;\n \n \t/* PATHSPEC_LITERAL_PATH ignores magic */\n-\tif (!(flags & PATHSPEC_LITERAL_PATH)) {\n+\tif (flags & PATHSPEC_LITERAL_PATH) {\n+\t\tmagic = PATHSPEC_LITERAL;\n+\t} else {\n \t\tcopyfrom = parse_element_magic(&element_magic,\n \t\t\t\t\t       &pathspec_prefix,\n \t\t\t\t\t       elt);\n@@ -318,6 +319,8 @@ static unsigned prefix_pathspec(struct pathspec_item *item,\n \t\tmagic |= get_global_magic(element_magic);\n \t}\n \n+\titem->magic = 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@@ -390,7 +393,6 @@ static unsigned prefix_pathspec(struct pathspec_item *item,\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 static int pathspec_item_cmp(const void *a_, const void *b_)\n@@ -489,17 +491,12 @@ void parse_pathspec(struct pathspec *pathspec,\n \tfor (i = 0; i < n; i++) {\n \t\tentry = argv[i];\n \n-\t\titem[i].magic = prefix_pathspec(item + i,\n-\t\t\t\t\t\tflags,\n-\t\t\t\t\t\tprefix, prefixlen, entry);\n-\t\tif ((flags & PATHSPEC_LITERAL_PATH) &&\n-\t\t    !(magic_mask & PATHSPEC_LITERAL))\n-\t\t\titem[i].magic |= PATHSPEC_LITERAL;\n+\t\tinit_pathspec_item(item + i, flags, prefix, prefixlen, entry);\n+\n \t\tif (item[i].magic & PATHSPEC_EXCLUDE)\n \t\t\tnr_exclude++;\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\tunsupported_magic(entry, item[i].magic & magic_mask);\n \n \t\tif ((flags & PATHSPEC_SYMLINK_LEADING_PATH) &&\n \t\t    has_symlink_leading_path(item[i].match, item[i].len)) {\n\n-- \n2.8.0.rc3.226.g39d4020\n\n"},{"id":"307283","messageId":"1481223550-65277-2-git-send-email-bmwill@google.com","threadId":"44632","inReplyTo":"1481223550-65277-1-git-send-email-bmwill@google.com","subject":"[PATCH v2 01/16] mv: remove use of deprecated 'get_pathspec()'","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2016-12-08T18:58:55Z","receivedAt":"2016-12-08T18:59:34Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Convert the 'internal_copy_pathspec()' function to 'prefix_path()'\ninstead of using the deprecated 'get_pathspec()' interface.  Also,\nrename 'internal_copy_pathspec()' to 'internal_prefix_pathspec()' to be\nmore descriptive of what the funciton is actually doing.\n\nIn addition to this, fix a memory leak caused by only duplicating some\nof the pathspec elements.  Instead always duplicate all of the the\npathspec elements as an intermediate step (with modificationed based on\nthe passed in flags).  This way the intermediate strings can then be\nfreed after getting the result from 'prefix_path()'.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n builtin/mv.c | 50 +++++++++++++++++++++++++++++++-------------------\n 1 file changed, 31 insertions(+), 19 deletions(-)\n\ndiff --git a/builtin/mv.c b/builtin/mv.c\nindex 2f43877..4e86dc5 100644\n--- a/builtin/mv.c\n+++ b/builtin/mv.c\n@@ -4,6 +4,7 @@\n  * Copyright (C) 2006 Johannes Schindelin\n  */\n #include \"builtin.h\"\n+#include \"pathspec.h\"\n #include \"lockfile.h\"\n #include \"dir.h\"\n #include \"cache-tree.h\"\n@@ -19,31 +20,42 @@ static const char * const builtin_mv_usage[] = {\n #define DUP_BASENAME 1\n #define KEEP_TRAILING_SLASH 2\n \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, unsigned flags)\n+static const char **internal_prefix_pathspec(const char *prefix,\n+\t\t\t\t\t     const char **pathspec,\n+\t\t\t\t\t     int count, unsigned flags)\n {\n \tint i;\n \tconst char **result;\n+\tint prefixlen = prefix ? strlen(prefix) : 0;\n \tALLOC_ARRAY(result, count + 1);\n-\tCOPY_ARRAY(result, pathspec, count);\n-\tresult[count] = NULL;\n+\n+\t/* Create an intermediate copy of the pathspec based on the flags */\n \tfor (i = 0; i < count; i++) {\n-\t\tint length = strlen(result[i]);\n+\t\tint length = strlen(pathspec[i]);\n \t\tint to_copy = length;\n+\t\tchar *it;\n \t\twhile (!(flags & KEEP_TRAILING_SLASH) &&\n-\t\t       to_copy > 0 && is_dir_sep(result[i][to_copy - 1]))\n+\t\t       to_copy > 0 && is_dir_sep(pathspec[i][to_copy - 1]))\n \t\t\tto_copy--;\n-\t\tif (to_copy != length || flags & DUP_BASENAME) {\n-\t\t\tchar *it = xmemdupz(result[i], to_copy);\n-\t\t\tif (flags & DUP_BASENAME) {\n-\t\t\t\tresult[i] = xstrdup(basename(it));\n-\t\t\t\tfree(it);\n-\t\t\t} else\n-\t\t\t\tresult[i] = it;\n+\n+\t\tit = xmemdupz(pathspec[i], to_copy);\n+\t\tif (flags & DUP_BASENAME) {\n+\t\t\tresult[i] = xstrdup(basename(it));\n+\t\t\tfree(it);\n+\t\t} else {\n+\t\t\tresult[i] = it;\n \t\t}\n \t}\n-\treturn get_pathspec(prefix, result);\n+\tresult[count] = NULL;\n+\n+\t/* Prefix the pathspec and free the old intermediate strings */\n+\tfor (i = 0; i < count; i++) {\n+\t\tconst char *match = prefix_path(prefix, prefixlen, result[i]);\n+\t\tfree((char *) result[i]);\n+\t\tresult[i] = match;\n+\t}\n+\n+\treturn result;\n }\n \n static const char *add_slash(const char *path)\n@@ -130,7 +142,7 @@ 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 = internal_copy_pathspec(prefix, argv, argc, 0);\n+\tsource = internal_prefix_pathspec(prefix, argv, argc, 0);\n \tmodes = xcalloc(argc, sizeof(enum update_mode));\n \t/*\n \t * Keep trailing slash, needed to let\n@@ -140,16 +152,16 @@ int cmd_mv(int argc, const char **argv, const char *prefix)\n \tflags = KEEP_TRAILING_SLASH;\n \tif (argc == 1 && is_directory(argv[0]) && !is_directory(argv[1]))\n \t\tflags = 0;\n-\tdest_path = internal_copy_pathspec(prefix, argv + argc, 1, flags);\n+\tdest_path = internal_prefix_pathspec(prefix, argv + argc, 1, flags);\n \tsubmodule_gitfile = xcalloc(argc, sizeof(char *));\n \n \tif (dest_path[0][0] == '\\0')\n \t\t/* special case: \".\" was normalized to \"\" */\n-\t\tdestination = internal_copy_pathspec(dest_path[0], argv, argc, DUP_BASENAME);\n+\t\tdestination = internal_prefix_pathspec(dest_path[0], argv, argc, DUP_BASENAME);\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 = internal_copy_pathspec(dest_path[0], argv, argc, DUP_BASENAME);\n+\t\tdestination = internal_prefix_pathspec(dest_path[0], argv, argc, DUP_BASENAME);\n \t} else {\n \t\tif (argc != 1)\n \t\t\tdie(_(\"destination '%s' is not a directory\"), dest_path[0]);\n-- \n2.8.0.rc3.226.g39d4020\n\n"},{"id":"307284","messageId":"1481223550-65277-3-git-send-email-bmwill@google.com","threadId":"44632","inReplyTo":"1481223550-65277-1-git-send-email-bmwill@google.com","subject":"[PATCH v2 02/16] dir: convert create_simplify to use the pathspec struct interface","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2016-12-08T18:58:56Z","receivedAt":"2016-12-08T18:59:38Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Convert 'create_simplify()' to use the pathspec struct interface from\nusing the '_raw' entry in the pathspec.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n dir.c | 25 ++++++++++++-------------\n 1 file changed, 12 insertions(+), 13 deletions(-)\n\ndiff --git a/dir.c b/dir.c\nindex bfa8c8a..7df292b 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -1787,25 +1787,24 @@ static int cmp_name(const void *p1, const void *p2)\n \treturn name_compare(e1->name, e1->len, e2->name, e2->len);\n }\n \n-static struct path_simplify *create_simplify(const char **pathspec)\n+static struct path_simplify *create_simplify(const struct pathspec *pathspec)\n {\n-\tint nr, alloc = 0;\n+\tint i;\n \tstruct path_simplify *simplify = NULL;\n \n-\tif (!pathspec)\n+\tif (!pathspec || !pathspec->nr)\n \t\treturn NULL;\n \n-\tfor (nr = 0 ; ; nr++) {\n+\tALLOC_ARRAY(simplify, pathspec->nr + 1);\n+\tfor (i = 0; i < pathspec->nr; i++) {\n \t\tconst char *match;\n-\t\tALLOC_GROW(simplify, nr + 1, alloc);\n-\t\tmatch = *pathspec++;\n-\t\tif (!match)\n-\t\t\tbreak;\n-\t\tsimplify[nr].path = match;\n-\t\tsimplify[nr].len = simple_length(match);\n+\t\tmatch = pathspec->items[i].match;\n+\t\tsimplify[i].path = match;\n+\t\tsimplify[i].len = pathspec->items[i].nowildcard_len;\n \t}\n-\tsimplify[nr].path = NULL;\n-\tsimplify[nr].len = 0;\n+\tsimplify[i].path = NULL;\n+\tsimplify[i].len = 0;\n+\n \treturn simplify;\n }\n \n@@ -2036,7 +2035,7 @@ int read_directory(struct dir_struct *dir, const char *path, int len, const stru\n \t * subset of positive ones, which has no impacts on\n \t * create_simplify().\n \t */\n-\tsimplify = create_simplify(pathspec ? pathspec->_raw : NULL);\n+\tsimplify = create_simplify(pathspec);\n \tuntracked = validate_untracked_cache(dir, len, pathspec);\n \tif (!untracked)\n \t\t/*\n-- \n2.8.0.rc3.226.g39d4020\n\n"},{"id":"307285","messageId":"1481223550-65277-4-git-send-email-bmwill@google.com","threadId":"44632","inReplyTo":"1481223550-65277-1-git-send-email-bmwill@google.com","subject":"[PATCH v2 03/16] dir: convert fill_directory to use the pathspec struct interface","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2016-12-08T18:58:57Z","receivedAt":"2016-12-08T18:59:40Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Convert 'fill_directory()' to use the pathspec struct interface from\nusing the '_raw' entry in the pathspec struct.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n dir.c | 12 ++++++++----\n 1 file changed, 8 insertions(+), 4 deletions(-)\n\ndiff --git a/dir.c b/dir.c\nindex 7df292b..a50b6f0 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -179,17 +179,21 @@ char *common_prefix(const struct pathspec *pathspec)\n \n int fill_directory(struct dir_struct *dir, const struct pathspec *pathspec)\n {\n-\tsize_t len;\n+\tchar *prefix;\n+\tsize_t prefix_len;\n \n \t/*\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+\tprefix = common_prefix(pathspec);\n+\tprefix_len = prefix ? strlen(prefix) : 0;\n \n \t/* Read the directory and prune it */\n-\tread_directory(dir, pathspec->nr ? pathspec->_raw[0] : \"\", len, pathspec);\n-\treturn len;\n+\tread_directory(dir, prefix, prefix_len, pathspec);\n+\n+\tfree(prefix);\n+\treturn prefix_len;\n }\n \n int within_depth(const char *name, int namelen,\n-- \n2.8.0.rc3.226.g39d4020\n\n"},{"id":"307286","messageId":"1481223550-65277-7-git-send-email-bmwill@google.com","threadId":"44632","inReplyTo":"1481223550-65277-1-git-send-email-bmwill@google.com","subject":"[PATCH v2 06/16] pathspec: copy and free owned memory","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2016-12-08T18:59:00Z","receivedAt":"2016-12-08T18:59:46Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"The 'original' string entry in a pathspec_item is only duplicated some\nof the time, instead always make a copy of the original and take\nownership of the memory.\n\nSince both 'match' and 'original' string entries in a pathspec_item are\nowned by the pathspec struct, they need to be freed when clearing the\npathspec struct (in 'clear_pathspec()') and duplicated when copying the\npathspec struct (in 'copy_pathspec()').\n\nAlso change the type of 'match' and 'original' to 'char *' in order to\nmore explicitly show the ownership of the memory.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n pathspec.c | 22 ++++++++++++++++++----\n pathspec.h |  4 ++--\n 2 files changed, 20 insertions(+), 6 deletions(-)\n\ndiff --git a/pathspec.c b/pathspec.c\nindex 1f918cb..8f367f0 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -259,8 +259,9 @@ static unsigned prefix_pathspec(struct pathspec_item *item,\n \t\t}\n \t\tstrbuf_addstr(&sb, match);\n \t\titem->original = strbuf_detach(&sb, NULL);\n-\t} else\n-\t\titem->original = elt;\n+\t} else {\n+\t\titem->original = xstrdup(elt);\n+\t}\n \titem->len = strlen(item->match);\n \titem->prefix = prefixlen;\n \n@@ -388,8 +389,8 @@ void parse_pathspec(struct pathspec *pathspec,\n \t\t\tdie(\"BUG: PATHSPEC_PREFER_CWD requires arguments\");\n \n \t\tpathspec->items = item = xcalloc(1, sizeof(*item));\n-\t\titem->match = prefix;\n-\t\titem->original = prefix;\n+\t\titem->match = xstrdup(prefix);\n+\t\titem->original = xstrdup(prefix);\n \t\titem->nowildcard_len = item->len = strlen(prefix);\n \t\titem->prefix = item->len;\n \t\tpathspec->nr = 1;\n@@ -453,13 +454,26 @@ void parse_pathspec(struct pathspec *pathspec,\n \n void copy_pathspec(struct pathspec *dst, const struct pathspec *src)\n {\n+\tint i;\n+\n \t*dst = *src;\n \tALLOC_ARRAY(dst->items, dst->nr);\n \tCOPY_ARRAY(dst->items, src->items, dst->nr);\n+\n+\tfor (i = 0; i < dst->nr; i++) {\n+\t\tdst->items[i].match = xstrdup(src->items[i].match);\n+\t\tdst->items[i].original = xstrdup(src->items[i].original);\n+\t}\n }\n \n void clear_pathspec(struct pathspec *pathspec)\n {\n+\tint i;\n+\n+\tfor (i = 0; i < pathspec->nr; i++) {\n+\t\tfree(pathspec->items[i].match);\n+\t\tfree(pathspec->items[i].original);\n+\t}\n \tfree(pathspec->items);\n \tpathspec->items = NULL;\n }\ndiff --git a/pathspec.h b/pathspec.h\nindex 70a592e..49fd823 100644\n--- a/pathspec.h\n+++ b/pathspec.h\n@@ -25,8 +25,8 @@ struct pathspec {\n \tunsigned magic;\n \tint max_depth;\n \tstruct pathspec_item {\n-\t\tconst char *match;\n-\t\tconst char *original;\n+\t\tchar *match;\n+\t\tchar *original;\n \t\tunsigned magic;\n \t\tint len, prefix;\n \t\tint nowildcard_len;\n-- \n2.8.0.rc3.226.g39d4020\n\n"},{"id":"307287","messageId":"1481223550-65277-12-git-send-email-bmwill@google.com","threadId":"44632","inReplyTo":"1481223550-65277-1-git-send-email-bmwill@google.com","subject":"[PATCH v2 11/16] pathspec: create parse_short_magic function","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2016-12-08T18:59:05Z","receivedAt":"2016-12-08T18:59:49Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Factor out the logic responsible for parsing short magic into its own\nfunction.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n pathspec.c | 54 ++++++++++++++++++++++++++++++++++++------------------\n 1 file changed, 36 insertions(+), 18 deletions(-)\n\ndiff --git a/pathspec.c b/pathspec.c\nindex 523d7bf..29054d2 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -157,6 +157,41 @@ static int get_global_magic(int element_magic)\n }\n \n /*\n+ * Parse the pathspec element looking for short magic\n+ *\n+ * saves all magic in 'magic'\n+ * returns the position in 'elem' after all magic has been parsed\n+ */\n+static const char *parse_short_magic(unsigned *magic, const char *elem)\n+{\n+\tconst char *pos;\n+\n+\tfor (pos = elem + 1; *pos && *pos != ':'; pos++) {\n+\t\tchar ch = *pos;\n+\t\tint i;\n+\n+\t\tif (!is_pathspec_magic(ch))\n+\t\t\tbreak;\n+\n+\t\tfor (i = 0; i < ARRAY_SIZE(pathspec_magic); i++) {\n+\t\t\tif (pathspec_magic[i].mnemonic == ch) {\n+\t\t\t\t*magic |= pathspec_magic[i].bit;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t}\n+\n+\t\tif (ARRAY_SIZE(pathspec_magic) <= i)\n+\t\t\tdie(_(\"Unimplemented pathspec magic '%c' in '%s'\"),\n+\t\t\t    ch, elem);\n+\t}\n+\n+\tif (*pos == ':')\n+\t\tpos++;\n+\n+\treturn pos;\n+}\n+\n+/*\n  * Take an element of a pathspec and check for magic signatures.\n  * Append the result to the prefix. Return the magic bitmap.\n  *\n@@ -220,24 +255,7 @@ static unsigned prefix_pathspec(struct pathspec_item *item, unsigned flags,\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\telement_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-\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\tcopyfrom = parse_short_magic(&element_magic, elt);\n \t}\n \n \tmagic |= element_magic;\n-- \n2.8.0.rc3.226.g39d4020\n\n"},{"id":"307288","messageId":"1481223550-65277-11-git-send-email-bmwill@google.com","threadId":"44632","inReplyTo":"1481223550-65277-1-git-send-email-bmwill@google.com","subject":"[PATCH v2 10/16] pathspec: factor global magic into its own function","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2016-12-08T18:59:04Z","receivedAt":"2016-12-08T18:59:50Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Create helper functions to read the global magic environment variables\nin additon to factoring out the global magic gathering logic into its\nown function.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n pathspec.c | 127 +++++++++++++++++++++++++++++++++++++------------------------\n 1 file changed, 78 insertions(+), 49 deletions(-)\n\ndiff --git a/pathspec.c b/pathspec.c\nindex 49adea4..523d7bf 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -87,6 +87,75 @@ static void prefix_magic(struct strbuf *sb, int prefixlen, unsigned magic)\n \tstrbuf_addf(sb, \",prefix:%d)\", prefixlen);\n }\n \n+static inline int get_literal_global(void)\n+{\n+\tstatic int literal = -1;\n+\n+\tif (literal < 0)\n+\t\tliteral = git_env_bool(GIT_LITERAL_PATHSPECS_ENVIRONMENT, 0);\n+\n+\treturn literal;\n+}\n+\n+static inline int get_glob_global(void)\n+{\n+\tstatic int glob = -1;\n+\n+\tif (glob < 0)\n+\t\tglob = git_env_bool(GIT_GLOB_PATHSPECS_ENVIRONMENT, 0);\n+\n+\treturn glob;\n+}\n+\n+static inline int get_noglob_global(void)\n+{\n+\tstatic int noglob = -1;\n+\n+\tif (noglob < 0)\n+\t\tnoglob = git_env_bool(GIT_NOGLOB_PATHSPECS_ENVIRONMENT, 0);\n+\n+\treturn noglob;\n+}\n+\n+static inline int get_icase_global(void)\n+{\n+\tstatic int icase = -1;\n+\n+\tif (icase < 0)\n+\t\ticase = git_env_bool(GIT_ICASE_PATHSPECS_ENVIRONMENT, 0);\n+\n+\treturn icase;\n+}\n+\n+static int get_global_magic(int element_magic)\n+{\n+\tint global_magic = 0;\n+\n+\tif (get_literal_global())\n+\t\tglobal_magic |= PATHSPEC_LITERAL;\n+\n+\t/* --glob-pathspec is overridden by :(literal) */\n+\tif (get_glob_global() && !(element_magic & PATHSPEC_LITERAL))\n+\t\tglobal_magic |= PATHSPEC_GLOB;\n+\n+\tif (get_glob_global() && get_noglob_global())\n+\t\tdie(_(\"global 'glob' and 'noglob' pathspec settings are incompatible\"));\n+\n+\tif (get_icase_global())\n+\t\tglobal_magic |= PATHSPEC_ICASE;\n+\n+\tif ((global_magic & PATHSPEC_LITERAL) &&\n+\t    (global_magic & ~PATHSPEC_LITERAL))\n+\t\tdie(_(\"global 'literal' pathspec setting is incompatible \"\n+\t\t      \"with all other global pathspec settings\"));\n+\n+\t/* --noglob-pathspec adds :(literal) _unless_ :(glob) is specified */\n+\tif (get_noglob_global() && !(element_magic & PATHSPEC_GLOB))\n+\t\tglobal_magic |= PATHSPEC_LITERAL;\n+\n+\treturn global_magic;\n+}\n+\n /*\n  * Take an element of a pathspec and check for magic signatures.\n  * Append the result to the prefix. Return the magic bitmap.\n@@ -104,46 +173,12 @@ static unsigned prefix_pathspec(struct pathspec_item *item, unsigned flags,\n \t\t\t\tconst char *prefix, int prefixlen,\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-\tstatic int icase_global = -1;\n-\tunsigned magic = 0, element_magic = 0, global_magic = 0;\n+\tunsigned magic = 0, element_magic = 0;\n \tconst char *copyfrom = elt;\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 (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-\n-\tif (icase_global < 0)\n-\t\ticase_global = git_env_bool(GIT_ICASE_PATHSPECS_ENVIRONMENT, 0);\n-\tif (icase_global)\n-\t\tglobal_magic |= PATHSPEC_ICASE;\n-\n-\tif ((global_magic & PATHSPEC_LITERAL) &&\n-\t    (global_magic & ~PATHSPEC_LITERAL))\n-\t\tdie(_(\"global 'literal' pathspec setting is incompatible \"\n-\t\t      \"with all other global pathspec settings\"));\n-\n-\tif (flags & PATHSPEC_LITERAL_PATH)\n-\t\tglobal_magic = 0;\n-\n-\tif (elt[0] != ':' || literal_global ||\n+\tif (elt[0] != ':' || get_literal_global() ||\n \t    (flags & PATHSPEC_LITERAL_PATH)) {\n \t\t; /* nothing to do */\n \t} else if (elt[1] == '(') {\n@@ -207,15 +242,11 @@ static unsigned prefix_pathspec(struct pathspec_item *item, unsigned flags,\n \n \tmagic |= element_magic;\n \n-\t/* --noglob-pathspec adds :(literal) _unless_ :(glob) is specified */\n-\tif (noglob_global && !(magic & PATHSPEC_GLOB))\n-\t\tglobal_magic |= PATHSPEC_LITERAL;\n-\n-\t/* --glob-pathspec is overridden by :(literal) */\n-\tif ((global_magic & PATHSPEC_GLOB) && (magic & PATHSPEC_LITERAL))\n-\t\tglobal_magic &= ~PATHSPEC_GLOB;\n-\n-\tmagic |= global_magic;\n+\t/* PATHSPEC_LITERAL_PATH ignores magic */\n+\tif (flags & PATHSPEC_LITERAL_PATH)\n+\t\tmagic = PATHSPEC_LITERAL;\n+\telse\n+\t\tmagic |= get_global_magic(element_magic);\n \n \tif (pathspec_prefix >= 0 &&\n \t    (prefixlen || (prefix && *prefix)))\n@@ -241,7 +272,7 @@ static unsigned prefix_pathspec(struct pathspec_item *item, unsigned flags,\n \t * original. Useful for passing to another command.\n \t */\n \tif ((flags & PATHSPEC_PREFIX_ORIGIN) &&\n-\t    prefixlen && !literal_global) {\n+\t    prefixlen && !get_literal_global()) {\n \t\tstruct strbuf sb = STRBUF_INIT;\n \n \t\t/* Preserve the actual prefix length of each pattern */\n@@ -407,9 +438,7 @@ void parse_pathspec(struct pathspec *pathspec,\n \n \t\titem[i].magic = prefix_pathspec(item + i, flags,\n \t\t\t\t\t\tprefix, prefixlen, entry);\n-\t\tif ((flags & PATHSPEC_LITERAL_PATH) &&\n-\t\t    !(magic_mask & PATHSPEC_LITERAL))\n-\t\t\titem[i].magic |= PATHSPEC_LITERAL;\n+\n \t\tif (item[i].magic & PATHSPEC_EXCLUDE)\n \t\t\tnr_exclude++;\n \t\tif (item[i].magic & magic_mask)\n-- \n2.8.0.rc3.226.g39d4020\n\n"},{"id":"307289","messageId":"1481223550-65277-10-git-send-email-bmwill@google.com","threadId":"44632","inReplyTo":"1481223550-65277-1-git-send-email-bmwill@google.com","subject":"[PATCH v2 09/16] pathspec: simpler logic to prefix original pathspec elements","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2016-12-08T18:59:03Z","receivedAt":"2016-12-08T18:59:51Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"The logic used to prefix an original pathspec element with 'prefix'\nmagic is more general purpose and can be used for more than just short\nmagic.  Remove the extra code paths and rename 'prefix_short_magic' to\n'prefix_magic' to better indicate that it can be used in more general\nsituations.\n\nAlso, slightly change the logic which decides when to prefix the\noriginal element in order to prevent a pathspec of \".\" from getting\nconverted to \"\" (empty string).\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n pathspec.c | 33 +++++++++++++--------------------\n 1 file changed, 13 insertions(+), 20 deletions(-)\n\ndiff --git a/pathspec.c b/pathspec.c\nindex a360193..49adea4 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -74,13 +74,12 @@ static struct pathspec_magic {\n \t{ PATHSPEC_EXCLUDE, '!', \"exclude\" },\n };\n \n-static void prefix_short_magic(struct strbuf *sb, int prefixlen,\n-\t\t\t       unsigned short_magic)\n+static void prefix_magic(struct strbuf *sb, int prefixlen, unsigned magic)\n {\n \tint i;\n \tstrbuf_addstr(sb, \":(\");\n \tfor (i = 0; i < ARRAY_SIZE(pathspec_magic); i++)\n-\t\tif (short_magic & pathspec_magic[i].bit) {\n+\t\tif (magic & pathspec_magic[i].bit) {\n \t\t\tif (sb->buf[sb->len - 1] != '(')\n \t\t\t\tstrbuf_addch(sb, ',');\n \t\t\tstrbuf_addstr(sb, pathspec_magic[i].name);\n@@ -109,8 +108,8 @@ static unsigned prefix_pathspec(struct pathspec_item *item, unsigned flags,\n \tstatic int glob_global = -1;\n \tstatic int noglob_global = -1;\n \tstatic int icase_global = -1;\n-\tunsigned magic = 0, short_magic = 0, global_magic = 0;\n-\tconst char *copyfrom = elt, *long_magic_end = NULL;\n+\tunsigned magic = 0, element_magic = 0, global_magic = 0;\n+\tconst char *copyfrom = elt;\n \tchar *match;\n \tint i, pathspec_prefix = -1;\n \n@@ -164,7 +163,7 @@ static unsigned prefix_pathspec(struct pathspec_item *item, unsigned flags,\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\telement_magic |= pathspec_magic[i].bit;\n \t\t\t\t\tbreak;\n \t\t\t\t}\n \t\t\t\tif (starts_with(copyfrom, \"prefix:\")) {\n@@ -183,7 +182,6 @@ static unsigned prefix_pathspec(struct pathspec_item *item, unsigned flags,\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@@ -196,7 +194,7 @@ static unsigned prefix_pathspec(struct pathspec_item *item, unsigned flags,\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\tshort_magic |= pathspec_magic[i].bit;\n+\t\t\t\t\telement_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@@ -207,7 +205,7 @@ static unsigned prefix_pathspec(struct pathspec_item *item, unsigned flags,\n \t\t\tcopyfrom++;\n \t}\n \n-\tmagic |= short_magic;\n+\tmagic |= element_magic;\n \n \t/* --noglob-pathspec adds :(literal) _unless_ :(glob) is specified */\n \tif (noglob_global && !(magic & PATHSPEC_GLOB))\n@@ -242,18 +240,13 @@ static unsigned prefix_pathspec(struct pathspec_item *item, unsigned flags,\n \t * Prefix the pathspec (keep all magic) and assign to\n \t * original. Useful for passing to another command.\n \t */\n-\tif (flags & PATHSPEC_PREFIX_ORIGIN) {\n+\tif ((flags & PATHSPEC_PREFIX_ORIGIN) &&\n+\t    prefixlen && !literal_global) {\n \t\tstruct strbuf sb = STRBUF_INIT;\n-\t\tif (prefixlen && !literal_global) {\n-\t\t\t/* Preserve the actual prefix length of each pattern */\n-\t\t\tif (short_magic)\n-\t\t\t\tprefix_short_magic(&sb, prefixlen, short_magic);\n-\t\t\telse if (long_magic_end) {\n-\t\t\t\tstrbuf_add(&sb, elt, long_magic_end - elt);\n-\t\t\t\tstrbuf_addf(&sb, \",prefix:%d)\", prefixlen);\n-\t\t\t} else\n-\t\t\t\tstrbuf_addf(&sb, \":(prefix:%d)\", prefixlen);\n-\t\t}\n+\n+\t\t/* Preserve the actual prefix length of each pattern */\n+\t\tprefix_magic(&sb, prefixlen, element_magic);\n+\n \t\tstrbuf_addstr(&sb, match);\n \t\titem->original = strbuf_detach(&sb, NULL);\n \t} else {\n-- \n2.8.0.rc3.226.g39d4020\n\n"},{"id":"307290","messageId":"1481223550-65277-13-git-send-email-bmwill@google.com","threadId":"44632","inReplyTo":"1481223550-65277-1-git-send-email-bmwill@google.com","subject":"[PATCH v2 12/16] pathspec: create parse_long_magic function","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2016-12-08T18:59:06Z","receivedAt":"2016-12-08T18:59:56Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Factor out the logic responsible for parsing long magic into its own\nfunction.  As well as hoist the prefix check logic outside of the inner\nloop as there isn't anything that needs to be done after matching\n\"prefix:\".\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n pathspec.c | 92 ++++++++++++++++++++++++++++++++++++++------------------------\n 1 file changed, 57 insertions(+), 35 deletions(-)\n\ndiff --git a/pathspec.c b/pathspec.c\nindex 29054d2..6e9555e 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -157,6 +157,60 @@ static int get_global_magic(int element_magic)\n }\n \n /*\n+ * Parse the pathspec element looking for long magic\n+ *\n+ * saves all magic in 'magic'\n+ * if prefix magic is used, save the prefix length in 'prefix_len'\n+ * returns the position in 'elem' after all magic has been parsed\n+ */\n+static const char *parse_long_magic(unsigned *magic, int *prefix_len,\n+\t\t\t\t    const char *elem)\n+{\n+\tconst char *pos;\n+\tconst char *nextat;\n+\n+\tfor (pos = elem + 2; *pos && *pos != ')'; pos = nextat) {\n+\t\tsize_t len = strcspn(pos, \",)\");\n+\t\tint i;\n+\n+\t\tif (pos[len] == ',')\n+\t\t\tnextat = pos + len + 1; /* handle ',' */\n+\t\telse\n+\t\t\tnextat = pos + len; /* handle ')' and '\\0' */\n+\n+\t\tif (!len)\n+\t\t\tcontinue;\n+\n+\t\tif (starts_with(pos, \"prefix:\")) {\n+\t\t\tchar *endptr;\n+\t\t\t*prefix_len = strtol(pos + 7, &endptr, 10);\n+\t\t\tif (endptr - pos != len)\n+\t\t\t\tdie(_(\"invalid parameter for pathspec magic 'prefix'\"));\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\tfor (i = 0; i < ARRAY_SIZE(pathspec_magic); i++) {\n+\t\t\tif (strlen(pathspec_magic[i].name) == len &&\n+\t\t\t    !strncmp(pathspec_magic[i].name, pos, len)) {\n+\t\t\t\t*magic |= pathspec_magic[i].bit;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t}\n+\n+\t\tif (ARRAY_SIZE(pathspec_magic) <= i)\n+\t\t\tdie(_(\"Invalid pathspec magic '%.*s' in '%s'\"),\n+\t\t\t    (int) len, pos, elem);\n+\t}\n+\n+\tif (*pos != ')')\n+\t\tdie(_(\"Missing ')' at the end of pathspec magic in '%s'\"),\n+\t\t    elem);\n+\tpos++;\n+\n+\treturn pos;\n+}\n+\n+/*\n  * Parse the pathspec element looking for short magic\n  *\n  * saves all magic in 'magic'\n@@ -218,41 +272,9 @@ static unsigned prefix_pathspec(struct pathspec_item *item, unsigned flags,\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 + 1;\n-\t\t\telse\n-\t\t\t\t/* handle ')' and '\\0' */\n-\t\t\t\tnextat = copyfrom + len;\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\telement_magic |= pathspec_magic[i].bit;\n-\t\t\t\t\tbreak;\n-\t\t\t\t}\n-\t\t\t\tif (starts_with(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\tcopyfrom++;\n+\t\tcopyfrom = parse_long_magic(&element_magic,\n+\t\t\t\t\t    &pathspec_prefix,\n+\t\t\t\t\t    elt);\n \t} else {\n \t\t/* shorthand */\n \t\tcopyfrom = parse_short_magic(&element_magic, elt);\n-- \n2.8.0.rc3.226.g39d4020\n\n"},{"id":"307291","messageId":"1481223550-65277-17-git-send-email-bmwill@google.com","threadId":"44632","inReplyTo":"1481223550-65277-1-git-send-email-bmwill@google.com","subject":"[PATCH v2 16/16] pathspec: rename prefix_pathspec to init_pathspec_item","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2016-12-08T18:59:10Z","receivedAt":"2016-12-08T18:59:59Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Give a more relevant name to the prefix_pathspec function as it does\nmore than just prefix a pathspec element.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n pathspec.c | 24 +++++++-----------------\n 1 file changed, 7 insertions(+), 17 deletions(-)\n\ndiff --git a/pathspec.c b/pathspec.c\nindex 4686298..08abdd3 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -297,21 +297,11 @@ static void strip_submodule_slash_expensive(struct pathspec_item *item)\n }\n \n /*\n- * Take an element of a pathspec and check for magic signatures.\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- *\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+ * Perform the initialization of a pathspec_item based on a pathspec element.\n  */\n-static unsigned prefix_pathspec(struct pathspec_item *item, unsigned flags,\n-\t\t\t\tconst char *prefix, int prefixlen,\n-\t\t\t\tconst char *elt)\n+static void init_pathspec_item(struct pathspec_item *item, unsigned flags,\n+\t\t\t       const char *prefix, int prefixlen,\n+\t\t\t       const char *elt)\n {\n \tunsigned magic = 0, element_magic = 0;\n \tconst char *copyfrom = elt;\n@@ -329,6 +319,8 @@ static unsigned prefix_pathspec(struct pathspec_item *item, unsigned flags,\n \t\tmagic |= get_global_magic(element_magic);\n \t}\n \n+\titem->magic = 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@@ -401,7 +393,6 @@ static unsigned prefix_pathspec(struct pathspec_item *item, unsigned flags,\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 static int pathspec_item_cmp(const void *a_, const void *b_)\n@@ -500,8 +491,7 @@ void parse_pathspec(struct pathspec *pathspec,\n \tfor (i = 0; i < n; i++) {\n \t\tentry = argv[i];\n \n-\t\titem[i].magic = prefix_pathspec(item + i, flags,\n-\t\t\t\t\t\tprefix, prefixlen, entry);\n+\t\tinit_pathspec_item(item + i, flags, prefix, prefixlen, entry);\n \n \t\tif (item[i].magic & PATHSPEC_EXCLUDE)\n \t\t\tnr_exclude++;\n-- \n2.8.0.rc3.226.g39d4020\n\n"},{"id":"307292","messageId":"1481223550-65277-14-git-send-email-bmwill@google.com","threadId":"44632","inReplyTo":"1481223550-65277-1-git-send-email-bmwill@google.com","subject":"[PATCH v2 13/16] pathspec: create parse_element_magic helper","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2016-12-08T18:59:07Z","receivedAt":"2016-12-08T19:01:59Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Factor out the logic responsible for the magic in a pathspec element\ninto its own function.\n\nAlso avoid calling into the parsing functions when\n`PATHSPEC_LITERAL_PATH` is specified since it causes magic to be\nignored and all paths to be treated as literals.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n pathspec.c | 37 ++++++++++++++++++++-----------------\n 1 file changed, 20 insertions(+), 17 deletions(-)\n\ndiff --git a/pathspec.c b/pathspec.c\nindex 6e9555e..f37f887 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -245,6 +245,19 @@ static const char *parse_short_magic(unsigned *magic, const char *elem)\n \treturn pos;\n }\n \n+static const char *parse_element_magic(unsigned *magic, int *prefix_len,\n+\t\t\t\t       const char *elem)\n+{\n+\tif (elem[0] != ':' || get_literal_global())\n+\t\treturn elem; /* nothing to do */\n+\telse if (elem[1] == '(')\n+\t\t/* longhand */\n+\t\treturn parse_long_magic(magic, prefix_len, elem);\n+\telse\n+\t\t/* shorthand */\n+\t\treturn parse_short_magic(magic, elem);\n+}\n+\n /*\n  * Take an element of a pathspec and check for magic signatures.\n  * Append the result to the prefix. Return the magic bitmap.\n@@ -267,26 +280,16 @@ static unsigned prefix_pathspec(struct pathspec_item *item, unsigned flags,\n \tchar *match;\n \tint i, pathspec_prefix = -1;\n \n-\tif (elt[0] != ':' || get_literal_global() ||\n-\t    (flags & PATHSPEC_LITERAL_PATH)) {\n-\t\t; /* nothing to do */\n-\t} else if (elt[1] == '(') {\n-\t\t/* longhand */\n-\t\tcopyfrom = parse_long_magic(&element_magic,\n-\t\t\t\t\t    &pathspec_prefix,\n-\t\t\t\t\t    elt);\n-\t} else {\n-\t\t/* shorthand */\n-\t\tcopyfrom = parse_short_magic(&element_magic, elt);\n-\t}\n-\n-\tmagic |= element_magic;\n-\n \t/* PATHSPEC_LITERAL_PATH ignores magic */\n-\tif (flags & PATHSPEC_LITERAL_PATH)\n+\tif (flags & PATHSPEC_LITERAL_PATH) {\n \t\tmagic = PATHSPEC_LITERAL;\n-\telse\n+\t} else {\n+\t\tcopyfrom = parse_element_magic(&element_magic,\n+\t\t\t\t\t       &pathspec_prefix,\n+\t\t\t\t\t       elt);\n+\t\tmagic |= element_magic;\n \t\tmagic |= get_global_magic(element_magic);\n+\t}\n \n \tif (pathspec_prefix >= 0 &&\n \t    (prefixlen || (prefix && *prefix)))\n-- \n2.8.0.rc3.226.g39d4020\n\n"},{"id":"307293","messageId":"1481223550-65277-16-git-send-email-bmwill@google.com","threadId":"44632","inReplyTo":"1481223550-65277-1-git-send-email-bmwill@google.com","subject":"[PATCH v2 15/16] pathspec: small readability changes","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2016-12-08T18:59:09Z","receivedAt":"2016-12-08T19:02:04Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"A few small changes to improve readability.  This is done by grouping related\nassignments, adding blank lines, ensuring lines are <80 characters, and\nadding additional comments.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n pathspec.c | 15 ++++++++++-----\n 1 file changed, 10 insertions(+), 5 deletions(-)\n\ndiff --git a/pathspec.c b/pathspec.c\nindex cf88390..4686298 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -336,6 +336,7 @@ static unsigned prefix_pathspec(struct pathspec_item *item, unsigned flags,\n \tif ((magic & PATHSPEC_LITERAL) && (magic & PATHSPEC_GLOB))\n \t\tdie(_(\"%s: 'literal' and 'glob' are incompatible\"), elt);\n \n+\t/* Create match string which will be used for pathspec matching */\n \tif (pathspec_prefix >= 0) {\n \t\tmatch = xstrdup(copyfrom);\n \t\tprefixlen = pathspec_prefix;\n@@ -343,11 +344,16 @@ static unsigned prefix_pathspec(struct pathspec_item *item, unsigned flags,\n \t\tmatch = xstrdup(copyfrom);\n \t\tprefixlen = 0;\n \t} else {\n-\t\tmatch = prefix_path_gently(prefix, prefixlen, &prefixlen, copyfrom);\n+\t\tmatch = prefix_path_gently(prefix, prefixlen,\n+\t\t\t\t\t   &prefixlen, copyfrom);\n \t\tif (!match)\n \t\t\tdie(_(\"%s: '%s' is outside repository\"), elt, copyfrom);\n \t}\n+\n \titem->match = match;\n+\titem->len = strlen(item->match);\n+\titem->prefix = prefixlen;\n+\n \t/*\n \t * Prefix the pathspec (keep all magic) and assign to\n \t * original. Useful for passing to another command.\n@@ -364,8 +370,6 @@ static unsigned prefix_pathspec(struct pathspec_item *item, unsigned flags,\n \t} else {\n \t\titem->original = xstrdup(elt);\n \t}\n-\titem->len = strlen(item->match);\n-\titem->prefix = prefixlen;\n \n \tif (flags & PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP)\n \t    strip_submodule_slash_cheap(item);\n@@ -373,13 +377,14 @@ static unsigned prefix_pathspec(struct pathspec_item *item, unsigned flags,\n \tif (flags & PATHSPEC_STRIP_SUBMODULE_SLASH_EXPENSIVE)\n \t    strip_submodule_slash_expensive(item);\n \n-\tif (magic & PATHSPEC_LITERAL)\n+\tif (magic & PATHSPEC_LITERAL) {\n \t\titem->nowildcard_len = item->len;\n-\telse {\n+\t} else {\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+\n \titem->flags = 0;\n \tif (magic & PATHSPEC_GLOB) {\n \t\t/*\n-- \n2.8.0.rc3.226.g39d4020\n\n"},{"id":"307294","messageId":"1481223550-65277-15-git-send-email-bmwill@google.com","threadId":"44632","inReplyTo":"1481223550-65277-1-git-send-email-bmwill@google.com","subject":"[PATCH v2 14/16] pathspec: create strip submodule slash helpers","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2016-12-08T18:59:08Z","receivedAt":"2016-12-08T19:02:07Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Factor out the logic responsible for stripping the trailing slash on\npathspecs referencing submodules into its own function.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n pathspec.c | 68 ++++++++++++++++++++++++++++++++++++++------------------------\n 1 file changed, 42 insertions(+), 26 deletions(-)\n\ndiff --git a/pathspec.c b/pathspec.c\nindex f37f887..cf88390 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -258,6 +258,44 @@ static const char *parse_element_magic(unsigned *magic, int *prefix_len,\n \t\treturn parse_short_magic(magic, elem);\n }\n \n+static void strip_submodule_slash_cheap(struct pathspec_item *item)\n+{\n+\tint i;\n+\n+\tif ((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\titem->match[item->len] = '\\0';\n+\t}\n+}\n+\n+static void strip_submodule_slash_expensive(struct pathspec_item *item)\n+{\n+\tint i;\n+\n+\tfor (i = 0; i < active_nr; i++) {\n+\t\tstruct cache_entry *ce = active_cache[i];\n+\t\tint ce_len = ce_namelen(ce);\n+\n+\t\tif (!S_ISGITLINK(ce->ce_mode))\n+\t\t\tcontinue;\n+\n+\t\tif (item->len <= ce_len || item->match[ce_len] != '/' ||\n+\t\t    memcmp(ce->name, item->match, ce_len))\n+\t\t\tcontinue;\n+\n+\t\tif (item->len == ce_len + 1) {\n+\t\t\t/* strip trailing slash */\n+\t\t\titem->len--;\n+\t\t\titem->match[item->len] = '\\0';\n+\t\t} else {\n+\t\t\tdie (_(\"Pathspec '%s' is in submodule '%.*s'\"),\n+\t\t\t     item->original, ce_len, ce->name);\n+\t\t}\n+\t}\n+}\n+\n /*\n  * Take an element of a pathspec and check for magic signatures.\n  * Append the result to the prefix. Return the magic bitmap.\n@@ -278,7 +316,7 @@ static unsigned prefix_pathspec(struct pathspec_item *item, unsigned flags,\n \tunsigned magic = 0, element_magic = 0;\n \tconst char *copyfrom = elt;\n \tchar *match;\n-\tint i, pathspec_prefix = -1;\n+\tint pathspec_prefix = -1;\n \n \t/* PATHSPEC_LITERAL_PATH ignores magic */\n \tif (flags & PATHSPEC_LITERAL_PATH) {\n@@ -329,33 +367,11 @@ static unsigned prefix_pathspec(struct pathspec_item *item, unsigned flags,\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-\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+\tif (flags & PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP)\n+\t    strip_submodule_slash_cheap(item);\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+\t    strip_submodule_slash_expensive(item);\n \n \tif (magic & PATHSPEC_LITERAL)\n \t\titem->nowildcard_len = item->len;\n-- \n2.8.0.rc3.226.g39d4020\n\n"},{"id":"307295","messageId":"1481223550-65277-9-git-send-email-bmwill@google.com","threadId":"44632","inReplyTo":"1481223550-65277-1-git-send-email-bmwill@google.com","subject":"[PATCH v2 08/16] pathspec: always show mnemonic and name in unsupported_magic","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2016-12-08T18:59:02Z","receivedAt":"2016-12-08T19:02:10Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"For better clarity, always show the mnemonic and name of the unsupported\nmagic being used.  This lets users have a more clear understanding of\nwhat magic feature isn't supported.  And if they supplied a mnemonic,\nthe user will be told what its corresponding name is which will allow\nthem to more easily search the man pages for that magic type.\n\nThis also avoids passing an extra parameter around the pathspec\ninitialization code.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n pathspec.c | 23 ++++++++---------------\n 1 file changed, 8 insertions(+), 15 deletions(-)\n\ndiff --git a/pathspec.c b/pathspec.c\nindex ec0d590..a360193 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -68,7 +68,7 @@ static struct pathspec_magic {\n \tconst char *name;\n } pathspec_magic[] = {\n \t{ PATHSPEC_FROMTOP, '/', \"top\" },\n-\t{ PATHSPEC_LITERAL,   0, \"literal\" },\n+\t{ PATHSPEC_LITERAL,'\\0', \"literal\" },\n \t{ PATHSPEC_GLOB,   '\\0', \"glob\" },\n \t{ PATHSPEC_ICASE,  '\\0', \"icase\" },\n \t{ PATHSPEC_EXCLUDE, '!', \"exclude\" },\n@@ -101,9 +101,7 @@ static void prefix_short_magic(struct strbuf *sb, int prefixlen,\n  * the prefix part must always match literally, and a single stupid\n  * string cannot express such a case.\n  */\n-static unsigned prefix_pathspec(struct pathspec_item *item,\n-\t\t\t\tunsigned *p_short_magic,\n-\t\t\t\tunsigned flags,\n+static unsigned prefix_pathspec(struct pathspec_item *item, unsigned flags,\n \t\t\t\tconst char *prefix, int prefixlen,\n \t\t\t\tconst char *elt)\n {\n@@ -210,7 +208,6 @@ static unsigned prefix_pathspec(struct pathspec_item *item,\n \t}\n \n \tmagic |= short_magic;\n-\t*p_short_magic = short_magic;\n \n \t/* --noglob-pathspec adds :(literal) _unless_ :(glob) is specified */\n \tif (noglob_global && !(magic & PATHSPEC_GLOB))\n@@ -329,8 +326,7 @@ static int pathspec_item_cmp(const void *a_, const void *b_)\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+\t\t\t\t       unsigned magic)\n {\n \tstruct strbuf sb = STRBUF_INIT;\n \tint i;\n@@ -340,8 +336,9 @@ static void NORETURN unsupported_magic(const char *pattern,\n \t\t\tcontinue;\n \t\tif (sb.len)\n \t\t\tstrbuf_addch(&sb, ' ');\n-\t\tif (short_magic & m->bit)\n-\t\t\tstrbuf_addf(&sb, \"'%c'\", m->mnemonic);\n+\n+\t\tif (m->mnemonic)\n+\t\t\tstrbuf_addf(&sb, \"'(%c)%s'\", m->mnemonic, m->name);\n \t\telse\n \t\t\tstrbuf_addf(&sb, \"'%s'\", m->name);\n \t}\n@@ -413,11 +410,9 @@ void parse_pathspec(struct pathspec *pathspec,\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\tflags,\n+\t\titem[i].magic = prefix_pathspec(item + i, flags,\n \t\t\t\t\t\tprefix, prefixlen, entry);\n \t\tif ((flags & PATHSPEC_LITERAL_PATH) &&\n \t\t    !(magic_mask & PATHSPEC_LITERAL))\n@@ -425,9 +420,7 @@ void parse_pathspec(struct pathspec *pathspec,\n \t\tif (item[i].magic & PATHSPEC_EXCLUDE)\n \t\t\tnr_exclude++;\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\t\tunsupported_magic(entry, item[i].magic & magic_mask);\n \n \t\tif ((flags & PATHSPEC_SYMLINK_LEADING_PATH) &&\n \t\t    has_symlink_leading_path(item[i].match, item[i].len)) {\n-- \n2.8.0.rc3.226.g39d4020\n\n"},{"id":"307296","messageId":"1481223550-65277-5-git-send-email-bmwill@google.com","threadId":"44632","inReplyTo":"1481223550-65277-1-git-send-email-bmwill@google.com","subject":"[PATCH v2 04/16] ls-tree: convert show_recursive to use the pathspec struct interface","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2016-12-08T18:58:58Z","receivedAt":"2016-12-08T19:02:15Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Convert 'show_recursive()' to use the pathspec struct interface from\nusing the '_raw' entry in the pathspec struct.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n builtin/ls-tree.c | 16 +++++++---------\n 1 file changed, 7 insertions(+), 9 deletions(-)\n\ndiff --git a/builtin/ls-tree.c b/builtin/ls-tree.c\nindex 0e30d86..d7ebeb4 100644\n--- a/builtin/ls-tree.c\n+++ b/builtin/ls-tree.c\n@@ -31,21 +31,18 @@ static const  char * const ls_tree_usage[] = {\n \n static int show_recursive(const char *base, int baselen, const char *pathname)\n {\n-\tconst char **s;\n+\tint i;\n \n \tif (ls_options & LS_RECURSIVE)\n \t\treturn 1;\n \n-\ts = pathspec._raw;\n-\tif (!s)\n+\tif (!pathspec.nr)\n \t\treturn 0;\n \n-\tfor (;;) {\n-\t\tconst char *spec = *s++;\n+\tfor (i = 0; i < pathspec.nr; i++) {\n+\t\tconst char *spec = pathspec.items[i].match;\n \t\tint len, speclen;\n \n-\t\tif (!spec)\n-\t\t\treturn 0;\n \t\tif (strncmp(base, spec, baselen))\n \t\t\tcontinue;\n \t\tlen = strlen(pathname);\n@@ -59,6 +56,7 @@ static int show_recursive(const char *base, int baselen, const char *pathname)\n \t\t\tcontinue;\n \t\treturn 1;\n \t}\n+\treturn 0;\n }\n \n static int show_tree(const unsigned char *sha1, struct strbuf *base,\n@@ -175,8 +173,8 @@ 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() or tree_entry_interesting()\n \t */\n-\tparse_pathspec(&pathspec, PATHSPEC_GLOB | PATHSPEC_ICASE |\n-\t\t\t\t  PATHSPEC_EXCLUDE,\n+\tparse_pathspec(&pathspec, PATHSPEC_ALL_MAGIC &\n+\t\t\t\t  ~(PATHSPEC_FROMTOP | PATHSPEC_LITERAL),\n \t\t       PATHSPEC_PREFER_CWD,\n \t\t       prefix, argv + 1);\n \tfor (i = 0; i < pathspec.nr; i++)\n-- \n2.8.0.rc3.226.g39d4020\n\n"},{"id":"307297","messageId":"1481223550-65277-6-git-send-email-bmwill@google.com","threadId":"44632","inReplyTo":"1481223550-65277-1-git-send-email-bmwill@google.com","subject":"[PATCH v2 05/16] pathspec: remove the deprecated get_pathspec function","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2016-12-08T18:58:59Z","receivedAt":"2016-12-08T19:02:37Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Now that all callers of the old 'get_pathspec' interface have been\nmigrated to use the new pathspec struct interface it can be removed\nfrom the codebase.\n\nSince there are no more users of the '_raw' field in the pathspec struct\nit can also be removed.  This patch also removes the old functionality\nof modifying the const char **argv array that was passed into\nparse_pathspec.  Instead the constructed 'match' string (which is a\npathspec element with the prefix prepended) is only stored in its\ncorresponding pathspec_item entry.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n Documentation/technical/api-setup.txt |  2 --\n cache.h                               |  1 -\n pathspec.c                            | 42 +++--------------------------------\n pathspec.h                            |  1 -\n 4 files changed, 3 insertions(+), 43 deletions(-)\n\ndiff --git a/Documentation/technical/api-setup.txt b/Documentation/technical/api-setup.txt\nindex 540e455..eb1fa98 100644\n--- a/Documentation/technical/api-setup.txt\n+++ b/Documentation/technical/api-setup.txt\n@@ -27,8 +27,6 @@ parse_pathspec(). This function takes several arguments:\n \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 them\n politely. At a lower level, different pathspec-related functions may\n not support the same set of features. Such pathspec-sensitive\ndiff --git a/cache.h b/cache.h\nindex a50a61a..0f80e01 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -514,7 +514,6 @@ extern void set_git_work_tree(const char *tree);\n \n #define ALTERNATE_DB_ENVIRONMENT \"GIT_ALTERNATE_OBJECT_DIRECTORIES\"\n \n-extern const char **get_pathspec(const char *prefix, const char **pathspec);\n extern void setup_work_tree(void);\n extern const char *setup_git_directory_gently(int *);\n extern const char *setup_git_directory(void);\ndiff --git a/pathspec.c b/pathspec.c\nindex 22ca74a..1f918cb 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -103,7 +103,7 @@ static void prefix_short_magic(struct strbuf *sb, int prefixlen,\n  */\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\tunsigned flags,\n \t\t\t\tconst char *prefix, int prefixlen,\n \t\t\t\tconst char *elt)\n {\n@@ -240,7 +240,7 @@ static unsigned prefix_pathspec(struct pathspec_item *item,\n \t\tif (!match)\n \t\t\tdie(_(\"%s: '%s' is outside repository\"), elt, copyfrom);\n \t}\n-\t*raw = item->match = match;\n+\titem->match = match;\n \t/*\n \t * Prefix the pathspec (keep all magic) and assign to\n \t * original. Useful for passing to another command.\n@@ -381,8 +381,6 @@ void parse_pathspec(struct pathspec *pathspec,\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@@ -394,10 +392,7 @@ void parse_pathspec(struct pathspec *pathspec,\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;\n-\t\tpathspec->_raw = raw;\n \t\treturn;\n \t}\n \n@@ -415,7 +410,6 @@ void parse_pathspec(struct pathspec *pathspec,\n \tpathspec->nr = n;\n \tALLOC_ARRAY(pathspec->items, n);\n \titem = pathspec->items;\n-\tpathspec->_raw = argv;\n \tprefixlen = prefix ? strlen(prefix) : 0;\n \n \tfor (i = 0; i < n; i++) {\n@@ -423,7 +417,7 @@ void parse_pathspec(struct pathspec *pathspec,\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\tflags,\n \t\t\t\t\t\tprefix, prefixlen, entry);\n \t\tif ((flags & PATHSPEC_LITERAL_PATH) &&\n \t\t    !(magic_mask & PATHSPEC_LITERAL))\n@@ -457,36 +451,6 @@ void parse_pathspec(struct pathspec *pathspec,\n \t}\n }\n \n-/*\n- * N.B. get_pathspec() is deprecated in favor of the \"struct pathspec\"\n- * based interface - see pathspec.c:parse_pathspec().\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-\tstruct pathspec ps;\n-\tparse_pathspec(&ps,\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;\n-}\n-\n void copy_pathspec(struct pathspec *dst, const struct pathspec *src)\n {\n \t*dst = *src;\ndiff --git a/pathspec.h b/pathspec.h\nindex 59809e4..70a592e 100644\n--- a/pathspec.h\n+++ b/pathspec.h\n@@ -19,7 +19,6 @@\n #define PATHSPEC_ONESTAR 1\t/* the pathspec pattern satisfies GFNM_ONESTAR */\n \n struct pathspec {\n-\tconst char **_raw; /* get_pathspec() result, not freed by clear_pathspec() */\n \tint nr;\n \tunsigned int has_wildcard:1;\n \tunsigned int recursive:1;\n-- \n2.8.0.rc3.226.g39d4020\n\n"},{"id":"307298","messageId":"1481223550-65277-8-git-send-email-bmwill@google.com","threadId":"44632","inReplyTo":"1481223550-65277-1-git-send-email-bmwill@google.com","subject":"[PATCH v2 07/16] pathspec: remove unused variable from unsupported_magic","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2016-12-08T18:59:01Z","receivedAt":"2016-12-08T19:02:40Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Removed unused variable 'n' from the 'unsupported_magic()' function.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n pathspec.c | 5 ++---\n 1 file changed, 2 insertions(+), 3 deletions(-)\n\ndiff --git a/pathspec.c b/pathspec.c\nindex 8f367f0..ec0d590 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -333,8 +333,8 @@ static void NORETURN unsupported_magic(const char *pattern,\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+\tint i;\n+\tfor (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@@ -344,7 +344,6 @@ static void NORETURN unsupported_magic(const char *pattern,\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 substitute \"this command\" with a command\n-- \n2.8.0.rc3.226.g39d4020\n\n"},{"id":"307320","messageId":"xmqqk2barls5.fsf@gitster.mtv.corp.google.com","threadId":"44632","inReplyTo":"1481223550-65277-1-git-send-email-bmwill@google.com","subject":"Re: [PATCH v2 00/16] pathspec cleanup","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-12-09T00:25:30Z","receivedAt":"2016-12-09T00:26:34Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Will queue, but with fixes on issues spotted by my pre-acceptance\nmechanical filter squashed in, to fix style issues in the\ndestination of code movements.\n\n pathspec.c | 10 +++++-----\n 1 file changed, 5 insertions(+), 5 deletions(-)\n\ndiff --git a/pathspec.c b/pathspec.c\nindex 08abdd3922..cabc02e79b 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -68,7 +68,7 @@ static struct pathspec_magic {\n \tconst char *name;\n } pathspec_magic[] = {\n \t{ PATHSPEC_FROMTOP, '/', \"top\" },\n-\t{ PATHSPEC_LITERAL,'\\0', \"literal\" },\n+\t{ PATHSPEC_LITERAL, '\\0', \"literal\" },\n \t{ PATHSPEC_GLOB,   '\\0', \"glob\" },\n \t{ PATHSPEC_ICASE,  '\\0', \"icase\" },\n \t{ PATHSPEC_EXCLUDE, '!', \"exclude\" },\n@@ -290,8 +290,8 @@ static void strip_submodule_slash_expensive(struct pathspec_item *item)\n \t\t\titem->len--;\n \t\t\titem->match[item->len] = '\\0';\n \t\t} else {\n-\t\t\tdie (_(\"Pathspec '%s' is in submodule '%.*s'\"),\n-\t\t\t     item->original, ce_len, ce->name);\n+\t\t\tdie(_(\"Pathspec '%s' is in submodule '%.*s'\"),\n+\t\t\t    item->original, ce_len, ce->name);\n \t\t}\n \t}\n }\n@@ -364,10 +364,10 @@ static void init_pathspec_item(struct pathspec_item *item, unsigned flags,\n \t}\n \n \tif (flags & PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP)\n-\t    strip_submodule_slash_cheap(item);\n+\t\tstrip_submodule_slash_cheap(item);\n \n \tif (flags & PATHSPEC_STRIP_SUBMODULE_SLASH_EXPENSIVE)\n-\t    strip_submodule_slash_expensive(item);\n+\t\tstrip_submodule_slash_expensive(item);\n \n \tif (magic & PATHSPEC_LITERAL) {\n \t\titem->nowildcard_len = item->len;\n\n\n"},{"id":"307321","messageId":"xmqqfulyrlmf.fsf@gitster.mtv.corp.google.com","threadId":"44632","inReplyTo":"1481223550-65277-15-git-send-email-bmwill@google.com","subject":"Re: [PATCH v2 14/16] pathspec: create strip submodule slash helpers","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-12-09T00:28:56Z","receivedAt":"2016-12-09T00:29:03Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Brandon Williams <bmwill@google.com> writes:\n\n> +static void strip_submodule_slash_cheap(struct pathspec_item *item)\n> +{\n> +\tint i;\n> +\n> +\tif ((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\titem->match[item->len] = '\\0';\n> +\t}\n> +}\n\nI know that this is merely a moved code, but while I was reading\nthis, it triggered \"Do not make an assignment inside if condition\"\ncheck.  But more importantly, is the code even correct?  If the path\nfor the submodule is unmerged, we would get a negative i that points\nat the conflicting entry; don't we want to do something about it, at\nleast when we have a submodule entry at stage #2 (i.e. ours)?\n"},{"id":"307344","messageId":"CACsJy8AX6C8Tux9_8ZynBMNS2EW2pKQOGK8k0hVmbWvbZ8pa=Q@mail.gmail.com","threadId":"44632","inReplyTo":"xmqqfulyrlmf.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v2 14/16] pathspec: create strip submodule slash helpers","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2016-12-09T12:16:06Z","receivedAt":"2016-12-09T12:16:42Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Fri, Dec 9, 2016 at 7:28 AM, Junio C Hamano <gitster@pobox.com> wrote:\n> Brandon Williams <bmwill@google.com> writes:\n>\n>> +static void strip_submodule_slash_cheap(struct pathspec_item *item)\n>> +{\n>> +     int i;\n>> +\n>> +     if ((item->len >= 1 && item->match[item->len - 1] == '/') &&\n>> +         (i = cache_name_pos(item->match, item->len - 1)) >= 0 &&\n>> +         S_ISGITLINK(active_cache[i]->ce_mode)) {\n>> +             item->len--;\n>> +             item->match[item->len] = '\\0';\n>> +     }\n>> +}\n>\n> I know that this is merely a moved code, but while I was reading\n> this, it triggered \"Do not make an assignment inside if condition\"\n> check.\n\nYeah with a function of its own, it's probably better to separate that\nassignment.\n\n> But more importantly, is the code even correct?  If the path\n> for the submodule is unmerged, we would get a negative i that points\n> at the conflicting entry; don't we want to do something about it, at\n> least when we have a submodule entry at stage #2 (i.e. ours)?\n\nIn my defense I was simply moving (again!) the code from\nstrip_trailing_slash_from_submodules() in b69bb3f:builtin/ls-files.c.\nCould be an improvement point for submodule people, I guess.\n-- \nDuy\n"},{"id":"307350","messageId":"CACsJy8Cc6hE1Rbqjrc93xDMc0UUm0yMh0A-fyu3dfJ2G1jhENQ@mail.gmail.com","threadId":"44632","inReplyTo":"20161208181957.GP116201@google.com","subject":"Re: [PATCH 02/17] dir: convert create_simplify to use the pathspec struct interface","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2016-12-09T13:08:42Z","receivedAt":"2016-12-09T13:09:20Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Fri, Dec 9, 2016 at 1:19 AM, Brandon Williams <bmwill@google.com> wrote:\n> On 12/08, Duy Nguyen wrote:\n>> On Thu, Dec 8, 2016 at 7:03 AM, Brandon Williams <bmwill@google.com> wrote:\n>> > On 12/07, Duy Nguyen wrote:\n>> >> On Wed, Dec 7, 2016 at 4:51 AM, Brandon Williams <bmwill@google.com> wrote:\n>> >> > Convert 'create_simplify()' to use the pathspec struct interface from\n>> >> > using the '_raw' entry in the pathspec.\n>> >>\n>> >> It would be even better to kill this create_simplify() and let\n>> >> simplify_away() handle struct pathspec directly.\n>> >>\n>> >> There is a bug in this code, that might have been found if we\n>> >> simpify_away() handled pathspec directly: the memcmp() in\n>> >> simplify_away() will not play well with :(icase) magic. My bad. If\n>> >> :(icase) is used, the easiest/safe way is simplify nothing. Later on\n>> >> maybe we can teach simplify_away() to do strncasecmp instead. We could\n>> >> ignore exclude patterns there too (although not excluding is not a\n>> >> bug).\n>> >\n>> > So are you implying that the simplify struct needs to be killed?  That\n>> > way the pathspec struct itself is being passed around instead?\n>>\n>> Yes. simplify struct was a thing when pathspec was an array of char *.\n>> At this point I think it can retire (when we have time to retire it)\n>\n> Alright, then for now I can leave this change as is and have a follow up\n> series that kills the simplify struct.\n\nDo let me know if you decide to drop it, so I can put it back in my backlog.\n-- \nDuy\n"},{"id":"307383","messageId":"20161209190347.GA88637@google.com","threadId":"44632","inReplyTo":"xmqqk2barls5.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v2 00/16] pathspec cleanup","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2016-12-09T19:03:47Z","receivedAt":"2016-12-09T19:03:55Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"On 12/08, Junio C Hamano wrote:\n> Will queue, but with fixes on issues spotted by my pre-acceptance\n> mechanical filter squashed in, to fix style issues in the\n> destination of code movements.\n\nIs this pre-acceptance filter you use something that I could run\nlocally?\n\n-- \nBrandon Williams\n"},{"id":"307386","messageId":"1481311118-174146-1-git-send-email-bmwill@google.com","threadId":"44632","inReplyTo":"CACsJy8AX6C8Tux9_8ZynBMNS2EW2pKQOGK8k0hVmbWvbZ8pa=Q@mail.gmail.com","subject":"[PATCH 14/16] pathspec: create strip submodule slash helpers","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2016-12-09T19:18:38Z","receivedAt":"2016-12-09T19:19:05Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Factor out the logic responsible for stripping the trailing slash on\npathspecs referencing submodules into its own function.\n\nChange-Id: Icad62647c04b4195309def0e3db416203d14f9e4\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n pathspec.c | 68 ++++++++++++++++++++++++++++++++++++++------------------------\n 1 file changed, 42 insertions(+), 26 deletions(-)\n\ndiff --git a/pathspec.c b/pathspec.c\nindex 84a57cf..4d9a6a0 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -258,6 +258,44 @@ static const char *parse_element_magic(unsigned *magic, int *prefix_len,\n \t\treturn parse_short_magic(magic, elem);\n }\n \n+static void strip_submodule_slash_cheap(struct pathspec_item *item)\n+{\n+\tif (item->len >= 1 && item->match[item->len - 1] == '/') {\n+\t\tint i = cache_name_pos(item->match, item->len - 1);\n+\n+\t\tif (i >= 0 && S_ISGITLINK(active_cache[i]->ce_mode)) {\n+\t\t\titem->len--;\n+\t\t\titem->match[item->len] = '\\0';\n+\t\t}\n+\t}\n+}\n+\n+static void strip_submodule_slash_expensive(struct pathspec_item *item)\n+{\n+\tint i;\n+\n+\tfor (i = 0; i < active_nr; i++) {\n+\t\tstruct cache_entry *ce = active_cache[i];\n+\t\tint ce_len = ce_namelen(ce);\n+\n+\t\tif (!S_ISGITLINK(ce->ce_mode))\n+\t\t\tcontinue;\n+\n+\t\tif (item->len <= ce_len || item->match[ce_len] != '/' ||\n+\t\t    memcmp(ce->name, item->match, ce_len))\n+\t\t\tcontinue;\n+\n+\t\tif (item->len == ce_len + 1) {\n+\t\t\t/* strip trailing slash */\n+\t\t\titem->len--;\n+\t\t\titem->match[item->len] = '\\0';\n+\t\t} else {\n+\t\t\tdie(_(\"Pathspec '%s' is in submodule '%.*s'\"),\n+\t\t\t    item->original, ce_len, ce->name);\n+\t\t}\n+\t}\n+}\n+\n /*\n  * Take an element of a pathspec and check for magic signatures.\n  * Append the result to the prefix. Return the magic bitmap.\n@@ -278,7 +316,7 @@ static unsigned prefix_pathspec(struct pathspec_item *item, unsigned flags,\n \tunsigned magic = 0, element_magic = 0;\n \tconst char *copyfrom = elt;\n \tchar *match;\n-\tint i, pathspec_prefix = -1;\n+\tint pathspec_prefix = -1;\n \n \t/* PATHSPEC_LITERAL_PATH ignores magic */\n \tif (flags & PATHSPEC_LITERAL_PATH) {\n@@ -329,33 +367,11 @@ static unsigned prefix_pathspec(struct pathspec_item *item, unsigned flags,\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-\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+\tif (flags & PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP)\n+\t\tstrip_submodule_slash_cheap(item);\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+\t\tstrip_submodule_slash_expensive(item);\n \n \tif (magic & PATHSPEC_LITERAL)\n \t\titem->nowildcard_len = item->len;\n-- \n2.8.0.rc3.226.g39d4020\n\n"},{"id":"307387","messageId":"20161209192316.GB88637@google.com","threadId":"44632","inReplyTo":"CACsJy8Cc6hE1Rbqjrc93xDMc0UUm0yMh0A-fyu3dfJ2G1jhENQ@mail.gmail.com","subject":"Re: [PATCH 02/17] dir: convert create_simplify to use the pathspec struct interface","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2016-12-09T19:23:16Z","receivedAt":"2016-12-09T19:23:34Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"On 12/09, Duy Nguyen wrote:\n> On Fri, Dec 9, 2016 at 1:19 AM, Brandon Williams <bmwill@google.com> wrote:\n> > On 12/08, Duy Nguyen wrote:\n> >> On Thu, Dec 8, 2016 at 7:03 AM, Brandon Williams <bmwill@google.com> wrote:\n> >> > On 12/07, Duy Nguyen wrote:\n> >> >> On Wed, Dec 7, 2016 at 4:51 AM, Brandon Williams <bmwill@google.com> wrote:\n> >> >> > Convert 'create_simplify()' to use the pathspec struct interface from\n> >> >> > using the '_raw' entry in the pathspec.\n> >> >>\n> >> >> It would be even better to kill this create_simplify() and let\n> >> >> simplify_away() handle struct pathspec directly.\n> >> >>\n> >> >> There is a bug in this code, that might have been found if we\n> >> >> simpify_away() handled pathspec directly: the memcmp() in\n> >> >> simplify_away() will not play well with :(icase) magic. My bad. If\n> >> >> :(icase) is used, the easiest/safe way is simplify nothing. Later on\n> >> >> maybe we can teach simplify_away() to do strncasecmp instead. We could\n> >> >> ignore exclude patterns there too (although not excluding is not a\n> >> >> bug).\n> >> >\n> >> > So are you implying that the simplify struct needs to be killed?  That\n> >> > way the pathspec struct itself is being passed around instead?\n> >>\n> >> Yes. simplify struct was a thing when pathspec was an array of char *.\n> >> At this point I think it can retire (when we have time to retire it)\n> >\n> > Alright, then for now I can leave this change as is and have a follow up\n> > series that kills the simplify struct.\n> \n> Do let me know if you decide to drop it, so I can put it back in my backlog.\n\nK will do\n\n-- \nBrandon Williams\n"},{"id":"307391","messageId":"CAGZ79kYVumubF58fdwejE2hvCLfgdVqTxn_w=S-CBFY-NdgqQg@mail.gmail.com","threadId":"44632","inReplyTo":"1481311118-174146-1-git-send-email-bmwill@google.com","subject":"Re: [PATCH 14/16] pathspec: create strip submodule slash helpers","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2016-12-09T19:40:04Z","receivedAt":"2016-12-09T19:40:10Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"On Fri, Dec 9, 2016 at 11:18 AM, Brandon Williams <bmwill@google.com> wrote:\n> Factor out the logic responsible for stripping the trailing slash on\n> pathspecs referencing submodules into its own function.\n>\n> Change-Id: Icad62647c04b4195309def0e3db416203d14f9e4\n\nI think we should come up with a solution to wipe out change ids\nbefore sending emails. ;)\n\n> Signed-off-by: Brandon Williams <bmwill@google.com>\n> ---\n>  pathspec.c | 68 ++++++++++++++++++++++++++++++++++++++------------------------\n>  1 file changed, 42 insertions(+), 26 deletions(-)\n>\n> diff --git a/pathspec.c b/pathspec.c\n> index 84a57cf..4d9a6a0 100644\n> --- a/pathspec.c\n> +++ b/pathspec.c\n> @@ -258,6 +258,44 @@ static const char *parse_element_magic(unsigned *magic, int *prefix_len,\n>                 return parse_short_magic(magic, elem);\n>  }\n>\n> +static void strip_submodule_slash_cheap(struct pathspec_item *item)\n> +{\n> +       if (item->len >= 1 && item->match[item->len - 1] == '/') {\n> +               int i = cache_name_pos(item->match, item->len - 1);\n> +\n> +               if (i >= 0 && S_ISGITLINK(active_cache[i]->ce_mode)) {\n> +                       item->len--;\n> +                       item->match[item->len] = '\\0';\n> +               }\n> +       }\n> +}\n> +\n> +static void strip_submodule_slash_expensive(struct pathspec_item *item)\n> +{\n> +       int i;\n> +\n> +       for (i = 0; i < active_nr; i++) {\n> +               struct cache_entry *ce = active_cache[i];\n> +               int ce_len = ce_namelen(ce);\n> +\n> +               if (!S_ISGITLINK(ce->ce_mode))\n> +                       continue;\n> +\n> +               if (item->len <= ce_len || item->match[ce_len] != '/' ||\n> +                   memcmp(ce->name, item->match, ce_len))\n> +                       continue;\n> +\n> +               if (item->len == ce_len + 1) {\n> +                       /* strip trailing slash */\n> +                       item->len--;\n> +                       item->match[item->len] = '\\0';\n> +               } else {\n> +                       die(_(\"Pathspec '%s' is in submodule '%.*s'\"),\n> +                           item->original, ce_len, ce->name);\n> +               }\n> +       }\n> +}\n> +\n>  /*\n>   * Take an element of a pathspec and check for magic signatures.\n>   * Append the result to the prefix. Return the magic bitmap.\n> @@ -278,7 +316,7 @@ static unsigned prefix_pathspec(struct pathspec_item *item, unsigned flags,\n>         unsigned magic = 0, element_magic = 0;\n>         const char *copyfrom = elt;\n>         char *match;\n> -       int i, pathspec_prefix = -1;\n> +       int pathspec_prefix = -1;\n>\n>         /* PATHSPEC_LITERAL_PATH ignores magic */\n>         if (flags & PATHSPEC_LITERAL_PATH) {\n> @@ -329,33 +367,11 @@ static unsigned prefix_pathspec(struct pathspec_item *item, unsigned flags,\n>         item->len = strlen(item->match);\n>         item->prefix = prefixlen;\n>\n> -       if ((flags & PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP) &&\n> -           (item->len >= 1 && item->match[item->len - 1] == '/') &&\n> -           (i = cache_name_pos(item->match, item->len - 1)) >= 0 &&\n> -           S_ISGITLINK(active_cache[i]->ce_mode)) {\n> -               item->len--;\n> -               match[item->len] = '\\0';\n> -       }\n> +       if (flags & PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP)\n> +               strip_submodule_slash_cheap(item);\n>\n>         if (flags & PATHSPEC_STRIP_SUBMODULE_SLASH_EXPENSIVE)\n> -               for (i = 0; i < active_nr; i++) {\n> -                       struct cache_entry *ce = active_cache[i];\n> -                       int ce_len = ce_namelen(ce);\n> -\n> -                       if (!S_ISGITLINK(ce->ce_mode))\n> -                               continue;\n> -\n> -                       if (item->len <= ce_len || match[ce_len] != '/' ||\n> -                           memcmp(ce->name, match, ce_len))\n> -                               continue;\n> -                       if (item->len == ce_len + 1) {\n> -                               /* strip trailing slash */\n> -                               item->len--;\n> -                               match[item->len] = '\\0';\n> -                       } else\n> -                               die (_(\"Pathspec '%s' is in submodule '%.*s'\"),\n> -                                    elt, ce_len, ce->name);\n> -               }\n> +               strip_submodule_slash_expensive(item);\n>\n>         if (magic & PATHSPEC_LITERAL)\n>                 item->nowildcard_len = item->len;\n> --\n> 2.8.0.rc3.226.g39d4020\n>\n"},{"id":"307394","messageId":"20161209203042.GE88637@google.com","threadId":"44632","inReplyTo":"CAGZ79kYVumubF58fdwejE2hvCLfgdVqTxn_w=S-CBFY-NdgqQg@mail.gmail.com","subject":"Re: [PATCH 14/16] pathspec: create strip submodule slash helpers","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2016-12-09T20:30:42Z","receivedAt":"2016-12-09T20:30:50Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"On 12/09, Stefan Beller wrote:\n> On Fri, Dec 9, 2016 at 11:18 AM, Brandon Williams <bmwill@google.com> wrote:\n> > Factor out the logic responsible for stripping the trailing slash on\n> > pathspecs referencing submodules into its own function.\n> >\n> > Change-Id: Icad62647c04b4195309def0e3db416203d14f9e4\n> \n> I think we should come up with a solution to wipe out change ids\n> before sending emails. ;)\n\nDarn! Yeah maybe a hook or something :D\n\n-- \nBrandon Williams\n"},{"id":"307406","messageId":"xmqqwpf8pt0g.fsf@gitster.mtv.corp.google.com","threadId":"44632","inReplyTo":"1481223550-65277-13-git-send-email-bmwill@google.com","subject":"Re: [PATCH v2 12/16] pathspec: create parse_long_magic function","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-12-09T23:44:31Z","receivedAt":"2016-12-09T23:44:40Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Brandon Williams <bmwill@google.com> writes:\n\n> Factor out the logic responsible for parsing long magic into its own\n> function.  As well as hoist the prefix check logic outside of the inner\n> loop as there isn't anything that needs to be done after matching\n> \"prefix:\".\n>\n> Signed-off-by: Brandon Williams <bmwill@google.com>\n\nThese refactoring changes look like they are all going in the good\ndirection.  Stefan's :(attr:<attribute spec>)path\" changes however\nhave severe conflicts (e.g. the topic already does something similar\nto this step and calls the factored-out function eat_long_magic()).\n\nMy gut feeling is that we probably should ask Stefan's series to be\nrebased on top of this series that cleans up pathspec implementation,\nonce it stabilizes.  We could probably go the other way around, but\nlogically it makes more sense to build \"pathspec can also match\nusing attributes information\" on top of a refactored codebase.\n\nThoughts?\n"},{"id":"307407","messageId":"CAGZ79ka0P0rKF8QH3V0jC-O19eT0oaE+fJLGifbfmm3jC_SijA@mail.gmail.com","threadId":"44632","inReplyTo":"xmqqwpf8pt0g.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v2 12/16] pathspec: create parse_long_magic function","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2016-12-09T23:52:20Z","receivedAt":"2016-12-09T23:52:26Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"On Fri, Dec 9, 2016 at 3:44 PM, Junio C Hamano <gitster@pobox.com> wrote:\n> Brandon Williams <bmwill@google.com> writes:\n>\n>> Factor out the logic responsible for parsing long magic into its own\n>> function.  As well as hoist the prefix check logic outside of the inner\n>> loop as there isn't anything that needs to be done after matching\n>> \"prefix:\".\n>>\n>> Signed-off-by: Brandon Williams <bmwill@google.com>\n>\n> These refactoring changes look like they are all going in the good\n> direction.  Stefan's :(attr:<attribute spec>)path\" changes however\n> have severe conflicts (e.g. the topic already does something similar\n> to this step and calls the factored-out function eat_long_magic()).\n>\n> My gut feeling is that we probably should ask Stefan's series to be\n> rebased on top of this series that cleans up pathspec implementation,\n> once it stabilizes.\n\nVery much so.\n\nJonathan Nieder mentioned off list that he prefers to see that\nseries rerolled without mutexes if possible. That is possible by\ncreating the questions \"struct attr_check\" before preloading the\nindex and then using the read only questions in the threaded code,\nto obtain answers fast; also no need for a mutex.\n\nI did not look into that yet, though. So I think you could discard that\nseries (again) until I find time to either redo the series or\nresend it with a proper explanation on why the approach above\nis not feasible.\n\n>  We could probably go the other way around, but\n> logically it makes more sense to build \"pathspec can also match\n> using attributes information\" on top of a refactored codebase.\n>\n> Thoughts?\n\nPlease let the refactoring in in favor of the attr series.\n"},{"id":"307411","messageId":"20161210002923.GG88637@google.com","threadId":"44632","inReplyTo":"CAGZ79ka0P0rKF8QH3V0jC-O19eT0oaE+fJLGifbfmm3jC_SijA@mail.gmail.com","subject":"Re: [PATCH v2 12/16] pathspec: create parse_long_magic function","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2016-12-10T00:29:23Z","receivedAt":"2016-12-10T00:29:30Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"On 12/09, Stefan Beller wrote:\n> On Fri, Dec 9, 2016 at 3:44 PM, Junio C Hamano <gitster@pobox.com> wrote:\n> > Brandon Williams <bmwill@google.com> writes:\n> >\n> >> Factor out the logic responsible for parsing long magic into its own\n> >> function.  As well as hoist the prefix check logic outside of the inner\n> >> loop as there isn't anything that needs to be done after matching\n> >> \"prefix:\".\n> >>\n> >> Signed-off-by: Brandon Williams <bmwill@google.com>\n> >\n> > These refactoring changes look like they are all going in the good\n> > direction.  Stefan's :(attr:<attribute spec>)path\" changes however\n> > have severe conflicts (e.g. the topic already does something similar\n> > to this step and calls the factored-out function eat_long_magic()).\n> >\n> > My gut feeling is that we probably should ask Stefan's series to be\n> > rebased on top of this series that cleans up pathspec implementation,\n> > once it stabilizes.\n> \n> Very much so.\n> \n> Jonathan Nieder mentioned off list that he prefers to see that\n> series rerolled without mutexes if possible. That is possible by\n> creating the questions \"struct attr_check\" before preloading the\n> index and then using the read only questions in the threaded code,\n> to obtain answers fast; also no need for a mutex.\n> \n> I did not look into that yet, though. So I think you could discard that\n> series (again) until I find time to either redo the series or\n> resend it with a proper explanation on why the approach above\n> is not feasible.\n> \n> >  We could probably go the other way around, but\n> > logically it makes more sense to build \"pathspec can also match\n> > using attributes information\" on top of a refactored codebase.\n> >\n> > Thoughts?\n> \n> Please let the refactoring in in favor of the attr series.\n\nSounds good.  I only looked at your series briefly, but I'm hoping that\nthese refactoring changes I'm proposing make it relatively easy for you\nto build on top of in the future.\n\n-- \nBrandon Williams\n"},{"id":"307442","messageId":"xmqqk2b7ps08.fsf@gitster.mtv.corp.google.com","threadId":"44632","inReplyTo":"CAGZ79ka0P0rKF8QH3V0jC-O19eT0oaE+fJLGifbfmm3jC_SijA@mail.gmail.com","subject":"Re: [PATCH v2 12/16] pathspec: create parse_long_magic function","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-12-10T18:18:31Z","receivedAt":"2016-12-10T18:18:38Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Stefan Beller <sbeller@google.com> writes:\n\n> Jonathan Nieder mentioned off list that he prefers to see that\n> series rerolled without mutexes if possible. That is possible by\n> creating the questions \"struct attr_check\" before preloading the\n> index and then using the read only questions in the threaded code,\n> to obtain answers fast; also no need for a mutex.\n\nI do not see how it would work without further splitting the\nattr_stack.  I think you made it per check[], but you would further\nsplit it per <check, thread> before losing the mutex, no?\n"},{"id":"307486","messageId":"CAGZ79kbbk4vdW_mbC0riXOf=31V9AQV7zKEh56G+sxjjzAr2-g@mail.gmail.com","threadId":"44632","inReplyTo":"xmqqk2b7ps08.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v2 12/16] pathspec: create parse_long_magic function","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2016-12-12T05:38:26Z","receivedAt":"2016-12-12T05:38:32Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"On Sat, Dec 10, 2016 at 10:18 AM, Junio C Hamano <gitster@pobox.com> wrote:\n> Stefan Beller <sbeller@google.com> writes:\n>\n>> Jonathan Nieder mentioned off list that he prefers to see that\n>> series rerolled without mutexes if possible. That is possible by\n>> creating the questions \"struct attr_check\" before preloading the\n>> index and then using the read only questions in the threaded code,\n>> to obtain answers fast; also no need for a mutex.\n>\n> I do not see how it would work without further splitting the\n> attr_stack.  I think you made it per check[], but you would further\n> split it per <check, thread> before losing the mutex, no?\n\nWell I have not yet looked into it again, so my memories are\nrusty, but the <check> is read only, such that the answers only\nneed to be per thread?\n"},{"id":"307488","messageId":"xmqqfultoej1.fsf@gitster.mtv.corp.google.com","threadId":"44632","inReplyTo":"CAGZ79kbbk4vdW_mbC0riXOf=31V9AQV7zKEh56G+sxjjzAr2-g@mail.gmail.com","subject":"Re: [PATCH v2 12/16] pathspec: create parse_long_magic function","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-12-12T06:19:30Z","receivedAt":"2016-12-12T06:19:40Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Stefan Beller <sbeller@google.com> writes:\n\n>> I do not see how it would work without further splitting the\n>> attr_stack.  I think you made it per check[], but you would further\n>> split it per <check, thread> before losing the mutex, no?\n>\n> Well I have not yet looked into it again, so my memories are\n> rusty, but the <check> is read only, such that the answers only\n> need to be per thread?\n\n<check> is read-only, so as long as you populate the singleton\nattr's beforehand, they can be shared across threads.  <answer>\nof course needs an instance per thread, and that is why you have\nthem typically on stack.\n\nThe process of filling <answer> by asking for a set of attrs in\n<check> for one <path> goes roughly like:\n\n - make sure attr_stack is set up for <path>, namely, the\n   info/attributes and .gitattributes files for each leading\n   directory are parsed.\n\n - go over the attr_stack entries and see what entries match <path>,\n   and collect the result for <check> in <answer>\n\nBefore d90675c151 (\"attr: keep attr stack for each check\",\n2016-11-10), I had only one instance of an attr stack [*1*], but\nwith that commit, you made it per <check>, which is a good move to\nallow us to optimize by keeping only the attributes relevant to\n<check> on the attr stack.\n\nBut it does not solve the threading issue.\n\nIf multiple threads are asking for the same set of attrs\n(i.e. running the same codepath using the same <check>) but for\n<path>s in different parts of the working tree (e.g. \"git checkout\"\nthat is multi-threaded, each thread asking for eol related\nattributes and checking out different subdirectories), you'd need\nmutex for correct operation at least, but that won't perform well\nbecause you'd end up thrashing the attr stack.  You'd need to split\nattr stack further and make it per (<check>, thread) tuple and you\nno longer need mutex at that point, but not before that.\n\n\n[footnote]\n\n*1* This is because the attr subsystem originally wasn't designed to\n    be used from multiple threads at the same time hence it was\n    sufficient to have a single \"currently interested are of the\n    directory hierarchy\".\n"},{"id":"307696","messageId":"20161213224920.GB4121@google.com","threadId":"44632","inReplyTo":"20161209192316.GB88637@google.com","subject":"Re: [PATCH 02/17] dir: convert create_simplify to use the pathspec struct interface","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2016-12-13T22:49:20Z","receivedAt":"2016-12-13T22:49:29Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"On 12/09, Brandon Williams wrote:\n> On 12/09, Duy Nguyen wrote:\n> > On Fri, Dec 9, 2016 at 1:19 AM, Brandon Williams <bmwill@google.com> wrote:\n> > > On 12/08, Duy Nguyen wrote:\n> > >> On Thu, Dec 8, 2016 at 7:03 AM, Brandon Williams <bmwill@google.com> wrote:\n> > >> > On 12/07, Duy Nguyen wrote:\n> > >> >> On Wed, Dec 7, 2016 at 4:51 AM, Brandon Williams <bmwill@google.com> wrote:\n> > >> >> > Convert 'create_simplify()' to use the pathspec struct interface from\n> > >> >> > using the '_raw' entry in the pathspec.\n> > >> >>\n> > >> >> It would be even better to kill this create_simplify() and let\n> > >> >> simplify_away() handle struct pathspec directly.\n> > >> >>\n> > >> >> There is a bug in this code, that might have been found if we\n> > >> >> simpify_away() handled pathspec directly: the memcmp() in\n> > >> >> simplify_away() will not play well with :(icase) magic. My bad. If\n> > >> >> :(icase) is used, the easiest/safe way is simplify nothing. Later on\n> > >> >> maybe we can teach simplify_away() to do strncasecmp instead. We could\n> > >> >> ignore exclude patterns there too (although not excluding is not a\n> > >> >> bug).\n> > >> >\n> > >> > So are you implying that the simplify struct needs to be killed?  That\n> > >> > way the pathspec struct itself is being passed around instead?\n> > >>\n> > >> Yes. simplify struct was a thing when pathspec was an array of char *.\n> > >> At this point I think it can retire (when we have time to retire it)\n> > >\n> > > Alright, then for now I can leave this change as is and have a follow up\n> > > series that kills the simplify struct.\n> > \n> > Do let me know if you decide to drop it, so I can put it back in my backlog.\n> \n> K will do\n> \n\nThis actually turned out to be more straight forward than I thought.\nI'll reroll this series again (with a few other changes) and include\nkilling the simplify struct.\n\n-- \nBrandon Williams\n"},{"id":"307698","messageId":"1481670870-66754-1-git-send-email-bmwill@google.com","threadId":"44632","inReplyTo":"1481223550-65277-1-git-send-email-bmwill@google.com","subject":"[PATCH v3 00/16] pathspec cleanup","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2016-12-13T23:14:14Z","receivedAt":"2016-12-13T23:15:52Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Differences in v3:\n* more readable strip submodule slash helper function which conforms to git's\n  style guide. [14/16]\n* instead of having create_simply() use struct pathspec directly, remove the\n  struct path_simplify entirely and use struct pathspec directly in both\n  simplify_away() and exclude_matches_pathspec(). [02/16]\n* small style issues corrected from v2. [15/16]\n\nBrandon Williams (16):\n  mv: remove use of deprecated 'get_pathspec()'\n  dir: remove struct path_simplify\n  dir: convert fill_directory to use the pathspec struct interface\n  ls-tree: convert show_recursive to use the pathspec struct interface\n  pathspec: remove the deprecated get_pathspec function\n  pathspec: copy and free owned memory\n  pathspec: remove unused variable from unsupported_magic\n  pathspec: always show mnemonic and name in unsupported_magic\n  pathspec: simpler logic to prefix original pathspec elements\n  pathspec: factor global magic into its own function\n  pathspec: create parse_short_magic function\n  pathspec: create parse_long_magic function\n  pathspec: create parse_element_magic helper\n  pathspec: create strip submodule slash helpers\n  pathspec: small readability changes\n  pathspec: rename prefix_pathspec to init_pathspec_item\n\n Documentation/technical/api-setup.txt |   2 -\n builtin/ls-tree.c                     |  16 +-\n builtin/mv.c                          |  50 ++--\n cache.h                               |   1 -\n dir.c                                 | 166 +++++-------\n pathspec.c                            | 476 +++++++++++++++++++---------------\n pathspec.h                            |   5 +-\n 7 files changed, 369 insertions(+), 347 deletions(-)\n\n--- interdiff on 'origin/bw/pathspec-cleanup'\n\ndiff --git a/dir.c b/dir.c\nindex a50b6f0..15f7c99 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -16,11 +16,6 @@\n #include \"varint.h\"\n #include \"ewah/ewok.h\"\n \n-struct path_simplify {\n-\tint len;\n-\tconst char *path;\n-};\n-\n /*\n  * Tells read_directory_recursive how a file or directory should be treated.\n  * Values are ordered by significance, e.g. if a directory contains both\n@@ -50,7 +45,7 @@ struct cached_dir {\n \n static enum path_treatment read_directory_recursive(struct dir_struct *dir,\n \tconst char *path, int len, struct untracked_cache_dir *untracked,\n-\tint check_only, const struct path_simplify *simplify);\n+\tint check_only, const struct pathspec *pathspec);\n static int get_dtype(struct dirent *de, const char *path, int len);\n \n int fspathcmp(const char *a, const char *b)\n@@ -1316,7 +1311,7 @@ static enum exist_status directory_exists_in_index(const char *dirname, int len)\n static enum path_treatment treat_directory(struct dir_struct *dir,\n \tstruct untracked_cache_dir *untracked,\n \tconst char *dirname, int len, int baselen, int exclude,\n-\tconst struct path_simplify *simplify)\n+\tconst struct pathspec *pathspec)\n {\n \t/* The \"len-1\" is to strip the final '/' */\n \tswitch (directory_exists_in_index(dirname, len-1)) {\n@@ -1345,7 +1340,7 @@ static enum path_treatment treat_directory(struct dir_struct *dir,\n \tuntracked = lookup_untracked(dir->untracked, untracked,\n \t\t\t\t     dirname + baselen, len - baselen);\n \treturn read_directory_recursive(dir, dirname, len,\n-\t\t\t\t\tuntracked, 1, simplify);\n+\t\t\t\t\tuntracked, 1, pathspec);\n }\n \n /*\n@@ -1353,24 +1348,25 @@ static enum path_treatment treat_directory(struct dir_struct *dir,\n  * reading - if the path cannot possibly be in the pathspec,\n  * return true, and we'll skip it early.\n  */\n-static int simplify_away(const char *path, int pathlen, const struct path_simplify *simplify)\n+static int simplify_away(const char *path, int pathlen,\n+\t\t\t const struct pathspec *pathspec)\n {\n-\tif (simplify) {\n-\t\tfor (;;) {\n-\t\t\tconst char *match = simplify->path;\n-\t\t\tint len = simplify->len;\n+\tint i;\n \n-\t\t\tif (!match)\n-\t\t\t\tbreak;\n-\t\t\tif (len > pathlen)\n-\t\t\t\tlen = pathlen;\n-\t\t\tif (!memcmp(path, match, len))\n-\t\t\t\treturn 0;\n-\t\t\tsimplify++;\n-\t\t}\n-\t\treturn 1;\n+\tif (!pathspec || !pathspec->nr)\n+\t\treturn 0;\n+\n+\tfor (i = 0; i < pathspec->nr; i++) {\n+\t\tconst struct pathspec_item *item = &pathspec->items[i];\n+\t\tint len = item->nowildcard_len;\n+\n+\t\tif (len > pathlen)\n+\t\t\tlen = pathlen;\n+\t\tif (!ps_strncmp(item, item->match, path, len))\n+\t\t\treturn 0;\n \t}\n-\treturn 0;\n+\n+\treturn 1;\n }\n \n /*\n@@ -1384,19 +1380,25 @@ static int simplify_away(const char *path, int pathlen, const struct path_simpli\n  *   2. the path is a directory prefix of some element in the\n  *      pathspec\n  */\n-static int exclude_matches_pathspec(const char *path, int len,\n-\t\tconst struct path_simplify *simplify)\n-{\n-\tif (simplify) {\n-\t\tfor (; simplify->path; simplify++) {\n-\t\t\tif (len == simplify->len\n-\t\t\t    && !memcmp(path, simplify->path, len))\n-\t\t\t\treturn 1;\n-\t\t\tif (len < simplify->len\n-\t\t\t    && simplify->path[len] == '/'\n-\t\t\t    && !memcmp(path, simplify->path, len))\n-\t\t\t\treturn 1;\n-\t\t}\n+static int exclude_matches_pathspec(const char *path, int pathlen,\n+\t\t\t\t    const struct pathspec *pathspec)\n+{\n+\tint i;\n+\n+\tif (!pathspec || !pathspec->nr)\n+\t\treturn 0;\n+\n+\tfor (i = 0; i < pathspec->nr; i++) {\n+\t\tconst struct pathspec_item *item = &pathspec->items[i];\n+\t\tint len = item->nowildcard_len;\n+\n+\t\tif (len == pathlen &&\n+\t\t    !ps_strncmp(item, item->match, path, pathlen))\n+\t\t\treturn 1;\n+\t\tif (len > pathlen &&\n+\t\t    item->match[pathlen] == '/' &&\n+\t\t    !ps_strncmp(item, item->match, path, pathlen))\n+\t\t\treturn 1;\n \t}\n \treturn 0;\n }\n@@ -1464,7 +1466,7 @@ static enum path_treatment treat_one_path(struct dir_struct *dir,\n \t\t\t\t\t  struct untracked_cache_dir *untracked,\n \t\t\t\t\t  struct strbuf *path,\n \t\t\t\t\t  int baselen,\n-\t\t\t\t\t  const struct path_simplify *simplify,\n+\t\t\t\t\t  const struct pathspec *pathspec,\n \t\t\t\t\t  int dtype, struct dirent *de)\n {\n \tint exclude;\n@@ -1516,7 +1518,7 @@ static enum path_treatment treat_one_path(struct dir_struct *dir,\n \tcase DT_DIR:\n \t\tstrbuf_addch(path, '/');\n \t\treturn treat_directory(dir, untracked, path->buf, path->len,\n-\t\t\t\t       baselen, exclude, simplify);\n+\t\t\t\t       baselen, exclude, pathspec);\n \tcase DT_REG:\n \tcase DT_LNK:\n \t\treturn exclude ? path_excluded : path_untracked;\n@@ -1528,7 +1530,7 @@ static enum path_treatment treat_path_fast(struct dir_struct *dir,\n \t\t\t\t\t   struct cached_dir *cdir,\n \t\t\t\t\t   struct strbuf *path,\n \t\t\t\t\t   int baselen,\n-\t\t\t\t\t   const struct path_simplify *simplify)\n+\t\t\t\t\t   const struct pathspec *pathspec)\n {\n \tstrbuf_setlen(path, baselen);\n \tif (!cdir->ucd) {\n@@ -1545,7 +1547,7 @@ static enum path_treatment treat_path_fast(struct dir_struct *dir,\n \t\t * with check_only set.\n \t\t */\n \t\treturn read_directory_recursive(dir, path->buf, path->len,\n-\t\t\t\t\t\tcdir->ucd, 1, simplify);\n+\t\t\t\t\t\tcdir->ucd, 1, pathspec);\n \t/*\n \t * We get path_recurse in the first run when\n \t * directory_exists_in_index() returns index_nonexistent. We\n@@ -1560,23 +1562,23 @@ static enum path_treatment treat_path(struct dir_struct *dir,\n \t\t\t\t      struct cached_dir *cdir,\n \t\t\t\t      struct strbuf *path,\n \t\t\t\t      int baselen,\n-\t\t\t\t      const struct path_simplify *simplify)\n+\t\t\t\t      const struct pathspec *pathspec)\n {\n \tint dtype;\n \tstruct dirent *de = cdir->de;\n \n \tif (!de)\n \t\treturn treat_path_fast(dir, untracked, cdir, path,\n-\t\t\t\t       baselen, simplify);\n+\t\t\t\t       baselen, pathspec);\n \tif (is_dot_or_dotdot(de->d_name) || !strcmp(de->d_name, \".git\"))\n \t\treturn path_none;\n \tstrbuf_setlen(path, baselen);\n \tstrbuf_addstr(path, de->d_name);\n-\tif (simplify_away(path->buf, path->len, simplify))\n+\tif (simplify_away(path->buf, path->len, pathspec))\n \t\treturn path_none;\n \n \tdtype = DTYPE(de);\n-\treturn treat_one_path(dir, untracked, path, baselen, simplify, dtype, de);\n+\treturn treat_one_path(dir, untracked, path, baselen, pathspec, dtype, de);\n }\n \n static void add_untracked(struct untracked_cache_dir *dir, const char *name)\n@@ -1707,7 +1709,7 @@ static void close_cached_dir(struct cached_dir *cdir)\n static enum path_treatment read_directory_recursive(struct dir_struct *dir,\n \t\t\t\t    const char *base, int baselen,\n \t\t\t\t    struct untracked_cache_dir *untracked, int check_only,\n-\t\t\t\t    const struct path_simplify *simplify)\n+\t\t\t\t    const struct pathspec *pathspec)\n {\n \tstruct cached_dir cdir;\n \tenum path_treatment state, subdir_state, dir_state = path_none;\n@@ -1723,7 +1725,8 @@ static enum path_treatment read_directory_recursive(struct dir_struct *dir,\n \n \twhile (!read_cached_dir(&cdir)) {\n \t\t/* check how the file or directory should be treated */\n-\t\tstate = treat_path(dir, untracked, &cdir, &path, baselen, simplify);\n+\t\tstate = treat_path(dir, untracked, &cdir, &path,\n+\t\t\t\t   baselen, pathspec);\n \n \t\tif (state > dir_state)\n \t\t\tdir_state = state;\n@@ -1735,8 +1738,9 @@ static enum path_treatment read_directory_recursive(struct dir_struct *dir,\n \t\t\t\t\t      path.buf + baselen,\n \t\t\t\t\t      path.len - baselen);\n \t\t\tsubdir_state =\n-\t\t\t\tread_directory_recursive(dir, path.buf, path.len,\n-\t\t\t\t\t\t\t ud, check_only, simplify);\n+\t\t\t\tread_directory_recursive(dir, path.buf,\n+\t\t\t\t\t\t\t path.len, ud,\n+\t\t\t\t\t\t\t check_only, pathspec);\n \t\t\tif (subdir_state > dir_state)\n \t\t\t\tdir_state = subdir_state;\n \t\t}\n@@ -1760,7 +1764,7 @@ static enum path_treatment read_directory_recursive(struct dir_struct *dir,\n \t\t\telse if ((dir->flags & DIR_SHOW_IGNORED_TOO) ||\n \t\t\t\t((dir->flags & DIR_COLLECT_IGNORED) &&\n \t\t\t\texclude_matches_pathspec(path.buf, path.len,\n-\t\t\t\t\tsimplify)))\n+\t\t\t\t\t\t\t pathspec)))\n \t\t\t\tdir_add_ignored(dir, path.buf, path.len);\n \t\t\tbreak;\n \n@@ -1791,35 +1795,9 @@ static int cmp_name(const void *p1, const void *p2)\n \treturn name_compare(e1->name, e1->len, e2->name, e2->len);\n }\n \n-static struct path_simplify *create_simplify(const struct pathspec *pathspec)\n-{\n-\tint i;\n-\tstruct path_simplify *simplify = NULL;\n-\n-\tif (!pathspec || !pathspec->nr)\n-\t\treturn NULL;\n-\n-\tALLOC_ARRAY(simplify, pathspec->nr + 1);\n-\tfor (i = 0; i < pathspec->nr; i++) {\n-\t\tconst char *match;\n-\t\tmatch = pathspec->items[i].match;\n-\t\tsimplify[i].path = match;\n-\t\tsimplify[i].len = pathspec->items[i].nowildcard_len;\n-\t}\n-\tsimplify[i].path = NULL;\n-\tsimplify[i].len = 0;\n-\n-\treturn simplify;\n-}\n-\n-static void free_simplify(struct path_simplify *simplify)\n-{\n-\tfree(simplify);\n-}\n-\n static int treat_leading_path(struct dir_struct *dir,\n \t\t\t      const char *path, int len,\n-\t\t\t      const struct path_simplify *simplify)\n+\t\t\t      const struct pathspec *pathspec)\n {\n \tstruct strbuf sb = STRBUF_INIT;\n \tint baselen, rc = 0;\n@@ -1843,9 +1821,9 @@ static int treat_leading_path(struct dir_struct *dir,\n \t\tstrbuf_add(&sb, path, baselen);\n \t\tif (!is_directory(sb.buf))\n \t\t\tbreak;\n-\t\tif (simplify_away(sb.buf, sb.len, simplify))\n+\t\tif (simplify_away(sb.buf, sb.len, pathspec))\n \t\t\tbreak;\n-\t\tif (treat_one_path(dir, NULL, &sb, baselen, simplify,\n+\t\tif (treat_one_path(dir, NULL, &sb, baselen, pathspec,\n \t\t\t\t   DT_DIR, NULL) == path_none)\n \t\t\tbreak; /* do not recurse into it */\n \t\tif (len <= baselen) {\n@@ -2013,14 +1991,11 @@ static struct untracked_cache_dir *validate_untracked_cache(struct dir_struct *d\n \treturn root;\n }\n \n-int read_directory(struct dir_struct *dir, const char *path, int len, const struct pathspec *pathspec)\n+int read_directory(struct dir_struct *dir, const char *path,\n+\t\t   int len, const struct pathspec *pathspec)\n {\n-\tstruct path_simplify *simplify;\n \tstruct untracked_cache_dir *untracked;\n \n-\t/*\n-\t * Check out create_simplify()\n-\t */\n \tif (pathspec)\n \t\tGUARD_PATHSPEC(pathspec,\n \t\t\t       PATHSPEC_FROMTOP |\n@@ -2033,13 +2008,6 @@ 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-\t/*\n-\t * exclude patterns are treated like positive ones in\n-\t * create_simplify. Usually exclude patterns should be a\n-\t * subset of positive ones, which has no impacts on\n-\t * create_simplify().\n-\t */\n-\tsimplify = create_simplify(pathspec);\n \tuntracked = validate_untracked_cache(dir, len, pathspec);\n \tif (!untracked)\n \t\t/*\n@@ -2047,9 +2015,8 @@ int read_directory(struct dir_struct *dir, const char *path, int len, const stru\n \t\t * e.g. prep_exclude()\n \t\t */\n \t\tdir->untracked = NULL;\n-\tif (!len || treat_leading_path(dir, path, len, simplify))\n-\t\tread_directory_recursive(dir, path, len, untracked, 0, simplify);\n-\tfree_simplify(simplify);\n+\tif (!len || treat_leading_path(dir, path, len, pathspec))\n+\t\tread_directory_recursive(dir, path, len, untracked, 0, pathspec);\n \tQSORT(dir->entries, dir->nr, cmp_name);\n \tQSORT(dir->ignored, dir->ignored_nr, cmp_name);\n \tif (dir->untracked) {\ndiff --git a/pathspec.c b/pathspec.c\nindex cabc02e..d4efcf6 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -67,11 +67,11 @@ static struct pathspec_magic {\n \tchar mnemonic; /* this cannot be ':'! */\n \tconst char *name;\n } pathspec_magic[] = {\n-\t{ PATHSPEC_FROMTOP, '/', \"top\" },\n+\t{ PATHSPEC_FROMTOP,  '/', \"top\" },\n \t{ PATHSPEC_LITERAL, '\\0', \"literal\" },\n-\t{ PATHSPEC_GLOB,   '\\0', \"glob\" },\n-\t{ PATHSPEC_ICASE,  '\\0', \"icase\" },\n-\t{ PATHSPEC_EXCLUDE, '!', \"exclude\" },\n+\t{ PATHSPEC_GLOB,    '\\0', \"glob\" },\n+\t{ PATHSPEC_ICASE,   '\\0', \"icase\" },\n+\t{ PATHSPEC_EXCLUDE,  '!', \"exclude\" },\n };\n \n static void prefix_magic(struct strbuf *sb, int prefixlen, unsigned magic)\n@@ -260,13 +260,13 @@ static const char *parse_element_magic(unsigned *magic, int *prefix_len,\n \n static void strip_submodule_slash_cheap(struct pathspec_item *item)\n {\n-\tint i;\n+\tif (item->len >= 1 && item->match[item->len - 1] == '/') {\n+\t\tint i = cache_name_pos(item->match, item->len - 1);\n \n-\tif ((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\titem->match[item->len] = '\\0';\n+\t\tif (i >= 0 && S_ISGITLINK(active_cache[i]->ce_mode)) {\n+\t\t\titem->len--;\n+\t\t\titem->match[item->len] = '\\0';\n+\t\t}\n \t}\n }\n \n-- \n2.8.0.rc3.226.g39d4020\n\n"},{"id":"307699","messageId":"1481670870-66754-3-git-send-email-bmwill@google.com","threadId":"44632","inReplyTo":"1481670870-66754-1-git-send-email-bmwill@google.com","subject":"[PATCH v3 02/16] dir: remove struct path_simplify","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2016-12-13T23:14:16Z","receivedAt":"2016-12-13T23:15:57Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Teach simplify_away() and exclude_matches_pathspec() to handle struct\npathspec directly, eliminating the need for the struct path_simplify.\n\nAlso renamed the len parameter to pathlen in exclude_matches_pathspec()\nto match the parameter names used in simplify_away().\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n dir.c | 154 ++++++++++++++++++++++++++----------------------------------------\n 1 file changed, 60 insertions(+), 94 deletions(-)\n\ndiff --git a/dir.c b/dir.c\nindex bfa8c8a..aadf073 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -16,11 +16,6 @@\n #include \"varint.h\"\n #include \"ewah/ewok.h\"\n \n-struct path_simplify {\n-\tint len;\n-\tconst char *path;\n-};\n-\n /*\n  * Tells read_directory_recursive how a file or directory should be treated.\n  * Values are ordered by significance, e.g. if a directory contains both\n@@ -50,7 +45,7 @@ struct cached_dir {\n \n static enum path_treatment read_directory_recursive(struct dir_struct *dir,\n \tconst char *path, int len, struct untracked_cache_dir *untracked,\n-\tint check_only, const struct path_simplify *simplify);\n+\tint check_only, const struct pathspec *pathspec);\n static int get_dtype(struct dirent *de, const char *path, int len);\n \n int fspathcmp(const char *a, const char *b)\n@@ -1312,7 +1307,7 @@ static enum exist_status directory_exists_in_index(const char *dirname, int len)\n static enum path_treatment treat_directory(struct dir_struct *dir,\n \tstruct untracked_cache_dir *untracked,\n \tconst char *dirname, int len, int baselen, int exclude,\n-\tconst struct path_simplify *simplify)\n+\tconst struct pathspec *pathspec)\n {\n \t/* The \"len-1\" is to strip the final '/' */\n \tswitch (directory_exists_in_index(dirname, len-1)) {\n@@ -1341,7 +1336,7 @@ static enum path_treatment treat_directory(struct dir_struct *dir,\n \tuntracked = lookup_untracked(dir->untracked, untracked,\n \t\t\t\t     dirname + baselen, len - baselen);\n \treturn read_directory_recursive(dir, dirname, len,\n-\t\t\t\t\tuntracked, 1, simplify);\n+\t\t\t\t\tuntracked, 1, pathspec);\n }\n \n /*\n@@ -1349,24 +1344,25 @@ static enum path_treatment treat_directory(struct dir_struct *dir,\n  * reading - if the path cannot possibly be in the pathspec,\n  * return true, and we'll skip it early.\n  */\n-static int simplify_away(const char *path, int pathlen, const struct path_simplify *simplify)\n+static int simplify_away(const char *path, int pathlen,\n+\t\t\t const struct pathspec *pathspec)\n {\n-\tif (simplify) {\n-\t\tfor (;;) {\n-\t\t\tconst char *match = simplify->path;\n-\t\t\tint len = simplify->len;\n+\tint i;\n \n-\t\t\tif (!match)\n-\t\t\t\tbreak;\n-\t\t\tif (len > pathlen)\n-\t\t\t\tlen = pathlen;\n-\t\t\tif (!memcmp(path, match, len))\n-\t\t\t\treturn 0;\n-\t\t\tsimplify++;\n-\t\t}\n-\t\treturn 1;\n+\tif (!pathspec || !pathspec->nr)\n+\t\treturn 0;\n+\n+\tfor (i = 0; i < pathspec->nr; i++) {\n+\t\tconst struct pathspec_item *item = &pathspec->items[i];\n+\t\tint len = item->nowildcard_len;\n+\n+\t\tif (len > pathlen)\n+\t\t\tlen = pathlen;\n+\t\tif (!ps_strncmp(item, item->match, path, len))\n+\t\t\treturn 0;\n \t}\n-\treturn 0;\n+\n+\treturn 1;\n }\n \n /*\n@@ -1380,19 +1376,25 @@ static int simplify_away(const char *path, int pathlen, const struct path_simpli\n  *   2. the path is a directory prefix of some element in the\n  *      pathspec\n  */\n-static int exclude_matches_pathspec(const char *path, int len,\n-\t\tconst struct path_simplify *simplify)\n-{\n-\tif (simplify) {\n-\t\tfor (; simplify->path; simplify++) {\n-\t\t\tif (len == simplify->len\n-\t\t\t    && !memcmp(path, simplify->path, len))\n-\t\t\t\treturn 1;\n-\t\t\tif (len < simplify->len\n-\t\t\t    && simplify->path[len] == '/'\n-\t\t\t    && !memcmp(path, simplify->path, len))\n-\t\t\t\treturn 1;\n-\t\t}\n+static int exclude_matches_pathspec(const char *path, int pathlen,\n+\t\t\t\t    const struct pathspec *pathspec)\n+{\n+\tint i;\n+\n+\tif (!pathspec || !pathspec->nr)\n+\t\treturn 0;\n+\n+\tfor (i = 0; i < pathspec->nr; i++) {\n+\t\tconst struct pathspec_item *item = &pathspec->items[i];\n+\t\tint len = item->nowildcard_len;\n+\n+\t\tif (len == pathlen &&\n+\t\t    !ps_strncmp(item, item->match, path, pathlen))\n+\t\t\treturn 1;\n+\t\tif (len > pathlen &&\n+\t\t    item->match[pathlen] == '/' &&\n+\t\t    !ps_strncmp(item, item->match, path, pathlen))\n+\t\t\treturn 1;\n \t}\n \treturn 0;\n }\n@@ -1460,7 +1462,7 @@ static enum path_treatment treat_one_path(struct dir_struct *dir,\n \t\t\t\t\t  struct untracked_cache_dir *untracked,\n \t\t\t\t\t  struct strbuf *path,\n \t\t\t\t\t  int baselen,\n-\t\t\t\t\t  const struct path_simplify *simplify,\n+\t\t\t\t\t  const struct pathspec *pathspec,\n \t\t\t\t\t  int dtype, struct dirent *de)\n {\n \tint exclude;\n@@ -1512,7 +1514,7 @@ static enum path_treatment treat_one_path(struct dir_struct *dir,\n \tcase DT_DIR:\n \t\tstrbuf_addch(path, '/');\n \t\treturn treat_directory(dir, untracked, path->buf, path->len,\n-\t\t\t\t       baselen, exclude, simplify);\n+\t\t\t\t       baselen, exclude, pathspec);\n \tcase DT_REG:\n \tcase DT_LNK:\n \t\treturn exclude ? path_excluded : path_untracked;\n@@ -1524,7 +1526,7 @@ static enum path_treatment treat_path_fast(struct dir_struct *dir,\n \t\t\t\t\t   struct cached_dir *cdir,\n \t\t\t\t\t   struct strbuf *path,\n \t\t\t\t\t   int baselen,\n-\t\t\t\t\t   const struct path_simplify *simplify)\n+\t\t\t\t\t   const struct pathspec *pathspec)\n {\n \tstrbuf_setlen(path, baselen);\n \tif (!cdir->ucd) {\n@@ -1541,7 +1543,7 @@ static enum path_treatment treat_path_fast(struct dir_struct *dir,\n \t\t * with check_only set.\n \t\t */\n \t\treturn read_directory_recursive(dir, path->buf, path->len,\n-\t\t\t\t\t\tcdir->ucd, 1, simplify);\n+\t\t\t\t\t\tcdir->ucd, 1, pathspec);\n \t/*\n \t * We get path_recurse in the first run when\n \t * directory_exists_in_index() returns index_nonexistent. We\n@@ -1556,23 +1558,23 @@ static enum path_treatment treat_path(struct dir_struct *dir,\n \t\t\t\t      struct cached_dir *cdir,\n \t\t\t\t      struct strbuf *path,\n \t\t\t\t      int baselen,\n-\t\t\t\t      const struct path_simplify *simplify)\n+\t\t\t\t      const struct pathspec *pathspec)\n {\n \tint dtype;\n \tstruct dirent *de = cdir->de;\n \n \tif (!de)\n \t\treturn treat_path_fast(dir, untracked, cdir, path,\n-\t\t\t\t       baselen, simplify);\n+\t\t\t\t       baselen, pathspec);\n \tif (is_dot_or_dotdot(de->d_name) || !strcmp(de->d_name, \".git\"))\n \t\treturn path_none;\n \tstrbuf_setlen(path, baselen);\n \tstrbuf_addstr(path, de->d_name);\n-\tif (simplify_away(path->buf, path->len, simplify))\n+\tif (simplify_away(path->buf, path->len, pathspec))\n \t\treturn path_none;\n \n \tdtype = DTYPE(de);\n-\treturn treat_one_path(dir, untracked, path, baselen, simplify, dtype, de);\n+\treturn treat_one_path(dir, untracked, path, baselen, pathspec, dtype, de);\n }\n \n static void add_untracked(struct untracked_cache_dir *dir, const char *name)\n@@ -1703,7 +1705,7 @@ static void close_cached_dir(struct cached_dir *cdir)\n static enum path_treatment read_directory_recursive(struct dir_struct *dir,\n \t\t\t\t    const char *base, int baselen,\n \t\t\t\t    struct untracked_cache_dir *untracked, int check_only,\n-\t\t\t\t    const struct path_simplify *simplify)\n+\t\t\t\t    const struct pathspec *pathspec)\n {\n \tstruct cached_dir cdir;\n \tenum path_treatment state, subdir_state, dir_state = path_none;\n@@ -1719,7 +1721,8 @@ static enum path_treatment read_directory_recursive(struct dir_struct *dir,\n \n \twhile (!read_cached_dir(&cdir)) {\n \t\t/* check how the file or directory should be treated */\n-\t\tstate = treat_path(dir, untracked, &cdir, &path, baselen, simplify);\n+\t\tstate = treat_path(dir, untracked, &cdir, &path,\n+\t\t\t\t   baselen, pathspec);\n \n \t\tif (state > dir_state)\n \t\t\tdir_state = state;\n@@ -1731,8 +1734,9 @@ static enum path_treatment read_directory_recursive(struct dir_struct *dir,\n \t\t\t\t\t      path.buf + baselen,\n \t\t\t\t\t      path.len - baselen);\n \t\t\tsubdir_state =\n-\t\t\t\tread_directory_recursive(dir, path.buf, path.len,\n-\t\t\t\t\t\t\t ud, check_only, simplify);\n+\t\t\t\tread_directory_recursive(dir, path.buf,\n+\t\t\t\t\t\t\t path.len, ud,\n+\t\t\t\t\t\t\t check_only, pathspec);\n \t\t\tif (subdir_state > dir_state)\n \t\t\t\tdir_state = subdir_state;\n \t\t}\n@@ -1756,7 +1760,7 @@ static enum path_treatment read_directory_recursive(struct dir_struct *dir,\n \t\t\telse if ((dir->flags & DIR_SHOW_IGNORED_TOO) ||\n \t\t\t\t((dir->flags & DIR_COLLECT_IGNORED) &&\n \t\t\t\texclude_matches_pathspec(path.buf, path.len,\n-\t\t\t\t\tsimplify)))\n+\t\t\t\t\t\t\t pathspec)))\n \t\t\t\tdir_add_ignored(dir, path.buf, path.len);\n \t\t\tbreak;\n \n@@ -1787,36 +1791,9 @@ static int cmp_name(const void *p1, const void *p2)\n \treturn name_compare(e1->name, e1->len, e2->name, e2->len);\n }\n \n-static struct path_simplify *create_simplify(const char **pathspec)\n-{\n-\tint nr, alloc = 0;\n-\tstruct path_simplify *simplify = NULL;\n-\n-\tif (!pathspec)\n-\t\treturn NULL;\n-\n-\tfor (nr = 0 ; ; nr++) {\n-\t\tconst char *match;\n-\t\tALLOC_GROW(simplify, nr + 1, alloc);\n-\t\tmatch = *pathspec++;\n-\t\tif (!match)\n-\t\t\tbreak;\n-\t\tsimplify[nr].path = match;\n-\t\tsimplify[nr].len = simple_length(match);\n-\t}\n-\tsimplify[nr].path = NULL;\n-\tsimplify[nr].len = 0;\n-\treturn simplify;\n-}\n-\n-static void free_simplify(struct path_simplify *simplify)\n-{\n-\tfree(simplify);\n-}\n-\n static int treat_leading_path(struct dir_struct *dir,\n \t\t\t      const char *path, int len,\n-\t\t\t      const struct path_simplify *simplify)\n+\t\t\t      const struct pathspec *pathspec)\n {\n \tstruct strbuf sb = STRBUF_INIT;\n \tint baselen, rc = 0;\n@@ -1840,9 +1817,9 @@ static int treat_leading_path(struct dir_struct *dir,\n \t\tstrbuf_add(&sb, path, baselen);\n \t\tif (!is_directory(sb.buf))\n \t\t\tbreak;\n-\t\tif (simplify_away(sb.buf, sb.len, simplify))\n+\t\tif (simplify_away(sb.buf, sb.len, pathspec))\n \t\t\tbreak;\n-\t\tif (treat_one_path(dir, NULL, &sb, baselen, simplify,\n+\t\tif (treat_one_path(dir, NULL, &sb, baselen, pathspec,\n \t\t\t\t   DT_DIR, NULL) == path_none)\n \t\t\tbreak; /* do not recurse into it */\n \t\tif (len <= baselen) {\n@@ -2010,14 +1987,11 @@ static struct untracked_cache_dir *validate_untracked_cache(struct dir_struct *d\n \treturn root;\n }\n \n-int read_directory(struct dir_struct *dir, const char *path, int len, const struct pathspec *pathspec)\n+int read_directory(struct dir_struct *dir, const char *path,\n+\t\t   int len, const struct pathspec *pathspec)\n {\n-\tstruct path_simplify *simplify;\n \tstruct untracked_cache_dir *untracked;\n \n-\t/*\n-\t * Check out create_simplify()\n-\t */\n \tif (pathspec)\n \t\tGUARD_PATHSPEC(pathspec,\n \t\t\t       PATHSPEC_FROMTOP |\n@@ -2030,13 +2004,6 @@ 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-\t/*\n-\t * exclude patterns are treated like positive ones in\n-\t * create_simplify. Usually exclude patterns should be a\n-\t * subset of positive ones, which has no impacts on\n-\t * create_simplify().\n-\t */\n-\tsimplify = create_simplify(pathspec ? pathspec->_raw : NULL);\n \tuntracked = validate_untracked_cache(dir, len, pathspec);\n \tif (!untracked)\n \t\t/*\n@@ -2044,9 +2011,8 @@ int read_directory(struct dir_struct *dir, const char *path, int len, const stru\n \t\t * e.g. prep_exclude()\n \t\t */\n \t\tdir->untracked = NULL;\n-\tif (!len || treat_leading_path(dir, path, len, simplify))\n-\t\tread_directory_recursive(dir, path, len, untracked, 0, simplify);\n-\tfree_simplify(simplify);\n+\tif (!len || treat_leading_path(dir, path, len, pathspec))\n+\t\tread_directory_recursive(dir, path, len, untracked, 0, pathspec);\n \tQSORT(dir->entries, dir->nr, cmp_name);\n \tQSORT(dir->ignored, dir->ignored_nr, cmp_name);\n \tif (dir->untracked) {\n-- \n2.8.0.rc3.226.g39d4020\n\n"},{"id":"307700","messageId":"1481670870-66754-5-git-send-email-bmwill@google.com","threadId":"44632","inReplyTo":"1481670870-66754-1-git-send-email-bmwill@google.com","subject":"[PATCH v3 04/16] ls-tree: convert show_recursive to use the pathspec struct interface","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2016-12-13T23:14:18Z","receivedAt":"2016-12-13T23:16:36Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Convert 'show_recursive()' to use the pathspec struct interface from\nusing the '_raw' entry in the pathspec struct.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n builtin/ls-tree.c | 16 +++++++---------\n 1 file changed, 7 insertions(+), 9 deletions(-)\n\ndiff --git a/builtin/ls-tree.c b/builtin/ls-tree.c\nindex 0e30d86..d7ebeb4 100644\n--- a/builtin/ls-tree.c\n+++ b/builtin/ls-tree.c\n@@ -31,21 +31,18 @@ static const  char * const ls_tree_usage[] = {\n \n static int show_recursive(const char *base, int baselen, const char *pathname)\n {\n-\tconst char **s;\n+\tint i;\n \n \tif (ls_options & LS_RECURSIVE)\n \t\treturn 1;\n \n-\ts = pathspec._raw;\n-\tif (!s)\n+\tif (!pathspec.nr)\n \t\treturn 0;\n \n-\tfor (;;) {\n-\t\tconst char *spec = *s++;\n+\tfor (i = 0; i < pathspec.nr; i++) {\n+\t\tconst char *spec = pathspec.items[i].match;\n \t\tint len, speclen;\n \n-\t\tif (!spec)\n-\t\t\treturn 0;\n \t\tif (strncmp(base, spec, baselen))\n \t\t\tcontinue;\n \t\tlen = strlen(pathname);\n@@ -59,6 +56,7 @@ static int show_recursive(const char *base, int baselen, const char *pathname)\n \t\t\tcontinue;\n \t\treturn 1;\n \t}\n+\treturn 0;\n }\n \n static int show_tree(const unsigned char *sha1, struct strbuf *base,\n@@ -175,8 +173,8 @@ 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() or tree_entry_interesting()\n \t */\n-\tparse_pathspec(&pathspec, PATHSPEC_GLOB | PATHSPEC_ICASE |\n-\t\t\t\t  PATHSPEC_EXCLUDE,\n+\tparse_pathspec(&pathspec, PATHSPEC_ALL_MAGIC &\n+\t\t\t\t  ~(PATHSPEC_FROMTOP | PATHSPEC_LITERAL),\n \t\t       PATHSPEC_PREFER_CWD,\n \t\t       prefix, argv + 1);\n \tfor (i = 0; i < pathspec.nr; i++)\n-- \n2.8.0.rc3.226.g39d4020\n\n"},{"id":"307701","messageId":"1481670870-66754-4-git-send-email-bmwill@google.com","threadId":"44632","inReplyTo":"1481670870-66754-1-git-send-email-bmwill@google.com","subject":"[PATCH v3 03/16] dir: convert fill_directory to use the pathspec struct interface","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2016-12-13T23:14:17Z","receivedAt":"2016-12-13T23:16:40Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Convert 'fill_directory()' to use the pathspec struct interface from\nusing the '_raw' entry in the pathspec struct.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n dir.c | 12 ++++++++----\n 1 file changed, 8 insertions(+), 4 deletions(-)\n\ndiff --git a/dir.c b/dir.c\nindex aadf073..15f7c99 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -174,17 +174,21 @@ char *common_prefix(const struct pathspec *pathspec)\n \n int fill_directory(struct dir_struct *dir, const struct pathspec *pathspec)\n {\n-\tsize_t len;\n+\tchar *prefix;\n+\tsize_t prefix_len;\n \n \t/*\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+\tprefix = common_prefix(pathspec);\n+\tprefix_len = prefix ? strlen(prefix) : 0;\n \n \t/* Read the directory and prune it */\n-\tread_directory(dir, pathspec->nr ? pathspec->_raw[0] : \"\", len, pathspec);\n-\treturn len;\n+\tread_directory(dir, prefix, prefix_len, pathspec);\n+\n+\tfree(prefix);\n+\treturn prefix_len;\n }\n \n int within_depth(const char *name, int namelen,\n-- \n2.8.0.rc3.226.g39d4020\n\n"},{"id":"307702","messageId":"1481670870-66754-8-git-send-email-bmwill@google.com","threadId":"44632","inReplyTo":"1481670870-66754-1-git-send-email-bmwill@google.com","subject":"[PATCH v3 07/16] pathspec: remove unused variable from unsupported_magic","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2016-12-13T23:14:21Z","receivedAt":"2016-12-13T23:16:45Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Removed unused variable 'n' from the 'unsupported_magic()' function.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n pathspec.c | 5 ++---\n 1 file changed, 2 insertions(+), 3 deletions(-)\n\ndiff --git a/pathspec.c b/pathspec.c\nindex 8f367f0..ec0d590 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -333,8 +333,8 @@ static void NORETURN unsupported_magic(const char *pattern,\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+\tint i;\n+\tfor (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@@ -344,7 +344,6 @@ static void NORETURN unsupported_magic(const char *pattern,\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 substitute \"this command\" with a command\n-- \n2.8.0.rc3.226.g39d4020\n\n"},{"id":"307703","messageId":"1481670870-66754-9-git-send-email-bmwill@google.com","threadId":"44632","inReplyTo":"1481670870-66754-1-git-send-email-bmwill@google.com","subject":"[PATCH v3 08/16] pathspec: always show mnemonic and name in unsupported_magic","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2016-12-13T23:14:22Z","receivedAt":"2016-12-13T23:16:50Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"For better clarity, always show the mnemonic and name of the unsupported\nmagic being used.  This lets users have a more clear understanding of\nwhat magic feature isn't supported.  And if they supplied a mnemonic,\nthe user will be told what its corresponding name is which will allow\nthem to more easily search the man pages for that magic type.\n\nThis also avoids passing an extra parameter around the pathspec\ninitialization code.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n pathspec.c | 21 +++++++--------------\n 1 file changed, 7 insertions(+), 14 deletions(-)\n\ndiff --git a/pathspec.c b/pathspec.c\nindex ec0d590..609c58f 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -101,9 +101,7 @@ static void prefix_short_magic(struct strbuf *sb, int prefixlen,\n  * the prefix part must always match literally, and a single stupid\n  * string cannot express such a case.\n  */\n-static unsigned prefix_pathspec(struct pathspec_item *item,\n-\t\t\t\tunsigned *p_short_magic,\n-\t\t\t\tunsigned flags,\n+static unsigned prefix_pathspec(struct pathspec_item *item, unsigned flags,\n \t\t\t\tconst char *prefix, int prefixlen,\n \t\t\t\tconst char *elt)\n {\n@@ -210,7 +208,6 @@ static unsigned prefix_pathspec(struct pathspec_item *item,\n \t}\n \n \tmagic |= short_magic;\n-\t*p_short_magic = short_magic;\n \n \t/* --noglob-pathspec adds :(literal) _unless_ :(glob) is specified */\n \tif (noglob_global && !(magic & PATHSPEC_GLOB))\n@@ -329,8 +326,7 @@ static int pathspec_item_cmp(const void *a_, const void *b_)\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+\t\t\t\t       unsigned magic)\n {\n \tstruct strbuf sb = STRBUF_INIT;\n \tint i;\n@@ -340,8 +336,9 @@ static void NORETURN unsupported_magic(const char *pattern,\n \t\t\tcontinue;\n \t\tif (sb.len)\n \t\t\tstrbuf_addch(&sb, ' ');\n-\t\tif (short_magic & m->bit)\n-\t\t\tstrbuf_addf(&sb, \"'%c'\", m->mnemonic);\n+\n+\t\tif (m->mnemonic)\n+\t\t\tstrbuf_addf(&sb, \"'(%c)%s'\", m->mnemonic, m->name);\n \t\telse\n \t\t\tstrbuf_addf(&sb, \"'%s'\", m->name);\n \t}\n@@ -413,11 +410,9 @@ void parse_pathspec(struct pathspec *pathspec,\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\tflags,\n+\t\titem[i].magic = prefix_pathspec(item + i, flags,\n \t\t\t\t\t\tprefix, prefixlen, entry);\n \t\tif ((flags & PATHSPEC_LITERAL_PATH) &&\n \t\t    !(magic_mask & PATHSPEC_LITERAL))\n@@ -425,9 +420,7 @@ void parse_pathspec(struct pathspec *pathspec,\n \t\tif (item[i].magic & PATHSPEC_EXCLUDE)\n \t\t\tnr_exclude++;\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\t\tunsupported_magic(entry, item[i].magic & magic_mask);\n \n \t\tif ((flags & PATHSPEC_SYMLINK_LEADING_PATH) &&\n \t\t    has_symlink_leading_path(item[i].match, item[i].len)) {\n-- \n2.8.0.rc3.226.g39d4020\n\n"},{"id":"307704","messageId":"1481670870-66754-7-git-send-email-bmwill@google.com","threadId":"44632","inReplyTo":"1481670870-66754-1-git-send-email-bmwill@google.com","subject":"[PATCH v3 06/16] pathspec: copy and free owned memory","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2016-12-13T23:14:20Z","receivedAt":"2016-12-13T23:16:53Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"The 'original' string entry in a pathspec_item is only duplicated some\nof the time, instead always make a copy of the original and take\nownership of the memory.\n\nSince both 'match' and 'original' string entries in a pathspec_item are\nowned by the pathspec struct, they need to be freed when clearing the\npathspec struct (in 'clear_pathspec()') and duplicated when copying the\npathspec struct (in 'copy_pathspec()').\n\nAlso change the type of 'match' and 'original' to 'char *' in order to\nmore explicitly show the ownership of the memory.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n pathspec.c | 22 ++++++++++++++++++----\n pathspec.h |  4 ++--\n 2 files changed, 20 insertions(+), 6 deletions(-)\n\ndiff --git a/pathspec.c b/pathspec.c\nindex 1f918cb..8f367f0 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -259,8 +259,9 @@ static unsigned prefix_pathspec(struct pathspec_item *item,\n \t\t}\n \t\tstrbuf_addstr(&sb, match);\n \t\titem->original = strbuf_detach(&sb, NULL);\n-\t} else\n-\t\titem->original = elt;\n+\t} else {\n+\t\titem->original = xstrdup(elt);\n+\t}\n \titem->len = strlen(item->match);\n \titem->prefix = prefixlen;\n \n@@ -388,8 +389,8 @@ void parse_pathspec(struct pathspec *pathspec,\n \t\t\tdie(\"BUG: PATHSPEC_PREFER_CWD requires arguments\");\n \n \t\tpathspec->items = item = xcalloc(1, sizeof(*item));\n-\t\titem->match = prefix;\n-\t\titem->original = prefix;\n+\t\titem->match = xstrdup(prefix);\n+\t\titem->original = xstrdup(prefix);\n \t\titem->nowildcard_len = item->len = strlen(prefix);\n \t\titem->prefix = item->len;\n \t\tpathspec->nr = 1;\n@@ -453,13 +454,26 @@ void parse_pathspec(struct pathspec *pathspec,\n \n void copy_pathspec(struct pathspec *dst, const struct pathspec *src)\n {\n+\tint i;\n+\n \t*dst = *src;\n \tALLOC_ARRAY(dst->items, dst->nr);\n \tCOPY_ARRAY(dst->items, src->items, dst->nr);\n+\n+\tfor (i = 0; i < dst->nr; i++) {\n+\t\tdst->items[i].match = xstrdup(src->items[i].match);\n+\t\tdst->items[i].original = xstrdup(src->items[i].original);\n+\t}\n }\n \n void clear_pathspec(struct pathspec *pathspec)\n {\n+\tint i;\n+\n+\tfor (i = 0; i < pathspec->nr; i++) {\n+\t\tfree(pathspec->items[i].match);\n+\t\tfree(pathspec->items[i].original);\n+\t}\n \tfree(pathspec->items);\n \tpathspec->items = NULL;\n }\ndiff --git a/pathspec.h b/pathspec.h\nindex 70a592e..49fd823 100644\n--- a/pathspec.h\n+++ b/pathspec.h\n@@ -25,8 +25,8 @@ struct pathspec {\n \tunsigned magic;\n \tint max_depth;\n \tstruct pathspec_item {\n-\t\tconst char *match;\n-\t\tconst char *original;\n+\t\tchar *match;\n+\t\tchar *original;\n \t\tunsigned magic;\n \t\tint len, prefix;\n \t\tint nowildcard_len;\n-- \n2.8.0.rc3.226.g39d4020\n\n"},{"id":"307705","messageId":"1481670870-66754-2-git-send-email-bmwill@google.com","threadId":"44632","inReplyTo":"1481670870-66754-1-git-send-email-bmwill@google.com","subject":"[PATCH v3 01/16] mv: remove use of deprecated 'get_pathspec()'","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2016-12-13T23:14:15Z","receivedAt":"2016-12-13T23:16:54Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Convert the 'internal_copy_pathspec()' function to 'prefix_path()'\ninstead of using the deprecated 'get_pathspec()' interface.  Also,\nrename 'internal_copy_pathspec()' to 'internal_prefix_pathspec()' to be\nmore descriptive of what the funciton is actually doing.\n\nIn addition to this, fix a memory leak caused by only duplicating some\nof the pathspec elements.  Instead always duplicate all of the the\npathspec elements as an intermediate step (with modificationed based on\nthe passed in flags).  This way the intermediate strings can then be\nfreed after getting the result from 'prefix_path()'.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n builtin/mv.c | 50 +++++++++++++++++++++++++++++++-------------------\n 1 file changed, 31 insertions(+), 19 deletions(-)\n\ndiff --git a/builtin/mv.c b/builtin/mv.c\nindex 2f43877..4e86dc5 100644\n--- a/builtin/mv.c\n+++ b/builtin/mv.c\n@@ -4,6 +4,7 @@\n  * Copyright (C) 2006 Johannes Schindelin\n  */\n #include \"builtin.h\"\n+#include \"pathspec.h\"\n #include \"lockfile.h\"\n #include \"dir.h\"\n #include \"cache-tree.h\"\n@@ -19,31 +20,42 @@ static const char * const builtin_mv_usage[] = {\n #define DUP_BASENAME 1\n #define KEEP_TRAILING_SLASH 2\n \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, unsigned flags)\n+static const char **internal_prefix_pathspec(const char *prefix,\n+\t\t\t\t\t     const char **pathspec,\n+\t\t\t\t\t     int count, unsigned flags)\n {\n \tint i;\n \tconst char **result;\n+\tint prefixlen = prefix ? strlen(prefix) : 0;\n \tALLOC_ARRAY(result, count + 1);\n-\tCOPY_ARRAY(result, pathspec, count);\n-\tresult[count] = NULL;\n+\n+\t/* Create an intermediate copy of the pathspec based on the flags */\n \tfor (i = 0; i < count; i++) {\n-\t\tint length = strlen(result[i]);\n+\t\tint length = strlen(pathspec[i]);\n \t\tint to_copy = length;\n+\t\tchar *it;\n \t\twhile (!(flags & KEEP_TRAILING_SLASH) &&\n-\t\t       to_copy > 0 && is_dir_sep(result[i][to_copy - 1]))\n+\t\t       to_copy > 0 && is_dir_sep(pathspec[i][to_copy - 1]))\n \t\t\tto_copy--;\n-\t\tif (to_copy != length || flags & DUP_BASENAME) {\n-\t\t\tchar *it = xmemdupz(result[i], to_copy);\n-\t\t\tif (flags & DUP_BASENAME) {\n-\t\t\t\tresult[i] = xstrdup(basename(it));\n-\t\t\t\tfree(it);\n-\t\t\t} else\n-\t\t\t\tresult[i] = it;\n+\n+\t\tit = xmemdupz(pathspec[i], to_copy);\n+\t\tif (flags & DUP_BASENAME) {\n+\t\t\tresult[i] = xstrdup(basename(it));\n+\t\t\tfree(it);\n+\t\t} else {\n+\t\t\tresult[i] = it;\n \t\t}\n \t}\n-\treturn get_pathspec(prefix, result);\n+\tresult[count] = NULL;\n+\n+\t/* Prefix the pathspec and free the old intermediate strings */\n+\tfor (i = 0; i < count; i++) {\n+\t\tconst char *match = prefix_path(prefix, prefixlen, result[i]);\n+\t\tfree((char *) result[i]);\n+\t\tresult[i] = match;\n+\t}\n+\n+\treturn result;\n }\n \n static const char *add_slash(const char *path)\n@@ -130,7 +142,7 @@ 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 = internal_copy_pathspec(prefix, argv, argc, 0);\n+\tsource = internal_prefix_pathspec(prefix, argv, argc, 0);\n \tmodes = xcalloc(argc, sizeof(enum update_mode));\n \t/*\n \t * Keep trailing slash, needed to let\n@@ -140,16 +152,16 @@ int cmd_mv(int argc, const char **argv, const char *prefix)\n \tflags = KEEP_TRAILING_SLASH;\n \tif (argc == 1 && is_directory(argv[0]) && !is_directory(argv[1]))\n \t\tflags = 0;\n-\tdest_path = internal_copy_pathspec(prefix, argv + argc, 1, flags);\n+\tdest_path = internal_prefix_pathspec(prefix, argv + argc, 1, flags);\n \tsubmodule_gitfile = xcalloc(argc, sizeof(char *));\n \n \tif (dest_path[0][0] == '\\0')\n \t\t/* special case: \".\" was normalized to \"\" */\n-\t\tdestination = internal_copy_pathspec(dest_path[0], argv, argc, DUP_BASENAME);\n+\t\tdestination = internal_prefix_pathspec(dest_path[0], argv, argc, DUP_BASENAME);\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 = internal_copy_pathspec(dest_path[0], argv, argc, DUP_BASENAME);\n+\t\tdestination = internal_prefix_pathspec(dest_path[0], argv, argc, DUP_BASENAME);\n \t} else {\n \t\tif (argc != 1)\n \t\t\tdie(_(\"destination '%s' is not a directory\"), dest_path[0]);\n-- \n2.8.0.rc3.226.g39d4020\n\n"},{"id":"307706","messageId":"1481670870-66754-10-git-send-email-bmwill@google.com","threadId":"44632","inReplyTo":"1481670870-66754-1-git-send-email-bmwill@google.com","subject":"[PATCH v3 09/16] pathspec: simpler logic to prefix original pathspec elements","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2016-12-13T23:14:23Z","receivedAt":"2016-12-13T23:17:11Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"The logic used to prefix an original pathspec element with 'prefix'\nmagic is more general purpose and can be used for more than just short\nmagic.  Remove the extra code paths and rename 'prefix_short_magic' to\n'prefix_magic' to better indicate that it can be used in more general\nsituations.\n\nAlso, slightly change the logic which decides when to prefix the\noriginal element in order to prevent a pathspec of \".\" from getting\nconverted to \"\" (empty string).\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n pathspec.c | 33 +++++++++++++--------------------\n 1 file changed, 13 insertions(+), 20 deletions(-)\n\ndiff --git a/pathspec.c b/pathspec.c\nindex 609c58f..d44f4b6 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -74,13 +74,12 @@ static struct pathspec_magic {\n \t{ PATHSPEC_EXCLUDE, '!', \"exclude\" },\n };\n \n-static void prefix_short_magic(struct strbuf *sb, int prefixlen,\n-\t\t\t       unsigned short_magic)\n+static void prefix_magic(struct strbuf *sb, int prefixlen, unsigned magic)\n {\n \tint i;\n \tstrbuf_addstr(sb, \":(\");\n \tfor (i = 0; i < ARRAY_SIZE(pathspec_magic); i++)\n-\t\tif (short_magic & pathspec_magic[i].bit) {\n+\t\tif (magic & pathspec_magic[i].bit) {\n \t\t\tif (sb->buf[sb->len - 1] != '(')\n \t\t\t\tstrbuf_addch(sb, ',');\n \t\t\tstrbuf_addstr(sb, pathspec_magic[i].name);\n@@ -109,8 +108,8 @@ static unsigned prefix_pathspec(struct pathspec_item *item, unsigned flags,\n \tstatic int glob_global = -1;\n \tstatic int noglob_global = -1;\n \tstatic int icase_global = -1;\n-\tunsigned magic = 0, short_magic = 0, global_magic = 0;\n-\tconst char *copyfrom = elt, *long_magic_end = NULL;\n+\tunsigned magic = 0, element_magic = 0, global_magic = 0;\n+\tconst char *copyfrom = elt;\n \tchar *match;\n \tint i, pathspec_prefix = -1;\n \n@@ -164,7 +163,7 @@ static unsigned prefix_pathspec(struct pathspec_item *item, unsigned flags,\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\telement_magic |= pathspec_magic[i].bit;\n \t\t\t\t\tbreak;\n \t\t\t\t}\n \t\t\t\tif (starts_with(copyfrom, \"prefix:\")) {\n@@ -183,7 +182,6 @@ static unsigned prefix_pathspec(struct pathspec_item *item, unsigned flags,\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@@ -196,7 +194,7 @@ static unsigned prefix_pathspec(struct pathspec_item *item, unsigned flags,\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\tshort_magic |= pathspec_magic[i].bit;\n+\t\t\t\t\telement_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@@ -207,7 +205,7 @@ static unsigned prefix_pathspec(struct pathspec_item *item, unsigned flags,\n \t\t\tcopyfrom++;\n \t}\n \n-\tmagic |= short_magic;\n+\tmagic |= element_magic;\n \n \t/* --noglob-pathspec adds :(literal) _unless_ :(glob) is specified */\n \tif (noglob_global && !(magic & PATHSPEC_GLOB))\n@@ -242,18 +240,13 @@ static unsigned prefix_pathspec(struct pathspec_item *item, unsigned flags,\n \t * Prefix the pathspec (keep all magic) and assign to\n \t * original. Useful for passing to another command.\n \t */\n-\tif (flags & PATHSPEC_PREFIX_ORIGIN) {\n+\tif ((flags & PATHSPEC_PREFIX_ORIGIN) &&\n+\t    prefixlen && !literal_global) {\n \t\tstruct strbuf sb = STRBUF_INIT;\n-\t\tif (prefixlen && !literal_global) {\n-\t\t\t/* Preserve the actual prefix length of each pattern */\n-\t\t\tif (short_magic)\n-\t\t\t\tprefix_short_magic(&sb, prefixlen, short_magic);\n-\t\t\telse if (long_magic_end) {\n-\t\t\t\tstrbuf_add(&sb, elt, long_magic_end - elt);\n-\t\t\t\tstrbuf_addf(&sb, \",prefix:%d)\", prefixlen);\n-\t\t\t} else\n-\t\t\t\tstrbuf_addf(&sb, \":(prefix:%d)\", prefixlen);\n-\t\t}\n+\n+\t\t/* Preserve the actual prefix length of each pattern */\n+\t\tprefix_magic(&sb, prefixlen, element_magic);\n+\n \t\tstrbuf_addstr(&sb, match);\n \t\titem->original = strbuf_detach(&sb, NULL);\n \t} else {\n-- \n2.8.0.rc3.226.g39d4020\n\n"},{"id":"307707","messageId":"1481670870-66754-6-git-send-email-bmwill@google.com","threadId":"44632","inReplyTo":"1481670870-66754-1-git-send-email-bmwill@google.com","subject":"[PATCH v3 05/16] pathspec: remove the deprecated get_pathspec function","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2016-12-13T23:14:19Z","receivedAt":"2016-12-13T23:17:16Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Now that all callers of the old 'get_pathspec' interface have been\nmigrated to use the new pathspec struct interface it can be removed\nfrom the codebase.\n\nSince there are no more users of the '_raw' field in the pathspec struct\nit can also be removed.  This patch also removes the old functionality\nof modifying the const char **argv array that was passed into\nparse_pathspec.  Instead the constructed 'match' string (which is a\npathspec element with the prefix prepended) is only stored in its\ncorresponding pathspec_item entry.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n Documentation/technical/api-setup.txt |  2 --\n cache.h                               |  1 -\n pathspec.c                            | 42 +++--------------------------------\n pathspec.h                            |  1 -\n 4 files changed, 3 insertions(+), 43 deletions(-)\n\ndiff --git a/Documentation/technical/api-setup.txt b/Documentation/technical/api-setup.txt\nindex 540e455..eb1fa98 100644\n--- a/Documentation/technical/api-setup.txt\n+++ b/Documentation/technical/api-setup.txt\n@@ -27,8 +27,6 @@ parse_pathspec(). This function takes several arguments:\n \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 them\n politely. At a lower level, different pathspec-related functions may\n not support the same set of features. Such pathspec-sensitive\ndiff --git a/cache.h b/cache.h\nindex a50a61a..0f80e01 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -514,7 +514,6 @@ extern void set_git_work_tree(const char *tree);\n \n #define ALTERNATE_DB_ENVIRONMENT \"GIT_ALTERNATE_OBJECT_DIRECTORIES\"\n \n-extern const char **get_pathspec(const char *prefix, const char **pathspec);\n extern void setup_work_tree(void);\n extern const char *setup_git_directory_gently(int *);\n extern const char *setup_git_directory(void);\ndiff --git a/pathspec.c b/pathspec.c\nindex 22ca74a..1f918cb 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -103,7 +103,7 @@ static void prefix_short_magic(struct strbuf *sb, int prefixlen,\n  */\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\tunsigned flags,\n \t\t\t\tconst char *prefix, int prefixlen,\n \t\t\t\tconst char *elt)\n {\n@@ -240,7 +240,7 @@ static unsigned prefix_pathspec(struct pathspec_item *item,\n \t\tif (!match)\n \t\t\tdie(_(\"%s: '%s' is outside repository\"), elt, copyfrom);\n \t}\n-\t*raw = item->match = match;\n+\titem->match = match;\n \t/*\n \t * Prefix the pathspec (keep all magic) and assign to\n \t * original. Useful for passing to another command.\n@@ -381,8 +381,6 @@ void parse_pathspec(struct pathspec *pathspec,\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@@ -394,10 +392,7 @@ void parse_pathspec(struct pathspec *pathspec,\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;\n-\t\tpathspec->_raw = raw;\n \t\treturn;\n \t}\n \n@@ -415,7 +410,6 @@ void parse_pathspec(struct pathspec *pathspec,\n \tpathspec->nr = n;\n \tALLOC_ARRAY(pathspec->items, n);\n \titem = pathspec->items;\n-\tpathspec->_raw = argv;\n \tprefixlen = prefix ? strlen(prefix) : 0;\n \n \tfor (i = 0; i < n; i++) {\n@@ -423,7 +417,7 @@ void parse_pathspec(struct pathspec *pathspec,\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\tflags,\n \t\t\t\t\t\tprefix, prefixlen, entry);\n \t\tif ((flags & PATHSPEC_LITERAL_PATH) &&\n \t\t    !(magic_mask & PATHSPEC_LITERAL))\n@@ -457,36 +451,6 @@ void parse_pathspec(struct pathspec *pathspec,\n \t}\n }\n \n-/*\n- * N.B. get_pathspec() is deprecated in favor of the \"struct pathspec\"\n- * based interface - see pathspec.c:parse_pathspec().\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-\tstruct pathspec ps;\n-\tparse_pathspec(&ps,\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;\n-}\n-\n void copy_pathspec(struct pathspec *dst, const struct pathspec *src)\n {\n \t*dst = *src;\ndiff --git a/pathspec.h b/pathspec.h\nindex 59809e4..70a592e 100644\n--- a/pathspec.h\n+++ b/pathspec.h\n@@ -19,7 +19,6 @@\n #define PATHSPEC_ONESTAR 1\t/* the pathspec pattern satisfies GFNM_ONESTAR */\n \n struct pathspec {\n-\tconst char **_raw; /* get_pathspec() result, not freed by clear_pathspec() */\n \tint nr;\n \tunsigned int has_wildcard:1;\n \tunsigned int recursive:1;\n-- \n2.8.0.rc3.226.g39d4020\n\n"},{"id":"307708","messageId":"1481670870-66754-14-git-send-email-bmwill@google.com","threadId":"44632","inReplyTo":"1481670870-66754-1-git-send-email-bmwill@google.com","subject":"[PATCH v3 13/16] pathspec: create parse_element_magic helper","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2016-12-13T23:14:27Z","receivedAt":"2016-12-13T23:21:10Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Factor out the logic responsible for the magic in a pathspec element\ninto its own function.\n\nAlso avoid calling into the parsing functions when\n`PATHSPEC_LITERAL_PATH` is specified since it causes magic to be\nignored and all paths to be treated as literals.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n pathspec.c | 37 ++++++++++++++++++++-----------------\n 1 file changed, 20 insertions(+), 17 deletions(-)\n\ndiff --git a/pathspec.c b/pathspec.c\nindex c77be17..a0fec49 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -245,6 +245,19 @@ static const char *parse_short_magic(unsigned *magic, const char *elem)\n \treturn pos;\n }\n \n+static const char *parse_element_magic(unsigned *magic, int *prefix_len,\n+\t\t\t\t       const char *elem)\n+{\n+\tif (elem[0] != ':' || get_literal_global())\n+\t\treturn elem; /* nothing to do */\n+\telse if (elem[1] == '(')\n+\t\t/* longhand */\n+\t\treturn parse_long_magic(magic, prefix_len, elem);\n+\telse\n+\t\t/* shorthand */\n+\t\treturn parse_short_magic(magic, elem);\n+}\n+\n /*\n  * Take an element of a pathspec and check for magic signatures.\n  * Append the result to the prefix. Return the magic bitmap.\n@@ -267,26 +280,16 @@ static unsigned prefix_pathspec(struct pathspec_item *item, unsigned flags,\n \tchar *match;\n \tint i, pathspec_prefix = -1;\n \n-\tif (elt[0] != ':' || get_literal_global() ||\n-\t    (flags & PATHSPEC_LITERAL_PATH)) {\n-\t\t; /* nothing to do */\n-\t} else if (elt[1] == '(') {\n-\t\t/* longhand */\n-\t\tcopyfrom = parse_long_magic(&element_magic,\n-\t\t\t\t\t    &pathspec_prefix,\n-\t\t\t\t\t    elt);\n-\t} else {\n-\t\t/* shorthand */\n-\t\tcopyfrom = parse_short_magic(&element_magic, elt);\n-\t}\n-\n-\tmagic |= element_magic;\n-\n \t/* PATHSPEC_LITERAL_PATH ignores magic */\n-\tif (flags & PATHSPEC_LITERAL_PATH)\n+\tif (flags & PATHSPEC_LITERAL_PATH) {\n \t\tmagic = PATHSPEC_LITERAL;\n-\telse\n+\t} else {\n+\t\tcopyfrom = parse_element_magic(&element_magic,\n+\t\t\t\t\t       &pathspec_prefix,\n+\t\t\t\t\t       elt);\n+\t\tmagic |= element_magic;\n \t\tmagic |= get_global_magic(element_magic);\n+\t}\n \n \tif (pathspec_prefix >= 0 &&\n \t    (prefixlen || (prefix && *prefix)))\n-- \n2.8.0.rc3.226.g39d4020\n\n"},{"id":"307709","messageId":"1481670870-66754-16-git-send-email-bmwill@google.com","threadId":"44632","inReplyTo":"1481670870-66754-1-git-send-email-bmwill@google.com","subject":"[PATCH v3 15/16] pathspec: small readability changes","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2016-12-13T23:14:29Z","receivedAt":"2016-12-13T23:21:38Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"A few small changes to improve readability.  This is done by grouping related\nassignments, adding blank lines, ensuring lines are <80 characters, and\nadding additional comments.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n pathspec.c | 25 +++++++++++++++----------\n 1 file changed, 15 insertions(+), 10 deletions(-)\n\ndiff --git a/pathspec.c b/pathspec.c\nindex 6fd4b8e..4ce2016 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -67,11 +67,11 @@ static struct pathspec_magic {\n \tchar mnemonic; /* this cannot be ':'! */\n \tconst char *name;\n } pathspec_magic[] = {\n-\t{ PATHSPEC_FROMTOP, '/', \"top\" },\n-\t{ PATHSPEC_LITERAL,   0, \"literal\" },\n-\t{ PATHSPEC_GLOB,   '\\0', \"glob\" },\n-\t{ PATHSPEC_ICASE,  '\\0', \"icase\" },\n-\t{ PATHSPEC_EXCLUDE, '!', \"exclude\" },\n+\t{ PATHSPEC_FROMTOP,  '/', \"top\" },\n+\t{ PATHSPEC_LITERAL, '\\0', \"literal\" },\n+\t{ PATHSPEC_GLOB,    '\\0', \"glob\" },\n+\t{ PATHSPEC_ICASE,   '\\0', \"icase\" },\n+\t{ PATHSPEC_EXCLUDE,  '!', \"exclude\" },\n };\n \n static void prefix_magic(struct strbuf *sb, int prefixlen, unsigned magic)\n@@ -336,6 +336,7 @@ static unsigned prefix_pathspec(struct pathspec_item *item, unsigned flags,\n \tif ((magic & PATHSPEC_LITERAL) && (magic & PATHSPEC_GLOB))\n \t\tdie(_(\"%s: 'literal' and 'glob' are incompatible\"), elt);\n \n+\t/* Create match string which will be used for pathspec matching */\n \tif (pathspec_prefix >= 0) {\n \t\tmatch = xstrdup(copyfrom);\n \t\tprefixlen = pathspec_prefix;\n@@ -343,11 +344,16 @@ static unsigned prefix_pathspec(struct pathspec_item *item, unsigned flags,\n \t\tmatch = xstrdup(copyfrom);\n \t\tprefixlen = 0;\n \t} else {\n-\t\tmatch = prefix_path_gently(prefix, prefixlen, &prefixlen, copyfrom);\n+\t\tmatch = prefix_path_gently(prefix, prefixlen,\n+\t\t\t\t\t   &prefixlen, copyfrom);\n \t\tif (!match)\n \t\t\tdie(_(\"%s: '%s' is outside repository\"), elt, copyfrom);\n \t}\n+\n \titem->match = match;\n+\titem->len = strlen(item->match);\n+\titem->prefix = prefixlen;\n+\n \t/*\n \t * Prefix the pathspec (keep all magic) and assign to\n \t * original. Useful for passing to another command.\n@@ -364,8 +370,6 @@ static unsigned prefix_pathspec(struct pathspec_item *item, unsigned flags,\n \t} else {\n \t\titem->original = xstrdup(elt);\n \t}\n-\titem->len = strlen(item->match);\n-\titem->prefix = prefixlen;\n \n \tif (flags & PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP)\n \t\tstrip_submodule_slash_cheap(item);\n@@ -373,13 +377,14 @@ static unsigned prefix_pathspec(struct pathspec_item *item, unsigned flags,\n \tif (flags & PATHSPEC_STRIP_SUBMODULE_SLASH_EXPENSIVE)\n \t\tstrip_submodule_slash_expensive(item);\n \n-\tif (magic & PATHSPEC_LITERAL)\n+\tif (magic & PATHSPEC_LITERAL) {\n \t\titem->nowildcard_len = item->len;\n-\telse {\n+\t} else {\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+\n \titem->flags = 0;\n \tif (magic & PATHSPEC_GLOB) {\n \t\t/*\n-- \n2.8.0.rc3.226.g39d4020\n\n"},{"id":"307710","messageId":"1481670870-66754-15-git-send-email-bmwill@google.com","threadId":"44632","inReplyTo":"1481670870-66754-1-git-send-email-bmwill@google.com","subject":"[PATCH v3 14/16] pathspec: create strip submodule slash helpers","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2016-12-13T23:14:28Z","receivedAt":"2016-12-13T23:22:03Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Factor out the logic responsible for stripping the trailing slash on\npathspecs referencing submodules into its own function.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n pathspec.c | 68 ++++++++++++++++++++++++++++++++++++++------------------------\n 1 file changed, 42 insertions(+), 26 deletions(-)\n\ndiff --git a/pathspec.c b/pathspec.c\nindex a0fec49..6fd4b8e 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -258,6 +258,44 @@ static const char *parse_element_magic(unsigned *magic, int *prefix_len,\n \t\treturn parse_short_magic(magic, elem);\n }\n \n+static void strip_submodule_slash_cheap(struct pathspec_item *item)\n+{\n+\tif (item->len >= 1 && item->match[item->len - 1] == '/') {\n+\t\tint i = cache_name_pos(item->match, item->len - 1);\n+\n+\t\tif (i >= 0 && S_ISGITLINK(active_cache[i]->ce_mode)) {\n+\t\t\titem->len--;\n+\t\t\titem->match[item->len] = '\\0';\n+\t\t}\n+\t}\n+}\n+\n+static void strip_submodule_slash_expensive(struct pathspec_item *item)\n+{\n+\tint i;\n+\n+\tfor (i = 0; i < active_nr; i++) {\n+\t\tstruct cache_entry *ce = active_cache[i];\n+\t\tint ce_len = ce_namelen(ce);\n+\n+\t\tif (!S_ISGITLINK(ce->ce_mode))\n+\t\t\tcontinue;\n+\n+\t\tif (item->len <= ce_len || item->match[ce_len] != '/' ||\n+\t\t    memcmp(ce->name, item->match, ce_len))\n+\t\t\tcontinue;\n+\n+\t\tif (item->len == ce_len + 1) {\n+\t\t\t/* strip trailing slash */\n+\t\t\titem->len--;\n+\t\t\titem->match[item->len] = '\\0';\n+\t\t} else {\n+\t\t\tdie(_(\"Pathspec '%s' is in submodule '%.*s'\"),\n+\t\t\t    item->original, ce_len, ce->name);\n+\t\t}\n+\t}\n+}\n+\n /*\n  * Take an element of a pathspec and check for magic signatures.\n  * Append the result to the prefix. Return the magic bitmap.\n@@ -278,7 +316,7 @@ static unsigned prefix_pathspec(struct pathspec_item *item, unsigned flags,\n \tunsigned magic = 0, element_magic = 0;\n \tconst char *copyfrom = elt;\n \tchar *match;\n-\tint i, pathspec_prefix = -1;\n+\tint pathspec_prefix = -1;\n \n \t/* PATHSPEC_LITERAL_PATH ignores magic */\n \tif (flags & PATHSPEC_LITERAL_PATH) {\n@@ -329,33 +367,11 @@ static unsigned prefix_pathspec(struct pathspec_item *item, unsigned flags,\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-\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+\tif (flags & PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP)\n+\t\tstrip_submodule_slash_cheap(item);\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+\t\tstrip_submodule_slash_expensive(item);\n \n \tif (magic & PATHSPEC_LITERAL)\n \t\titem->nowildcard_len = item->len;\n-- \n2.8.0.rc3.226.g39d4020\n\n"},{"id":"307711","messageId":"1481670870-66754-13-git-send-email-bmwill@google.com","threadId":"44632","inReplyTo":"1481670870-66754-1-git-send-email-bmwill@google.com","subject":"[PATCH v3 12/16] pathspec: create parse_long_magic function","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2016-12-13T23:14:26Z","receivedAt":"2016-12-13T23:22:08Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Factor out the logic responsible for parsing long magic into its own\nfunction.  As well as hoist the prefix check logic outside of the inner\nloop as there isn't anything that needs to be done after matching\n\"prefix:\".\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n pathspec.c | 92 ++++++++++++++++++++++++++++++++++++++------------------------\n 1 file changed, 57 insertions(+), 35 deletions(-)\n\ndiff --git a/pathspec.c b/pathspec.c\nindex 94ec201..c77be17 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -157,6 +157,60 @@ static int get_global_magic(int element_magic)\n }\n \n /*\n+ * Parse the pathspec element looking for long magic\n+ *\n+ * saves all magic in 'magic'\n+ * if prefix magic is used, save the prefix length in 'prefix_len'\n+ * returns the position in 'elem' after all magic has been parsed\n+ */\n+static const char *parse_long_magic(unsigned *magic, int *prefix_len,\n+\t\t\t\t    const char *elem)\n+{\n+\tconst char *pos;\n+\tconst char *nextat;\n+\n+\tfor (pos = elem + 2; *pos && *pos != ')'; pos = nextat) {\n+\t\tsize_t len = strcspn(pos, \",)\");\n+\t\tint i;\n+\n+\t\tif (pos[len] == ',')\n+\t\t\tnextat = pos + len + 1; /* handle ',' */\n+\t\telse\n+\t\t\tnextat = pos + len; /* handle ')' and '\\0' */\n+\n+\t\tif (!len)\n+\t\t\tcontinue;\n+\n+\t\tif (starts_with(pos, \"prefix:\")) {\n+\t\t\tchar *endptr;\n+\t\t\t*prefix_len = strtol(pos + 7, &endptr, 10);\n+\t\t\tif (endptr - pos != len)\n+\t\t\t\tdie(_(\"invalid parameter for pathspec magic 'prefix'\"));\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\tfor (i = 0; i < ARRAY_SIZE(pathspec_magic); i++) {\n+\t\t\tif (strlen(pathspec_magic[i].name) == len &&\n+\t\t\t    !strncmp(pathspec_magic[i].name, pos, len)) {\n+\t\t\t\t*magic |= pathspec_magic[i].bit;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t}\n+\n+\t\tif (ARRAY_SIZE(pathspec_magic) <= i)\n+\t\t\tdie(_(\"Invalid pathspec magic '%.*s' in '%s'\"),\n+\t\t\t    (int) len, pos, elem);\n+\t}\n+\n+\tif (*pos != ')')\n+\t\tdie(_(\"Missing ')' at the end of pathspec magic in '%s'\"),\n+\t\t    elem);\n+\tpos++;\n+\n+\treturn pos;\n+}\n+\n+/*\n  * Parse the pathspec element looking for short magic\n  *\n  * saves all magic in 'magic'\n@@ -218,41 +272,9 @@ static unsigned prefix_pathspec(struct pathspec_item *item, unsigned flags,\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 + 1;\n-\t\t\telse\n-\t\t\t\t/* handle ')' and '\\0' */\n-\t\t\t\tnextat = copyfrom + len;\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\telement_magic |= pathspec_magic[i].bit;\n-\t\t\t\t\tbreak;\n-\t\t\t\t}\n-\t\t\t\tif (starts_with(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\tcopyfrom++;\n+\t\tcopyfrom = parse_long_magic(&element_magic,\n+\t\t\t\t\t    &pathspec_prefix,\n+\t\t\t\t\t    elt);\n \t} else {\n \t\t/* shorthand */\n \t\tcopyfrom = parse_short_magic(&element_magic, elt);\n-- \n2.8.0.rc3.226.g39d4020\n\n"},{"id":"307712","messageId":"1481670870-66754-17-git-send-email-bmwill@google.com","threadId":"44632","inReplyTo":"1481670870-66754-1-git-send-email-bmwill@google.com","subject":"[PATCH v3 16/16] pathspec: rename prefix_pathspec to init_pathspec_item","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2016-12-13T23:14:30Z","receivedAt":"2016-12-13T23:23:12Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Give a more relevant name to the prefix_pathspec function as it does\nmore than just prefix a pathspec element.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n pathspec.c | 24 +++++++-----------------\n 1 file changed, 7 insertions(+), 17 deletions(-)\n\ndiff --git a/pathspec.c b/pathspec.c\nindex 4ce2016..d4efcf6 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -297,21 +297,11 @@ static void strip_submodule_slash_expensive(struct pathspec_item *item)\n }\n \n /*\n- * Take an element of a pathspec and check for magic signatures.\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- *\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+ * Perform the initialization of a pathspec_item based on a pathspec element.\n  */\n-static unsigned prefix_pathspec(struct pathspec_item *item, unsigned flags,\n-\t\t\t\tconst char *prefix, int prefixlen,\n-\t\t\t\tconst char *elt)\n+static void init_pathspec_item(struct pathspec_item *item, unsigned flags,\n+\t\t\t       const char *prefix, int prefixlen,\n+\t\t\t       const char *elt)\n {\n \tunsigned magic = 0, element_magic = 0;\n \tconst char *copyfrom = elt;\n@@ -329,6 +319,8 @@ static unsigned prefix_pathspec(struct pathspec_item *item, unsigned flags,\n \t\tmagic |= get_global_magic(element_magic);\n \t}\n \n+\titem->magic = 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@@ -401,7 +393,6 @@ static unsigned prefix_pathspec(struct pathspec_item *item, unsigned flags,\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 static int pathspec_item_cmp(const void *a_, const void *b_)\n@@ -500,8 +491,7 @@ void parse_pathspec(struct pathspec *pathspec,\n \tfor (i = 0; i < n; i++) {\n \t\tentry = argv[i];\n \n-\t\titem[i].magic = prefix_pathspec(item + i, flags,\n-\t\t\t\t\t\tprefix, prefixlen, entry);\n+\t\tinit_pathspec_item(item + i, flags, prefix, prefixlen, entry);\n \n \t\tif (item[i].magic & PATHSPEC_EXCLUDE)\n \t\t\tnr_exclude++;\n-- \n2.8.0.rc3.226.g39d4020\n\n"},{"id":"307713","messageId":"1481670870-66754-12-git-send-email-bmwill@google.com","threadId":"44632","inReplyTo":"1481670870-66754-1-git-send-email-bmwill@google.com","subject":"[PATCH v3 11/16] pathspec: create parse_short_magic function","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2016-12-13T23:14:25Z","receivedAt":"2016-12-13T23:23:56Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Factor out the logic responsible for parsing short magic into its own\nfunction.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n pathspec.c | 54 ++++++++++++++++++++++++++++++++++++------------------\n 1 file changed, 36 insertions(+), 18 deletions(-)\n\ndiff --git a/pathspec.c b/pathspec.c\nindex 10ce9c1..94ec201 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -157,6 +157,41 @@ static int get_global_magic(int element_magic)\n }\n \n /*\n+ * Parse the pathspec element looking for short magic\n+ *\n+ * saves all magic in 'magic'\n+ * returns the position in 'elem' after all magic has been parsed\n+ */\n+static const char *parse_short_magic(unsigned *magic, const char *elem)\n+{\n+\tconst char *pos;\n+\n+\tfor (pos = elem + 1; *pos && *pos != ':'; pos++) {\n+\t\tchar ch = *pos;\n+\t\tint i;\n+\n+\t\tif (!is_pathspec_magic(ch))\n+\t\t\tbreak;\n+\n+\t\tfor (i = 0; i < ARRAY_SIZE(pathspec_magic); i++) {\n+\t\t\tif (pathspec_magic[i].mnemonic == ch) {\n+\t\t\t\t*magic |= pathspec_magic[i].bit;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t}\n+\n+\t\tif (ARRAY_SIZE(pathspec_magic) <= i)\n+\t\t\tdie(_(\"Unimplemented pathspec magic '%c' in '%s'\"),\n+\t\t\t    ch, elem);\n+\t}\n+\n+\tif (*pos == ':')\n+\t\tpos++;\n+\n+\treturn pos;\n+}\n+\n+/*\n  * Take an element of a pathspec and check for magic signatures.\n  * Append the result to the prefix. Return the magic bitmap.\n  *\n@@ -220,24 +255,7 @@ static unsigned prefix_pathspec(struct pathspec_item *item, unsigned flags,\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\telement_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-\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\tcopyfrom = parse_short_magic(&element_magic, elt);\n \t}\n \n \tmagic |= element_magic;\n-- \n2.8.0.rc3.226.g39d4020\n\n"},{"id":"307714","messageId":"1481670870-66754-11-git-send-email-bmwill@google.com","threadId":"44632","inReplyTo":"1481670870-66754-1-git-send-email-bmwill@google.com","subject":"[PATCH v3 10/16] pathspec: factor global magic into its own function","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2016-12-13T23:14:24Z","receivedAt":"2016-12-13T23:24:22Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Create helper functions to read the global magic environment variables\nin additon to factoring out the global magic gathering logic into its\nown function.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n pathspec.c | 127 +++++++++++++++++++++++++++++++++++++------------------------\n 1 file changed, 78 insertions(+), 49 deletions(-)\n\ndiff --git a/pathspec.c b/pathspec.c\nindex d44f4b6..10ce9c1 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -87,6 +87,75 @@ static void prefix_magic(struct strbuf *sb, int prefixlen, unsigned magic)\n \tstrbuf_addf(sb, \",prefix:%d)\", prefixlen);\n }\n \n+static inline int get_literal_global(void)\n+{\n+\tstatic int literal = -1;\n+\n+\tif (literal < 0)\n+\t\tliteral = git_env_bool(GIT_LITERAL_PATHSPECS_ENVIRONMENT, 0);\n+\n+\treturn literal;\n+}\n+\n+static inline int get_glob_global(void)\n+{\n+\tstatic int glob = -1;\n+\n+\tif (glob < 0)\n+\t\tglob = git_env_bool(GIT_GLOB_PATHSPECS_ENVIRONMENT, 0);\n+\n+\treturn glob;\n+}\n+\n+static inline int get_noglob_global(void)\n+{\n+\tstatic int noglob = -1;\n+\n+\tif (noglob < 0)\n+\t\tnoglob = git_env_bool(GIT_NOGLOB_PATHSPECS_ENVIRONMENT, 0);\n+\n+\treturn noglob;\n+}\n+\n+static inline int get_icase_global(void)\n+{\n+\tstatic int icase = -1;\n+\n+\tif (icase < 0)\n+\t\ticase = git_env_bool(GIT_ICASE_PATHSPECS_ENVIRONMENT, 0);\n+\n+\treturn icase;\n+}\n+\n+static int get_global_magic(int element_magic)\n+{\n+\tint global_magic = 0;\n+\n+\tif (get_literal_global())\n+\t\tglobal_magic |= PATHSPEC_LITERAL;\n+\n+\t/* --glob-pathspec is overridden by :(literal) */\n+\tif (get_glob_global() && !(element_magic & PATHSPEC_LITERAL))\n+\t\tglobal_magic |= PATHSPEC_GLOB;\n+\n+\tif (get_glob_global() && get_noglob_global())\n+\t\tdie(_(\"global 'glob' and 'noglob' pathspec settings are incompatible\"));\n+\n+\tif (get_icase_global())\n+\t\tglobal_magic |= PATHSPEC_ICASE;\n+\n+\tif ((global_magic & PATHSPEC_LITERAL) &&\n+\t    (global_magic & ~PATHSPEC_LITERAL))\n+\t\tdie(_(\"global 'literal' pathspec setting is incompatible \"\n+\t\t      \"with all other global pathspec settings\"));\n+\n+\t/* --noglob-pathspec adds :(literal) _unless_ :(glob) is specified */\n+\tif (get_noglob_global() && !(element_magic & PATHSPEC_GLOB))\n+\t\tglobal_magic |= PATHSPEC_LITERAL;\n+\n+\treturn global_magic;\n+}\n+\n /*\n  * Take an element of a pathspec and check for magic signatures.\n  * Append the result to the prefix. Return the magic bitmap.\n@@ -104,46 +173,12 @@ static unsigned prefix_pathspec(struct pathspec_item *item, unsigned flags,\n \t\t\t\tconst char *prefix, int prefixlen,\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-\tstatic int icase_global = -1;\n-\tunsigned magic = 0, element_magic = 0, global_magic = 0;\n+\tunsigned magic = 0, element_magic = 0;\n \tconst char *copyfrom = elt;\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 (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-\n-\tif (icase_global < 0)\n-\t\ticase_global = git_env_bool(GIT_ICASE_PATHSPECS_ENVIRONMENT, 0);\n-\tif (icase_global)\n-\t\tglobal_magic |= PATHSPEC_ICASE;\n-\n-\tif ((global_magic & PATHSPEC_LITERAL) &&\n-\t    (global_magic & ~PATHSPEC_LITERAL))\n-\t\tdie(_(\"global 'literal' pathspec setting is incompatible \"\n-\t\t      \"with all other global pathspec settings\"));\n-\n-\tif (flags & PATHSPEC_LITERAL_PATH)\n-\t\tglobal_magic = 0;\n-\n-\tif (elt[0] != ':' || literal_global ||\n+\tif (elt[0] != ':' || get_literal_global() ||\n \t    (flags & PATHSPEC_LITERAL_PATH)) {\n \t\t; /* nothing to do */\n \t} else if (elt[1] == '(') {\n@@ -207,15 +242,11 @@ static unsigned prefix_pathspec(struct pathspec_item *item, unsigned flags,\n \n \tmagic |= element_magic;\n \n-\t/* --noglob-pathspec adds :(literal) _unless_ :(glob) is specified */\n-\tif (noglob_global && !(magic & PATHSPEC_GLOB))\n-\t\tglobal_magic |= PATHSPEC_LITERAL;\n-\n-\t/* --glob-pathspec is overridden by :(literal) */\n-\tif ((global_magic & PATHSPEC_GLOB) && (magic & PATHSPEC_LITERAL))\n-\t\tglobal_magic &= ~PATHSPEC_GLOB;\n-\n-\tmagic |= global_magic;\n+\t/* PATHSPEC_LITERAL_PATH ignores magic */\n+\tif (flags & PATHSPEC_LITERAL_PATH)\n+\t\tmagic = PATHSPEC_LITERAL;\n+\telse\n+\t\tmagic |= get_global_magic(element_magic);\n \n \tif (pathspec_prefix >= 0 &&\n \t    (prefixlen || (prefix && *prefix)))\n@@ -241,7 +272,7 @@ static unsigned prefix_pathspec(struct pathspec_item *item, unsigned flags,\n \t * original. Useful for passing to another command.\n \t */\n \tif ((flags & PATHSPEC_PREFIX_ORIGIN) &&\n-\t    prefixlen && !literal_global) {\n+\t    prefixlen && !get_literal_global()) {\n \t\tstruct strbuf sb = STRBUF_INIT;\n \n \t\t/* Preserve the actual prefix length of each pattern */\n@@ -407,9 +438,7 @@ void parse_pathspec(struct pathspec *pathspec,\n \n \t\titem[i].magic = prefix_pathspec(item + i, flags,\n \t\t\t\t\t\tprefix, prefixlen, entry);\n-\t\tif ((flags & PATHSPEC_LITERAL_PATH) &&\n-\t\t    !(magic_mask & PATHSPEC_LITERAL))\n-\t\t\titem[i].magic |= PATHSPEC_LITERAL;\n+\n \t\tif (item[i].magic & PATHSPEC_EXCLUDE)\n \t\t\tnr_exclude++;\n \t\tif (item[i].magic & magic_mask)\n-- \n2.8.0.rc3.226.g39d4020\n\n"},{"id":"308064","messageId":"CAGZ79kYNhz6mSqa0vtjCOcRWydgXGdgXZW6BsAHheTnWUaJMuQ@mail.gmail.com","threadId":"44632","inReplyTo":"1481670870-66754-3-git-send-email-bmwill@google.com","subject":"Re: [PATCH v3 02/16] dir: remove struct path_simplify","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2016-12-19T17:33:03Z","receivedAt":"2016-12-19T17:34:04Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"On Tue, Dec 13, 2016 at 3:14 PM, Brandon Williams <bmwill@google.com> wrote:\n> Teach simplify_away() and exclude_matches_pathspec() to handle struct\n> pathspec directly, eliminating the need for the struct path_simplify.\n>\n> Also renamed the len parameter to pathlen in exclude_matches_pathspec()\n> to match the parameter names used in simplify_away().\n>\n> Signed-off-by: Brandon Williams <bmwill@google.com>\n\nLooks good to me,\n\nThanks,\nStefan\n"},{"id":"308697","messageId":"CACsJy8AaRqJ4jaZ19__kFR+pXtjJ4o_Jik8NL_Mk5yaA4aGRBQ@mail.gmail.com","threadId":"44632","inReplyTo":"1481670870-66754-3-git-send-email-bmwill@google.com","subject":"Re: [PATCH v3 02/16] dir: remove struct path_simplify","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2017-01-03T12:02:41Z","receivedAt":"2017-01-03T12:03:18Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Wed, Dec 14, 2016 at 6:14 AM, Brandon Williams <bmwill@google.com> wrote:\n> @@ -2010,14 +1987,11 @@ static struct untracked_cache_dir *validate_untracked_cache(struct dir_struct *d\n>         return root;\n>  }\n>\n> -int read_directory(struct dir_struct *dir, const char *path, int len, const struct pathspec *pathspec)\n> +int read_directory(struct dir_struct *dir, const char *path,\n> +                  int len, const struct pathspec *pathspec)\n>  {\n> -       struct path_simplify *simplify;\n>         struct untracked_cache_dir *untracked;\n>\n> -       /*\n> -        * Check out create_simplify()\n> -        */\n>         if (pathspec)\n>                 GUARD_PATHSPEC(pathspec,\n>                                PATHSPEC_FROMTOP |\n\n\nThis GUARD_PATHSPEC macro should be moved into simplify_away() and\nexclude_pathspec_matches(), so that next time somebody adds a new\npathspec magic, they can basically grep GUARD_PATHSPEC and determine\nif these code can support their favorite magic or not.\n-- \nDuy\n"},{"id":"308698","messageId":"CACsJy8BnzE0Dis19RCddeFGhn-9Lm8R38NqN4T4qhHi1dRA8FQ@mail.gmail.com","threadId":"44632","inReplyTo":"1481670870-66754-7-git-send-email-bmwill@google.com","subject":"Re: [PATCH v3 06/16] pathspec: copy and free owned memory","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2017-01-03T12:06:22Z","receivedAt":"2017-01-03T12:07:10Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Wed, Dec 14, 2016 at 6:14 AM, Brandon Williams <bmwill@google.com> wrote:\n>  void clear_pathspec(struct pathspec *pathspec)\n>  {\n> +       int i;\n> +\n> +       for (i = 0; i < pathspec->nr; i++) {\n> +               free(pathspec->items[i].match);\n> +               free(pathspec->items[i].original);\n> +       }\n>         free(pathspec->items);\n>         pathspec->items = NULL;\n\nWe should set pathspec->nr to zero so that calling this function again\nwon't cause any harm.\n\n>  }\n-- \nDuy\n"},{"id":"308699","messageId":"CACsJy8Cja1um2oFDWufyk_7xaZbf9+=kyuWFx==Vb0nHiMqiwA@mail.gmail.com","threadId":"44632","inReplyTo":"1481670870-66754-9-git-send-email-bmwill@google.com","subject":"Re: [PATCH v3 08/16] pathspec: always show mnemonic and name in unsupported_magic","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2017-01-03T12:14:25Z","receivedAt":"2017-01-03T12:15:00Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Wed, Dec 14, 2016 at 6:14 AM, Brandon Williams <bmwill@google.com> wrote:\n> @@ -340,8 +336,9 @@ static void NORETURN unsupported_magic(const char *pattern,\n>                         continue;\n>                 if (sb.len)\n>                         strbuf_addch(&sb, ' ');\n> -               if (short_magic & m->bit)\n> -                       strbuf_addf(&sb, \"'%c'\", m->mnemonic);\n> +\n> +               if (m->mnemonic)\n> +                       strbuf_addf(&sb, \"'(%c)%s'\", m->mnemonic, m->name);\n>                 else\n>                         strbuf_addf(&sb, \"'%s'\", m->name);\n>         }\n\nThe die() call is out of diff context, but it'll print\n\npathspec magic not supported by this command: (!)top\n\nwhich looks too much like :(<name>)<mnemonic> pathspec syntax too me\nand threw me off a bit. And it's a bit cryptic, isn't it? Since this\nis meant for human, maybe we can just write\n\npathspec magic not supported by this command: top (mnemonic: '!')\n-- \nDuy\n"},{"id":"308709","messageId":"20170103181525.GB42671@google.com","threadId":"44632","inReplyTo":"CACsJy8Cja1um2oFDWufyk_7xaZbf9+=kyuWFx==Vb0nHiMqiwA@mail.gmail.com","subject":"Re: [PATCH v3 08/16] pathspec: always show mnemonic and name in unsupported_magic","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-01-03T18:15:25Z","receivedAt":"2017-01-03T18:15:33Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"On 01/03, Duy Nguyen wrote:\n> On Wed, Dec 14, 2016 at 6:14 AM, Brandon Williams <bmwill@google.com> wrote:\n> > @@ -340,8 +336,9 @@ static void NORETURN unsupported_magic(const char *pattern,\n> >                         continue;\n> >                 if (sb.len)\n> >                         strbuf_addch(&sb, ' ');\n> > -               if (short_magic & m->bit)\n> > -                       strbuf_addf(&sb, \"'%c'\", m->mnemonic);\n> > +\n> > +               if (m->mnemonic)\n> > +                       strbuf_addf(&sb, \"'(%c)%s'\", m->mnemonic, m->name);\n> >                 else\n> >                         strbuf_addf(&sb, \"'%s'\", m->name);\n> >         }\n> \n> The die() call is out of diff context, but it'll print\n> \n> pathspec magic not supported by this command: (!)top\n> \n> which looks too much like :(<name>)<mnemonic> pathspec syntax too me\n> and threw me off a bit. And it's a bit cryptic, isn't it? Since this\n> is meant for human, maybe we can just write\n> \n> pathspec magic not supported by this command: top (mnemonic: '!')\n\nI was trying to keep it short and sweet, turns out that ends up being\nmore difficult to understand.  I like your suggestion, it definitely\nmakes things much clearer.\n\n-- \nBrandon Williams\n"},{"id":"308713","messageId":"20170103184241.128409-4-bmwill@google.com","threadId":"44632","inReplyTo":"20170103184241.128409-1-bmwill@google.com","subject":"[PATCH v4 03/16] dir: convert fill_directory to use the pathspec struct interface","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-01-03T18:42:28Z","receivedAt":"2017-01-03T18:49:14Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Convert 'fill_directory()' to use the pathspec struct interface from\nusing the '_raw' entry in the pathspec struct.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n dir.c | 12 ++++++++----\n 1 file changed, 8 insertions(+), 4 deletions(-)\n\ndiff --git a/dir.c b/dir.c\nindex 1df61f10f..e8ddd7f8a 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -174,17 +174,21 @@ char *common_prefix(const struct pathspec *pathspec)\n \n int fill_directory(struct dir_struct *dir, const struct pathspec *pathspec)\n {\n-\tsize_t len;\n+\tchar *prefix;\n+\tsize_t prefix_len;\n \n \t/*\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+\tprefix = common_prefix(pathspec);\n+\tprefix_len = prefix ? strlen(prefix) : 0;\n \n \t/* Read the directory and prune it */\n-\tread_directory(dir, pathspec->nr ? pathspec->_raw[0] : \"\", len, pathspec);\n-\treturn len;\n+\tread_directory(dir, prefix, prefix_len, pathspec);\n+\n+\tfree(prefix);\n+\treturn prefix_len;\n }\n \n int within_depth(const char *name, int namelen,\n-- \n2.11.0.390.gc69c2f50cf-goog\n\n"},{"id":"308714","messageId":"20170103184241.128409-11-bmwill@google.com","threadId":"44632","inReplyTo":"20170103184241.128409-1-bmwill@google.com","subject":"[PATCH v4 10/16] pathspec: factor global magic into its own function","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-01-03T18:42:35Z","receivedAt":"2017-01-03T18:49:29Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Create helper functions to read the global magic environment variables\nin additon to factoring out the global magic gathering logic into its\nown function.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n pathspec.c | 127 +++++++++++++++++++++++++++++++++++++------------------------\n 1 file changed, 78 insertions(+), 49 deletions(-)\n\ndiff --git a/pathspec.c b/pathspec.c\nindex 032436bc1..f760f44f9 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -87,6 +87,75 @@ static void prefix_magic(struct strbuf *sb, int prefixlen, unsigned magic)\n \tstrbuf_addf(sb, \",prefix:%d)\", prefixlen);\n }\n \n+static inline int get_literal_global(void)\n+{\n+\tstatic int literal = -1;\n+\n+\tif (literal < 0)\n+\t\tliteral = git_env_bool(GIT_LITERAL_PATHSPECS_ENVIRONMENT, 0);\n+\n+\treturn literal;\n+}\n+\n+static inline int get_glob_global(void)\n+{\n+\tstatic int glob = -1;\n+\n+\tif (glob < 0)\n+\t\tglob = git_env_bool(GIT_GLOB_PATHSPECS_ENVIRONMENT, 0);\n+\n+\treturn glob;\n+}\n+\n+static inline int get_noglob_global(void)\n+{\n+\tstatic int noglob = -1;\n+\n+\tif (noglob < 0)\n+\t\tnoglob = git_env_bool(GIT_NOGLOB_PATHSPECS_ENVIRONMENT, 0);\n+\n+\treturn noglob;\n+}\n+\n+static inline int get_icase_global(void)\n+{\n+\tstatic int icase = -1;\n+\n+\tif (icase < 0)\n+\t\ticase = git_env_bool(GIT_ICASE_PATHSPECS_ENVIRONMENT, 0);\n+\n+\treturn icase;\n+}\n+\n+static int get_global_magic(int element_magic)\n+{\n+\tint global_magic = 0;\n+\n+\tif (get_literal_global())\n+\t\tglobal_magic |= PATHSPEC_LITERAL;\n+\n+\t/* --glob-pathspec is overridden by :(literal) */\n+\tif (get_glob_global() && !(element_magic & PATHSPEC_LITERAL))\n+\t\tglobal_magic |= PATHSPEC_GLOB;\n+\n+\tif (get_glob_global() && get_noglob_global())\n+\t\tdie(_(\"global 'glob' and 'noglob' pathspec settings are incompatible\"));\n+\n+\tif (get_icase_global())\n+\t\tglobal_magic |= PATHSPEC_ICASE;\n+\n+\tif ((global_magic & PATHSPEC_LITERAL) &&\n+\t    (global_magic & ~PATHSPEC_LITERAL))\n+\t\tdie(_(\"global 'literal' pathspec setting is incompatible \"\n+\t\t      \"with all other global pathspec settings\"));\n+\n+\t/* --noglob-pathspec adds :(literal) _unless_ :(glob) is specified */\n+\tif (get_noglob_global() && !(element_magic & PATHSPEC_GLOB))\n+\t\tglobal_magic |= PATHSPEC_LITERAL;\n+\n+\treturn global_magic;\n+}\n+\n /*\n  * Take an element of a pathspec and check for magic signatures.\n  * Append the result to the prefix. Return the magic bitmap.\n@@ -104,46 +173,12 @@ static unsigned prefix_pathspec(struct pathspec_item *item, unsigned flags,\n \t\t\t\tconst char *prefix, int prefixlen,\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-\tstatic int icase_global = -1;\n-\tunsigned magic = 0, element_magic = 0, global_magic = 0;\n+\tunsigned magic = 0, element_magic = 0;\n \tconst char *copyfrom = elt;\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 (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-\n-\tif (icase_global < 0)\n-\t\ticase_global = git_env_bool(GIT_ICASE_PATHSPECS_ENVIRONMENT, 0);\n-\tif (icase_global)\n-\t\tglobal_magic |= PATHSPEC_ICASE;\n-\n-\tif ((global_magic & PATHSPEC_LITERAL) &&\n-\t    (global_magic & ~PATHSPEC_LITERAL))\n-\t\tdie(_(\"global 'literal' pathspec setting is incompatible \"\n-\t\t      \"with all other global pathspec settings\"));\n-\n-\tif (flags & PATHSPEC_LITERAL_PATH)\n-\t\tglobal_magic = 0;\n-\n-\tif (elt[0] != ':' || literal_global ||\n+\tif (elt[0] != ':' || get_literal_global() ||\n \t    (flags & PATHSPEC_LITERAL_PATH)) {\n \t\t; /* nothing to do */\n \t} else if (elt[1] == '(') {\n@@ -207,15 +242,11 @@ static unsigned prefix_pathspec(struct pathspec_item *item, unsigned flags,\n \n \tmagic |= element_magic;\n \n-\t/* --noglob-pathspec adds :(literal) _unless_ :(glob) is specified */\n-\tif (noglob_global && !(magic & PATHSPEC_GLOB))\n-\t\tglobal_magic |= PATHSPEC_LITERAL;\n-\n-\t/* --glob-pathspec is overridden by :(literal) */\n-\tif ((global_magic & PATHSPEC_GLOB) && (magic & PATHSPEC_LITERAL))\n-\t\tglobal_magic &= ~PATHSPEC_GLOB;\n-\n-\tmagic |= global_magic;\n+\t/* PATHSPEC_LITERAL_PATH ignores magic */\n+\tif (flags & PATHSPEC_LITERAL_PATH)\n+\t\tmagic = PATHSPEC_LITERAL;\n+\telse\n+\t\tmagic |= get_global_magic(element_magic);\n \n \tif (pathspec_prefix >= 0 &&\n \t    (prefixlen || (prefix && *prefix)))\n@@ -241,7 +272,7 @@ static unsigned prefix_pathspec(struct pathspec_item *item, unsigned flags,\n \t * original. Useful for passing to another command.\n \t */\n \tif ((flags & PATHSPEC_PREFIX_ORIGIN) &&\n-\t    prefixlen && !literal_global) {\n+\t    prefixlen && !get_literal_global()) {\n \t\tstruct strbuf sb = STRBUF_INIT;\n \n \t\t/* Preserve the actual prefix length of each pattern */\n@@ -408,9 +439,7 @@ void parse_pathspec(struct pathspec *pathspec,\n \n \t\titem[i].magic = prefix_pathspec(item + i, flags,\n \t\t\t\t\t\tprefix, prefixlen, entry);\n-\t\tif ((flags & PATHSPEC_LITERAL_PATH) &&\n-\t\t    !(magic_mask & PATHSPEC_LITERAL))\n-\t\t\titem[i].magic |= PATHSPEC_LITERAL;\n+\n \t\tif (item[i].magic & PATHSPEC_EXCLUDE)\n \t\t\tnr_exclude++;\n \t\tif (item[i].magic & magic_mask)\n-- \n2.11.0.390.gc69c2f50cf-goog\n\n"},{"id":"308715","messageId":"20170103184241.128409-5-bmwill@google.com","threadId":"44632","inReplyTo":"20170103184241.128409-1-bmwill@google.com","subject":"[PATCH v4 04/16] ls-tree: convert show_recursive to use the pathspec struct interface","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-01-03T18:42:29Z","receivedAt":"2017-01-03T18:49:59Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Convert 'show_recursive()' to use the pathspec struct interface from\nusing the '_raw' entry in the pathspec struct.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n builtin/ls-tree.c | 16 +++++++---------\n 1 file changed, 7 insertions(+), 9 deletions(-)\n\ndiff --git a/builtin/ls-tree.c b/builtin/ls-tree.c\nindex 0e30d8623..d7ebeb4ce 100644\n--- a/builtin/ls-tree.c\n+++ b/builtin/ls-tree.c\n@@ -31,21 +31,18 @@ static const  char * const ls_tree_usage[] = {\n \n static int show_recursive(const char *base, int baselen, const char *pathname)\n {\n-\tconst char **s;\n+\tint i;\n \n \tif (ls_options & LS_RECURSIVE)\n \t\treturn 1;\n \n-\ts = pathspec._raw;\n-\tif (!s)\n+\tif (!pathspec.nr)\n \t\treturn 0;\n \n-\tfor (;;) {\n-\t\tconst char *spec = *s++;\n+\tfor (i = 0; i < pathspec.nr; i++) {\n+\t\tconst char *spec = pathspec.items[i].match;\n \t\tint len, speclen;\n \n-\t\tif (!spec)\n-\t\t\treturn 0;\n \t\tif (strncmp(base, spec, baselen))\n \t\t\tcontinue;\n \t\tlen = strlen(pathname);\n@@ -59,6 +56,7 @@ static int show_recursive(const char *base, int baselen, const char *pathname)\n \t\t\tcontinue;\n \t\treturn 1;\n \t}\n+\treturn 0;\n }\n \n static int show_tree(const unsigned char *sha1, struct strbuf *base,\n@@ -175,8 +173,8 @@ 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() or tree_entry_interesting()\n \t */\n-\tparse_pathspec(&pathspec, PATHSPEC_GLOB | PATHSPEC_ICASE |\n-\t\t\t\t  PATHSPEC_EXCLUDE,\n+\tparse_pathspec(&pathspec, PATHSPEC_ALL_MAGIC &\n+\t\t\t\t  ~(PATHSPEC_FROMTOP | PATHSPEC_LITERAL),\n \t\t       PATHSPEC_PREFER_CWD,\n \t\t       prefix, argv + 1);\n \tfor (i = 0; i < pathspec.nr; i++)\n-- \n2.11.0.390.gc69c2f50cf-goog\n\n"},{"id":"308716","messageId":"20170103184241.128409-2-bmwill@google.com","threadId":"44632","inReplyTo":"20170103184241.128409-1-bmwill@google.com","subject":"[PATCH v4 01/16] mv: remove use of deprecated 'get_pathspec()'","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-01-03T18:42:26Z","receivedAt":"2017-01-03T18:50:12Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Convert the 'internal_copy_pathspec()' function to 'prefix_path()'\ninstead of using the deprecated 'get_pathspec()' interface.  Also,\nrename 'internal_copy_pathspec()' to 'internal_prefix_pathspec()' to be\nmore descriptive of what the funciton is actually doing.\n\nIn addition to this, fix a memory leak caused by only duplicating some\nof the pathspec elements.  Instead always duplicate all of the the\npathspec elements as an intermediate step (with modificationed based on\nthe passed in flags).  This way the intermediate strings can then be\nfreed after getting the result from 'prefix_path()'.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n builtin/mv.c | 50 +++++++++++++++++++++++++++++++-------------------\n 1 file changed, 31 insertions(+), 19 deletions(-)\n\ndiff --git a/builtin/mv.c b/builtin/mv.c\nindex 2f43877bc..4e86dc523 100644\n--- a/builtin/mv.c\n+++ b/builtin/mv.c\n@@ -4,6 +4,7 @@\n  * Copyright (C) 2006 Johannes Schindelin\n  */\n #include \"builtin.h\"\n+#include \"pathspec.h\"\n #include \"lockfile.h\"\n #include \"dir.h\"\n #include \"cache-tree.h\"\n@@ -19,31 +20,42 @@ static const char * const builtin_mv_usage[] = {\n #define DUP_BASENAME 1\n #define KEEP_TRAILING_SLASH 2\n \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, unsigned flags)\n+static const char **internal_prefix_pathspec(const char *prefix,\n+\t\t\t\t\t     const char **pathspec,\n+\t\t\t\t\t     int count, unsigned flags)\n {\n \tint i;\n \tconst char **result;\n+\tint prefixlen = prefix ? strlen(prefix) : 0;\n \tALLOC_ARRAY(result, count + 1);\n-\tCOPY_ARRAY(result, pathspec, count);\n-\tresult[count] = NULL;\n+\n+\t/* Create an intermediate copy of the pathspec based on the flags */\n \tfor (i = 0; i < count; i++) {\n-\t\tint length = strlen(result[i]);\n+\t\tint length = strlen(pathspec[i]);\n \t\tint to_copy = length;\n+\t\tchar *it;\n \t\twhile (!(flags & KEEP_TRAILING_SLASH) &&\n-\t\t       to_copy > 0 && is_dir_sep(result[i][to_copy - 1]))\n+\t\t       to_copy > 0 && is_dir_sep(pathspec[i][to_copy - 1]))\n \t\t\tto_copy--;\n-\t\tif (to_copy != length || flags & DUP_BASENAME) {\n-\t\t\tchar *it = xmemdupz(result[i], to_copy);\n-\t\t\tif (flags & DUP_BASENAME) {\n-\t\t\t\tresult[i] = xstrdup(basename(it));\n-\t\t\t\tfree(it);\n-\t\t\t} else\n-\t\t\t\tresult[i] = it;\n+\n+\t\tit = xmemdupz(pathspec[i], to_copy);\n+\t\tif (flags & DUP_BASENAME) {\n+\t\t\tresult[i] = xstrdup(basename(it));\n+\t\t\tfree(it);\n+\t\t} else {\n+\t\t\tresult[i] = it;\n \t\t}\n \t}\n-\treturn get_pathspec(prefix, result);\n+\tresult[count] = NULL;\n+\n+\t/* Prefix the pathspec and free the old intermediate strings */\n+\tfor (i = 0; i < count; i++) {\n+\t\tconst char *match = prefix_path(prefix, prefixlen, result[i]);\n+\t\tfree((char *) result[i]);\n+\t\tresult[i] = match;\n+\t}\n+\n+\treturn result;\n }\n \n static const char *add_slash(const char *path)\n@@ -130,7 +142,7 @@ 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 = internal_copy_pathspec(prefix, argv, argc, 0);\n+\tsource = internal_prefix_pathspec(prefix, argv, argc, 0);\n \tmodes = xcalloc(argc, sizeof(enum update_mode));\n \t/*\n \t * Keep trailing slash, needed to let\n@@ -140,16 +152,16 @@ int cmd_mv(int argc, const char **argv, const char *prefix)\n \tflags = KEEP_TRAILING_SLASH;\n \tif (argc == 1 && is_directory(argv[0]) && !is_directory(argv[1]))\n \t\tflags = 0;\n-\tdest_path = internal_copy_pathspec(prefix, argv + argc, 1, flags);\n+\tdest_path = internal_prefix_pathspec(prefix, argv + argc, 1, flags);\n \tsubmodule_gitfile = xcalloc(argc, sizeof(char *));\n \n \tif (dest_path[0][0] == '\\0')\n \t\t/* special case: \".\" was normalized to \"\" */\n-\t\tdestination = internal_copy_pathspec(dest_path[0], argv, argc, DUP_BASENAME);\n+\t\tdestination = internal_prefix_pathspec(dest_path[0], argv, argc, DUP_BASENAME);\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 = internal_copy_pathspec(dest_path[0], argv, argc, DUP_BASENAME);\n+\t\tdestination = internal_prefix_pathspec(dest_path[0], argv, argc, DUP_BASENAME);\n \t} else {\n \t\tif (argc != 1)\n \t\t\tdie(_(\"destination '%s' is not a directory\"), dest_path[0]);\n-- \n2.11.0.390.gc69c2f50cf-goog\n\n"},{"id":"308717","messageId":"20170103184241.128409-10-bmwill@google.com","threadId":"44632","inReplyTo":"20170103184241.128409-1-bmwill@google.com","subject":"[PATCH v4 09/16] pathspec: simpler logic to prefix original pathspec elements","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-01-03T18:42:34Z","receivedAt":"2017-01-03T18:50:15Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"The logic used to prefix an original pathspec element with 'prefix'\nmagic is more general purpose and can be used for more than just short\nmagic.  Remove the extra code paths and rename 'prefix_short_magic' to\n'prefix_magic' to better indicate that it can be used in more general\nsituations.\n\nAlso, slightly change the logic which decides when to prefix the\noriginal element in order to prevent a pathspec of \".\" from getting\nconverted to \"\" (empty string).\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n pathspec.c | 33 +++++++++++++--------------------\n 1 file changed, 13 insertions(+), 20 deletions(-)\n\ndiff --git a/pathspec.c b/pathspec.c\nindex ee87494c7..032436bc1 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -74,13 +74,12 @@ static struct pathspec_magic {\n \t{ PATHSPEC_EXCLUDE, '!', \"exclude\" },\n };\n \n-static void prefix_short_magic(struct strbuf *sb, int prefixlen,\n-\t\t\t       unsigned short_magic)\n+static void prefix_magic(struct strbuf *sb, int prefixlen, unsigned magic)\n {\n \tint i;\n \tstrbuf_addstr(sb, \":(\");\n \tfor (i = 0; i < ARRAY_SIZE(pathspec_magic); i++)\n-\t\tif (short_magic & pathspec_magic[i].bit) {\n+\t\tif (magic & pathspec_magic[i].bit) {\n \t\t\tif (sb->buf[sb->len - 1] != '(')\n \t\t\t\tstrbuf_addch(sb, ',');\n \t\t\tstrbuf_addstr(sb, pathspec_magic[i].name);\n@@ -109,8 +108,8 @@ static unsigned prefix_pathspec(struct pathspec_item *item, unsigned flags,\n \tstatic int glob_global = -1;\n \tstatic int noglob_global = -1;\n \tstatic int icase_global = -1;\n-\tunsigned magic = 0, short_magic = 0, global_magic = 0;\n-\tconst char *copyfrom = elt, *long_magic_end = NULL;\n+\tunsigned magic = 0, element_magic = 0, global_magic = 0;\n+\tconst char *copyfrom = elt;\n \tchar *match;\n \tint i, pathspec_prefix = -1;\n \n@@ -164,7 +163,7 @@ static unsigned prefix_pathspec(struct pathspec_item *item, unsigned flags,\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\telement_magic |= pathspec_magic[i].bit;\n \t\t\t\t\tbreak;\n \t\t\t\t}\n \t\t\t\tif (starts_with(copyfrom, \"prefix:\")) {\n@@ -183,7 +182,6 @@ static unsigned prefix_pathspec(struct pathspec_item *item, unsigned flags,\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@@ -196,7 +194,7 @@ static unsigned prefix_pathspec(struct pathspec_item *item, unsigned flags,\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\tshort_magic |= pathspec_magic[i].bit;\n+\t\t\t\t\telement_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@@ -207,7 +205,7 @@ static unsigned prefix_pathspec(struct pathspec_item *item, unsigned flags,\n \t\t\tcopyfrom++;\n \t}\n \n-\tmagic |= short_magic;\n+\tmagic |= element_magic;\n \n \t/* --noglob-pathspec adds :(literal) _unless_ :(glob) is specified */\n \tif (noglob_global && !(magic & PATHSPEC_GLOB))\n@@ -242,18 +240,13 @@ static unsigned prefix_pathspec(struct pathspec_item *item, unsigned flags,\n \t * Prefix the pathspec (keep all magic) and assign to\n \t * original. Useful for passing to another command.\n \t */\n-\tif (flags & PATHSPEC_PREFIX_ORIGIN) {\n+\tif ((flags & PATHSPEC_PREFIX_ORIGIN) &&\n+\t    prefixlen && !literal_global) {\n \t\tstruct strbuf sb = STRBUF_INIT;\n-\t\tif (prefixlen && !literal_global) {\n-\t\t\t/* Preserve the actual prefix length of each pattern */\n-\t\t\tif (short_magic)\n-\t\t\t\tprefix_short_magic(&sb, prefixlen, short_magic);\n-\t\t\telse if (long_magic_end) {\n-\t\t\t\tstrbuf_add(&sb, elt, long_magic_end - elt);\n-\t\t\t\tstrbuf_addf(&sb, \",prefix:%d)\", prefixlen);\n-\t\t\t} else\n-\t\t\t\tstrbuf_addf(&sb, \":(prefix:%d)\", prefixlen);\n-\t\t}\n+\n+\t\t/* Preserve the actual prefix length of each pattern */\n+\t\tprefix_magic(&sb, prefixlen, element_magic);\n+\n \t\tstrbuf_addstr(&sb, match);\n \t\titem->original = strbuf_detach(&sb, NULL);\n \t} else {\n-- \n2.11.0.390.gc69c2f50cf-goog\n\n"},{"id":"308718","messageId":"20170103184241.128409-15-bmwill@google.com","threadId":"44632","inReplyTo":"20170103184241.128409-1-bmwill@google.com","subject":"[PATCH v4 14/16] pathspec: create strip submodule slash helpers","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-01-03T18:42:39Z","receivedAt":"2017-01-03T18:50:43Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Factor out the logic responsible for stripping the trailing slash on\npathspecs referencing submodules into its own function.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n pathspec.c | 68 ++++++++++++++++++++++++++++++++++++++------------------------\n 1 file changed, 42 insertions(+), 26 deletions(-)\n\ndiff --git a/pathspec.c b/pathspec.c\nindex fe811a0a4..4a1f8ea44 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -258,6 +258,44 @@ static const char *parse_element_magic(unsigned *magic, int *prefix_len,\n \t\treturn parse_short_magic(magic, elem);\n }\n \n+static void strip_submodule_slash_cheap(struct pathspec_item *item)\n+{\n+\tif (item->len >= 1 && item->match[item->len - 1] == '/') {\n+\t\tint i = cache_name_pos(item->match, item->len - 1);\n+\n+\t\tif (i >= 0 && S_ISGITLINK(active_cache[i]->ce_mode)) {\n+\t\t\titem->len--;\n+\t\t\titem->match[item->len] = '\\0';\n+\t\t}\n+\t}\n+}\n+\n+static void strip_submodule_slash_expensive(struct pathspec_item *item)\n+{\n+\tint i;\n+\n+\tfor (i = 0; i < active_nr; i++) {\n+\t\tstruct cache_entry *ce = active_cache[i];\n+\t\tint ce_len = ce_namelen(ce);\n+\n+\t\tif (!S_ISGITLINK(ce->ce_mode))\n+\t\t\tcontinue;\n+\n+\t\tif (item->len <= ce_len || item->match[ce_len] != '/' ||\n+\t\t    memcmp(ce->name, item->match, ce_len))\n+\t\t\tcontinue;\n+\n+\t\tif (item->len == ce_len + 1) {\n+\t\t\t/* strip trailing slash */\n+\t\t\titem->len--;\n+\t\t\titem->match[item->len] = '\\0';\n+\t\t} else {\n+\t\t\tdie(_(\"Pathspec '%s' is in submodule '%.*s'\"),\n+\t\t\t    item->original, ce_len, ce->name);\n+\t\t}\n+\t}\n+}\n+\n /*\n  * Take an element of a pathspec and check for magic signatures.\n  * Append the result to the prefix. Return the magic bitmap.\n@@ -278,7 +316,7 @@ static unsigned prefix_pathspec(struct pathspec_item *item, unsigned flags,\n \tunsigned magic = 0, element_magic = 0;\n \tconst char *copyfrom = elt;\n \tchar *match;\n-\tint i, pathspec_prefix = -1;\n+\tint pathspec_prefix = -1;\n \n \t/* PATHSPEC_LITERAL_PATH ignores magic */\n \tif (flags & PATHSPEC_LITERAL_PATH) {\n@@ -329,33 +367,11 @@ static unsigned prefix_pathspec(struct pathspec_item *item, unsigned flags,\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-\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+\tif (flags & PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP)\n+\t\tstrip_submodule_slash_cheap(item);\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+\t\tstrip_submodule_slash_expensive(item);\n \n \tif (magic & PATHSPEC_LITERAL)\n \t\titem->nowildcard_len = item->len;\n-- \n2.11.0.390.gc69c2f50cf-goog\n\n"},{"id":"308719","messageId":"20170103184241.128409-9-bmwill@google.com","threadId":"44632","inReplyTo":"20170103184241.128409-1-bmwill@google.com","subject":"[PATCH v4 08/16] pathspec: always show mnemonic and name in unsupported_magic","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-01-03T18:42:33Z","receivedAt":"2017-01-03T18:50:54Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"For better clarity, always show the mnemonic and name of the unsupported\nmagic being used.  This lets users have a more clear understanding of\nwhat magic feature isn't supported.  And if they supplied a mnemonic,\nthe user will be told what its corresponding name is which will allow\nthem to more easily search the man pages for that magic type.\n\nThis also avoids passing an extra parameter around the pathspec\ninitialization code.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n pathspec.c | 24 +++++++++---------------\n 1 file changed, 9 insertions(+), 15 deletions(-)\n\ndiff --git a/pathspec.c b/pathspec.c\nindex b9a3819d6..ee87494c7 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -101,9 +101,7 @@ static void prefix_short_magic(struct strbuf *sb, int prefixlen,\n  * the prefix part must always match literally, and a single stupid\n  * string cannot express such a case.\n  */\n-static unsigned prefix_pathspec(struct pathspec_item *item,\n-\t\t\t\tunsigned *p_short_magic,\n-\t\t\t\tunsigned flags,\n+static unsigned prefix_pathspec(struct pathspec_item *item, unsigned flags,\n \t\t\t\tconst char *prefix, int prefixlen,\n \t\t\t\tconst char *elt)\n {\n@@ -210,7 +208,6 @@ static unsigned prefix_pathspec(struct pathspec_item *item,\n \t}\n \n \tmagic |= short_magic;\n-\t*p_short_magic = short_magic;\n \n \t/* --noglob-pathspec adds :(literal) _unless_ :(glob) is specified */\n \tif (noglob_global && !(magic & PATHSPEC_GLOB))\n@@ -329,8 +326,7 @@ static int pathspec_item_cmp(const void *a_, const void *b_)\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+\t\t\t\t       unsigned magic)\n {\n \tstruct strbuf sb = STRBUF_INIT;\n \tint i;\n@@ -339,9 +335,11 @@ static void NORETURN unsupported_magic(const char *pattern,\n \t\tif (!(magic & m->bit))\n \t\t\tcontinue;\n \t\tif (sb.len)\n-\t\t\tstrbuf_addch(&sb, ' ');\n-\t\tif (short_magic & m->bit)\n-\t\t\tstrbuf_addf(&sb, \"'%c'\", m->mnemonic);\n+\t\t\tstrbuf_addstr(&sb, \", \");\n+\n+\t\tif (m->mnemonic)\n+\t\t\tstrbuf_addf(&sb, \"'%s' (mnemonic: '%c')\",\n+\t\t\t\t    m->name, m->mnemonic);\n \t\telse\n \t\t\tstrbuf_addf(&sb, \"'%s'\", m->name);\n \t}\n@@ -413,11 +411,9 @@ void parse_pathspec(struct pathspec *pathspec,\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\tflags,\n+\t\titem[i].magic = prefix_pathspec(item + i, flags,\n \t\t\t\t\t\tprefix, prefixlen, entry);\n \t\tif ((flags & PATHSPEC_LITERAL_PATH) &&\n \t\t    !(magic_mask & PATHSPEC_LITERAL))\n@@ -425,9 +421,7 @@ void parse_pathspec(struct pathspec *pathspec,\n \t\tif (item[i].magic & PATHSPEC_EXCLUDE)\n \t\t\tnr_exclude++;\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\t\tunsupported_magic(entry, item[i].magic & magic_mask);\n \n \t\tif ((flags & PATHSPEC_SYMLINK_LEADING_PATH) &&\n \t\t    has_symlink_leading_path(item[i].match, item[i].len)) {\n-- \n2.11.0.390.gc69c2f50cf-goog\n\n"},{"id":"308720","messageId":"20170103184241.128409-8-bmwill@google.com","threadId":"44632","inReplyTo":"20170103184241.128409-1-bmwill@google.com","subject":"[PATCH v4 07/16] pathspec: remove unused variable from unsupported_magic","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-01-03T18:42:32Z","receivedAt":"2017-01-03T18:50:57Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Removed unused variable 'n' from the 'unsupported_magic()' function.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n pathspec.c | 5 ++---\n 1 file changed, 2 insertions(+), 3 deletions(-)\n\ndiff --git a/pathspec.c b/pathspec.c\nindex b8faa8f46..b9a3819d6 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -333,8 +333,8 @@ static void NORETURN unsupported_magic(const char *pattern,\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+\tint i;\n+\tfor (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@@ -344,7 +344,6 @@ static void NORETURN unsupported_magic(const char *pattern,\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 substitute \"this command\" with a command\n-- \n2.11.0.390.gc69c2f50cf-goog\n\n"},{"id":"308721","messageId":"20170103184241.128409-6-bmwill@google.com","threadId":"44632","inReplyTo":"20170103184241.128409-1-bmwill@google.com","subject":"[PATCH v4 05/16] pathspec: remove the deprecated get_pathspec function","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-01-03T18:42:30Z","receivedAt":"2017-01-03T18:51:16Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Now that all callers of the old 'get_pathspec' interface have been\nmigrated to use the new pathspec struct interface it can be removed\nfrom the codebase.\n\nSince there are no more users of the '_raw' field in the pathspec struct\nit can also be removed.  This patch also removes the old functionality\nof modifying the const char **argv array that was passed into\nparse_pathspec.  Instead the constructed 'match' string (which is a\npathspec element with the prefix prepended) is only stored in its\ncorresponding pathspec_item entry.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n Documentation/technical/api-setup.txt |  2 --\n cache.h                               |  1 -\n pathspec.c                            | 42 +++--------------------------------\n pathspec.h                            |  1 -\n 4 files changed, 3 insertions(+), 43 deletions(-)\n\ndiff --git a/Documentation/technical/api-setup.txt b/Documentation/technical/api-setup.txt\nindex 540e45568..eb1fa9853 100644\n--- a/Documentation/technical/api-setup.txt\n+++ b/Documentation/technical/api-setup.txt\n@@ -27,8 +27,6 @@ parse_pathspec(). This function takes several arguments:\n \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 them\n politely. At a lower level, different pathspec-related functions may\n not support the same set of features. Such pathspec-sensitive\ndiff --git a/cache.h b/cache.h\nindex a50a61a19..0f80e01bd 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -514,7 +514,6 @@ extern void set_git_work_tree(const char *tree);\n \n #define ALTERNATE_DB_ENVIRONMENT \"GIT_ALTERNATE_OBJECT_DIRECTORIES\"\n \n-extern const char **get_pathspec(const char *prefix, const char **pathspec);\n extern void setup_work_tree(void);\n extern const char *setup_git_directory_gently(int *);\n extern const char *setup_git_directory(void);\ndiff --git a/pathspec.c b/pathspec.c\nindex 22ca74a12..1f918cbae 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -103,7 +103,7 @@ static void prefix_short_magic(struct strbuf *sb, int prefixlen,\n  */\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\tunsigned flags,\n \t\t\t\tconst char *prefix, int prefixlen,\n \t\t\t\tconst char *elt)\n {\n@@ -240,7 +240,7 @@ static unsigned prefix_pathspec(struct pathspec_item *item,\n \t\tif (!match)\n \t\t\tdie(_(\"%s: '%s' is outside repository\"), elt, copyfrom);\n \t}\n-\t*raw = item->match = match;\n+\titem->match = match;\n \t/*\n \t * Prefix the pathspec (keep all magic) and assign to\n \t * original. Useful for passing to another command.\n@@ -381,8 +381,6 @@ void parse_pathspec(struct pathspec *pathspec,\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@@ -394,10 +392,7 @@ void parse_pathspec(struct pathspec *pathspec,\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;\n-\t\tpathspec->_raw = raw;\n \t\treturn;\n \t}\n \n@@ -415,7 +410,6 @@ void parse_pathspec(struct pathspec *pathspec,\n \tpathspec->nr = n;\n \tALLOC_ARRAY(pathspec->items, n);\n \titem = pathspec->items;\n-\tpathspec->_raw = argv;\n \tprefixlen = prefix ? strlen(prefix) : 0;\n \n \tfor (i = 0; i < n; i++) {\n@@ -423,7 +417,7 @@ void parse_pathspec(struct pathspec *pathspec,\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\tflags,\n \t\t\t\t\t\tprefix, prefixlen, entry);\n \t\tif ((flags & PATHSPEC_LITERAL_PATH) &&\n \t\t    !(magic_mask & PATHSPEC_LITERAL))\n@@ -457,36 +451,6 @@ void parse_pathspec(struct pathspec *pathspec,\n \t}\n }\n \n-/*\n- * N.B. get_pathspec() is deprecated in favor of the \"struct pathspec\"\n- * based interface - see pathspec.c:parse_pathspec().\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-\tstruct pathspec ps;\n-\tparse_pathspec(&ps,\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;\n-}\n-\n void copy_pathspec(struct pathspec *dst, const struct pathspec *src)\n {\n \t*dst = *src;\ndiff --git a/pathspec.h b/pathspec.h\nindex 59809e479..70a592e91 100644\n--- a/pathspec.h\n+++ b/pathspec.h\n@@ -19,7 +19,6 @@\n #define PATHSPEC_ONESTAR 1\t/* the pathspec pattern satisfies GFNM_ONESTAR */\n \n struct pathspec {\n-\tconst char **_raw; /* get_pathspec() result, not freed by clear_pathspec() */\n \tint nr;\n \tunsigned int has_wildcard:1;\n \tunsigned int recursive:1;\n-- \n2.11.0.390.gc69c2f50cf-goog\n\n"},{"id":"308722","messageId":"20170103184241.128409-14-bmwill@google.com","threadId":"44632","inReplyTo":"20170103184241.128409-1-bmwill@google.com","subject":"[PATCH v4 13/16] pathspec: create parse_element_magic helper","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-01-03T18:42:38Z","receivedAt":"2017-01-03T18:53:11Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Factor out the logic responsible for the magic in a pathspec element\ninto its own function.\n\nAlso avoid calling into the parsing functions when\n`PATHSPEC_LITERAL_PATH` is specified since it causes magic to be\nignored and all paths to be treated as literals.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n pathspec.c | 37 ++++++++++++++++++++-----------------\n 1 file changed, 20 insertions(+), 17 deletions(-)\n\ndiff --git a/pathspec.c b/pathspec.c\nindex f1439f6f9..fe811a0a4 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -245,6 +245,19 @@ static const char *parse_short_magic(unsigned *magic, const char *elem)\n \treturn pos;\n }\n \n+static const char *parse_element_magic(unsigned *magic, int *prefix_len,\n+\t\t\t\t       const char *elem)\n+{\n+\tif (elem[0] != ':' || get_literal_global())\n+\t\treturn elem; /* nothing to do */\n+\telse if (elem[1] == '(')\n+\t\t/* longhand */\n+\t\treturn parse_long_magic(magic, prefix_len, elem);\n+\telse\n+\t\t/* shorthand */\n+\t\treturn parse_short_magic(magic, elem);\n+}\n+\n /*\n  * Take an element of a pathspec and check for magic signatures.\n  * Append the result to the prefix. Return the magic bitmap.\n@@ -267,26 +280,16 @@ static unsigned prefix_pathspec(struct pathspec_item *item, unsigned flags,\n \tchar *match;\n \tint i, pathspec_prefix = -1;\n \n-\tif (elt[0] != ':' || get_literal_global() ||\n-\t    (flags & PATHSPEC_LITERAL_PATH)) {\n-\t\t; /* nothing to do */\n-\t} else if (elt[1] == '(') {\n-\t\t/* longhand */\n-\t\tcopyfrom = parse_long_magic(&element_magic,\n-\t\t\t\t\t    &pathspec_prefix,\n-\t\t\t\t\t    elt);\n-\t} else {\n-\t\t/* shorthand */\n-\t\tcopyfrom = parse_short_magic(&element_magic, elt);\n-\t}\n-\n-\tmagic |= element_magic;\n-\n \t/* PATHSPEC_LITERAL_PATH ignores magic */\n-\tif (flags & PATHSPEC_LITERAL_PATH)\n+\tif (flags & PATHSPEC_LITERAL_PATH) {\n \t\tmagic = PATHSPEC_LITERAL;\n-\telse\n+\t} else {\n+\t\tcopyfrom = parse_element_magic(&element_magic,\n+\t\t\t\t\t       &pathspec_prefix,\n+\t\t\t\t\t       elt);\n+\t\tmagic |= element_magic;\n \t\tmagic |= get_global_magic(element_magic);\n+\t}\n \n \tif (pathspec_prefix >= 0 &&\n \t    (prefixlen || (prefix && *prefix)))\n-- \n2.11.0.390.gc69c2f50cf-goog\n\n"},{"id":"308723","messageId":"20170103184241.128409-12-bmwill@google.com","threadId":"44632","inReplyTo":"20170103184241.128409-1-bmwill@google.com","subject":"[PATCH v4 11/16] pathspec: create parse_short_magic function","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-01-03T18:42:36Z","receivedAt":"2017-01-03T18:53:14Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Factor out the logic responsible for parsing short magic into its own\nfunction.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n pathspec.c | 54 ++++++++++++++++++++++++++++++++++++------------------\n 1 file changed, 36 insertions(+), 18 deletions(-)\n\ndiff --git a/pathspec.c b/pathspec.c\nindex f760f44f9..8574010d5 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -157,6 +157,41 @@ static int get_global_magic(int element_magic)\n }\n \n /*\n+ * Parse the pathspec element looking for short magic\n+ *\n+ * saves all magic in 'magic'\n+ * returns the position in 'elem' after all magic has been parsed\n+ */\n+static const char *parse_short_magic(unsigned *magic, const char *elem)\n+{\n+\tconst char *pos;\n+\n+\tfor (pos = elem + 1; *pos && *pos != ':'; pos++) {\n+\t\tchar ch = *pos;\n+\t\tint i;\n+\n+\t\tif (!is_pathspec_magic(ch))\n+\t\t\tbreak;\n+\n+\t\tfor (i = 0; i < ARRAY_SIZE(pathspec_magic); i++) {\n+\t\t\tif (pathspec_magic[i].mnemonic == ch) {\n+\t\t\t\t*magic |= pathspec_magic[i].bit;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t}\n+\n+\t\tif (ARRAY_SIZE(pathspec_magic) <= i)\n+\t\t\tdie(_(\"Unimplemented pathspec magic '%c' in '%s'\"),\n+\t\t\t    ch, elem);\n+\t}\n+\n+\tif (*pos == ':')\n+\t\tpos++;\n+\n+\treturn pos;\n+}\n+\n+/*\n  * Take an element of a pathspec and check for magic signatures.\n  * Append the result to the prefix. Return the magic bitmap.\n  *\n@@ -220,24 +255,7 @@ static unsigned prefix_pathspec(struct pathspec_item *item, unsigned flags,\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\telement_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-\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\tcopyfrom = parse_short_magic(&element_magic, elt);\n \t}\n \n \tmagic |= element_magic;\n-- \n2.11.0.390.gc69c2f50cf-goog\n\n"},{"id":"308724","messageId":"20170103184241.128409-7-bmwill@google.com","threadId":"44632","inReplyTo":"20170103184241.128409-1-bmwill@google.com","subject":"[PATCH v4 06/16] pathspec: copy and free owned memory","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-01-03T18:42:31Z","receivedAt":"2017-01-03T18:53:22Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"The 'original' string entry in a pathspec_item is only duplicated some\nof the time, instead always make a copy of the original and take\nownership of the memory.\n\nSince both 'match' and 'original' string entries in a pathspec_item are\nowned by the pathspec struct, they need to be freed when clearing the\npathspec struct (in 'clear_pathspec()') and duplicated when copying the\npathspec struct (in 'copy_pathspec()').\n\nAlso change the type of 'match' and 'original' to 'char *' in order to\nmore explicitly show the ownership of the memory.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n pathspec.c | 23 +++++++++++++++++++----\n pathspec.h |  4 ++--\n 2 files changed, 21 insertions(+), 6 deletions(-)\n\ndiff --git a/pathspec.c b/pathspec.c\nindex 1f918cbae..b8faa8f46 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -259,8 +259,9 @@ static unsigned prefix_pathspec(struct pathspec_item *item,\n \t\t}\n \t\tstrbuf_addstr(&sb, match);\n \t\titem->original = strbuf_detach(&sb, NULL);\n-\t} else\n-\t\titem->original = elt;\n+\t} else {\n+\t\titem->original = xstrdup(elt);\n+\t}\n \titem->len = strlen(item->match);\n \titem->prefix = prefixlen;\n \n@@ -388,8 +389,8 @@ void parse_pathspec(struct pathspec *pathspec,\n \t\t\tdie(\"BUG: PATHSPEC_PREFER_CWD requires arguments\");\n \n \t\tpathspec->items = item = xcalloc(1, sizeof(*item));\n-\t\titem->match = prefix;\n-\t\titem->original = prefix;\n+\t\titem->match = xstrdup(prefix);\n+\t\titem->original = xstrdup(prefix);\n \t\titem->nowildcard_len = item->len = strlen(prefix);\n \t\titem->prefix = item->len;\n \t\tpathspec->nr = 1;\n@@ -453,13 +454,27 @@ void parse_pathspec(struct pathspec *pathspec,\n \n void copy_pathspec(struct pathspec *dst, const struct pathspec *src)\n {\n+\tint i;\n+\n \t*dst = *src;\n \tALLOC_ARRAY(dst->items, dst->nr);\n \tCOPY_ARRAY(dst->items, src->items, dst->nr);\n+\n+\tfor (i = 0; i < dst->nr; i++) {\n+\t\tdst->items[i].match = xstrdup(src->items[i].match);\n+\t\tdst->items[i].original = xstrdup(src->items[i].original);\n+\t}\n }\n \n void clear_pathspec(struct pathspec *pathspec)\n {\n+\tint i;\n+\n+\tfor (i = 0; i < pathspec->nr; i++) {\n+\t\tfree(pathspec->items[i].match);\n+\t\tfree(pathspec->items[i].original);\n+\t}\n \tfree(pathspec->items);\n \tpathspec->items = NULL;\n+\tpathspec->nr = 0;\n }\ndiff --git a/pathspec.h b/pathspec.h\nindex 70a592e91..49fd823dd 100644\n--- a/pathspec.h\n+++ b/pathspec.h\n@@ -25,8 +25,8 @@ struct pathspec {\n \tunsigned magic;\n \tint max_depth;\n \tstruct pathspec_item {\n-\t\tconst char *match;\n-\t\tconst char *original;\n+\t\tchar *match;\n+\t\tchar *original;\n \t\tunsigned magic;\n \t\tint len, prefix;\n \t\tint nowildcard_len;\n-- \n2.11.0.390.gc69c2f50cf-goog\n\n"},{"id":"308725","messageId":"20170103184241.128409-1-bmwill@google.com","threadId":"44632","inReplyTo":"1481670870-66754-1-git-send-email-bmwill@google.com","subject":"[PATCH v4 00/16] pathspec cleanup","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-01-03T18:42:25Z","receivedAt":"2017-01-03T18:53:52Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"v4 addresses a few comments from Duy.\n* [2/16] push the guard pathspec macro into simplify_away() and\n  exclude_matches_pathsepc().\n* [6/16] when freeing a pathspec struct, set pathsepc->nr = 0.\n* [8/16] tweak the die message when using unsupported magic to be more human\n  readable.\n\nBrandon Williams (16):\n  mv: remove use of deprecated 'get_pathspec()'\n  dir: remove struct path_simplify\n  dir: convert fill_directory to use the pathspec struct interface\n  ls-tree: convert show_recursive to use the pathspec struct interface\n  pathspec: remove the deprecated get_pathspec function\n  pathspec: copy and free owned memory\n  pathspec: remove unused variable from unsupported_magic\n  pathspec: always show mnemonic and name in unsupported_magic\n  pathspec: simpler logic to prefix original pathspec elements\n  pathspec: factor global magic into its own function\n  pathspec: create parse_short_magic function\n  pathspec: create parse_long_magic function\n  pathspec: create parse_element_magic helper\n  pathspec: create strip submodule slash helpers\n  pathspec: small readability changes\n  pathspec: rename prefix_pathspec to init_pathspec_item\n\n Documentation/technical/api-setup.txt |   2 -\n builtin/ls-tree.c                     |  16 +-\n builtin/mv.c                          |  50 ++--\n cache.h                               |   1 -\n dir.c                                 | 193 ++++++--------\n pathspec.c                            | 480 +++++++++++++++++++---------------\n pathspec.h                            |   5 +-\n 7 files changed, 390 insertions(+), 357 deletions(-)\n\n--- interdiff between v3 and v4\n\ndiff --git a/dir.c b/dir.c\nindex 15f7c9993..e8ddd7f8a 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -1353,6 +1353,15 @@ static int simplify_away(const char *path, int pathlen,\n {\n \tint i;\n \n+\tif (pathspec)\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_glob |\n+\t\t\t       pathspec_icase |\n+\t\t\t       pathspec_exclude);\n+\n \tif (!pathspec || !pathspec->nr)\n \t\treturn 0;\n \n@@ -1385,6 +1394,15 @@ static int exclude_matches_pathspec(const char *path, int pathlen,\n {\n \tint i;\n \n+\tif (pathspec)\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_glob |\n+\t\t\t       pathspec_icase |\n+\t\t\t       pathspec_exclude);\n+\n \tif (!pathspec || !pathspec->nr)\n \t\treturn 0;\n \n@@ -1996,15 +2014,6 @@ int read_directory(struct dir_struct *dir, const char *path,\n {\n \tstruct untracked_cache_dir *untracked;\n \n-\tif (pathspec)\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_glob |\n-\t\t\t       pathspec_icase |\n-\t\t\t       pathspec_exclude);\n-\n \tif (has_symlink_leading_path(path, len))\n \t\treturn dir->nr;\n\ndiff --git a/pathspec.c b/pathspec.c\nindex d4efcf666..bcf3ba039 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -414,10 +414,11 @@ static void NORETURN unsupported_magic(const char *pattern,\n \t\tif (!(magic & m->bit))\n \t\t\tcontinue;\n \t\tif (sb.len)\n-\t\t\tstrbuf_addch(&sb, ' ');\n+\t\t\tstrbuf_addstr(&sb, \", \");\n \n \t\tif (m->mnemonic)\n-\t\t\tstrbuf_addf(&sb, \"'(%c)%s'\", m->mnemonic, m->name);\n+\t\t\tstrbuf_addf(&sb, \"'%s' (mnemonic: '%c')\",\n+\t\t\t\t    m->name, m->mnemonic);\n \t\telse\n \t\t\tstrbuf_addf(&sb, \"'%s'\", m->name);\n \t}\n@@ -544,4 +545,5 @@ void clear_pathspec(struct pathspec *pathspec)\n \t}\n \tfree(pathspec->items);\n \tpathspec->items = NULL;\n+\tpathspec->nr = 0;\n }\n\n-- \n2.11.0.390.gc69c2f50cf-goog\n\n"},{"id":"308726","messageId":"20170103184241.128409-16-bmwill@google.com","threadId":"44632","inReplyTo":"20170103184241.128409-1-bmwill@google.com","subject":"[PATCH v4 15/16] pathspec: small readability changes","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-01-03T18:42:40Z","receivedAt":"2017-01-03T18:53:57Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"A few small changes to improve readability.  This is done by grouping related\nassignments, adding blank lines, ensuring lines are <80 characters, and\nadding additional comments.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n pathspec.c | 25 +++++++++++++++----------\n 1 file changed, 15 insertions(+), 10 deletions(-)\n\ndiff --git a/pathspec.c b/pathspec.c\nindex 4a1f8ea44..ae9e1401f 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -67,11 +67,11 @@ static struct pathspec_magic {\n \tchar mnemonic; /* this cannot be ':'! */\n \tconst char *name;\n } pathspec_magic[] = {\n-\t{ PATHSPEC_FROMTOP, '/', \"top\" },\n-\t{ PATHSPEC_LITERAL,   0, \"literal\" },\n-\t{ PATHSPEC_GLOB,   '\\0', \"glob\" },\n-\t{ PATHSPEC_ICASE,  '\\0', \"icase\" },\n-\t{ PATHSPEC_EXCLUDE, '!', \"exclude\" },\n+\t{ PATHSPEC_FROMTOP,  '/', \"top\" },\n+\t{ PATHSPEC_LITERAL, '\\0', \"literal\" },\n+\t{ PATHSPEC_GLOB,    '\\0', \"glob\" },\n+\t{ PATHSPEC_ICASE,   '\\0', \"icase\" },\n+\t{ PATHSPEC_EXCLUDE,  '!', \"exclude\" },\n };\n \n static void prefix_magic(struct strbuf *sb, int prefixlen, unsigned magic)\n@@ -336,6 +336,7 @@ static unsigned prefix_pathspec(struct pathspec_item *item, unsigned flags,\n \tif ((magic & PATHSPEC_LITERAL) && (magic & PATHSPEC_GLOB))\n \t\tdie(_(\"%s: 'literal' and 'glob' are incompatible\"), elt);\n \n+\t/* Create match string which will be used for pathspec matching */\n \tif (pathspec_prefix >= 0) {\n \t\tmatch = xstrdup(copyfrom);\n \t\tprefixlen = pathspec_prefix;\n@@ -343,11 +344,16 @@ static unsigned prefix_pathspec(struct pathspec_item *item, unsigned flags,\n \t\tmatch = xstrdup(copyfrom);\n \t\tprefixlen = 0;\n \t} else {\n-\t\tmatch = prefix_path_gently(prefix, prefixlen, &prefixlen, copyfrom);\n+\t\tmatch = prefix_path_gently(prefix, prefixlen,\n+\t\t\t\t\t   &prefixlen, copyfrom);\n \t\tif (!match)\n \t\t\tdie(_(\"%s: '%s' is outside repository\"), elt, copyfrom);\n \t}\n+\n \titem->match = match;\n+\titem->len = strlen(item->match);\n+\titem->prefix = prefixlen;\n+\n \t/*\n \t * Prefix the pathspec (keep all magic) and assign to\n \t * original. Useful for passing to another command.\n@@ -364,8 +370,6 @@ static unsigned prefix_pathspec(struct pathspec_item *item, unsigned flags,\n \t} else {\n \t\titem->original = xstrdup(elt);\n \t}\n-\titem->len = strlen(item->match);\n-\titem->prefix = prefixlen;\n \n \tif (flags & PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP)\n \t\tstrip_submodule_slash_cheap(item);\n@@ -373,13 +377,14 @@ static unsigned prefix_pathspec(struct pathspec_item *item, unsigned flags,\n \tif (flags & PATHSPEC_STRIP_SUBMODULE_SLASH_EXPENSIVE)\n \t\tstrip_submodule_slash_expensive(item);\n \n-\tif (magic & PATHSPEC_LITERAL)\n+\tif (magic & PATHSPEC_LITERAL) {\n \t\titem->nowildcard_len = item->len;\n-\telse {\n+\t} else {\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+\n \titem->flags = 0;\n \tif (magic & PATHSPEC_GLOB) {\n \t\t/*\n-- \n2.11.0.390.gc69c2f50cf-goog\n\n"},{"id":"308728","messageId":"20170103184241.128409-3-bmwill@google.com","threadId":"44632","inReplyTo":"20170103184241.128409-1-bmwill@google.com","subject":"[PATCH v4 02/16] dir: remove struct path_simplify","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-01-03T18:42:27Z","receivedAt":"2017-01-03T19:09:19Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Teach simplify_away() and exclude_matches_pathspec() to handle struct\npathspec directly, eliminating the need for the struct path_simplify.\n\nAlso renamed the len parameter to pathlen in exclude_matches_pathspec()\nto match the parameter names used in simplify_away().\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n dir.c | 181 +++++++++++++++++++++++++++++-------------------------------------\n 1 file changed, 78 insertions(+), 103 deletions(-)\n\ndiff --git a/dir.c b/dir.c\nindex bfa8c8a9a..1df61f10f 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -16,11 +16,6 @@\n #include \"varint.h\"\n #include \"ewah/ewok.h\"\n \n-struct path_simplify {\n-\tint len;\n-\tconst char *path;\n-};\n-\n /*\n  * Tells read_directory_recursive how a file or directory should be treated.\n  * Values are ordered by significance, e.g. if a directory contains both\n@@ -50,7 +45,7 @@ struct cached_dir {\n \n static enum path_treatment read_directory_recursive(struct dir_struct *dir,\n \tconst char *path, int len, struct untracked_cache_dir *untracked,\n-\tint check_only, const struct path_simplify *simplify);\n+\tint check_only, const struct pathspec *pathspec);\n static int get_dtype(struct dirent *de, const char *path, int len);\n \n int fspathcmp(const char *a, const char *b)\n@@ -1312,7 +1307,7 @@ static enum exist_status directory_exists_in_index(const char *dirname, int len)\n static enum path_treatment treat_directory(struct dir_struct *dir,\n \tstruct untracked_cache_dir *untracked,\n \tconst char *dirname, int len, int baselen, int exclude,\n-\tconst struct path_simplify *simplify)\n+\tconst struct pathspec *pathspec)\n {\n \t/* The \"len-1\" is to strip the final '/' */\n \tswitch (directory_exists_in_index(dirname, len-1)) {\n@@ -1341,7 +1336,7 @@ static enum path_treatment treat_directory(struct dir_struct *dir,\n \tuntracked = lookup_untracked(dir->untracked, untracked,\n \t\t\t\t     dirname + baselen, len - baselen);\n \treturn read_directory_recursive(dir, dirname, len,\n-\t\t\t\t\tuntracked, 1, simplify);\n+\t\t\t\t\tuntracked, 1, pathspec);\n }\n \n /*\n@@ -1349,24 +1344,34 @@ static enum path_treatment treat_directory(struct dir_struct *dir,\n  * reading - if the path cannot possibly be in the pathspec,\n  * return true, and we'll skip it early.\n  */\n-static int simplify_away(const char *path, int pathlen, const struct path_simplify *simplify)\n+static int simplify_away(const char *path, int pathlen,\n+\t\t\t const struct pathspec *pathspec)\n {\n-\tif (simplify) {\n-\t\tfor (;;) {\n-\t\t\tconst char *match = simplify->path;\n-\t\t\tint len = simplify->len;\n+\tint i;\n \n-\t\t\tif (!match)\n-\t\t\t\tbreak;\n-\t\t\tif (len > pathlen)\n-\t\t\t\tlen = pathlen;\n-\t\t\tif (!memcmp(path, match, len))\n-\t\t\t\treturn 0;\n-\t\t\tsimplify++;\n-\t\t}\n-\t\treturn 1;\n+\tif (pathspec)\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_GLOB |\n+\t\t\t       PATHSPEC_ICASE |\n+\t\t\t       PATHSPEC_EXCLUDE);\n+\n+\tif (!pathspec || !pathspec->nr)\n+\t\treturn 0;\n+\n+\tfor (i = 0; i < pathspec->nr; i++) {\n+\t\tconst struct pathspec_item *item = &pathspec->items[i];\n+\t\tint len = item->nowildcard_len;\n+\n+\t\tif (len > pathlen)\n+\t\t\tlen = pathlen;\n+\t\tif (!ps_strncmp(item, item->match, path, len))\n+\t\t\treturn 0;\n \t}\n-\treturn 0;\n+\n+\treturn 1;\n }\n \n /*\n@@ -1380,19 +1385,34 @@ static int simplify_away(const char *path, int pathlen, const struct path_simpli\n  *   2. the path is a directory prefix of some element in the\n  *      pathspec\n  */\n-static int exclude_matches_pathspec(const char *path, int len,\n-\t\tconst struct path_simplify *simplify)\n-{\n-\tif (simplify) {\n-\t\tfor (; simplify->path; simplify++) {\n-\t\t\tif (len == simplify->len\n-\t\t\t    && !memcmp(path, simplify->path, len))\n-\t\t\t\treturn 1;\n-\t\t\tif (len < simplify->len\n-\t\t\t    && simplify->path[len] == '/'\n-\t\t\t    && !memcmp(path, simplify->path, len))\n-\t\t\t\treturn 1;\n-\t\t}\n+static int exclude_matches_pathspec(const char *path, int pathlen,\n+\t\t\t\t    const struct pathspec *pathspec)\n+{\n+\tint i;\n+\n+\tif (pathspec)\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_GLOB |\n+\t\t\t       PATHSPEC_ICASE |\n+\t\t\t       PATHSPEC_EXCLUDE);\n+\n+\tif (!pathspec || !pathspec->nr)\n+\t\treturn 0;\n+\n+\tfor (i = 0; i < pathspec->nr; i++) {\n+\t\tconst struct pathspec_item *item = &pathspec->items[i];\n+\t\tint len = item->nowildcard_len;\n+\n+\t\tif (len == pathlen &&\n+\t\t    !ps_strncmp(item, item->match, path, pathlen))\n+\t\t\treturn 1;\n+\t\tif (len > pathlen &&\n+\t\t    item->match[pathlen] == '/' &&\n+\t\t    !ps_strncmp(item, item->match, path, pathlen))\n+\t\t\treturn 1;\n \t}\n \treturn 0;\n }\n@@ -1460,7 +1480,7 @@ static enum path_treatment treat_one_path(struct dir_struct *dir,\n \t\t\t\t\t  struct untracked_cache_dir *untracked,\n \t\t\t\t\t  struct strbuf *path,\n \t\t\t\t\t  int baselen,\n-\t\t\t\t\t  const struct path_simplify *simplify,\n+\t\t\t\t\t  const struct pathspec *pathspec,\n \t\t\t\t\t  int dtype, struct dirent *de)\n {\n \tint exclude;\n@@ -1512,7 +1532,7 @@ static enum path_treatment treat_one_path(struct dir_struct *dir,\n \tcase DT_DIR:\n \t\tstrbuf_addch(path, '/');\n \t\treturn treat_directory(dir, untracked, path->buf, path->len,\n-\t\t\t\t       baselen, exclude, simplify);\n+\t\t\t\t       baselen, exclude, pathspec);\n \tcase DT_REG:\n \tcase DT_LNK:\n \t\treturn exclude ? path_excluded : path_untracked;\n@@ -1524,7 +1544,7 @@ static enum path_treatment treat_path_fast(struct dir_struct *dir,\n \t\t\t\t\t   struct cached_dir *cdir,\n \t\t\t\t\t   struct strbuf *path,\n \t\t\t\t\t   int baselen,\n-\t\t\t\t\t   const struct path_simplify *simplify)\n+\t\t\t\t\t   const struct pathspec *pathspec)\n {\n \tstrbuf_setlen(path, baselen);\n \tif (!cdir->ucd) {\n@@ -1541,7 +1561,7 @@ static enum path_treatment treat_path_fast(struct dir_struct *dir,\n \t\t * with check_only set.\n \t\t */\n \t\treturn read_directory_recursive(dir, path->buf, path->len,\n-\t\t\t\t\t\tcdir->ucd, 1, simplify);\n+\t\t\t\t\t\tcdir->ucd, 1, pathspec);\n \t/*\n \t * We get path_recurse in the first run when\n \t * directory_exists_in_index() returns index_nonexistent. We\n@@ -1556,23 +1576,23 @@ static enum path_treatment treat_path(struct dir_struct *dir,\n \t\t\t\t      struct cached_dir *cdir,\n \t\t\t\t      struct strbuf *path,\n \t\t\t\t      int baselen,\n-\t\t\t\t      const struct path_simplify *simplify)\n+\t\t\t\t      const struct pathspec *pathspec)\n {\n \tint dtype;\n \tstruct dirent *de = cdir->de;\n \n \tif (!de)\n \t\treturn treat_path_fast(dir, untracked, cdir, path,\n-\t\t\t\t       baselen, simplify);\n+\t\t\t\t       baselen, pathspec);\n \tif (is_dot_or_dotdot(de->d_name) || !strcmp(de->d_name, \".git\"))\n \t\treturn path_none;\n \tstrbuf_setlen(path, baselen);\n \tstrbuf_addstr(path, de->d_name);\n-\tif (simplify_away(path->buf, path->len, simplify))\n+\tif (simplify_away(path->buf, path->len, pathspec))\n \t\treturn path_none;\n \n \tdtype = DTYPE(de);\n-\treturn treat_one_path(dir, untracked, path, baselen, simplify, dtype, de);\n+\treturn treat_one_path(dir, untracked, path, baselen, pathspec, dtype, de);\n }\n \n static void add_untracked(struct untracked_cache_dir *dir, const char *name)\n@@ -1703,7 +1723,7 @@ static void close_cached_dir(struct cached_dir *cdir)\n static enum path_treatment read_directory_recursive(struct dir_struct *dir,\n \t\t\t\t    const char *base, int baselen,\n \t\t\t\t    struct untracked_cache_dir *untracked, int check_only,\n-\t\t\t\t    const struct path_simplify *simplify)\n+\t\t\t\t    const struct pathspec *pathspec)\n {\n \tstruct cached_dir cdir;\n \tenum path_treatment state, subdir_state, dir_state = path_none;\n@@ -1719,7 +1739,8 @@ static enum path_treatment read_directory_recursive(struct dir_struct *dir,\n \n \twhile (!read_cached_dir(&cdir)) {\n \t\t/* check how the file or directory should be treated */\n-\t\tstate = treat_path(dir, untracked, &cdir, &path, baselen, simplify);\n+\t\tstate = treat_path(dir, untracked, &cdir, &path,\n+\t\t\t\t   baselen, pathspec);\n \n \t\tif (state > dir_state)\n \t\t\tdir_state = state;\n@@ -1731,8 +1752,9 @@ static enum path_treatment read_directory_recursive(struct dir_struct *dir,\n \t\t\t\t\t      path.buf + baselen,\n \t\t\t\t\t      path.len - baselen);\n \t\t\tsubdir_state =\n-\t\t\t\tread_directory_recursive(dir, path.buf, path.len,\n-\t\t\t\t\t\t\t ud, check_only, simplify);\n+\t\t\t\tread_directory_recursive(dir, path.buf,\n+\t\t\t\t\t\t\t path.len, ud,\n+\t\t\t\t\t\t\t check_only, pathspec);\n \t\t\tif (subdir_state > dir_state)\n \t\t\t\tdir_state = subdir_state;\n \t\t}\n@@ -1756,7 +1778,7 @@ static enum path_treatment read_directory_recursive(struct dir_struct *dir,\n \t\t\telse if ((dir->flags & DIR_SHOW_IGNORED_TOO) ||\n \t\t\t\t((dir->flags & DIR_COLLECT_IGNORED) &&\n \t\t\t\texclude_matches_pathspec(path.buf, path.len,\n-\t\t\t\t\tsimplify)))\n+\t\t\t\t\t\t\t pathspec)))\n \t\t\t\tdir_add_ignored(dir, path.buf, path.len);\n \t\t\tbreak;\n \n@@ -1787,36 +1809,9 @@ static int cmp_name(const void *p1, const void *p2)\n \treturn name_compare(e1->name, e1->len, e2->name, e2->len);\n }\n \n-static struct path_simplify *create_simplify(const char **pathspec)\n-{\n-\tint nr, alloc = 0;\n-\tstruct path_simplify *simplify = NULL;\n-\n-\tif (!pathspec)\n-\t\treturn NULL;\n-\n-\tfor (nr = 0 ; ; nr++) {\n-\t\tconst char *match;\n-\t\tALLOC_GROW(simplify, nr + 1, alloc);\n-\t\tmatch = *pathspec++;\n-\t\tif (!match)\n-\t\t\tbreak;\n-\t\tsimplify[nr].path = match;\n-\t\tsimplify[nr].len = simple_length(match);\n-\t}\n-\tsimplify[nr].path = NULL;\n-\tsimplify[nr].len = 0;\n-\treturn simplify;\n-}\n-\n-static void free_simplify(struct path_simplify *simplify)\n-{\n-\tfree(simplify);\n-}\n-\n static int treat_leading_path(struct dir_struct *dir,\n \t\t\t      const char *path, int len,\n-\t\t\t      const struct path_simplify *simplify)\n+\t\t\t      const struct pathspec *pathspec)\n {\n \tstruct strbuf sb = STRBUF_INIT;\n \tint baselen, rc = 0;\n@@ -1840,9 +1835,9 @@ static int treat_leading_path(struct dir_struct *dir,\n \t\tstrbuf_add(&sb, path, baselen);\n \t\tif (!is_directory(sb.buf))\n \t\t\tbreak;\n-\t\tif (simplify_away(sb.buf, sb.len, simplify))\n+\t\tif (simplify_away(sb.buf, sb.len, pathspec))\n \t\t\tbreak;\n-\t\tif (treat_one_path(dir, NULL, &sb, baselen, simplify,\n+\t\tif (treat_one_path(dir, NULL, &sb, baselen, pathspec,\n \t\t\t\t   DT_DIR, NULL) == path_none)\n \t\t\tbreak; /* do not recurse into it */\n \t\tif (len <= baselen) {\n@@ -2010,33 +2005,14 @@ static struct untracked_cache_dir *validate_untracked_cache(struct dir_struct *d\n \treturn root;\n }\n \n-int read_directory(struct dir_struct *dir, const char *path, int len, const struct pathspec *pathspec)\n+int read_directory(struct dir_struct *dir, const char *path,\n+\t\t   int len, const struct pathspec *pathspec)\n {\n-\tstruct path_simplify *simplify;\n \tstruct untracked_cache_dir *untracked;\n \n-\t/*\n-\t * Check out create_simplify()\n-\t */\n-\tif (pathspec)\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_GLOB |\n-\t\t\t       PATHSPEC_ICASE |\n-\t\t\t       PATHSPEC_EXCLUDE);\n-\n \tif (has_symlink_leading_path(path, len))\n \t\treturn dir->nr;\n \n-\t/*\n-\t * exclude patterns are treated like positive ones in\n-\t * create_simplify. Usually exclude patterns should be a\n-\t * subset of positive ones, which has no impacts on\n-\t * create_simplify().\n-\t */\n-\tsimplify = create_simplify(pathspec ? pathspec->_raw : NULL);\n \tuntracked = validate_untracked_cache(dir, len, pathspec);\n \tif (!untracked)\n \t\t/*\n@@ -2044,9 +2020,8 @@ int read_directory(struct dir_struct *dir, const char *path, int len, const stru\n \t\t * e.g. prep_exclude()\n \t\t */\n \t\tdir->untracked = NULL;\n-\tif (!len || treat_leading_path(dir, path, len, simplify))\n-\t\tread_directory_recursive(dir, path, len, untracked, 0, simplify);\n-\tfree_simplify(simplify);\n+\tif (!len || treat_leading_path(dir, path, len, pathspec))\n+\t\tread_directory_recursive(dir, path, len, untracked, 0, pathspec);\n \tQSORT(dir->entries, dir->nr, cmp_name);\n \tQSORT(dir->ignored, dir->ignored_nr, cmp_name);\n \tif (dir->untracked) {\n-- \n2.11.0.390.gc69c2f50cf-goog\n\n"},{"id":"308735","messageId":"20170103184241.128409-13-bmwill@google.com","threadId":"44632","inReplyTo":"20170103184241.128409-1-bmwill@google.com","subject":"[PATCH v4 12/16] pathspec: create parse_long_magic function","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-01-03T18:42:37Z","receivedAt":"2017-01-03T19:13:37Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Factor out the logic responsible for parsing long magic into its own\nfunction.  As well as hoist the prefix check logic outside of the inner\nloop as there isn't anything that needs to be done after matching\n\"prefix:\".\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n pathspec.c | 92 ++++++++++++++++++++++++++++++++++++++------------------------\n 1 file changed, 57 insertions(+), 35 deletions(-)\n\ndiff --git a/pathspec.c b/pathspec.c\nindex 8574010d5..f1439f6f9 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -157,6 +157,60 @@ static int get_global_magic(int element_magic)\n }\n \n /*\n+ * Parse the pathspec element looking for long magic\n+ *\n+ * saves all magic in 'magic'\n+ * if prefix magic is used, save the prefix length in 'prefix_len'\n+ * returns the position in 'elem' after all magic has been parsed\n+ */\n+static const char *parse_long_magic(unsigned *magic, int *prefix_len,\n+\t\t\t\t    const char *elem)\n+{\n+\tconst char *pos;\n+\tconst char *nextat;\n+\n+\tfor (pos = elem + 2; *pos && *pos != ')'; pos = nextat) {\n+\t\tsize_t len = strcspn(pos, \",)\");\n+\t\tint i;\n+\n+\t\tif (pos[len] == ',')\n+\t\t\tnextat = pos + len + 1; /* handle ',' */\n+\t\telse\n+\t\t\tnextat = pos + len; /* handle ')' and '\\0' */\n+\n+\t\tif (!len)\n+\t\t\tcontinue;\n+\n+\t\tif (starts_with(pos, \"prefix:\")) {\n+\t\t\tchar *endptr;\n+\t\t\t*prefix_len = strtol(pos + 7, &endptr, 10);\n+\t\t\tif (endptr - pos != len)\n+\t\t\t\tdie(_(\"invalid parameter for pathspec magic 'prefix'\"));\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\tfor (i = 0; i < ARRAY_SIZE(pathspec_magic); i++) {\n+\t\t\tif (strlen(pathspec_magic[i].name) == len &&\n+\t\t\t    !strncmp(pathspec_magic[i].name, pos, len)) {\n+\t\t\t\t*magic |= pathspec_magic[i].bit;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t}\n+\n+\t\tif (ARRAY_SIZE(pathspec_magic) <= i)\n+\t\t\tdie(_(\"Invalid pathspec magic '%.*s' in '%s'\"),\n+\t\t\t    (int) len, pos, elem);\n+\t}\n+\n+\tif (*pos != ')')\n+\t\tdie(_(\"Missing ')' at the end of pathspec magic in '%s'\"),\n+\t\t    elem);\n+\tpos++;\n+\n+\treturn pos;\n+}\n+\n+/*\n  * Parse the pathspec element looking for short magic\n  *\n  * saves all magic in 'magic'\n@@ -218,41 +272,9 @@ static unsigned prefix_pathspec(struct pathspec_item *item, unsigned flags,\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 + 1;\n-\t\t\telse\n-\t\t\t\t/* handle ')' and '\\0' */\n-\t\t\t\tnextat = copyfrom + len;\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\telement_magic |= pathspec_magic[i].bit;\n-\t\t\t\t\tbreak;\n-\t\t\t\t}\n-\t\t\t\tif (starts_with(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\tcopyfrom++;\n+\t\tcopyfrom = parse_long_magic(&element_magic,\n+\t\t\t\t\t    &pathspec_prefix,\n+\t\t\t\t\t    elt);\n \t} else {\n \t\t/* shorthand */\n \t\tcopyfrom = parse_short_magic(&element_magic, elt);\n-- \n2.11.0.390.gc69c2f50cf-goog\n\n"},{"id":"308736","messageId":"20170103184241.128409-17-bmwill@google.com","threadId":"44632","inReplyTo":"20170103184241.128409-1-bmwill@google.com","subject":"[PATCH v4 16/16] pathspec: rename prefix_pathspec to init_pathspec_item","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-01-03T18:42:41Z","receivedAt":"2017-01-03T19:17:37Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Give a more relevant name to the prefix_pathspec function as it does\nmore than just prefix a pathspec element.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n pathspec.c | 24 +++++++-----------------\n 1 file changed, 7 insertions(+), 17 deletions(-)\n\ndiff --git a/pathspec.c b/pathspec.c\nindex ae9e1401f..bcf3ba039 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -297,21 +297,11 @@ static void strip_submodule_slash_expensive(struct pathspec_item *item)\n }\n \n /*\n- * Take an element of a pathspec and check for magic signatures.\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- *\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+ * Perform the initialization of a pathspec_item based on a pathspec element.\n  */\n-static unsigned prefix_pathspec(struct pathspec_item *item, unsigned flags,\n-\t\t\t\tconst char *prefix, int prefixlen,\n-\t\t\t\tconst char *elt)\n+static void init_pathspec_item(struct pathspec_item *item, unsigned flags,\n+\t\t\t       const char *prefix, int prefixlen,\n+\t\t\t       const char *elt)\n {\n \tunsigned magic = 0, element_magic = 0;\n \tconst char *copyfrom = elt;\n@@ -329,6 +319,8 @@ static unsigned prefix_pathspec(struct pathspec_item *item, unsigned flags,\n \t\tmagic |= get_global_magic(element_magic);\n \t}\n \n+\titem->magic = 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@@ -401,7 +393,6 @@ static unsigned prefix_pathspec(struct pathspec_item *item, unsigned flags,\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 static int pathspec_item_cmp(const void *a_, const void *b_)\n@@ -501,8 +492,7 @@ void parse_pathspec(struct pathspec *pathspec,\n \tfor (i = 0; i < n; i++) {\n \t\tentry = argv[i];\n \n-\t\titem[i].magic = prefix_pathspec(item + i, flags,\n-\t\t\t\t\t\tprefix, prefixlen, entry);\n+\t\tinit_pathspec_item(item + i, flags, prefix, prefixlen, entry);\n \n \t\tif (item[i].magic & PATHSPEC_EXCLUDE)\n \t\t\tnr_exclude++;\n-- \n2.11.0.390.gc69c2f50cf-goog\n\n"},{"id":"308772","messageId":"CACsJy8C=SC+gE1HQeGdE5z3+S8RHwiM-4ZXBzuwvN=+COUGNzg@mail.gmail.com","threadId":"44632","inReplyTo":"20170103184241.128409-1-bmwill@google.com","subject":"Re: [PATCH v4 00/16] pathspec cleanup","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2017-01-04T13:56:28Z","receivedAt":"2017-01-04T13:58:23Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Wed, Jan 4, 2017 at 1:42 AM, Brandon Williams <bmwill@google.com> wrote:\n> diff --git a/dir.c b/dir.c\n> index 15f7c9993..e8ddd7f8a 100644\n> --- a/dir.c\n> +++ b/dir.c\n> @@ -1353,6 +1353,15 @@ static int simplify_away(const char *path, int pathlen,\n>  {\n>         int i;\n>\n> +       if (pathspec)\n> +               guard_pathspec(pathspec,\n> +                              pathspec_fromtop |\n> +                              pathspec_maxdepth |\n> +                              pathspec_literal |\n> +                              pathspec_glob |\n> +                              pathspec_icase |\n> +                              pathspec_exclude);\n\nYou have done some magic (or your MTA/editor did) to lower case\nGUARD_PATHSPEC and all the flags. The real patch looks good though, so\nno problem.\n\n> +\n>         if (!pathspec || !pathspec->nr)\n>                 return 0;\n\n\nSuper tiny nit, if GUARD_PATHSPEC is placed after this line, then we\ndon't have to check if pathspec is non-NULL. Probably not worth a\nre-roll unless somebody else finds something else.\n\n>                 if (m->mnemonic)\n> -                       strbuf_addf(&sb, \"'(%c)%s'\", m->mnemonic, m->name);\n> +                       strbuf_addf(&sb, \"'%s' (mnemonic: '%c')\",\n> +                                   m->name, m->mnemonic);\n\n.. and that somebody might be me :) we need to mark \"mnemonic\" for\ntranslation. Putting _() around the string would do.\n\nIdeally I would give the translators the whole sentence so they can\nhave good context (and good translation as a result). But since we\npotentially concatenate multiple unsupported magic in the string,\nthere's no way to provide one (or a few) fixed string(s) at compile\ntime. So let's just _() it and leave it at that.\n-- \nDuy\n"},{"id":"308774","messageId":"20170104175347.GA69227@google.com","threadId":"44632","inReplyTo":"CACsJy8C=SC+gE1HQeGdE5z3+S8RHwiM-4ZXBzuwvN=+COUGNzg@mail.gmail.com","subject":"Re: [PATCH v4 00/16] pathspec cleanup","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-01-04T17:53:47Z","receivedAt":"2017-01-04T17:54:03Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"On 01/04, Duy Nguyen wrote:\n> On Wed, Jan 4, 2017 at 1:42 AM, Brandon Williams <bmwill@google.com> wrote:\n> > diff --git a/dir.c b/dir.c\n> > index 15f7c9993..e8ddd7f8a 100644\n> > --- a/dir.c\n> > +++ b/dir.c\n> > @@ -1353,6 +1353,15 @@ static int simplify_away(const char *path, int pathlen,\n> >  {\n> >         int i;\n> >\n> > +       if (pathspec)\n> > +               guard_pathspec(pathspec,\n> > +                              pathspec_fromtop |\n> > +                              pathspec_maxdepth |\n> > +                              pathspec_literal |\n> > +                              pathspec_glob |\n> > +                              pathspec_icase |\n> > +                              pathspec_exclude);\n> \n> You have done some magic (or your MTA/editor did) to lower case\n> GUARD_PATHSPEC and all the flags. The real patch looks good though, so\n> no problem.\n\nThat's really odd, I was sure I just did a cut and paste.  I'll fix that\n:)\n\n> \n> > +\n> >         if (!pathspec || !pathspec->nr)\n> >                 return 0;\n> \n> \n> Super tiny nit, if GUARD_PATHSPEC is placed after this line, then we\n> don't have to check if pathspec is non-NULL. Probably not worth a\n> re-roll unless somebody else finds something else.\n\nI saw this after I sent out the series again, and I agree.  I'll move\nthe guard to be after this check.\n\n> \n> >                 if (m->mnemonic)\n> > -                       strbuf_addf(&sb, \"'(%c)%s'\", m->mnemonic, m->name);\n> > +                       strbuf_addf(&sb, \"'%s' (mnemonic: '%c')\",\n> > +                                   m->name, m->mnemonic);\n> \n> .. and that somebody might be me :) we need to mark \"mnemonic\" for\n> translation. Putting _() around the string would do.\n> \n> Ideally I would give the translators the whole sentence so they can\n> have good context (and good translation as a result). But since we\n> potentially concatenate multiple unsupported magic in the string,\n> there's no way to provide one (or a few) fixed string(s) at compile\n> time. So let's just _() it and leave it at that.\n\nWill do!\n\n-- \nBrandon Williams\n"},{"id":"308775","messageId":"20170104175608.GB69227@google.com","threadId":"44632","inReplyTo":"20170104175347.GA69227@google.com","subject":"Re: [PATCH v4 00/16] pathspec cleanup","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-01-04T17:56:08Z","receivedAt":"2017-01-04T17:56:24Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"On 01/04, Brandon Williams wrote:\n> On 01/04, Duy Nguyen wrote:\n> > On Wed, Jan 4, 2017 at 1:42 AM, Brandon Williams <bmwill@google.com> wrote:\n> > > diff --git a/dir.c b/dir.c\n> > > index 15f7c9993..e8ddd7f8a 100644\n> > > --- a/dir.c\n> > > +++ b/dir.c\n> > > @@ -1353,6 +1353,15 @@ static int simplify_away(const char *path, int pathlen,\n> > >  {\n> > >         int i;\n> > >\n> > > +       if (pathspec)\n> > > +               guard_pathspec(pathspec,\n> > > +                              pathspec_fromtop |\n> > > +                              pathspec_maxdepth |\n> > > +                              pathspec_literal |\n> > > +                              pathspec_glob |\n> > > +                              pathspec_icase |\n> > > +                              pathspec_exclude);\n> > \n> > You have done some magic (or your MTA/editor did) to lower case\n> > GUARD_PATHSPEC and all the flags. The real patch looks good though, so\n> > no problem.\n> \n> That's really odd, I was sure I just did a cut and paste.  I'll fix that\n> :)\n\nSo it looks like what ever I did to insert this into the cover letter\nmade everything lower case.  The actual patch itself looks fine.\n\n-- \nBrandon Williams\n"},{"id":"308776","messageId":"20170104180411.150000-16-bmwill@google.com","threadId":"44632","inReplyTo":"20170104180411.150000-1-bmwill@google.com","subject":"[PATCH v5 15/16] pathspec: small readability changes","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-01-04T18:04:10Z","receivedAt":"2017-01-04T18:04:52Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"A few small changes to improve readability.  This is done by grouping related\nassignments, adding blank lines, ensuring lines are <80 characters, and\nadding additional comments.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n pathspec.c | 25 +++++++++++++++----------\n 1 file changed, 15 insertions(+), 10 deletions(-)\n\ndiff --git a/pathspec.c b/pathspec.c\nindex f3a7a1d33..e53530e7a 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -67,11 +67,11 @@ static struct pathspec_magic {\n \tchar mnemonic; /* this cannot be ':'! */\n \tconst char *name;\n } pathspec_magic[] = {\n-\t{ PATHSPEC_FROMTOP, '/', \"top\" },\n-\t{ PATHSPEC_LITERAL,   0, \"literal\" },\n-\t{ PATHSPEC_GLOB,   '\\0', \"glob\" },\n-\t{ PATHSPEC_ICASE,  '\\0', \"icase\" },\n-\t{ PATHSPEC_EXCLUDE, '!', \"exclude\" },\n+\t{ PATHSPEC_FROMTOP,  '/', \"top\" },\n+\t{ PATHSPEC_LITERAL, '\\0', \"literal\" },\n+\t{ PATHSPEC_GLOB,    '\\0', \"glob\" },\n+\t{ PATHSPEC_ICASE,   '\\0', \"icase\" },\n+\t{ PATHSPEC_EXCLUDE,  '!', \"exclude\" },\n };\n \n static void prefix_magic(struct strbuf *sb, int prefixlen, unsigned magic)\n@@ -336,6 +336,7 @@ static unsigned prefix_pathspec(struct pathspec_item *item, unsigned flags,\n \tif ((magic & PATHSPEC_LITERAL) && (magic & PATHSPEC_GLOB))\n \t\tdie(_(\"%s: 'literal' and 'glob' are incompatible\"), elt);\n \n+\t/* Create match string which will be used for pathspec matching */\n \tif (pathspec_prefix >= 0) {\n \t\tmatch = xstrdup(copyfrom);\n \t\tprefixlen = pathspec_prefix;\n@@ -343,11 +344,16 @@ static unsigned prefix_pathspec(struct pathspec_item *item, unsigned flags,\n \t\tmatch = xstrdup(copyfrom);\n \t\tprefixlen = 0;\n \t} else {\n-\t\tmatch = prefix_path_gently(prefix, prefixlen, &prefixlen, copyfrom);\n+\t\tmatch = prefix_path_gently(prefix, prefixlen,\n+\t\t\t\t\t   &prefixlen, copyfrom);\n \t\tif (!match)\n \t\t\tdie(_(\"%s: '%s' is outside repository\"), elt, copyfrom);\n \t}\n+\n \titem->match = match;\n+\titem->len = strlen(item->match);\n+\titem->prefix = prefixlen;\n+\n \t/*\n \t * Prefix the pathspec (keep all magic) and assign to\n \t * original. Useful for passing to another command.\n@@ -364,8 +370,6 @@ static unsigned prefix_pathspec(struct pathspec_item *item, unsigned flags,\n \t} else {\n \t\titem->original = xstrdup(elt);\n \t}\n-\titem->len = strlen(item->match);\n-\titem->prefix = prefixlen;\n \n \tif (flags & PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP)\n \t\tstrip_submodule_slash_cheap(item);\n@@ -373,13 +377,14 @@ static unsigned prefix_pathspec(struct pathspec_item *item, unsigned flags,\n \tif (flags & PATHSPEC_STRIP_SUBMODULE_SLASH_EXPENSIVE)\n \t\tstrip_submodule_slash_expensive(item);\n \n-\tif (magic & PATHSPEC_LITERAL)\n+\tif (magic & PATHSPEC_LITERAL) {\n \t\titem->nowildcard_len = item->len;\n-\telse {\n+\t} else {\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+\n \titem->flags = 0;\n \tif (magic & PATHSPEC_GLOB) {\n \t\t/*\n-- \n2.11.0.390.gc69c2f50cf-goog\n\n"},{"id":"308777","messageId":"20170104180411.150000-14-bmwill@google.com","threadId":"44632","inReplyTo":"20170104180411.150000-1-bmwill@google.com","subject":"[PATCH v5 13/16] pathspec: create parse_element_magic helper","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-01-04T18:04:08Z","receivedAt":"2017-01-04T18:04:56Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Factor out the logic responsible for the magic in a pathspec element\ninto its own function.\n\nAlso avoid calling into the parsing functions when\n`PATHSPEC_LITERAL_PATH` is specified since it causes magic to be\nignored and all paths to be treated as literals.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n pathspec.c | 37 ++++++++++++++++++++-----------------\n 1 file changed, 20 insertions(+), 17 deletions(-)\n\ndiff --git a/pathspec.c b/pathspec.c\nindex f6356bde1..00fcae4e1 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -245,6 +245,19 @@ static const char *parse_short_magic(unsigned *magic, const char *elem)\n \treturn pos;\n }\n \n+static const char *parse_element_magic(unsigned *magic, int *prefix_len,\n+\t\t\t\t       const char *elem)\n+{\n+\tif (elem[0] != ':' || get_literal_global())\n+\t\treturn elem; /* nothing to do */\n+\telse if (elem[1] == '(')\n+\t\t/* longhand */\n+\t\treturn parse_long_magic(magic, prefix_len, elem);\n+\telse\n+\t\t/* shorthand */\n+\t\treturn parse_short_magic(magic, elem);\n+}\n+\n /*\n  * Take an element of a pathspec and check for magic signatures.\n  * Append the result to the prefix. Return the magic bitmap.\n@@ -267,26 +280,16 @@ static unsigned prefix_pathspec(struct pathspec_item *item, unsigned flags,\n \tchar *match;\n \tint i, pathspec_prefix = -1;\n \n-\tif (elt[0] != ':' || get_literal_global() ||\n-\t    (flags & PATHSPEC_LITERAL_PATH)) {\n-\t\t; /* nothing to do */\n-\t} else if (elt[1] == '(') {\n-\t\t/* longhand */\n-\t\tcopyfrom = parse_long_magic(&element_magic,\n-\t\t\t\t\t    &pathspec_prefix,\n-\t\t\t\t\t    elt);\n-\t} else {\n-\t\t/* shorthand */\n-\t\tcopyfrom = parse_short_magic(&element_magic, elt);\n-\t}\n-\n-\tmagic |= element_magic;\n-\n \t/* PATHSPEC_LITERAL_PATH ignores magic */\n-\tif (flags & PATHSPEC_LITERAL_PATH)\n+\tif (flags & PATHSPEC_LITERAL_PATH) {\n \t\tmagic = PATHSPEC_LITERAL;\n-\telse\n+\t} else {\n+\t\tcopyfrom = parse_element_magic(&element_magic,\n+\t\t\t\t\t       &pathspec_prefix,\n+\t\t\t\t\t       elt);\n+\t\tmagic |= element_magic;\n \t\tmagic |= get_global_magic(element_magic);\n+\t}\n \n \tif (pathspec_prefix >= 0 &&\n \t    (prefixlen || (prefix && *prefix)))\n-- \n2.11.0.390.gc69c2f50cf-goog\n\n"},{"id":"308778","messageId":"20170104180411.150000-13-bmwill@google.com","threadId":"44632","inReplyTo":"20170104180411.150000-1-bmwill@google.com","subject":"[PATCH v5 12/16] pathspec: create parse_long_magic function","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-01-04T18:04:07Z","receivedAt":"2017-01-04T18:04:59Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Factor out the logic responsible for parsing long magic into its own\nfunction.  As well as hoist the prefix check logic outside of the inner\nloop as there isn't anything that needs to be done after matching\n\"prefix:\".\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n pathspec.c | 92 ++++++++++++++++++++++++++++++++++++++------------------------\n 1 file changed, 57 insertions(+), 35 deletions(-)\n\ndiff --git a/pathspec.c b/pathspec.c\nindex 1b0901848..f6356bde1 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -157,6 +157,60 @@ static int get_global_magic(int element_magic)\n }\n \n /*\n+ * Parse the pathspec element looking for long magic\n+ *\n+ * saves all magic in 'magic'\n+ * if prefix magic is used, save the prefix length in 'prefix_len'\n+ * returns the position in 'elem' after all magic has been parsed\n+ */\n+static const char *parse_long_magic(unsigned *magic, int *prefix_len,\n+\t\t\t\t    const char *elem)\n+{\n+\tconst char *pos;\n+\tconst char *nextat;\n+\n+\tfor (pos = elem + 2; *pos && *pos != ')'; pos = nextat) {\n+\t\tsize_t len = strcspn(pos, \",)\");\n+\t\tint i;\n+\n+\t\tif (pos[len] == ',')\n+\t\t\tnextat = pos + len + 1; /* handle ',' */\n+\t\telse\n+\t\t\tnextat = pos + len; /* handle ')' and '\\0' */\n+\n+\t\tif (!len)\n+\t\t\tcontinue;\n+\n+\t\tif (starts_with(pos, \"prefix:\")) {\n+\t\t\tchar *endptr;\n+\t\t\t*prefix_len = strtol(pos + 7, &endptr, 10);\n+\t\t\tif (endptr - pos != len)\n+\t\t\t\tdie(_(\"invalid parameter for pathspec magic 'prefix'\"));\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\tfor (i = 0; i < ARRAY_SIZE(pathspec_magic); i++) {\n+\t\t\tif (strlen(pathspec_magic[i].name) == len &&\n+\t\t\t    !strncmp(pathspec_magic[i].name, pos, len)) {\n+\t\t\t\t*magic |= pathspec_magic[i].bit;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t}\n+\n+\t\tif (ARRAY_SIZE(pathspec_magic) <= i)\n+\t\t\tdie(_(\"Invalid pathspec magic '%.*s' in '%s'\"),\n+\t\t\t    (int) len, pos, elem);\n+\t}\n+\n+\tif (*pos != ')')\n+\t\tdie(_(\"Missing ')' at the end of pathspec magic in '%s'\"),\n+\t\t    elem);\n+\tpos++;\n+\n+\treturn pos;\n+}\n+\n+/*\n  * Parse the pathspec element looking for short magic\n  *\n  * saves all magic in 'magic'\n@@ -218,41 +272,9 @@ static unsigned prefix_pathspec(struct pathspec_item *item, unsigned flags,\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 + 1;\n-\t\t\telse\n-\t\t\t\t/* handle ')' and '\\0' */\n-\t\t\t\tnextat = copyfrom + len;\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\telement_magic |= pathspec_magic[i].bit;\n-\t\t\t\t\tbreak;\n-\t\t\t\t}\n-\t\t\t\tif (starts_with(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\tcopyfrom++;\n+\t\tcopyfrom = parse_long_magic(&element_magic,\n+\t\t\t\t\t    &pathspec_prefix,\n+\t\t\t\t\t    elt);\n \t} else {\n \t\t/* shorthand */\n \t\tcopyfrom = parse_short_magic(&element_magic, elt);\n-- \n2.11.0.390.gc69c2f50cf-goog\n\n"},{"id":"308779","messageId":"20170104180411.150000-11-bmwill@google.com","threadId":"44632","inReplyTo":"20170104180411.150000-1-bmwill@google.com","subject":"[PATCH v5 10/16] pathspec: factor global magic into its own function","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-01-04T18:04:05Z","receivedAt":"2017-01-04T18:05:25Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Create helper functions to read the global magic environment variables\nin additon to factoring out the global magic gathering logic into its\nown function.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n pathspec.c | 127 +++++++++++++++++++++++++++++++++++++------------------------\n 1 file changed, 78 insertions(+), 49 deletions(-)\n\ndiff --git a/pathspec.c b/pathspec.c\nindex af7f2d01d..77df55da6 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -87,6 +87,75 @@ static void prefix_magic(struct strbuf *sb, int prefixlen, unsigned magic)\n \tstrbuf_addf(sb, \",prefix:%d)\", prefixlen);\n }\n \n+static inline int get_literal_global(void)\n+{\n+\tstatic int literal = -1;\n+\n+\tif (literal < 0)\n+\t\tliteral = git_env_bool(GIT_LITERAL_PATHSPECS_ENVIRONMENT, 0);\n+\n+\treturn literal;\n+}\n+\n+static inline int get_glob_global(void)\n+{\n+\tstatic int glob = -1;\n+\n+\tif (glob < 0)\n+\t\tglob = git_env_bool(GIT_GLOB_PATHSPECS_ENVIRONMENT, 0);\n+\n+\treturn glob;\n+}\n+\n+static inline int get_noglob_global(void)\n+{\n+\tstatic int noglob = -1;\n+\n+\tif (noglob < 0)\n+\t\tnoglob = git_env_bool(GIT_NOGLOB_PATHSPECS_ENVIRONMENT, 0);\n+\n+\treturn noglob;\n+}\n+\n+static inline int get_icase_global(void)\n+{\n+\tstatic int icase = -1;\n+\n+\tif (icase < 0)\n+\t\ticase = git_env_bool(GIT_ICASE_PATHSPECS_ENVIRONMENT, 0);\n+\n+\treturn icase;\n+}\n+\n+static int get_global_magic(int element_magic)\n+{\n+\tint global_magic = 0;\n+\n+\tif (get_literal_global())\n+\t\tglobal_magic |= PATHSPEC_LITERAL;\n+\n+\t/* --glob-pathspec is overridden by :(literal) */\n+\tif (get_glob_global() && !(element_magic & PATHSPEC_LITERAL))\n+\t\tglobal_magic |= PATHSPEC_GLOB;\n+\n+\tif (get_glob_global() && get_noglob_global())\n+\t\tdie(_(\"global 'glob' and 'noglob' pathspec settings are incompatible\"));\n+\n+\tif (get_icase_global())\n+\t\tglobal_magic |= PATHSPEC_ICASE;\n+\n+\tif ((global_magic & PATHSPEC_LITERAL) &&\n+\t    (global_magic & ~PATHSPEC_LITERAL))\n+\t\tdie(_(\"global 'literal' pathspec setting is incompatible \"\n+\t\t      \"with all other global pathspec settings\"));\n+\n+\t/* --noglob-pathspec adds :(literal) _unless_ :(glob) is specified */\n+\tif (get_noglob_global() && !(element_magic & PATHSPEC_GLOB))\n+\t\tglobal_magic |= PATHSPEC_LITERAL;\n+\n+\treturn global_magic;\n+}\n+\n /*\n  * Take an element of a pathspec and check for magic signatures.\n  * Append the result to the prefix. Return the magic bitmap.\n@@ -104,46 +173,12 @@ static unsigned prefix_pathspec(struct pathspec_item *item, unsigned flags,\n \t\t\t\tconst char *prefix, int prefixlen,\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-\tstatic int icase_global = -1;\n-\tunsigned magic = 0, element_magic = 0, global_magic = 0;\n+\tunsigned magic = 0, element_magic = 0;\n \tconst char *copyfrom = elt;\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 (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-\n-\tif (icase_global < 0)\n-\t\ticase_global = git_env_bool(GIT_ICASE_PATHSPECS_ENVIRONMENT, 0);\n-\tif (icase_global)\n-\t\tglobal_magic |= PATHSPEC_ICASE;\n-\n-\tif ((global_magic & PATHSPEC_LITERAL) &&\n-\t    (global_magic & ~PATHSPEC_LITERAL))\n-\t\tdie(_(\"global 'literal' pathspec setting is incompatible \"\n-\t\t      \"with all other global pathspec settings\"));\n-\n-\tif (flags & PATHSPEC_LITERAL_PATH)\n-\t\tglobal_magic = 0;\n-\n-\tif (elt[0] != ':' || literal_global ||\n+\tif (elt[0] != ':' || get_literal_global() ||\n \t    (flags & PATHSPEC_LITERAL_PATH)) {\n \t\t; /* nothing to do */\n \t} else if (elt[1] == '(') {\n@@ -207,15 +242,11 @@ static unsigned prefix_pathspec(struct pathspec_item *item, unsigned flags,\n \n \tmagic |= element_magic;\n \n-\t/* --noglob-pathspec adds :(literal) _unless_ :(glob) is specified */\n-\tif (noglob_global && !(magic & PATHSPEC_GLOB))\n-\t\tglobal_magic |= PATHSPEC_LITERAL;\n-\n-\t/* --glob-pathspec is overridden by :(literal) */\n-\tif ((global_magic & PATHSPEC_GLOB) && (magic & PATHSPEC_LITERAL))\n-\t\tglobal_magic &= ~PATHSPEC_GLOB;\n-\n-\tmagic |= global_magic;\n+\t/* PATHSPEC_LITERAL_PATH ignores magic */\n+\tif (flags & PATHSPEC_LITERAL_PATH)\n+\t\tmagic = PATHSPEC_LITERAL;\n+\telse\n+\t\tmagic |= get_global_magic(element_magic);\n \n \tif (pathspec_prefix >= 0 &&\n \t    (prefixlen || (prefix && *prefix)))\n@@ -241,7 +272,7 @@ static unsigned prefix_pathspec(struct pathspec_item *item, unsigned flags,\n \t * original. Useful for passing to another command.\n \t */\n \tif ((flags & PATHSPEC_PREFIX_ORIGIN) &&\n-\t    prefixlen && !literal_global) {\n+\t    prefixlen && !get_literal_global()) {\n \t\tstruct strbuf sb = STRBUF_INIT;\n \n \t\t/* Preserve the actual prefix length of each pattern */\n@@ -408,9 +439,7 @@ void parse_pathspec(struct pathspec *pathspec,\n \n \t\titem[i].magic = prefix_pathspec(item + i, flags,\n \t\t\t\t\t\tprefix, prefixlen, entry);\n-\t\tif ((flags & PATHSPEC_LITERAL_PATH) &&\n-\t\t    !(magic_mask & PATHSPEC_LITERAL))\n-\t\t\titem[i].magic |= PATHSPEC_LITERAL;\n+\n \t\tif (item[i].magic & PATHSPEC_EXCLUDE)\n \t\t\tnr_exclude++;\n \t\tif (item[i].magic & magic_mask)\n-- \n2.11.0.390.gc69c2f50cf-goog\n\n"},{"id":"308780","messageId":"20170104180411.150000-9-bmwill@google.com","threadId":"44632","inReplyTo":"20170104180411.150000-1-bmwill@google.com","subject":"[PATCH v5 08/16] pathspec: always show mnemonic and name in unsupported_magic","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-01-04T18:04:03Z","receivedAt":"2017-01-04T18:05:29Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"For better clarity, always show the mnemonic and name of the unsupported\nmagic being used.  This lets users have a more clear understanding of\nwhat magic feature isn't supported.  And if they supplied a mnemonic,\nthe user will be told what its corresponding name is which will allow\nthem to more easily search the man pages for that magic type.\n\nThis also avoids passing an extra parameter around the pathspec\ninitialization code.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n pathspec.c | 24 +++++++++---------------\n 1 file changed, 9 insertions(+), 15 deletions(-)\n\ndiff --git a/pathspec.c b/pathspec.c\nindex b9a3819d6..5df364bc6 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -101,9 +101,7 @@ static void prefix_short_magic(struct strbuf *sb, int prefixlen,\n  * the prefix part must always match literally, and a single stupid\n  * string cannot express such a case.\n  */\n-static unsigned prefix_pathspec(struct pathspec_item *item,\n-\t\t\t\tunsigned *p_short_magic,\n-\t\t\t\tunsigned flags,\n+static unsigned prefix_pathspec(struct pathspec_item *item, unsigned flags,\n \t\t\t\tconst char *prefix, int prefixlen,\n \t\t\t\tconst char *elt)\n {\n@@ -210,7 +208,6 @@ static unsigned prefix_pathspec(struct pathspec_item *item,\n \t}\n \n \tmagic |= short_magic;\n-\t*p_short_magic = short_magic;\n \n \t/* --noglob-pathspec adds :(literal) _unless_ :(glob) is specified */\n \tif (noglob_global && !(magic & PATHSPEC_GLOB))\n@@ -329,8 +326,7 @@ static int pathspec_item_cmp(const void *a_, const void *b_)\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+\t\t\t\t       unsigned magic)\n {\n \tstruct strbuf sb = STRBUF_INIT;\n \tint i;\n@@ -339,9 +335,11 @@ static void NORETURN unsupported_magic(const char *pattern,\n \t\tif (!(magic & m->bit))\n \t\t\tcontinue;\n \t\tif (sb.len)\n-\t\t\tstrbuf_addch(&sb, ' ');\n-\t\tif (short_magic & m->bit)\n-\t\t\tstrbuf_addf(&sb, \"'%c'\", m->mnemonic);\n+\t\t\tstrbuf_addstr(&sb, \", \");\n+\n+\t\tif (m->mnemonic)\n+\t\t\tstrbuf_addf(&sb, _(\"'%s' (mnemonic: '%c')\"),\n+\t\t\t\t    m->name, m->mnemonic);\n \t\telse\n \t\t\tstrbuf_addf(&sb, \"'%s'\", m->name);\n \t}\n@@ -413,11 +411,9 @@ void parse_pathspec(struct pathspec *pathspec,\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\tflags,\n+\t\titem[i].magic = prefix_pathspec(item + i, flags,\n \t\t\t\t\t\tprefix, prefixlen, entry);\n \t\tif ((flags & PATHSPEC_LITERAL_PATH) &&\n \t\t    !(magic_mask & PATHSPEC_LITERAL))\n@@ -425,9 +421,7 @@ void parse_pathspec(struct pathspec *pathspec,\n \t\tif (item[i].magic & PATHSPEC_EXCLUDE)\n \t\t\tnr_exclude++;\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\t\tunsupported_magic(entry, item[i].magic & magic_mask);\n \n \t\tif ((flags & PATHSPEC_SYMLINK_LEADING_PATH) &&\n \t\t    has_symlink_leading_path(item[i].match, item[i].len)) {\n-- \n2.11.0.390.gc69c2f50cf-goog\n\n"},{"id":"308781","messageId":"20170104180411.150000-10-bmwill@google.com","threadId":"44632","inReplyTo":"20170104180411.150000-1-bmwill@google.com","subject":"[PATCH v5 09/16] pathspec: simpler logic to prefix original pathspec elements","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-01-04T18:04:04Z","receivedAt":"2017-01-04T18:05:31Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"The logic used to prefix an original pathspec element with 'prefix'\nmagic is more general purpose and can be used for more than just short\nmagic.  Remove the extra code paths and rename 'prefix_short_magic' to\n'prefix_magic' to better indicate that it can be used in more general\nsituations.\n\nAlso, slightly change the logic which decides when to prefix the\noriginal element in order to prevent a pathspec of \".\" from getting\nconverted to \"\" (empty string).\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n pathspec.c | 33 +++++++++++++--------------------\n 1 file changed, 13 insertions(+), 20 deletions(-)\n\ndiff --git a/pathspec.c b/pathspec.c\nindex 5df364bc6..af7f2d01d 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -74,13 +74,12 @@ static struct pathspec_magic {\n \t{ PATHSPEC_EXCLUDE, '!', \"exclude\" },\n };\n \n-static void prefix_short_magic(struct strbuf *sb, int prefixlen,\n-\t\t\t       unsigned short_magic)\n+static void prefix_magic(struct strbuf *sb, int prefixlen, unsigned magic)\n {\n \tint i;\n \tstrbuf_addstr(sb, \":(\");\n \tfor (i = 0; i < ARRAY_SIZE(pathspec_magic); i++)\n-\t\tif (short_magic & pathspec_magic[i].bit) {\n+\t\tif (magic & pathspec_magic[i].bit) {\n \t\t\tif (sb->buf[sb->len - 1] != '(')\n \t\t\t\tstrbuf_addch(sb, ',');\n \t\t\tstrbuf_addstr(sb, pathspec_magic[i].name);\n@@ -109,8 +108,8 @@ static unsigned prefix_pathspec(struct pathspec_item *item, unsigned flags,\n \tstatic int glob_global = -1;\n \tstatic int noglob_global = -1;\n \tstatic int icase_global = -1;\n-\tunsigned magic = 0, short_magic = 0, global_magic = 0;\n-\tconst char *copyfrom = elt, *long_magic_end = NULL;\n+\tunsigned magic = 0, element_magic = 0, global_magic = 0;\n+\tconst char *copyfrom = elt;\n \tchar *match;\n \tint i, pathspec_prefix = -1;\n \n@@ -164,7 +163,7 @@ static unsigned prefix_pathspec(struct pathspec_item *item, unsigned flags,\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\telement_magic |= pathspec_magic[i].bit;\n \t\t\t\t\tbreak;\n \t\t\t\t}\n \t\t\t\tif (starts_with(copyfrom, \"prefix:\")) {\n@@ -183,7 +182,6 @@ static unsigned prefix_pathspec(struct pathspec_item *item, unsigned flags,\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@@ -196,7 +194,7 @@ static unsigned prefix_pathspec(struct pathspec_item *item, unsigned flags,\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\tshort_magic |= pathspec_magic[i].bit;\n+\t\t\t\t\telement_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@@ -207,7 +205,7 @@ static unsigned prefix_pathspec(struct pathspec_item *item, unsigned flags,\n \t\t\tcopyfrom++;\n \t}\n \n-\tmagic |= short_magic;\n+\tmagic |= element_magic;\n \n \t/* --noglob-pathspec adds :(literal) _unless_ :(glob) is specified */\n \tif (noglob_global && !(magic & PATHSPEC_GLOB))\n@@ -242,18 +240,13 @@ static unsigned prefix_pathspec(struct pathspec_item *item, unsigned flags,\n \t * Prefix the pathspec (keep all magic) and assign to\n \t * original. Useful for passing to another command.\n \t */\n-\tif (flags & PATHSPEC_PREFIX_ORIGIN) {\n+\tif ((flags & PATHSPEC_PREFIX_ORIGIN) &&\n+\t    prefixlen && !literal_global) {\n \t\tstruct strbuf sb = STRBUF_INIT;\n-\t\tif (prefixlen && !literal_global) {\n-\t\t\t/* Preserve the actual prefix length of each pattern */\n-\t\t\tif (short_magic)\n-\t\t\t\tprefix_short_magic(&sb, prefixlen, short_magic);\n-\t\t\telse if (long_magic_end) {\n-\t\t\t\tstrbuf_add(&sb, elt, long_magic_end - elt);\n-\t\t\t\tstrbuf_addf(&sb, \",prefix:%d)\", prefixlen);\n-\t\t\t} else\n-\t\t\t\tstrbuf_addf(&sb, \":(prefix:%d)\", prefixlen);\n-\t\t}\n+\n+\t\t/* Preserve the actual prefix length of each pattern */\n+\t\tprefix_magic(&sb, prefixlen, element_magic);\n+\n \t\tstrbuf_addstr(&sb, match);\n \t\titem->original = strbuf_detach(&sb, NULL);\n \t} else {\n-- \n2.11.0.390.gc69c2f50cf-goog\n\n"},{"id":"308782","messageId":"20170104180411.150000-17-bmwill@google.com","threadId":"44632","inReplyTo":"20170104180411.150000-1-bmwill@google.com","subject":"[PATCH v5 16/16] pathspec: rename prefix_pathspec to init_pathspec_item","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-01-04T18:04:11Z","receivedAt":"2017-01-04T18:05:41Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Give a more relevant name to the prefix_pathspec function as it does\nmore than just prefix a pathspec element.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n pathspec.c | 24 +++++++-----------------\n 1 file changed, 7 insertions(+), 17 deletions(-)\n\ndiff --git a/pathspec.c b/pathspec.c\nindex e53530e7a..ff2509ddd 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -297,21 +297,11 @@ static void strip_submodule_slash_expensive(struct pathspec_item *item)\n }\n \n /*\n- * Take an element of a pathspec and check for magic signatures.\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- *\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+ * Perform the initialization of a pathspec_item based on a pathspec element.\n  */\n-static unsigned prefix_pathspec(struct pathspec_item *item, unsigned flags,\n-\t\t\t\tconst char *prefix, int prefixlen,\n-\t\t\t\tconst char *elt)\n+static void init_pathspec_item(struct pathspec_item *item, unsigned flags,\n+\t\t\t       const char *prefix, int prefixlen,\n+\t\t\t       const char *elt)\n {\n \tunsigned magic = 0, element_magic = 0;\n \tconst char *copyfrom = elt;\n@@ -329,6 +319,8 @@ static unsigned prefix_pathspec(struct pathspec_item *item, unsigned flags,\n \t\tmagic |= get_global_magic(element_magic);\n \t}\n \n+\titem->magic = 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@@ -401,7 +393,6 @@ static unsigned prefix_pathspec(struct pathspec_item *item, unsigned flags,\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 static int pathspec_item_cmp(const void *a_, const void *b_)\n@@ -501,8 +492,7 @@ void parse_pathspec(struct pathspec *pathspec,\n \tfor (i = 0; i < n; i++) {\n \t\tentry = argv[i];\n \n-\t\titem[i].magic = prefix_pathspec(item + i, flags,\n-\t\t\t\t\t\tprefix, prefixlen, entry);\n+\t\tinit_pathspec_item(item + i, flags, prefix, prefixlen, entry);\n \n \t\tif (item[i].magic & PATHSPEC_EXCLUDE)\n \t\t\tnr_exclude++;\n-- \n2.11.0.390.gc69c2f50cf-goog\n\n"},{"id":"308783","messageId":"20170104180411.150000-15-bmwill@google.com","threadId":"44632","inReplyTo":"20170104180411.150000-1-bmwill@google.com","subject":"[PATCH v5 14/16] pathspec: create strip submodule slash helpers","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-01-04T18:04:09Z","receivedAt":"2017-01-04T18:05:45Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Factor out the logic responsible for stripping the trailing slash on\npathspecs referencing submodules into its own function.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n pathspec.c | 68 ++++++++++++++++++++++++++++++++++++++------------------------\n 1 file changed, 42 insertions(+), 26 deletions(-)\n\ndiff --git a/pathspec.c b/pathspec.c\nindex 00fcae4e1..f3a7a1d33 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -258,6 +258,44 @@ static const char *parse_element_magic(unsigned *magic, int *prefix_len,\n \t\treturn parse_short_magic(magic, elem);\n }\n \n+static void strip_submodule_slash_cheap(struct pathspec_item *item)\n+{\n+\tif (item->len >= 1 && item->match[item->len - 1] == '/') {\n+\t\tint i = cache_name_pos(item->match, item->len - 1);\n+\n+\t\tif (i >= 0 && S_ISGITLINK(active_cache[i]->ce_mode)) {\n+\t\t\titem->len--;\n+\t\t\titem->match[item->len] = '\\0';\n+\t\t}\n+\t}\n+}\n+\n+static void strip_submodule_slash_expensive(struct pathspec_item *item)\n+{\n+\tint i;\n+\n+\tfor (i = 0; i < active_nr; i++) {\n+\t\tstruct cache_entry *ce = active_cache[i];\n+\t\tint ce_len = ce_namelen(ce);\n+\n+\t\tif (!S_ISGITLINK(ce->ce_mode))\n+\t\t\tcontinue;\n+\n+\t\tif (item->len <= ce_len || item->match[ce_len] != '/' ||\n+\t\t    memcmp(ce->name, item->match, ce_len))\n+\t\t\tcontinue;\n+\n+\t\tif (item->len == ce_len + 1) {\n+\t\t\t/* strip trailing slash */\n+\t\t\titem->len--;\n+\t\t\titem->match[item->len] = '\\0';\n+\t\t} else {\n+\t\t\tdie(_(\"Pathspec '%s' is in submodule '%.*s'\"),\n+\t\t\t    item->original, ce_len, ce->name);\n+\t\t}\n+\t}\n+}\n+\n /*\n  * Take an element of a pathspec and check for magic signatures.\n  * Append the result to the prefix. Return the magic bitmap.\n@@ -278,7 +316,7 @@ static unsigned prefix_pathspec(struct pathspec_item *item, unsigned flags,\n \tunsigned magic = 0, element_magic = 0;\n \tconst char *copyfrom = elt;\n \tchar *match;\n-\tint i, pathspec_prefix = -1;\n+\tint pathspec_prefix = -1;\n \n \t/* PATHSPEC_LITERAL_PATH ignores magic */\n \tif (flags & PATHSPEC_LITERAL_PATH) {\n@@ -329,33 +367,11 @@ static unsigned prefix_pathspec(struct pathspec_item *item, unsigned flags,\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-\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+\tif (flags & PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP)\n+\t\tstrip_submodule_slash_cheap(item);\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+\t\tstrip_submodule_slash_expensive(item);\n \n \tif (magic & PATHSPEC_LITERAL)\n \t\titem->nowildcard_len = item->len;\n-- \n2.11.0.390.gc69c2f50cf-goog\n\n"},{"id":"308784","messageId":"20170104180411.150000-8-bmwill@google.com","threadId":"44632","inReplyTo":"20170104180411.150000-1-bmwill@google.com","subject":"[PATCH v5 07/16] pathspec: remove unused variable from unsupported_magic","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-01-04T18:04:02Z","receivedAt":"2017-01-04T18:05:46Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Removed unused variable 'n' from the 'unsupported_magic()' function.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n pathspec.c | 5 ++---\n 1 file changed, 2 insertions(+), 3 deletions(-)\n\ndiff --git a/pathspec.c b/pathspec.c\nindex b8faa8f46..b9a3819d6 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -333,8 +333,8 @@ static void NORETURN unsupported_magic(const char *pattern,\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+\tint i;\n+\tfor (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@@ -344,7 +344,6 @@ static void NORETURN unsupported_magic(const char *pattern,\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 substitute \"this command\" with a command\n-- \n2.11.0.390.gc69c2f50cf-goog\n\n"},{"id":"308785","messageId":"20170104180411.150000-12-bmwill@google.com","threadId":"44632","inReplyTo":"20170104180411.150000-1-bmwill@google.com","subject":"[PATCH v5 11/16] pathspec: create parse_short_magic function","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-01-04T18:04:06Z","receivedAt":"2017-01-04T18:05:47Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Factor out the logic responsible for parsing short magic into its own\nfunction.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n pathspec.c | 54 ++++++++++++++++++++++++++++++++++++------------------\n 1 file changed, 36 insertions(+), 18 deletions(-)\n\ndiff --git a/pathspec.c b/pathspec.c\nindex 77df55da6..1b0901848 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -157,6 +157,41 @@ static int get_global_magic(int element_magic)\n }\n \n /*\n+ * Parse the pathspec element looking for short magic\n+ *\n+ * saves all magic in 'magic'\n+ * returns the position in 'elem' after all magic has been parsed\n+ */\n+static const char *parse_short_magic(unsigned *magic, const char *elem)\n+{\n+\tconst char *pos;\n+\n+\tfor (pos = elem + 1; *pos && *pos != ':'; pos++) {\n+\t\tchar ch = *pos;\n+\t\tint i;\n+\n+\t\tif (!is_pathspec_magic(ch))\n+\t\t\tbreak;\n+\n+\t\tfor (i = 0; i < ARRAY_SIZE(pathspec_magic); i++) {\n+\t\t\tif (pathspec_magic[i].mnemonic == ch) {\n+\t\t\t\t*magic |= pathspec_magic[i].bit;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t}\n+\n+\t\tif (ARRAY_SIZE(pathspec_magic) <= i)\n+\t\t\tdie(_(\"Unimplemented pathspec magic '%c' in '%s'\"),\n+\t\t\t    ch, elem);\n+\t}\n+\n+\tif (*pos == ':')\n+\t\tpos++;\n+\n+\treturn pos;\n+}\n+\n+/*\n  * Take an element of a pathspec and check for magic signatures.\n  * Append the result to the prefix. Return the magic bitmap.\n  *\n@@ -220,24 +255,7 @@ static unsigned prefix_pathspec(struct pathspec_item *item, unsigned flags,\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\telement_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-\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\tcopyfrom = parse_short_magic(&element_magic, elt);\n \t}\n \n \tmagic |= element_magic;\n-- \n2.11.0.390.gc69c2f50cf-goog\n\n"},{"id":"308786","messageId":"20170104180411.150000-5-bmwill@google.com","threadId":"44632","inReplyTo":"20170104180411.150000-1-bmwill@google.com","subject":"[PATCH v5 04/16] ls-tree: convert show_recursive to use the pathspec struct interface","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-01-04T18:03:59Z","receivedAt":"2017-01-04T18:05:55Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Convert 'show_recursive()' to use the pathspec struct interface from\nusing the '_raw' entry in the pathspec struct.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n builtin/ls-tree.c | 16 +++++++---------\n 1 file changed, 7 insertions(+), 9 deletions(-)\n\ndiff --git a/builtin/ls-tree.c b/builtin/ls-tree.c\nindex 0e30d8623..d7ebeb4ce 100644\n--- a/builtin/ls-tree.c\n+++ b/builtin/ls-tree.c\n@@ -31,21 +31,18 @@ static const  char * const ls_tree_usage[] = {\n \n static int show_recursive(const char *base, int baselen, const char *pathname)\n {\n-\tconst char **s;\n+\tint i;\n \n \tif (ls_options & LS_RECURSIVE)\n \t\treturn 1;\n \n-\ts = pathspec._raw;\n-\tif (!s)\n+\tif (!pathspec.nr)\n \t\treturn 0;\n \n-\tfor (;;) {\n-\t\tconst char *spec = *s++;\n+\tfor (i = 0; i < pathspec.nr; i++) {\n+\t\tconst char *spec = pathspec.items[i].match;\n \t\tint len, speclen;\n \n-\t\tif (!spec)\n-\t\t\treturn 0;\n \t\tif (strncmp(base, spec, baselen))\n \t\t\tcontinue;\n \t\tlen = strlen(pathname);\n@@ -59,6 +56,7 @@ static int show_recursive(const char *base, int baselen, const char *pathname)\n \t\t\tcontinue;\n \t\treturn 1;\n \t}\n+\treturn 0;\n }\n \n static int show_tree(const unsigned char *sha1, struct strbuf *base,\n@@ -175,8 +173,8 @@ 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() or tree_entry_interesting()\n \t */\n-\tparse_pathspec(&pathspec, PATHSPEC_GLOB | PATHSPEC_ICASE |\n-\t\t\t\t  PATHSPEC_EXCLUDE,\n+\tparse_pathspec(&pathspec, PATHSPEC_ALL_MAGIC &\n+\t\t\t\t  ~(PATHSPEC_FROMTOP | PATHSPEC_LITERAL),\n \t\t       PATHSPEC_PREFER_CWD,\n \t\t       prefix, argv + 1);\n \tfor (i = 0; i < pathspec.nr; i++)\n-- \n2.11.0.390.gc69c2f50cf-goog\n\n"},{"id":"308787","messageId":"20170104180411.150000-3-bmwill@google.com","threadId":"44632","inReplyTo":"20170104180411.150000-1-bmwill@google.com","subject":"[PATCH v5 02/16] dir: remove struct path_simplify","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-01-04T18:03:57Z","receivedAt":"2017-01-04T18:05:59Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Teach simplify_away() and exclude_matches_pathspec() to handle struct\npathspec directly, eliminating the need for the struct path_simplify.\n\nAlso renamed the len parameter to pathlen in exclude_matches_pathspec()\nto match the parameter names used in simplify_away().\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n dir.c | 179 ++++++++++++++++++++++++++++--------------------------------------\n 1 file changed, 76 insertions(+), 103 deletions(-)\n\ndiff --git a/dir.c b/dir.c\nindex bfa8c8a9a..9ae454dde 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -16,11 +16,6 @@\n #include \"varint.h\"\n #include \"ewah/ewok.h\"\n \n-struct path_simplify {\n-\tint len;\n-\tconst char *path;\n-};\n-\n /*\n  * Tells read_directory_recursive how a file or directory should be treated.\n  * Values are ordered by significance, e.g. if a directory contains both\n@@ -50,7 +45,7 @@ struct cached_dir {\n \n static enum path_treatment read_directory_recursive(struct dir_struct *dir,\n \tconst char *path, int len, struct untracked_cache_dir *untracked,\n-\tint check_only, const struct path_simplify *simplify);\n+\tint check_only, const struct pathspec *pathspec);\n static int get_dtype(struct dirent *de, const char *path, int len);\n \n int fspathcmp(const char *a, const char *b)\n@@ -1312,7 +1307,7 @@ static enum exist_status directory_exists_in_index(const char *dirname, int len)\n static enum path_treatment treat_directory(struct dir_struct *dir,\n \tstruct untracked_cache_dir *untracked,\n \tconst char *dirname, int len, int baselen, int exclude,\n-\tconst struct path_simplify *simplify)\n+\tconst struct pathspec *pathspec)\n {\n \t/* The \"len-1\" is to strip the final '/' */\n \tswitch (directory_exists_in_index(dirname, len-1)) {\n@@ -1341,7 +1336,7 @@ static enum path_treatment treat_directory(struct dir_struct *dir,\n \tuntracked = lookup_untracked(dir->untracked, untracked,\n \t\t\t\t     dirname + baselen, len - baselen);\n \treturn read_directory_recursive(dir, dirname, len,\n-\t\t\t\t\tuntracked, 1, simplify);\n+\t\t\t\t\tuntracked, 1, pathspec);\n }\n \n /*\n@@ -1349,24 +1344,33 @@ static enum path_treatment treat_directory(struct dir_struct *dir,\n  * reading - if the path cannot possibly be in the pathspec,\n  * return true, and we'll skip it early.\n  */\n-static int simplify_away(const char *path, int pathlen, const struct path_simplify *simplify)\n+static int simplify_away(const char *path, int pathlen,\n+\t\t\t const struct pathspec *pathspec)\n {\n-\tif (simplify) {\n-\t\tfor (;;) {\n-\t\t\tconst char *match = simplify->path;\n-\t\t\tint len = simplify->len;\n+\tint i;\n \n-\t\t\tif (!match)\n-\t\t\t\tbreak;\n-\t\t\tif (len > pathlen)\n-\t\t\t\tlen = pathlen;\n-\t\t\tif (!memcmp(path, match, len))\n-\t\t\t\treturn 0;\n-\t\t\tsimplify++;\n-\t\t}\n-\t\treturn 1;\n+\tif (!pathspec || !pathspec->nr)\n+\t\treturn 0;\n+\n+\tGUARD_PATHSPEC(pathspec,\n+\t\t       PATHSPEC_FROMTOP |\n+\t\t       PATHSPEC_MAXDEPTH |\n+\t\t       PATHSPEC_LITERAL |\n+\t\t       PATHSPEC_GLOB |\n+\t\t       PATHSPEC_ICASE |\n+\t\t       PATHSPEC_EXCLUDE);\n+\n+\tfor (i = 0; i < pathspec->nr; i++) {\n+\t\tconst struct pathspec_item *item = &pathspec->items[i];\n+\t\tint len = item->nowildcard_len;\n+\n+\t\tif (len > pathlen)\n+\t\t\tlen = pathlen;\n+\t\tif (!ps_strncmp(item, item->match, path, len))\n+\t\t\treturn 0;\n \t}\n-\treturn 0;\n+\n+\treturn 1;\n }\n \n /*\n@@ -1380,19 +1384,33 @@ static int simplify_away(const char *path, int pathlen, const struct path_simpli\n  *   2. the path is a directory prefix of some element in the\n  *      pathspec\n  */\n-static int exclude_matches_pathspec(const char *path, int len,\n-\t\tconst struct path_simplify *simplify)\n-{\n-\tif (simplify) {\n-\t\tfor (; simplify->path; simplify++) {\n-\t\t\tif (len == simplify->len\n-\t\t\t    && !memcmp(path, simplify->path, len))\n-\t\t\t\treturn 1;\n-\t\t\tif (len < simplify->len\n-\t\t\t    && simplify->path[len] == '/'\n-\t\t\t    && !memcmp(path, simplify->path, len))\n-\t\t\t\treturn 1;\n-\t\t}\n+static int exclude_matches_pathspec(const char *path, int pathlen,\n+\t\t\t\t    const struct pathspec *pathspec)\n+{\n+\tint i;\n+\n+\tif (!pathspec || !pathspec->nr)\n+\t\treturn 0;\n+\n+\tGUARD_PATHSPEC(pathspec,\n+\t\t       PATHSPEC_FROMTOP |\n+\t\t       PATHSPEC_MAXDEPTH |\n+\t\t       PATHSPEC_LITERAL |\n+\t\t       PATHSPEC_GLOB |\n+\t\t       PATHSPEC_ICASE |\n+\t\t       PATHSPEC_EXCLUDE);\n+\n+\tfor (i = 0; i < pathspec->nr; i++) {\n+\t\tconst struct pathspec_item *item = &pathspec->items[i];\n+\t\tint len = item->nowildcard_len;\n+\n+\t\tif (len == pathlen &&\n+\t\t    !ps_strncmp(item, item->match, path, pathlen))\n+\t\t\treturn 1;\n+\t\tif (len > pathlen &&\n+\t\t    item->match[pathlen] == '/' &&\n+\t\t    !ps_strncmp(item, item->match, path, pathlen))\n+\t\t\treturn 1;\n \t}\n \treturn 0;\n }\n@@ -1460,7 +1478,7 @@ static enum path_treatment treat_one_path(struct dir_struct *dir,\n \t\t\t\t\t  struct untracked_cache_dir *untracked,\n \t\t\t\t\t  struct strbuf *path,\n \t\t\t\t\t  int baselen,\n-\t\t\t\t\t  const struct path_simplify *simplify,\n+\t\t\t\t\t  const struct pathspec *pathspec,\n \t\t\t\t\t  int dtype, struct dirent *de)\n {\n \tint exclude;\n@@ -1512,7 +1530,7 @@ static enum path_treatment treat_one_path(struct dir_struct *dir,\n \tcase DT_DIR:\n \t\tstrbuf_addch(path, '/');\n \t\treturn treat_directory(dir, untracked, path->buf, path->len,\n-\t\t\t\t       baselen, exclude, simplify);\n+\t\t\t\t       baselen, exclude, pathspec);\n \tcase DT_REG:\n \tcase DT_LNK:\n \t\treturn exclude ? path_excluded : path_untracked;\n@@ -1524,7 +1542,7 @@ static enum path_treatment treat_path_fast(struct dir_struct *dir,\n \t\t\t\t\t   struct cached_dir *cdir,\n \t\t\t\t\t   struct strbuf *path,\n \t\t\t\t\t   int baselen,\n-\t\t\t\t\t   const struct path_simplify *simplify)\n+\t\t\t\t\t   const struct pathspec *pathspec)\n {\n \tstrbuf_setlen(path, baselen);\n \tif (!cdir->ucd) {\n@@ -1541,7 +1559,7 @@ static enum path_treatment treat_path_fast(struct dir_struct *dir,\n \t\t * with check_only set.\n \t\t */\n \t\treturn read_directory_recursive(dir, path->buf, path->len,\n-\t\t\t\t\t\tcdir->ucd, 1, simplify);\n+\t\t\t\t\t\tcdir->ucd, 1, pathspec);\n \t/*\n \t * We get path_recurse in the first run when\n \t * directory_exists_in_index() returns index_nonexistent. We\n@@ -1556,23 +1574,23 @@ static enum path_treatment treat_path(struct dir_struct *dir,\n \t\t\t\t      struct cached_dir *cdir,\n \t\t\t\t      struct strbuf *path,\n \t\t\t\t      int baselen,\n-\t\t\t\t      const struct path_simplify *simplify)\n+\t\t\t\t      const struct pathspec *pathspec)\n {\n \tint dtype;\n \tstruct dirent *de = cdir->de;\n \n \tif (!de)\n \t\treturn treat_path_fast(dir, untracked, cdir, path,\n-\t\t\t\t       baselen, simplify);\n+\t\t\t\t       baselen, pathspec);\n \tif (is_dot_or_dotdot(de->d_name) || !strcmp(de->d_name, \".git\"))\n \t\treturn path_none;\n \tstrbuf_setlen(path, baselen);\n \tstrbuf_addstr(path, de->d_name);\n-\tif (simplify_away(path->buf, path->len, simplify))\n+\tif (simplify_away(path->buf, path->len, pathspec))\n \t\treturn path_none;\n \n \tdtype = DTYPE(de);\n-\treturn treat_one_path(dir, untracked, path, baselen, simplify, dtype, de);\n+\treturn treat_one_path(dir, untracked, path, baselen, pathspec, dtype, de);\n }\n \n static void add_untracked(struct untracked_cache_dir *dir, const char *name)\n@@ -1703,7 +1721,7 @@ static void close_cached_dir(struct cached_dir *cdir)\n static enum path_treatment read_directory_recursive(struct dir_struct *dir,\n \t\t\t\t    const char *base, int baselen,\n \t\t\t\t    struct untracked_cache_dir *untracked, int check_only,\n-\t\t\t\t    const struct path_simplify *simplify)\n+\t\t\t\t    const struct pathspec *pathspec)\n {\n \tstruct cached_dir cdir;\n \tenum path_treatment state, subdir_state, dir_state = path_none;\n@@ -1719,7 +1737,8 @@ static enum path_treatment read_directory_recursive(struct dir_struct *dir,\n \n \twhile (!read_cached_dir(&cdir)) {\n \t\t/* check how the file or directory should be treated */\n-\t\tstate = treat_path(dir, untracked, &cdir, &path, baselen, simplify);\n+\t\tstate = treat_path(dir, untracked, &cdir, &path,\n+\t\t\t\t   baselen, pathspec);\n \n \t\tif (state > dir_state)\n \t\t\tdir_state = state;\n@@ -1731,8 +1750,9 @@ static enum path_treatment read_directory_recursive(struct dir_struct *dir,\n \t\t\t\t\t      path.buf + baselen,\n \t\t\t\t\t      path.len - baselen);\n \t\t\tsubdir_state =\n-\t\t\t\tread_directory_recursive(dir, path.buf, path.len,\n-\t\t\t\t\t\t\t ud, check_only, simplify);\n+\t\t\t\tread_directory_recursive(dir, path.buf,\n+\t\t\t\t\t\t\t path.len, ud,\n+\t\t\t\t\t\t\t check_only, pathspec);\n \t\t\tif (subdir_state > dir_state)\n \t\t\t\tdir_state = subdir_state;\n \t\t}\n@@ -1756,7 +1776,7 @@ static enum path_treatment read_directory_recursive(struct dir_struct *dir,\n \t\t\telse if ((dir->flags & DIR_SHOW_IGNORED_TOO) ||\n \t\t\t\t((dir->flags & DIR_COLLECT_IGNORED) &&\n \t\t\t\texclude_matches_pathspec(path.buf, path.len,\n-\t\t\t\t\tsimplify)))\n+\t\t\t\t\t\t\t pathspec)))\n \t\t\t\tdir_add_ignored(dir, path.buf, path.len);\n \t\t\tbreak;\n \n@@ -1787,36 +1807,9 @@ static int cmp_name(const void *p1, const void *p2)\n \treturn name_compare(e1->name, e1->len, e2->name, e2->len);\n }\n \n-static struct path_simplify *create_simplify(const char **pathspec)\n-{\n-\tint nr, alloc = 0;\n-\tstruct path_simplify *simplify = NULL;\n-\n-\tif (!pathspec)\n-\t\treturn NULL;\n-\n-\tfor (nr = 0 ; ; nr++) {\n-\t\tconst char *match;\n-\t\tALLOC_GROW(simplify, nr + 1, alloc);\n-\t\tmatch = *pathspec++;\n-\t\tif (!match)\n-\t\t\tbreak;\n-\t\tsimplify[nr].path = match;\n-\t\tsimplify[nr].len = simple_length(match);\n-\t}\n-\tsimplify[nr].path = NULL;\n-\tsimplify[nr].len = 0;\n-\treturn simplify;\n-}\n-\n-static void free_simplify(struct path_simplify *simplify)\n-{\n-\tfree(simplify);\n-}\n-\n static int treat_leading_path(struct dir_struct *dir,\n \t\t\t      const char *path, int len,\n-\t\t\t      const struct path_simplify *simplify)\n+\t\t\t      const struct pathspec *pathspec)\n {\n \tstruct strbuf sb = STRBUF_INIT;\n \tint baselen, rc = 0;\n@@ -1840,9 +1833,9 @@ static int treat_leading_path(struct dir_struct *dir,\n \t\tstrbuf_add(&sb, path, baselen);\n \t\tif (!is_directory(sb.buf))\n \t\t\tbreak;\n-\t\tif (simplify_away(sb.buf, sb.len, simplify))\n+\t\tif (simplify_away(sb.buf, sb.len, pathspec))\n \t\t\tbreak;\n-\t\tif (treat_one_path(dir, NULL, &sb, baselen, simplify,\n+\t\tif (treat_one_path(dir, NULL, &sb, baselen, pathspec,\n \t\t\t\t   DT_DIR, NULL) == path_none)\n \t\t\tbreak; /* do not recurse into it */\n \t\tif (len <= baselen) {\n@@ -2010,33 +2003,14 @@ static struct untracked_cache_dir *validate_untracked_cache(struct dir_struct *d\n \treturn root;\n }\n \n-int read_directory(struct dir_struct *dir, const char *path, int len, const struct pathspec *pathspec)\n+int read_directory(struct dir_struct *dir, const char *path,\n+\t\t   int len, const struct pathspec *pathspec)\n {\n-\tstruct path_simplify *simplify;\n \tstruct untracked_cache_dir *untracked;\n \n-\t/*\n-\t * Check out create_simplify()\n-\t */\n-\tif (pathspec)\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_GLOB |\n-\t\t\t       PATHSPEC_ICASE |\n-\t\t\t       PATHSPEC_EXCLUDE);\n-\n \tif (has_symlink_leading_path(path, len))\n \t\treturn dir->nr;\n \n-\t/*\n-\t * exclude patterns are treated like positive ones in\n-\t * create_simplify. Usually exclude patterns should be a\n-\t * subset of positive ones, which has no impacts on\n-\t * create_simplify().\n-\t */\n-\tsimplify = create_simplify(pathspec ? pathspec->_raw : NULL);\n \tuntracked = validate_untracked_cache(dir, len, pathspec);\n \tif (!untracked)\n \t\t/*\n@@ -2044,9 +2018,8 @@ int read_directory(struct dir_struct *dir, const char *path, int len, const stru\n \t\t * e.g. prep_exclude()\n \t\t */\n \t\tdir->untracked = NULL;\n-\tif (!len || treat_leading_path(dir, path, len, simplify))\n-\t\tread_directory_recursive(dir, path, len, untracked, 0, simplify);\n-\tfree_simplify(simplify);\n+\tif (!len || treat_leading_path(dir, path, len, pathspec))\n+\t\tread_directory_recursive(dir, path, len, untracked, 0, pathspec);\n \tQSORT(dir->entries, dir->nr, cmp_name);\n \tQSORT(dir->ignored, dir->ignored_nr, cmp_name);\n \tif (dir->untracked) {\n-- \n2.11.0.390.gc69c2f50cf-goog\n\n"},{"id":"308788","messageId":"20170104180411.150000-4-bmwill@google.com","threadId":"44632","inReplyTo":"20170104180411.150000-1-bmwill@google.com","subject":"[PATCH v5 03/16] dir: convert fill_directory to use the pathspec struct interface","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-01-04T18:03:58Z","receivedAt":"2017-01-04T18:06:00Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Convert 'fill_directory()' to use the pathspec struct interface from\nusing the '_raw' entry in the pathspec struct.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n dir.c | 12 ++++++++----\n 1 file changed, 8 insertions(+), 4 deletions(-)\n\ndiff --git a/dir.c b/dir.c\nindex 9ae454dde..bc5ff7216 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -174,17 +174,21 @@ char *common_prefix(const struct pathspec *pathspec)\n \n int fill_directory(struct dir_struct *dir, const struct pathspec *pathspec)\n {\n-\tsize_t len;\n+\tchar *prefix;\n+\tsize_t prefix_len;\n \n \t/*\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+\tprefix = common_prefix(pathspec);\n+\tprefix_len = prefix ? strlen(prefix) : 0;\n \n \t/* Read the directory and prune it */\n-\tread_directory(dir, pathspec->nr ? pathspec->_raw[0] : \"\", len, pathspec);\n-\treturn len;\n+\tread_directory(dir, prefix, prefix_len, pathspec);\n+\n+\tfree(prefix);\n+\treturn prefix_len;\n }\n \n int within_depth(const char *name, int namelen,\n-- \n2.11.0.390.gc69c2f50cf-goog\n\n"},{"id":"308789","messageId":"20170104180411.150000-1-bmwill@google.com","threadId":"44632","inReplyTo":"20170103184241.128409-1-bmwill@google.com","subject":"[PATCH v5 00/16] pathspec cleanup","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-01-04T18:03:55Z","receivedAt":"2017-01-04T18:06:02Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Changes in v5:\n* Move GUARD_PATHSPEC to prevent checking if pathspec is null twice.\n* Mark a string containing 'mnemonic' for translation.\n\nBrandon Williams (16):\n  mv: remove use of deprecated 'get_pathspec()'\n  dir: remove struct path_simplify\n  dir: convert fill_directory to use the pathspec struct interface\n  ls-tree: convert show_recursive to use the pathspec struct interface\n  pathspec: remove the deprecated get_pathspec function\n  pathspec: copy and free owned memory\n  pathspec: remove unused variable from unsupported_magic\n  pathspec: always show mnemonic and name in unsupported_magic\n  pathspec: simpler logic to prefix original pathspec elements\n  pathspec: factor global magic into its own function\n  pathspec: create parse_short_magic function\n  pathspec: create parse_long_magic function\n  pathspec: create parse_element_magic helper\n  pathspec: create strip submodule slash helpers\n  pathspec: small readability changes\n  pathspec: rename prefix_pathspec to init_pathspec_item\n\n Documentation/technical/api-setup.txt |   2 -\n builtin/ls-tree.c                     |  16 +-\n builtin/mv.c                          |  50 ++--\n cache.h                               |   1 -\n dir.c                                 | 191 ++++++--------\n pathspec.c                            | 480 +++++++++++++++++++---------------\n pathspec.h                            |   5 +-\n 7 files changed, 388 insertions(+), 357 deletions(-)\n\n--- interdiff between v4 and v5\n\ndiff --git a/dir.c b/dir.c\nindex e8ddd7f8a..bc5ff7216 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -1353,18 +1353,17 @@ static int simplify_away(const char *path, int pathlen,\n {\n \tint i;\n \n-\tif (pathspec)\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_GLOB |\n-\t\t\t       PATHSPEC_ICASE |\n-\t\t\t       PATHSPEC_EXCLUDE);\n-\n \tif (!pathspec || !pathspec->nr)\n \t\treturn 0;\n \n+\tGUARD_PATHSPEC(pathspec,\n+\t\t       PATHSPEC_FROMTOP |\n+\t\t       PATHSPEC_MAXDEPTH |\n+\t\t       PATHSPEC_LITERAL |\n+\t\t       PATHSPEC_GLOB |\n+\t\t       PATHSPEC_ICASE |\n+\t\t       PATHSPEC_EXCLUDE);\n+\n \tfor (i = 0; i < pathspec->nr; i++) {\n \t\tconst struct pathspec_item *item = &pathspec->items[i];\n \t\tint len = item->nowildcard_len;\n@@ -1394,18 +1393,17 @@ static int exclude_matches_pathspec(const char *path, int pathlen,\n {\n \tint i;\n \n-\tif (pathspec)\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_GLOB |\n-\t\t\t       PATHSPEC_ICASE |\n-\t\t\t       PATHSPEC_EXCLUDE);\n-\n \tif (!pathspec || !pathspec->nr)\n \t\treturn 0;\n \n+\tGUARD_PATHSPEC(pathspec,\n+\t\t       PATHSPEC_FROMTOP |\n+\t\t       PATHSPEC_MAXDEPTH |\n+\t\t       PATHSPEC_LITERAL |\n+\t\t       PATHSPEC_GLOB |\n+\t\t       PATHSPEC_ICASE |\n+\t\t       PATHSPEC_EXCLUDE);\n+\n \tfor (i = 0; i < pathspec->nr; i++) {\n \t\tconst struct pathspec_item *item = &pathspec->items[i];\n \t\tint len = item->nowildcard_len;\ndiff --git a/pathspec.c b/pathspec.c\nindex bcf3ba039..ff2509ddd 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -417,7 +417,7 @@ static void NORETURN unsupported_magic(const char *pattern,\n \t\t\tstrbuf_addstr(&sb, \", \");\n \n \t\tif (m->mnemonic)\n-\t\t\tstrbuf_addf(&sb, \"'%s' (mnemonic: '%c')\",\n+\t\t\tstrbuf_addf(&sb, _(\"'%s' (mnemonic: '%c')\"),\n \t\t\t\t    m->name, m->mnemonic);\n \t\telse\n \t\t\tstrbuf_addf(&sb, \"'%s'\", m->name);\n\n-- \n2.11.0.390.gc69c2f50cf-goog\n\n"},{"id":"308790","messageId":"20170104180411.150000-2-bmwill@google.com","threadId":"44632","inReplyTo":"20170104180411.150000-1-bmwill@google.com","subject":"[PATCH v5 01/16] mv: remove use of deprecated 'get_pathspec()'","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-01-04T18:03:56Z","receivedAt":"2017-01-04T18:06:04Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Convert the 'internal_copy_pathspec()' function to 'prefix_path()'\ninstead of using the deprecated 'get_pathspec()' interface.  Also,\nrename 'internal_copy_pathspec()' to 'internal_prefix_pathspec()' to be\nmore descriptive of what the funciton is actually doing.\n\nIn addition to this, fix a memory leak caused by only duplicating some\nof the pathspec elements.  Instead always duplicate all of the the\npathspec elements as an intermediate step (with modificationed based on\nthe passed in flags).  This way the intermediate strings can then be\nfreed after getting the result from 'prefix_path()'.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n builtin/mv.c | 50 +++++++++++++++++++++++++++++++-------------------\n 1 file changed, 31 insertions(+), 19 deletions(-)\n\ndiff --git a/builtin/mv.c b/builtin/mv.c\nindex 2f43877bc..4e86dc523 100644\n--- a/builtin/mv.c\n+++ b/builtin/mv.c\n@@ -4,6 +4,7 @@\n  * Copyright (C) 2006 Johannes Schindelin\n  */\n #include \"builtin.h\"\n+#include \"pathspec.h\"\n #include \"lockfile.h\"\n #include \"dir.h\"\n #include \"cache-tree.h\"\n@@ -19,31 +20,42 @@ static const char * const builtin_mv_usage[] = {\n #define DUP_BASENAME 1\n #define KEEP_TRAILING_SLASH 2\n \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, unsigned flags)\n+static const char **internal_prefix_pathspec(const char *prefix,\n+\t\t\t\t\t     const char **pathspec,\n+\t\t\t\t\t     int count, unsigned flags)\n {\n \tint i;\n \tconst char **result;\n+\tint prefixlen = prefix ? strlen(prefix) : 0;\n \tALLOC_ARRAY(result, count + 1);\n-\tCOPY_ARRAY(result, pathspec, count);\n-\tresult[count] = NULL;\n+\n+\t/* Create an intermediate copy of the pathspec based on the flags */\n \tfor (i = 0; i < count; i++) {\n-\t\tint length = strlen(result[i]);\n+\t\tint length = strlen(pathspec[i]);\n \t\tint to_copy = length;\n+\t\tchar *it;\n \t\twhile (!(flags & KEEP_TRAILING_SLASH) &&\n-\t\t       to_copy > 0 && is_dir_sep(result[i][to_copy - 1]))\n+\t\t       to_copy > 0 && is_dir_sep(pathspec[i][to_copy - 1]))\n \t\t\tto_copy--;\n-\t\tif (to_copy != length || flags & DUP_BASENAME) {\n-\t\t\tchar *it = xmemdupz(result[i], to_copy);\n-\t\t\tif (flags & DUP_BASENAME) {\n-\t\t\t\tresult[i] = xstrdup(basename(it));\n-\t\t\t\tfree(it);\n-\t\t\t} else\n-\t\t\t\tresult[i] = it;\n+\n+\t\tit = xmemdupz(pathspec[i], to_copy);\n+\t\tif (flags & DUP_BASENAME) {\n+\t\t\tresult[i] = xstrdup(basename(it));\n+\t\t\tfree(it);\n+\t\t} else {\n+\t\t\tresult[i] = it;\n \t\t}\n \t}\n-\treturn get_pathspec(prefix, result);\n+\tresult[count] = NULL;\n+\n+\t/* Prefix the pathspec and free the old intermediate strings */\n+\tfor (i = 0; i < count; i++) {\n+\t\tconst char *match = prefix_path(prefix, prefixlen, result[i]);\n+\t\tfree((char *) result[i]);\n+\t\tresult[i] = match;\n+\t}\n+\n+\treturn result;\n }\n \n static const char *add_slash(const char *path)\n@@ -130,7 +142,7 @@ 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 = internal_copy_pathspec(prefix, argv, argc, 0);\n+\tsource = internal_prefix_pathspec(prefix, argv, argc, 0);\n \tmodes = xcalloc(argc, sizeof(enum update_mode));\n \t/*\n \t * Keep trailing slash, needed to let\n@@ -140,16 +152,16 @@ int cmd_mv(int argc, const char **argv, const char *prefix)\n \tflags = KEEP_TRAILING_SLASH;\n \tif (argc == 1 && is_directory(argv[0]) && !is_directory(argv[1]))\n \t\tflags = 0;\n-\tdest_path = internal_copy_pathspec(prefix, argv + argc, 1, flags);\n+\tdest_path = internal_prefix_pathspec(prefix, argv + argc, 1, flags);\n \tsubmodule_gitfile = xcalloc(argc, sizeof(char *));\n \n \tif (dest_path[0][0] == '\\0')\n \t\t/* special case: \".\" was normalized to \"\" */\n-\t\tdestination = internal_copy_pathspec(dest_path[0], argv, argc, DUP_BASENAME);\n+\t\tdestination = internal_prefix_pathspec(dest_path[0], argv, argc, DUP_BASENAME);\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 = internal_copy_pathspec(dest_path[0], argv, argc, DUP_BASENAME);\n+\t\tdestination = internal_prefix_pathspec(dest_path[0], argv, argc, DUP_BASENAME);\n \t} else {\n \t\tif (argc != 1)\n \t\t\tdie(_(\"destination '%s' is not a directory\"), dest_path[0]);\n-- \n2.11.0.390.gc69c2f50cf-goog\n\n"},{"id":"308791","messageId":"20170104180411.150000-6-bmwill@google.com","threadId":"44632","inReplyTo":"20170104180411.150000-1-bmwill@google.com","subject":"[PATCH v5 05/16] pathspec: remove the deprecated get_pathspec function","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-01-04T18:04:00Z","receivedAt":"2017-01-04T18:06:05Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"Now that all callers of the old 'get_pathspec' interface have been\nmigrated to use the new pathspec struct interface it can be removed\nfrom the codebase.\n\nSince there are no more users of the '_raw' field in the pathspec struct\nit can also be removed.  This patch also removes the old functionality\nof modifying the const char **argv array that was passed into\nparse_pathspec.  Instead the constructed 'match' string (which is a\npathspec element with the prefix prepended) is only stored in its\ncorresponding pathspec_item entry.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n Documentation/technical/api-setup.txt |  2 --\n cache.h                               |  1 -\n pathspec.c                            | 42 +++--------------------------------\n pathspec.h                            |  1 -\n 4 files changed, 3 insertions(+), 43 deletions(-)\n\ndiff --git a/Documentation/technical/api-setup.txt b/Documentation/technical/api-setup.txt\nindex 540e45568..eb1fa9853 100644\n--- a/Documentation/technical/api-setup.txt\n+++ b/Documentation/technical/api-setup.txt\n@@ -27,8 +27,6 @@ parse_pathspec(). This function takes several arguments:\n \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 them\n politely. At a lower level, different pathspec-related functions may\n not support the same set of features. Such pathspec-sensitive\ndiff --git a/cache.h b/cache.h\nindex a50a61a19..0f80e01bd 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -514,7 +514,6 @@ extern void set_git_work_tree(const char *tree);\n \n #define ALTERNATE_DB_ENVIRONMENT \"GIT_ALTERNATE_OBJECT_DIRECTORIES\"\n \n-extern const char **get_pathspec(const char *prefix, const char **pathspec);\n extern void setup_work_tree(void);\n extern const char *setup_git_directory_gently(int *);\n extern const char *setup_git_directory(void);\ndiff --git a/pathspec.c b/pathspec.c\nindex 22ca74a12..1f918cbae 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -103,7 +103,7 @@ static void prefix_short_magic(struct strbuf *sb, int prefixlen,\n  */\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\tunsigned flags,\n \t\t\t\tconst char *prefix, int prefixlen,\n \t\t\t\tconst char *elt)\n {\n@@ -240,7 +240,7 @@ static unsigned prefix_pathspec(struct pathspec_item *item,\n \t\tif (!match)\n \t\t\tdie(_(\"%s: '%s' is outside repository\"), elt, copyfrom);\n \t}\n-\t*raw = item->match = match;\n+\titem->match = match;\n \t/*\n \t * Prefix the pathspec (keep all magic) and assign to\n \t * original. Useful for passing to another command.\n@@ -381,8 +381,6 @@ void parse_pathspec(struct pathspec *pathspec,\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@@ -394,10 +392,7 @@ void parse_pathspec(struct pathspec *pathspec,\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;\n-\t\tpathspec->_raw = raw;\n \t\treturn;\n \t}\n \n@@ -415,7 +410,6 @@ void parse_pathspec(struct pathspec *pathspec,\n \tpathspec->nr = n;\n \tALLOC_ARRAY(pathspec->items, n);\n \titem = pathspec->items;\n-\tpathspec->_raw = argv;\n \tprefixlen = prefix ? strlen(prefix) : 0;\n \n \tfor (i = 0; i < n; i++) {\n@@ -423,7 +417,7 @@ void parse_pathspec(struct pathspec *pathspec,\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\tflags,\n \t\t\t\t\t\tprefix, prefixlen, entry);\n \t\tif ((flags & PATHSPEC_LITERAL_PATH) &&\n \t\t    !(magic_mask & PATHSPEC_LITERAL))\n@@ -457,36 +451,6 @@ void parse_pathspec(struct pathspec *pathspec,\n \t}\n }\n \n-/*\n- * N.B. get_pathspec() is deprecated in favor of the \"struct pathspec\"\n- * based interface - see pathspec.c:parse_pathspec().\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-\tstruct pathspec ps;\n-\tparse_pathspec(&ps,\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;\n-}\n-\n void copy_pathspec(struct pathspec *dst, const struct pathspec *src)\n {\n \t*dst = *src;\ndiff --git a/pathspec.h b/pathspec.h\nindex 59809e479..70a592e91 100644\n--- a/pathspec.h\n+++ b/pathspec.h\n@@ -19,7 +19,6 @@\n #define PATHSPEC_ONESTAR 1\t/* the pathspec pattern satisfies GFNM_ONESTAR */\n \n struct pathspec {\n-\tconst char **_raw; /* get_pathspec() result, not freed by clear_pathspec() */\n \tint nr;\n \tunsigned int has_wildcard:1;\n \tunsigned int recursive:1;\n-- \n2.11.0.390.gc69c2f50cf-goog\n\n"},{"id":"308792","messageId":"20170104180411.150000-7-bmwill@google.com","threadId":"44632","inReplyTo":"20170104180411.150000-1-bmwill@google.com","subject":"[PATCH v5 06/16] pathspec: copy and free owned memory","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-01-04T18:04:01Z","receivedAt":"2017-01-04T18:06:09Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"The 'original' string entry in a pathspec_item is only duplicated some\nof the time, instead always make a copy of the original and take\nownership of the memory.\n\nSince both 'match' and 'original' string entries in a pathspec_item are\nowned by the pathspec struct, they need to be freed when clearing the\npathspec struct (in 'clear_pathspec()') and duplicated when copying the\npathspec struct (in 'copy_pathspec()').\n\nAlso change the type of 'match' and 'original' to 'char *' in order to\nmore explicitly show the ownership of the memory.\n\nSigned-off-by: Brandon Williams <bmwill@google.com>\n---\n pathspec.c | 23 +++++++++++++++++++----\n pathspec.h |  4 ++--\n 2 files changed, 21 insertions(+), 6 deletions(-)\n\ndiff --git a/pathspec.c b/pathspec.c\nindex 1f918cbae..b8faa8f46 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -259,8 +259,9 @@ static unsigned prefix_pathspec(struct pathspec_item *item,\n \t\t}\n \t\tstrbuf_addstr(&sb, match);\n \t\titem->original = strbuf_detach(&sb, NULL);\n-\t} else\n-\t\titem->original = elt;\n+\t} else {\n+\t\titem->original = xstrdup(elt);\n+\t}\n \titem->len = strlen(item->match);\n \titem->prefix = prefixlen;\n \n@@ -388,8 +389,8 @@ void parse_pathspec(struct pathspec *pathspec,\n \t\t\tdie(\"BUG: PATHSPEC_PREFER_CWD requires arguments\");\n \n \t\tpathspec->items = item = xcalloc(1, sizeof(*item));\n-\t\titem->match = prefix;\n-\t\titem->original = prefix;\n+\t\titem->match = xstrdup(prefix);\n+\t\titem->original = xstrdup(prefix);\n \t\titem->nowildcard_len = item->len = strlen(prefix);\n \t\titem->prefix = item->len;\n \t\tpathspec->nr = 1;\n@@ -453,13 +454,27 @@ void parse_pathspec(struct pathspec *pathspec,\n \n void copy_pathspec(struct pathspec *dst, const struct pathspec *src)\n {\n+\tint i;\n+\n \t*dst = *src;\n \tALLOC_ARRAY(dst->items, dst->nr);\n \tCOPY_ARRAY(dst->items, src->items, dst->nr);\n+\n+\tfor (i = 0; i < dst->nr; i++) {\n+\t\tdst->items[i].match = xstrdup(src->items[i].match);\n+\t\tdst->items[i].original = xstrdup(src->items[i].original);\n+\t}\n }\n \n void clear_pathspec(struct pathspec *pathspec)\n {\n+\tint i;\n+\n+\tfor (i = 0; i < pathspec->nr; i++) {\n+\t\tfree(pathspec->items[i].match);\n+\t\tfree(pathspec->items[i].original);\n+\t}\n \tfree(pathspec->items);\n \tpathspec->items = NULL;\n+\tpathspec->nr = 0;\n }\ndiff --git a/pathspec.h b/pathspec.h\nindex 70a592e91..49fd823dd 100644\n--- a/pathspec.h\n+++ b/pathspec.h\n@@ -25,8 +25,8 @@ struct pathspec {\n \tunsigned magic;\n \tint max_depth;\n \tstruct pathspec_item {\n-\t\tconst char *match;\n-\t\tconst char *original;\n+\t\tchar *match;\n+\t\tchar *original;\n \t\tunsigned magic;\n \t\tint len, prefix;\n \t\tint nowildcard_len;\n-- \n2.11.0.390.gc69c2f50cf-goog\n\n"},{"id":"308924","messageId":"CACsJy8CM6FfHpVuqby=hjPmiYAxvJjzr1W6LdO5B82KQnTmmog@mail.gmail.com","threadId":"44632","inReplyTo":"20170104180411.150000-1-bmwill@google.com","subject":"Re: [PATCH v5 00/16] pathspec cleanup","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2017-01-07T09:29:31Z","receivedAt":"2017-01-07T09:30:24Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Thu, Jan 5, 2017 at 1:03 AM, Brandon Williams <bmwill@google.com> wrote:\n> Changes in v5:\n> * Move GUARD_PATHSPEC to prevent checking if pathspec is null twice.\n> * Mark a string containing 'mnemonic' for translation.\n\nArgh.. I've run out of things to complain about! Ack!\n-- \nDuy\n"},{"id":"308975","messageId":"xmqqlgulyoni.fsf@gitster.mtv.corp.google.com","threadId":"44632","inReplyTo":"CACsJy8CM6FfHpVuqby=hjPmiYAxvJjzr1W6LdO5B82KQnTmmog@mail.gmail.com","subject":"Re: [PATCH v5 00/16] pathspec cleanup","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-01-09T02:04:33Z","receivedAt":"2017-01-09T02:04:43Z","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 Thu, Jan 5, 2017 at 1:03 AM, Brandon Williams <bmwill@google.com> wrote:\n>> Changes in v5:\n>> * Move GUARD_PATHSPEC to prevent checking if pathspec is null twice.\n>> * Mark a string containing 'mnemonic' for translation.\n>\n> Argh.. I've run out of things to complain about! Ack!\n\nThanks ;-)  Will queue with your reviewed-by.\n"},{"id":"309044","messageId":"20170109175759.GA62878@google.com","threadId":"44632","inReplyTo":"CACsJy8CM6FfHpVuqby=hjPmiYAxvJjzr1W6LdO5B82KQnTmmog@mail.gmail.com","subject":"Re: [PATCH v5 00/16] pathspec cleanup","fromName":"Brandon Williams","fromEmail":"bmwill@google.com","sentAt":"2017-01-09T17:57:59Z","receivedAt":"2017-01-09T17:58:07Z","isPatch":true,"sender":{"key":"bwilliams.eng@gmail.com","avatar":null},"body":"On 01/07, Duy Nguyen wrote:\n> On Thu, Jan 5, 2017 at 1:03 AM, Brandon Williams <bmwill@google.com> wrote:\n> > Changes in v5:\n> > * Move GUARD_PATHSPEC to prevent checking if pathspec is null twice.\n> > * Mark a string containing 'mnemonic' for translation.\n> \n> Argh.. I've run out of things to complain about! Ack!\n\nhaha! Well thanks again for your help in reviewing this series!\n\n-- \nBrandon Williams\n"}]}