string-list: unify string_list_split* functions

Thanks to the previous step, the only difference between these two related functions is that string_list_split() works on a string without modifying its contents (i.e. taking "const char *") and the resulting pieces of strings are their own copies in a string list, while string_list_split_in_place() works on a mutable string and the resulting pieces of strings come from the original string. Consolidate their implementations into a single helper function, and make them a thin wrapper around it. We can later add an extra flags parameter to extend both of these functions by updating only the internal helper function. Signed-off-by: Junio C Hamano <gitster@pobox.com>

Junio C Hamano committed Aug 1, 2025 at 15:04 UTC 527535fcdd2d9dec56877435f609852d0f2bf163
1 file changed +56 -40
string-list.c
+56 -40
@@ -276,55 +276,71 @@ void unsorted_string_list_delete_item(struct string_list *list, int i, int free_
276 list->nr--;
277 }
278
279 -int string_list_split(struct string_list *list, const char *string,
280 - const char *delim, int maxsplit)
279 +/*
280 + * append a substring [p..end] to list; return number of things it
281 + * appended to the list.
282 + */
283 +static int append_one(struct string_list *list,
284 + const char *p, const char *end,
285 + int in_place)
286 +{
287 + if (!end)
288 + end = p + strlen(p);
289 +
290 + if (in_place) {
291 + *((char *)end) = '\0';
292 + string_list_append(list, p);
293 + } else {
294 + string_list_append_nodup(list, xmemdupz(p, end - p));
295 + }
296 + return 1;
297 +}
298 +
299 +/*
300 + * Unfortunately this cannot become a public interface, as _in_place()
301 + * wants to have "const char *string" while the other variant wants to
302 + * have "char *string" for type safety.
303 + *
304 + * This accepts "const char *string" to allow both wrappers to use it;
305 + * it internally casts away the constness when in_place is true by
306 + * taking advantage of strpbrk() that takes a "const char *" arg and
307 + * returns "char *" pointer into that const string. Yucky but works ;-).
308 + */
309 +static int split_string(struct string_list *list, const char *string, const char *delim,
310 + int maxsplit, int in_place)
311 {
312 int count = 0;
283 - const char *p = string, *end;
313 + const char *p = string;
314 +
315 + if (in_place && list->strdup_strings)
316 + BUG("string_list_split_in_place() called with strdup_strings");
317 + else if (!in_place && !list->strdup_strings)
318 + BUG("string_list_split() called without strdup_strings");
319
285 - if (!list->strdup_strings)
286 - BUG("internal error in string_list_split(): "
287 - "list->strdup_strings must be set");
320 for (;;) {
289 - count++;
290 - if (maxsplit >= 0 && count > maxsplit) {
291 - string_list_append(list, p);
292 - return count;
293 - }
294 - end = strpbrk(p, delim);
295 - if (end) {
296 - string_list_append_nodup(list, xmemdupz(p, end - p));
297 - p = end + 1;
298 - } else {
299 - string_list_append(list, p);
321 + char *end;
322 +
323 + if (0 <= maxsplit && maxsplit <= count)
324 + end = NULL;
325 + else
326 + end = strpbrk(p, delim);
327 +
328 + count += append_one(list, p, end, in_place);
329 +
330 + if (!end)
331 return count;
301 - }
332 + p = end + 1;
333 }
334 }
335
336 +int string_list_split(struct string_list *list, const char *string,
337 + const char *delim, int maxsplit)
338 +{
339 + return split_string(list, string, delim, maxsplit, 0);
340 +}
341 +
342 int string_list_split_in_place(struct string_list *list, char *string,
343 const char *delim, int maxsplit)
344 {
308 - int count = 0;
309 - char *p = string, *end;
310 -
311 - if (list->strdup_strings)
312 - BUG("internal error in string_list_split_in_place(): "
313 - "list->strdup_strings must not be set");
314 - for (;;) {
315 - count++;
316 - if (maxsplit >= 0 && count > maxsplit) {
317 - string_list_append(list, p);
318 - return count;
319 - }
320 - end = strpbrk(p, delim);
321 - if (end) {
322 - *end = '\0';
323 - string_list_append(list, p);
324 - p = end + 1;
325 - } else {
326 - string_list_append(list, p);
327 - return count;
328 - }
329 - }
345 + return split_string(list, string, delim, maxsplit, 1);
346 }