util: add some extra strv helpers

Part-of: <https://gitlab.freedesktop.org/libinput/libinput/-/merge_requests/1178>
This commit is contained in:
Peter Hutterer 2025-03-12 12:03:06 +10:00 committed by Marge Bot
parent 5c751491fa
commit 63a8ad2ead
3 changed files with 138 additions and 0 deletions

View file

@ -62,6 +62,63 @@ next_word(const char **state, size_t *len, const char *separators)
return next;
}
size_t
strv_len(char **strv)
{
if (!strv)
return 0;
size_t size = 1;
while (*strv) {
size++;
strv++;
}
return size;
}
char **
strv_append_vprintf(char **strv, const char *fmt, va_list args)
{
char *dup = strdup_vprintf(fmt, args);
char **s = strv_append_take(strv, &dup);
return s;
}
char **
strv_append_printf(char **strv, const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
char **s = strv_append_vprintf(strv, fmt, args);
va_end(args);
return s;
}
char **
strv_append_strdup(char **strv, const char *str)
{
char *dup = safe_strdup(str);
return strv_append_take(strv, &dup);
}
char **
strv_append_take(char **strv, char **str)
{
if (str && *str) {
size_t len = max(strv_len(strv) + 1, 2);
char **s = realloc(strv, len * sizeof(*strv));
if (!s)
abort();
s[len - 1] = NULL;
s[len - 2] = *str;
*str = NULL;
return s;
} else {
return strv;
}
}
/**
* Return a null-terminated string array with the contents of argv
* duplicated.

View file

@ -301,9 +301,18 @@ safe_atod(const char *str, double *val)
return true;
}
/* Returns the length of the strv, including the terminating NULL */
size_t strv_len(char **strv);
char **strv_from_argv(int argc, char **argv);
char **strv_from_string(const char *in, const char *separator, size_t *num_elements);
char *strv_join(char **strv, const char *joiner);
char **strv_append_strdup(char **strv, const char *s);
/* Takes ownership of the string and appends it to strv, s is set to NULL */
char **strv_append_take(char **strv, char **s);
__attribute__ ((format (printf, 2, 3)))
char **strv_append_printf(char **strv, const char *fmt, ...);
__attribute__ ((format (printf, 2, 0)))
char **strv_append_vprintf(char **strv, const char *fmt, va_list args);
typedef int (*strv_foreach_callback_t)(const char *str, size_t index, void *data);
int strv_for_each(const char **strv, strv_foreach_callback_t func, void *data);

View file

@ -1207,6 +1207,77 @@ START_TEST(strv_for_each_test)
}
END_TEST
__attribute__ ((format (printf, 1, 0)))
static char **
test_strv_appendv(char *format, ...)
{
va_list args;
va_start(args, format);
char **strv = NULL;
strv = strv_append_vprintf(strv, "%s %d", args);
va_end(args);
return strv;
}
START_TEST(strv_append_test)
{
{
char *test_strv1[] = {"a", "b", "c", NULL};
char **test_strv2 = NULL;
litest_assert_int_eq(strv_len(test_strv1), 4U);
litest_assert_int_eq(strv_len(test_strv2), 0U);
}
{
char **strv = NULL;
char *dup = safe_strdup("test");
strv = strv_append_take(strv, &dup);
litest_assert_ptr_null(dup);
litest_assert_ptr_notnull(strv);
litest_assert_str_eq(strv[0], "test");
litest_assert_ptr_eq(strv[1], NULL);
litest_assert_int_eq(strv_len(strv), 2U);
char *dup2 = safe_strdup("test2");
strv = strv_append_take(strv, &dup2);
litest_assert_ptr_null(dup2);
litest_assert_str_eq(strv[1], "test2");
litest_assert_ptr_eq(strv[2], NULL);
litest_assert_int_eq(strv_len(strv), 3U);
strv = strv_append_take(strv, NULL);
litest_assert_int_eq(strv_len(strv), 3U);
strv_free(strv);
}
{
char **strv = NULL;
strv = strv_append_strdup(strv, "banana");
litest_assert(strv != NULL);
litest_assert_str_eq(strv[0], "banana");
litest_assert_ptr_null(strv[1]);
litest_assert_int_eq(strv_len(strv), 2U);
strv_free(strv);
}
{
char **strv = test_strv_appendv("%s %d", "apple", 2);
litest_assert_ptr_notnull(strv);
litest_assert_str_eq(strv[0], "apple 2");
litest_assert_ptr_null(strv[1]);
litest_assert_int_eq(strv_len(strv), 2U);
strv_free(strv);
}
{
char **strv = NULL;
strv = strv_append_printf(strv, "coco%s", "nut");
litest_assert_ptr_notnull(strv);
litest_assert_str_eq(strv[0], "coconut");
litest_assert_ptr_null(strv[1]);
litest_assert_int_eq(strv_len(strv), 2U);
strv_free(strv);
}
}
END_TEST
START_TEST(double_array_from_string_test)
{
struct double_array_from_string_test {
@ -2092,6 +2163,7 @@ int main(void)
ADD_TEST(safe_atod_test);
ADD_TEST(strsplit_test);
ADD_TEST(strv_for_each_test);
ADD_TEST(strv_append_test);
ADD_TEST(double_array_from_string_test);
ADD_TEST(strargv_test);
ADD_TEST(kvsplit_double_test);