chiark / gitweb /
systemadm: when systemd isn't found, quit right-away
[elogind.git] / strv.c
diff --git a/strv.c b/strv.c
index 25ea92c112c26e6170436e7b08dc71857dbc64f7..ed5755a0d19dd797ca3a4ff7a627b33e16a9b345 100644 (file)
--- a/strv.c
+++ b/strv.c
@@ -23,6 +23,7 @@
 #include <stdlib.h>
 #include <stdarg.h>
 #include <string.h>
+#include <errno.h>
 
 #include "util.h"
 #include "strv.h"
@@ -84,21 +85,20 @@ unsigned strv_length(char **l) {
         return n;
 }
 
-char **strv_new(const char *x, ...) {
+char **strv_new_ap(const char *x, va_list ap) {
         const char *s;
         char **a;
         unsigned n = 0, i = 0;
-        va_list ap;
+        va_list aq;
+
 
         if (x) {
                 n = 1;
 
-                va_start(ap, x);
-
-                while (va_arg(ap, const char*))
+                va_copy(aq, ap);
+                while (va_arg(aq, const char*))
                         n++;
-
-                va_end(ap);
+                va_end(aq);
         }
 
         if (!(a = new(char*, n+1)))
@@ -112,19 +112,16 @@ char **strv_new(const char *x, ...) {
 
                 i++;
 
-                va_start(ap, x);
-
                 while ((s = va_arg(ap, const char*))) {
                         if (!(a[i] = strdup(s)))
                                 goto fail;
 
                         i++;
                 }
-
-                va_end(ap);
         }
 
         a[i] = NULL;
+
         return a;
 
 fail:
@@ -134,9 +131,21 @@ fail:
                         free(a[i-1]);
 
         free(a);
+
         return NULL;
 }
 
+char **strv_new(const char *x, ...) {
+        char **r;
+        va_list ap;
+
+        va_start(ap, x);
+        r = strv_new_ap(x, ap);
+        va_end(ap);
+
+        return r;
+}
+
 char **strv_merge(char **a, char **b) {
         char **r, **k;
 
@@ -281,6 +290,8 @@ char *strv_join(char **l, const char *separator) {
                 e = stpcpy(e, *s);
         }
 
+        *e = 0;
+
         return r;
 }
 
@@ -299,6 +310,7 @@ char **strv_append(char **l, const char *s) {
         for (k = r; *l; k++, l++)
                 if (!(*k = strdup(*l)))
                         goto fail;
+
         if (!(*(k++) = strdup(s)))
                 goto fail;
 
@@ -347,3 +359,78 @@ char **strv_remove(char **l, const char *s) {
         *t = NULL;
         return l;
 }
+
+static int env_append(char **r, char ***k, char **a) {
+        assert(r);
+        assert(k);
+        assert(a);
+
+        /* Add the entries of a to *k unless they already exist in *r
+         * in which case they are overriden instead. This assumes
+         * there is enough space in the r */
+
+        for (; *a; a++) {
+                char **j;
+                size_t n = strcspn(*a, "=") + 1;
+
+                for (j = r; j < *k; j++)
+                        if (strncmp(*j, *a, n) == 0)
+                                break;
+
+                if (j >= *k)
+                        (*k)++;
+                else
+                        free(*j);
+
+                if (!(*j = strdup(*a)))
+                        return -ENOMEM;
+        }
+
+        return 0;
+}
+
+char **strv_env_merge(char **x, ...) {
+        size_t n = 0;
+        char **l, **k, **r;
+        va_list ap;
+
+        /* Merges an arbitrary number of environment sets */
+
+        if (x) {
+                n += strv_length(x);
+
+                va_start(ap, x);
+                while ((l = va_arg(ap, char**)))
+                        n += strv_length(l);
+                va_end(ap);
+        }
+
+
+        if (!(r = new(char*, n+1)))
+                return NULL;
+
+        k = r;
+
+        if (x) {
+                if (env_append(r, &k, x) < 0)
+                        goto fail;
+
+                va_start(ap, x);
+                while ((l = va_arg(ap, char**)))
+                        if (env_append(r, &k, l) < 0)
+                                goto fail;
+                va_end(ap);
+        }
+
+        *k = NULL;
+
+        return r;
+
+fail:
+        for (k--; k >= r; k--)
+                free(*k);
+
+        free(r);
+
+        return NULL;
+}