Skip to content

Commit 3b0b6b5

Browse files
committed
Merge branch 'mh/string-list'
* mh/string-list: api-string-list.txt: initialize the string_list the easy way string_list: add a function string_list_longest_prefix() string_list: add a new function, string_list_remove_duplicates() string_list: add a new function, filter_string_list() string_list: add two new functions for splitting strings string_list: add function string_list_append_nodup()
2 parents 992311c + 51f3145 commit 3b0b6b5

File tree

7 files changed

+502
-10
lines changed

7 files changed

+502
-10
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,7 @@
194194
/test-run-command
195195
/test-sha1
196196
/test-sigchain
197+
/test-string-list
197198
/test-subprocess
198199
/test-svn-fe
199200
/common-cmds.h

Documentation/technical/api-string-list.txt

Lines changed: 63 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,27 +20,33 @@ If you need something advanced, you can manually malloc() the `items`
2020
member (you need this if you add things later) and you should set the
2121
`nr` and `alloc` members in that case, too.
2222

23-
. Adds new items to the list, using `string_list_append` or
24-
`string_list_insert`.
23+
. Adds new items to the list, using `string_list_append`,
24+
`string_list_append_nodup`, `string_list_insert`,
25+
`string_list_split`, and/or `string_list_split_in_place`.
2526

2627
. Can check if a string is in the list using `string_list_has_string` or
2728
`unsorted_string_list_has_string` and get it from the list using
2829
`string_list_lookup` for sorted lists.
2930

3031
. Can sort an unsorted list using `sort_string_list`.
3132

33+
. Can remove duplicate items from a sorted list using
34+
`string_list_remove_duplicates`.
35+
3236
. Can remove individual items of an unsorted list using
3337
`unsorted_string_list_delete_item`.
3438

39+
. Can remove items not matching a criterion from a sorted or unsorted
40+
list using `filter_string_list`.
41+
3542
. Finally it should free the list using `string_list_clear`.
3643

3744
Example:
3845

3946
----
40-
struct string_list list;
47+
struct string_list list = STRING_LIST_INIT_NODUP;
4148
int i;
4249

43-
memset(&list, 0, sizeof(struct string_list));
4450
string_list_append(&list, "foo");
4551
string_list_append(&list, "bar");
4652
for (i = 0; i < list.nr; i++)
@@ -60,6 +66,22 @@ Functions
6066

6167
* General ones (works with sorted and unsorted lists as well)
6268

69+
`filter_string_list`::
70+
71+
Apply a function to each item in a list, retaining only the
72+
items for which the function returns true. If free_util is
73+
true, call free() on the util members of any items that have
74+
to be deleted. Preserve the order of the items that are
75+
retained.
76+
77+
`string_list_longest_prefix`::
78+
79+
Return the longest string within a string_list that is a
80+
prefix (in the sense of prefixcmp()) of the specified string,
81+
or NULL if no such prefix exists. This function does not
82+
require the string_list to be sorted (it does a linear
83+
search).
84+
6385
`print_string_list`::
6486

6587
Dump a string_list to stdout, useful mainly for debugging purposes. It
@@ -96,11 +118,28 @@ write `string_list_insert(...)->util = ...;`.
96118
Look up a given string in the string_list, returning the containing
97119
string_list_item. If the string is not found, NULL is returned.
98120

121+
`string_list_remove_duplicates`::
122+
123+
Remove all but the first of consecutive entries that have the
124+
same string value. If free_util is true, call free() on the
125+
util members of any items that have to be deleted.
126+
99127
* Functions for unsorted lists only
100128

101129
`string_list_append`::
102130

103-
Append a new string to the end of the string_list.
131+
Append a new string to the end of the string_list. If
132+
`strdup_string` is set, then the string argument is copied;
133+
otherwise the new `string_list_entry` refers to the input
134+
string.
135+
136+
`string_list_append_nodup`::
137+
138+
Append a new string to the end of the string_list. The new
139+
`string_list_entry` always refers to the input string, even if
140+
`strdup_string` is set. This function can be used to hand
141+
ownership of a malloc()ed string to a `string_list` that has
142+
`strdup_string` set.
104143

105144
`sort_string_list`::
106145

@@ -124,6 +163,25 @@ counterpart for sorted lists, which performs a binary search.
124163
is set. The third parameter controls if the `util` pointer of the
125164
items should be freed or not.
126165

166+
`string_list_split`::
167+
`string_list_split_in_place`::
168+
169+
Split a string into substrings on a delimiter character and
170+
append the substrings to a `string_list`. If `maxsplit` is
171+
non-negative, then split at most `maxsplit` times. Return the
172+
number of substrings appended to the list.
173+
+
174+
`string_list_split` requires a `string_list` that has `strdup_strings`
175+
set to true; it leaves the input string untouched and makes copies of
176+
the substrings in newly-allocated memory.
177+
`string_list_split_in_place` requires a `string_list` that has
178+
`strdup_strings` set to false; it splits the input string in place,
179+
overwriting the delimiter characters with NULs and creating new
180+
string_list_items that point into the original string (the original
181+
string must therefore not be modified or freed while the `string_list`
182+
is in use).
183+
184+
127185
Data structures
128186
---------------
129187

Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -509,6 +509,7 @@ TEST_PROGRAMS_NEED_X += test-run-command
509509
TEST_PROGRAMS_NEED_X += test-scrap-cache-tree
510510
TEST_PROGRAMS_NEED_X += test-sha1
511511
TEST_PROGRAMS_NEED_X += test-sigchain
512+
TEST_PROGRAMS_NEED_X += test-string-list
512513
TEST_PROGRAMS_NEED_X += test-subprocess
513514
TEST_PROGRAMS_NEED_X += test-svn-fe
514515

string-list.c

Lines changed: 122 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,23 @@ struct string_list_item *string_list_lookup(struct string_list *list, const char
9292
return list->items + i;
9393
}
9494

95+
void string_list_remove_duplicates(struct string_list *list, int free_util)
96+
{
97+
if (list->nr > 1) {
98+
int src, dst;
99+
for (src = dst = 1; src < list->nr; src++) {
100+
if (!strcmp(list->items[dst - 1].string, list->items[src].string)) {
101+
if (list->strdup_strings)
102+
free(list->items[src].string);
103+
if (free_util)
104+
free(list->items[src].util);
105+
} else
106+
list->items[dst++] = list->items[src];
107+
}
108+
list->nr = dst;
109+
}
110+
}
111+
95112
int for_each_string_list(struct string_list *list,
96113
string_list_each_func_t fn, void *cb_data)
97114
{
@@ -102,6 +119,43 @@ int for_each_string_list(struct string_list *list,
102119
return ret;
103120
}
104121

122+
void filter_string_list(struct string_list *list, int free_util,
123+
string_list_each_func_t want, void *cb_data)
124+
{
125+
int src, dst = 0;
126+
for (src = 0; src < list->nr; src++) {
127+
if (want(&list->items[src], cb_data)) {
128+
list->items[dst++] = list->items[src];
129+
} else {
130+
if (list->strdup_strings)
131+
free(list->items[src].string);
132+
if (free_util)
133+
free(list->items[src].util);
134+
}
135+
}
136+
list->nr = dst;
137+
}
138+
139+
char *string_list_longest_prefix(const struct string_list *prefixes,
140+
const char *string)
141+
{
142+
int i, max_len = -1;
143+
char *retval = NULL;
144+
145+
for (i = 0; i < prefixes->nr; i++) {
146+
char *prefix = prefixes->items[i].string;
147+
if (!prefixcmp(string, prefix)) {
148+
int len = strlen(prefix);
149+
if (len > max_len) {
150+
retval = prefix;
151+
max_len = len;
152+
}
153+
}
154+
}
155+
156+
return retval;
157+
}
158+
105159
void string_list_clear(struct string_list *list, int free_util)
106160
{
107161
if (list->items) {
@@ -148,13 +202,23 @@ void print_string_list(const struct string_list *p, const char *text)
148202
printf("%s:%p\n", p->items[i].string, p->items[i].util);
149203
}
150204

151-
struct string_list_item *string_list_append(struct string_list *list, const char *string)
205+
struct string_list_item *string_list_append_nodup(struct string_list *list,
206+
char *string)
152207
{
208+
struct string_list_item *retval;
153209
ALLOC_GROW(list->items, list->nr + 1, list->alloc);
154-
list->items[list->nr].string =
155-
list->strdup_strings ? xstrdup(string) : (char *)string;
156-
list->items[list->nr].util = NULL;
157-
return list->items + list->nr++;
210+
retval = &list->items[list->nr++];
211+
retval->string = string;
212+
retval->util = NULL;
213+
return retval;
214+
}
215+
216+
struct string_list_item *string_list_append(struct string_list *list,
217+
const char *string)
218+
{
219+
return string_list_append_nodup(
220+
list,
221+
list->strdup_strings ? xstrdup(string) : (char *)string);
158222
}
159223

160224
static int cmp_items(const void *a, const void *b)
@@ -194,3 +258,56 @@ void unsorted_string_list_delete_item(struct string_list *list, int i, int free_
194258
list->items[i] = list->items[list->nr-1];
195259
list->nr--;
196260
}
261+
262+
int string_list_split(struct string_list *list, const char *string,
263+
int delim, int maxsplit)
264+
{
265+
int count = 0;
266+
const char *p = string, *end;
267+
268+
if (!list->strdup_strings)
269+
die("internal error in string_list_split(): "
270+
"list->strdup_strings must be set");
271+
for (;;) {
272+
count++;
273+
if (maxsplit >= 0 && count > maxsplit) {
274+
string_list_append(list, p);
275+
return count;
276+
}
277+
end = strchr(p, delim);
278+
if (end) {
279+
string_list_append_nodup(list, xmemdupz(p, end - p));
280+
p = end + 1;
281+
} else {
282+
string_list_append(list, p);
283+
return count;
284+
}
285+
}
286+
}
287+
288+
int string_list_split_in_place(struct string_list *list, char *string,
289+
int delim, int maxsplit)
290+
{
291+
int count = 0;
292+
char *p = string, *end;
293+
294+
if (list->strdup_strings)
295+
die("internal error in string_list_split_in_place(): "
296+
"list->strdup_strings must not be set");
297+
for (;;) {
298+
count++;
299+
if (maxsplit >= 0 && count > maxsplit) {
300+
string_list_append(list, p);
301+
return count;
302+
}
303+
end = strchr(p, delim);
304+
if (end) {
305+
*end = '\0';
306+
string_list_append(list, p);
307+
p = end + 1;
308+
} else {
309+
string_list_append(list, p);
310+
return count;
311+
}
312+
}
313+
}

string-list.h

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,24 @@ int for_each_string_list(struct string_list *list,
2929
#define for_each_string_list_item(item,list) \
3030
for (item = (list)->items; item < (list)->items + (list)->nr; ++item)
3131

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+
* Return the longest string in prefixes that is a prefix (in the
43+
* sense of prefixcmp()) of string, or NULL if no such prefix exists.
44+
* This function does not require the string_list to be sorted (it
45+
* does a linear search).
46+
*/
47+
char *string_list_longest_prefix(const struct string_list *prefixes, const char *string);
48+
49+
3250
/* Use these functions only on sorted lists: */
3351
int string_list_has_string(const struct string_list *list, const char *string);
3452
int string_list_find_insert_index(const struct string_list *list, const char *string,
@@ -38,11 +56,64 @@ struct string_list_item *string_list_insert_at_index(struct string_list *list,
3856
int insert_at, const char *string);
3957
struct string_list_item *string_list_lookup(struct string_list *list, const char *string);
4058

59+
/*
60+
* Remove all but the first of consecutive entries with the same
61+
* string value. If free_util is true, call free() on the util
62+
* members of any items that have to be deleted.
63+
*/
64+
void string_list_remove_duplicates(struct string_list *sorted_list, int free_util);
65+
66+
4167
/* Use these functions only on unsorted lists: */
68+
69+
/*
70+
* Add string to the end of list. If list->strdup_string is set, then
71+
* string is copied; otherwise the new string_list_entry refers to the
72+
* input string.
73+
*/
4274
struct string_list_item *string_list_append(struct string_list *list, const char *string);
75+
76+
/*
77+
* Like string_list_append(), except string is never copied. When
78+
* list->strdup_strings is set, this function can be used to hand
79+
* ownership of a malloc()ed string to list without making an extra
80+
* copy.
81+
*/
82+
struct string_list_item *string_list_append_nodup(struct string_list *list, char *string);
83+
4384
void sort_string_list(struct string_list *list);
4485
int unsorted_string_list_has_string(struct string_list *list, const char *string);
4586
struct string_list_item *unsorted_string_list_lookup(struct string_list *list,
4687
const char *string);
88+
4789
void unsorted_string_list_delete_item(struct string_list *list, int i, int free_util);
90+
91+
/*
92+
* Split string into substrings on character delim and append the
93+
* substrings to list. The input string is not modified.
94+
* list->strdup_strings must be set, as new memory needs to be
95+
* allocated to hold the substrings. If maxsplit is non-negative,
96+
* then split at most maxsplit times. Return the number of substrings
97+
* appended to list.
98+
*
99+
* Examples:
100+
* string_list_split(l, "foo:bar:baz", ':', -1) -> ["foo", "bar", "baz"]
101+
* string_list_split(l, "foo:bar:baz", ':', 0) -> ["foo:bar:baz"]
102+
* string_list_split(l, "foo:bar:baz", ':', 1) -> ["foo", "bar:baz"]
103+
* string_list_split(l, "foo:bar:", ':', -1) -> ["foo", "bar", ""]
104+
* string_list_split(l, "", ':', -1) -> [""]
105+
* string_list_split(l, ":", ':', -1) -> ["", ""]
106+
*/
107+
int string_list_split(struct string_list *list, const char *string,
108+
int delim, int maxsplit);
109+
110+
/*
111+
* Like string_list_split(), except that string is split in-place: the
112+
* delimiter characters in string are overwritten with NULs, and the
113+
* new string_list_items point into string (which therefore must not
114+
* be modified or freed while the string_list is in use).
115+
* list->strdup_strings must *not* be set.
116+
*/
117+
int string_list_split_in_place(struct string_list *list, char *string,
118+
int delim, int maxsplit);
48119
#endif /* STRING_LIST_H */

0 commit comments

Comments
 (0)