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>
maint
Junio C Hamano 2025-08-01 15:04:19 -07:00
parent 9f6dfe43c8
commit 527535fcdd
1 changed files with 59 additions and 43 deletions

View File

@ -276,55 +276,71 @@ void unsorted_string_list_delete_item(struct string_list *list, int i, int free_
list->nr--;
}

/*
* append a substring [p..end] to list; return number of things it
* appended to the list.
*/
static int append_one(struct string_list *list,
const char *p, const char *end,
int in_place)
{
if (!end)
end = p + strlen(p);

if (in_place) {
*((char *)end) = '\0';
string_list_append(list, p);
} else {
string_list_append_nodup(list, xmemdupz(p, end - p));
}
return 1;
}

/*
* Unfortunately this cannot become a public interface, as _in_place()
* wants to have "const char *string" while the other variant wants to
* have "char *string" for type safety.
*
* This accepts "const char *string" to allow both wrappers to use it;
* it internally casts away the constness when in_place is true by
* taking advantage of strpbrk() that takes a "const char *" arg and
* returns "char *" pointer into that const string. Yucky but works ;-).
*/
static int split_string(struct string_list *list, const char *string, const char *delim,
int maxsplit, int in_place)
{
int count = 0;
const char *p = string;

if (in_place && list->strdup_strings)
BUG("string_list_split_in_place() called with strdup_strings");
else if (!in_place && !list->strdup_strings)
BUG("string_list_split() called without strdup_strings");

for (;;) {
char *end;

if (0 <= maxsplit && maxsplit <= count)
end = NULL;
else
end = strpbrk(p, delim);

count += append_one(list, p, end, in_place);

if (!end)
return count;
p = end + 1;
}
}

int string_list_split(struct string_list *list, const char *string,
const char *delim, int maxsplit)
{
int count = 0;
const char *p = string, *end;

if (!list->strdup_strings)
BUG("internal error in string_list_split(): "
"list->strdup_strings must be set");
for (;;) {
count++;
if (maxsplit >= 0 && count > maxsplit) {
string_list_append(list, p);
return count;
}
end = strpbrk(p, delim);
if (end) {
string_list_append_nodup(list, xmemdupz(p, end - p));
p = end + 1;
} else {
string_list_append(list, p);
return count;
}
}
return split_string(list, string, delim, maxsplit, 0);
}

int string_list_split_in_place(struct string_list *list, char *string,
const char *delim, int maxsplit)
{
int count = 0;
char *p = string, *end;

if (list->strdup_strings)
BUG("internal error in string_list_split_in_place(): "
"list->strdup_strings must not be set");
for (;;) {
count++;
if (maxsplit >= 0 && count > maxsplit) {
string_list_append(list, p);
return count;
}
end = strpbrk(p, delim);
if (end) {
*end = '\0';
string_list_append(list, p);
p = end + 1;
} else {
string_list_append(list, p);
return count;
}
}
return split_string(list, string, delim, maxsplit, 1);
}