{"thread":{"id":"31494","subject":"[PATCH v2 0/6] Add some string_list-related functions","startedAt":"2012-09-10T21:18:40Z","lastAt":"2012-09-12T17:55:25Z","messageCount":14,"participants":["Michael Haggerty","Junio C Hamano"],"isPatch":true,"patchVersion":2,"patchTotal":6},"messages":[{"id":"198731","messageId":"1347311926-5207-1-git-send-email-mhagger@alum.mit.edu","threadId":"31494","inReplyTo":null,"subject":"[PATCH v2 0/6] Add some string_list-related functions","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2012-09-10T21:18:40Z","receivedAt":"2012-09-10T21:18:40Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"Version 2 of a patch series that adds some functions to the\nstring_list API.  This patch series applies to current master.  Thanks\nfor Junio for lots of great feedback.\n\nThe patch series \"Clean up how fetch_pack() handles the heads list\"\nv3, which requires some of the new string_list functionality, works\nunmodified on top of this version of the patch series.\n\nChanges since v1:\n\n* Expose a new function, string_list_append_nodup().  This is used in\n  the implementation of string_list_split() and should be generally\n  useful.\n\n* Straighten out the API for splitting strings (with help from Junio):\n\n  * Implement two separate functions, one for splitting strings in\n    place and a second for making copies while splitting a const\n    string.\n\n  * Redefine maxsplit=0 to mean \"copy input string to output list as a\n    single entry\" for better consistency.\n\n* Add tests for more of the new functionality and simplify some of the\n  other tests.\n\n* Various comment and documentation improvements.\n\nMichael Haggerty (6):\n  string_list: add function string_list_append_nodup()\n  string_list: add two new functions for splitting strings\n  string_list: add a new function, filter_string_list()\n  string_list: add a new function, string_list_remove_duplicates()\n  string_list: add a function string_list_longest_prefix()\n  api-string-list.txt: initialize the string_list the easy way\n\n .gitignore                                  |   1 +\n Documentation/technical/api-string-list.txt |  67 +++++++++++++--\n Makefile                                    |   1 +\n string-list.c                               | 123 ++++++++++++++++++++++++++--\n string-list.h                               |  71 ++++++++++++++++\n t/t0063-string-list.sh                      | 121 +++++++++++++++++++++++++++\n test-string-list.c                          | 123 ++++++++++++++++++++++++++++\n 7 files changed, 497 insertions(+), 10 deletions(-)\n create mode 100755 t/t0063-string-list.sh\n create mode 100644 test-string-list.c\n\n-- \n1.7.11.3\n"},{"id":"198732","messageId":"1347311926-5207-2-git-send-email-mhagger@alum.mit.edu","threadId":"31494","inReplyTo":"1347311926-5207-1-git-send-email-mhagger@alum.mit.edu","subject":"[PATCH v2 1/6] string_list: add function string_list_append_nodup()","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2012-09-10T21:18:41Z","receivedAt":"2012-09-10T21:18:41Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"Add a new function that appends a string to a string_list without\ncopying it.  This can be used to pass ownership of an already-copied\nstring to a string_list that has strdup_strings set.\n\nSigned-off-by: Michael Haggerty <mhagger@alum.mit.edu>\n---\n Documentation/technical/api-string-list.txt | 17 ++++++++++++++---\n string-list.c                               | 20 +++++++++++++++-----\n string-list.h                               | 18 ++++++++++++++++++\n 3 files changed, 47 insertions(+), 8 deletions(-)\n\ndiff --git a/Documentation/technical/api-string-list.txt b/Documentation/technical/api-string-list.txt\nindex 5a0c14f..113f841 100644\n--- a/Documentation/technical/api-string-list.txt\n+++ b/Documentation/technical/api-string-list.txt\n@@ -20,8 +20,8 @@ If you need something advanced, you can manually malloc() the `items`\n member (you need this if you add things later) and you should set the\n `nr` and `alloc` members in that case, too.\n \n-. Adds new items to the list, using `string_list_append` or\n-  `string_list_insert`.\n+. Adds new items to the list, using `string_list_append`,\n+  `string_list_append_nodup`, or `string_list_insert`.\n \n . Can check if a string is in the list using `string_list_has_string` or\n   `unsorted_string_list_has_string` and get it from the list using\n@@ -100,7 +100,18 @@ write `string_list_insert(...)->util = ...;`.\n \n `string_list_append`::\n \n-\tAppend a new string to the end of the string_list.\n+\tAppend a new string to the end of the string_list.  If\n+\t`strdup_string` is set, then the string argument is copied;\n+\totherwise the new `string_list_entry` refers to the input\n+\tstring.\n+\n+`string_list_append_nodup`::\n+\n+\tAppend a new string to the end of the string_list.  The new\n+\t`string_list_entry` always refers to the input string, even if\n+\t`strdup_string` is set.  This function can be used to hand\n+\townership of a malloc()ed string to a `string_list` that has\n+\t`strdup_string` set.\n \n `sort_string_list`::\n \ndiff --git a/string-list.c b/string-list.c\nindex d9810ab..5594b7d 100644\n--- a/string-list.c\n+++ b/string-list.c\n@@ -148,13 +148,23 @@ void print_string_list(const struct string_list *p, const char *text)\n \t\tprintf(\"%s:%p\\n\", p->items[i].string, p->items[i].util);\n }\n \n-struct string_list_item *string_list_append(struct string_list *list, const char *string)\n+struct string_list_item *string_list_append_nodup(struct string_list *list,\n+\t\t\t\t\t\t  char *string)\n {\n+\tstruct string_list_item *retval;\n \tALLOC_GROW(list->items, list->nr + 1, list->alloc);\n-\tlist->items[list->nr].string =\n-\t\tlist->strdup_strings ? xstrdup(string) : (char *)string;\n-\tlist->items[list->nr].util = NULL;\n-\treturn list->items + list->nr++;\n+\tretval = &list->items[list->nr++];\n+\tretval->string = (char *)string;\n+\tretval->util = NULL;\n+\treturn retval;\n+}\n+\n+struct string_list_item *string_list_append(struct string_list *list,\n+\t\t\t\t\t    const char *string)\n+{\n+\treturn string_list_append_nodup(\n+\t\t\tlist,\n+\t\t\tlist->strdup_strings ? xstrdup(string) : (char *)string);\n }\n \n static int cmp_items(const void *a, const void *b)\ndiff --git a/string-list.h b/string-list.h\nindex 0684cb7..1b3915b 100644\n--- a/string-list.h\n+++ b/string-list.h\n@@ -29,6 +29,7 @@ int for_each_string_list(struct string_list *list,\n #define for_each_string_list_item(item,list) \\\n \tfor (item = (list)->items; item < (list)->items + (list)->nr; ++item)\n \n+\n /* Use these functions only on sorted lists: */\n int string_list_has_string(const struct string_list *list, const char *string);\n int string_list_find_insert_index(const struct string_list *list, const char *string,\n@@ -38,11 +39,28 @@ struct string_list_item *string_list_insert_at_index(struct string_list *list,\n \t\t\t\t\t\t     int insert_at, const char *string);\n struct string_list_item *string_list_lookup(struct string_list *list, const char *string);\n \n+\n /* Use these functions only on unsorted lists: */\n+\n+/*\n+ * Add string to the end of list.  If list->strdup_string is set, then\n+ * string is copied; otherwise the new string_list_entry refers to the\n+ * input string.\n+ */\n struct string_list_item *string_list_append(struct string_list *list, const char *string);\n+\n+/*\n+ * Like string_list_append(), except string is never copied.  When\n+ * list->strdup_strings is set, this function can be used to hand\n+ * ownership of a malloc()ed string to list without making an extra\n+ * copy.\n+ */\n+struct string_list_item *string_list_append_nodup(struct string_list *list, char *string);\n+\n void sort_string_list(struct string_list *list);\n int unsorted_string_list_has_string(struct string_list *list, const char *string);\n struct string_list_item *unsorted_string_list_lookup(struct string_list *list,\n \t\t\t\t\t\t     const char *string);\n+\n void unsorted_string_list_delete_item(struct string_list *list, int i, int free_util);\n #endif /* STRING_LIST_H */\n-- \n1.7.11.3\n"},{"id":"198733","messageId":"1347311926-5207-3-git-send-email-mhagger@alum.mit.edu","threadId":"31494","inReplyTo":"1347311926-5207-1-git-send-email-mhagger@alum.mit.edu","subject":"[PATCH v2 2/6] string_list: add two new functions for splitting strings","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2012-09-10T21:18:42Z","receivedAt":"2012-09-10T21:18:42Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"Add two new functions, string_list_split() and\nstring_list_split_in_place().  These split a string into a string_list\non a separator character.  The first makes copies of the substrings\n(leaving the input string untouched) and the second splits the\noriginal string in place, overwriting the separator characters with\nNULs and referring to the original string's memory.\n\nThese functions are similar to the strbuf_split_*() functions except\nthat they work with the more powerful string_list interface.\n\nSigned-off-by: Michael Haggerty <mhagger@alum.mit.edu>\n---\n .gitignore                                  |  1 +\n Documentation/technical/api-string-list.txt | 21 +++++++++-\n Makefile                                    |  1 +\n string-list.c                               | 49 ++++++++++++++++++++++\n string-list.h                               | 29 +++++++++++++\n t/t0063-string-list.sh                      | 63 +++++++++++++++++++++++++++++\n test-string-list.c                          | 45 +++++++++++++++++++++\n 7 files changed, 208 insertions(+), 1 deletion(-)\n create mode 100755 t/t0063-string-list.sh\n create mode 100644 test-string-list.c\n\ndiff --git a/.gitignore b/.gitignore\nindex bb5c91e..0ca7df8 100644\n--- a/.gitignore\n+++ b/.gitignore\n@@ -193,6 +193,7 @@\n /test-run-command\n /test-sha1\n /test-sigchain\n+/test-string-list\n /test-subprocess\n /test-svn-fe\n /common-cmds.h\ndiff --git a/Documentation/technical/api-string-list.txt b/Documentation/technical/api-string-list.txt\nindex 113f841..670217c 100644\n--- a/Documentation/technical/api-string-list.txt\n+++ b/Documentation/technical/api-string-list.txt\n@@ -21,7 +21,8 @@ member (you need this if you add things later) and you should set the\n `nr` and `alloc` members in that case, too.\n \n . Adds new items to the list, using `string_list_append`,\n-  `string_list_append_nodup`, or `string_list_insert`.\n+  `string_list_append_nodup`, `string_list_insert`,\n+  `string_list_split`, and/or `string_list_split_in_place`.\n \n . Can check if a string is in the list using `string_list_has_string` or\n   `unsorted_string_list_has_string` and get it from the list using\n@@ -135,6 +136,24 @@ counterpart for sorted lists, which performs a binary search.\n \tis set. The third parameter controls if the `util` pointer of the\n \titems should be freed or not.\n \n+`string_list_split`, `string_list_split_in_place`::\n+\n+\tSplit a string into substrings on a delimiter character and\n+\tappend the substrings to a `string_list`.  If `maxsplit` is\n+\tnon-negative, then split at most `maxsplit` times.  Return the\n+\tnumber of substrings appended to the list.\n++\n+`string_list_split` requires a `string_list` that has `strdup_strings`\n+set to true; it leaves the input string untouched and makes copies of\n+the substrings in newly-allocated memory.\n+`string_list_split_in_place` requires a `string_list` that has\n+`strdup_strings` set to false; it splits the input string in place,\n+overwriting the delimiter characters with NULs and creating new\n+string_list_items that point into the original string (the original\n+string must therefore not be modified or freed while the `string_list`\n+is in use).\n+\n+\n Data structures\n ---------------\n \ndiff --git a/Makefile b/Makefile\nindex 66e8216..ebbb381 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -501,6 +501,7 @@ TEST_PROGRAMS_NEED_X += test-run-command\n TEST_PROGRAMS_NEED_X += test-scrap-cache-tree\n TEST_PROGRAMS_NEED_X += test-sha1\n TEST_PROGRAMS_NEED_X += test-sigchain\n+TEST_PROGRAMS_NEED_X += test-string-list\n TEST_PROGRAMS_NEED_X += test-subprocess\n TEST_PROGRAMS_NEED_X += test-svn-fe\n \ndiff --git a/string-list.c b/string-list.c\nindex 5594b7d..f9051ec 100644\n--- a/string-list.c\n+++ b/string-list.c\n@@ -204,3 +204,52 @@ void unsorted_string_list_delete_item(struct string_list *list, int i, int free_\n \tlist->items[i] = list->items[list->nr-1];\n \tlist->nr--;\n }\n+\n+int string_list_split(struct string_list *list, const char *string,\n+\t\t      int delim, int maxsplit)\n+{\n+\tint count = 0;\n+\tconst char *p = string, *end;\n+\n+\tassert(list->strdup_strings);\n+\tfor (;;) {\n+\t\tcount++;\n+\t\tif (maxsplit >= 0 && count > maxsplit) {\n+\t\t\tstring_list_append(list, p);\n+\t\t\treturn count;\n+\t\t}\n+\t\tend = strchr(p, delim);\n+\t\tif (end) {\n+\t\t\tstring_list_append_nodup(list, xmemdupz(p, end - p));\n+\t\t\tp = end + 1;\n+\t\t} else {\n+\t\t\tstring_list_append(list, p);\n+\t\t\treturn count;\n+\t\t}\n+\t}\n+}\n+\n+int string_list_split_in_place(struct string_list *list, char *string,\n+\t\t\t       int delim, int maxsplit)\n+{\n+\tint count = 0;\n+\tchar *p = string, *end;\n+\n+\tassert(!list->strdup_strings);\n+\tfor (;;) {\n+\t\tcount++;\n+\t\tif (maxsplit >= 0 && count > maxsplit) {\n+\t\t\tstring_list_append(list, p);\n+\t\t\treturn count;\n+\t\t}\n+\t\tend = strchr(p, delim);\n+\t\tif (end) {\n+\t\t\t*end = '\\0';\n+\t\t\tstring_list_append(list, p);\n+\t\t\tp = end + 1;\n+\t\t} else {\n+\t\t\tstring_list_append(list, p);\n+\t\t\treturn count;\n+\t\t}\n+\t}\n+}\ndiff --git a/string-list.h b/string-list.h\nindex 1b3915b..dc5fbc8 100644\n--- a/string-list.h\n+++ b/string-list.h\n@@ -63,4 +63,33 @@ struct string_list_item *unsorted_string_list_lookup(struct string_list *list,\n \t\t\t\t\t\t     const char *string);\n \n void unsorted_string_list_delete_item(struct string_list *list, int i, int free_util);\n+\n+/*\n+ * Split string into substrings on character delim and append the\n+ * substrings to list.  The input string is not modified.\n+ * list->strdup_strings must be set, as new memory needs to be\n+ * allocated to hold the substrings.  If maxsplit is non-negative,\n+ * then split at most maxsplit times.  Return the number of substrings\n+ * appended to list.\n+ *\n+ * Examples:\n+ *   string_list_split(l, \"foo:bar:baz\", ':', -1) -> [\"foo\", \"bar\", \"baz\"]\n+ *   string_list_split(l, \"foo:bar:baz\", ':', 0) -> [\"foo:bar:baz\"]\n+ *   string_list_split(l, \"foo:bar:baz\", ':', 1) -> [\"foo\", \"bar:baz\"]\n+ *   string_list_split(l, \"foo:bar:\", ':', -1) -> [\"foo\", \"bar\", \"\"]\n+ *   string_list_split(l, \"\", ':', -1) -> [\"\"]\n+ *   string_list_split(l, \":\", ':', -1) -> [\"\", \"\"]\n+ */\n+int string_list_split(struct string_list *list, const char *string,\n+\t\t      int delim, int maxsplit);\n+\n+/*\n+ * Like string_list_split(), except that string is split in-place: the\n+ * delimiter characters in string are overwritten with NULs, and the\n+ * new string_list_items point into string (which therefore must not\n+ * be modified or freed while the string_list is in use).\n+ * list->strdup_strings must *not* be set.\n+ */\n+int string_list_split_in_place(struct string_list *list, char *string,\n+\t\t\t       int delim, int maxsplit);\n #endif /* STRING_LIST_H */\ndiff --git a/t/t0063-string-list.sh b/t/t0063-string-list.sh\nnew file mode 100755\nindex 0000000..fb85430\n--- /dev/null\n+++ b/t/t0063-string-list.sh\n@@ -0,0 +1,63 @@\n+#!/bin/sh\n+#\n+# Copyright (c) 2012 Michael Haggerty\n+#\n+\n+test_description='Test string list functionality'\n+\n+. ./test-lib.sh\n+\n+test_split () {\n+\tcat >expected &&\n+\ttest_expect_success \"split $1 at $2, max $3\" \"\n+\t\ttest-string-list split '$1' '$2' '$3' >actual &&\n+\t\ttest_cmp expected actual &&\n+\t\ttest-string-list split_in_place '$1' '$2' '$3' >actual &&\n+\t\ttest_cmp expected actual\n+\t\"\n+}\n+\n+test_split \"foo:bar:baz\" \":\" \"-1\" <<EOF\n+3\n+[0]: \"foo\"\n+[1]: \"bar\"\n+[2]: \"baz\"\n+EOF\n+\n+test_split \"foo:bar:baz\" \":\" \"0\" <<EOF\n+1\n+[0]: \"foo:bar:baz\"\n+EOF\n+\n+test_split \"foo:bar:baz\" \":\" \"1\" <<EOF\n+2\n+[0]: \"foo\"\n+[1]: \"bar:baz\"\n+EOF\n+\n+test_split \"foo:bar:baz\" \":\" \"2\" <<EOF\n+3\n+[0]: \"foo\"\n+[1]: \"bar\"\n+[2]: \"baz\"\n+EOF\n+\n+test_split \"foo:bar:\" \":\" \"-1\" <<EOF\n+3\n+[0]: \"foo\"\n+[1]: \"bar\"\n+[2]: \"\"\n+EOF\n+\n+test_split \"\" \":\" \"-1\" <<EOF\n+1\n+[0]: \"\"\n+EOF\n+\n+test_split \":\" \":\" \"-1\" <<EOF\n+2\n+[0]: \"\"\n+[1]: \"\"\n+EOF\n+\n+test_done\ndiff --git a/test-string-list.c b/test-string-list.c\nnew file mode 100644\nindex 0000000..cdc3cf3\n--- /dev/null\n+++ b/test-string-list.c\n@@ -0,0 +1,45 @@\n+#include \"cache.h\"\n+#include \"string-list.h\"\n+\n+void write_list(const struct string_list *list)\n+{\n+\tint i;\n+\tfor (i = 0; i < list->nr; i++)\n+\t\tprintf(\"[%d]: \\\"%s\\\"\\n\", i, list->items[i].string);\n+}\n+\n+int main(int argc, char **argv)\n+{\n+\tif (argc == 5 && !strcmp(argv[1], \"split\")) {\n+\t\tstruct string_list list = STRING_LIST_INIT_DUP;\n+\t\tint i;\n+\t\tconst char *s = argv[2];\n+\t\tint delim = *argv[3];\n+\t\tint maxsplit = atoi(argv[4]);\n+\n+\t\ti = string_list_split(&list, s, delim, maxsplit);\n+\t\tprintf(\"%d\\n\", i);\n+\t\twrite_list(&list);\n+\t\tstring_list_clear(&list, 0);\n+\t\treturn 0;\n+\t}\n+\n+\tif (argc == 5 && !strcmp(argv[1], \"split_in_place\")) {\n+\t\tstruct string_list list = STRING_LIST_INIT_NODUP;\n+\t\tint i;\n+\t\tchar *s = xstrdup(argv[2]);\n+\t\tint delim = *argv[3];\n+\t\tint maxsplit = atoi(argv[4]);\n+\n+\t\ti = string_list_split_in_place(&list, s, delim, maxsplit);\n+\t\tprintf(\"%d\\n\", i);\n+\t\twrite_list(&list);\n+\t\tstring_list_clear(&list, 0);\n+\t\tfree(s);\n+\t\treturn 0;\n+\t}\n+\n+\tfprintf(stderr, \"%s: unknown function name: %s\\n\", argv[0],\n+\t\targv[1] ? argv[1] : \"(there was none)\");\n+\treturn 1;\n+}\n-- \n1.7.11.3\n"},{"id":"198735","messageId":"1347311926-5207-4-git-send-email-mhagger@alum.mit.edu","threadId":"31494","inReplyTo":"1347311926-5207-1-git-send-email-mhagger@alum.mit.edu","subject":"[PATCH v2 3/6] string_list: add a new function, filter_string_list()","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2012-09-10T21:18:43Z","receivedAt":"2012-09-10T21:18:43Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"This function allows entries that don't match a specified criterion to\nbe discarded from a string_list while preserving the order of the\nremaining entries.\n\nSigned-off-by: Michael Haggerty <mhagger@alum.mit.edu>\n---\n Documentation/technical/api-string-list.txt | 11 +++++++\n string-list.c                               | 17 ++++++++++\n string-list.h                               |  9 ++++++\n t/t0063-string-list.sh                      | 11 +++++++\n test-string-list.c                          | 48 +++++++++++++++++++++++++++++\n 5 files changed, 96 insertions(+)\n\ndiff --git a/Documentation/technical/api-string-list.txt b/Documentation/technical/api-string-list.txt\nindex 670217c..ea65818 100644\n--- a/Documentation/technical/api-string-list.txt\n+++ b/Documentation/technical/api-string-list.txt\n@@ -33,6 +33,9 @@ member (you need this if you add things later) and you should set the\n . Can remove individual items of an unsorted list using\n   `unsorted_string_list_delete_item`.\n \n+. Can remove items not matching a criterion from a sorted or unsorted\n+  list using `filter_string_list`.\n+\n . Finally it should free the list using `string_list_clear`.\n \n Example:\n@@ -61,6 +64,14 @@ Functions\n \n * General ones (works with sorted and unsorted lists as well)\n \n+`filter_string_list`::\n+\n+\tApply a function to each item in a list, retaining only the\n+\titems for which the function returns true.  If free_util is\n+\ttrue, call free() on the util members of any items that have\n+\tto be deleted.  Preserve the order of the items that are\n+\tretained.\n+\n `print_string_list`::\n \n \tDump a string_list to stdout, useful mainly for debugging purposes. It\ndiff --git a/string-list.c b/string-list.c\nindex f9051ec..e0806fb 100644\n--- a/string-list.c\n+++ b/string-list.c\n@@ -102,6 +102,23 @@ int for_each_string_list(struct string_list *list,\n \treturn ret;\n }\n \n+void filter_string_list(struct string_list *list, int free_util,\n+\t\t\tstring_list_each_func_t want, void *cb_data)\n+{\n+\tint src, dst = 0;\n+\tfor (src = 0; src < list->nr; src++) {\n+\t\tif (want(&list->items[src], cb_data)) {\n+\t\t\tlist->items[dst++] = list->items[src];\n+\t\t} else {\n+\t\t\tif (list->strdup_strings)\n+\t\t\t\tfree(list->items[src].string);\n+\t\t\tif (free_util)\n+\t\t\t\tfree(list->items[src].util);\n+\t\t}\n+\t}\n+\tlist->nr = dst;\n+}\n+\n void string_list_clear(struct string_list *list, int free_util)\n {\n \tif (list->items) {\ndiff --git a/string-list.h b/string-list.h\nindex dc5fbc8..7d18e62 100644\n--- a/string-list.h\n+++ b/string-list.h\n@@ -29,6 +29,15 @@ int for_each_string_list(struct string_list *list,\n #define for_each_string_list_item(item,list) \\\n \tfor (item = (list)->items; item < (list)->items + (list)->nr; ++item)\n \n+/*\n+ * Apply want to each item in list, retaining only the ones for which\n+ * the function returns true.  If free_util is true, call free() on\n+ * the util members of any items that have to be deleted.  Preserve\n+ * the order of the items that are retained.\n+ */\n+void filter_string_list(struct string_list *list, int free_util,\n+\t\t\tstring_list_each_func_t want, void *cb_data);\n+\n \n /* Use these functions only on sorted lists: */\n int string_list_has_string(const struct string_list *list, const char *string);\ndiff --git a/t/t0063-string-list.sh b/t/t0063-string-list.sh\nindex fb85430..a5f05cd 100755\n--- a/t/t0063-string-list.sh\n+++ b/t/t0063-string-list.sh\n@@ -60,4 +60,15 @@ test_split \":\" \":\" \"-1\" <<EOF\n [1]: \"\"\n EOF\n \n+test_expect_success \"test filter_string_list\" '\n+\ttest \"x-\" = \"x$(test-string-list filter - y)\" &&\n+\ttest \"x-\" = \"x$(test-string-list filter no y)\" &&\n+\ttest yes = \"$(test-string-list filter yes y)\" &&\n+\ttest yes = \"$(test-string-list filter no:yes y)\" &&\n+\ttest yes = \"$(test-string-list filter yes:no y)\" &&\n+\ttest y1:y2 = \"$(test-string-list filter y1:y2 y)\" &&\n+\ttest y2:y1 = \"$(test-string-list filter y2:y1 y)\" &&\n+\ttest \"x-\" = \"x$(test-string-list filter x1:x2 y)\"\n+'\n+\n test_done\ndiff --git a/test-string-list.c b/test-string-list.c\nindex cdc3cf3..702276c 100644\n--- a/test-string-list.c\n+++ b/test-string-list.c\n@@ -1,6 +1,20 @@\n #include \"cache.h\"\n #include \"string-list.h\"\n \n+/*\n+ * Parse an argument into a string list.  arg should either be a\n+ * ':'-separated list of strings, or \"-\" to indicate an empty string\n+ * list (as opposed to \"\", which indicates a string list containing a\n+ * single empty string).  list->strdup_strings must be set.\n+ */\n+void parse_string_list(struct string_list *list, const char *arg)\n+{\n+\tif (!strcmp(arg, \"-\"))\n+\t\treturn;\n+\n+\t(void)string_list_split(list, arg, ':', -1);\n+}\n+\n void write_list(const struct string_list *list)\n {\n \tint i;\n@@ -8,6 +22,25 @@ void write_list(const struct string_list *list)\n \t\tprintf(\"[%d]: \\\"%s\\\"\\n\", i, list->items[i].string);\n }\n \n+void write_list_compact(const struct string_list *list)\n+{\n+\tint i;\n+\tif (!list->nr)\n+\t\tprintf(\"-\\n\");\n+\telse {\n+\t\tprintf(\"%s\", list->items[0].string);\n+\t\tfor (i = 1; i < list->nr; i++)\n+\t\t\tprintf(\":%s\", list->items[i].string);\n+\t\tprintf(\"\\n\");\n+\t}\n+}\n+\n+int prefix_cb(struct string_list_item *item, void *cb_data)\n+{\n+\tconst char *prefix = (const char *)cb_data;\n+\treturn !prefixcmp(item->string, prefix);\n+}\n+\n int main(int argc, char **argv)\n {\n \tif (argc == 5 && !strcmp(argv[1], \"split\")) {\n@@ -39,6 +72,21 @@ int main(int argc, char **argv)\n \t\treturn 0;\n \t}\n \n+\tif (argc == 4 && !strcmp(argv[1], \"filter\")) {\n+\t\t/*\n+\t\t * Retain only the items that have the specified prefix.\n+\t\t * Arguments: list|- prefix\n+\t\t */\n+\t\tstruct string_list list = STRING_LIST_INIT_DUP;\n+\t\tconst char *prefix = argv[3];\n+\n+\t\tparse_string_list(&list, argv[2]);\n+\t\tfilter_string_list(&list, 0, prefix_cb, (void *)prefix);\n+\t\twrite_list_compact(&list);\n+\t\tstring_list_clear(&list, 0);\n+\t\treturn 0;\n+\t}\n+\n \tfprintf(stderr, \"%s: unknown function name: %s\\n\", argv[0],\n \t\targv[1] ? argv[1] : \"(there was none)\");\n \treturn 1;\n-- \n1.7.11.3\n"},{"id":"198734","messageId":"1347311926-5207-5-git-send-email-mhagger@alum.mit.edu","threadId":"31494","inReplyTo":"1347311926-5207-1-git-send-email-mhagger@alum.mit.edu","subject":"[PATCH v2 4/6] string_list: add a new function, string_list_remove_duplicates()","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2012-09-10T21:18:44Z","receivedAt":"2012-09-10T21:18:44Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"Add a function that deletes duplicate entries from a sorted\nstring_list.\n\nSigned-off-by: Michael Haggerty <mhagger@alum.mit.edu>\n---\n Documentation/technical/api-string-list.txt |  9 +++++++++\n string-list.c                               | 17 +++++++++++++++++\n string-list.h                               |  7 +++++++\n t/t0063-string-list.sh                      | 17 +++++++++++++++++\n test-string-list.c                          | 10 ++++++++++\n 5 files changed, 60 insertions(+)\n\ndiff --git a/Documentation/technical/api-string-list.txt b/Documentation/technical/api-string-list.txt\nindex ea65818..dd9aa3d 100644\n--- a/Documentation/technical/api-string-list.txt\n+++ b/Documentation/technical/api-string-list.txt\n@@ -30,6 +30,9 @@ member (you need this if you add things later) and you should set the\n \n . Can sort an unsorted list using `sort_string_list`.\n \n+. Can remove duplicate items from a sorted list using\n+  `string_list_remove_duplicates`.\n+\n . Can remove individual items of an unsorted list using\n   `unsorted_string_list_delete_item`.\n \n@@ -108,6 +111,12 @@ write `string_list_insert(...)->util = ...;`.\n \tLook up a given string in the string_list, returning the containing\n \tstring_list_item. If the string is not found, NULL is returned.\n \n+`string_list_remove_duplicates`::\n+\n+\tRemove all but the first of consecutive entries that have the\n+\tsame string value.  If free_util is true, call free() on the\n+\tutil members of any items that have to be deleted.\n+\n * Functions for unsorted lists only\n \n `string_list_append`::\ndiff --git a/string-list.c b/string-list.c\nindex e0806fb..e9b7fd8 100644\n--- a/string-list.c\n+++ b/string-list.c\n@@ -92,6 +92,23 @@ struct string_list_item *string_list_lookup(struct string_list *list, const char\n \treturn list->items + i;\n }\n \n+void string_list_remove_duplicates(struct string_list *list, int free_util)\n+{\n+\tif (list->nr > 1) {\n+\t\tint src, dst;\n+\t\tfor (src = dst = 1; src < list->nr; src++) {\n+\t\t\tif (!strcmp(list->items[dst - 1].string, list->items[src].string)) {\n+\t\t\t\tif (list->strdup_strings)\n+\t\t\t\t\tfree(list->items[src].string);\n+\t\t\t\tif (free_util)\n+\t\t\t\t\tfree(list->items[src].util);\n+\t\t\t} else\n+\t\t\t\tlist->items[dst++] = list->items[src];\n+\t\t}\n+\t\tlist->nr = dst;\n+\t}\n+}\n+\n int for_each_string_list(struct string_list *list,\n \t\t\t string_list_each_func_t fn, void *cb_data)\n {\ndiff --git a/string-list.h b/string-list.h\nindex 7d18e62..3a6a6dc 100644\n--- a/string-list.h\n+++ b/string-list.h\n@@ -48,6 +48,13 @@ struct string_list_item *string_list_insert_at_index(struct string_list *list,\n \t\t\t\t\t\t     int insert_at, const char *string);\n struct string_list_item *string_list_lookup(struct string_list *list, const char *string);\n \n+/*\n+ * Remove all but the first of consecutive entries with the same\n+ * string value.  If free_util is true, call free() on the util\n+ * members of any items that have to be deleted.\n+ */\n+void string_list_remove_duplicates(struct string_list *sorted_list, int free_util);\n+\n \n /* Use these functions only on unsorted lists: */\n \ndiff --git a/t/t0063-string-list.sh b/t/t0063-string-list.sh\nindex a5f05cd..dbfc05e 100755\n--- a/t/t0063-string-list.sh\n+++ b/t/t0063-string-list.sh\n@@ -71,4 +71,21 @@ test_expect_success \"test filter_string_list\" '\n \ttest \"x-\" = \"x$(test-string-list filter x1:x2 y)\"\n '\n \n+test_expect_success \"test remove_duplicates\" '\n+\ttest \"x-\" = \"x$(test-string-list remove_duplicates -)\" &&\n+\ttest \"x\" = \"x$(test-string-list remove_duplicates \"\")\" &&\n+\ttest a = \"$(test-string-list remove_duplicates a)\" &&\n+\ttest a = \"$(test-string-list remove_duplicates a:a)\" &&\n+\ttest a = \"$(test-string-list remove_duplicates a:a:a:a:a)\" &&\n+\ttest a:b = \"$(test-string-list remove_duplicates a:b)\" &&\n+\ttest a:b = \"$(test-string-list remove_duplicates a:a:b)\" &&\n+\ttest a:b = \"$(test-string-list remove_duplicates a:b:b)\" &&\n+\ttest a:b:c = \"$(test-string-list remove_duplicates a:b:c)\" &&\n+\ttest a:b:c = \"$(test-string-list remove_duplicates a:a:b:c)\" &&\n+\ttest a:b:c = \"$(test-string-list remove_duplicates a:b:b:c)\" &&\n+\ttest a:b:c = \"$(test-string-list remove_duplicates a:b:c:c)\" &&\n+\ttest a:b:c = \"$(test-string-list remove_duplicates a:a:b:b:c:c)\" &&\n+\ttest a:b:c = \"$(test-string-list remove_duplicates a:a:a:b:b:b:c:c:c)\"\n+'\n+\n test_done\ndiff --git a/test-string-list.c b/test-string-list.c\nindex 702276c..2d6eda7 100644\n--- a/test-string-list.c\n+++ b/test-string-list.c\n@@ -87,6 +87,16 @@ int main(int argc, char **argv)\n \t\treturn 0;\n \t}\n \n+\tif (argc == 3 && !strcmp(argv[1], \"remove_duplicates\")) {\n+\t\tstruct string_list list = STRING_LIST_INIT_DUP;\n+\n+\t\tparse_string_list(&list, argv[2]);\n+\t\tstring_list_remove_duplicates(&list, 0);\n+\t\twrite_list_compact(&list);\n+\t\tstring_list_clear(&list, 0);\n+\t\treturn 0;\n+\t}\n+\n \tfprintf(stderr, \"%s: unknown function name: %s\\n\", argv[0],\n \t\targv[1] ? argv[1] : \"(there was none)\");\n \treturn 1;\n-- \n1.7.11.3\n"},{"id":"198737","messageId":"1347311926-5207-6-git-send-email-mhagger@alum.mit.edu","threadId":"31494","inReplyTo":"1347311926-5207-1-git-send-email-mhagger@alum.mit.edu","subject":"[PATCH v2 5/6] string_list: add a function string_list_longest_prefix()","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2012-09-10T21:18:45Z","receivedAt":"2012-09-10T21:18:45Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"Add a function that finds the longest string from a string_list that\nis a prefix of a given string.\n\nSigned-off-by: Michael Haggerty <mhagger@alum.mit.edu>\n---\n Documentation/technical/api-string-list.txt |  8 ++++++++\n string-list.c                               | 20 +++++++++++++++++++\n string-list.h                               |  8 ++++++++\n t/t0063-string-list.sh                      | 30 +++++++++++++++++++++++++++++\n test-string-list.c                          | 20 +++++++++++++++++++\n 5 files changed, 86 insertions(+)\n\ndiff --git a/Documentation/technical/api-string-list.txt b/Documentation/technical/api-string-list.txt\nindex dd9aa3d..231a877 100644\n--- a/Documentation/technical/api-string-list.txt\n+++ b/Documentation/technical/api-string-list.txt\n@@ -75,6 +75,14 @@ Functions\n \tto be deleted.  Preserve the order of the items that are\n \tretained.\n \n+`string_list_longest_prefix`::\n+\n+\tReturn the longest string within a string_list that is a\n+\tprefix (in the sense of prefixcmp()) of the specified string,\n+\tor NULL if no such prefix exists.  This function does not\n+\trequire the string_list to be sorted (it does a linear\n+\tsearch).\n+\n `print_string_list`::\n \n \tDump a string_list to stdout, useful mainly for debugging purposes. It\ndiff --git a/string-list.c b/string-list.c\nindex e9b7fd8..0b1f00a 100644\n--- a/string-list.c\n+++ b/string-list.c\n@@ -136,6 +136,26 @@ void filter_string_list(struct string_list *list, int free_util,\n \tlist->nr = dst;\n }\n \n+char *string_list_longest_prefix(const struct string_list *prefixes,\n+\t\t\t\t const char *string)\n+{\n+\tint i, max_len = -1;\n+\tchar *retval = NULL;\n+\n+\tfor (i = 0; i < prefixes->nr; i++) {\n+\t\tchar *prefix = prefixes->items[i].string;\n+\t\tif (!prefixcmp(string, prefix)) {\n+\t\t\tint len = strlen(prefix);\n+\t\t\tif (len > max_len) {\n+\t\t\t\tretval = prefix;\n+\t\t\t\tmax_len = len;\n+\t\t\t}\n+\t\t}\n+\t}\n+\n+\treturn retval;\n+}\n+\n void string_list_clear(struct string_list *list, int free_util)\n {\n \tif (list->items) {\ndiff --git a/string-list.h b/string-list.h\nindex 3a6a6dc..5efd07b 100644\n--- a/string-list.h\n+++ b/string-list.h\n@@ -38,6 +38,14 @@ int for_each_string_list(struct string_list *list,\n void filter_string_list(struct string_list *list, int free_util,\n \t\t\tstring_list_each_func_t want, void *cb_data);\n \n+/*\n+ * Return the longest string in prefixes that is a prefix (in the\n+ * sense of prefixcmp()) of string, or NULL if no such prefix exists.\n+ * This function does not require the string_list to be sorted (it\n+ * does a linear search).\n+ */\n+char *string_list_longest_prefix(const struct string_list *prefixes, const char *string);\n+\n \n /* Use these functions only on sorted lists: */\n int string_list_has_string(const struct string_list *list, const char *string);\ndiff --git a/t/t0063-string-list.sh b/t/t0063-string-list.sh\nindex dbfc05e..41c8826 100755\n--- a/t/t0063-string-list.sh\n+++ b/t/t0063-string-list.sh\n@@ -17,6 +17,14 @@ test_split () {\n \t\"\n }\n \n+test_longest_prefix () {\n+\ttest \"$(test-string-list longest_prefix \"$1\" \"$2\")\" = \"$3\"\n+}\n+\n+test_no_longest_prefix () {\n+\ttest_must_fail test-string-list longest_prefix \"$1\" \"$2\"\n+}\n+\n test_split \"foo:bar:baz\" \":\" \"-1\" <<EOF\n 3\n [0]: \"foo\"\n@@ -88,4 +96,26 @@ test_expect_success \"test remove_duplicates\" '\n \ttest a:b:c = \"$(test-string-list remove_duplicates a:a:a:b:b:b:c:c:c)\"\n '\n \n+test_expect_success \"test longest_prefix\" '\n+\ttest_no_longest_prefix - '' &&\n+\ttest_no_longest_prefix - x &&\n+\ttest_longest_prefix \"\" x \"\" &&\n+\ttest_longest_prefix x x x &&\n+\ttest_longest_prefix \"\" foo \"\" &&\n+\ttest_longest_prefix : foo \"\" &&\n+\ttest_longest_prefix f foo f &&\n+\ttest_longest_prefix foo foobar foo &&\n+\ttest_longest_prefix foo foo foo &&\n+\ttest_no_longest_prefix bar foo &&\n+\ttest_no_longest_prefix bar:bar foo &&\n+\ttest_no_longest_prefix foobar foo &&\n+\ttest_longest_prefix foo:bar foo foo &&\n+\ttest_longest_prefix foo:bar bar bar &&\n+\ttest_longest_prefix foo::bar foo foo &&\n+\ttest_longest_prefix foo:foobar foo foo &&\n+\ttest_longest_prefix foobar:foo foo foo &&\n+\ttest_longest_prefix foo: bar \"\" &&\n+\ttest_longest_prefix :foo bar \"\"\n+'\n+\n test_done\ndiff --git a/test-string-list.c b/test-string-list.c\nindex 2d6eda7..5e9631f 100644\n--- a/test-string-list.c\n+++ b/test-string-list.c\n@@ -97,6 +97,26 @@ int main(int argc, char **argv)\n \t\treturn 0;\n \t}\n \n+\tif (argc == 4 && !strcmp(argv[1], \"longest_prefix\")) {\n+\t\t/* arguments: <colon-separated-prefixes>|- <string> */\n+\t\tstruct string_list prefixes = STRING_LIST_INIT_DUP;\n+\t\tint retval;\n+\t\tconst char *prefix_string = argv[2];\n+\t\tconst char *string = argv[3];\n+\t\tconst char *match;\n+\n+\t\tparse_string_list(&prefixes, prefix_string);\n+\t\tmatch = string_list_longest_prefix(&prefixes, string);\n+\t\tif (match) {\n+\t\t\tprintf(\"%s\\n\", match);\n+\t\t\tretval = 0;\n+\t\t}\n+\t\telse\n+\t\t\tretval = 1;\n+\t\tstring_list_clear(&prefixes, 0);\n+\t\treturn retval;\n+\t}\n+\n \tfprintf(stderr, \"%s: unknown function name: %s\\n\", argv[0],\n \t\targv[1] ? argv[1] : \"(there was none)\");\n \treturn 1;\n-- \n1.7.11.3\n"},{"id":"198738","messageId":"1347311926-5207-7-git-send-email-mhagger@alum.mit.edu","threadId":"31494","inReplyTo":"1347311926-5207-1-git-send-email-mhagger@alum.mit.edu","subject":"[PATCH v2 6/6] api-string-list.txt: initialize the string_list the easy way","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2012-09-10T21:18:46Z","receivedAt":"2012-09-10T21:18:46Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"In the demo code blurb, show how to initialize the string_list using\nSTRING_LIST_INIT_NODUP rather than memset().\n\nSigned-off-by: Michael Haggerty <mhagger@alum.mit.edu>\n---\n Documentation/technical/api-string-list.txt | 3 +--\n 1 file changed, 1 insertion(+), 2 deletions(-)\n\ndiff --git a/Documentation/technical/api-string-list.txt b/Documentation/technical/api-string-list.txt\nindex 231a877..88330ff 100644\n--- a/Documentation/technical/api-string-list.txt\n+++ b/Documentation/technical/api-string-list.txt\n@@ -44,10 +44,9 @@ member (you need this if you add things later) and you should set the\n Example:\n \n ----\n-struct string_list list;\n+struct string_list list = STRING_LIST_INIT_NODUP;\n int i;\n \n-memset(&list, 0, sizeof(struct string_list));\n string_list_append(&list, \"foo\");\n string_list_append(&list, \"bar\");\n for (i = 0; i < list.nr; i++)\n-- \n1.7.11.3\n"},{"id":"198744","messageId":"7vpq5tleyo.fsf@alter.siamese.dyndns.org","threadId":"31494","inReplyTo":"1347311926-5207-2-git-send-email-mhagger@alum.mit.edu","subject":"Re: [PATCH v2 1/6] string_list: add function string_list_append_nodup()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-09-10T21:56:15Z","receivedAt":"2012-09-10T21:56:15Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Michael Haggerty <mhagger@alum.mit.edu> writes:\n\n> diff --git a/string-list.c b/string-list.c\n> index d9810ab..5594b7d 100644\n> --- a/string-list.c\n> +++ b/string-list.c\n> @@ -148,13 +148,23 @@ void print_string_list(const struct string_list *p, const char *text)\n>  \t\tprintf(\"%s:%p\\n\", p->items[i].string, p->items[i].util);\n>  }\n>  \n> -struct string_list_item *string_list_append(struct string_list *list, const char *string)\n> +struct string_list_item *string_list_append_nodup(struct string_list *list,\n> +\t\t\t\t\t\t  char *string)\n>  {\n> +\tstruct string_list_item *retval;\n>  \tALLOC_GROW(list->items, list->nr + 1, list->alloc);\n> -\tlist->items[list->nr].string =\n> -\t\tlist->strdup_strings ? xstrdup(string) : (char *)string;\n> -\tlist->items[list->nr].util = NULL;\n> -\treturn list->items + list->nr++;\n> +\tretval = &list->items[list->nr++];\n> +\tretval->string = (char *)string;\n\nDo you still need this cast, now the function takes non-const \"char *string\"?\n"},{"id":"198747","messageId":"7vlighlerf.fsf@alter.siamese.dyndns.org","threadId":"31494","inReplyTo":"1347311926-5207-3-git-send-email-mhagger@alum.mit.edu","subject":"Re: [PATCH v2 2/6] string_list: add two new functions for splitting strings","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-09-10T22:00:36Z","receivedAt":"2012-09-10T22:00:36Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Michael Haggerty <mhagger@alum.mit.edu> writes:\n\n> diff --git a/string-list.c b/string-list.c\n> index 5594b7d..f9051ec 100644\n> --- a/string-list.c\n> +++ b/string-list.c\n> @@ -204,3 +204,52 @@ void unsorted_string_list_delete_item(struct string_list *list, int i, int free_\n>  \tlist->items[i] = list->items[list->nr-1];\n>  \tlist->nr--;\n>  }\n> +\n> +int string_list_split(struct string_list *list, const char *string,\n> +\t\t      int delim, int maxsplit)\n> +{\n> +\tint count = 0;\n> +\tconst char *p = string, *end;\n> +\n> +\tassert(list->strdup_strings);\n\nThis may be a taste thing, but I'd prefer to see assert() only for\nverification of pre-condition by internal callers to catch stupid\nprogramming errors.  For a library-ish function like sl_split() that\nexpects to be called from anybody outside the string-list API, a\nviolation of this pre-condition is a usage error of the API, and\nshould trigger a runtime error (even without NDEBUG), no?\n"},{"id":"198748","messageId":"504E63B1.2070100@alum.mit.edu","threadId":"31494","inReplyTo":"7vpq5tleyo.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH v2 1/6] string_list: add function string_list_append_nodup()","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2012-09-10T22:03:29Z","receivedAt":"2012-09-10T22:03:29Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"On 09/10/2012 11:56 PM, Junio C Hamano wrote:\n> Michael Haggerty <mhagger@alum.mit.edu> writes:\n> \n>> diff --git a/string-list.c b/string-list.c\n>> index d9810ab..5594b7d 100644\n>> --- a/string-list.c\n>> +++ b/string-list.c\n>> @@ -148,13 +148,23 @@ void print_string_list(const struct string_list *p, const char *text)\n>>  \t\tprintf(\"%s:%p\\n\", p->items[i].string, p->items[i].util);\n>>  }\n>>  \n>> -struct string_list_item *string_list_append(struct string_list *list, const char *string)\n>> +struct string_list_item *string_list_append_nodup(struct string_list *list,\n>> +\t\t\t\t\t\t  char *string)\n>>  {\n>> +\tstruct string_list_item *retval;\n>>  \tALLOC_GROW(list->items, list->nr + 1, list->alloc);\n>> -\tlist->items[list->nr].string =\n>> -\t\tlist->strdup_strings ? xstrdup(string) : (char *)string;\n>> -\tlist->items[list->nr].util = NULL;\n>> -\treturn list->items + list->nr++;\n>> +\tretval = &list->items[list->nr++];\n>> +\tretval->string = (char *)string;\n> \n> Do you still need this cast, now the function takes non-const \"char *string\"?\n\nGood catch.  Do you want to fix this in your repo or should I re-roll?\n\nMichael\n\n-- \nMichael Haggerty\nmhagger@alum.mit.edu\nhttp://softwareswirl.blogspot.com/\n"},{"id":"198751","messageId":"7v8vchld82.fsf@alter.siamese.dyndns.org","threadId":"31494","inReplyTo":"1347311926-5207-3-git-send-email-mhagger@alum.mit.edu","subject":"Re: [PATCH v2 2/6] string_list: add two new functions for splitting strings","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-09-10T22:33:49Z","receivedAt":"2012-09-10T22:33:49Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Michael Haggerty <mhagger@alum.mit.edu> writes:\n\n> +`string_list_split`, `string_list_split_in_place`::\n> +\n> +\tSplit a string into substrings on a delimiter character and\n> +\tappend the substrings to a `string_list`.  If `maxsplit` is\n> +\tnon-negative, then split at most `maxsplit` times.  Return the\n> +\tnumber of substrings appended to the list.\n\n\nI recall that we favor\n\n`A`::\n`B`::\n\n\tDescription for A and B\n\nfor some reason but do not remember exactly why.\n"},{"id":"198832","messageId":"50508A44.1020008@alum.mit.edu","threadId":"31494","inReplyTo":"7v8vchld82.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH v2 2/6] string_list: add two new functions for splitting strings","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2012-09-12T13:12:36Z","receivedAt":"2012-09-12T13:12:36Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"On 09/11/2012 12:33 AM, Junio C Hamano wrote:\n> Michael Haggerty <mhagger@alum.mit.edu> writes:\n> \n>> +`string_list_split`, `string_list_split_in_place`::\n>> +\n>> +\tSplit a string into substrings on a delimiter character and\n>> +\tappend the substrings to a `string_list`.  If `maxsplit` is\n>> +\tnon-negative, then split at most `maxsplit` times.  Return the\n>> +\tnumber of substrings appended to the list.\n> \n> \n> I recall that we favor\n> \n> `A`::\n> `B`::\n> \n> \tDescription for A and B\n> \n> for some reason but do not remember exactly why.\n\nWill change.  Thanks.\n\nMichael\n\n-- \nMichael Haggerty\nmhagger@alum.mit.edu\nhttp://softwareswirl.blogspot.com/\n"},{"id":"198834","messageId":"50508F01.1030001@alum.mit.edu","threadId":"31494","inReplyTo":"7vpq5tleyo.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH v2 1/6] string_list: add function string_list_append_nodup()","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2012-09-12T13:32:49Z","receivedAt":"2012-09-12T13:32:49Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"On 09/10/2012 11:56 PM, Junio C Hamano wrote:\n> Michael Haggerty <mhagger@alum.mit.edu> writes:\n> \n>> diff --git a/string-list.c b/string-list.c\n>> index d9810ab..5594b7d 100644\n>> --- a/string-list.c\n>> +++ b/string-list.c\n>> @@ -148,13 +148,23 @@ void print_string_list(const struct string_list *p, const char *text)\n>>  \t\tprintf(\"%s:%p\\n\", p->items[i].string, p->items[i].util);\n>>  }\n>>  \n>> -struct string_list_item *string_list_append(struct string_list *list, const char *string)\n>> +struct string_list_item *string_list_append_nodup(struct string_list *list,\n>> +\t\t\t\t\t\t  char *string)\n>>  {\n>> +\tstruct string_list_item *retval;\n>>  \tALLOC_GROW(list->items, list->nr + 1, list->alloc);\n>> -\tlist->items[list->nr].string =\n>> -\t\tlist->strdup_strings ? xstrdup(string) : (char *)string;\n>> -\tlist->items[list->nr].util = NULL;\n>> -\treturn list->items + list->nr++;\n>> +\tretval = &list->items[list->nr++];\n>> +\tretval->string = (char *)string;\n> \n> Do you still need this cast, now the function takes non-const \"char *string\"?\n\nThanks.  Fixed in forthcoming re-roll.\n\nMichael\n\n-- \nMichael Haggerty\nmhagger@alum.mit.edu\nhttp://softwareswirl.blogspot.com/\n"},{"id":"198861","messageId":"7vtxv3ceia.fsf@alter.siamese.dyndns.org","threadId":"31494","inReplyTo":"50508A44.1020008@alum.mit.edu","subject":"Re: [PATCH v2 2/6] string_list: add two new functions for splitting strings","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-09-12T17:55:25Z","receivedAt":"2012-09-12T17:55:25Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Michael Haggerty <mhagger@alum.mit.edu> writes:\n\n> On 09/11/2012 12:33 AM, Junio C Hamano wrote:\n>> Michael Haggerty <mhagger@alum.mit.edu> writes:\n>> \n>>> +`string_list_split`, `string_list_split_in_place`::\n>>> +\n>>> +\tSplit a string into substrings on a delimiter character and\n>>> +\tappend the substrings to a `string_list`.  If `maxsplit` is\n>>> +\tnon-negative, then split at most `maxsplit` times.  Return the\n>>> +\tnumber of substrings appended to the list.\n>> \n>> \n>> I recall that we favor\n>> \n>> `A`::\n>> `B`::\n>> \n>> \tDescription for A and B\n>> \n>> for some reason but do not remember exactly why.\n>\n> Will change.  Thanks.\n\nThanks.  It comes from this one:\n\ncommit bf474e2402e51843e8230c064da6ccfdf3a8ff54\nAuthor: Markus Heidelberg <markus.heidelberg@web.de>\nDate:   Fri Jan 16 22:42:33 2009 +0100\n\n    Documentation: let asciidoc align related options\n    \n    Command line options can share the same paragraph of description, if\n    they are related or synonymous. In these cases they should be\n    written among each other, so that asciidoc can format them itself.\n    \n    Signed-off-by: Markus Heidelberg <markus.heidelberg@web.de>\n    Signed-off-by: Junio C Hamano <gitster@pobox.com>\n"}]}