From: Lennart Poettering Date: Tue, 16 Jan 2024 21:38:31 +0000 (+0100) Subject: strv: add strv_extend_many() helper X-Git-Tag: v256-rc1~1126^2~4 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=80f1e209a5284907585941173702fc9d6e30f62a;p=thirdparty%2Fsystemd.git strv: add strv_extend_many() helper This is supposed to be a nicer, faster replacement for the often seen pattern strv_extend_strv(l, STRV_MAKE(…), false) --- diff --git a/src/basic/strv.c b/src/basic/strv.c index 97da11e1644..e32653818b0 100644 --- a/src/basic/strv.c +++ b/src/basic/strv.c @@ -590,6 +590,66 @@ int strv_extend_with_size(char ***l, size_t *n, const char *value) { return strv_consume_with_size(l, n, v); } +int strv_extend_many_internal(char ***l, const char *value, ...) { + va_list ap; + size_t n, m; + int r; + + assert(l); + + m = n = strv_length(*l); + + r = 0; + va_start(ap, value); + for (const char *s = value; s != POINTER_MAX; s = va_arg(ap, const char*)) { + if (!s) + continue; + + if (m > SIZE_MAX-1) { /* overflow */ + r = -ENOMEM; + break; + } + m++; + } + va_end(ap); + + if (r < 0) + return r; + if (m > SIZE_MAX-1) + return -ENOMEM; + + char **c = reallocarray(*l, GREEDY_ALLOC_ROUND_UP(m+1), sizeof(char*)); + if (!c) + return -ENOMEM; + *l = c; + + r = 0; + size_t i = n; + va_start(ap, value); + for (const char *s = value; s != POINTER_MAX; s = va_arg(ap, const char*)) { + if (!s) + continue; + + c[i] = strdup(s); + if (!c[i]) { + r = -ENOMEM; + break; + } + i++; + } + va_end(ap); + + if (r < 0) { + /* rollback on error */ + for (size_t j = n; j < i; j++) + c[j] = mfree(c[j]); + return r; + } + + c[i] = NULL; + return 0; +} + char** strv_uniq(char **l) { /* Drops duplicate entries. The first identical string will be * kept, the others dropped */ diff --git a/src/basic/strv.h b/src/basic/strv.h index f6502e50ef0..91337b92870 100644 --- a/src/basic/strv.h +++ b/src/basic/strv.h @@ -55,6 +55,9 @@ static inline int strv_extend(char ***l, const char *value) { return strv_extend_with_size(l, NULL, value); } +int strv_extend_many_internal(char ***l, const char *value, ...); +#define strv_extend_many(l, ...) strv_extend_many_internal(l, __VA_ARGS__, POINTER_MAX) + int strv_extendf(char ***l, const char *format, ...) _printf_(2,3); int strv_push_with_size(char ***l, size_t *n, char *value); diff --git a/src/test/test-strv.c b/src/test/test-strv.c index f70e2aa862d..da8721214a2 100644 --- a/src/test/test-strv.c +++ b/src/test/test-strv.c @@ -1014,4 +1014,29 @@ TEST(endswith_strv) { assert_se(streq_ptr(endswith_strv("waldo", STRV_MAKE("knurz", "", "waldo")), "")); } +TEST(strv_extend_many) { + _cleanup_strv_free_ char **l = NULL; + + assert_se(strv_extend_many(&l, NULL) >= 0); + assert_se(strv_isempty(l)); + + assert_se(strv_extend_many(&l, NULL, NULL, NULL) >= 0); + assert_se(strv_isempty(l)); + + assert_se(strv_extend_many(&l, "foo") >= 0); + assert_se(strv_equal(l, STRV_MAKE("foo"))); + + assert_se(strv_extend_many(&l, NULL, "bar", NULL) >= 0); + assert_se(strv_equal(l, STRV_MAKE("foo", "bar"))); + + assert_se(strv_extend_many(&l, "waldo", "quux") >= 0); + assert_se(strv_equal(l, STRV_MAKE("foo", "bar", "waldo", "quux"))); + + assert_se(strv_extend_many(&l, "1", "2", "3", "4") >= 0); + assert_se(strv_equal(l, STRV_MAKE("foo", "bar", "waldo", "quux", "1", "2", "3", "4"))); + + assert_se(strv_extend_many(&l, "yes", NULL, "no") >= 0); + assert_se(strv_equal(l, STRV_MAKE("foo", "bar", "waldo", "quux", "1", "2", "3", "4", "yes", "no"))); +} + DEFINE_TEST_MAIN(LOG_INFO);