X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=strv.c;h=ed5755a0d19dd797ca3a4ff7a627b33e16a9b345;hp=7e0810bffe48ddb8b71e82b36d8498d7ec8fbf14;hb=43d0fcbd3f54a5f3c5636acf9b54f19a07de7a18;hpb=cba8922fd40b9eca203bc1d63bef72dd1edf302c diff --git a/strv.c b/strv.c index 7e0810bff..ed5755a0d 100644 --- a/strv.c +++ b/strv.c @@ -1,20 +1,42 @@ /*-*- Mode: C; c-basic-offset: 8 -*-*/ +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with systemd; If not, see . +***/ + #include #include #include #include +#include #include "util.h" #include "strv.h" char *strv_find(char **l, const char *name) { + char **i; + assert(l); assert(name); - for (; *l; l++) - if (streq(*l, name)) - return *l; + STRV_FOREACH(i, l) + if (streq(*i, name)) + return *i; return NULL; } @@ -63,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))) @@ -91,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: @@ -113,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; @@ -142,16 +172,265 @@ fail: for (k--; k >= r; k--) free(*k); + free(r); + + return NULL; +} + +char **strv_merge_concat(char **a, char **b, const char *suffix) { + char **r, **k; + + /* Like strv_merge(), but appends suffix to all strings in b, before adding */ + + if (!b) + return strv_copy(a); + + if (!(r = new(char*, strv_length(a)+strv_length(b)+1))) + return NULL; + + for (k = r; *a; k++, a++) + if (!(*k = strdup(*a))) + goto fail; + for (; *b; k++, b++) + if (!(*k = strappend(*b, suffix))) + goto fail; + + *k = NULL; + return r; + +fail: + for (k--; k >= r; k--) + free(*k); + + free(r); + return NULL; } -bool strv_contains(char **l, const char *s) { +char **strv_split(const char *s, const char *separator) { + char *state; + char *w; + size_t l; + unsigned n, i; + char **r; + + assert(s); + + n = 0; + FOREACH_WORD_SEPARATOR(w, l, s, separator, state) + n++; + + if (!(r = new(char*, n+1))) + return NULL; + + i = 0; + FOREACH_WORD_SEPARATOR(w, l, s, separator, state) + if (!(r[i++] = strndup(w, l))) { + strv_free(r); + return NULL; + } + + r[i] = NULL; + return r; +} + +char **strv_split_quoted(const char *s) { + char *state; + char *w; + size_t l; + unsigned n, i; + char **r; + + assert(s); + + n = 0; + FOREACH_WORD_QUOTED(w, l, s, state) + n++; + + if (!(r = new(char*, n+1))) + return NULL; + + i = 0; + FOREACH_WORD_QUOTED(w, l, s, state) + if (!(r[i++] = strndup(w, l))) { + strv_free(r); + return NULL; + } + + r[i] = NULL; + return r; +} + +char *strv_join(char **l, const char *separator) { + char *r, *e; + char **s; + size_t n, k; + + if (!separator) + separator = " "; + + k = strlen(separator); + + n = 0; + STRV_FOREACH(s, l) { + if (n != 0) + n += k; + n += strlen(*s); + } + + if (!(r = new(char, n+1))) + return NULL; + + e = r; + STRV_FOREACH(s, l) { + if (e != r) + e = stpcpy(e, separator); + + e = stpcpy(e, *s); + } + + *e = 0; + + return r; +} + +char **strv_append(char **l, const char *s) { + char **r, **k; + + if (!l) + return strv_new(s, NULL); + + if (!s) + return strv_copy(l); + + if (!(r = new(char*, strv_length(l)+2))) + return NULL; + + for (k = r; *l; k++, l++) + if (!(*k = strdup(*l))) + goto fail; + + if (!(*(k++) = strdup(s))) + goto fail; + + *k = NULL; + return r; + +fail: + for (k--; k >= r; k--) + free(*k); + + free(r); + + return NULL; +} + +char **strv_uniq(char **l) { char **i; + /* Drops duplicate entries. The first identical string will be + * kept, the others dropped */ + STRV_FOREACH(i, l) - if (streq(*i, s)) - return true; + strv_remove(i+1, *i); + + return l; +} + +char **strv_remove(char **l, const char *s) { + char **f, **t; + + if (!l) + return NULL; + + /* Drops every occurence of s in the string list */ + + for (f = t = l; *f; f++) { + + if (streq(*f, s)) { + free(*f); + continue; + } + + *(t++) = *f; + } + + *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); + } + - return false; + 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; }