strv: introduce strv_env_merge() to merge environment arrays

This commit is contained in:
Lennart Poettering 2010-02-14 22:38:30 +01:00
parent 8d49745c2b
commit 2e6c9e6bde
2 changed files with 79 additions and 0 deletions

77
strv.c
View File

@ -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;
}

2
strv.h
View File

@ -49,6 +49,8 @@ char **strv_split_quoted(const char *s);
char *strv_join(char **l, const char *separator);
char **strv_env_merge(char **x, ...) _sentinel;
#define STRV_FOREACH(s, l) \
for ((s) = (l); (s) && *(s); (s)++)