{"thread":{"id":"37906","subject":"[PATCH 1/3] tree.c: update read_tree_recursive callback to pass strbuf as base","startedAt":"2014-11-08T11:00:30Z","lastAt":"2014-11-09T08:58:39Z","messageCount":8,"participants":["Nguyễn Thái Ngọc Duy","Duy Nguyen","Eric Sunshine"],"isPatch":true,"patchVersion":1,"patchTotal":3},"messages":[{"id":"251551","messageId":"1415444432-18596-1-git-send-email-pclouds@gmail.com","threadId":"37906","inReplyTo":null,"subject":"[PATCH 1/3] tree.c: update read_tree_recursive callback to pass strbuf as base","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2014-11-08T11:00:30Z","receivedAt":"2014-11-08T11:00:30Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"This allows the callback to use 'base' as a temporary buffer to\nquickly assemble full path \"without\" extra allocation. The caller has\nto restore it afterwards of course.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n archive.c          | 10 +++++-----\n builtin/checkout.c |  8 ++++----\n builtin/log.c      |  2 +-\n builtin/ls-tree.c  |  9 +++++----\n merge-recursive.c  | 15 ++++++---------\n tree.c             | 16 +++++++++++-----\n tree.h             |  3 ++-\n 7 files changed, 34 insertions(+), 29 deletions(-)\n\ndiff --git a/archive.c b/archive.c\nindex 3fc0fb2..fcd0b53 100644\n--- a/archive.c\n+++ b/archive.c\n@@ -103,8 +103,8 @@ struct archiver_context {\n \twrite_archive_entry_fn_t write_entry;\n };\n \n-static int write_archive_entry(const unsigned char *sha1, const char *base,\n-\t\tint baselen, const char *filename, unsigned mode, int stage,\n+static int write_archive_entry(const unsigned char *sha1, struct strbuf *base,\n+\t\tconst char *filename, unsigned mode, int stage,\n \t\tvoid *context)\n {\n \tstatic struct strbuf path = STRBUF_INIT;\n@@ -119,7 +119,7 @@ static int write_archive_entry(const unsigned char *sha1, const char *base,\n \tstrbuf_reset(&path);\n \tstrbuf_grow(&path, PATH_MAX);\n \tstrbuf_add(&path, args->base, args->baselen);\n-\tstrbuf_add(&path, base, baselen);\n+\tstrbuf_addbuf(&path, base);\n \tstrbuf_addstr(&path, filename);\n \tif (S_ISDIR(mode) || S_ISGITLINK(mode))\n \t\tstrbuf_addch(&path, '/');\n@@ -207,8 +207,8 @@ static const struct archiver *lookup_archiver(const char *name)\n \treturn NULL;\n }\n \n-static int reject_entry(const unsigned char *sha1, const char *base,\n-\t\t\tint baselen, const char *filename, unsigned mode,\n+static int reject_entry(const unsigned char *sha1, struct strbuf *base,\n+\t\t\tconst char *filename, unsigned mode,\n \t\t\tint stage, void *context)\n {\n \treturn -1;\ndiff --git a/builtin/checkout.c b/builtin/checkout.c\nindex f71e745..575b76a 100644\n--- a/builtin/checkout.c\n+++ b/builtin/checkout.c\n@@ -62,7 +62,7 @@ static int post_checkout_hook(struct commit *old, struct commit *new,\n \n }\n \n-static int update_some(const unsigned char *sha1, const char *base, int baselen,\n+static int update_some(const unsigned char *sha1, struct strbuf *base,\n \t\tconst char *pathname, unsigned mode, int stage, void *context)\n {\n \tint len;\n@@ -71,11 +71,11 @@ static int update_some(const unsigned char *sha1, const char *base, int baselen,\n \tif (S_ISDIR(mode))\n \t\treturn READ_TREE_RECURSIVE;\n \n-\tlen = baselen + strlen(pathname);\n+\tlen = base->len + strlen(pathname);\n \tce = xcalloc(1, cache_entry_size(len));\n \thashcpy(ce->sha1, sha1);\n-\tmemcpy(ce->name, base, baselen);\n-\tmemcpy(ce->name + baselen, pathname, len - baselen);\n+\tmemcpy(ce->name, base->buf, base->len);\n+\tmemcpy(ce->name + base->len, pathname, len - base->len);\n \tce->ce_flags = create_ce_flags(0) | CE_UPDATE;\n \tce->ce_namelen = len;\n \tce->ce_mode = create_ce_mode(mode);\ndiff --git a/builtin/log.c b/builtin/log.c\nindex 4389722..d097d16 100644\n--- a/builtin/log.c\n+++ b/builtin/log.c\n@@ -487,7 +487,7 @@ static int show_tag_object(const unsigned char *sha1, struct rev_info *rev)\n }\n \n static int show_tree_object(const unsigned char *sha1,\n-\t\tconst char *base, int baselen,\n+\t\tstruct strbuf *base,\n \t\tconst char *pathname, unsigned mode, int stage, void *context)\n {\n \tprintf(\"%s%s\\n\", pathname, S_ISDIR(mode) ? \"/\" : \"\");\ndiff --git a/builtin/ls-tree.c b/builtin/ls-tree.c\nindex 51184df..1ab0381 100644\n--- a/builtin/ls-tree.c\n+++ b/builtin/ls-tree.c\n@@ -61,7 +61,7 @@ static int show_recursive(const char *base, int baselen, const char *pathname)\n \t}\n }\n \n-static int show_tree(const unsigned char *sha1, const char *base, int baselen,\n+static int show_tree(const unsigned char *sha1, struct strbuf *base,\n \t\tconst char *pathname, unsigned mode, int stage, void *context)\n {\n \tint retval = 0;\n@@ -79,7 +79,7 @@ static int show_tree(const unsigned char *sha1, const char *base, int baselen,\n \t\t */\n \t\ttype = commit_type;\n \t} else if (S_ISDIR(mode)) {\n-\t\tif (show_recursive(base, baselen, pathname)) {\n+\t\tif (show_recursive(base->buf, base->len, pathname)) {\n \t\t\tretval = READ_TREE_RECURSIVE;\n \t\t\tif (!(ls_options & LS_SHOW_TREES))\n \t\t\t\treturn retval;\n@@ -90,7 +90,8 @@ static int show_tree(const unsigned char *sha1, const char *base, int baselen,\n \t\treturn 0;\n \n \tif (chomp_prefix &&\n-\t    (baselen < chomp_prefix || memcmp(ls_tree_prefix, base, chomp_prefix)))\n+\t    (base->len < chomp_prefix ||\n+\t     memcmp(ls_tree_prefix, base->buf, chomp_prefix)))\n \t\treturn 0;\n \n \tif (!(ls_options & LS_NAME_ONLY)) {\n@@ -112,7 +113,7 @@ static int show_tree(const unsigned char *sha1, const char *base, int baselen,\n \t\t\tprintf(\"%06o %s %s\\t\", mode, type,\n \t\t\t       find_unique_abbrev(sha1, abbrev));\n \t}\n-\twrite_name_quotedpfx(base + chomp_prefix, baselen - chomp_prefix,\n+\twrite_name_quotedpfx(base->buf + chomp_prefix, base->len - chomp_prefix,\n \t\t\t  pathname, stdout, line_termination);\n \treturn retval;\n }\ndiff --git a/merge-recursive.c b/merge-recursive.c\nindex 1d332b8..1bd8c0d 100644\n--- a/merge-recursive.c\n+++ b/merge-recursive.c\n@@ -276,23 +276,20 @@ struct tree *write_tree_from_memory(struct merge_options *o)\n }\n \n static int save_files_dirs(const unsigned char *sha1,\n-\t\tconst char *base, int baselen, const char *path,\n+\t\tstruct strbuf *base, const char *path,\n \t\tunsigned int mode, int stage, void *context)\n {\n-\tint len = strlen(path);\n-\tchar *newpath = xmalloc(baselen + len + 1);\n+\tint base_len = base->len;\n \tstruct merge_options *o = context;\n \n-\tmemcpy(newpath, base, baselen);\n-\tmemcpy(newpath + baselen, path, len);\n-\tnewpath[baselen + len] = '\\0';\n+\tstrbuf_addstr(base, path);\n \n \tif (S_ISDIR(mode))\n-\t\tstring_list_insert(&o->current_directory_set, newpath);\n+\t\tstring_list_insert(&o->current_directory_set, base->buf);\n \telse\n-\t\tstring_list_insert(&o->current_file_set, newpath);\n-\tfree(newpath);\n+\t\tstring_list_insert(&o->current_file_set, base->buf);\n \n+\tstrbuf_setlen(base, base_len);\n \treturn (S_ISDIR(mode) ? READ_TREE_RECURSIVE : 0);\n }\n \ndiff --git a/tree.c b/tree.c\nindex bb02c1c..58ebfce 100644\n--- a/tree.c\n+++ b/tree.c\n@@ -30,9 +30,12 @@ static int read_one_entry_opt(const unsigned char *sha1, const char *base, int b\n \treturn add_cache_entry(ce, opt);\n }\n \n-static int read_one_entry(const unsigned char *sha1, const char *base, int baselen, const char *pathname, unsigned mode, int stage, void *context)\n+static int read_one_entry(const unsigned char *sha1, struct strbuf *base,\n+\t\t\t  const char *pathname, unsigned mode, int stage,\n+\t\t\t  void *context)\n {\n-\treturn read_one_entry_opt(sha1, base, baselen, pathname, mode, stage,\n+\treturn read_one_entry_opt(sha1, base->buf, base->len, pathname,\n+\t\t\t\t  mode, stage,\n \t\t\t\t  ADD_CACHE_OK_TO_ADD|ADD_CACHE_SKIP_DFCHECK);\n }\n \n@@ -40,9 +43,12 @@ static int read_one_entry(const unsigned char *sha1, const char *base, int basel\n  * This is used when the caller knows there is no existing entries at\n  * the stage that will conflict with the entry being added.\n  */\n-static int read_one_entry_quick(const unsigned char *sha1, const char *base, int baselen, const char *pathname, unsigned mode, int stage, void *context)\n+static int read_one_entry_quick(const unsigned char *sha1, struct strbuf *base,\n+\t\t\t\tconst char *pathname, unsigned mode, int stage,\n+\t\t\t\tvoid *context)\n {\n-\treturn read_one_entry_opt(sha1, base, baselen, pathname, mode, stage,\n+\treturn read_one_entry_opt(sha1, base->buf, base->len, pathname,\n+\t\t\t\t  mode, stage,\n \t\t\t\t  ADD_CACHE_JUST_APPEND);\n }\n \n@@ -70,7 +76,7 @@ static int read_tree_1(struct tree *tree, struct strbuf *base,\n \t\t\t\tcontinue;\n \t\t}\n \n-\t\tswitch (fn(entry.sha1, base->buf, base->len,\n+\t\tswitch (fn(entry.sha1, base,\n \t\t\t   entry.path, entry.mode, stage, context)) {\n \t\tcase 0:\n \t\t\tcontinue;\ndiff --git a/tree.h b/tree.h\nindex d84ac63..d24125f 100644\n--- a/tree.h\n+++ b/tree.h\n@@ -4,6 +4,7 @@\n #include \"object.h\"\n \n extern const char *tree_type;\n+struct strbuf;\n \n struct tree {\n \tstruct object object;\n@@ -22,7 +23,7 @@ void free_tree_buffer(struct tree *tree);\n struct tree *parse_tree_indirect(const unsigned char *sha1);\n \n #define READ_TREE_RECURSIVE 1\n-typedef int (*read_tree_fn_t)(const unsigned char *, const char *, int, const char *, unsigned int, int, void *);\n+typedef int (*read_tree_fn_t)(const unsigned char *, struct strbuf *, const char *, unsigned int, int, void *);\n \n extern int read_tree_recursive(struct tree *tree,\n \t\t\t       const char *base, int baselen,\n-- \n2.1.0.rc0.78.gc0d8480\n"},{"id":"251552","messageId":"1415444432-18596-2-git-send-email-pclouds@gmail.com","threadId":"37906","inReplyTo":"1415444432-18596-1-git-send-email-pclouds@gmail.com","subject":"[PATCH 2/3] ls-tree: disable negative pathspec because it's not supported","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2014-11-08T11:00:31Z","receivedAt":"2014-11-08T11:00:31Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n builtin/ls-tree.c | 3 ++-\n 1 file changed, 2 insertions(+), 1 deletion(-)\n\ndiff --git a/builtin/ls-tree.c b/builtin/ls-tree.c\nindex 1ab0381..d226344 100644\n--- a/builtin/ls-tree.c\n+++ b/builtin/ls-tree.c\n@@ -174,7 +174,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+\tparse_pathspec(&pathspec, PATHSPEC_GLOB | PATHSPEC_ICASE |\n+\t\t\t\t  PATHSPEC_EXCLUDE,\n \t\t       PATHSPEC_PREFER_CWD,\n \t\t       prefix, argv + 1);\n \tfor (i = 0; i < pathspec.nr; i++)\n-- \n2.1.0.rc0.78.gc0d8480\n"},{"id":"251553","messageId":"1415444432-18596-3-git-send-email-pclouds@gmail.com","threadId":"37906","inReplyTo":"1415444432-18596-1-git-send-email-pclouds@gmail.com","subject":"[PATCH 3/3] ls-tree: remove path filtering logic in show_tree","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2014-11-08T11:00:32Z","receivedAt":"2014-11-08T11:00:32Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"ls-tree uses read_tree_recursive() which already does path filtering\nusing pathspec. No need to filter one more time based on prefix\nonly. \"ls-tree ../somewhere\" does not work because of this.\nwrite_name_quotedpfx() can now be retired because nobody else\nuses it.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n builtin/ls-tree.c            | 14 +++++++-------\n quote.c                      | 21 ---------------------\n quote.h                      |  2 --\n t/t3102-ls-tree-wildcards.sh |  8 ++++++++\n 4 files changed, 15 insertions(+), 30 deletions(-)\n\ndiff --git a/builtin/ls-tree.c b/builtin/ls-tree.c\nindex d226344..3b04a0f 100644\n--- a/builtin/ls-tree.c\n+++ b/builtin/ls-tree.c\n@@ -65,6 +65,7 @@ static int show_tree(const unsigned char *sha1, struct strbuf *base,\n \t\tconst char *pathname, unsigned mode, int stage, void *context)\n {\n \tint retval = 0;\n+\tint baselen;\n \tconst char *type = blob_type;\n \n \tif (S_ISGITLINK(mode)) {\n@@ -89,11 +90,6 @@ static int show_tree(const unsigned char *sha1, struct strbuf *base,\n \telse if (ls_options & LS_TREE_ONLY)\n \t\treturn 0;\n \n-\tif (chomp_prefix &&\n-\t    (base->len < chomp_prefix ||\n-\t     memcmp(ls_tree_prefix, base->buf, chomp_prefix)))\n-\t\treturn 0;\n-\n \tif (!(ls_options & LS_NAME_ONLY)) {\n \t\tif (ls_options & LS_SHOW_SIZE) {\n \t\t\tchar size_text[24];\n@@ -113,8 +109,12 @@ static int show_tree(const unsigned char *sha1, struct strbuf *base,\n \t\t\tprintf(\"%06o %s %s\\t\", mode, type,\n \t\t\t       find_unique_abbrev(sha1, abbrev));\n \t}\n-\twrite_name_quotedpfx(base->buf + chomp_prefix, base->len - chomp_prefix,\n-\t\t\t  pathname, stdout, line_termination);\n+\tbaselen = base->len;\n+\tstrbuf_addstr(base, pathname);\n+\twrite_name_quoted_relative(base->buf,\n+\t\t\t\t   chomp_prefix ? ls_tree_prefix : NULL,\n+\t\t\t\t   stdout, line_termination);\n+\tstrbuf_setlen(base, baselen);\n \treturn retval;\n }\n \ndiff --git a/quote.c b/quote.c\nindex 45e3db1..7920e18 100644\n--- a/quote.c\n+++ b/quote.c\n@@ -274,27 +274,6 @@ void write_name_quoted(const char *name, FILE *fp, int terminator)\n \tfputc(terminator, fp);\n }\n \n-void write_name_quotedpfx(const char *pfx, size_t pfxlen,\n-\t\t\t  const char *name, FILE *fp, int terminator)\n-{\n-\tint needquote = 0;\n-\n-\tif (terminator) {\n-\t\tneedquote = next_quote_pos(pfx, pfxlen) < pfxlen\n-\t\t\t|| name[next_quote_pos(name, -1)];\n-\t}\n-\tif (needquote) {\n-\t\tfputc('\"', fp);\n-\t\tquote_c_style_counted(pfx, pfxlen, NULL, fp, 1);\n-\t\tquote_c_style(name, NULL, fp, 1);\n-\t\tfputc('\"', fp);\n-\t} else {\n-\t\tfwrite(pfx, pfxlen, 1, fp);\n-\t\tfputs(name, fp);\n-\t}\n-\tfputc(terminator, fp);\n-}\n-\n void write_name_quoted_relative(const char *name, const char *prefix,\n \t\t\t\tFILE *fp, int terminator)\n {\ndiff --git a/quote.h b/quote.h\nindex 71dcc3a..99e04d3 100644\n--- a/quote.h\n+++ b/quote.h\n@@ -56,8 +56,6 @@ extern size_t quote_c_style(const char *name, struct strbuf *, FILE *, int no_dq\n extern void quote_two_c_style(struct strbuf *, const char *, const char *, int);\n \n extern void write_name_quoted(const char *name, FILE *, int terminator);\n-extern void write_name_quotedpfx(const char *pfx, size_t pfxlen,\n-                                 const char *name, FILE *, int terminator);\n extern void write_name_quoted_relative(const char *name, const char *prefix,\n \t\tFILE *fp, int terminator);\n \ndiff --git a/t/t3102-ls-tree-wildcards.sh b/t/t3102-ls-tree-wildcards.sh\nindex c286854..83fca8d 100755\n--- a/t/t3102-ls-tree-wildcards.sh\n+++ b/t/t3102-ls-tree-wildcards.sh\n@@ -19,4 +19,12 @@ EOF\n \ttest_cmp expected actual\n '\n \n+test_expect_success 'ls-tree outside prefix' '\n+\tcat >expected <<EOF &&\n+100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391\t../a[a]/three\n+EOF\n+\t( cd aa && git ls-tree -r HEAD \"../a[a]\"; ) >actual &&\n+\ttest_cmp expected actual\n+'\n+\n test_done\n-- \n2.1.0.rc0.78.gc0d8480\n"},{"id":"251554","messageId":"CACsJy8AHXkZexzOvhUL+ooi1v9fM0NgK_Lb-NYCP2zY+8p06=A@mail.gmail.com","threadId":"37906","inReplyTo":"1415444432-18596-1-git-send-email-pclouds@gmail.com","subject":"Re: [PATCH 1/3] tree.c: update read_tree_recursive callback to pass strbuf as base","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2014-11-08T11:03:25Z","receivedAt":"2014-11-08T11:03:25Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Sat, Nov 8, 2014 at 6:00 PM, Nguyễn Thái Ngọc Duy <pclouds@gmail.com> wrote:\n> This allows the callback to use 'base' as a temporary buffer to\n> quickly assemble full path \"without\" extra allocation. The caller has\n\nErrr.. the _callback_ has to. restore...\n\n> to restore it afterwards of course.\n-- \nDuy\n"},{"id":"251573","messageId":"CAPig+cQretAzbabEh=+RxHi5KtLLfqsyvteiPF2jPD3K+_7Lpw@mail.gmail.com","threadId":"37906","inReplyTo":"1415444432-18596-1-git-send-email-pclouds@gmail.com","subject":"Re: [PATCH 1/3] tree.c: update read_tree_recursive callback to pass strbuf as base","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2014-11-09T03:56:28Z","receivedAt":"2014-11-09T03:56:28Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Sat, Nov 8, 2014 at 6:00 AM, Nguyễn Thái Ngọc Duy <pclouds@gmail.com> wrote:\n> This allows the callback to use 'base' as a temporary buffer to\n> quickly assemble full path \"without\" extra allocation. The caller has\n> to restore it afterwards of course.\n>\n> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n> ---\n> diff --git a/merge-recursive.c b/merge-recursive.c\n> index 1d332b8..1bd8c0d 100644\n> --- a/merge-recursive.c\n> +++ b/merge-recursive.c\n> @@ -276,23 +276,20 @@ struct tree *write_tree_from_memory(struct merge_options *o)\n>  }\n>\n>  static int save_files_dirs(const unsigned char *sha1,\n> -               const char *base, int baselen, const char *path,\n> +               struct strbuf *base, const char *path,\n>                 unsigned int mode, int stage, void *context)\n>  {\n> -       int len = strlen(path);\n> -       char *newpath = xmalloc(baselen + len + 1);\n> +       int base_len = base->len;\n\nNit: The removed function argument was named 'baselen'. Also, patch\n3/3 introduces a variable 'baseline' for the same purpose. Thus,\n'base_len' here is a bit inconsistent.\n\n>         struct merge_options *o = context;\n>\n> -       memcpy(newpath, base, baselen);\n> -       memcpy(newpath + baselen, path, len);\n> -       newpath[baselen + len] = '\\0';\n> +       strbuf_addstr(base, path);\n>\n>         if (S_ISDIR(mode))\n> -               string_list_insert(&o->current_directory_set, newpath);\n> +               string_list_insert(&o->current_directory_set, base->buf);\n>         else\n> -               string_list_insert(&o->current_file_set, newpath);\n> -       free(newpath);\n> +               string_list_insert(&o->current_file_set, base->buf);\n>\n> +       strbuf_setlen(base, base_len);\n>         return (S_ISDIR(mode) ? READ_TREE_RECURSIVE : 0);\n>  }\n>\n> diff --git a/tree.c b/tree.c\n> index bb02c1c..58ebfce 100644\n> --- a/tree.c\n> +++ b/tree.c\n> @@ -30,9 +30,12 @@ static int read_one_entry_opt(const unsigned char *sha1, const char *base, int b\n>         return add_cache_entry(ce, opt);\n>  }\n>\n> -static int read_one_entry(const unsigned char *sha1, const char *base, int baselen, const char *pathname, unsigned mode, int stage, void *context)\n> +static int read_one_entry(const unsigned char *sha1, struct strbuf *base,\n> +                         const char *pathname, unsigned mode, int stage,\n> +                         void *context)\n>  {\n> -       return read_one_entry_opt(sha1, base, baselen, pathname, mode, stage,\n> +       return read_one_entry_opt(sha1, base->buf, base->len, pathname,\n> +                                 mode, stage,\n>                                   ADD_CACHE_OK_TO_ADD|ADD_CACHE_SKIP_DFCHECK);\n>  }\n>\n> @@ -40,9 +43,12 @@ static int read_one_entry(const unsigned char *sha1, const char *base, int basel\n>   * This is used when the caller knows there is no existing entries at\n>   * the stage that will conflict with the entry being added.\n>   */\n> -static int read_one_entry_quick(const unsigned char *sha1, const char *base, int baselen, const char *pathname, unsigned mode, int stage, void *context)\n> +static int read_one_entry_quick(const unsigned char *sha1, struct strbuf *base,\n> +                               const char *pathname, unsigned mode, int stage,\n> +                               void *context)\n>  {\n> -       return read_one_entry_opt(sha1, base, baselen, pathname, mode, stage,\n> +       return read_one_entry_opt(sha1, base->buf, base->len, pathname,\n> +                                 mode, stage,\n>                                   ADD_CACHE_JUST_APPEND);\n>  }\n>\n> @@ -70,7 +76,7 @@ static int read_tree_1(struct tree *tree, struct strbuf *base,\n>                                 continue;\n>                 }\n>\n> -               switch (fn(entry.sha1, base->buf, base->len,\n> +               switch (fn(entry.sha1, base,\n>                            entry.path, entry.mode, stage, context)) {\n>                 case 0:\n>                         continue;\n> diff --git a/tree.h b/tree.h\n> index d84ac63..d24125f 100644\n> --- a/tree.h\n> +++ b/tree.h\n> @@ -4,6 +4,7 @@\n>  #include \"object.h\"\n>\n>  extern const char *tree_type;\n> +struct strbuf;\n>\n>  struct tree {\n>         struct object object;\n> @@ -22,7 +23,7 @@ void free_tree_buffer(struct tree *tree);\n>  struct tree *parse_tree_indirect(const unsigned char *sha1);\n>\n>  #define READ_TREE_RECURSIVE 1\n> -typedef int (*read_tree_fn_t)(const unsigned char *, const char *, int, const char *, unsigned int, int, void *);\n> +typedef int (*read_tree_fn_t)(const unsigned char *, struct strbuf *, const char *, unsigned int, int, void *);\n>\n>  extern int read_tree_recursive(struct tree *tree,\n>                                const char *base, int baselen,\n> --\n> 2.1.0.rc0.78.gc0d8480\n>\n> --\n> To unsubscribe from this list: send the line \"unsubscribe git\" in\n> the body of a message to majordomo@vger.kernel.org\n> More majordomo info at  http://vger.kernel.org/majordomo-info.html\n"},{"id":"251581","messageId":"1415523519-28789-1-git-send-email-pclouds@gmail.com","threadId":"37906","inReplyTo":"1415444432-18596-1-git-send-email-pclouds@gmail.com","subject":"[PATCH v2 1/3] tree.c: update read_tree_recursive callback to pass strbuf as base","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2014-11-09T08:58:37Z","receivedAt":"2014-11-09T08:58:37Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"This allows the callback to use 'base' as a temporary buffer to\nquickly assemble full path \"without\" extra allocation. The callback has\nto restore it afterwards of course.\n\nHelped-by: Eric Sunshine <sunshine@sunshineco.com>\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n Rebased on latest master, required because of my new changes on master..\n s/base_len/baselen/\n\n archive.c          | 34 +++++++++++++++++++++-------------\n builtin/checkout.c |  8 ++++----\n builtin/log.c      |  2 +-\n builtin/ls-tree.c  |  9 +++++----\n merge-recursive.c  | 15 ++++++---------\n tree.c             | 16 +++++++++++-----\n tree.h             |  3 ++-\n 7 files changed, 50 insertions(+), 37 deletions(-)\n\ndiff --git a/archive.c b/archive.c\nindex 94a9981..9e30246 100644\n--- a/archive.c\n+++ b/archive.c\n@@ -157,18 +157,26 @@ static int write_archive_entry(const unsigned char *sha1, const char *base,\n \treturn write_entry(args, sha1, path.buf, path.len, mode);\n }\n \n+static int write_archive_entry_buf(const unsigned char *sha1, struct strbuf *base,\n+\t\tconst char *filename, unsigned mode, int stage,\n+\t\tvoid *context)\n+{\n+\treturn write_archive_entry(sha1, base->buf, base->len,\n+\t\t\t\t     filename, mode, stage, context);\n+}\n+\n static void queue_directory(const unsigned char *sha1,\n-\t\tconst char *base, int baselen, const char *filename,\n+\t\tstruct strbuf *base, const char *filename,\n \t\tunsigned mode, int stage, struct archiver_context *c)\n {\n \tstruct directory *d;\n-\td = xmallocz(sizeof(*d) + baselen + 1 + strlen(filename));\n+\td = xmallocz(sizeof(*d) + base->len + 1 + strlen(filename));\n \td->up\t   = c->bottom;\n-\td->baselen = baselen;\n+\td->baselen = base->len;\n \td->mode\t   = mode;\n \td->stage   = stage;\n \tc->bottom  = d;\n-\td->len = sprintf(d->path, \"%.*s%s/\", baselen, base, filename);\n+\td->len = sprintf(d->path, \"%.*s%s/\", (int)base->len, base->buf, filename);\n \thashcpy(d->sha1, sha1);\n }\n \n@@ -191,28 +199,28 @@ static int write_directory(struct archiver_context *c)\n }\n \n static int queue_or_write_archive_entry(const unsigned char *sha1,\n-\t\tconst char *base, int baselen, const char *filename,\n+\t\tstruct strbuf *base, const char *filename,\n \t\tunsigned mode, int stage, void *context)\n {\n \tstruct archiver_context *c = context;\n \n \twhile (c->bottom &&\n-\t       !(baselen >= c->bottom->len &&\n-\t\t !strncmp(base, c->bottom->path, c->bottom->len))) {\n+\t       !(base->len >= c->bottom->len &&\n+\t\t !strncmp(base->buf, c->bottom->path, c->bottom->len))) {\n \t\tstruct directory *next = c->bottom->up;\n \t\tfree(c->bottom);\n \t\tc->bottom = next;\n \t}\n \n \tif (S_ISDIR(mode)) {\n-\t\tqueue_directory(sha1, base, baselen, filename,\n+\t\tqueue_directory(sha1, base, filename,\n \t\t\t\tmode, stage, c);\n \t\treturn READ_TREE_RECURSIVE;\n \t}\n \n \tif (write_directory(c))\n \t\treturn -1;\n-\treturn write_archive_entry(sha1, base, baselen, filename, mode,\n+\treturn write_archive_entry(sha1, base->buf, base->len, filename, mode,\n \t\t\t\t   stage, context);\n }\n \n@@ -260,7 +268,7 @@ int write_archive_entries(struct archiver_args *args,\n \terr = read_tree_recursive(args->tree, \"\", 0, 0, &args->pathspec,\n \t\t\t\t  args->pathspec.has_wildcard ?\n \t\t\t\t  queue_or_write_archive_entry :\n-\t\t\t\t  write_archive_entry,\n+\t\t\t\t  write_archive_entry_buf,\n \t\t\t\t  &context);\n \tif (err == READ_TREE_RECURSIVE)\n \t\terr = 0;\n@@ -286,14 +294,14 @@ static const struct archiver *lookup_archiver(const char *name)\n \treturn NULL;\n }\n \n-static int reject_entry(const unsigned char *sha1, const char *base,\n-\t\t\tint baselen, const char *filename, unsigned mode,\n+static int reject_entry(const unsigned char *sha1, struct strbuf *base,\n+\t\t\tconst char *filename, unsigned mode,\n \t\t\tint stage, void *context)\n {\n \tint ret = -1;\n \tif (S_ISDIR(mode)) {\n \t\tstruct strbuf sb = STRBUF_INIT;\n-\t\tstrbuf_addstr(&sb, base);\n+\t\tstrbuf_addbuf(&sb, base);\n \t\tstrbuf_addstr(&sb, filename);\n \t\tif (!match_pathspec(context, sb.buf, sb.len, 0, NULL, 1))\n \t\t\tret = READ_TREE_RECURSIVE;\ndiff --git a/builtin/checkout.c b/builtin/checkout.c\nindex 5410dac..8adf48d 100644\n--- a/builtin/checkout.c\n+++ b/builtin/checkout.c\n@@ -62,7 +62,7 @@ static int post_checkout_hook(struct commit *old, struct commit *new,\n \n }\n \n-static int update_some(const unsigned char *sha1, const char *base, int baselen,\n+static int update_some(const unsigned char *sha1, struct strbuf *base,\n \t\tconst char *pathname, unsigned mode, int stage, void *context)\n {\n \tint len;\n@@ -71,11 +71,11 @@ static int update_some(const unsigned char *sha1, const char *base, int baselen,\n \tif (S_ISDIR(mode))\n \t\treturn READ_TREE_RECURSIVE;\n \n-\tlen = baselen + strlen(pathname);\n+\tlen = base->len + strlen(pathname);\n \tce = xcalloc(1, cache_entry_size(len));\n \thashcpy(ce->sha1, sha1);\n-\tmemcpy(ce->name, base, baselen);\n-\tmemcpy(ce->name + baselen, pathname, len - baselen);\n+\tmemcpy(ce->name, base->buf, base->len);\n+\tmemcpy(ce->name + base->len, pathname, len - base->len);\n \tce->ce_flags = create_ce_flags(0) | CE_UPDATE;\n \tce->ce_namelen = len;\n \tce->ce_mode = create_ce_mode(mode);\ndiff --git a/builtin/log.c b/builtin/log.c\nindex 734aab3..f2a9f01 100644\n--- a/builtin/log.c\n+++ b/builtin/log.c\n@@ -489,7 +489,7 @@ static int show_tag_object(const unsigned char *sha1, struct rev_info *rev)\n }\n \n static int show_tree_object(const unsigned char *sha1,\n-\t\tconst char *base, int baselen,\n+\t\tstruct strbuf *base,\n \t\tconst char *pathname, unsigned mode, int stage, void *context)\n {\n \tprintf(\"%s%s\\n\", pathname, S_ISDIR(mode) ? \"/\" : \"\");\ndiff --git a/builtin/ls-tree.c b/builtin/ls-tree.c\nindex 51184df..1ab0381 100644\n--- a/builtin/ls-tree.c\n+++ b/builtin/ls-tree.c\n@@ -61,7 +61,7 @@ static int show_recursive(const char *base, int baselen, const char *pathname)\n \t}\n }\n \n-static int show_tree(const unsigned char *sha1, const char *base, int baselen,\n+static int show_tree(const unsigned char *sha1, struct strbuf *base,\n \t\tconst char *pathname, unsigned mode, int stage, void *context)\n {\n \tint retval = 0;\n@@ -79,7 +79,7 @@ static int show_tree(const unsigned char *sha1, const char *base, int baselen,\n \t\t */\n \t\ttype = commit_type;\n \t} else if (S_ISDIR(mode)) {\n-\t\tif (show_recursive(base, baselen, pathname)) {\n+\t\tif (show_recursive(base->buf, base->len, pathname)) {\n \t\t\tretval = READ_TREE_RECURSIVE;\n \t\t\tif (!(ls_options & LS_SHOW_TREES))\n \t\t\t\treturn retval;\n@@ -90,7 +90,8 @@ static int show_tree(const unsigned char *sha1, const char *base, int baselen,\n \t\treturn 0;\n \n \tif (chomp_prefix &&\n-\t    (baselen < chomp_prefix || memcmp(ls_tree_prefix, base, chomp_prefix)))\n+\t    (base->len < chomp_prefix ||\n+\t     memcmp(ls_tree_prefix, base->buf, chomp_prefix)))\n \t\treturn 0;\n \n \tif (!(ls_options & LS_NAME_ONLY)) {\n@@ -112,7 +113,7 @@ static int show_tree(const unsigned char *sha1, const char *base, int baselen,\n \t\t\tprintf(\"%06o %s %s\\t\", mode, type,\n \t\t\t       find_unique_abbrev(sha1, abbrev));\n \t}\n-\twrite_name_quotedpfx(base + chomp_prefix, baselen - chomp_prefix,\n+\twrite_name_quotedpfx(base->buf + chomp_prefix, base->len - chomp_prefix,\n \t\t\t  pathname, stdout, line_termination);\n \treturn retval;\n }\ndiff --git a/merge-recursive.c b/merge-recursive.c\nindex fdb7d0f..25c067e 100644\n--- a/merge-recursive.c\n+++ b/merge-recursive.c\n@@ -275,23 +275,20 @@ struct tree *write_tree_from_memory(struct merge_options *o)\n }\n \n static int save_files_dirs(const unsigned char *sha1,\n-\t\tconst char *base, int baselen, const char *path,\n+\t\tstruct strbuf *base, const char *path,\n \t\tunsigned int mode, int stage, void *context)\n {\n-\tint len = strlen(path);\n-\tchar *newpath = xmalloc(baselen + len + 1);\n+\tint baselen = base->len;\n \tstruct merge_options *o = context;\n \n-\tmemcpy(newpath, base, baselen);\n-\tmemcpy(newpath + baselen, path, len);\n-\tnewpath[baselen + len] = '\\0';\n+\tstrbuf_addstr(base, path);\n \n \tif (S_ISDIR(mode))\n-\t\tstring_list_insert(&o->current_directory_set, newpath);\n+\t\tstring_list_insert(&o->current_directory_set, base->buf);\n \telse\n-\t\tstring_list_insert(&o->current_file_set, newpath);\n-\tfree(newpath);\n+\t\tstring_list_insert(&o->current_file_set, base->buf);\n \n+\tstrbuf_setlen(base, baselen);\n \treturn (S_ISDIR(mode) ? READ_TREE_RECURSIVE : 0);\n }\n \ndiff --git a/tree.c b/tree.c\nindex bb02c1c..58ebfce 100644\n--- a/tree.c\n+++ b/tree.c\n@@ -30,9 +30,12 @@ static int read_one_entry_opt(const unsigned char *sha1, const char *base, int b\n \treturn add_cache_entry(ce, opt);\n }\n \n-static int read_one_entry(const unsigned char *sha1, const char *base, int baselen, const char *pathname, unsigned mode, int stage, void *context)\n+static int read_one_entry(const unsigned char *sha1, struct strbuf *base,\n+\t\t\t  const char *pathname, unsigned mode, int stage,\n+\t\t\t  void *context)\n {\n-\treturn read_one_entry_opt(sha1, base, baselen, pathname, mode, stage,\n+\treturn read_one_entry_opt(sha1, base->buf, base->len, pathname,\n+\t\t\t\t  mode, stage,\n \t\t\t\t  ADD_CACHE_OK_TO_ADD|ADD_CACHE_SKIP_DFCHECK);\n }\n \n@@ -40,9 +43,12 @@ static int read_one_entry(const unsigned char *sha1, const char *base, int basel\n  * This is used when the caller knows there is no existing entries at\n  * the stage that will conflict with the entry being added.\n  */\n-static int read_one_entry_quick(const unsigned char *sha1, const char *base, int baselen, const char *pathname, unsigned mode, int stage, void *context)\n+static int read_one_entry_quick(const unsigned char *sha1, struct strbuf *base,\n+\t\t\t\tconst char *pathname, unsigned mode, int stage,\n+\t\t\t\tvoid *context)\n {\n-\treturn read_one_entry_opt(sha1, base, baselen, pathname, mode, stage,\n+\treturn read_one_entry_opt(sha1, base->buf, base->len, pathname,\n+\t\t\t\t  mode, stage,\n \t\t\t\t  ADD_CACHE_JUST_APPEND);\n }\n \n@@ -70,7 +76,7 @@ static int read_tree_1(struct tree *tree, struct strbuf *base,\n \t\t\t\tcontinue;\n \t\t}\n \n-\t\tswitch (fn(entry.sha1, base->buf, base->len,\n+\t\tswitch (fn(entry.sha1, base,\n \t\t\t   entry.path, entry.mode, stage, context)) {\n \t\tcase 0:\n \t\t\tcontinue;\ndiff --git a/tree.h b/tree.h\nindex d84ac63..d24125f 100644\n--- a/tree.h\n+++ b/tree.h\n@@ -4,6 +4,7 @@\n #include \"object.h\"\n \n extern const char *tree_type;\n+struct strbuf;\n \n struct tree {\n \tstruct object object;\n@@ -22,7 +23,7 @@ void free_tree_buffer(struct tree *tree);\n struct tree *parse_tree_indirect(const unsigned char *sha1);\n \n #define READ_TREE_RECURSIVE 1\n-typedef int (*read_tree_fn_t)(const unsigned char *, const char *, int, const char *, unsigned int, int, void *);\n+typedef int (*read_tree_fn_t)(const unsigned char *, struct strbuf *, const char *, unsigned int, int, void *);\n \n extern int read_tree_recursive(struct tree *tree,\n \t\t\t       const char *base, int baselen,\n-- \n2.1.0.rc0.78.gc0d8480\n"},{"id":"251582","messageId":"1415523519-28789-2-git-send-email-pclouds@gmail.com","threadId":"37906","inReplyTo":"1415523519-28789-1-git-send-email-pclouds@gmail.com","subject":"[PATCH v2 2/3] ls-tree: disable negative pathspec because it's not supported","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2014-11-09T08:58:38Z","receivedAt":"2014-11-09T08:58:38Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n builtin/ls-tree.c | 3 ++-\n 1 file changed, 2 insertions(+), 1 deletion(-)\n\ndiff --git a/builtin/ls-tree.c b/builtin/ls-tree.c\nindex 1ab0381..d226344 100644\n--- a/builtin/ls-tree.c\n+++ b/builtin/ls-tree.c\n@@ -174,7 +174,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+\tparse_pathspec(&pathspec, PATHSPEC_GLOB | PATHSPEC_ICASE |\n+\t\t\t\t  PATHSPEC_EXCLUDE,\n \t\t       PATHSPEC_PREFER_CWD,\n \t\t       prefix, argv + 1);\n \tfor (i = 0; i < pathspec.nr; i++)\n-- \n2.1.0.rc0.78.gc0d8480\n"},{"id":"251583","messageId":"1415523519-28789-3-git-send-email-pclouds@gmail.com","threadId":"37906","inReplyTo":"1415523519-28789-1-git-send-email-pclouds@gmail.com","subject":"[PATCH v2 3/3] ls-tree: remove path filtering logic in show_tree","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2014-11-09T08:58:39Z","receivedAt":"2014-11-09T08:58:39Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"ls-tree uses read_tree_recursive() which already does path filtering\nusing pathspec. No need to filter one more time based on prefix\nonly. \"ls-tree ../somewhere\" does not work because of\nthis. write_name_quotedpfx() can now be retired because nobody else\nuses it.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n builtin/ls-tree.c            | 14 +++++++-------\n quote.c                      | 21 ---------------------\n quote.h                      |  2 --\n t/t3102-ls-tree-wildcards.sh |  8 ++++++++\n 4 files changed, 15 insertions(+), 30 deletions(-)\n\ndiff --git a/builtin/ls-tree.c b/builtin/ls-tree.c\nindex d226344..3b04a0f 100644\n--- a/builtin/ls-tree.c\n+++ b/builtin/ls-tree.c\n@@ -65,6 +65,7 @@ static int show_tree(const unsigned char *sha1, struct strbuf *base,\n \t\tconst char *pathname, unsigned mode, int stage, void *context)\n {\n \tint retval = 0;\n+\tint baselen;\n \tconst char *type = blob_type;\n \n \tif (S_ISGITLINK(mode)) {\n@@ -89,11 +90,6 @@ static int show_tree(const unsigned char *sha1, struct strbuf *base,\n \telse if (ls_options & LS_TREE_ONLY)\n \t\treturn 0;\n \n-\tif (chomp_prefix &&\n-\t    (base->len < chomp_prefix ||\n-\t     memcmp(ls_tree_prefix, base->buf, chomp_prefix)))\n-\t\treturn 0;\n-\n \tif (!(ls_options & LS_NAME_ONLY)) {\n \t\tif (ls_options & LS_SHOW_SIZE) {\n \t\t\tchar size_text[24];\n@@ -113,8 +109,12 @@ static int show_tree(const unsigned char *sha1, struct strbuf *base,\n \t\t\tprintf(\"%06o %s %s\\t\", mode, type,\n \t\t\t       find_unique_abbrev(sha1, abbrev));\n \t}\n-\twrite_name_quotedpfx(base->buf + chomp_prefix, base->len - chomp_prefix,\n-\t\t\t  pathname, stdout, line_termination);\n+\tbaselen = base->len;\n+\tstrbuf_addstr(base, pathname);\n+\twrite_name_quoted_relative(base->buf,\n+\t\t\t\t   chomp_prefix ? ls_tree_prefix : NULL,\n+\t\t\t\t   stdout, line_termination);\n+\tstrbuf_setlen(base, baselen);\n \treturn retval;\n }\n \ndiff --git a/quote.c b/quote.c\nindex 45e3db1..7920e18 100644\n--- a/quote.c\n+++ b/quote.c\n@@ -274,27 +274,6 @@ void write_name_quoted(const char *name, FILE *fp, int terminator)\n \tfputc(terminator, fp);\n }\n \n-void write_name_quotedpfx(const char *pfx, size_t pfxlen,\n-\t\t\t  const char *name, FILE *fp, int terminator)\n-{\n-\tint needquote = 0;\n-\n-\tif (terminator) {\n-\t\tneedquote = next_quote_pos(pfx, pfxlen) < pfxlen\n-\t\t\t|| name[next_quote_pos(name, -1)];\n-\t}\n-\tif (needquote) {\n-\t\tfputc('\"', fp);\n-\t\tquote_c_style_counted(pfx, pfxlen, NULL, fp, 1);\n-\t\tquote_c_style(name, NULL, fp, 1);\n-\t\tfputc('\"', fp);\n-\t} else {\n-\t\tfwrite(pfx, pfxlen, 1, fp);\n-\t\tfputs(name, fp);\n-\t}\n-\tfputc(terminator, fp);\n-}\n-\n void write_name_quoted_relative(const char *name, const char *prefix,\n \t\t\t\tFILE *fp, int terminator)\n {\ndiff --git a/quote.h b/quote.h\nindex 71dcc3a..99e04d3 100644\n--- a/quote.h\n+++ b/quote.h\n@@ -56,8 +56,6 @@ extern size_t quote_c_style(const char *name, struct strbuf *, FILE *, int no_dq\n extern void quote_two_c_style(struct strbuf *, const char *, const char *, int);\n \n extern void write_name_quoted(const char *name, FILE *, int terminator);\n-extern void write_name_quotedpfx(const char *pfx, size_t pfxlen,\n-                                 const char *name, FILE *, int terminator);\n extern void write_name_quoted_relative(const char *name, const char *prefix,\n \t\tFILE *fp, int terminator);\n \ndiff --git a/t/t3102-ls-tree-wildcards.sh b/t/t3102-ls-tree-wildcards.sh\nindex c286854..83fca8d 100755\n--- a/t/t3102-ls-tree-wildcards.sh\n+++ b/t/t3102-ls-tree-wildcards.sh\n@@ -19,4 +19,12 @@ EOF\n \ttest_cmp expected actual\n '\n \n+test_expect_success 'ls-tree outside prefix' '\n+\tcat >expected <<EOF &&\n+100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391\t../a[a]/three\n+EOF\n+\t( cd aa && git ls-tree -r HEAD \"../a[a]\"; ) >actual &&\n+\ttest_cmp expected actual\n+'\n+\n test_done\n-- \n2.1.0.rc0.78.gc0d8480\n"}]}