{"thread":{"id":"39466","subject":"[WIP/PATCH v4 1/8] for-each-ref: extract helper functions out of grab_single_ref()","startedAt":"2015-05-30T17:53:24Z","lastAt":"2015-06-01T19:35:52Z","messageCount":44,"participants":["Karthik Nayak","Eric Sunshine","Christian Couder","Junio C Hamano","Matthieu Moy"],"isPatch":true,"patchVersion":4,"patchTotal":8},"messages":[{"id":"262475","messageId":"1433008411-8550-1-git-send-email-karthik.188@gmail.com","threadId":"39466","inReplyTo":"5569EF77.4010300@gmail.com","subject":"[WIP/PATCH v4 1/8] for-each-ref: extract helper functions out of grab_single_ref()","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2015-05-30T17:53:24Z","receivedAt":"2015-05-30T17:53:24Z","isPatch":true,"sender":{"key":"karthik.188@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1786334?v=4"},"body":"Extract two helper functions out of grab_single_ref(). Firstly,\nnew_refinfo() which is used to allocate memory for a new refinfo\nstructure and copy the objectname, refname and flag to it.\nSecondly, match_name_as_path() which when given an array of patterns\nand the refname checks if the refname matches any of the patterns\ngiven while the pattern is a pathname, also while supporting wild\ncharacters.\n\nThis is a preperatory patch for restructuring 'for-each-ref' and\neventually moving most of it to 'ref-filter' to provide the\nfunctionality to similar commands via public API's.\n\nHelped-by: Junio C Hamano <gitster@pobox.com>\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr>\nSigned-off-by: Karthik Nayak <karthik.188@gmail.com>\n---\n builtin/for-each-ref.c | 69 ++++++++++++++++++++++++++++++--------------------\n 1 file changed, 41 insertions(+), 28 deletions(-)\n\ndiff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c\nindex 83f9cf9..b33e2de 100644\n--- a/builtin/for-each-ref.c\n+++ b/builtin/for-each-ref.c\n@@ -837,6 +837,43 @@ struct grab_ref_cbdata {\n };\n \n /*\n+ * Given a refname, return 1 if the refname matches with one of the patterns\n+ * while the pattern is a pathname like 'refs/tags' or 'refs/heads/master'\n+ * and so on, else return 0. Supports use of wild characters.\n+ */\n+static int match_name_as_path(const char **pattern, const char *refname)\n+{\n+\tint namelen = strlen(refname);\n+\tfor (; *pattern; pattern++) {\n+\t\tconst char *p = *pattern;\n+\t\tint plen = strlen(p);\n+\n+\t\tif ((plen <= namelen) &&\n+\t\t    !strncmp(refname, p, plen) &&\n+\t\t    (refname[plen] == '\\0' ||\n+\t\t     refname[plen] == '/' ||\n+\t\t     p[plen-1] == '/'))\n+\t\t\treturn 1;\n+\t\tif (!wildmatch(p, refname, WM_PATHNAME, NULL))\n+\t\t\treturn 1;\n+\t}\n+\treturn 0;\n+}\n+\n+/* Allocate space for a new refinfo and copy the objectname and flag to it */\n+static struct refinfo *new_refinfo(const char *refname,\n+\t\t\t\t   const unsigned char *objectname,\n+\t\t\t\t   int flag)\n+{\n+\tstruct refinfo *ref = xcalloc(1, sizeof(struct refinfo));\n+\tref->refname = xstrdup(refname);\n+\thashcpy(ref->objectname, objectname);\n+\tref->flag = flag;\n+\n+\treturn ref;\n+}\n+\n+/*\n  * A call-back given to for_each_ref().  Filter refs and keep them for\n  * later object processing.\n  */\n@@ -851,40 +888,16 @@ static int grab_single_ref(const char *refname, const unsigned char *sha1, int f\n \t\t  return 0;\n \t}\n \n-\tif (*cb->grab_pattern) {\n-\t\tconst char **pattern;\n-\t\tint namelen = strlen(refname);\n-\t\tfor (pattern = cb->grab_pattern; *pattern; pattern++) {\n-\t\t\tconst char *p = *pattern;\n-\t\t\tint plen = strlen(p);\n-\n-\t\t\tif ((plen <= namelen) &&\n-\t\t\t    !strncmp(refname, p, plen) &&\n-\t\t\t    (refname[plen] == '\\0' ||\n-\t\t\t     refname[plen] == '/' ||\n-\t\t\t     p[plen-1] == '/'))\n-\t\t\t\tbreak;\n-\t\t\tif (!wildmatch(p, refname, WM_PATHNAME, NULL))\n-\t\t\t\tbreak;\n-\t\t}\n-\t\tif (!*pattern)\n-\t\t\treturn 0;\n-\t}\n+\tif (*cb->grab_pattern && !match_name_as_path(cb->grab_pattern, refname))\n+\t\treturn 0;\n \n-\t/*\n-\t * We do not open the object yet; sort may only need refname\n-\t * to do its job and the resulting list may yet to be pruned\n-\t * by maxcount logic.\n-\t */\n-\tref = xcalloc(1, sizeof(*ref));\n-\tref->refname = xstrdup(refname);\n-\thashcpy(ref->objectname, sha1);\n-\tref->flag = flag;\n+\tref = new_refinfo(refname, sha1, flag);\n \n \tcnt = cb->grab_cnt;\n \tREALLOC_ARRAY(cb->grab_array, cnt + 1);\n \tcb->grab_array[cnt++] = ref;\n \tcb->grab_cnt = cnt;\n+\n \treturn 0;\n }\n \n-- \n2.4.2\n"},{"id":"262476","messageId":"1433008411-8550-2-git-send-email-karthik.188@gmail.com","threadId":"39466","inReplyTo":"5569EF77.4010300@gmail.com","subject":"[WIP/PATCH v4 2/8] for-each-ref: simplify code","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2015-05-30T17:53:25Z","receivedAt":"2015-05-30T17:53:25Z","isPatch":true,"sender":{"key":"karthik.188@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1786334?v=4"},"body":"In 'grab_single_ref()' remove the extra count variable 'cnt' and\nuse the variable 'grab_cnt' of structure 'grab_ref_cbdata' directly\ninstead.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr>\nSigned-off-by: Karthik Nayak <karthik.188@gmail.com>\n---\n builtin/for-each-ref.c | 7 ++-----\n 1 file changed, 2 insertions(+), 5 deletions(-)\n\ndiff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c\nindex b33e2de..919d45e 100644\n--- a/builtin/for-each-ref.c\n+++ b/builtin/for-each-ref.c\n@@ -881,7 +881,6 @@ static int grab_single_ref(const char *refname, const unsigned char *sha1, int f\n {\n \tstruct grab_ref_cbdata *cb = cb_data;\n \tstruct refinfo *ref;\n-\tint cnt;\n \n \tif (flag & REF_BAD_NAME) {\n \t\t  warning(\"ignoring ref with broken name %s\", refname);\n@@ -893,10 +892,8 @@ static int grab_single_ref(const char *refname, const unsigned char *sha1, int f\n \n \tref = new_refinfo(refname, sha1, flag);\n \n-\tcnt = cb->grab_cnt;\n-\tREALLOC_ARRAY(cb->grab_array, cnt + 1);\n-\tcb->grab_array[cnt++] = ref;\n-\tcb->grab_cnt = cnt;\n+\tREALLOC_ARRAY(cb->grab_array, cb->grab_cnt + 1);\n+\tcb->grab_array[cb->grab_cnt++] = ref;\n \n \treturn 0;\n }\n-- \n2.4.2\n"},{"id":"262477","messageId":"1433008411-8550-3-git-send-email-karthik.188@gmail.com","threadId":"39466","inReplyTo":"5569EF77.4010300@gmail.com","subject":"[WIP/PATCH v4 3/8] for-each-ref: rename 'refinfo' to 'ref_array_item'","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2015-05-30T17:53:26Z","receivedAt":"2015-05-30T17:53:26Z","isPatch":true,"sender":{"key":"karthik.188@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1786334?v=4"},"body":"Rename 'refinfo' to 'ref_array_item' as a preparatory step for introduction of new structures in the forthcoming patch.\n\nRe-order the fields in 'ref_array_item' so that refname can be\neventually converted to a FLEX_ARRAY.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr>\nSigned-off-by: Karthik Nayak <karthik.188@gmail.com>\n---\n builtin/for-each-ref.c | 40 ++++++++++++++++++++--------------------\n 1 file changed, 20 insertions(+), 20 deletions(-)\n\ndiff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c\nindex 919d45e..e634fd2 100644\n--- a/builtin/for-each-ref.c\n+++ b/builtin/for-each-ref.c\n@@ -31,12 +31,12 @@ struct ref_sort {\n \tunsigned reverse : 1;\n };\n \n-struct refinfo {\n-\tchar *refname;\n+struct ref_array_item {\n \tunsigned char objectname[20];\n \tint flag;\n \tconst char *symref;\n \tstruct atom_value *value;\n+\tchar *refname;\n };\n \n static struct {\n@@ -85,7 +85,7 @@ static struct {\n  * a \"*\" to denote deref_tag().\n  *\n  * We parse given format string and sort specifiers, and make a list\n- * of properties that we need to extract out of objects.  refinfo\n+ * of properties that we need to extract out of objects.  ref_array_item\n  * structure will hold an array of values extracted that can be\n  * indexed with the \"atom number\", which is an index into this\n  * array.\n@@ -622,7 +622,7 @@ static inline char *copy_advance(char *dst, const char *src)\n /*\n  * Parse the object referred by ref, and grab needed value.\n  */\n-static void populate_value(struct refinfo *ref)\n+static void populate_value(struct ref_array_item *ref)\n {\n \tvoid *buf;\n \tstruct object *obj;\n@@ -821,7 +821,7 @@ static void populate_value(struct refinfo *ref)\n  * Given a ref, return the value for the atom.  This lazily gets value\n  * out of the object by calling populate value.\n  */\n-static void get_value(struct refinfo *ref, int atom, struct atom_value **v)\n+static void get_value(struct ref_array_item *ref, int atom, struct atom_value **v)\n {\n \tif (!ref->value) {\n \t\tpopulate_value(ref);\n@@ -831,7 +831,7 @@ static void get_value(struct refinfo *ref, int atom, struct atom_value **v)\n }\n \n struct grab_ref_cbdata {\n-\tstruct refinfo **grab_array;\n+\tstruct ref_array_item **grab_array;\n \tconst char **grab_pattern;\n \tint grab_cnt;\n };\n@@ -860,12 +860,12 @@ static int match_name_as_path(const char **pattern, const char *refname)\n \treturn 0;\n }\n \n-/* Allocate space for a new refinfo and copy the objectname and flag to it */\n-static struct refinfo *new_refinfo(const char *refname,\n-\t\t\t\t   const unsigned char *objectname,\n-\t\t\t\t   int flag)\n+/* Allocate space for a new ref_array_item and copy the objectname and flag to it */\n+static struct ref_array_item *new_ref_array_item(const char *refname,\n+\t\t\t\t\t\t const unsigned char *objectname,\n+\t\t\t\t\t\t int flag)\n {\n-\tstruct refinfo *ref = xcalloc(1, sizeof(struct refinfo));\n+\tstruct ref_array_item *ref = xcalloc(1, sizeof(struct ref_array_item));\n \tref->refname = xstrdup(refname);\n \thashcpy(ref->objectname, objectname);\n \tref->flag = flag;\n@@ -880,7 +880,7 @@ static struct refinfo *new_refinfo(const char *refname,\n static int grab_single_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data)\n {\n \tstruct grab_ref_cbdata *cb = cb_data;\n-\tstruct refinfo *ref;\n+\tstruct ref_array_item *ref;\n \n \tif (flag & REF_BAD_NAME) {\n \t\t  warning(\"ignoring ref with broken name %s\", refname);\n@@ -890,7 +890,7 @@ static int grab_single_ref(const char *refname, const unsigned char *sha1, int f\n \tif (*cb->grab_pattern && !match_name_as_path(cb->grab_pattern, refname))\n \t\treturn 0;\n \n-\tref = new_refinfo(refname, sha1, flag);\n+\tref = new_ref_array_item(refname, sha1, flag);\n \n \tREALLOC_ARRAY(cb->grab_array, cb->grab_cnt + 1);\n \tcb->grab_array[cb->grab_cnt++] = ref;\n@@ -898,7 +898,7 @@ static int grab_single_ref(const char *refname, const unsigned char *sha1, int f\n \treturn 0;\n }\n \n-static int cmp_ref_sort(struct ref_sort *s, struct refinfo *a, struct refinfo *b)\n+static int cmp_ref_sort(struct ref_sort *s, struct ref_array_item *a, struct ref_array_item *b)\n {\n \tstruct atom_value *va, *vb;\n \tint cmp;\n@@ -925,8 +925,8 @@ static int cmp_ref_sort(struct ref_sort *s, struct refinfo *a, struct refinfo *b\n static struct ref_sort *ref_sort;\n static int compare_refs(const void *a_, const void *b_)\n {\n-\tstruct refinfo *a = *((struct refinfo **)a_);\n-\tstruct refinfo *b = *((struct refinfo **)b_);\n+\tstruct ref_array_item *a = *((struct ref_array_item **)a_);\n+\tstruct ref_array_item *b = *((struct ref_array_item **)b_);\n \tstruct ref_sort *s;\n \n \tfor (s = ref_sort; s; s = s->next) {\n@@ -937,10 +937,10 @@ static int compare_refs(const void *a_, const void *b_)\n \treturn 0;\n }\n \n-static void sort_refs(struct ref_sort *sort, struct refinfo **refs, int num_refs)\n+static void sort_refs(struct ref_sort *sort, struct ref_array_item **refs, int num_refs)\n {\n \tref_sort = sort;\n-\tqsort(refs, num_refs, sizeof(struct refinfo *), compare_refs);\n+\tqsort(refs, num_refs, sizeof(struct ref_array_item *), compare_refs);\n }\n \n static void print_value(struct atom_value *v, int quote_style)\n@@ -1007,7 +1007,7 @@ static void emit(const char *cp, const char *ep)\n \t}\n }\n \n-static void show_ref(struct refinfo *info, const char *format, int quote_style)\n+static void show_ref(struct ref_array_item *info, const char *format, int quote_style)\n {\n \tconst char *cp, *sp, *ep;\n \n@@ -1080,7 +1080,7 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix)\n \tconst char *format = \"%(objectname) %(objecttype)\\t%(refname)\";\n \tstruct ref_sort *sort = NULL, **sort_tail = &sort;\n \tint maxcount = 0, quote_style = 0;\n-\tstruct refinfo **refs;\n+\tstruct ref_array_item **refs;\n \tstruct grab_ref_cbdata cbdata;\n \n \tstruct option opts[] = {\n-- \n2.4.2\n"},{"id":"262479","messageId":"1433008411-8550-4-git-send-email-karthik.188@gmail.com","threadId":"39466","inReplyTo":"5569EF77.4010300@gmail.com","subject":"[WIP/PATCH v4 4/8] for-each-ref: introduce new structures for better organisation","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2015-05-30T17:53:27Z","receivedAt":"2015-05-30T17:53:27Z","isPatch":true,"sender":{"key":"karthik.188@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1786334?v=4"},"body":"Intoduce 'ref_filter_cbdata' which will hold 'ref_filter'\n(Conditions to filter the refs on) and 'ref_array' (The array\nof ref_array_items). Modify the code to use these new structures.\n\nThis is a preparatory patch to eventually move code from 'for-each-ref'\nto 'ref-filter' and making it publically available.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr>\nSigned-off-by: Karthik Nayak <karthik.188@gmail.com>\n---\n builtin/for-each-ref.c | 56 ++++++++++++++++++++++++++++----------------------\n 1 file changed, 31 insertions(+), 25 deletions(-)\n\ndiff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c\nindex e634fd2..ef54c90 100644\n--- a/builtin/for-each-ref.c\n+++ b/builtin/for-each-ref.c\n@@ -39,6 +39,20 @@ struct ref_array_item {\n \tchar *refname;\n };\n \n+struct ref_array {\n+\tint nr, alloc;\n+\tstruct ref_array_item **items;\n+};\n+\n+struct ref_filter {\n+\tconst char **name_patterns;\n+};\n+\n+struct ref_filter_cbdata {\n+\tstruct ref_array array;\n+\tstruct ref_filter filter;\n+};\n+\n static struct {\n \tconst char *name;\n \tcmp_type cmp_type;\n@@ -85,7 +99,7 @@ static struct {\n  * a \"*\" to denote deref_tag().\n  *\n  * We parse given format string and sort specifiers, and make a list\n- * of properties that we need to extract out of objects.  ref_array_item\n+ * of properties that we need to extract out of objects. ref_array_item\n  * structure will hold an array of values extracted that can be\n  * indexed with the \"atom number\", which is an index into this\n  * array.\n@@ -830,12 +844,6 @@ static void get_value(struct ref_array_item *ref, int atom, struct atom_value **\n \t*v = &ref->value[atom];\n }\n \n-struct grab_ref_cbdata {\n-\tstruct ref_array_item **grab_array;\n-\tconst char **grab_pattern;\n-\tint grab_cnt;\n-};\n-\n /*\n  * Given a refname, return 1 if the refname matches with one of the patterns\n  * while the pattern is a pathname like 'refs/tags' or 'refs/heads/master'\n@@ -879,7 +887,8 @@ static struct ref_array_item *new_ref_array_item(const char *refname,\n  */\n static int grab_single_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data)\n {\n-\tstruct grab_ref_cbdata *cb = cb_data;\n+\tstruct ref_filter_cbdata *ref_cbdata = cb_data;\n+\tstruct ref_filter *filter = &ref_cbdata->filter;\n \tstruct ref_array_item *ref;\n \n \tif (flag & REF_BAD_NAME) {\n@@ -887,13 +896,13 @@ static int grab_single_ref(const char *refname, const unsigned char *sha1, int f\n \t\t  return 0;\n \t}\n \n-\tif (*cb->grab_pattern && !match_name_as_path(cb->grab_pattern, refname))\n+\tif (*filter->name_patterns && !match_name_as_path(filter->name_patterns, refname))\n \t\treturn 0;\n \n \tref = new_ref_array_item(refname, sha1, flag);\n \n-\tREALLOC_ARRAY(cb->grab_array, cb->grab_cnt + 1);\n-\tcb->grab_array[cb->grab_cnt++] = ref;\n+\tREALLOC_ARRAY(ref_cbdata->array.items, ref_cbdata->array.nr + 1);\n+\tref_cbdata->array.items[ref_cbdata->array.nr++] = ref;\n \n \treturn 0;\n }\n@@ -937,10 +946,10 @@ static int compare_refs(const void *a_, const void *b_)\n \treturn 0;\n }\n \n-static void sort_refs(struct ref_sort *sort, struct ref_array_item **refs, int num_refs)\n+static void sort_refs(struct ref_sort *sort, struct ref_array *array)\n {\n \tref_sort = sort;\n-\tqsort(refs, num_refs, sizeof(struct ref_array_item *), compare_refs);\n+\tqsort(array->items, array->nr, sizeof(struct ref_array_item *), compare_refs);\n }\n \n static void print_value(struct atom_value *v, int quote_style)\n@@ -1076,12 +1085,12 @@ static char const * const for_each_ref_usage[] = {\n \n int cmd_for_each_ref(int argc, const char **argv, const char *prefix)\n {\n-\tint i, num_refs;\n+\tint i;\n \tconst char *format = \"%(objectname) %(objecttype)\\t%(refname)\";\n \tstruct ref_sort *sort = NULL, **sort_tail = &sort;\n \tint maxcount = 0, quote_style = 0;\n-\tstruct ref_array_item **refs;\n-\tstruct grab_ref_cbdata cbdata;\n+\tstruct ref_filter_cbdata ref_cbdata;\n+\tmemset(&ref_cbdata, 0, sizeof(ref_cbdata));\n \n \tstruct option opts[] = {\n \t\tOPT_BIT('s', \"shell\", &quote_style,\n@@ -1119,17 +1128,14 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix)\n \t/* for warn_ambiguous_refs */\n \tgit_config(git_default_config, NULL);\n \n-\tmemset(&cbdata, 0, sizeof(cbdata));\n-\tcbdata.grab_pattern = argv;\n-\tfor_each_rawref(grab_single_ref, &cbdata);\n-\trefs = cbdata.grab_array;\n-\tnum_refs = cbdata.grab_cnt;\n+\tref_cbdata.filter.name_patterns = argv;\n+\tfor_each_rawref(grab_single_ref, &ref_cbdata);\n \n-\tsort_refs(sort, refs, num_refs);\n+\tsort_refs(sort, &ref_cbdata.array);\n \n-\tif (!maxcount || num_refs < maxcount)\n-\t\tmaxcount = num_refs;\n+\tif (!maxcount || ref_cbdata.array.nr < maxcount)\n+\t\tmaxcount = ref_cbdata.array.nr;\n \tfor (i = 0; i < maxcount; i++)\n-\t\tshow_ref(refs[i], format, quote_style);\n+\t\tshow_ref(ref_cbdata.array.items[i], format, quote_style);\n \treturn 0;\n }\n-- \n2.4.2\n"},{"id":"262478","messageId":"1433008411-8550-5-git-send-email-karthik.188@gmail.com","threadId":"39466","inReplyTo":"5569EF77.4010300@gmail.com","subject":"[WIP/PATCH v4 5/8] for-each-ref: introduce 'ref_filter_clear_data()'","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2015-05-30T17:53:28Z","receivedAt":"2015-05-30T17:53:28Z","isPatch":true,"sender":{"key":"karthik.188@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1786334?v=4"},"body":"Introduce and implement 'ref_filter_clear_data()' which will free\nall allocated memory for 'ref_filter_cbdata' and its underlying array\nof 'ref_array_item'.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr>\nSigned-off-by: Karthik Nayak <karthik.188@gmail.com>\n---\n builtin/for-each-ref.c | 13 +++++++++++++\n 1 file changed, 13 insertions(+)\n\ndiff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c\nindex ef54c90..f896e1c 100644\n--- a/builtin/for-each-ref.c\n+++ b/builtin/for-each-ref.c\n@@ -907,6 +907,18 @@ static int grab_single_ref(const char *refname, const unsigned char *sha1, int f\n \treturn 0;\n }\n \n+/* Free all memory allocated for ref_filter_cbdata */\n+void ref_filter_clear_data(struct ref_filter_cbdata *ref_cbdata)\n+{\n+\tint i;\n+\n+\tfor (i = 0; i < ref_cbdata->array.nr; i++)\n+\t\tfree(ref_cbdata->array.items[i]);\n+\tfree(ref_cbdata->array.items);\n+\tref_cbdata->array.items = NULL;\n+\tref_cbdata->array.nr = ref_cbdata->array.alloc = 0;\n+}\n+\n static int cmp_ref_sort(struct ref_sort *s, struct ref_array_item *a, struct ref_array_item *b)\n {\n \tstruct atom_value *va, *vb;\n@@ -1137,5 +1149,6 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix)\n \t\tmaxcount = ref_cbdata.array.nr;\n \tfor (i = 0; i < maxcount; i++)\n \t\tshow_ref(ref_cbdata.array.items[i], format, quote_style);\n+\tref_filter_clear_data(&ref_cbdata);\n \treturn 0;\n }\n-- \n2.4.2\n"},{"id":"262480","messageId":"1433008411-8550-6-git-send-email-karthik.188@gmail.com","threadId":"39466","inReplyTo":"5569EF77.4010300@gmail.com","subject":"[WIP/PATCH v4 6/8] for-each-ref: rename some functions and make them public","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2015-05-30T17:53:29Z","receivedAt":"2015-05-30T17:53:29Z","isPatch":true,"sender":{"key":"karthik.188@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1786334?v=4"},"body":"Rename some of the functions and make them publically available.\nThis is a preparatory step for moving code from 'for-each-ref'\nto 'ref-filter' to make meaningful, targeted services available to\nother commands via public APIs.\n\nBased-on-patch-by: Jeff King <peff@peff.net>\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr>\nSigned-off-by: Karthik Nayak <karthik.188@gmail.com>\n---\n builtin/for-each-ref.c | 45 +++++++++++++++++++++++----------------------\n 1 file changed, 23 insertions(+), 22 deletions(-)\n\ndiff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c\nindex f896e1c..8fed04b 100644\n--- a/builtin/for-each-ref.c\n+++ b/builtin/for-each-ref.c\n@@ -112,7 +112,7 @@ static int need_color_reset_at_eol;\n /*\n  * Used to parse format string and sort specifiers\n  */\n-static int parse_atom(const char *atom, const char *ep)\n+int parse_ref_filter_atom(const char *atom, const char *ep)\n {\n \tconst char *sp;\n \tint i, at;\n@@ -189,7 +189,7 @@ static const char *find_next(const char *cp)\n  * Make sure the format string is well formed, and parse out\n  * the used atoms.\n  */\n-static int verify_format(const char *format)\n+int verify_ref_format(const char *format)\n {\n \tconst char *cp, *sp;\n \n@@ -201,7 +201,7 @@ static int verify_format(const char *format)\n \t\tif (!ep)\n \t\t\treturn error(\"malformed format string %s\", sp);\n \t\t/* sp points at \"%(\" and ep points at the closing \")\" */\n-\t\tat = parse_atom(sp + 2, ep);\n+\t\tat = parse_ref_filter_atom(sp + 2, ep);\n \t\tcp = ep + 1;\n \n \t\tif (skip_prefix(used_atom[at], \"color:\", &color))\n@@ -408,7 +408,7 @@ static void grab_date(const char *buf, struct atom_value *v, const char *atomnam\n \t/*\n \t * We got here because atomname ends in \"date\" or \"date<something>\";\n \t * it's not possible that <something> is not \":<format>\" because\n-\t * parse_atom() wouldn't have allowed it, so we can assume that no\n+\t * parse_ref_filter_atom() wouldn't have allowed it, so we can assume that no\n \t * \":\" means no format is specified, and use the default.\n \t */\n \tformatp = strchr(atomname, ':');\n@@ -835,7 +835,7 @@ static void populate_value(struct ref_array_item *ref)\n  * Given a ref, return the value for the atom.  This lazily gets value\n  * out of the object by calling populate value.\n  */\n-static void get_value(struct ref_array_item *ref, int atom, struct atom_value **v)\n+static void get_ref_atom_value(struct ref_array_item *ref, int atom, struct atom_value **v)\n {\n \tif (!ref->value) {\n \t\tpopulate_value(ref);\n@@ -882,10 +882,10 @@ static struct ref_array_item *new_ref_array_item(const char *refname,\n }\n \n /*\n- * A call-back given to for_each_ref().  Filter refs and keep them for\n+ * A call-back given to for_each_ref(). Filter refs and keep them for\n  * later object processing.\n  */\n-static int grab_single_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data)\n+int ref_filter_handler(const char *refname, const unsigned char *sha1, int flag, void *cb_data)\n {\n \tstruct ref_filter_cbdata *ref_cbdata = cb_data;\n \tstruct ref_filter *filter = &ref_cbdata->filter;\n@@ -925,8 +925,8 @@ static int cmp_ref_sort(struct ref_sort *s, struct ref_array_item *a, struct ref\n \tint cmp;\n \tcmp_type cmp_type = used_atom_type[s->atom];\n \n-\tget_value(a, s->atom, &va);\n-\tget_value(b, s->atom, &vb);\n+\tget_ref_atom_value(a, s->atom, &va);\n+\tget_ref_atom_value(b, s->atom, &vb);\n \tswitch (cmp_type) {\n \tcase FIELD_STR:\n \t\tcmp = strcmp(va->s, vb->s);\n@@ -958,7 +958,7 @@ static int compare_refs(const void *a_, const void *b_)\n \treturn 0;\n }\n \n-static void sort_refs(struct ref_sort *sort, struct ref_array *array)\n+void sort_ref_array(struct ref_sort *sort, struct ref_array *array)\n {\n \tref_sort = sort;\n \tqsort(array->items, array->nr, sizeof(struct ref_array_item *), compare_refs);\n@@ -1028,7 +1028,7 @@ static void emit(const char *cp, const char *ep)\n \t}\n }\n \n-static void show_ref(struct ref_array_item *info, const char *format, int quote_style)\n+void show_ref_array_item(struct ref_array_item *info, const char *format, int quote_style)\n {\n \tconst char *cp, *sp, *ep;\n \n@@ -1038,7 +1038,7 @@ static void show_ref(struct ref_array_item *info, const char *format, int quote_\n \t\tep = strchr(sp, ')');\n \t\tif (cp < sp)\n \t\t\temit(cp, sp);\n-\t\tget_value(info, parse_atom(sp + 2, ep), &atomv);\n+\t\tget_ref_atom_value(info, parse_ref_filter_atom(sp + 2, ep), &atomv);\n \t\tprint_value(atomv, quote_style);\n \t}\n \tif (*cp) {\n@@ -1057,18 +1057,19 @@ static void show_ref(struct ref_array_item *info, const char *format, int quote_\n \tputchar('\\n');\n }\n \n-static struct ref_sort *default_sort(void)\n+/*  If no sorting option is given, use refname to sort as default */\n+struct ref_sort *ref_default_sort(void)\n {\n \tstatic const char cstr_name[] = \"refname\";\n \n \tstruct ref_sort *sort = xcalloc(1, sizeof(*sort));\n \n \tsort->next = NULL;\n-\tsort->atom = parse_atom(cstr_name, cstr_name + strlen(cstr_name));\n+\tsort->atom = parse_ref_filter_atom(cstr_name, cstr_name + strlen(cstr_name));\n \treturn sort;\n }\n \n-static int opt_parse_sort(const struct option *opt, const char *arg, int unset)\n+int opt_parse_ref_sort(const struct option *opt, const char *arg, int unset)\n {\n \tstruct ref_sort **sort_tail = opt->value;\n \tstruct ref_sort *s;\n@@ -1086,7 +1087,7 @@ static int opt_parse_sort(const struct option *opt, const char *arg, int unset)\n \t\targ++;\n \t}\n \tlen = strlen(arg);\n-\ts->atom = parse_atom(arg, arg+len);\n+\ts->atom = parse_ref_filter_atom(arg, arg+len);\n \treturn 0;\n }\n \n@@ -1118,7 +1119,7 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix)\n \t\tOPT_INTEGER( 0 , \"count\", &maxcount, N_(\"show only <n> matched refs\")),\n \t\tOPT_STRING(  0 , \"format\", &format, N_(\"format\"), N_(\"format to use for the output\")),\n \t\tOPT_CALLBACK(0 , \"sort\", sort_tail, N_(\"key\"),\n-\t\t\t    N_(\"field name to sort on\"), &opt_parse_sort),\n+\t\t\t    N_(\"field name to sort on\"), &opt_parse_ref_sort),\n \t\tOPT_END(),\n \t};\n \n@@ -1131,24 +1132,24 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix)\n \t\terror(\"more than one quoting style?\");\n \t\tusage_with_options(for_each_ref_usage, opts);\n \t}\n-\tif (verify_format(format))\n+\tif (verify_ref_format(format))\n \t\tusage_with_options(for_each_ref_usage, opts);\n \n \tif (!sort)\n-\t\tsort = default_sort();\n+\t\tsort = ref_default_sort();\n \n \t/* for warn_ambiguous_refs */\n \tgit_config(git_default_config, NULL);\n \n \tref_cbdata.filter.name_patterns = argv;\n-\tfor_each_rawref(grab_single_ref, &ref_cbdata);\n+\tfor_each_rawref(ref_filter_handler, &ref_cbdata);\n \n-\tsort_refs(sort, &ref_cbdata.array);\n+\tsort_ref_array(sort, &ref_cbdata.array);\n \n \tif (!maxcount || ref_cbdata.array.nr < maxcount)\n \t\tmaxcount = ref_cbdata.array.nr;\n \tfor (i = 0; i < maxcount; i++)\n-\t\tshow_ref(ref_cbdata.array.items[i], format, quote_style);\n+\t\tshow_ref_array_item(ref_cbdata.array.items[i], format, quote_style);\n \tref_filter_clear_data(&ref_cbdata);\n \treturn 0;\n }\n-- \n2.4.2\n"},{"id":"262481","messageId":"1433008411-8550-7-git-send-email-karthik.188@gmail.com","threadId":"39466","inReplyTo":"5569EF77.4010300@gmail.com","subject":"[WIP/PATCH v4 7/8] ref-filter: move code from 'for-each-ref'","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2015-05-30T17:53:30Z","receivedAt":"2015-05-30T17:53:30Z","isPatch":true,"sender":{"key":"karthik.188@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1786334?v=4"},"body":"Move most of the code from 'for-each-ref' to 'ref-filter' to make\nit publicly available to other commands, this is to unify the code\nof 'tag -l', 'branch -l' and 'for-each-ref' so that they can share\ntheir implementations with each other.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr>\nSigned-off-by: Karthik Nayak <karthik.188@gmail.com>\n---\n builtin/for-each-ref.c | 1048 -----------------------------------------------\n ref-filter.c           | 1050 ++++++++++++++++++++++++++++++++++++++++++++++++\n 2 files changed, 1050 insertions(+), 1048 deletions(-)\n create mode 100644 ref-filter.c\n\ndiff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c\nindex 8fed04b..65ed954 100644\n--- a/builtin/for-each-ref.c\n+++ b/builtin/for-each-ref.c\n@@ -1,15 +1,7 @@\n #include \"builtin.h\"\n #include \"cache.h\"\n #include \"refs.h\"\n-#include \"object.h\"\n-#include \"tag.h\"\n-#include \"commit.h\"\n-#include \"tree.h\"\n-#include \"blob.h\"\n-#include \"quote.h\"\n #include \"parse-options.h\"\n-#include \"remote.h\"\n-#include \"color.h\"\n \n /* Quoting styles */\n #define QUOTE_NONE 0\n@@ -18,8 +10,6 @@\n #define QUOTE_PYTHON 4\n #define QUOTE_TCL 8\n \n-typedef enum { FIELD_STR, FIELD_ULONG, FIELD_TIME } cmp_type;\n-\n struct atom_value {\n \tconst char *s;\n \tunsigned long ul; /* used for sorting when not FIELD_STR */\n@@ -53,1044 +43,6 @@ struct ref_filter_cbdata {\n \tstruct ref_filter filter;\n };\n \n-static struct {\n-\tconst char *name;\n-\tcmp_type cmp_type;\n-} valid_atom[] = {\n-\t{ \"refname\" },\n-\t{ \"objecttype\" },\n-\t{ \"objectsize\", FIELD_ULONG },\n-\t{ \"objectname\" },\n-\t{ \"tree\" },\n-\t{ \"parent\" },\n-\t{ \"numparent\", FIELD_ULONG },\n-\t{ \"object\" },\n-\t{ \"type\" },\n-\t{ \"tag\" },\n-\t{ \"author\" },\n-\t{ \"authorname\" },\n-\t{ \"authoremail\" },\n-\t{ \"authordate\", FIELD_TIME },\n-\t{ \"committer\" },\n-\t{ \"committername\" },\n-\t{ \"committeremail\" },\n-\t{ \"committerdate\", FIELD_TIME },\n-\t{ \"tagger\" },\n-\t{ \"taggername\" },\n-\t{ \"taggeremail\" },\n-\t{ \"taggerdate\", FIELD_TIME },\n-\t{ \"creator\" },\n-\t{ \"creatordate\", FIELD_TIME },\n-\t{ \"subject\" },\n-\t{ \"body\" },\n-\t{ \"contents\" },\n-\t{ \"contents:subject\" },\n-\t{ \"contents:body\" },\n-\t{ \"contents:signature\" },\n-\t{ \"upstream\" },\n-\t{ \"symref\" },\n-\t{ \"flag\" },\n-\t{ \"HEAD\" },\n-\t{ \"color\" },\n-};\n-\n-/*\n- * An atom is a valid field atom listed above, possibly prefixed with\n- * a \"*\" to denote deref_tag().\n- *\n- * We parse given format string and sort specifiers, and make a list\n- * of properties that we need to extract out of objects. ref_array_item\n- * structure will hold an array of values extracted that can be\n- * indexed with the \"atom number\", which is an index into this\n- * array.\n- */\n-static const char **used_atom;\n-static cmp_type *used_atom_type;\n-static int used_atom_cnt, need_tagged, need_symref;\n-static int need_color_reset_at_eol;\n-\n-/*\n- * Used to parse format string and sort specifiers\n- */\n-int parse_ref_filter_atom(const char *atom, const char *ep)\n-{\n-\tconst char *sp;\n-\tint i, at;\n-\n-\tsp = atom;\n-\tif (*sp == '*' && sp < ep)\n-\t\tsp++; /* deref */\n-\tif (ep <= sp)\n-\t\tdie(\"malformed field name: %.*s\", (int)(ep-atom), atom);\n-\n-\t/* Do we have the atom already used elsewhere? */\n-\tfor (i = 0; i < used_atom_cnt; i++) {\n-\t\tint len = strlen(used_atom[i]);\n-\t\tif (len == ep - atom && !memcmp(used_atom[i], atom, len))\n-\t\t\treturn i;\n-\t}\n-\n-\t/* Is the atom a valid one? */\n-\tfor (i = 0; i < ARRAY_SIZE(valid_atom); i++) {\n-\t\tint len = strlen(valid_atom[i].name);\n-\t\t/*\n-\t\t * If the atom name has a colon, strip it and everything after\n-\t\t * it off - it specifies the format for this entry, and\n-\t\t * shouldn't be used for checking against the valid_atom\n-\t\t * table.\n-\t\t */\n-\t\tconst char *formatp = strchr(sp, ':');\n-\t\tif (!formatp || ep < formatp)\n-\t\t\tformatp = ep;\n-\t\tif (len == formatp - sp && !memcmp(valid_atom[i].name, sp, len))\n-\t\t\tbreak;\n-\t}\n-\n-\tif (ARRAY_SIZE(valid_atom) <= i)\n-\t\tdie(\"unknown field name: %.*s\", (int)(ep-atom), atom);\n-\n-\t/* Add it in, including the deref prefix */\n-\tat = used_atom_cnt;\n-\tused_atom_cnt++;\n-\tREALLOC_ARRAY(used_atom, used_atom_cnt);\n-\tREALLOC_ARRAY(used_atom_type, used_atom_cnt);\n-\tused_atom[at] = xmemdupz(atom, ep - atom);\n-\tused_atom_type[at] = valid_atom[i].cmp_type;\n-\tif (*atom == '*')\n-\t\tneed_tagged = 1;\n-\tif (!strcmp(used_atom[at], \"symref\"))\n-\t\tneed_symref = 1;\n-\treturn at;\n-}\n-\n-/*\n- * In a format string, find the next occurrence of %(atom).\n- */\n-static const char *find_next(const char *cp)\n-{\n-\twhile (*cp) {\n-\t\tif (*cp == '%') {\n-\t\t\t/*\n-\t\t\t * %( is the start of an atom;\n-\t\t\t * %% is a quoted per-cent.\n-\t\t\t */\n-\t\t\tif (cp[1] == '(')\n-\t\t\t\treturn cp;\n-\t\t\telse if (cp[1] == '%')\n-\t\t\t\tcp++; /* skip over two % */\n-\t\t\t/* otherwise this is a singleton, literal % */\n-\t\t}\n-\t\tcp++;\n-\t}\n-\treturn NULL;\n-}\n-\n-/*\n- * Make sure the format string is well formed, and parse out\n- * the used atoms.\n- */\n-int verify_ref_format(const char *format)\n-{\n-\tconst char *cp, *sp;\n-\n-\tneed_color_reset_at_eol = 0;\n-\tfor (cp = format; *cp && (sp = find_next(cp)); ) {\n-\t\tconst char *color, *ep = strchr(sp, ')');\n-\t\tint at;\n-\n-\t\tif (!ep)\n-\t\t\treturn error(\"malformed format string %s\", sp);\n-\t\t/* sp points at \"%(\" and ep points at the closing \")\" */\n-\t\tat = parse_ref_filter_atom(sp + 2, ep);\n-\t\tcp = ep + 1;\n-\n-\t\tif (skip_prefix(used_atom[at], \"color:\", &color))\n-\t\t\tneed_color_reset_at_eol = !!strcmp(color, \"reset\");\n-\t}\n-\treturn 0;\n-}\n-\n-/*\n- * Given an object name, read the object data and size, and return a\n- * \"struct object\".  If the object data we are returning is also borrowed\n- * by the \"struct object\" representation, set *eaten as well---it is a\n- * signal from parse_object_buffer to us not to free the buffer.\n- */\n-static void *get_obj(const unsigned char *sha1, struct object **obj, unsigned long *sz, int *eaten)\n-{\n-\tenum object_type type;\n-\tvoid *buf = read_sha1_file(sha1, &type, sz);\n-\n-\tif (buf)\n-\t\t*obj = parse_object_buffer(sha1, type, *sz, buf, eaten);\n-\telse\n-\t\t*obj = NULL;\n-\treturn buf;\n-}\n-\n-static int grab_objectname(const char *name, const unsigned char *sha1,\n-\t\t\t    struct atom_value *v)\n-{\n-\tif (!strcmp(name, \"objectname\")) {\n-\t\tchar *s = xmalloc(41);\n-\t\tstrcpy(s, sha1_to_hex(sha1));\n-\t\tv->s = s;\n-\t\treturn 1;\n-\t}\n-\tif (!strcmp(name, \"objectname:short\")) {\n-\t\tv->s = xstrdup(find_unique_abbrev(sha1, DEFAULT_ABBREV));\n-\t\treturn 1;\n-\t}\n-\treturn 0;\n-}\n-\n-/* See grab_values */\n-static void grab_common_values(struct atom_value *val, int deref, struct object *obj, void *buf, unsigned long sz)\n-{\n-\tint i;\n-\n-\tfor (i = 0; i < used_atom_cnt; i++) {\n-\t\tconst char *name = used_atom[i];\n-\t\tstruct atom_value *v = &val[i];\n-\t\tif (!!deref != (*name == '*'))\n-\t\t\tcontinue;\n-\t\tif (deref)\n-\t\t\tname++;\n-\t\tif (!strcmp(name, \"objecttype\"))\n-\t\t\tv->s = typename(obj->type);\n-\t\telse if (!strcmp(name, \"objectsize\")) {\n-\t\t\tchar *s = xmalloc(40);\n-\t\t\tsprintf(s, \"%lu\", sz);\n-\t\t\tv->ul = sz;\n-\t\t\tv->s = s;\n-\t\t}\n-\t\telse if (deref)\n-\t\t\tgrab_objectname(name, obj->sha1, v);\n-\t}\n-}\n-\n-/* See grab_values */\n-static void grab_tag_values(struct atom_value *val, int deref, struct object *obj, void *buf, unsigned long sz)\n-{\n-\tint i;\n-\tstruct tag *tag = (struct tag *) obj;\n-\n-\tfor (i = 0; i < used_atom_cnt; i++) {\n-\t\tconst char *name = used_atom[i];\n-\t\tstruct atom_value *v = &val[i];\n-\t\tif (!!deref != (*name == '*'))\n-\t\t\tcontinue;\n-\t\tif (deref)\n-\t\t\tname++;\n-\t\tif (!strcmp(name, \"tag\"))\n-\t\t\tv->s = tag->tag;\n-\t\telse if (!strcmp(name, \"type\") && tag->tagged)\n-\t\t\tv->s = typename(tag->tagged->type);\n-\t\telse if (!strcmp(name, \"object\") && tag->tagged) {\n-\t\t\tchar *s = xmalloc(41);\n-\t\t\tstrcpy(s, sha1_to_hex(tag->tagged->sha1));\n-\t\t\tv->s = s;\n-\t\t}\n-\t}\n-}\n-\n-/* See grab_values */\n-static void grab_commit_values(struct atom_value *val, int deref, struct object *obj, void *buf, unsigned long sz)\n-{\n-\tint i;\n-\tstruct commit *commit = (struct commit *) obj;\n-\n-\tfor (i = 0; i < used_atom_cnt; i++) {\n-\t\tconst char *name = used_atom[i];\n-\t\tstruct atom_value *v = &val[i];\n-\t\tif (!!deref != (*name == '*'))\n-\t\t\tcontinue;\n-\t\tif (deref)\n-\t\t\tname++;\n-\t\tif (!strcmp(name, \"tree\")) {\n-\t\t\tchar *s = xmalloc(41);\n-\t\t\tstrcpy(s, sha1_to_hex(commit->tree->object.sha1));\n-\t\t\tv->s = s;\n-\t\t}\n-\t\tif (!strcmp(name, \"numparent\")) {\n-\t\t\tchar *s = xmalloc(40);\n-\t\t\tv->ul = commit_list_count(commit->parents);\n-\t\t\tsprintf(s, \"%lu\", v->ul);\n-\t\t\tv->s = s;\n-\t\t}\n-\t\telse if (!strcmp(name, \"parent\")) {\n-\t\t\tint num = commit_list_count(commit->parents);\n-\t\t\tint i;\n-\t\t\tstruct commit_list *parents;\n-\t\t\tchar *s = xmalloc(41 * num + 1);\n-\t\t\tv->s = s;\n-\t\t\tfor (i = 0, parents = commit->parents;\n-\t\t\t     parents;\n-\t\t\t     parents = parents->next, i = i + 41) {\n-\t\t\t\tstruct commit *parent = parents->item;\n-\t\t\t\tstrcpy(s+i, sha1_to_hex(parent->object.sha1));\n-\t\t\t\tif (parents->next)\n-\t\t\t\t\ts[i+40] = ' ';\n-\t\t\t}\n-\t\t\tif (!i)\n-\t\t\t\t*s = '\\0';\n-\t\t}\n-\t}\n-}\n-\n-static const char *find_wholine(const char *who, int wholen, const char *buf, unsigned long sz)\n-{\n-\tconst char *eol;\n-\twhile (*buf) {\n-\t\tif (!strncmp(buf, who, wholen) &&\n-\t\t    buf[wholen] == ' ')\n-\t\t\treturn buf + wholen + 1;\n-\t\teol = strchr(buf, '\\n');\n-\t\tif (!eol)\n-\t\t\treturn \"\";\n-\t\teol++;\n-\t\tif (*eol == '\\n')\n-\t\t\treturn \"\"; /* end of header */\n-\t\tbuf = eol;\n-\t}\n-\treturn \"\";\n-}\n-\n-static const char *copy_line(const char *buf)\n-{\n-\tconst char *eol = strchrnul(buf, '\\n');\n-\treturn xmemdupz(buf, eol - buf);\n-}\n-\n-static const char *copy_name(const char *buf)\n-{\n-\tconst char *cp;\n-\tfor (cp = buf; *cp && *cp != '\\n'; cp++) {\n-\t\tif (!strncmp(cp, \" <\", 2))\n-\t\t\treturn xmemdupz(buf, cp - buf);\n-\t}\n-\treturn \"\";\n-}\n-\n-static const char *copy_email(const char *buf)\n-{\n-\tconst char *email = strchr(buf, '<');\n-\tconst char *eoemail;\n-\tif (!email)\n-\t\treturn \"\";\n-\teoemail = strchr(email, '>');\n-\tif (!eoemail)\n-\t\treturn \"\";\n-\treturn xmemdupz(email, eoemail + 1 - email);\n-}\n-\n-static char *copy_subject(const char *buf, unsigned long len)\n-{\n-\tchar *r = xmemdupz(buf, len);\n-\tint i;\n-\n-\tfor (i = 0; i < len; i++)\n-\t\tif (r[i] == '\\n')\n-\t\t\tr[i] = ' ';\n-\n-\treturn r;\n-}\n-\n-static void grab_date(const char *buf, struct atom_value *v, const char *atomname)\n-{\n-\tconst char *eoemail = strstr(buf, \"> \");\n-\tchar *zone;\n-\tunsigned long timestamp;\n-\tlong tz;\n-\tenum date_mode date_mode = DATE_NORMAL;\n-\tconst char *formatp;\n-\n-\t/*\n-\t * We got here because atomname ends in \"date\" or \"date<something>\";\n-\t * it's not possible that <something> is not \":<format>\" because\n-\t * parse_ref_filter_atom() wouldn't have allowed it, so we can assume that no\n-\t * \":\" means no format is specified, and use the default.\n-\t */\n-\tformatp = strchr(atomname, ':');\n-\tif (formatp != NULL) {\n-\t\tformatp++;\n-\t\tdate_mode = parse_date_format(formatp);\n-\t}\n-\n-\tif (!eoemail)\n-\t\tgoto bad;\n-\ttimestamp = strtoul(eoemail + 2, &zone, 10);\n-\tif (timestamp == ULONG_MAX)\n-\t\tgoto bad;\n-\ttz = strtol(zone, NULL, 10);\n-\tif ((tz == LONG_MIN || tz == LONG_MAX) && errno == ERANGE)\n-\t\tgoto bad;\n-\tv->s = xstrdup(show_date(timestamp, tz, date_mode));\n-\tv->ul = timestamp;\n-\treturn;\n- bad:\n-\tv->s = \"\";\n-\tv->ul = 0;\n-}\n-\n-/* See grab_values */\n-static void grab_person(const char *who, struct atom_value *val, int deref, struct object *obj, void *buf, unsigned long sz)\n-{\n-\tint i;\n-\tint wholen = strlen(who);\n-\tconst char *wholine = NULL;\n-\n-\tfor (i = 0; i < used_atom_cnt; i++) {\n-\t\tconst char *name = used_atom[i];\n-\t\tstruct atom_value *v = &val[i];\n-\t\tif (!!deref != (*name == '*'))\n-\t\t\tcontinue;\n-\t\tif (deref)\n-\t\t\tname++;\n-\t\tif (strncmp(who, name, wholen))\n-\t\t\tcontinue;\n-\t\tif (name[wholen] != 0 &&\n-\t\t    strcmp(name + wholen, \"name\") &&\n-\t\t    strcmp(name + wholen, \"email\") &&\n-\t\t    !starts_with(name + wholen, \"date\"))\n-\t\t\tcontinue;\n-\t\tif (!wholine)\n-\t\t\twholine = find_wholine(who, wholen, buf, sz);\n-\t\tif (!wholine)\n-\t\t\treturn; /* no point looking for it */\n-\t\tif (name[wholen] == 0)\n-\t\t\tv->s = copy_line(wholine);\n-\t\telse if (!strcmp(name + wholen, \"name\"))\n-\t\t\tv->s = copy_name(wholine);\n-\t\telse if (!strcmp(name + wholen, \"email\"))\n-\t\t\tv->s = copy_email(wholine);\n-\t\telse if (starts_with(name + wholen, \"date\"))\n-\t\t\tgrab_date(wholine, v, name);\n-\t}\n-\n-\t/*\n-\t * For a tag or a commit object, if \"creator\" or \"creatordate\" is\n-\t * requested, do something special.\n-\t */\n-\tif (strcmp(who, \"tagger\") && strcmp(who, \"committer\"))\n-\t\treturn; /* \"author\" for commit object is not wanted */\n-\tif (!wholine)\n-\t\twholine = find_wholine(who, wholen, buf, sz);\n-\tif (!wholine)\n-\t\treturn;\n-\tfor (i = 0; i < used_atom_cnt; i++) {\n-\t\tconst char *name = used_atom[i];\n-\t\tstruct atom_value *v = &val[i];\n-\t\tif (!!deref != (*name == '*'))\n-\t\t\tcontinue;\n-\t\tif (deref)\n-\t\t\tname++;\n-\n-\t\tif (starts_with(name, \"creatordate\"))\n-\t\t\tgrab_date(wholine, v, name);\n-\t\telse if (!strcmp(name, \"creator\"))\n-\t\t\tv->s = copy_line(wholine);\n-\t}\n-}\n-\n-static void find_subpos(const char *buf, unsigned long sz,\n-\t\t\tconst char **sub, unsigned long *sublen,\n-\t\t\tconst char **body, unsigned long *bodylen,\n-\t\t\tunsigned long *nonsiglen,\n-\t\t\tconst char **sig, unsigned long *siglen)\n-{\n-\tconst char *eol;\n-\t/* skip past header until we hit empty line */\n-\twhile (*buf && *buf != '\\n') {\n-\t\teol = strchrnul(buf, '\\n');\n-\t\tif (*eol)\n-\t\t\teol++;\n-\t\tbuf = eol;\n-\t}\n-\t/* skip any empty lines */\n-\twhile (*buf == '\\n')\n-\t\tbuf++;\n-\n-\t/* parse signature first; we might not even have a subject line */\n-\t*sig = buf + parse_signature(buf, strlen(buf));\n-\t*siglen = strlen(*sig);\n-\n-\t/* subject is first non-empty line */\n-\t*sub = buf;\n-\t/* subject goes to first empty line */\n-\twhile (buf < *sig && *buf && *buf != '\\n') {\n-\t\teol = strchrnul(buf, '\\n');\n-\t\tif (*eol)\n-\t\t\teol++;\n-\t\tbuf = eol;\n-\t}\n-\t*sublen = buf - *sub;\n-\t/* drop trailing newline, if present */\n-\tif (*sublen && (*sub)[*sublen - 1] == '\\n')\n-\t\t*sublen -= 1;\n-\n-\t/* skip any empty lines */\n-\twhile (*buf == '\\n')\n-\t\tbuf++;\n-\t*body = buf;\n-\t*bodylen = strlen(buf);\n-\t*nonsiglen = *sig - buf;\n-}\n-\n-/* See grab_values */\n-static void grab_sub_body_contents(struct atom_value *val, int deref, struct object *obj, void *buf, unsigned long sz)\n-{\n-\tint i;\n-\tconst char *subpos = NULL, *bodypos = NULL, *sigpos = NULL;\n-\tunsigned long sublen = 0, bodylen = 0, nonsiglen = 0, siglen = 0;\n-\n-\tfor (i = 0; i < used_atom_cnt; i++) {\n-\t\tconst char *name = used_atom[i];\n-\t\tstruct atom_value *v = &val[i];\n-\t\tif (!!deref != (*name == '*'))\n-\t\t\tcontinue;\n-\t\tif (deref)\n-\t\t\tname++;\n-\t\tif (strcmp(name, \"subject\") &&\n-\t\t    strcmp(name, \"body\") &&\n-\t\t    strcmp(name, \"contents\") &&\n-\t\t    strcmp(name, \"contents:subject\") &&\n-\t\t    strcmp(name, \"contents:body\") &&\n-\t\t    strcmp(name, \"contents:signature\"))\n-\t\t\tcontinue;\n-\t\tif (!subpos)\n-\t\t\tfind_subpos(buf, sz,\n-\t\t\t\t    &subpos, &sublen,\n-\t\t\t\t    &bodypos, &bodylen, &nonsiglen,\n-\t\t\t\t    &sigpos, &siglen);\n-\n-\t\tif (!strcmp(name, \"subject\"))\n-\t\t\tv->s = copy_subject(subpos, sublen);\n-\t\telse if (!strcmp(name, \"contents:subject\"))\n-\t\t\tv->s = copy_subject(subpos, sublen);\n-\t\telse if (!strcmp(name, \"body\"))\n-\t\t\tv->s = xmemdupz(bodypos, bodylen);\n-\t\telse if (!strcmp(name, \"contents:body\"))\n-\t\t\tv->s = xmemdupz(bodypos, nonsiglen);\n-\t\telse if (!strcmp(name, \"contents:signature\"))\n-\t\t\tv->s = xmemdupz(sigpos, siglen);\n-\t\telse if (!strcmp(name, \"contents\"))\n-\t\t\tv->s = xstrdup(subpos);\n-\t}\n-}\n-\n-/*\n- * We want to have empty print-string for field requests\n- * that do not apply (e.g. \"authordate\" for a tag object)\n- */\n-static void fill_missing_values(struct atom_value *val)\n-{\n-\tint i;\n-\tfor (i = 0; i < used_atom_cnt; i++) {\n-\t\tstruct atom_value *v = &val[i];\n-\t\tif (v->s == NULL)\n-\t\t\tv->s = \"\";\n-\t}\n-}\n-\n-/*\n- * val is a list of atom_value to hold returned values.  Extract\n- * the values for atoms in used_atom array out of (obj, buf, sz).\n- * when deref is false, (obj, buf, sz) is the object that is\n- * pointed at by the ref itself; otherwise it is the object the\n- * ref (which is a tag) refers to.\n- */\n-static void grab_values(struct atom_value *val, int deref, struct object *obj, void *buf, unsigned long sz)\n-{\n-\tgrab_common_values(val, deref, obj, buf, sz);\n-\tswitch (obj->type) {\n-\tcase OBJ_TAG:\n-\t\tgrab_tag_values(val, deref, obj, buf, sz);\n-\t\tgrab_sub_body_contents(val, deref, obj, buf, sz);\n-\t\tgrab_person(\"tagger\", val, deref, obj, buf, sz);\n-\t\tbreak;\n-\tcase OBJ_COMMIT:\n-\t\tgrab_commit_values(val, deref, obj, buf, sz);\n-\t\tgrab_sub_body_contents(val, deref, obj, buf, sz);\n-\t\tgrab_person(\"author\", val, deref, obj, buf, sz);\n-\t\tgrab_person(\"committer\", val, deref, obj, buf, sz);\n-\t\tbreak;\n-\tcase OBJ_TREE:\n-\t\t/* grab_tree_values(val, deref, obj, buf, sz); */\n-\t\tbreak;\n-\tcase OBJ_BLOB:\n-\t\t/* grab_blob_values(val, deref, obj, buf, sz); */\n-\t\tbreak;\n-\tdefault:\n-\t\tdie(\"Eh?  Object of type %d?\", obj->type);\n-\t}\n-}\n-\n-static inline char *copy_advance(char *dst, const char *src)\n-{\n-\twhile (*src)\n-\t\t*dst++ = *src++;\n-\treturn dst;\n-}\n-\n-/*\n- * Parse the object referred by ref, and grab needed value.\n- */\n-static void populate_value(struct ref_array_item *ref)\n-{\n-\tvoid *buf;\n-\tstruct object *obj;\n-\tint eaten, i;\n-\tunsigned long size;\n-\tconst unsigned char *tagged;\n-\n-\tref->value = xcalloc(used_atom_cnt, sizeof(struct atom_value));\n-\n-\tif (need_symref && (ref->flag & REF_ISSYMREF) && !ref->symref) {\n-\t\tunsigned char unused1[20];\n-\t\tref->symref = resolve_refdup(ref->refname, RESOLVE_REF_READING,\n-\t\t\t\t\t     unused1, NULL);\n-\t\tif (!ref->symref)\n-\t\t\tref->symref = \"\";\n-\t}\n-\n-\t/* Fill in specials first */\n-\tfor (i = 0; i < used_atom_cnt; i++) {\n-\t\tconst char *name = used_atom[i];\n-\t\tstruct atom_value *v = &ref->value[i];\n-\t\tint deref = 0;\n-\t\tconst char *refname;\n-\t\tconst char *formatp;\n-\t\tstruct branch *branch = NULL;\n-\n-\t\tif (*name == '*') {\n-\t\t\tderef = 1;\n-\t\t\tname++;\n-\t\t}\n-\n-\t\tif (starts_with(name, \"refname\"))\n-\t\t\trefname = ref->refname;\n-\t\telse if (starts_with(name, \"symref\"))\n-\t\t\trefname = ref->symref ? ref->symref : \"\";\n-\t\telse if (starts_with(name, \"upstream\")) {\n-\t\t\t/* only local branches may have an upstream */\n-\t\t\tif (!starts_with(ref->refname, \"refs/heads/\"))\n-\t\t\t\tcontinue;\n-\t\t\tbranch = branch_get(ref->refname + 11);\n-\n-\t\t\tif (!branch || !branch->merge || !branch->merge[0] ||\n-\t\t\t    !branch->merge[0]->dst)\n-\t\t\t\tcontinue;\n-\t\t\trefname = branch->merge[0]->dst;\n-\t\t} else if (starts_with(name, \"color:\")) {\n-\t\t\tchar color[COLOR_MAXLEN] = \"\";\n-\n-\t\t\tif (color_parse(name + 6, color) < 0)\n-\t\t\t\tdie(_(\"unable to parse format\"));\n-\t\t\tv->s = xstrdup(color);\n-\t\t\tcontinue;\n-\t\t} else if (!strcmp(name, \"flag\")) {\n-\t\t\tchar buf[256], *cp = buf;\n-\t\t\tif (ref->flag & REF_ISSYMREF)\n-\t\t\t\tcp = copy_advance(cp, \",symref\");\n-\t\t\tif (ref->flag & REF_ISPACKED)\n-\t\t\t\tcp = copy_advance(cp, \",packed\");\n-\t\t\tif (cp == buf)\n-\t\t\t\tv->s = \"\";\n-\t\t\telse {\n-\t\t\t\t*cp = '\\0';\n-\t\t\t\tv->s = xstrdup(buf + 1);\n-\t\t\t}\n-\t\t\tcontinue;\n-\t\t} else if (!deref && grab_objectname(name, ref->objectname, v)) {\n-\t\t\tcontinue;\n-\t\t} else if (!strcmp(name, \"HEAD\")) {\n-\t\t\tconst char *head;\n-\t\t\tunsigned char sha1[20];\n-\n-\t\t\thead = resolve_ref_unsafe(\"HEAD\", RESOLVE_REF_READING,\n-\t\t\t\t\t\t  sha1, NULL);\n-\t\t\tif (!strcmp(ref->refname, head))\n-\t\t\t\tv->s = \"*\";\n-\t\t\telse\n-\t\t\t\tv->s = \" \";\n-\t\t\tcontinue;\n-\t\t} else\n-\t\t\tcontinue;\n-\n-\t\tformatp = strchr(name, ':');\n-\t\tif (formatp) {\n-\t\t\tint num_ours, num_theirs;\n-\n-\t\t\tformatp++;\n-\t\t\tif (!strcmp(formatp, \"short\"))\n-\t\t\t\trefname = shorten_unambiguous_ref(refname,\n-\t\t\t\t\t\t      warn_ambiguous_refs);\n-\t\t\telse if (!strcmp(formatp, \"track\") &&\n-\t\t\t\t starts_with(name, \"upstream\")) {\n-\t\t\t\tchar buf[40];\n-\n-\t\t\t\tif (stat_tracking_info(branch, &num_ours,\n-\t\t\t\t\t\t       &num_theirs) != 1)\n-\t\t\t\t\tcontinue;\n-\n-\t\t\t\tif (!num_ours && !num_theirs)\n-\t\t\t\t\tv->s = \"\";\n-\t\t\t\telse if (!num_ours) {\n-\t\t\t\t\tsprintf(buf, \"[behind %d]\", num_theirs);\n-\t\t\t\t\tv->s = xstrdup(buf);\n-\t\t\t\t} else if (!num_theirs) {\n-\t\t\t\t\tsprintf(buf, \"[ahead %d]\", num_ours);\n-\t\t\t\t\tv->s = xstrdup(buf);\n-\t\t\t\t} else {\n-\t\t\t\t\tsprintf(buf, \"[ahead %d, behind %d]\",\n-\t\t\t\t\t\tnum_ours, num_theirs);\n-\t\t\t\t\tv->s = xstrdup(buf);\n-\t\t\t\t}\n-\t\t\t\tcontinue;\n-\t\t\t} else if (!strcmp(formatp, \"trackshort\") &&\n-\t\t\t\t   starts_with(name, \"upstream\")) {\n-\t\t\t\tassert(branch);\n-\n-\t\t\t\tif (stat_tracking_info(branch, &num_ours,\n-\t\t\t\t\t\t\t&num_theirs) != 1)\n-\t\t\t\t\tcontinue;\n-\n-\t\t\t\tif (!num_ours && !num_theirs)\n-\t\t\t\t\tv->s = \"=\";\n-\t\t\t\telse if (!num_ours)\n-\t\t\t\t\tv->s = \"<\";\n-\t\t\t\telse if (!num_theirs)\n-\t\t\t\t\tv->s = \">\";\n-\t\t\t\telse\n-\t\t\t\t\tv->s = \"<>\";\n-\t\t\t\tcontinue;\n-\t\t\t} else\n-\t\t\t\tdie(\"unknown %.*s format %s\",\n-\t\t\t\t    (int)(formatp - name), name, formatp);\n-\t\t}\n-\n-\t\tif (!deref)\n-\t\t\tv->s = refname;\n-\t\telse {\n-\t\t\tint len = strlen(refname);\n-\t\t\tchar *s = xmalloc(len + 4);\n-\t\t\tsprintf(s, \"%s^{}\", refname);\n-\t\t\tv->s = s;\n-\t\t}\n-\t}\n-\n-\tfor (i = 0; i < used_atom_cnt; i++) {\n-\t\tstruct atom_value *v = &ref->value[i];\n-\t\tif (v->s == NULL)\n-\t\t\tgoto need_obj;\n-\t}\n-\treturn;\n-\n- need_obj:\n-\tbuf = get_obj(ref->objectname, &obj, &size, &eaten);\n-\tif (!buf)\n-\t\tdie(\"missing object %s for %s\",\n-\t\t    sha1_to_hex(ref->objectname), ref->refname);\n-\tif (!obj)\n-\t\tdie(\"parse_object_buffer failed on %s for %s\",\n-\t\t    sha1_to_hex(ref->objectname), ref->refname);\n-\n-\tgrab_values(ref->value, 0, obj, buf, size);\n-\tif (!eaten)\n-\t\tfree(buf);\n-\n-\t/*\n-\t * If there is no atom that wants to know about tagged\n-\t * object, we are done.\n-\t */\n-\tif (!need_tagged || (obj->type != OBJ_TAG))\n-\t\treturn;\n-\n-\t/*\n-\t * If it is a tag object, see if we use a value that derefs\n-\t * the object, and if we do grab the object it refers to.\n-\t */\n-\ttagged = ((struct tag *)obj)->tagged->sha1;\n-\n-\t/*\n-\t * NEEDSWORK: This derefs tag only once, which\n-\t * is good to deal with chains of trust, but\n-\t * is not consistent with what deref_tag() does\n-\t * which peels the onion to the core.\n-\t */\n-\tbuf = get_obj(tagged, &obj, &size, &eaten);\n-\tif (!buf)\n-\t\tdie(\"missing object %s for %s\",\n-\t\t    sha1_to_hex(tagged), ref->refname);\n-\tif (!obj)\n-\t\tdie(\"parse_object_buffer failed on %s for %s\",\n-\t\t    sha1_to_hex(tagged), ref->refname);\n-\tgrab_values(ref->value, 1, obj, buf, size);\n-\tif (!eaten)\n-\t\tfree(buf);\n-}\n-\n-/*\n- * Given a ref, return the value for the atom.  This lazily gets value\n- * out of the object by calling populate value.\n- */\n-static void get_ref_atom_value(struct ref_array_item *ref, int atom, struct atom_value **v)\n-{\n-\tif (!ref->value) {\n-\t\tpopulate_value(ref);\n-\t\tfill_missing_values(ref->value);\n-\t}\n-\t*v = &ref->value[atom];\n-}\n-\n-/*\n- * Given a refname, return 1 if the refname matches with one of the patterns\n- * while the pattern is a pathname like 'refs/tags' or 'refs/heads/master'\n- * and so on, else return 0. Supports use of wild characters.\n- */\n-static int match_name_as_path(const char **pattern, const char *refname)\n-{\n-\tint namelen = strlen(refname);\n-\tfor (; *pattern; pattern++) {\n-\t\tconst char *p = *pattern;\n-\t\tint plen = strlen(p);\n-\n-\t\tif ((plen <= namelen) &&\n-\t\t    !strncmp(refname, p, plen) &&\n-\t\t    (refname[plen] == '\\0' ||\n-\t\t     refname[plen] == '/' ||\n-\t\t     p[plen-1] == '/'))\n-\t\t\treturn 1;\n-\t\tif (!wildmatch(p, refname, WM_PATHNAME, NULL))\n-\t\t\treturn 1;\n-\t}\n-\treturn 0;\n-}\n-\n-/* Allocate space for a new ref_array_item and copy the objectname and flag to it */\n-static struct ref_array_item *new_ref_array_item(const char *refname,\n-\t\t\t\t\t\t const unsigned char *objectname,\n-\t\t\t\t\t\t int flag)\n-{\n-\tstruct ref_array_item *ref = xcalloc(1, sizeof(struct ref_array_item));\n-\tref->refname = xstrdup(refname);\n-\thashcpy(ref->objectname, objectname);\n-\tref->flag = flag;\n-\n-\treturn ref;\n-}\n-\n-/*\n- * A call-back given to for_each_ref(). Filter refs and keep them for\n- * later object processing.\n- */\n-int ref_filter_handler(const char *refname, const unsigned char *sha1, int flag, void *cb_data)\n-{\n-\tstruct ref_filter_cbdata *ref_cbdata = cb_data;\n-\tstruct ref_filter *filter = &ref_cbdata->filter;\n-\tstruct ref_array_item *ref;\n-\n-\tif (flag & REF_BAD_NAME) {\n-\t\t  warning(\"ignoring ref with broken name %s\", refname);\n-\t\t  return 0;\n-\t}\n-\n-\tif (*filter->name_patterns && !match_name_as_path(filter->name_patterns, refname))\n-\t\treturn 0;\n-\n-\tref = new_ref_array_item(refname, sha1, flag);\n-\n-\tREALLOC_ARRAY(ref_cbdata->array.items, ref_cbdata->array.nr + 1);\n-\tref_cbdata->array.items[ref_cbdata->array.nr++] = ref;\n-\n-\treturn 0;\n-}\n-\n-/* Free all memory allocated for ref_filter_cbdata */\n-void ref_filter_clear_data(struct ref_filter_cbdata *ref_cbdata)\n-{\n-\tint i;\n-\n-\tfor (i = 0; i < ref_cbdata->array.nr; i++)\n-\t\tfree(ref_cbdata->array.items[i]);\n-\tfree(ref_cbdata->array.items);\n-\tref_cbdata->array.items = NULL;\n-\tref_cbdata->array.nr = ref_cbdata->array.alloc = 0;\n-}\n-\n-static int cmp_ref_sort(struct ref_sort *s, struct ref_array_item *a, struct ref_array_item *b)\n-{\n-\tstruct atom_value *va, *vb;\n-\tint cmp;\n-\tcmp_type cmp_type = used_atom_type[s->atom];\n-\n-\tget_ref_atom_value(a, s->atom, &va);\n-\tget_ref_atom_value(b, s->atom, &vb);\n-\tswitch (cmp_type) {\n-\tcase FIELD_STR:\n-\t\tcmp = strcmp(va->s, vb->s);\n-\t\tbreak;\n-\tdefault:\n-\t\tif (va->ul < vb->ul)\n-\t\t\tcmp = -1;\n-\t\telse if (va->ul == vb->ul)\n-\t\t\tcmp = 0;\n-\t\telse\n-\t\t\tcmp = 1;\n-\t\tbreak;\n-\t}\n-\treturn (s->reverse) ? -cmp : cmp;\n-}\n-\n-static struct ref_sort *ref_sort;\n-static int compare_refs(const void *a_, const void *b_)\n-{\n-\tstruct ref_array_item *a = *((struct ref_array_item **)a_);\n-\tstruct ref_array_item *b = *((struct ref_array_item **)b_);\n-\tstruct ref_sort *s;\n-\n-\tfor (s = ref_sort; s; s = s->next) {\n-\t\tint cmp = cmp_ref_sort(s, a, b);\n-\t\tif (cmp)\n-\t\t\treturn cmp;\n-\t}\n-\treturn 0;\n-}\n-\n-void sort_ref_array(struct ref_sort *sort, struct ref_array *array)\n-{\n-\tref_sort = sort;\n-\tqsort(array->items, array->nr, sizeof(struct ref_array_item *), compare_refs);\n-}\n-\n-static void print_value(struct atom_value *v, int quote_style)\n-{\n-\tstruct strbuf sb = STRBUF_INIT;\n-\tswitch (quote_style) {\n-\tcase QUOTE_NONE:\n-\t\tfputs(v->s, stdout);\n-\t\tbreak;\n-\tcase QUOTE_SHELL:\n-\t\tsq_quote_buf(&sb, v->s);\n-\t\tbreak;\n-\tcase QUOTE_PERL:\n-\t\tperl_quote_buf(&sb, v->s);\n-\t\tbreak;\n-\tcase QUOTE_PYTHON:\n-\t\tpython_quote_buf(&sb, v->s);\n-\t\tbreak;\n-\tcase QUOTE_TCL:\n-\t\ttcl_quote_buf(&sb, v->s);\n-\t\tbreak;\n-\t}\n-\tif (quote_style != QUOTE_NONE) {\n-\t\tfputs(sb.buf, stdout);\n-\t\tstrbuf_release(&sb);\n-\t}\n-}\n-\n-static int hex1(char ch)\n-{\n-\tif ('0' <= ch && ch <= '9')\n-\t\treturn ch - '0';\n-\telse if ('a' <= ch && ch <= 'f')\n-\t\treturn ch - 'a' + 10;\n-\telse if ('A' <= ch && ch <= 'F')\n-\t\treturn ch - 'A' + 10;\n-\treturn -1;\n-}\n-static int hex2(const char *cp)\n-{\n-\tif (cp[0] && cp[1])\n-\t\treturn (hex1(cp[0]) << 4) | hex1(cp[1]);\n-\telse\n-\t\treturn -1;\n-}\n-\n-static void emit(const char *cp, const char *ep)\n-{\n-\twhile (*cp && (!ep || cp < ep)) {\n-\t\tif (*cp == '%') {\n-\t\t\tif (cp[1] == '%')\n-\t\t\t\tcp++;\n-\t\t\telse {\n-\t\t\t\tint ch = hex2(cp + 1);\n-\t\t\t\tif (0 <= ch) {\n-\t\t\t\t\tputchar(ch);\n-\t\t\t\t\tcp += 3;\n-\t\t\t\t\tcontinue;\n-\t\t\t\t}\n-\t\t\t}\n-\t\t}\n-\t\tputchar(*cp);\n-\t\tcp++;\n-\t}\n-}\n-\n-void show_ref_array_item(struct ref_array_item *info, const char *format, int quote_style)\n-{\n-\tconst char *cp, *sp, *ep;\n-\n-\tfor (cp = format; *cp && (sp = find_next(cp)); cp = ep + 1) {\n-\t\tstruct atom_value *atomv;\n-\n-\t\tep = strchr(sp, ')');\n-\t\tif (cp < sp)\n-\t\t\temit(cp, sp);\n-\t\tget_ref_atom_value(info, parse_ref_filter_atom(sp + 2, ep), &atomv);\n-\t\tprint_value(atomv, quote_style);\n-\t}\n-\tif (*cp) {\n-\t\tsp = cp + strlen(cp);\n-\t\temit(cp, sp);\n-\t}\n-\tif (need_color_reset_at_eol) {\n-\t\tstruct atom_value resetv;\n-\t\tchar color[COLOR_MAXLEN] = \"\";\n-\n-\t\tif (color_parse(\"reset\", color) < 0)\n-\t\t\tdie(\"BUG: couldn't parse 'reset' as a color\");\n-\t\tresetv.s = color;\n-\t\tprint_value(&resetv, quote_style);\n-\t}\n-\tputchar('\\n');\n-}\n-\n-/*  If no sorting option is given, use refname to sort as default */\n-struct ref_sort *ref_default_sort(void)\n-{\n-\tstatic const char cstr_name[] = \"refname\";\n-\n-\tstruct ref_sort *sort = xcalloc(1, sizeof(*sort));\n-\n-\tsort->next = NULL;\n-\tsort->atom = parse_ref_filter_atom(cstr_name, cstr_name + strlen(cstr_name));\n-\treturn sort;\n-}\n-\n-int opt_parse_ref_sort(const struct option *opt, const char *arg, int unset)\n-{\n-\tstruct ref_sort **sort_tail = opt->value;\n-\tstruct ref_sort *s;\n-\tint len;\n-\n-\tif (!arg) /* should --no-sort void the list ? */\n-\t\treturn -1;\n-\n-\ts = xcalloc(1, sizeof(*s));\n-\ts->next = *sort_tail;\n-\t*sort_tail = s;\n-\n-\tif (*arg == '-') {\n-\t\ts->reverse = 1;\n-\t\targ++;\n-\t}\n-\tlen = strlen(arg);\n-\ts->atom = parse_ref_filter_atom(arg, arg+len);\n-\treturn 0;\n-}\n-\n static char const * const for_each_ref_usage[] = {\n \tN_(\"git for-each-ref [<options>] [<pattern>]\"),\n \tNULL\ndiff --git a/ref-filter.c b/ref-filter.c\nnew file mode 100644\nindex 0000000..2a8f504\n--- /dev/null\n+++ b/ref-filter.c\n@@ -0,0 +1,1050 @@\n+#include \"builtin.h\"\n+#include \"cache.h\"\n+#include \"parse-options.h\"\n+#include \"refs.h\"\n+#include \"wildmatch.h\"\n+#include \"commit.h\"\n+#include \"remote.h\"\n+#include \"color.h\"\n+#include \"tag.h\"\n+#include \"quote.h\"\n+\n+typedef enum { FIELD_STR, FIELD_ULONG, FIELD_TIME } cmp_type;\n+\n+static struct {\n+\tconst char *name;\n+\tcmp_type cmp_type;\n+} valid_atom[] = {\n+\t{ \"refname\" },\n+\t{ \"objecttype\" },\n+\t{ \"objectsize\", FIELD_ULONG },\n+\t{ \"objectname\" },\n+\t{ \"tree\" },\n+\t{ \"parent\" },\n+\t{ \"numparent\", FIELD_ULONG },\n+\t{ \"object\" },\n+\t{ \"type\" },\n+\t{ \"tag\" },\n+\t{ \"author\" },\n+\t{ \"authorname\" },\n+\t{ \"authoremail\" },\n+\t{ \"authordate\", FIELD_TIME },\n+\t{ \"committer\" },\n+\t{ \"committername\" },\n+\t{ \"committeremail\" },\n+\t{ \"committerdate\", FIELD_TIME },\n+\t{ \"tagger\" },\n+\t{ \"taggername\" },\n+\t{ \"taggeremail\" },\n+\t{ \"taggerdate\", FIELD_TIME },\n+\t{ \"creator\" },\n+\t{ \"creatordate\", FIELD_TIME },\n+\t{ \"subject\" },\n+\t{ \"body\" },\n+\t{ \"contents\" },\n+\t{ \"contents:subject\" },\n+\t{ \"contents:body\" },\n+\t{ \"contents:signature\" },\n+\t{ \"upstream\" },\n+\t{ \"symref\" },\n+\t{ \"flag\" },\n+\t{ \"HEAD\" },\n+\t{ \"color\" },\n+};\n+\n+/*\n+ * An atom is a valid field atom listed above, possibly prefixed with\n+ * a \"*\" to denote deref_tag().\n+ *\n+ * We parse given format string and sort specifiers, and make a list\n+ * of properties that we need to extract out of objects. ref_array_item\n+ * structure will hold an array of values extracted that can be\n+ * indexed with the \"atom number\", which is an index into this\n+ * array.\n+ */\n+static const char **used_atom;\n+static cmp_type *used_atom_type;\n+static int used_atom_cnt, need_tagged, need_symref;\n+static int need_color_reset_at_eol;\n+\n+/*\n+ * Used to parse format string and sort specifiers\n+ */\n+int parse_ref_filter_atom(const char *atom, const char *ep)\n+{\n+\tconst char *sp;\n+\tint i, at;\n+\n+\tsp = atom;\n+\tif (*sp == '*' && sp < ep)\n+\t\tsp++; /* deref */\n+\tif (ep <= sp)\n+\t\tdie(\"malformed field name: %.*s\", (int)(ep-atom), atom);\n+\n+\t/* Do we have the atom already used elsewhere? */\n+\tfor (i = 0; i < used_atom_cnt; i++) {\n+\t\tint len = strlen(used_atom[i]);\n+\t\tif (len == ep - atom && !memcmp(used_atom[i], atom, len))\n+\t\t\treturn i;\n+\t}\n+\n+\t/* Is the atom a valid one? */\n+\tfor (i = 0; i < ARRAY_SIZE(valid_atom); i++) {\n+\t\tint len = strlen(valid_atom[i].name);\n+\t\t/*\n+\t\t * If the atom name has a colon, strip it and everything after\n+\t\t * it off - it specifies the format for this entry, and\n+\t\t * shouldn't be used for checking against the valid_atom\n+\t\t * table.\n+\t\t */\n+\t\tconst char *formatp = strchr(sp, ':');\n+\t\tif (!formatp || ep < formatp)\n+\t\t\tformatp = ep;\n+\t\tif (len == formatp - sp && !memcmp(valid_atom[i].name, sp, len))\n+\t\t\tbreak;\n+\t}\n+\n+\tif (ARRAY_SIZE(valid_atom) <= i)\n+\t\tdie(\"unknown field name: %.*s\", (int)(ep-atom), atom);\n+\n+\t/* Add it in, including the deref prefix */\n+\tat = used_atom_cnt;\n+\tused_atom_cnt++;\n+\tREALLOC_ARRAY(used_atom, used_atom_cnt);\n+\tREALLOC_ARRAY(used_atom_type, used_atom_cnt);\n+\tused_atom[at] = xmemdupz(atom, ep - atom);\n+\tused_atom_type[at] = valid_atom[i].cmp_type;\n+\tif (*atom == '*')\n+\t\tneed_tagged = 1;\n+\tif (!strcmp(used_atom[at], \"symref\"))\n+\t\tneed_symref = 1;\n+\treturn at;\n+}\n+\n+/*\n+ * In a format string, find the next occurrence of %(atom).\n+ */\n+static const char *find_next(const char *cp)\n+{\n+\twhile (*cp) {\n+\t\tif (*cp == '%') {\n+\t\t\t/*\n+\t\t\t * %( is the start of an atom;\n+\t\t\t * %% is a quoted per-cent.\n+\t\t\t */\n+\t\t\tif (cp[1] == '(')\n+\t\t\t\treturn cp;\n+\t\t\telse if (cp[1] == '%')\n+\t\t\t\tcp++; /* skip over two % */\n+\t\t\t/* otherwise this is a singleton, literal % */\n+\t\t}\n+\t\tcp++;\n+\t}\n+\treturn NULL;\n+}\n+\n+/*\n+ * Make sure the format string is well formed, and parse out\n+ * the used atoms.\n+ */\n+int verify_ref_format(const char *format)\n+{\n+\tconst char *cp, *sp;\n+\n+\tneed_color_reset_at_eol = 0;\n+\tfor (cp = format; *cp && (sp = find_next(cp)); ) {\n+\t\tconst char *color, *ep = strchr(sp, ')');\n+\t\tint at;\n+\n+\t\tif (!ep)\n+\t\t\treturn error(\"malformed format string %s\", sp);\n+\t\t/* sp points at \"%(\" and ep points at the closing \")\" */\n+\t\tat = parse_ref_filter_atom(sp + 2, ep);\n+\t\tcp = ep + 1;\n+\n+\t\tif (skip_prefix(used_atom[at], \"color:\", &color))\n+\t\t\tneed_color_reset_at_eol = !!strcmp(color, \"reset\");\n+\t}\n+\treturn 0;\n+}\n+\n+/*\n+ * Given an object name, read the object data and size, and return a\n+ * \"struct object\".  If the object data we are returning is also borrowed\n+ * by the \"struct object\" representation, set *eaten as well---it is a\n+ * signal from parse_object_buffer to us not to free the buffer.\n+ */\n+static void *get_obj(const unsigned char *sha1, struct object **obj, unsigned long *sz, int *eaten)\n+{\n+\tenum object_type type;\n+\tvoid *buf = read_sha1_file(sha1, &type, sz);\n+\n+\tif (buf)\n+\t\t*obj = parse_object_buffer(sha1, type, *sz, buf, eaten);\n+\telse\n+\t\t*obj = NULL;\n+\treturn buf;\n+}\n+\n+static int grab_objectname(const char *name, const unsigned char *sha1,\n+\t\t\t    struct atom_value *v)\n+{\n+\tif (!strcmp(name, \"objectname\")) {\n+\t\tchar *s = xmalloc(41);\n+\t\tstrcpy(s, sha1_to_hex(sha1));\n+\t\tv->s = s;\n+\t\treturn 1;\n+\t}\n+\tif (!strcmp(name, \"objectname:short\")) {\n+\t\tv->s = xstrdup(find_unique_abbrev(sha1, DEFAULT_ABBREV));\n+\t\treturn 1;\n+\t}\n+\treturn 0;\n+}\n+\n+/* See grab_values */\n+static void grab_common_values(struct atom_value *val, int deref, struct object *obj, void *buf, unsigned long sz)\n+{\n+\tint i;\n+\n+\tfor (i = 0; i < used_atom_cnt; i++) {\n+\t\tconst char *name = used_atom[i];\n+\t\tstruct atom_value *v = &val[i];\n+\t\tif (!!deref != (*name == '*'))\n+\t\t\tcontinue;\n+\t\tif (deref)\n+\t\t\tname++;\n+\t\tif (!strcmp(name, \"objecttype\"))\n+\t\t\tv->s = typename(obj->type);\n+\t\telse if (!strcmp(name, \"objectsize\")) {\n+\t\t\tchar *s = xmalloc(40);\n+\t\t\tsprintf(s, \"%lu\", sz);\n+\t\t\tv->ul = sz;\n+\t\t\tv->s = s;\n+\t\t}\n+\t\telse if (deref)\n+\t\t\tgrab_objectname(name, obj->sha1, v);\n+\t}\n+}\n+\n+/* See grab_values */\n+static void grab_tag_values(struct atom_value *val, int deref, struct object *obj, void *buf, unsigned long sz)\n+{\n+\tint i;\n+\tstruct tag *tag = (struct tag *) obj;\n+\n+\tfor (i = 0; i < used_atom_cnt; i++) {\n+\t\tconst char *name = used_atom[i];\n+\t\tstruct atom_value *v = &val[i];\n+\t\tif (!!deref != (*name == '*'))\n+\t\t\tcontinue;\n+\t\tif (deref)\n+\t\t\tname++;\n+\t\tif (!strcmp(name, \"tag\"))\n+\t\t\tv->s = tag->tag;\n+\t\telse if (!strcmp(name, \"type\") && tag->tagged)\n+\t\t\tv->s = typename(tag->tagged->type);\n+\t\telse if (!strcmp(name, \"object\") && tag->tagged) {\n+\t\t\tchar *s = xmalloc(41);\n+\t\t\tstrcpy(s, sha1_to_hex(tag->tagged->sha1));\n+\t\t\tv->s = s;\n+\t\t}\n+\t}\n+}\n+\n+/* See grab_values */\n+static void grab_commit_values(struct atom_value *val, int deref, struct object *obj, void *buf, unsigned long sz)\n+{\n+\tint i;\n+\tstruct commit *commit = (struct commit *) obj;\n+\n+\tfor (i = 0; i < used_atom_cnt; i++) {\n+\t\tconst char *name = used_atom[i];\n+\t\tstruct atom_value *v = &val[i];\n+\t\tif (!!deref != (*name == '*'))\n+\t\t\tcontinue;\n+\t\tif (deref)\n+\t\t\tname++;\n+\t\tif (!strcmp(name, \"tree\")) {\n+\t\t\tchar *s = xmalloc(41);\n+\t\t\tstrcpy(s, sha1_to_hex(commit->tree->object.sha1));\n+\t\t\tv->s = s;\n+\t\t}\n+\t\tif (!strcmp(name, \"numparent\")) {\n+\t\t\tchar *s = xmalloc(40);\n+\t\t\tv->ul = commit_list_count(commit->parents);\n+\t\t\tsprintf(s, \"%lu\", v->ul);\n+\t\t\tv->s = s;\n+\t\t}\n+\t\telse if (!strcmp(name, \"parent\")) {\n+\t\t\tint num = commit_list_count(commit->parents);\n+\t\t\tint i;\n+\t\t\tstruct commit_list *parents;\n+\t\t\tchar *s = xmalloc(41 * num + 1);\n+\t\t\tv->s = s;\n+\t\t\tfor (i = 0, parents = commit->parents;\n+\t\t\t     parents;\n+\t\t\t     parents = parents->next, i = i + 41) {\n+\t\t\t\tstruct commit *parent = parents->item;\n+\t\t\t\tstrcpy(s+i, sha1_to_hex(parent->object.sha1));\n+\t\t\t\tif (parents->next)\n+\t\t\t\t\ts[i+40] = ' ';\n+\t\t\t}\n+\t\t\tif (!i)\n+\t\t\t\t*s = '\\0';\n+\t\t}\n+\t}\n+}\n+\n+static const char *find_wholine(const char *who, int wholen, const char *buf, unsigned long sz)\n+{\n+\tconst char *eol;\n+\twhile (*buf) {\n+\t\tif (!strncmp(buf, who, wholen) &&\n+\t\t    buf[wholen] == ' ')\n+\t\t\treturn buf + wholen + 1;\n+\t\teol = strchr(buf, '\\n');\n+\t\tif (!eol)\n+\t\t\treturn \"\";\n+\t\teol++;\n+\t\tif (*eol == '\\n')\n+\t\t\treturn \"\"; /* end of header */\n+\t\tbuf = eol;\n+\t}\n+\treturn \"\";\n+}\n+\n+static const char *copy_line(const char *buf)\n+{\n+\tconst char *eol = strchrnul(buf, '\\n');\n+\treturn xmemdupz(buf, eol - buf);\n+}\n+\n+static const char *copy_name(const char *buf)\n+{\n+\tconst char *cp;\n+\tfor (cp = buf; *cp && *cp != '\\n'; cp++) {\n+\t\tif (!strncmp(cp, \" <\", 2))\n+\t\t\treturn xmemdupz(buf, cp - buf);\n+\t}\n+\treturn \"\";\n+}\n+\n+static const char *copy_email(const char *buf)\n+{\n+\tconst char *email = strchr(buf, '<');\n+\tconst char *eoemail;\n+\tif (!email)\n+\t\treturn \"\";\n+\teoemail = strchr(email, '>');\n+\tif (!eoemail)\n+\t\treturn \"\";\n+\treturn xmemdupz(email, eoemail + 1 - email);\n+}\n+\n+static char *copy_subject(const char *buf, unsigned long len)\n+{\n+\tchar *r = xmemdupz(buf, len);\n+\tint i;\n+\n+\tfor (i = 0; i < len; i++)\n+\t\tif (r[i] == '\\n')\n+\t\t\tr[i] = ' ';\n+\n+\treturn r;\n+}\n+\n+static void grab_date(const char *buf, struct atom_value *v, const char *atomname)\n+{\n+\tconst char *eoemail = strstr(buf, \"> \");\n+\tchar *zone;\n+\tunsigned long timestamp;\n+\tlong tz;\n+\tenum date_mode date_mode = DATE_NORMAL;\n+\tconst char *formatp;\n+\n+\t/*\n+\t * We got here because atomname ends in \"date\" or \"date<something>\";\n+\t * it's not possible that <something> is not \":<format>\" because\n+\t * parse_ref_filter_atom() wouldn't have allowed it, so we can assume that no\n+\t * \":\" means no format is specified, and use the default.\n+\t */\n+\tformatp = strchr(atomname, ':');\n+\tif (formatp != NULL) {\n+\t\tformatp++;\n+\t\tdate_mode = parse_date_format(formatp);\n+\t}\n+\n+\tif (!eoemail)\n+\t\tgoto bad;\n+\ttimestamp = strtoul(eoemail + 2, &zone, 10);\n+\tif (timestamp == ULONG_MAX)\n+\t\tgoto bad;\n+\ttz = strtol(zone, NULL, 10);\n+\tif ((tz == LONG_MIN || tz == LONG_MAX) && errno == ERANGE)\n+\t\tgoto bad;\n+\tv->s = xstrdup(show_date(timestamp, tz, date_mode));\n+\tv->ul = timestamp;\n+\treturn;\n+ bad:\n+\tv->s = \"\";\n+\tv->ul = 0;\n+}\n+\n+/* See grab_values */\n+static void grab_person(const char *who, struct atom_value *val, int deref, struct object *obj, void *buf, unsigned long sz)\n+{\n+\tint i;\n+\tint wholen = strlen(who);\n+\tconst char *wholine = NULL;\n+\n+\tfor (i = 0; i < used_atom_cnt; i++) {\n+\t\tconst char *name = used_atom[i];\n+\t\tstruct atom_value *v = &val[i];\n+\t\tif (!!deref != (*name == '*'))\n+\t\t\tcontinue;\n+\t\tif (deref)\n+\t\t\tname++;\n+\t\tif (strncmp(who, name, wholen))\n+\t\t\tcontinue;\n+\t\tif (name[wholen] != 0 &&\n+\t\t    strcmp(name + wholen, \"name\") &&\n+\t\t    strcmp(name + wholen, \"email\") &&\n+\t\t    !starts_with(name + wholen, \"date\"))\n+\t\t\tcontinue;\n+\t\tif (!wholine)\n+\t\t\twholine = find_wholine(who, wholen, buf, sz);\n+\t\tif (!wholine)\n+\t\t\treturn; /* no point looking for it */\n+\t\tif (name[wholen] == 0)\n+\t\t\tv->s = copy_line(wholine);\n+\t\telse if (!strcmp(name + wholen, \"name\"))\n+\t\t\tv->s = copy_name(wholine);\n+\t\telse if (!strcmp(name + wholen, \"email\"))\n+\t\t\tv->s = copy_email(wholine);\n+\t\telse if (starts_with(name + wholen, \"date\"))\n+\t\t\tgrab_date(wholine, v, name);\n+\t}\n+\n+\t/*\n+\t * For a tag or a commit object, if \"creator\" or \"creatordate\" is\n+\t * requested, do something special.\n+\t */\n+\tif (strcmp(who, \"tagger\") && strcmp(who, \"committer\"))\n+\t\treturn; /* \"author\" for commit object is not wanted */\n+\tif (!wholine)\n+\t\twholine = find_wholine(who, wholen, buf, sz);\n+\tif (!wholine)\n+\t\treturn;\n+\tfor (i = 0; i < used_atom_cnt; i++) {\n+\t\tconst char *name = used_atom[i];\n+\t\tstruct atom_value *v = &val[i];\n+\t\tif (!!deref != (*name == '*'))\n+\t\t\tcontinue;\n+\t\tif (deref)\n+\t\t\tname++;\n+\n+\t\tif (starts_with(name, \"creatordate\"))\n+\t\t\tgrab_date(wholine, v, name);\n+\t\telse if (!strcmp(name, \"creator\"))\n+\t\t\tv->s = copy_line(wholine);\n+\t}\n+}\n+\n+static void find_subpos(const char *buf, unsigned long sz,\n+\t\t\tconst char **sub, unsigned long *sublen,\n+\t\t\tconst char **body, unsigned long *bodylen,\n+\t\t\tunsigned long *nonsiglen,\n+\t\t\tconst char **sig, unsigned long *siglen)\n+{\n+\tconst char *eol;\n+\t/* skip past header until we hit empty line */\n+\twhile (*buf && *buf != '\\n') {\n+\t\teol = strchrnul(buf, '\\n');\n+\t\tif (*eol)\n+\t\t\teol++;\n+\t\tbuf = eol;\n+\t}\n+\t/* skip any empty lines */\n+\twhile (*buf == '\\n')\n+\t\tbuf++;\n+\n+\t/* parse signature first; we might not even have a subject line */\n+\t*sig = buf + parse_signature(buf, strlen(buf));\n+\t*siglen = strlen(*sig);\n+\n+\t/* subject is first non-empty line */\n+\t*sub = buf;\n+\t/* subject goes to first empty line */\n+\twhile (buf < *sig && *buf && *buf != '\\n') {\n+\t\teol = strchrnul(buf, '\\n');\n+\t\tif (*eol)\n+\t\t\teol++;\n+\t\tbuf = eol;\n+\t}\n+\t*sublen = buf - *sub;\n+\t/* drop trailing newline, if present */\n+\tif (*sublen && (*sub)[*sublen - 1] == '\\n')\n+\t\t*sublen -= 1;\n+\n+\t/* skip any empty lines */\n+\twhile (*buf == '\\n')\n+\t\tbuf++;\n+\t*body = buf;\n+\t*bodylen = strlen(buf);\n+\t*nonsiglen = *sig - buf;\n+}\n+\n+/* See grab_values */\n+static void grab_sub_body_contents(struct atom_value *val, int deref, struct object *obj, void *buf, unsigned long sz)\n+{\n+\tint i;\n+\tconst char *subpos = NULL, *bodypos = NULL, *sigpos = NULL;\n+\tunsigned long sublen = 0, bodylen = 0, nonsiglen = 0, siglen = 0;\n+\n+\tfor (i = 0; i < used_atom_cnt; i++) {\n+\t\tconst char *name = used_atom[i];\n+\t\tstruct atom_value *v = &val[i];\n+\t\tif (!!deref != (*name == '*'))\n+\t\t\tcontinue;\n+\t\tif (deref)\n+\t\t\tname++;\n+\t\tif (strcmp(name, \"subject\") &&\n+\t\t    strcmp(name, \"body\") &&\n+\t\t    strcmp(name, \"contents\") &&\n+\t\t    strcmp(name, \"contents:subject\") &&\n+\t\t    strcmp(name, \"contents:body\") &&\n+\t\t    strcmp(name, \"contents:signature\"))\n+\t\t\tcontinue;\n+\t\tif (!subpos)\n+\t\t\tfind_subpos(buf, sz,\n+\t\t\t\t    &subpos, &sublen,\n+\t\t\t\t    &bodypos, &bodylen, &nonsiglen,\n+\t\t\t\t    &sigpos, &siglen);\n+\n+\t\tif (!strcmp(name, \"subject\"))\n+\t\t\tv->s = copy_subject(subpos, sublen);\n+\t\telse if (!strcmp(name, \"contents:subject\"))\n+\t\t\tv->s = copy_subject(subpos, sublen);\n+\t\telse if (!strcmp(name, \"body\"))\n+\t\t\tv->s = xmemdupz(bodypos, bodylen);\n+\t\telse if (!strcmp(name, \"contents:body\"))\n+\t\t\tv->s = xmemdupz(bodypos, nonsiglen);\n+\t\telse if (!strcmp(name, \"contents:signature\"))\n+\t\t\tv->s = xmemdupz(sigpos, siglen);\n+\t\telse if (!strcmp(name, \"contents\"))\n+\t\t\tv->s = xstrdup(subpos);\n+\t}\n+}\n+\n+/*\n+ * We want to have empty print-string for field requests\n+ * that do not apply (e.g. \"authordate\" for a tag object)\n+ */\n+static void fill_missing_values(struct atom_value *val)\n+{\n+\tint i;\n+\tfor (i = 0; i < used_atom_cnt; i++) {\n+\t\tstruct atom_value *v = &val[i];\n+\t\tif (v->s == NULL)\n+\t\t\tv->s = \"\";\n+\t}\n+}\n+\n+/*\n+ * val is a list of atom_value to hold returned values.  Extract\n+ * the values for atoms in used_atom array out of (obj, buf, sz).\n+ * when deref is false, (obj, buf, sz) is the object that is\n+ * pointed at by the ref itself; otherwise it is the object the\n+ * ref (which is a tag) refers to.\n+ */\n+static void grab_values(struct atom_value *val, int deref, struct object *obj, void *buf, unsigned long sz)\n+{\n+\tgrab_common_values(val, deref, obj, buf, sz);\n+\tswitch (obj->type) {\n+\tcase OBJ_TAG:\n+\t\tgrab_tag_values(val, deref, obj, buf, sz);\n+\t\tgrab_sub_body_contents(val, deref, obj, buf, sz);\n+\t\tgrab_person(\"tagger\", val, deref, obj, buf, sz);\n+\t\tbreak;\n+\tcase OBJ_COMMIT:\n+\t\tgrab_commit_values(val, deref, obj, buf, sz);\n+\t\tgrab_sub_body_contents(val, deref, obj, buf, sz);\n+\t\tgrab_person(\"author\", val, deref, obj, buf, sz);\n+\t\tgrab_person(\"committer\", val, deref, obj, buf, sz);\n+\t\tbreak;\n+\tcase OBJ_TREE:\n+\t\t/* grab_tree_values(val, deref, obj, buf, sz); */\n+\t\tbreak;\n+\tcase OBJ_BLOB:\n+\t\t/* grab_blob_values(val, deref, obj, buf, sz); */\n+\t\tbreak;\n+\tdefault:\n+\t\tdie(\"Eh?  Object of type %d?\", obj->type);\n+\t}\n+}\n+\n+static inline char *copy_advance(char *dst, const char *src)\n+{\n+\twhile (*src)\n+\t\t*dst++ = *src++;\n+\treturn dst;\n+}\n+\n+/*\n+ * Parse the object referred by ref, and grab needed value.\n+ */\n+static void populate_value(struct ref_array_item *ref)\n+{\n+\tvoid *buf;\n+\tstruct object *obj;\n+\tint eaten, i;\n+\tunsigned long size;\n+\tconst unsigned char *tagged;\n+\n+\tref->value = xcalloc(used_atom_cnt, sizeof(struct atom_value));\n+\n+\tif (need_symref && (ref->flag & REF_ISSYMREF) && !ref->symref) {\n+\t\tunsigned char unused1[20];\n+\t\tref->symref = resolve_refdup(ref->refname, RESOLVE_REF_READING,\n+\t\t\t\t\t     unused1, NULL);\n+\t\tif (!ref->symref)\n+\t\t\tref->symref = \"\";\n+\t}\n+\n+\t/* Fill in specials first */\n+\tfor (i = 0; i < used_atom_cnt; i++) {\n+\t\tconst char *name = used_atom[i];\n+\t\tstruct atom_value *v = &ref->value[i];\n+\t\tint deref = 0;\n+\t\tconst char *refname;\n+\t\tconst char *formatp;\n+\t\tstruct branch *branch = NULL;\n+\n+\t\tif (*name == '*') {\n+\t\t\tderef = 1;\n+\t\t\tname++;\n+\t\t}\n+\n+\t\tif (starts_with(name, \"refname\"))\n+\t\t\trefname = ref->refname;\n+\t\telse if (starts_with(name, \"symref\"))\n+\t\t\trefname = ref->symref ? ref->symref : \"\";\n+\t\telse if (starts_with(name, \"upstream\")) {\n+\t\t\t/* only local branches may have an upstream */\n+\t\t\tif (!starts_with(ref->refname, \"refs/heads/\"))\n+\t\t\t\tcontinue;\n+\t\t\tbranch = branch_get(ref->refname + 11);\n+\n+\t\t\tif (!branch || !branch->merge || !branch->merge[0] ||\n+\t\t\t    !branch->merge[0]->dst)\n+\t\t\t\tcontinue;\n+\t\t\trefname = branch->merge[0]->dst;\n+\t\t} else if (starts_with(name, \"color:\")) {\n+\t\t\tchar color[COLOR_MAXLEN] = \"\";\n+\n+\t\t\tif (color_parse(name + 6, color) < 0)\n+\t\t\t\tdie(_(\"unable to parse format\"));\n+\t\t\tv->s = xstrdup(color);\n+\t\t\tcontinue;\n+\t\t} else if (!strcmp(name, \"flag\")) {\n+\t\t\tchar buf[256], *cp = buf;\n+\t\t\tif (ref->flag & REF_ISSYMREF)\n+\t\t\t\tcp = copy_advance(cp, \",symref\");\n+\t\t\tif (ref->flag & REF_ISPACKED)\n+\t\t\t\tcp = copy_advance(cp, \",packed\");\n+\t\t\tif (cp == buf)\n+\t\t\t\tv->s = \"\";\n+\t\t\telse {\n+\t\t\t\t*cp = '\\0';\n+\t\t\t\tv->s = xstrdup(buf + 1);\n+\t\t\t}\n+\t\t\tcontinue;\n+\t\t} else if (!deref && grab_objectname(name, ref->objectname, v)) {\n+\t\t\tcontinue;\n+\t\t} else if (!strcmp(name, \"HEAD\")) {\n+\t\t\tconst char *head;\n+\t\t\tunsigned char sha1[20];\n+\n+\t\t\thead = resolve_ref_unsafe(\"HEAD\", RESOLVE_REF_READING,\n+\t\t\t\t\t\t  sha1, NULL);\n+\t\t\tif (!strcmp(ref->refname, head))\n+\t\t\t\tv->s = \"*\";\n+\t\t\telse\n+\t\t\t\tv->s = \" \";\n+\t\t\tcontinue;\n+\t\t} else\n+\t\t\tcontinue;\n+\n+\t\tformatp = strchr(name, ':');\n+\t\tif (formatp) {\n+\t\t\tint num_ours, num_theirs;\n+\n+\t\t\tformatp++;\n+\t\t\tif (!strcmp(formatp, \"short\"))\n+\t\t\t\trefname = shorten_unambiguous_ref(refname,\n+\t\t\t\t\t\t      warn_ambiguous_refs);\n+\t\t\telse if (!strcmp(formatp, \"track\") &&\n+\t\t\t\t starts_with(name, \"upstream\")) {\n+\t\t\t\tchar buf[40];\n+\n+\t\t\t\tif (stat_tracking_info(branch, &num_ours,\n+\t\t\t\t\t\t       &num_theirs) != 1)\n+\t\t\t\t\tcontinue;\n+\n+\t\t\t\tif (!num_ours && !num_theirs)\n+\t\t\t\t\tv->s = \"\";\n+\t\t\t\telse if (!num_ours) {\n+\t\t\t\t\tsprintf(buf, \"[behind %d]\", num_theirs);\n+\t\t\t\t\tv->s = xstrdup(buf);\n+\t\t\t\t} else if (!num_theirs) {\n+\t\t\t\t\tsprintf(buf, \"[ahead %d]\", num_ours);\n+\t\t\t\t\tv->s = xstrdup(buf);\n+\t\t\t\t} else {\n+\t\t\t\t\tsprintf(buf, \"[ahead %d, behind %d]\",\n+\t\t\t\t\t\tnum_ours, num_theirs);\n+\t\t\t\t\tv->s = xstrdup(buf);\n+\t\t\t\t}\n+\t\t\t\tcontinue;\n+\t\t\t} else if (!strcmp(formatp, \"trackshort\") &&\n+\t\t\t\t   starts_with(name, \"upstream\")) {\n+\t\t\t\tassert(branch);\n+\n+\t\t\t\tif (stat_tracking_info(branch, &num_ours,\n+\t\t\t\t\t\t\t&num_theirs) != 1)\n+\t\t\t\t\tcontinue;\n+\n+\t\t\t\tif (!num_ours && !num_theirs)\n+\t\t\t\t\tv->s = \"=\";\n+\t\t\t\telse if (!num_ours)\n+\t\t\t\t\tv->s = \"<\";\n+\t\t\t\telse if (!num_theirs)\n+\t\t\t\t\tv->s = \">\";\n+\t\t\t\telse\n+\t\t\t\t\tv->s = \"<>\";\n+\t\t\t\tcontinue;\n+\t\t\t} else\n+\t\t\t\tdie(\"unknown %.*s format %s\",\n+\t\t\t\t    (int)(formatp - name), name, formatp);\n+\t\t}\n+\n+\t\tif (!deref)\n+\t\t\tv->s = refname;\n+\t\telse {\n+\t\t\tint len = strlen(refname);\n+\t\t\tchar *s = xmalloc(len + 4);\n+\t\t\tsprintf(s, \"%s^{}\", refname);\n+\t\t\tv->s = s;\n+\t\t}\n+\t}\n+\n+\tfor (i = 0; i < used_atom_cnt; i++) {\n+\t\tstruct atom_value *v = &ref->value[i];\n+\t\tif (v->s == NULL)\n+\t\t\tgoto need_obj;\n+\t}\n+\treturn;\n+\n+ need_obj:\n+\tbuf = get_obj(ref->objectname, &obj, &size, &eaten);\n+\tif (!buf)\n+\t\tdie(\"missing object %s for %s\",\n+\t\t    sha1_to_hex(ref->objectname), ref->refname);\n+\tif (!obj)\n+\t\tdie(\"parse_object_buffer failed on %s for %s\",\n+\t\t    sha1_to_hex(ref->objectname), ref->refname);\n+\n+\tgrab_values(ref->value, 0, obj, buf, size);\n+\tif (!eaten)\n+\t\tfree(buf);\n+\n+\t/*\n+\t * If there is no atom that wants to know about tagged\n+\t * object, we are done.\n+\t */\n+\tif (!need_tagged || (obj->type != OBJ_TAG))\n+\t\treturn;\n+\n+\t/*\n+\t * If it is a tag object, see if we use a value that derefs\n+\t * the object, and if we do grab the object it refers to.\n+\t */\n+\ttagged = ((struct tag *)obj)->tagged->sha1;\n+\n+\t/*\n+\t * NEEDSWORK: This derefs tag only once, which\n+\t * is good to deal with chains of trust, but\n+\t * is not consistent with what deref_tag() does\n+\t * which peels the onion to the core.\n+\t */\n+\tbuf = get_obj(tagged, &obj, &size, &eaten);\n+\tif (!buf)\n+\t\tdie(\"missing object %s for %s\",\n+\t\t    sha1_to_hex(tagged), ref->refname);\n+\tif (!obj)\n+\t\tdie(\"parse_object_buffer failed on %s for %s\",\n+\t\t    sha1_to_hex(tagged), ref->refname);\n+\tgrab_values(ref->value, 1, obj, buf, size);\n+\tif (!eaten)\n+\t\tfree(buf);\n+}\n+\n+/*\n+ * Given a ref, return the value for the atom.  This lazily gets value\n+ * out of the object by calling populate value.\n+ */\n+static void get_ref_atom_value(struct ref_array_item *ref, int atom, struct atom_value **v)\n+{\n+\tif (!ref->value) {\n+\t\tpopulate_value(ref);\n+\t\tfill_missing_values(ref->value);\n+\t}\n+\t*v = &ref->value[atom];\n+}\n+\n+/*\n+ * Given a refname, return 1 if the refname matches with one of the patterns\n+ * while the pattern is a pathname like 'refs/tags' or 'refs/heads/master'\n+ * and so on, else return 0. Supports use of wild characters.\n+ */\n+static int match_name_as_path(const char **pattern, const char *refname)\n+{\n+\tint namelen = strlen(refname);\n+\tfor (; *pattern; pattern++) {\n+\t\tconst char *p = *pattern;\n+\t\tint plen = strlen(p);\n+\n+\t\tif ((plen <= namelen) &&\n+\t\t    !strncmp(refname, p, plen) &&\n+\t\t    (refname[plen] == '\\0' ||\n+\t\t     refname[plen] == '/' ||\n+\t\t     p[plen-1] == '/'))\n+\t\t\treturn 1;\n+\t\tif (!wildmatch(p, refname, WM_PATHNAME, NULL))\n+\t\t\treturn 1;\n+\t}\n+\treturn 0;\n+}\n+\n+/* Allocate space for a new ref_array_item and copy the objectname and flag to it */\n+static struct ref_array_item *new_ref_array_item(const char *refname,\n+\t\t\t\t\t\t const unsigned char *objectname,\n+\t\t\t\t\t\t int flag)\n+{\n+\tstruct ref_array_item *ref = xcalloc(1, sizeof(struct ref_array_item));\n+\tref->refname = xstrdup(refname);\n+\thashcpy(ref->objectname, objectname);\n+\tref->flag = flag;\n+\n+\treturn ref;\n+}\n+\n+/*\n+ * A call-back given to for_each_ref(). Filter refs and keep them for\n+ * later object processing.\n+ */\n+int ref_filter_handler(const char *refname, const unsigned char *sha1, int flag, void *cb_data)\n+{\n+\tstruct ref_filter_cbdata *ref_cbdata = cb_data;\n+\tstruct ref_filter *filter = &ref_cbdata->filter;\n+\tstruct ref_array_item *ref;\n+\n+\tif (flag & REF_BAD_NAME) {\n+\t\t  warning(\"ignoring ref with broken name %s\", refname);\n+\t\t  return 0;\n+\t}\n+\n+\tif (*filter->name_patterns && !match_name_as_path(filter->name_patterns, refname))\n+\t\treturn 0;\n+\n+\tref = new_ref_array_item(refname, sha1, flag);\n+\n+\tREALLOC_ARRAY(ref_cbdata->array.items, ref_cbdata->array.nr + 1);\n+\tref_cbdata->array.items[ref_cbdata->array.nr++] = ref;\n+\n+\treturn 0;\n+}\n+\n+/* Free all memory allocated for ref_filter_cbdata */\n+void ref_filter_clear_data(struct ref_filter_cbdata *ref_cbdata)\n+{\n+\tint i;\n+\n+\tfor (i = 0; i < ref_cbdata->array.nr; i++)\n+\t\tfree(ref_cbdata->array.items[i]);\n+\tfree(ref_cbdata->array.items);\n+\tref_cbdata->array.items = NULL;\n+\tref_cbdata->array.nr = ref_cbdata->array.alloc = 0;\n+}\n+\n+static int cmp_ref_sort(struct ref_sort *s, struct ref_array_item *a, struct ref_array_item *b)\n+{\n+\tstruct atom_value *va, *vb;\n+\tint cmp;\n+\tcmp_type cmp_type = used_atom_type[s->atom];\n+\n+\tget_ref_atom_value(a, s->atom, &va);\n+\tget_ref_atom_value(b, s->atom, &vb);\n+\tswitch (cmp_type) {\n+\tcase FIELD_STR:\n+\t\tcmp = strcmp(va->s, vb->s);\n+\t\tbreak;\n+\tdefault:\n+\t\tif (va->ul < vb->ul)\n+\t\t\tcmp = -1;\n+\t\telse if (va->ul == vb->ul)\n+\t\t\tcmp = 0;\n+\t\telse\n+\t\t\tcmp = 1;\n+\t\tbreak;\n+\t}\n+\treturn (s->reverse) ? -cmp : cmp;\n+}\n+\n+static struct ref_sort *ref_sort;\n+static int compare_refs(const void *a_, const void *b_)\n+{\n+\tstruct ref_array_item *a = *((struct ref_array_item **)a_);\n+\tstruct ref_array_item *b = *((struct ref_array_item **)b_);\n+\tstruct ref_sort *s;\n+\n+\tfor (s = ref_sort; s; s = s->next) {\n+\t\tint cmp = cmp_ref_sort(s, a, b);\n+\t\tif (cmp)\n+\t\t\treturn cmp;\n+\t}\n+\treturn 0;\n+}\n+\n+void sort_ref_array(struct ref_sort *sort, struct ref_array *array)\n+{\n+\tref_sort = sort;\n+\tqsort(array->items, array->nr, sizeof(struct ref_array_item *), compare_refs);\n+}\n+\n+static void print_value(struct atom_value *v, int quote_style)\n+{\n+\tstruct strbuf sb = STRBUF_INIT;\n+\tswitch (quote_style) {\n+\tcase QUOTE_NONE:\n+\t\tfputs(v->s, stdout);\n+\t\tbreak;\n+\tcase QUOTE_SHELL:\n+\t\tsq_quote_buf(&sb, v->s);\n+\t\tbreak;\n+\tcase QUOTE_PERL:\n+\t\tperl_quote_buf(&sb, v->s);\n+\t\tbreak;\n+\tcase QUOTE_PYTHON:\n+\t\tpython_quote_buf(&sb, v->s);\n+\t\tbreak;\n+\tcase QUOTE_TCL:\n+\t\ttcl_quote_buf(&sb, v->s);\n+\t\tbreak;\n+\t}\n+\tif (quote_style != QUOTE_NONE) {\n+\t\tfputs(sb.buf, stdout);\n+\t\tstrbuf_release(&sb);\n+\t}\n+}\n+\n+static int hex1(char ch)\n+{\n+\tif ('0' <= ch && ch <= '9')\n+\t\treturn ch - '0';\n+\telse if ('a' <= ch && ch <= 'f')\n+\t\treturn ch - 'a' + 10;\n+\telse if ('A' <= ch && ch <= 'F')\n+\t\treturn ch - 'A' + 10;\n+\treturn -1;\n+}\n+static int hex2(const char *cp)\n+{\n+\tif (cp[0] && cp[1])\n+\t\treturn (hex1(cp[0]) << 4) | hex1(cp[1]);\n+\telse\n+\t\treturn -1;\n+}\n+\n+static void emit(const char *cp, const char *ep)\n+{\n+\twhile (*cp && (!ep || cp < ep)) {\n+\t\tif (*cp == '%') {\n+\t\t\tif (cp[1] == '%')\n+\t\t\t\tcp++;\n+\t\t\telse {\n+\t\t\t\tint ch = hex2(cp + 1);\n+\t\t\t\tif (0 <= ch) {\n+\t\t\t\t\tputchar(ch);\n+\t\t\t\t\tcp += 3;\n+\t\t\t\t\tcontinue;\n+\t\t\t\t}\n+\t\t\t}\n+\t\t}\n+\t\tputchar(*cp);\n+\t\tcp++;\n+\t}\n+}\n+\n+void show_ref_array_item(struct ref_array_item *info, const char *format, int quote_style)\n+{\n+\tconst char *cp, *sp, *ep;\n+\n+\tfor (cp = format; *cp && (sp = find_next(cp)); cp = ep + 1) {\n+\t\tstruct atom_value *atomv;\n+\n+\t\tep = strchr(sp, ')');\n+\t\tif (cp < sp)\n+\t\t\temit(cp, sp);\n+\t\tget_ref_atom_value(info, parse_ref_filter_atom(sp + 2, ep), &atomv);\n+\t\tprint_value(atomv, quote_style);\n+\t}\n+\tif (*cp) {\n+\t\tsp = cp + strlen(cp);\n+\t\temit(cp, sp);\n+\t}\n+\tif (need_color_reset_at_eol) {\n+\t\tstruct atom_value resetv;\n+\t\tchar color[COLOR_MAXLEN] = \"\";\n+\n+\t\tif (color_parse(\"reset\", color) < 0)\n+\t\t\tdie(\"BUG: couldn't parse 'reset' as a color\");\n+\t\tresetv.s = color;\n+\t\tprint_value(&resetv, quote_style);\n+\t}\n+\tputchar('\\n');\n+}\n+\n+/*  If no sorting option is given, use refname to sort as default */\n+struct ref_sort *ref_default_sort(void)\n+{\n+\tstatic const char cstr_name[] = \"refname\";\n+\n+\tstruct ref_sort *sort = xcalloc(1, sizeof(*sort));\n+\n+\tsort->next = NULL;\n+\tsort->atom = parse_ref_filter_atom(cstr_name, cstr_name + strlen(cstr_name));\n+\treturn sort;\n+}\n+\n+int opt_parse_ref_sort(const struct option *opt, const char *arg, int unset)\n+{\n+\tstruct ref_sort **sort_tail = opt->value;\n+\tstruct ref_sort *s;\n+\tint len;\n+\n+\tif (!arg) /* should --no-sort void the list ? */\n+\t\treturn -1;\n+\n+\ts = xcalloc(1, sizeof(*s));\n+\ts->next = *sort_tail;\n+\t*sort_tail = s;\n+\n+\tif (*arg == '-') {\n+\t\ts->reverse = 1;\n+\t\targ++;\n+\t}\n+\tlen = strlen(arg);\n+\ts->atom = parse_ref_filter_atom(arg, arg+len);\n+\treturn 0;\n+}\n-- \n2.4.2\n"},{"id":"262482","messageId":"1433008411-8550-8-git-send-email-karthik.188@gmail.com","threadId":"39466","inReplyTo":"5569EF77.4010300@gmail.com","subject":"[WIP/PATCH v4 8/8] ref-filter: add 'ref-filter.h'","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2015-05-30T17:53:31Z","receivedAt":"2015-05-30T17:53:31Z","isPatch":true,"sender":{"key":"karthik.188@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1786334?v=4"},"body":"Create 'ref-filter.h', also add ref-filter to the Makefile.\nThis completes movement of creation of 'ref-filter' from\n'for-each-ref'.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr>\nSigned-off-by: Karthik Nayak <karthik.188@gmail.com>\n---\n Makefile               |  1 +\n builtin/for-each-ref.c | 41 +------------------------------\n ref-filter.c           |  1 +\n ref-filter.h           | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++\n 4 files changed, 69 insertions(+), 40 deletions(-)\n create mode 100644 ref-filter.h\n\ndiff --git a/Makefile b/Makefile\nindex 323c401..ad455a3 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -762,6 +762,7 @@ LIB_OBJS += reachable.o\n LIB_OBJS += read-cache.o\n LIB_OBJS += reflog-walk.o\n LIB_OBJS += refs.o\n+LIB_OBJS += ref-filter.o\n LIB_OBJS += remote.o\n LIB_OBJS += replace_object.o\n LIB_OBJS += rerere.o\ndiff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c\nindex 65ed954..2f11c01 100644\n--- a/builtin/for-each-ref.c\n+++ b/builtin/for-each-ref.c\n@@ -2,46 +2,7 @@\n #include \"cache.h\"\n #include \"refs.h\"\n #include \"parse-options.h\"\n-\n-/* Quoting styles */\n-#define QUOTE_NONE 0\n-#define QUOTE_SHELL 1\n-#define QUOTE_PERL 2\n-#define QUOTE_PYTHON 4\n-#define QUOTE_TCL 8\n-\n-struct atom_value {\n-\tconst char *s;\n-\tunsigned long ul; /* used for sorting when not FIELD_STR */\n-};\n-\n-struct ref_sort {\n-\tstruct ref_sort *next;\n-\tint atom; /* index into used_atom array */\n-\tunsigned reverse : 1;\n-};\n-\n-struct ref_array_item {\n-\tunsigned char objectname[20];\n-\tint flag;\n-\tconst char *symref;\n-\tstruct atom_value *value;\n-\tchar *refname;\n-};\n-\n-struct ref_array {\n-\tint nr, alloc;\n-\tstruct ref_array_item **items;\n-};\n-\n-struct ref_filter {\n-\tconst char **name_patterns;\n-};\n-\n-struct ref_filter_cbdata {\n-\tstruct ref_array array;\n-\tstruct ref_filter filter;\n-};\n+#include \"ref-filter.h\"\n \n static char const * const for_each_ref_usage[] = {\n \tN_(\"git for-each-ref [<options>] [<pattern>]\"),\ndiff --git a/ref-filter.c b/ref-filter.c\nindex 2a8f504..1c73750 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -2,6 +2,7 @@\n #include \"cache.h\"\n #include \"parse-options.h\"\n #include \"refs.h\"\n+#include \"ref-filter.h\"\n #include \"wildmatch.h\"\n #include \"commit.h\"\n #include \"remote.h\"\ndiff --git a/ref-filter.h b/ref-filter.h\nnew file mode 100644\nindex 0000000..dacae59\n--- /dev/null\n+++ b/ref-filter.h\n@@ -0,0 +1,66 @@\n+#ifndef REF_FILTER_H\n+#define REF_FILTER_H\n+\n+#include \"sha1-array.h\"\n+#include \"refs.h\"\n+#include \"commit.h\"\n+#include \"parse-options.h\"\n+\n+/* Quoting styles */\n+#define QUOTE_NONE 0\n+#define QUOTE_SHELL 1\n+#define QUOTE_PERL 2\n+#define QUOTE_PYTHON 4\n+#define QUOTE_TCL 8\n+\n+struct atom_value {\n+\tconst char *s;\n+\tunsigned long ul; /* used for sorting when not FIELD_STR */\n+};\n+\n+struct ref_sort {\n+\tstruct ref_sort *next;\n+\tint atom; /* index into used_atom array */\n+\tunsigned reverse : 1;\n+};\n+\n+struct ref_array_item {\n+\tunsigned char objectname[20];\n+\tint flag;\n+\tconst char *symref;\n+\tstruct atom_value *value;\n+\tchar *refname;\n+};\n+\n+struct ref_array {\n+\tint nr, alloc;\n+\tstruct ref_array_item **items;\n+};\n+\n+struct ref_filter {\n+\tconst char **name_patterns;\n+};\n+\n+struct ref_filter_cbdata {\n+\tstruct ref_array array;\n+\tstruct ref_filter filter;\n+};\n+\n+/*  Callback function for for_each_*ref(). This filters the refs based on the filters set */\n+int ref_filter_handler(const char *refname, const unsigned char *sha1, int flag, void *cb_data);\n+/*  Clear all memory allocated to ref_filter_data */\n+void ref_filter_clear_data(struct ref_filter_cbdata *ref_cbdata);\n+/*  Parse format string and sort specifiers */\n+int parse_ref_filter_atom(const char *atom, const char *ep);\n+/*  Used to verify if the given format is correct and to parse out the used atoms */\n+int verify_ref_format(const char *format);\n+/*  Sort the given ref_array as per the ref_sort provided */\n+void sort_ref_array(struct ref_sort *sort, struct ref_array *array);\n+/*  Print the ref using the given format and quote_style */\n+void show_ref_array_item(struct ref_array_item *info, const char *format, int quote_style);\n+/*  Callback function for parsing the sort option */\n+int opt_parse_ref_sort(const struct option *opt, const char *arg, int unset);\n+/*  Default sort option based on refname */\n+struct ref_sort *ref_default_sort(void);\n+\n+#endif /*  REF_FILTER_H  */\n-- \n2.4.2\n"},{"id":"262492","messageId":"CAPig+cSBaKwRqEEBB62LX0OyYGNddLHNU-zMEx2478kV8=+pDQ@mail.gmail.com","threadId":"39466","inReplyTo":"1433008411-8550-1-git-send-email-karthik.188@gmail.com","subject":"Re: [WIP/PATCH v4 1/8] for-each-ref: extract helper functions out of grab_single_ref()","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2015-05-31T02:58:27Z","receivedAt":"2015-05-31T02:58:27Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Sat, May 30, 2015 at 1:53 PM, Karthik Nayak <karthik.188@gmail.com> wrote:\n> Extract two helper functions out of grab_single_ref(). Firstly,\n> new_refinfo() which is used to allocate memory for a new refinfo\n> structure and copy the objectname, refname and flag to it.\n> Secondly, match_name_as_path() which when given an array of patterns\n> and the refname checks if the refname matches any of the patterns\n> given while the pattern is a pathname, also while supporting wild\n> characters.\n>\n> This is a preperatory patch for restructuring 'for-each-ref' and\n> eventually moving most of it to 'ref-filter' to provide the\n> functionality to similar commands via public API's.\n>\n> Helped-by: Junio C Hamano <gitster@pobox.com>\n> Mentored-by: Christian Couder <christian.couder@gmail.com>\n> Mentored-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr>\n> Signed-off-by: Karthik Nayak <karthik.188@gmail.com>\n> ---\n> diff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c\n> index 83f9cf9..b33e2de 100644\n> --- a/builtin/for-each-ref.c\n> +++ b/builtin/for-each-ref.c\n> @@ -837,6 +837,43 @@ struct grab_ref_cbdata {\n>  };\n>\n>  /*\n> + * Given a refname, return 1 if the refname matches with one of the patterns\n> + * while the pattern is a pathname like 'refs/tags' or 'refs/heads/master'\n> + * and so on, else return 0. Supports use of wild characters.\n> + */\n> +static int match_name_as_path(const char **pattern, const char *refname)\n> +{\n> +       int namelen = strlen(refname);\n> +       for (; *pattern; pattern++) {\n> +               const char *p = *pattern;\n> +               int plen = strlen(p);\n> +\n> +               if ((plen <= namelen) &&\n> +                   !strncmp(refname, p, plen) &&\n> +                   (refname[plen] == '\\0' ||\n> +                    refname[plen] == '/' ||\n> +                    p[plen-1] == '/'))\n> +                       return 1;\n> +               if (!wildmatch(p, refname, WM_PATHNAME, NULL))\n> +                       return 1;\n> +       }\n> +       return 0;\n> +}\n> +\n> +/* Allocate space for a new refinfo and copy the objectname and flag to it */\n> +static struct refinfo *new_refinfo(const char *refname,\n> +                                  const unsigned char *objectname,\n> +                                  int flag)\n> +{\n> +       struct refinfo *ref = xcalloc(1, sizeof(struct refinfo));\n> +       ref->refname = xstrdup(refname);\n> +       hashcpy(ref->objectname, objectname);\n> +       ref->flag = flag;\n> +\n> +       return ref;\n> +}\n> +\n> +/*\n>   * A call-back given to for_each_ref().  Filter refs and keep them for\n>   * later object processing.\n>   */\n> @@ -851,40 +888,16 @@ static int grab_single_ref(const char *refname, const unsigned char *sha1, int f\n>                   return 0;\n>         }\n>\n> -       if (*cb->grab_pattern) {\n> -               const char **pattern;\n> -               int namelen = strlen(refname);\n> -               for (pattern = cb->grab_pattern; *pattern; pattern++) {\n> -                       const char *p = *pattern;\n> -                       int plen = strlen(p);\n> -\n> -                       if ((plen <= namelen) &&\n> -                           !strncmp(refname, p, plen) &&\n> -                           (refname[plen] == '\\0' ||\n> -                            refname[plen] == '/' ||\n> -                            p[plen-1] == '/'))\n> -                               break;\n> -                       if (!wildmatch(p, refname, WM_PATHNAME, NULL))\n> -                               break;\n> -               }\n> -               if (!*pattern)\n> -                       return 0;\n> -       }\n> +       if (*cb->grab_pattern && !match_name_as_path(cb->grab_pattern, refname))\n> +               return 0;\n>\n> -       /*\n> -        * We do not open the object yet; sort may only need refname\n> -        * to do its job and the resulting list may yet to be pruned\n> -        * by maxcount logic.\n> -        */\n\nWhy did this comment get removed? Isn't it still meaningful to the\noverall logic of this function?\n\n> -       ref = xcalloc(1, sizeof(*ref));\n> -       ref->refname = xstrdup(refname);\n> -       hashcpy(ref->objectname, sha1);\n> -       ref->flag = flag;\n> +       ref = new_refinfo(refname, sha1, flag);\n>\n>         cnt = cb->grab_cnt;\n>         REALLOC_ARRAY(cb->grab_array, cnt + 1);\n>         cb->grab_array[cnt++] = ref;\n>         cb->grab_cnt = cnt;\n> +\n\nSneaking in whitespace change?\n\n>         return 0;\n>  }\n"},{"id":"262493","messageId":"CAPig+cSj8Ri=cz9gt_MmMcQQg7iH1beweKfrvEL3MExDY_EiKg@mail.gmail.com","threadId":"39466","inReplyTo":"1433008411-8550-4-git-send-email-karthik.188@gmail.com","subject":"Re: [WIP/PATCH v4 4/8] for-each-ref: introduce new structures for better organisation","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2015-05-31T03:14:39Z","receivedAt":"2015-05-31T03:14:39Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Sat, May 30, 2015 at 1:53 PM, Karthik Nayak <karthik.188@gmail.com> wrote:\n> Intoduce 'ref_filter_cbdata' which will hold 'ref_filter'\n\ns/Intoduce/Introduce/\n\n> (Conditions to filter the refs on) and 'ref_array' (The array\n\ns/Conditions/conditions/\ns/The/the/\n\n> of ref_array_items). Modify the code to use these new structures.\n>\n> This is a preparatory patch to eventually move code from 'for-each-ref'\n> to 'ref-filter' and making it publically available.\n\ns/publically/publicly/\n\n> Mentored-by: Christian Couder <christian.couder@gmail.com>\n> Mentored-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr>\n> Signed-off-by: Karthik Nayak <karthik.188@gmail.com>\n> ---\n> diff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c\n> index e634fd2..ef54c90 100644\n> --- a/builtin/for-each-ref.c\n> +++ b/builtin/for-each-ref.c\n> @@ -85,7 +99,7 @@ static struct {\n>   * a \"*\" to denote deref_tag().\n>   *\n>   * We parse given format string and sort specifiers, and make a list\n> - * of properties that we need to extract out of objects.  ref_array_item\n> + * of properties that we need to extract out of objects. ref_array_item\n\nSneaking in whitespace change?\n\n>   * structure will hold an array of values extracted that can be\n>   * indexed with the \"atom number\", which is an index into this\n>   * array.\n> @@ -1076,12 +1085,12 @@ static char const * const for_each_ref_usage[] = {\n>\n>  int cmd_for_each_ref(int argc, const char **argv, const char *prefix)\n>  {\n> -       int i, num_refs;\n> +       int i;\n>         const char *format = \"%(objectname) %(objecttype)\\t%(refname)\";\n>         struct ref_sort *sort = NULL, **sort_tail = &sort;\n>         int maxcount = 0, quote_style = 0;\n> -       struct ref_array_item **refs;\n> -       struct grab_ref_cbdata cbdata;\n> +       struct ref_filter_cbdata ref_cbdata;\n> +       memset(&ref_cbdata, 0, sizeof(ref_cbdata));\n>\n>         struct option opts[] = {\n\nDeclaration (struct option opts[]) after statement (memset). I think\nyou want to leave the memset() where it was below.\n\n>                 OPT_BIT('s', \"shell\", &quote_style,\n> @@ -1119,17 +1128,14 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix)\n>         /* for warn_ambiguous_refs */\n>         git_config(git_default_config, NULL);\n>\n> -       memset(&cbdata, 0, sizeof(cbdata));\n> -       cbdata.grab_pattern = argv;\n> -       for_each_rawref(grab_single_ref, &cbdata);\n> -       refs = cbdata.grab_array;\n> -       num_refs = cbdata.grab_cnt;\n> +       ref_cbdata.filter.name_patterns = argv;\n> +       for_each_rawref(grab_single_ref, &ref_cbdata);\n>\n> -       sort_refs(sort, refs, num_refs);\n> +       sort_refs(sort, &ref_cbdata.array);\n>\n> -       if (!maxcount || num_refs < maxcount)\n> -               maxcount = num_refs;\n> +       if (!maxcount || ref_cbdata.array.nr < maxcount)\n> +               maxcount = ref_cbdata.array.nr;\n>         for (i = 0; i < maxcount; i++)\n> -               show_ref(refs[i], format, quote_style);\n> +               show_ref(ref_cbdata.array.items[i], format, quote_style);\n>         return 0;\n>  }\n> --\n> 2.4.2\n"},{"id":"262494","messageId":"CAPig+cTyy5ai0O4BAG+3+_6x-8OC5SoUDR=swCq-bNFP3DfxUg@mail.gmail.com","threadId":"39466","inReplyTo":"1433008411-8550-6-git-send-email-karthik.188@gmail.com","subject":"Re: [WIP/PATCH v4 6/8] for-each-ref: rename some functions and make them public","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2015-05-31T03:21:02Z","receivedAt":"2015-05-31T03:21:02Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Sat, May 30, 2015 at 1:53 PM, Karthik Nayak <karthik.188@gmail.com> wrote:\n> Rename some of the functions and make them publically available.\n\ns/publically/publicly/\n\n> This is a preparatory step for moving code from 'for-each-ref'\n> to 'ref-filter' to make meaningful, targeted services available to\n> other commands via public APIs.\n>\n> Based-on-patch-by: Jeff King <peff@peff.net>\n> Mentored-by: Christian Couder <christian.couder@gmail.com>\n> Mentored-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr>\n> Signed-off-by: Karthik Nayak <karthik.188@gmail.com>\n> ---\n> diff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c\n> index f896e1c..8fed04b 100644\n> --- a/builtin/for-each-ref.c\n> +++ b/builtin/for-each-ref.c\n> @@ -882,10 +882,10 @@ static struct ref_array_item *new_ref_array_item(const char *refname,\n>  }\n>\n>  /*\n> - * A call-back given to for_each_ref().  Filter refs and keep them for\n> + * A call-back given to for_each_ref(). Filter refs and keep them for\n\nSneaking in whitespace change?\n\n>   * later object processing.\n>   */\n> -static int grab_single_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data)\n> +int ref_filter_handler(const char *refname, const unsigned char *sha1, int flag, void *cb_data)\n>  {\n>         struct ref_filter_cbdata *ref_cbdata = cb_data;\n>         struct ref_filter *filter = &ref_cbdata->filter;\n"},{"id":"262495","messageId":"CAPig+cR88O=STcJDrB+96uJ0Y60mO49QxoJfbOY8Xk4hPvNxGA@mail.gmail.com","threadId":"39466","inReplyTo":"1433008411-8550-8-git-send-email-karthik.188@gmail.com","subject":"Re: [WIP/PATCH v4 8/8] ref-filter: add 'ref-filter.h'","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2015-05-31T03:43:23Z","receivedAt":"2015-05-31T03:43:23Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Sat, May 30, 2015 at 1:53 PM, Karthik Nayak <karthik.188@gmail.com> wrote:\n> Create 'ref-filter.h', also add ref-filter to the Makefile.\n> This completes movement of creation of 'ref-filter' from\n> 'for-each-ref'.\n\nIt's important that the project can be built successfully and function\ncorrectly at each stage of a patch series. Unfortunately, the way this\nseries is organized, the build breaks after application of patch 7/8\nsince for-each-ref.c is trying to access functionality which was moved\nto ref-filter.c, but there is no header at that stage which advertises\nthe functionality. Fixing this may be as simple as swapping patches\n7/8 and 8/8, along with whatever minor adjustments they might need to\nkeep them sane. (The alternative would be to combine patches 7/8 and\n8/8, however, Matthieu didn't seem to favor that approach[1].)\n\nOverall, this round has been a more pleasant read than previous rounds.\n\n[1]: http://article.gmane.org/gmane.comp.version-control.git/270192\n\n> Mentored-by: Christian Couder <christian.couder@gmail.com>\n> Mentored-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr>\n> Signed-off-by: Karthik Nayak <karthik.188@gmail.com>\n> ---\n>  Makefile               |  1 +\n>  builtin/for-each-ref.c | 41 +------------------------------\n>  ref-filter.c           |  1 +\n>  ref-filter.h           | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++\n>  4 files changed, 69 insertions(+), 40 deletions(-)\n>  create mode 100644 ref-filter.h\n>\n> diff --git a/Makefile b/Makefile\n> index 323c401..ad455a3 100644\n> --- a/Makefile\n> +++ b/Makefile\n> @@ -762,6 +762,7 @@ LIB_OBJS += reachable.o\n>  LIB_OBJS += read-cache.o\n>  LIB_OBJS += reflog-walk.o\n>  LIB_OBJS += refs.o\n> +LIB_OBJS += ref-filter.o\n>  LIB_OBJS += remote.o\n>  LIB_OBJS += replace_object.o\n>  LIB_OBJS += rerere.o\n> diff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c\n> index 65ed954..2f11c01 100644\n> --- a/builtin/for-each-ref.c\n> +++ b/builtin/for-each-ref.c\n> @@ -2,46 +2,7 @@\n>  #include \"cache.h\"\n>  #include \"refs.h\"\n>  #include \"parse-options.h\"\n> -\n> -/* Quoting styles */\n> -#define QUOTE_NONE 0\n> -#define QUOTE_SHELL 1\n> -#define QUOTE_PERL 2\n> -#define QUOTE_PYTHON 4\n> -#define QUOTE_TCL 8\n> -\n> -struct atom_value {\n> -       const char *s;\n> -       unsigned long ul; /* used for sorting when not FIELD_STR */\n> -};\n> -\n> -struct ref_sort {\n> -       struct ref_sort *next;\n> -       int atom; /* index into used_atom array */\n> -       unsigned reverse : 1;\n> -};\n> -\n> -struct ref_array_item {\n> -       unsigned char objectname[20];\n> -       int flag;\n> -       const char *symref;\n> -       struct atom_value *value;\n> -       char *refname;\n> -};\n> -\n> -struct ref_array {\n> -       int nr, alloc;\n> -       struct ref_array_item **items;\n> -};\n> -\n> -struct ref_filter {\n> -       const char **name_patterns;\n> -};\n> -\n> -struct ref_filter_cbdata {\n> -       struct ref_array array;\n> -       struct ref_filter filter;\n> -};\n> +#include \"ref-filter.h\"\n>\n>  static char const * const for_each_ref_usage[] = {\n>         N_(\"git for-each-ref [<options>] [<pattern>]\"),\n> diff --git a/ref-filter.c b/ref-filter.c\n> index 2a8f504..1c73750 100644\n> --- a/ref-filter.c\n> +++ b/ref-filter.c\n> @@ -2,6 +2,7 @@\n>  #include \"cache.h\"\n>  #include \"parse-options.h\"\n>  #include \"refs.h\"\n> +#include \"ref-filter.h\"\n>  #include \"wildmatch.h\"\n>  #include \"commit.h\"\n>  #include \"remote.h\"\n> diff --git a/ref-filter.h b/ref-filter.h\n> new file mode 100644\n> index 0000000..dacae59\n> --- /dev/null\n> +++ b/ref-filter.h\n> @@ -0,0 +1,66 @@\n> +#ifndef REF_FILTER_H\n> +#define REF_FILTER_H\n> +\n> +#include \"sha1-array.h\"\n> +#include \"refs.h\"\n> +#include \"commit.h\"\n> +#include \"parse-options.h\"\n> +\n> +/* Quoting styles */\n> +#define QUOTE_NONE 0\n> +#define QUOTE_SHELL 1\n> +#define QUOTE_PERL 2\n> +#define QUOTE_PYTHON 4\n> +#define QUOTE_TCL 8\n> +\n> +struct atom_value {\n> +       const char *s;\n> +       unsigned long ul; /* used for sorting when not FIELD_STR */\n> +};\n> +\n> +struct ref_sort {\n> +       struct ref_sort *next;\n> +       int atom; /* index into used_atom array */\n> +       unsigned reverse : 1;\n> +};\n> +\n> +struct ref_array_item {\n> +       unsigned char objectname[20];\n> +       int flag;\n> +       const char *symref;\n> +       struct atom_value *value;\n> +       char *refname;\n> +};\n> +\n> +struct ref_array {\n> +       int nr, alloc;\n> +       struct ref_array_item **items;\n> +};\n> +\n> +struct ref_filter {\n> +       const char **name_patterns;\n> +};\n> +\n> +struct ref_filter_cbdata {\n> +       struct ref_array array;\n> +       struct ref_filter filter;\n> +};\n> +\n> +/*  Callback function for for_each_*ref(). This filters the refs based on the filters set */\n> +int ref_filter_handler(const char *refname, const unsigned char *sha1, int flag, void *cb_data);\n> +/*  Clear all memory allocated to ref_filter_data */\n> +void ref_filter_clear_data(struct ref_filter_cbdata *ref_cbdata);\n> +/*  Parse format string and sort specifiers */\n> +int parse_ref_filter_atom(const char *atom, const char *ep);\n> +/*  Used to verify if the given format is correct and to parse out the used atoms */\n> +int verify_ref_format(const char *format);\n> +/*  Sort the given ref_array as per the ref_sort provided */\n> +void sort_ref_array(struct ref_sort *sort, struct ref_array *array);\n> +/*  Print the ref using the given format and quote_style */\n> +void show_ref_array_item(struct ref_array_item *info, const char *format, int quote_style);\n> +/*  Callback function for parsing the sort option */\n> +int opt_parse_ref_sort(const struct option *opt, const char *arg, int unset);\n> +/*  Default sort option based on refname */\n> +struct ref_sort *ref_default_sort(void);\n> +\n> +#endif /*  REF_FILTER_H  */\n> --\n> 2.4.2\n"},{"id":"262496","messageId":"CAP8UFD341nSMLvsXynbDfQ4kLoddBL5rhXrhyePTT0LHACzfuQ@mail.gmail.com","threadId":"39466","inReplyTo":"1433008411-8550-5-git-send-email-karthik.188@gmail.com","subject":"Re: [WIP/PATCH v4 5/8] for-each-ref: introduce 'ref_filter_clear_data()'","fromName":"Christian Couder","fromEmail":"christian.couder@gmail.com","sentAt":"2015-05-31T07:38:30Z","receivedAt":"2015-05-31T07:38:30Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"On Sat, May 30, 2015 at 7:53 PM, Karthik Nayak <karthik.188@gmail.com> wrote:\n> Introduce and implement 'ref_filter_clear_data()' which will free\n> all allocated memory for 'ref_filter_cbdata' and its underlying array\n> of 'ref_array_item'.\n>\n> Mentored-by: Christian Couder <christian.couder@gmail.com>\n> Mentored-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr>\n> Signed-off-by: Karthik Nayak <karthik.188@gmail.com>\n> ---\n>  builtin/for-each-ref.c | 13 +++++++++++++\n>  1 file changed, 13 insertions(+)\n>\n> diff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c\n> index ef54c90..f896e1c 100644\n> --- a/builtin/for-each-ref.c\n> +++ b/builtin/for-each-ref.c\n> @@ -907,6 +907,18 @@ static int grab_single_ref(const char *refname, const unsigned char *sha1, int f\n>         return 0;\n>  }\n>\n> +/* Free all memory allocated for ref_filter_cbdata */\n> +void ref_filter_clear_data(struct ref_filter_cbdata *ref_cbdata)\n> +{\n> +       int i;\n> +\n> +       for (i = 0; i < ref_cbdata->array.nr; i++)\n> +               free(ref_cbdata->array.items[i]);\n> +       free(ref_cbdata->array.items);\n> +       ref_cbdata->array.items = NULL;\n> +       ref_cbdata->array.nr = ref_cbdata->array.alloc = 0;\n> +}\n\nAs this is clearing the array only, it would be better to have it in a\nref_array_clear() function.\nThere are already argv_array_clear() and sha1_array_clear() by the way.\nAnd maybe if many such ref_array functions are created and start being\nused elsewhere we can easily move everything into new ref-array.{c,h}\nfiles.\n\nThanks,\nChristian.\n"},{"id":"262497","messageId":"CAP8UFD080Yuv-CYcDzAG0u6OV7Sqry=0s1HKoJbt5wfKjTNO3Q@mail.gmail.com","threadId":"39466","inReplyTo":"1433008411-8550-6-git-send-email-karthik.188@gmail.com","subject":"Re: [WIP/PATCH v4 6/8] for-each-ref: rename some functions and make them public","fromName":"Christian Couder","fromEmail":"christian.couder@gmail.com","sentAt":"2015-05-31T08:04:32Z","receivedAt":"2015-05-31T08:04:32Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"On Sat, May 30, 2015 at 7:53 PM, Karthik Nayak <karthik.188@gmail.com> wrote:\n>\n> -static void sort_refs(struct ref_sort *sort, struct ref_array *array)\n> +void sort_ref_array(struct ref_sort *sort, struct ref_array *array)\n\nIt is probably better to call the above function ref_array_sort()...\n\n[...]\n\n> -static struct ref_sort *default_sort(void)\n> +/*  If no sorting option is given, use refname to sort as default */\n> +struct ref_sort *ref_default_sort(void)\n\n... especially since you call the above ref_default_sort()...\n\n> -static int opt_parse_sort(const struct option *opt, const char *arg, int unset)\n> +int opt_parse_ref_sort(const struct option *opt, const char *arg, int unset)\n\n... and the above opt_parse_sort().\n"},{"id":"262498","messageId":"556AC22E.90405@gmail.com","threadId":"39466","inReplyTo":"CAPig+cSBaKwRqEEBB62LX0OyYGNddLHNU-zMEx2478kV8=+pDQ@mail.gmail.com","subject":"Re: [WIP/PATCH v4 1/8] for-each-ref: extract helper functions out of grab_single_ref()","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2015-05-31T08:11:26Z","receivedAt":"2015-05-31T08:11:26Z","isPatch":true,"sender":{"key":"karthik.188@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1786334?v=4"},"body":">\n> Why did this comment get removed? Isn't it still meaningful to the\n> overall logic of this function?\n>\n\nWasn't intentional, will put that back.\n\n>\n> Sneaking in whitespace change?\n>\n\nNoted. thanks\n\n\n-- \nRegards,\nKarthik\n"},{"id":"262499","messageId":"CAP8UFD1TTMfruCE-+GT-LzhK5C9LorStPbn64tZ-hhAkC=8Bdw@mail.gmail.com","threadId":"39466","inReplyTo":"CAP8UFD080Yuv-CYcDzAG0u6OV7Sqry=0s1HKoJbt5wfKjTNO3Q@mail.gmail.com","subject":"Re: [WIP/PATCH v4 6/8] for-each-ref: rename some functions and make them public","fromName":"Christian Couder","fromEmail":"christian.couder@gmail.com","sentAt":"2015-05-31T08:11:51Z","receivedAt":"2015-05-31T08:11:51Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"On Sun, May 31, 2015 at 10:04 AM, Christian Couder\n<christian.couder@gmail.com> wrote:\n> On Sat, May 30, 2015 at 7:53 PM, Karthik Nayak <karthik.188@gmail.com> wrote:\n>>\n>> -static void sort_refs(struct ref_sort *sort, struct ref_array *array)\n>> +void sort_ref_array(struct ref_sort *sort, struct ref_array *array)\n>\n> It is probably better to call the above function ref_array_sort()...\n>\n> [...]\n>\n>> -static struct ref_sort *default_sort(void)\n>> +/*  If no sorting option is given, use refname to sort as default */\n>> +struct ref_sort *ref_default_sort(void)\n>\n> ... especially since you call the above ref_default_sort()...\n>\n>> -static int opt_parse_sort(const struct option *opt, const char *arg, int unset)\n>> +int opt_parse_ref_sort(const struct option *opt, const char *arg, int unset)\n>\n> ... and the above opt_parse_sort().\n\nAfter saying that I realize that these two other functions are not\ndoing the same thing.\nThis might suggest that they are not named very well as well.\n"},{"id":"262500","messageId":"556AC345.2070101@gmail.com","threadId":"39466","inReplyTo":"CAPig+cSj8Ri=cz9gt_MmMcQQg7iH1beweKfrvEL3MExDY_EiKg@mail.gmail.com","subject":"Re: [WIP/PATCH v4 4/8] for-each-ref: introduce new structures for better organisation","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2015-05-31T08:16:05Z","receivedAt":"2015-05-31T08:16:05Z","isPatch":true,"sender":{"key":"karthik.188@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1786334?v=4"},"body":"On 05/31/2015 08:44 AM, Eric Sunshine wrote:\n> On Sat, May 30, 2015 at 1:53 PM, Karthik Nayak <karthik.188@gmail.com> wrote:\n>> Intoduce 'ref_filter_cbdata' which will hold 'ref_filter'\n>\n> s/Intoduce/Introduce/\n>\n>> (Conditions to filter the refs on) and 'ref_array' (The array\n>\n> s/Conditions/conditions/\n> s/The/the/\n>\n>> of ref_array_items). Modify the code to use these new structures.\n>>\n>> This is a preparatory patch to eventually move code from 'for-each-ref'\n>> to 'ref-filter' and making it publically available.\n>\n> s/publically/publicly/\n>\n>> Mentored-by: Christian Couder <christian.couder@gmail.com>\n>> Mentored-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr>\n>> Signed-off-by: Karthik Nayak <karthik.188@gmail.com>\n>> ---\n>> diff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c\n>> index e634fd2..ef54c90 100644\n>> --- a/builtin/for-each-ref.c\n>> +++ b/builtin/for-each-ref.c\n>> @@ -85,7 +99,7 @@ static struct {\n>>    * a \"*\" to denote deref_tag().\n>>    *\n>>    * We parse given format string and sort specifiers, and make a list\n>> - * of properties that we need to extract out of objects.  ref_array_item\n>> + * of properties that we need to extract out of objects. ref_array_item\n>\n> Sneaking in whitespace change?\n>\n>>    * structure will hold an array of values extracted that can be\n>>    * indexed with the \"atom number\", which is an index into this\n>>    * array.\n>> @@ -1076,12 +1085,12 @@ static char const * const for_each_ref_usage[] = {\n>>\n>>   int cmd_for_each_ref(int argc, const char **argv, const char *prefix)\n>>   {\n>> -       int i, num_refs;\n>> +       int i;\n>>          const char *format = \"%(objectname) %(objecttype)\\t%(refname)\";\n>>          struct ref_sort *sort = NULL, **sort_tail = &sort;\n>>          int maxcount = 0, quote_style = 0;\n>> -       struct ref_array_item **refs;\n>> -       struct grab_ref_cbdata cbdata;\n>> +       struct ref_filter_cbdata ref_cbdata;\n>> +       memset(&ref_cbdata, 0, sizeof(ref_cbdata));\n>>\n>>          struct option opts[] = {\n>\n> Declaration (struct option opts[]) after statement (memset). I think\n> you want to leave the memset() where it was below.\n>\n>>                  OPT_BIT('s', \"shell\", &quote_style,\n>> @@ -1119,17 +1128,14 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix)\n>>          /* for warn_ambiguous_refs */\n>>          git_config(git_default_config, NULL);\n>>\n>> -       memset(&cbdata, 0, sizeof(cbdata));\n>> -       cbdata.grab_pattern = argv;\n>> -       for_each_rawref(grab_single_ref, &cbdata);\n>> -       refs = cbdata.grab_array;\n>> -       num_refs = cbdata.grab_cnt;\n>> +       ref_cbdata.filter.name_patterns = argv;\n>> +       for_each_rawref(grab_single_ref, &ref_cbdata);\n>>\n>> -       sort_refs(sort, refs, num_refs);\n>> +       sort_refs(sort, &ref_cbdata.array);\n>>\n>> -       if (!maxcount || num_refs < maxcount)\n>> -               maxcount = num_refs;\n>> +       if (!maxcount || ref_cbdata.array.nr < maxcount)\n>> +               maxcount = ref_cbdata.array.nr;\n>>          for (i = 0; i < maxcount; i++)\n>> -               show_ref(refs[i], format, quote_style);\n>> +               show_ref(ref_cbdata.array.items[i], format, quote_style);\n>>          return 0;\n>>   }\n>> --\n>> 2.4.2\n\nWill change these, thanks!\n\n-- \nRegards,\nKarthik\n"},{"id":"262501","messageId":"556AC362.80805@gmail.com","threadId":"39466","inReplyTo":"CAPig+cTyy5ai0O4BAG+3+_6x-8OC5SoUDR=swCq-bNFP3DfxUg@mail.gmail.com","subject":"Re: [WIP/PATCH v4 6/8] for-each-ref: rename some functions and make them public","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2015-05-31T08:16:34Z","receivedAt":"2015-05-31T08:16:34Z","isPatch":true,"sender":{"key":"karthik.188@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1786334?v=4"},"body":"On 05/31/2015 08:51 AM, Eric Sunshine wrote:\n> On Sat, May 30, 2015 at 1:53 PM, Karthik Nayak <karthik.188@gmail.com> wrote:\n>> Rename some of the functions and make them publically available.\n>\n> s/publically/publicly/\n>\n>> This is a preparatory step for moving code from 'for-each-ref'\n>> to 'ref-filter' to make meaningful, targeted services available to\n>> other commands via public APIs.\n>>\n>> Based-on-patch-by: Jeff King <peff@peff.net>\n>> Mentored-by: Christian Couder <christian.couder@gmail.com>\n>> Mentored-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr>\n>> Signed-off-by: Karthik Nayak <karthik.188@gmail.com>\n>> ---\n>> diff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c\n>> index f896e1c..8fed04b 100644\n>> --- a/builtin/for-each-ref.c\n>> +++ b/builtin/for-each-ref.c\n>> @@ -882,10 +882,10 @@ static struct ref_array_item *new_ref_array_item(const char *refname,\n>>   }\n>>\n>>   /*\n>> - * A call-back given to for_each_ref().  Filter refs and keep them for\n>> + * A call-back given to for_each_ref(). Filter refs and keep them for\n>\n> Sneaking in whitespace change?\n>\n>>    * later object processing.\n>>    */\n>> -static int grab_single_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data)\n>> +int ref_filter_handler(const char *refname, const unsigned char *sha1, int flag, void *cb_data)\n>>   {\n>>          struct ref_filter_cbdata *ref_cbdata = cb_data;\n>>          struct ref_filter *filter = &ref_cbdata->filter;\n\n\nNoted. Will fix!\n\n-- \nRegards,\nKarthik\n"},{"id":"262503","messageId":"556AC40C.5020205@gmail.com","threadId":"39466","inReplyTo":"CAPig+cR88O=STcJDrB+96uJ0Y60mO49QxoJfbOY8Xk4hPvNxGA@mail.gmail.com","subject":"Re: [WIP/PATCH v4 8/8] ref-filter: add 'ref-filter.h'","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2015-05-31T08:19:24Z","receivedAt":"2015-05-31T08:19:24Z","isPatch":true,"sender":{"key":"karthik.188@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1786334?v=4"},"body":"On 05/31/2015 09:13 AM, Eric Sunshine wrote:\n> On Sat, May 30, 2015 at 1:53 PM, Karthik Nayak <karthik.188@gmail.com> wrote:\n>> Create 'ref-filter.h', also add ref-filter to the Makefile.\n>> This completes movement of creation of 'ref-filter' from\n>> 'for-each-ref'.\n>\n> It's important that the project can be built successfully and function\n> correctly at each stage of a patch series. Unfortunately, the way this\n> series is organized, the build breaks after application of patch 7/8\n> since for-each-ref.c is trying to access functionality which was moved\n> to ref-filter.c, but there is no header at that stage which advertises\n> the functionality. Fixing this may be as simple as swapping patches\n> 7/8 and 8/8, along with whatever minor adjustments they might need to\n> keep them sane. (The alternative would be to combine patches 7/8 and\n> 8/8, however, Matthieu didn't seem to favor that approach[1].)\n>\n> Overall, this round has been a more pleasant read than previous rounds.\n>\n> [1]: http://article.gmane.org/gmane.comp.version-control.git/270192\n>\n\nThat is kind of a problem, If I need to swap those commits also, I'd \nhave to add the part where ref-filter is added to the Makefile with the \ncode movement from for-each-ref to ref-filter. This again will not just \nbe Code movement.\n\nBut I guess thats a fair trade-off, will change it. Thanks\n\n-- \nRegards,\nKarthik\n"},{"id":"262504","messageId":"556AC44B.8070709@gmail.com","threadId":"39466","inReplyTo":"CAP8UFD341nSMLvsXynbDfQ4kLoddBL5rhXrhyePTT0LHACzfuQ@mail.gmail.com","subject":"Re: [WIP/PATCH v4 5/8] for-each-ref: introduce 'ref_filter_clear_data()'","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2015-05-31T08:20:27Z","receivedAt":"2015-05-31T08:20:27Z","isPatch":true,"sender":{"key":"karthik.188@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1786334?v=4"},"body":">\n> As this is clearing the array only, it would be better to have it in a\n> ref_array_clear() function.\n> There are already argv_array_clear() and sha1_array_clear() by the way.\n> And maybe if many such ref_array functions are created and start being\n> used elsewhere we can easily move everything into new ref-array.{c,h}\n> files.\n>\n\nMakes sense. Will change.\n-- \nRegards,\nKarthik\n"},{"id":"262505","messageId":"CAP8UFD0hpUo5iooforU82c2BcFDYSbt7Gqn49qFW+LiwcVQJ_g@mail.gmail.com","threadId":"39466","inReplyTo":"1433008411-8550-8-git-send-email-karthik.188@gmail.com","subject":"Re: [WIP/PATCH v4 8/8] ref-filter: add 'ref-filter.h'","fromName":"Christian Couder","fromEmail":"christian.couder@gmail.com","sentAt":"2015-05-31T08:20:53Z","receivedAt":"2015-05-31T08:20:53Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"On Sat, May 30, 2015 at 7:53 PM, Karthik Nayak <karthik.188@gmail.com> wrote:\n>\n> -struct ref_sort {\n> -       struct ref_sort *next;\n> -       int atom; /* index into used_atom array */\n\nWhere is this used_atom array?\nI searched but couldn't find it in the same file.\n\n> -       unsigned reverse : 1;\n> -};\n"},{"id":"262506","messageId":"CAPig+cRF7VEqqBWJY_GRVL+8YCfrD-mYJ2idN1yzVE7JKeTpwA@mail.gmail.com","threadId":"39466","inReplyTo":"556AC40C.5020205@gmail.com","subject":"Re: [WIP/PATCH v4 8/8] ref-filter: add 'ref-filter.h'","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2015-05-31T08:29:36Z","receivedAt":"2015-05-31T08:29:36Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Sun, May 31, 2015 at 4:19 AM, Karthik Nayak <karthik.188@gmail.com> wrote:\n> On 05/31/2015 09:13 AM, Eric Sunshine wrote:\n>> On Sat, May 30, 2015 at 1:53 PM, Karthik Nayak <karthik.188@gmail.com>\n>> wrote:\n>>>\n>>> Create 'ref-filter.h', also add ref-filter to the Makefile.\n>>> This completes movement of creation of 'ref-filter' from\n>>> 'for-each-ref'.\n>>\n>> It's important that the project can be built successfully and function\n>> correctly at each stage of a patch series. Unfortunately, the way this\n>> series is organized, the build breaks after application of patch 7/8\n>> since for-each-ref.c is trying to access functionality which was moved\n>> to ref-filter.c, but there is no header at that stage which advertises\n>> the functionality. Fixing this may be as simple as swapping patches\n>> 7/8 and 8/8, along with whatever minor adjustments they might need to\n>> keep them sane. (The alternative would be to combine patches 7/8 and\n>> 8/8, however, Matthieu didn't seem to favor that approach[1].)\n>\n> That is kind of a problem, If I need to swap those commits also, I'd have to\n> add the part where ref-filter is added to the Makefile with the code\n> movement from for-each-ref to ref-filter. This again will not just be Code\n> movement.\n> But I guess thats a fair trade-off, will change it. Thanks\n\nDon't take the \"code movement-only\" recommendation too literally. What\npeople mean is that you shouldn't make changes to the lines you're\nmoving from one location to another (other than absolutely mandatory\nchanges to support the movement) since it's difficult to spot and\nreview changes in lines which are being moved.\n\nThe recommendation is not saying that the patch itself can't include\nany other changes (though, it's often best to minimize other changes\nin the same patch). In this case, the Makefile change is logically\nrelated to that particular code movement, so it's correct to include\nit in the patch. (Also, the Makefile change is so minor that it's not\na burden upon reviewers.)\n"},{"id":"262507","messageId":"556AD085.7080104@gmail.com","threadId":"39466","inReplyTo":"CAPig+cRF7VEqqBWJY_GRVL+8YCfrD-mYJ2idN1yzVE7JKeTpwA@mail.gmail.com","subject":"Re: [WIP/PATCH v4 8/8] ref-filter: add 'ref-filter.h'","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2015-05-31T09:12:37Z","receivedAt":"2015-05-31T09:12:37Z","isPatch":true,"sender":{"key":"karthik.188@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1786334?v=4"},"body":"On 05/31/2015 01:59 PM, Eric Sunshine wrote:\n> On Sun, May 31, 2015 at 4:19 AM, Karthik Nayak <karthik.188@gmail.com> wrote:\n> > On 05/31/2015 09:13 AM, Eric Sunshine wrote:\n> >> On Sat, May 30, 2015 at 1:53 PM, Karthik Nayak <karthik.188@gmail.com>\n> >> wrote:\n> >>>\n> >>> Create 'ref-filter.h', also add ref-filter to the Makefile.\n> >>> This completes movement of creation of 'ref-filter' from\n> >>> 'for-each-ref'.\n> >>\n> >> It's important that the project can be built successfully and function\n> >> correctly at each stage of a patch series. Unfortunately, the way this\n> >> series is organized, the build breaks after application of patch 7/8\n> >> since for-each-ref.c is trying to access functionality which was moved\n> >> to ref-filter.c, but there is no header at that stage which advertises\n> >> the functionality. Fixing this may be as simple as swapping patches\n> >> 7/8 and 8/8, along with whatever minor adjustments they might need to\n> >> keep them sane. (The alternative would be to combine patches 7/8 and\n> >> 8/8, however, Matthieu didn't seem to favor that approach[1].)\n> >\n> > That is kind of a problem, If I need to swap those commits also, I'd have to\n> > add the part where ref-filter is added to the Makefile with the code\n> > movement from for-each-ref to ref-filter. This again will not just be Code\n> > movement.\n> > But I guess thats a fair trade-off, will change it. Thanks\n>\n> Don't take the \"code movement-only\" recommendation too literally. What\n> people mean is that you shouldn't make changes to the lines you're\n> moving from one location to another (other than absolutely mandatory\n> changes to support the movement) since it's difficult to spot and\n> review changes in lines which are being moved.\n>\n> The recommendation is not saying that the patch itself can't include\n> any other changes (though, it's often best to minimize other changes\n> in the same patch). In this case, the Makefile change is logically\n> related to that particular code movement, so it's correct to include\n> it in the patch. (Also, the Makefile change is so minor that it's not\n> a burden upon reviewers.)\n>\nThanks for clearing it up.\n\n-- \nRegards,\nKarthik\n"},{"id":"262508","messageId":"556AD155.8010108@gmail.com","threadId":"39466","inReplyTo":"CAP8UFD0hpUo5iooforU82c2BcFDYSbt7Gqn49qFW+LiwcVQJ_g@mail.gmail.com","subject":"Re: [WIP/PATCH v4 8/8] ref-filter: add 'ref-filter.h'","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2015-05-31T09:16:05Z","receivedAt":"2015-05-31T09:16:05Z","isPatch":true,"sender":{"key":"karthik.188@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1786334?v=4"},"body":"On 05/31/2015 01:50 PM, Christian Couder wrote:\n> On Sat, May 30, 2015 at 7:53 PM, Karthik Nayak <karthik.188@gmail.com> wrote:\n>>\n>> -struct ref_sort {\n>> -       struct ref_sort *next;\n>> -       int atom; /* index into used_atom array */\n>\n> Where is this used_atom array?\n> I searched but couldn't find it in the same file.\n>\n>> -       unsigned reverse : 1;\n>> -};\n\n\nIt has been carried over since 9f613ddd, after which used_atom was \nremoved, I will remove that comment, just causes confusion\n\n-- \nRegards,\nKarthik\n"},{"id":"262509","messageId":"556AD1B2.3080502@gmail.com","threadId":"39466","inReplyTo":"CAP8UFD1TTMfruCE-+GT-LzhK5C9LorStPbn64tZ-hhAkC=8Bdw@mail.gmail.com","subject":"Re: [WIP/PATCH v4 6/8] for-each-ref: rename some functions and make them public","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2015-05-31T09:17:38Z","receivedAt":"2015-05-31T09:17:38Z","isPatch":true,"sender":{"key":"karthik.188@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1786334?v=4"},"body":"On 05/31/2015 01:41 PM, Christian Couder wrote:\n> On Sun, May 31, 2015 at 10:04 AM, Christian Couder\n> <christian.couder@gmail.com> wrote:\n>> On Sat, May 30, 2015 at 7:53 PM, Karthik Nayak <karthik.188@gmail.com> wrote:\n>>>\n>>> -static void sort_refs(struct ref_sort *sort, struct ref_array *array)\n>>> +void sort_ref_array(struct ref_sort *sort, struct ref_array *array)\n>>\n>> It is probably better to call the above function ref_array_sort()...\n>>\n>> [...]\n>>\n>>> -static struct ref_sort *default_sort(void)\n>>> +/*  If no sorting option is given, use refname to sort as default */\n>>> +struct ref_sort *ref_default_sort(void)\n>>\n>> ... especially since you call the above ref_default_sort()...\n>>\n>>> -static int opt_parse_sort(const struct option *opt, const char *arg, int unset)\n>>> +int opt_parse_ref_sort(const struct option *opt, const char *arg, int unset)\n>>\n>> ... and the above opt_parse_sort().\n>\n> After saying that I realize that these two other functions are not\n> doing the same thing.\n> This might suggest that they are not named very well as well.\n>\n\nWhat do you mean by \"not doing the same thing.\"\n\n-- \nRegards,\nKarthik\n"},{"id":"262512","messageId":"CAP8UFD117bJotFQSGjGnSub_0Xq=3wH2o3Du4c49xvmMxAyFDQ@mail.gmail.com","threadId":"39466","inReplyTo":"556AD1B2.3080502@gmail.com","subject":"Re: [WIP/PATCH v4 6/8] for-each-ref: rename some functions and make them public","fromName":"Christian Couder","fromEmail":"christian.couder@gmail.com","sentAt":"2015-05-31T14:03:11Z","receivedAt":"2015-05-31T14:03:11Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"On Sun, May 31, 2015 at 11:17 AM, Karthik Nayak <karthik.188@gmail.com> wrote:\n> On 05/31/2015 01:41 PM, Christian Couder wrote:\n>>\n>> On Sun, May 31, 2015 at 10:04 AM, Christian Couder\n>> <christian.couder@gmail.com> wrote:\n>>>\n>>> On Sat, May 30, 2015 at 7:53 PM, Karthik Nayak <karthik.188@gmail.com>\n>>> wrote:\n>>>>\n>>>>\n>>>> -static void sort_refs(struct ref_sort *sort, struct ref_array *array)\n>>>> +void sort_ref_array(struct ref_sort *sort, struct ref_array *array)\n>>>\n>>>\n>>> It is probably better to call the above function ref_array_sort()...\n>>>\n>>> [...]\n>>>\n>>>> -static struct ref_sort *default_sort(void)\n>>>> +/*  If no sorting option is given, use refname to sort as default */\n>>>> +struct ref_sort *ref_default_sort(void)\n>>>\n>>>\n>>> ... especially since you call the above ref_default_sort()...\n>>>\n>>>> -static int opt_parse_sort(const struct option *opt, const char *arg,\n>>>> int unset)\n>>>> +int opt_parse_ref_sort(const struct option *opt, const char *arg, int\n>>>> unset)\n>>>\n>>>\n>>> ... and the above opt_parse_sort().\n>>\n>>\n>> After saying that I realize that these two other functions are not\n>> doing the same thing.\n>> This might suggest that they are not named very well as well.\n>>\n>\n> What do you mean by \"not doing the same thing.\"\n\nsort_ref_array() is actually sorting a ref_array, while\nref_default_sort() and opt_parse_ref_sort() are not sorting anything.\n\nMaybe it would all be clearer with a renaming like the following:\n\nsort_refs() -> ref_array_sort()\nstruct ref_sort -> struct ref_sort_criteria\ndefault_sort() -> ref_default_sort_criteria()\nopt_parse_sort() -> opt_parse_ref_sort_criteria()\n"},{"id":"262513","messageId":"556B2921.2000407@gmail.com","threadId":"39466","inReplyTo":"CAP8UFD117bJotFQSGjGnSub_0Xq=3wH2o3Du4c49xvmMxAyFDQ@mail.gmail.com","subject":"Re: [WIP/PATCH v4 6/8] for-each-ref: rename some functions and make them public","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2015-05-31T15:30:41Z","receivedAt":"2015-05-31T15:30:41Z","isPatch":true,"sender":{"key":"karthik.188@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1786334?v=4"},"body":"On 05/31/2015 07:33 PM, Christian Couder wrote:\n> On Sun, May 31, 2015 at 11:17 AM, Karthik Nayak <karthik.188@gmail.com> wrote:\n> > On 05/31/2015 01:41 PM, Christian Couder wrote:\n> >>\n> >> On Sun, May 31, 2015 at 10:04 AM, Christian Couder\n> >> <christian.couder@gmail.com> wrote:\n> >>>\n> >>> On Sat, May 30, 2015 at 7:53 PM, Karthik Nayak <karthik.188@gmail.com>\n> >>> wrote:\n> >>>>\n> >>>>\n> >>>> -static void sort_refs(struct ref_sort *sort, struct ref_array *array)\n> >>>> +void sort_ref_array(struct ref_sort *sort, struct ref_array *array)\n> >>>\n> >>>\n> >>> It is probably better to call the above function ref_array_sort()...\n> >>>\n> >>> [...]\n> >>>\n> >>>> -static struct ref_sort *default_sort(void)\n> >>>> +/*  If no sorting option is given, use refname to sort as default */\n> >>>> +struct ref_sort *ref_default_sort(void)\n> >>>\n> >>>\n> >>> ... especially since you call the above ref_default_sort()...\n> >>>\n> >>>> -static int opt_parse_sort(const struct option *opt, const char *arg,\n> >>>> int unset)\n> >>>> +int opt_parse_ref_sort(const struct option *opt, const char *arg, int\n> >>>> unset)\n> >>>\n> >>>\n> >>> ... and the above opt_parse_sort().\n> >>\n> >>\n> >> After saying that I realize that these two other functions are not\n> >> doing the same thing.\n> >> This might suggest that they are not named very well as well.\n> >>\n> >\n> > What do you mean by \"not doing the same thing.\"\n>\n> sort_ref_array() is actually sorting a ref_array, while\n> ref_default_sort() and opt_parse_ref_sort() are not sorting anything.\n>\n> Maybe it would all be clearer with a renaming like the following:\n>\n> sort_refs() -> ref_array_sort()\n> struct ref_sort -> struct ref_sort_criteria\n> default_sort() -> ref_default_sort_criteria()\n> opt_parse_sort() -> opt_parse_ref_sort_criteria()\n>\nThanks will follow this, but will change opt_parse_ref_sort_criteria() to\nparse_opt_ref_sort_criteria() as this is what is commonly followed.\n-- \nRegards,\nKarthik\n"},{"id":"262515","messageId":"xmqqvbf8abwi.fsf@gitster.dls.corp.google.com","threadId":"39466","inReplyTo":"1433008411-8550-1-git-send-email-karthik.188@gmail.com","subject":"Re: [WIP/PATCH v4 1/8] for-each-ref: extract helper functions out of grab_single_ref()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-05-31T17:34:53Z","receivedAt":"2015-05-31T17:34:53Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Karthik Nayak <karthik.188@gmail.com> writes:\n\n>  /*\n> + * Given a refname, return 1 if the refname matches with one of the patterns\n> + * while the pattern is a pathname like 'refs/tags' or 'refs/heads/master'\n> + * and so on, else return 0. Supports use of wild characters.\n> + */\n> +static int match_name_as_path(const char **pattern, const char *refname)\n> +{\n\nI wonder why this is not \"match_refname\", in other words, what the\nsignificance of \"as path\" part of the name?  If you later are going\nto introuce match_name_as_something_else() and that name may not be\na refname, then this naming is perfectly sane.  If such a function\nyou will later introduce will still deal with names that are only\nrefnames, then match_refname_as_path() would be sensible.  Otherwise\nthis name seems overly long (i.e. \"as_path\" may not be adding value)\nwhile not being desctiptive enough (i.e. is meant to be limited to\nrefnames but just says \"name\").\n\nJust being curious.\n\n> @@ -851,40 +888,16 @@ static int grab_single_ref(const char *refname, const unsigned char *sha1, int f\n>  \t\t  return 0;\n>  \t}\n>  \n> -\tif (*cb->grab_pattern) {\n> -...\n> -\t}\n> +\tif (*cb->grab_pattern && !match_name_as_path(cb->grab_pattern, refname))\n> +\t\treturn 0;\n>  \n> -\t/*\n> -\t * We do not open the object yet; sort may only need refname\n> -\t * to do its job and the resulting list may yet to be pruned\n> -\t * by maxcount logic.\n> -\t */\n> -\tref = xcalloc(1, sizeof(*ref));\n\nThe comment still is a good reminder for those who will later touch\nthis grab_single_ref() function to make them think twice.\n\nThanks.\n"},{"id":"262516","messageId":"xmqqr3pwabsb.fsf@gitster.dls.corp.google.com","threadId":"39466","inReplyTo":"1433008411-8550-3-git-send-email-karthik.188@gmail.com","subject":"Re: [WIP/PATCH v4 3/8] for-each-ref: rename 'refinfo' to 'ref_array_item'","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-05-31T17:37:24Z","receivedAt":"2015-05-31T17:37:24Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Karthik Nayak <karthik.188@gmail.com> writes:\n\n> Rename 'refinfo' to 'ref_array_item' as a preparatory step for introduction of new structures in the forthcoming patch.\n>\n> Re-order the fields in 'ref_array_item' so that refname can be\n> eventually converted to a FLEX_ARRAY.\n\nNot a big enough deal to require a reroll, but I think it would be\neasier to read if this reordering is done in the same patch that\nmakes refname[] into a flex array.\n"},{"id":"262517","messageId":"556B4954.6040903@gmail.com","threadId":"39466","inReplyTo":"xmqqvbf8abwi.fsf@gitster.dls.corp.google.com","subject":"Re: [WIP/PATCH v4 1/8] for-each-ref: extract helper functions out of grab_single_ref()","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2015-05-31T17:48:04Z","receivedAt":"2015-05-31T17:48:04Z","isPatch":true,"sender":{"key":"karthik.188@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1786334?v=4"},"body":"On 05/31/2015 11:04 PM, Junio C Hamano wrote:\n> Karthik Nayak <karthik.188@gmail.com> writes:\n>\n>>   /*\n>> + * Given a refname, return 1 if the refname matches with one of the patterns\n>> + * while the pattern is a pathname like 'refs/tags' or 'refs/heads/master'\n>> + * and so on, else return 0. Supports use of wild characters.\n>> + */\n>> +static int match_name_as_path(const char **pattern, const char *refname)\n>> +{\n>\n> I wonder why this is not \"match_refname\", in other words, what the\n> significance of \"as path\" part of the name?  If you later are going\n> to introuce match_name_as_something_else() and that name may not be\n> a refname, then this naming is perfectly sane.  If such a function\n> you will later introduce will still deal with names that are only\n> refnames, then match_refname_as_path() would be sensible.  Otherwise\n> this name seems overly long (i.e. \"as_path\" may not be adding value)\n> while not being desctiptive enough (i.e. is meant to be limited to\n> refnames but just says \"name\").\n>\n> Just being curious.\n>\n\nGood Question, This is because in the future I'll eventually add pattern\nmatching for 'tag -l' and 'branch -l' which wont match as path, but\nwould be a regular string match (with wild character support). Hence\nkeeping that in mind I included 'as_path()' in the function name.\n\n>\n> The comment still is a good reminder for those who will later touch\n> this grab_single_ref() function to make them think twice.\n>\n> Thanks.\n>\n\nYes! It was removed it by mistake.\n\n-- \nRegards,\nKarthik\n"},{"id":"262518","messageId":"556B497E.3010105@gmail.com","threadId":"39466","inReplyTo":"xmqqr3pwabsb.fsf@gitster.dls.corp.google.com","subject":"Re: [WIP/PATCH v4 3/8] for-each-ref: rename 'refinfo' to 'ref_array_item'","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2015-05-31T17:48:46Z","receivedAt":"2015-05-31T17:48:46Z","isPatch":true,"sender":{"key":"karthik.188@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1786334?v=4"},"body":"On 05/31/2015 11:07 PM, Junio C Hamano wrote:\n> Karthik Nayak <karthik.188@gmail.com> writes:\n>\n>> Rename 'refinfo' to 'ref_array_item' as a preparatory step for introduction of new structures in the forthcoming patch.\n>>\n>> Re-order the fields in 'ref_array_item' so that refname can be\n>> eventually converted to a FLEX_ARRAY.\n>\n> Not a big enough deal to require a reroll, but I think it would be\n> easier to read if this reordering is done in the same patch that\n> makes refname[] into a flex array.\n>\n\nYes I was thinking the same, I'll add that in the re-roll.\n\n-- \nRegards,\nKarthik\n"},{"id":"262519","messageId":"xmqqmw0kab94.fsf@gitster.dls.corp.google.com","threadId":"39466","inReplyTo":"1433008411-8550-6-git-send-email-karthik.188@gmail.com","subject":"Re: [WIP/PATCH v4 6/8] for-each-ref: rename some functions and make them public","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-05-31T17:48:55Z","receivedAt":"2015-05-31T17:48:55Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Karthik Nayak <karthik.188@gmail.com> writes:\n\n>  /*\n> - * A call-back given to for_each_ref().  Filter refs and keep them for\n> + * A call-back given to for_each_ref(). Filter refs and keep them for\n>   * later object processing.\n>   */\n> -static int grab_single_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data)\n> +int ref_filter_handler(const char *refname, const unsigned char *sha1, int flag, void *cb_data)\n>  {\n\nI am not sure if this is a good external interface, i.e. to expect\ncallers of ref-filter API to do this:\n\n\tprepare cbdata;\n\tfor_each_ref(ref_filter_handler, &cbdata);\n\nIt might be better to expect callers to do this instead:\n\n\tprepare cbdata;\n        filter_refs(for_each_ref, &cbdata);\n\ni.e. introducing a new \"filter_refs()\" function as the entry point\nto the ref-filter API.  The filter_refs() entry point may internally\nuse ref_filter_handler() that will be file-scope static to ref-filter.c\nand at that point the overly generic \"-handler\" name would not bother\nanybody ;-) but more importantly, then you can extend the function\nsignature of filter_refs() not to be so tied to for_each_ref() API.\nIt could be that the internals of cbdata may not be something the\ncallers of filter-refs API does not even have to know about, in\nwhich case the call might even become something like:\n\n\tstruct ref_array refs = REF_ARRAY_INIT;\n        const char **ref_patterns = { \"refs/heads/*\", \"refs/tags/*\", NULL};\n\n\tfilter_refs(&refs, for_each_rawref, ref_patterns);\n\n        /* now \"refs\" has the result, the caller uses them */\n\tfor (i = 0; i < refs.nr; i++)\n        \trefs.item[i];\n\nJust a thought.\n"},{"id":"262520","messageId":"xmqqiob8aazn.fsf@gitster.dls.corp.google.com","threadId":"39466","inReplyTo":"CAP8UFD080Yuv-CYcDzAG0u6OV7Sqry=0s1HKoJbt5wfKjTNO3Q@mail.gmail.com","subject":"Re: [WIP/PATCH v4 6/8] for-each-ref: rename some functions and make them public","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-05-31T17:54:36Z","receivedAt":"2015-05-31T17:54:36Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Christian Couder <christian.couder@gmail.com> writes:\n\n> On Sat, May 30, 2015 at 7:53 PM, Karthik Nayak <karthik.188@gmail.com> wrote:\n>>\n>> -static void sort_refs(struct ref_sort *sort, struct ref_array *array)\n>> +void sort_ref_array(struct ref_sort *sort, struct ref_array *array)\n>\n> It is probably better to call the above function ref_array_sort()...\n\nCare to explain the reasoning behind that suggestion?  The function\n\"sorts\" \"ref_array\", so verb-object sounds like a valid construction\nof a name.  All the functions externalized by the patch under\ndiscussion follows that pattern, I think (e.g. parse-ref-filter-atom,\nverify-ref-format, show-ref-array-item).\n\nMaking the API function share a common prefix is another valid\nschool of design; while that may justify ref-array-sort(), but if\nyou are going in that direction, all the others need to be renamed\nalong that line consistently, I would think.\n"},{"id":"262529","messageId":"556B6234.2010809@gmail.com","threadId":"39466","inReplyTo":"xmqqmw0kab94.fsf@gitster.dls.corp.google.com","subject":"Re: [WIP/PATCH v4 6/8] for-each-ref: rename some functions and make them public","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2015-05-31T19:34:12Z","receivedAt":"2015-05-31T19:34:12Z","isPatch":true,"sender":{"key":"karthik.188@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1786334?v=4"},"body":"On 05/31/2015 11:18 PM, Junio C Hamano wrote:\n> Karthik Nayak <karthik.188@gmail.com> writes:\n>\n>>   /*\n>> - * A call-back given to for_each_ref().  Filter refs and keep them for\n>> + * A call-back given to for_each_ref(). Filter refs and keep them for\n>>    * later object processing.\n>>    */\n>> -static int grab_single_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data)\n>> +int ref_filter_handler(const char *refname, const unsigned char *sha1, int flag, void *cb_data)\n>>   {\n>\n> I am not sure if this is a good external interface, i.e. to expect\n> callers of ref-filter API to do this:\n>\n> \tprepare cbdata;\n> \tfor_each_ref(ref_filter_handler, &cbdata);\n>\n> It might be better to expect callers to do this instead:\n>\n> \tprepare cbdata;\n>          filter_refs(for_each_ref, &cbdata);\n>\n> i.e. introducing a new \"filter_refs()\" function as the entry point\n> to the ref-filter API.  The filter_refs() entry point may internally\n> use ref_filter_handler() that will be file-scope static to ref-filter.c\n> and at that point the overly generic \"-handler\" name would not bother\n> anybody ;-) but more importantly, then you can extend the function\n> signature of filter_refs() not to be so tied to for_each_ref() API.\n> It could be that the internals of cbdata may not be something the\n> callers of filter-refs API does not even have to know about, in\n> which case the call might even become something like:\n>\n> \tstruct ref_array refs = REF_ARRAY_INIT;\n>          const char **ref_patterns = { \"refs/heads/*\", \"refs/tags/*\", NULL};\n>\n> \tfilter_refs(&refs, for_each_rawref, ref_patterns);\n>\n>          /* now \"refs\" has the result, the caller uses them */\n> \tfor (i = 0; i < refs.nr; i++)\n>          \trefs.item[i];\n>\n> Just a thought.\n>\n\nThats brilliant, How about I introduce something of this sort\n\nint filter_refs(int (*for_each_ref_fn)(each_ref_fn, void *), \nref_filter_cbdata *cbdata)\n{\n\treturn for_each_ref_fn(ref_filter_handler, cbdata);\n}\n\nwhere its the most basic form, and things like\n\n >\n > \tstruct ref_array refs = REF_ARRAY_INIT;\n >          const char **ref_patterns = { \"refs/heads/*\", \"refs/tags/*\", \nNULL};\n >\n > \tfilter_refs(&refs, for_each_rawref, ref_patterns);\n >\n >          /* now \"refs\" has the result, the caller uses them */\n > \tfor (i = 0; i < refs.nr; i++)\n >          \trefs.item[i];\n >\n\nCould be achieved using a simple wrapper around 'filter_refs()' \nsomething like this perhaps.\n\nint filter_refs_with_pattern(struct ref_array *ref, int \n(*for_each_ref_fn)(each_ref_fn, void *), char **patterns)\n{\n\tint i;\n\tstruct ref_filter_cbdata data;\n\tdata.filter.name_patterns = patterns;\n\tfilter_refs(for_each_ref_fn, &data);\n\trefs->nr = data.array.nr;\n\tfor(i = 0; i < refs->nr; i++) {\n\t\t/* copy over the refs */\n\t}\n\treturn 0;\n}\n\nIs this on the lines of what you had in mind? If it is, than I could \njust create a new patch which would make ref_filter_handler() private \nand introduce filter_refs() as shown.\n\n-- \nRegards,\nKarthik\n"},{"id":"262531","messageId":"vpqvbf8jxbr.fsf@anie.imag.fr","threadId":"39466","inReplyTo":"xmqqvbf8abwi.fsf@gitster.dls.corp.google.com","subject":"Re: [WIP/PATCH v4 1/8] for-each-ref: extract helper functions out of grab_single_ref()","fromName":"Matthieu Moy","fromEmail":"matthieu.moy@grenoble-inp.fr","sentAt":"2015-05-31T20:39:36Z","receivedAt":"2015-05-31T20:39:36Z","isPatch":true,"sender":{"key":"matthieu.moy@grenoble-inp.fr","avatar":"https://gravatar.com/avatar/72c8a2705971a25dfaff23cece15130d405685845d911aedd5667ace277f3fc5?d=mp&s=160"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> Karthik Nayak <karthik.188@gmail.com> writes:\n>\n>>  /*\n>> + * Given a refname, return 1 if the refname matches with one of the patterns\n>> + * while the pattern is a pathname like 'refs/tags' or 'refs/heads/master'\n>> + * and so on, else return 0. Supports use of wild characters.\n>> + */\n>> +static int match_name_as_path(const char **pattern, const char *refname)\n>> +{\n>\n> I wonder why this is not \"match_refname\", in other words, what the\n> significance of \"as path\" part of the name?\n\nJust match_refname may not carry all the semantics of the function,\nwhich matches a prefix up to the end of string, or up to a / (but you\ncan't just be a prefix stopping in the middle of a word). To me, the\n\"_as_path\" helped understanding the overall behavior of the function.\n\n-- \nMatthieu Moy\nhttp://www-verimag.imag.fr/~moy/\n"},{"id":"262534","messageId":"vpqlhg4jx0d.fsf@anie.imag.fr","threadId":"39466","inReplyTo":"556AC40C.5020205@gmail.com","subject":"Re: [WIP/PATCH v4 8/8] ref-filter: add 'ref-filter.h'","fromName":"Matthieu Moy","fromEmail":"matthieu.moy@grenoble-inp.fr","sentAt":"2015-05-31T20:46:26Z","receivedAt":"2015-05-31T20:46:26Z","isPatch":true,"sender":{"key":"matthieu.moy@grenoble-inp.fr","avatar":"https://gravatar.com/avatar/72c8a2705971a25dfaff23cece15130d405685845d911aedd5667ace277f3fc5?d=mp&s=160"},"body":"Karthik Nayak <karthik.188@gmail.com> writes:\n\n> That is kind of a problem, If I need to swap those commits also, I'd\n> have to add the part where ref-filter is added to the Makefile with\n> the code movement from for-each-ref to ref-filter. This again will not\n> just be Code movement.\n\nYou can have a preparatory patch that adds ref-filter.c containing just\n\"#include ref-filter.h\" and ref-filter.h with proper content. After this\npreparatory patch, you're in a rather silly situation because you have\nan almost empty .c file, but it's still passing all tests and\ncompileable.\n\nThen, the next patch can be just code movement.\n\n-- \nMatthieu Moy\nhttp://www-verimag.imag.fr/~moy/\n"},{"id":"262535","messageId":"556B740A.5030404@gmail.com","threadId":"39466","inReplyTo":"vpqlhg4jx0d.fsf@anie.imag.fr","subject":"Re: [WIP/PATCH v4 8/8] ref-filter: add 'ref-filter.h'","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2015-05-31T20:50:18Z","receivedAt":"2015-05-31T20:50:18Z","isPatch":true,"sender":{"key":"karthik.188@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1786334?v=4"},"body":"On 06/01/2015 02:16 AM, Matthieu Moy wrote:\n> Karthik Nayak <karthik.188@gmail.com> writes:\n>\n> > That is kind of a problem, If I need to swap those commits also, I'd\n> > have to add the part where ref-filter is added to the Makefile with\n> > the code movement from for-each-ref to ref-filter. This again will not\n> > just be Code movement.\n>\n> You can have a preparatory patch that adds ref-filter.c containing just\n> \"#include ref-filter.h\" and ref-filter.h with proper content. After this\n> preparatory patch, you're in a rather silly situation because you have\n> an almost empty .c file, but it's still passing all tests and\n> compileable.\n>\n> Then, the next patch can be just code movement.\n>\nWould it be okay, If I just include the Makefile addition along with the code movement\nfrom 'for-each-ref' to 'ref-filter.c' like Eric suggested?\n\n-- \nRegards,\nKarthik\n"},{"id":"262546","messageId":"CAP8UFD1RnP1pk-MdzEBtiqTtpjaDyn-UZnEjCthrmHPYi1WCAA@mail.gmail.com","threadId":"39466","inReplyTo":"556B740A.5030404@gmail.com","subject":"Re: [WIP/PATCH v4 8/8] ref-filter: add 'ref-filter.h'","fromName":"Christian Couder","fromEmail":"christian.couder@gmail.com","sentAt":"2015-05-31T22:34:17Z","receivedAt":"2015-05-31T22:34:17Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"On Sun, May 31, 2015 at 10:50 PM, Karthik Nayak <karthik.188@gmail.com> wrote:\n> On 06/01/2015 02:16 AM, Matthieu Moy wrote:\n>>\n>> You can have a preparatory patch that adds ref-filter.c containing just\n>> \"#include ref-filter.h\" and ref-filter.h with proper content. After this\n>> preparatory patch, you're in a rather silly situation because you have\n>> an almost empty .c file, but it's still passing all tests and\n>> compileable.\n>>\n>> Then, the next patch can be just code movement.\n>>\n> Would it be okay, If I just include the Makefile addition along with the\n> code movement\n> from 'for-each-ref' to 'ref-filter.c' like Eric suggested?\n\nYeah, I think it is ok as well.\n"},{"id":"262557","messageId":"vpqoal0hr0e.fsf@anie.imag.fr","threadId":"39466","inReplyTo":"CAP8UFD117bJotFQSGjGnSub_0Xq=3wH2o3Du4c49xvmMxAyFDQ@mail.gmail.com","subject":"Re: [WIP/PATCH v4 6/8] for-each-ref: rename some functions and make them public","fromName":"Matthieu Moy","fromEmail":"matthieu.moy@grenoble-inp.fr","sentAt":"2015-06-01T06:38:57Z","receivedAt":"2015-06-01T06:38:57Z","isPatch":true,"sender":{"key":"matthieu.moy@grenoble-inp.fr","avatar":"https://gravatar.com/avatar/72c8a2705971a25dfaff23cece15130d405685845d911aedd5667ace277f3fc5?d=mp&s=160"},"body":"Christian Couder <christian.couder@gmail.com> writes:\n\n> sort_refs() -> ref_array_sort()\n> struct ref_sort -> struct ref_sort_criteria\n> default_sort() -> ref_default_sort_criteria()\n> opt_parse_sort() -> opt_parse_ref_sort_criteria()\n\nBTW, having such summary in the log message would help review: we could\nthink and discuss the naming by looking just at the summary, and then\ncheck that you did it correctly (easy).\n\n-- \nMatthieu Moy\nhttp://www-verimag.imag.fr/~moy/\n"},{"id":"262558","messageId":"vpqiob8hqmo.fsf@anie.imag.fr","threadId":"39466","inReplyTo":"556B740A.5030404@gmail.com","subject":"Re: [WIP/PATCH v4 8/8] ref-filter: add 'ref-filter.h'","fromName":"Matthieu Moy","fromEmail":"matthieu.moy@grenoble-inp.fr","sentAt":"2015-06-01T06:47:11Z","receivedAt":"2015-06-01T06:47:11Z","isPatch":true,"sender":{"key":"matthieu.moy@grenoble-inp.fr","avatar":"https://gravatar.com/avatar/72c8a2705971a25dfaff23cece15130d405685845d911aedd5667ace277f3fc5?d=mp&s=160"},"body":"Karthik Nayak <karthik.188@gmail.com> writes:\n\n> On 06/01/2015 02:16 AM, Matthieu Moy wrote:\n>> Karthik Nayak <karthik.188@gmail.com> writes:\n>>\n>> > That is kind of a problem, If I need to swap those commits also, I'd\n>> > have to add the part where ref-filter is added to the Makefile with\n>> > the code movement from for-each-ref to ref-filter. This again will not\n>> > just be Code movement.\n>>\n>> You can have a preparatory patch that adds ref-filter.c containing just\n>> \"#include ref-filter.h\" and ref-filter.h with proper content. After this\n>> preparatory patch, you're in a rather silly situation because you have\n>> an almost empty .c file, but it's still passing all tests and\n>> compileable.\n>>\n>> Then, the next patch can be just code movement.\n>>\n> Would it be okay, If I just include the Makefile addition along with the code movement\n> from 'for-each-ref' to 'ref-filter.c' like Eric suggested?\n\nI prefer pure code movement, but as Eric said it's also OK to have small\nother changes as long as they are related (so it makes sense to include\nthem in the same commit) and separate (in your case, they touch\ndifferent files so it's easy to notice the Makefile change in the\npatch).\n\nIn any case, because I prefer one way doesn't mean it's the only way or\neven that it's the right way.\n\n-- \nMatthieu Moy\nhttp://www-verimag.imag.fr/~moy/\n"},{"id":"262598","messageId":"xmqq1thva3x2.fsf@gitster.dls.corp.google.com","threadId":"39466","inReplyTo":"vpqvbf8jxbr.fsf@anie.imag.fr","subject":"Re: [WIP/PATCH v4 1/8] for-each-ref: extract helper functions out of grab_single_ref()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-06-01T14:39:37Z","receivedAt":"2015-06-01T14:39:37Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Matthieu Moy <Matthieu.Moy@grenoble-inp.fr> writes:\n\n> Just match_refname may not carry all the semantics of the function,\n> which matches a prefix up to the end of string, or up to a / (but you\n> can't just be a prefix stopping in the middle of a word). To me, the\n> \"_as_path\" helped understanding the overall behavior of the function.\n\nYeah, Karthik explained that the plan is to add different kinds of\nmatching later, and in that context _as_path is a good way to tell\nthem apart.\n\nThanks.\n"},{"id":"262600","messageId":"xmqqvbf78oow.fsf@gitster.dls.corp.google.com","threadId":"39466","inReplyTo":"556B6234.2010809@gmail.com","subject":"Re: [WIP/PATCH v4 6/8] for-each-ref: rename some functions and make them public","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-06-01T14:53:51Z","receivedAt":"2015-06-01T14:53:51Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Karthik Nayak <karthik.188@gmail.com> writes:\n\n> Could be achieved using a simple wrapper around 'filter_refs()'\n> something like this perhaps.\n>\n> int filter_refs_with_pattern(struct ref_array *ref, int\n> (*for_each_ref_fn)(each_ref_fn, void *), char **patterns)\n> {\n> \tint i;\n> \tstruct ref_filter_cbdata data;\n> \tdata.filter.name_patterns = patterns;\n> \tfilter_refs(for_each_ref_fn, &data);\n\nI presume that this is\n\n\tfilter_refs(&refs, for_each_ref_fn, &data);\n\nas you would need to have some way to get the result back ;-)\n\n> \trefs->nr = data.array.nr;\n> \tfor(i = 0; i < refs->nr; i++) {\n> \t\t/* copy over the refs */\n> \t}\n> \treturn 0;\n> }\n>\n> Is this on the lines of what you had in mind? If it is, than I could\n> just create a new patch which would make ref_filter_handler() private\n> and introduce filter_refs() as shown.\n\nYeah.  Even though I suggested\n\n\tfilter_refs(&for_each_ref, ...);\n\nI actually would think the external interface should not mention\nfor_each_ref() like I did.  The primary reason why I felt that it is\nbad for the API to export a generic callback function the caller can\nuse to call for_each_ref() or for_each_rawref()\" in the longer term\nis because it forces us to always iterate all refs; for_each_ref()\ndoes not know what the callback filter function wants to do.  The\nmost common way to filter in the context of your GSoC project is \"we\nlimit only to refs/heads/*, and then we may also filter by other\ncriteria\" (that is \"git branch\" \"-l\" or possibly with \"--contains\",\netc.), and it is very wasteful for that codepath to allow\nfor_each_ref() to even enumerate and feed all refs outside the\nrefs/heads/* area to your callback, which would involve reading all\nentries in packed-refs (which is a fixed cost so not an overhead)\nand then reading everything in .git/refs/* (which is an overhead we\ncould and should avoid when we know we are only interested in the\nbranches that live in refs/heads*).\n\nYour first implementation of course can just call for_each_ref() or\nfor_each_rawref(), and at the end of GSoC, the code may still do so.\nBut by keeping the external interface free of for_each_ref(), you\ncould later optimize.\n\nAnd your above sample only takes for_each_ref_fn without exposing the\ninternal use of for_each_ref(), which is good.\n"},{"id":"262643","messageId":"AD4CBEF2-90E7-4C75-89BF-A7C3E9F367B2@gmail.com","threadId":"39466","inReplyTo":"vpqoal0hr0e.fsf@anie.imag.fr","subject":"Re: [WIP/PATCH v4 6/8] for-each-ref: rename some functions and make them public","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2015-06-01T19:28:47Z","receivedAt":"2015-06-01T19:28:47Z","isPatch":true,"sender":{"key":"karthik.188@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1786334?v=4"},"body":"\n\nOn June 1, 2015 12:08:57 PM GMT+05:30, Matthieu Moy <Matthieu.Moy@grenoble-inp.fr> wrote:\n>Christian Couder <christian.couder@gmail.com> writes:\n>\n>> sort_refs() -> ref_array_sort()\n>> struct ref_sort -> struct ref_sort_criteria\n>> default_sort() -> ref_default_sort_criteria()\n>> opt_parse_sort() -> opt_parse_ref_sort_criteria()\n>\n>BTW, having such summary in the log message would help review: we could\n>think and discuss the naming by looking just at the summary, and then\n>check that you did it correctly (easy).\n\nYes agreed, will do that.\n"},{"id":"262646","messageId":"C9DFEB12-F48F-4F73-AFC8-F37892C75A92@gmail.com","threadId":"39466","inReplyTo":"xmqqvbf78oow.fsf@gitster.dls.corp.google.com","subject":"Re: [WIP/PATCH v4 6/8] for-each-ref: rename some functions and make them public","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2015-06-01T19:35:52Z","receivedAt":"2015-06-01T19:35:52Z","isPatch":true,"sender":{"key":"karthik.188@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1786334?v=4"},"body":"\n\nOn June 1, 2015 8:23:51 PM GMT+05:30, Junio C Hamano <gitster@pobox.com> wrote:\n>Karthik Nayak <karthik.188@gmail.com> writes:\n>\n>> Could be achieved using a simple wrapper around 'filter_refs()'\n>> something like this perhaps.\n>>\n>> int filter_refs_with_pattern(struct ref_array *ref, int\n>> (*for_each_ref_fn)(each_ref_fn, void *), char **patterns)\n>> {\n>> \tint i;\n>> \tstruct ref_filter_cbdata data;\n>> \tdata.filter.name_patterns = patterns;\n>> \tfilter_refs(for_each_ref_fn, &data);\n>\n>I presume that this is\n>\n>\tfilter_refs(&refs, for_each_ref_fn, &data);\n>\n>as you would need to have some way to get the result back ;-)\n>\n\nNo it's meant to be that way, see as it takes a struct ref_filter_cbdata, the filters are put in the data.filter.* and we obtain the refs in the data.array.items. So no need for another ref_array to hold the array of items.\n\n>> \trefs->nr = data.array.nr;\n>> \tfor(i = 0; i < refs->nr; i++) {\n>> \t\t/* copy over the refs */\n>> \t}\n>> \treturn 0;\n>> }\n>>\n>> Is this on the lines of what you had in mind? If it is, than I could\n>> just create a new patch which would make ref_filter_handler() private\n>> and introduce filter_refs() as shown.\n>\n>Yeah.  Even though I suggested\n>\n>\tfilter_refs(&for_each_ref, ...);\n>\n>I actually would think the external interface should not mention\n>for_each_ref() like I did.  The primary reason why I felt that it is\n>bad for the API to export a generic callback function the caller can\n>use to call for_each_ref() or for_each_rawref()\" in the longer term\n>is because it forces us to always iterate all refs; for_each_ref()\n>does not know what the callback filter function wants to do.  The\n>most common way to filter in the context of your GSoC project is \"we\n>limit only to refs/heads/*, and then we may also filter by other\n>criteria\" (that is \"git branch\" \"-l\" or possibly with \"--contains\",\n>etc.), and it is very wasteful for that codepath to allow\n>for_each_ref() to even enumerate and feed all refs outside the\n>refs/heads/* area to your callback, which would involve reading all\n>entries in packed-refs (which is a fixed cost so not an overhead)\n>and then reading everything in .git/refs/* (which is an overhead we\n>could and should avoid when we know we are only interested in the\n>branches that live in refs/heads*).\n>\n>Your first implementation of course can just call for_each_ref() or\n>for_each_rawref(), and at the end of GSoC, the code may still do so.\n>But by keeping the external interface free of for_each_ref(), you\n>could later optimize.\n>\n>And your above sample only takes for_each_ref_fn without exposing the\n>internal use of for_each_ref(), which is good.\n\nThat seems good, thanks for the guidance.\n"}]}