diff options
author | Lennart Poettering <lennart@poettering.net> | 2010-02-14 22:38:30 +0100 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2010-02-14 22:38:30 +0100 |
commit | 2e6c9e6bdee8ebc9d34095b6f542603a217498e0 (patch) | |
tree | 3b0231c24bc45119a2c206ae015da8af1d079558 /strv.c | |
parent | 8d49745c2be3385ff3c20f4c848abfe700b06435 (diff) |
strv: introduce strv_env_merge() to merge environment arrays
Diffstat (limited to 'strv.c')
-rw-r--r-- | strv.c | 77 |
1 files changed, 77 insertions, 0 deletions
@@ -23,6 +23,7 @@ #include <stdlib.h> #include <stdarg.h> #include <string.h> +#include <errno.h> #include "util.h" #include "strv.h" @@ -301,6 +302,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; @@ -349,3 +351,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; +} |