]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
strv: add strv_extend_many() helper
authorLennart Poettering <lennart@poettering.net>
Tue, 16 Jan 2024 21:38:31 +0000 (22:38 +0100)
committerLennart Poettering <lennart@poettering.net>
Wed, 17 Jan 2024 10:32:11 +0000 (11:32 +0100)
This is supposed to be a nicer, faster replacement for the often seen
pattern strv_extend_strv(l, STRV_MAKE(…), false)

src/basic/strv.c
src/basic/strv.h
src/test/test-strv.c

index 97da11e1644fbfb4452519366513ad9055817fbb..e32653818b0b417d797d1102c5ef14271343a873 100644 (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 */
index f6502e50ef0dd11203e08d1ec21a5b679ed87768..91337b9287086027e41ae56ecd7303c44ca95218 100644 (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);
index f70e2aa862d3d1f607b8fc91975a7831aab320cb..da8721214a2f42ce9f8b97029032e50c691e9310 100644 (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);