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)
This commit is contained in:
Lennart Poettering
2024-01-17 11:32:11 +01:00
parent b9d37112f2
commit 80f1e209a5
3 changed files with 88 additions and 0 deletions
+60
View File
@@ -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 */
+3
View File
@@ -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);
+25
View File
@@ -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);