string-list: optionally trim string pieces split by string_list_split*()
Teach the unified split_string() to take an optional "flags" word, and define the first flag STRING_LIST_SPLIT_TRIM to cause the split pieces to be trimmed before they are placed in the string list. Signed-off-by: Junio C Hamano <gitster@pobox.com>
Junio C Hamano committed
Aug 1, 2025 at 15:04 UTC
576454974165d51b7e39c0608cde1c84978f1a8a
3 files changed
+109
-5
string-list.c
+30
-5
@@ -282,11 +282,18 @@ void unsorted_string_list_delete_item(struct string_list *list, int i, int free_
282
*/
283
static int append_one(struct string_list *list,
284
const char *p, const char *end,
285
- int in_place)
285
+ int in_place, unsigned flags)
286
{
287
if (!end)
288
end = p + strlen(p);
289
290
+ if ((flags & STRING_LIST_SPLIT_TRIM)) {
291
+ /* rtrim */
292
+ for (; p < end; end--)
293
+ if (!isspace(end[-1]))
294
+ break;
295
+ }
296
+
297
if (in_place) {
298
*((char *)end) = '\0';
299
string_list_append(list, p);
@@ -307,7 +314,7 @@ static int append_one(struct string_list *list,
314
* returns "char *" pointer into that const string. Yucky but works ;-).
315
*/
316
static int split_string(struct string_list *list, const char *string, const char *delim,
310
- int maxsplit, int in_place)
317
+ int maxsplit, int in_place, unsigned flags)
318
{
319
int count = 0;
320
const char *p = string;
@@ -320,12 +327,18 @@ static int split_string(struct string_list *list, const char *string, const char
327
for (;;) {
328
char *end;
329
330
+ if (flags & STRING_LIST_SPLIT_TRIM) {
331
+ /* ltrim */
332
+ while (*p && isspace(*p))
333
+ p++;
334
+ }
335
+
336
if (0 <= maxsplit && maxsplit <= count)
337
end = NULL;
338
else
339
end = strpbrk(p, delim);
340
328
- count += append_one(list, p, end, in_place);
341
+ count += append_one(list, p, end, in_place, flags);
342
343
if (!end)
344
return count;
@@ -336,11 +349,23 @@ static int split_string(struct string_list *list, const char *string, const char
349
int string_list_split(struct string_list *list, const char *string,
350
const char *delim, int maxsplit)
351
{
339
- return split_string(list, string, delim, maxsplit, 0);
352
+ return split_string(list, string, delim, maxsplit, 0, 0);
353
}
354
355
int string_list_split_in_place(struct string_list *list, char *string,
356
const char *delim, int maxsplit)
357
{
345
- return split_string(list, string, delim, maxsplit, 1);
358
+ return split_string(list, string, delim, maxsplit, 1, 0);
359
+}
360
+
361
+int string_list_split_f(struct string_list *list, const char *string,
362
+ const char *delim, int maxsplit, unsigned flags)
363
+{
364
+ return split_string(list, string, delim, maxsplit, 0, flags);
365
+}
366
+
367
+int string_list_split_in_place_f(struct string_list *list, char *string,
368
+ const char *delim, int maxsplit, unsigned flags)
369
+{
370
+ return split_string(list, string, delim, maxsplit, 1, flags);
371
}
string-list.h
+15
@@ -281,4 +281,19 @@ int string_list_split(struct string_list *list, const char *string,
281
*/
282
int string_list_split_in_place(struct string_list *list, char *string,
283
const char *delim, int maxsplit);
284
+
285
+/* Flag bits for split_f and split_in_place_f functions */
286
+enum {
287
+ /*
288
+ * trim whitespaces around resulting string piece before adding
289
+ * it to the list
290
+ */
291
+ STRING_LIST_SPLIT_TRIM = (1 << 0),
292
+};
293
+
294
+int string_list_split_f(struct string_list *, const char *string,
295
+ const char *delim, int maxsplit, unsigned flags);
296
+
297
+int string_list_split_in_place_f(struct string_list *, char *string,
298
+ const char *delim, int maxsplit, unsigned flags);
299
#endif /* STRING_LIST_H */
t/unit-tests/u-string-list.c
+64
@@ -63,6 +63,70 @@ static void t_string_list_split(const char *data, const char *delim, int maxspli
63
string_list_clear(&list, 0);
64
}
65
66
+static void t_string_list_split_f(const char *data, const char *delim,
67
+ int maxsplit, unsigned flags, ...)
68
+{
69
+ struct string_list expected_strings = STRING_LIST_INIT_DUP;
70
+ struct string_list list = STRING_LIST_INIT_DUP;
71
+ va_list ap;
72
+ int len;
73
+
74
+ va_start(ap, flags);
75
+ t_vcreate_string_list_dup(&expected_strings, 0, ap);
76
+ va_end(ap);
77
+
78
+ string_list_clear(&list, 0);
79
+ len = string_list_split_f(&list, data, delim, maxsplit, flags);
80
+ cl_assert_equal_i(len, expected_strings.nr);
81
+ t_string_list_equal(&list, &expected_strings);
82
+
83
+ string_list_clear(&expected_strings, 0);
84
+ string_list_clear(&list, 0);
85
+}
86
+
87
+void test_string_list__split_f(void)
88
+{
89
+ t_string_list_split_f("::foo:bar:baz:", ":", -1, 0,
90
+ "", "", "foo", "bar", "baz", "", NULL);
91
+ t_string_list_split_f(" foo:bar : baz", ":", -1, STRING_LIST_SPLIT_TRIM,
92
+ "foo", "bar", "baz", NULL);
93
+ t_string_list_split_f(" a b c ", " ", 1, STRING_LIST_SPLIT_TRIM,
94
+ "a", "b c", NULL);
95
+}
96
+
97
+static void t_string_list_split_in_place_f(const char *data_, const char *delim,
98
+ int maxsplit, unsigned flags, ...)
99
+{
100
+ struct string_list expected_strings = STRING_LIST_INIT_DUP;
101
+ struct string_list list = STRING_LIST_INIT_NODUP;
102
+ char *data = xstrdup(data_);
103
+ va_list ap;
104
+ int len;
105
+
106
+ va_start(ap, flags);
107
+ t_vcreate_string_list_dup(&expected_strings, 0, ap);
108
+ va_end(ap);
109
+
110
+ string_list_clear(&list, 0);
111
+ len = string_list_split_in_place_f(&list, data, delim, maxsplit, flags);
112
+ cl_assert_equal_i(len, expected_strings.nr);
113
+ t_string_list_equal(&list, &expected_strings);
114
+
115
+ free(data);
116
+ string_list_clear(&expected_strings, 0);
117
+ string_list_clear(&list, 0);
118
+}
119
+
120
+void test_string_list__split_in_place_f(void)
121
+{
122
+ t_string_list_split_in_place_f("::foo:bar:baz:", ":", -1, 0,
123
+ "", "", "foo", "bar", "baz", "", NULL);
124
+ t_string_list_split_in_place_f(" foo:bar : baz", ":", -1, STRING_LIST_SPLIT_TRIM,
125
+ "foo", "bar", "baz", NULL);
126
+ t_string_list_split_in_place_f(" a b c ", " ", 1, STRING_LIST_SPLIT_TRIM,
127
+ "a", "b c", NULL);
128
+}
129
+
130
void test_string_list__split(void)
131
{
132
t_string_list_split("foo:bar:baz", ":", -1, "foo", "bar", "baz", NULL);