string_list: add a new function, filter_string_list()

This function allows entries that don't match a specified criterion to be discarded from a string_list while preserving the order of the remaining entries. Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Michael Haggerty committed Sep 12, 2012 at 16:04 UTC eb5f0c7a616531a024a582b72ca6d8775ff98d46
5 files changed +96
Documentation/technical/api-string-list.txt
+11
@@ -33,6 +33,9 @@ member (you need this if you add things later) and you should set the
33 . Can remove individual items of an unsorted list using
34 `unsorted_string_list_delete_item`.
35
36 +. Can remove items not matching a criterion from a sorted or unsorted
37 + list using `filter_string_list`.
38 +
39 . Finally it should free the list using `string_list_clear`.
40
41 Example:
@@ -61,6 +64,14 @@ Functions
64
65 * General ones (works with sorted and unsorted lists as well)
66
67 +`filter_string_list`::
68 +
69 + Apply a function to each item in a list, retaining only the
70 + items for which the function returns true. If free_util is
71 + true, call free() on the util members of any items that have
72 + to be deleted. Preserve the order of the items that are
73 + retained.
74 +
75 `print_string_list`::
76
77 Dump a string_list to stdout, useful mainly for debugging purposes. It
string-list.c
+17
@@ -102,6 +102,23 @@ int for_each_string_list(struct string_list *list,
102 return ret;
103 }
104
105 +void filter_string_list(struct string_list *list, int free_util,
106 + string_list_each_func_t want, void *cb_data)
107 +{
108 + int src, dst = 0;
109 + for (src = 0; src < list->nr; src++) {
110 + if (want(&list->items[src], cb_data)) {
111 + list->items[dst++] = list->items[src];
112 + } else {
113 + if (list->strdup_strings)
114 + free(list->items[src].string);
115 + if (free_util)
116 + free(list->items[src].util);
117 + }
118 + }
119 + list->nr = dst;
120 +}
121 +
122 void string_list_clear(struct string_list *list, int free_util)
123 {
124 if (list->items) {
string-list.h
+9
@@ -29,6 +29,15 @@ int for_each_string_list(struct string_list *list,
29 #define for_each_string_list_item(item,list) \
30 for (item = (list)->items; item < (list)->items + (list)->nr; ++item)
31
32 +/*
33 + * Apply want to each item in list, retaining only the ones for which
34 + * the function returns true. If free_util is true, call free() on
35 + * the util members of any items that have to be deleted. Preserve
36 + * the order of the items that are retained.
37 + */
38 +void filter_string_list(struct string_list *list, int free_util,
39 + string_list_each_func_t want, void *cb_data);
40 +
41
42 /* Use these functions only on sorted lists: */
43 int string_list_has_string(const struct string_list *list, const char *string);
t/t0063-string-list.sh
+11
@@ -60,4 +60,15 @@ test_split ":" ":" "-1" <<EOF
60 [1]: ""
61 EOF
62
63 +test_expect_success "test filter_string_list" '
64 + test "x-" = "x$(test-string-list filter - y)" &&
65 + test "x-" = "x$(test-string-list filter no y)" &&
66 + test yes = "$(test-string-list filter yes y)" &&
67 + test yes = "$(test-string-list filter no:yes y)" &&
68 + test yes = "$(test-string-list filter yes:no y)" &&
69 + test y1:y2 = "$(test-string-list filter y1:y2 y)" &&
70 + test y2:y1 = "$(test-string-list filter y2:y1 y)" &&
71 + test "x-" = "x$(test-string-list filter x1:x2 y)"
72 +'
73 +
74 test_done
test-string-list.c
+48
@@ -1,6 +1,20 @@
1 #include "cache.h"
2 #include "string-list.h"
3
4 +/*
5 + * Parse an argument into a string list. arg should either be a
6 + * ':'-separated list of strings, or "-" to indicate an empty string
7 + * list (as opposed to "", which indicates a string list containing a
8 + * single empty string). list->strdup_strings must be set.
9 + */
10 +void parse_string_list(struct string_list *list, const char *arg)
11 +{
12 + if (!strcmp(arg, "-"))
13 + return;
14 +
15 + (void)string_list_split(list, arg, ':', -1);
16 +}
17 +
18 void write_list(const struct string_list *list)
19 {
20 int i;
@@ -8,6 +22,25 @@ void write_list(const struct string_list *list)
22 printf("[%d]: \"%s\"\n", i, list->items[i].string);
23 }
24
25 +void write_list_compact(const struct string_list *list)
26 +{
27 + int i;
28 + if (!list->nr)
29 + printf("-\n");
30 + else {
31 + printf("%s", list->items[0].string);
32 + for (i = 1; i < list->nr; i++)
33 + printf(":%s", list->items[i].string);
34 + printf("\n");
35 + }
36 +}
37 +
38 +int prefix_cb(struct string_list_item *item, void *cb_data)
39 +{
40 + const char *prefix = (const char *)cb_data;
41 + return !prefixcmp(item->string, prefix);
42 +}
43 +
44 int main(int argc, char **argv)
45 {
46 if (argc == 5 && !strcmp(argv[1], "split")) {
@@ -39,6 +72,21 @@ int main(int argc, char **argv)
72 return 0;
73 }
74
75 + if (argc == 4 && !strcmp(argv[1], "filter")) {
76 + /*
77 + * Retain only the items that have the specified prefix.
78 + * Arguments: list|- prefix
79 + */
80 + struct string_list list = STRING_LIST_INIT_DUP;
81 + const char *prefix = argv[3];
82 +
83 + parse_string_list(&list, argv[2]);
84 + filter_string_list(&list, 0, prefix_cb, (void *)prefix);
85 + write_list_compact(&list);
86 + string_list_clear(&list, 0);
87 + return 0;
88 + }
89 +
90 fprintf(stderr, "%s: unknown function name: %s\n", argv[0],
91 argv[1] ? argv[1] : "(there was none)");
92 return 1;