X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fstrv.c;h=92851b223375516b5144f52afcc2ca4b471333fd;hp=a749096f9a35c193ea2d16c36091aac5a26ce33f;hb=f08fce88206f7315cff24678590cd73cd5e75f95;hpb=e99e38bbdcca3fe5956823bdb3d38544ccf93221 diff --git a/src/strv.c b/src/strv.c index a749096f9..92851b223 100644 --- a/src/strv.c +++ b/src/strv.c @@ -1,4 +1,4 @@ -/*-*- Mode: C; c-basic-offset: 8 -*-*/ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ /*** This file is part of systemd. @@ -31,7 +31,6 @@ char *strv_find(char **l, const char *name) { char **i; - assert(l); assert(name); STRV_FOREACH(i, l) @@ -41,6 +40,18 @@ char *strv_find(char **l, const char *name) { return NULL; } +char *strv_find_prefix(char **l, const char *name) { + char **i; + + assert(name); + + STRV_FOREACH(i, l) + if (startswith(*i, name)) + return *i; + + return NULL; +} + void strv_free(char **l) { char **k; @@ -56,20 +67,23 @@ void strv_free(char **l) { char **strv_copy(char **l) { char **r, **k; - if (!(r = new(char*, strv_length(l)+1))) + if (!(k = r = new(char*, strv_length(l)+1))) return NULL; - for (k = r; *l; k++, l++) - if (!(*k = strdup(*l))) - goto fail; + if (l) + for (; *l; k++, l++) + if (!(*k = strdup(*l))) + goto fail; *k = NULL; return r; fail: - for (k--, l--; k >= r; k--, l--) + for (k--; k >= r; k--) free(*k); + free(r); + return NULL; } @@ -91,7 +105,6 @@ char **strv_new_ap(const char *x, va_list ap) { unsigned n = 0, i = 0; va_list aq; - if (x) { n = 1; @@ -253,7 +266,7 @@ char **strv_split_quoted(const char *s) { i = 0; FOREACH_WORD_QUOTED(w, l, s, state) - if (!(r[i++] = strndup(w, l))) { + if (!(r[i++] = cunescape_length(w, l))) { strv_free(r); return NULL; } @@ -344,7 +357,10 @@ char **strv_remove(char **l, const char *s) { if (!l) return NULL; - /* Drops every occurence of s in the string list */ + assert(s); + + /* Drops every occurrence of s in the string list, edits + * in-place. */ for (f = t = l; *f; f++) { @@ -363,15 +379,22 @@ char **strv_remove(char **l, const char *s) { static int env_append(char **r, char ***k, char **a) { assert(r); assert(k); - assert(a); + + if (!a) + return 0; /* 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 */ + * in which case they are overridden instead. This assumes + * there is enough space in the r array. */ for (; *a; a++) { char **j; - size_t n = strcspn(*a, "=") + 1; + size_t n; + + n = strcspn(*a, "="); + + if ((*a)[n] == '=') + n++; for (j = r; j < *k; j++) if (strncmp(*j, *a, n) == 0) @@ -389,44 +412,41 @@ static int env_append(char **r, char ***k, char **a) { return 0; } -char **strv_env_merge(char **x, ...) { +char **strv_env_merge(unsigned n_lists, ...) { size_t n = 0; char **l, **k, **r; va_list ap; + unsigned i; /* 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); + va_start(ap, n_lists); + for (i = 0; i < n_lists; i++) { + 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) + va_start(ap, n_lists); + for (i = 0; i < n_lists; i++) { + l = va_arg(ap, char**); + if (env_append(r, &k, l) < 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); } + va_end(ap); *k = NULL; return r; fail: + va_end(ap); + for (k--; k >= r; k--) free(*k); @@ -461,37 +481,44 @@ static bool env_match(const char *t, const char *pattern) { return false; } -char **strv_env_delete(char **x, ...) { - size_t n = 0, i = 0; - char **l, **k, **r, **j; +char **strv_env_delete(char **x, unsigned n_lists, ...) { + size_t n, i = 0; + char **k, **r; va_list ap; - /* Deletes every entry fromx that is mentioned in the other + /* Deletes every entry from x that is mentioned in the other * string lists */ n = strv_length(x); - if (!(r = new(char*, n+1))) + r = new(char*, n+1); + if (!r) return NULL; STRV_FOREACH(k, x) { - va_start(ap, x); + unsigned v; + + va_start(ap, n_lists); + for (v = 0; v < n_lists; v++) { + char **l, **j; - while ((l = va_arg(ap, char**))) + l = va_arg(ap, char**); STRV_FOREACH(j, l) if (env_match(*k, *j)) - goto delete; - + goto skip; + } va_end(ap); - if (!(r[i++] = strdup(*k))) { + r[i] = strdup(*k); + if (!r[i]) { strv_free(r); return NULL; } + i++; continue; - delete: + skip: va_end(ap); } @@ -501,3 +528,153 @@ char **strv_env_delete(char **x, ...) { return r; } + +char **strv_env_unset(char **l, const char *p) { + + char **f, **t; + + if (!l) + return NULL; + + assert(p); + + /* Drops every occurrence of the env var setting p in the + * string list. edits in-place. */ + + for (f = t = l; *f; f++) { + + if (env_match(*f, p)) { + free(*f); + continue; + } + + *(t++) = *f; + } + + *t = NULL; + return l; +} + +char **strv_env_set(char **x, const char *p) { + + char **k, **r; + char* m[2] = { (char*) p, NULL }; + + /* Overrides the env var setting of p, returns a new copy */ + + if (!(r = new(char*, strv_length(x)+2))) + return NULL; + + k = r; + if (env_append(r, &k, x) < 0) + goto fail; + + if (env_append(r, &k, m) < 0) + goto fail; + + *k = NULL; + + return r; + +fail: + for (k--; k >= r; k--) + free(*k); + + free(r); + + return NULL; + +} + +char *strv_env_get_with_length(char **l, const char *name, size_t k) { + char **i; + + assert(name); + + STRV_FOREACH(i, l) + if (strncmp(*i, name, k) == 0 && + (*i)[k] == '=') + return *i + k + 1; + + return NULL; +} + +char *strv_env_get(char **l, const char *name) { + return strv_env_get_with_length(l, name, strlen(name)); +} + +char **strv_env_clean(char **l) { + char **r, **ret; + + for (r = ret = l; *l; l++) { + const char *equal; + + equal = strchr(*l, '='); + + if (equal && equal[1] == 0) { + free(*l); + continue; + } + + *(r++) = *l; + } + + *r = NULL; + + return ret; +} + +char **strv_parse_nulstr(const char *s, size_t l) { + const char *p; + unsigned c = 0, i = 0; + char **v; + + assert(s || l <= 0); + + if (l <= 0) + return strv_new(NULL, NULL); + + for (p = s; p < s + l; p++) + if (*p == 0) + c++; + + if (s[l-1] != 0) + c++; + + if (!(v = new0(char*, c+1))) + return NULL; + + p = s; + while (p < s + l) { + const char *e; + + e = memchr(p, 0, s + l - p); + + if (!(v[i++] = strndup(p, e ? e - p : s + l - p))) { + strv_free(v); + return NULL; + } + + if (!e) + break; + + p = e + 1; + } + + assert(i == c); + + return v; +} + +bool strv_overlap(char **a, char **b) { + char **i, **j; + + STRV_FOREACH(i, a) { + STRV_FOREACH(j, b) { + if (streq(*i, *j)) + return true; + } + } + + return false; +}