X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fshared%2Fstrv.c;h=6b76d0eaef57616b11f3aa5f32f29de714236605;hp=f61680d4763602e843ee02350f0016d433690e4d;hb=f274ece0f76b5709408821e317e87aef76123db6;hpb=71ecc858fa91a686a050bee51804d43865ce1acc diff --git a/src/shared/strv.c b/src/shared/strv.c index f61680d47..6b76d0eae 100644 --- a/src/shared/strv.c +++ b/src/shared/strv.c @@ -6,16 +6,16 @@ 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 + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 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. + Lesser General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . ***/ @@ -64,28 +64,32 @@ void strv_free(char **l) { free(l); } +void strv_freep(char ***l) { + if (!l) + return; + + strv_free(*l); + *l = NULL; +} + char **strv_copy(char **l) { char **r, **k; - k = r = new(char*, strv_length(l)+1); - if (!k) + k = r = new(char*, strv_length(l) + 1); + if (!r) return NULL; if (l) - for (; *l; k++, l++) - if (!(*k = strdup(*l))) - goto fail; + for (; *l; k++, l++) { + *k = strdup(*l); + if (!*k) { + strv_free(r); + return NULL; + } + } *k = NULL; return r; - -fail: - for (k--; k >= r; k--) - free(*k); - - free(r); - - return NULL; } unsigned strv_length(char **l) { @@ -106,28 +110,44 @@ char **strv_new_ap(const char *x, va_list ap) { unsigned n = 0, i = 0; va_list aq; + /* As a special trick we ignore all listed strings that equal + * (const char*) -1. This is supposed to be used with the + * STRV_IFNOTNULL() macro to include possibly NULL strings in + * the string list. */ + if (x) { - n = 1; + n = x == (const char*) -1 ? 0 : 1; va_copy(aq, ap); - while (va_arg(aq, const char*)) + while ((s = va_arg(aq, const char*))) { + if (s == (const char*) -1) + continue; + n++; + } + va_end(aq); } - if (!(a = new(char*, n+1))) + a = new(char*, n+1); + if (!a) return NULL; if (x) { - if (!(a[i] = strdup(x))) { - free(a); - return NULL; + if (x != (const char*) -1) { + a[i] = strdup(x); + if (!a[i]) + goto fail; + i++; } - i++; - while ((s = va_arg(ap, const char*))) { - if (!(a[i] = strdup(s))) + + if (s == (const char*) -1) + continue; + + a[i] = strdup(s); + if (!a[i]) goto fail; i++; @@ -139,13 +159,7 @@ char **strv_new_ap(const char *x, va_list ap) { return a; fail: - - for (; i > 0; i--) - if (a[i-1]) - free(a[i-1]); - - free(a); - + strv_free(a); return NULL; } @@ -169,25 +183,27 @@ char **strv_merge(char **a, char **b) { if (!b) return strv_copy(a); - if (!(r = new(char*, strv_length(a)+strv_length(b)+1))) + r = new(char*, strv_length(a) + strv_length(b) + 1); + if (!r) return NULL; - for (k = r; *a; k++, a++) - if (!(*k = strdup(*a))) + for (k = r; *a; k++, a++) { + *k = strdup(*a); + if (!*k) goto fail; - for (; *b; k++, b++) - if (!(*k = strdup(*b))) + } + + for (; *b; k++, b++) { + *k = strdup(*b); + if (!*k) goto fail; + } *k = NULL; return r; fail: - for (k--; k >= r; k--) - free(*k); - - free(r); - + strv_free(r); return NULL; } @@ -221,11 +237,7 @@ char **strv_merge_concat(char **a, char **b, const char *suffix) { return r; fail: - for (k--; k >= r; k--) - free(*k); - - free(r); - + strv_free(r); return NULL; } @@ -243,16 +255,21 @@ char **strv_split(const char *s, const char *separator) { FOREACH_WORD_SEPARATOR(w, l, s, separator, state) n++; - if (!(r = new(char*, n+1))) + r = new(char*, n+1); + if (!r) return NULL; i = 0; - FOREACH_WORD_SEPARATOR(w, l, s, separator, state) - if (!(r[i++] = strndup(w, l))) { + FOREACH_WORD_SEPARATOR(w, l, s, separator, state) { + r[i] = strndup(w, l); + if (!r[i]) { strv_free(r); return NULL; } + i++; + } + r[i] = NULL; return r; } @@ -270,15 +287,19 @@ char **strv_split_quoted(const char *s) { FOREACH_WORD_QUOTED(w, l, s, state) n++; - if (!(r = new(char*, n+1))) + r = new(char*, n+1); + if (!r) return NULL; i = 0; - FOREACH_WORD_QUOTED(w, l, s, state) - if (!(r[i++] = cunescape_length(w, l))) { + FOREACH_WORD_QUOTED(w, l, s, state) { + r[i] = cunescape_length(w, l); + if (!r[i]) { strv_free(r); return NULL; } + i++; + } r[i] = NULL; return r; @@ -301,7 +322,8 @@ char *strv_join(char **l, const char *separator) { n += strlen(*s); } - if (!(r = new(char, n+1))) + r = new(char, n+1); + if (!r) return NULL; e = r; @@ -330,22 +352,21 @@ char **strv_append(char **l, const char *s) { if (!r) return NULL; - for (k = r; *l; k++, l++) - if (!(*k = strdup(*l))) + for (k = r; *l; k++, l++) { + *k = strdup(*l); + if (!*k) goto fail; + } - if (!(*(k++) = strdup(s))) + k[0] = strdup(s); + if (!k[0]) goto fail; - *k = NULL; + k[1] = NULL; return r; fail: - for (k--; k >= r; k--) - free(*k); - - free(r); - + strv_free(r); return NULL; } @@ -440,7 +461,8 @@ static int env_append(char **r, char ***k, char **a) { else free(*j); - if (!(*j = strdup(*a))) + *j = strdup(*a); + if (!*j) return -ENOMEM; } @@ -462,7 +484,8 @@ char **strv_env_merge(unsigned n_lists, ...) { } va_end(ap); - if (!(r = new(char*, n+1))) + r = new(char*, n+1); + if (!r) return NULL; k = r; @@ -481,11 +504,7 @@ char **strv_env_merge(unsigned n_lists, ...) { fail: va_end(ap); - - for (k--; k >= r; k--) - free(*k); - - free(r); + strv_free(r); return NULL; } @@ -597,7 +616,8 @@ char **strv_env_set(char **x, const char *p) { /* Overrides the env var setting of p, returns a new copy */ - if (!(r = new(char*, strv_length(x)+2))) + r = new(char*, strv_length(x)+2); + if (!r) return NULL; k = r; @@ -612,11 +632,7 @@ char **strv_env_set(char **x, const char *p) { return r; fail: - for (k--; k >= r; k--) - free(*k); - - free(r); - + strv_free(r); return NULL; } @@ -676,7 +692,8 @@ char **strv_parse_nulstr(const char *s, size_t l) { if (s[l-1] != 0) c++; - if (!(v = new0(char*, c+1))) + v = new0(char*, c+1); + if (!v) return NULL; p = s; @@ -685,11 +702,14 @@ char **strv_parse_nulstr(const char *s, size_t l) { e = memchr(p, 0, s + l - p); - if (!(v[i++] = strndup(p, e ? e - p : s + l - p))) { + v[i] = strndup(p, e ? e - p : s + l - p); + if (!v[i]) { strv_free(v); return NULL; } + i++; + if (!e) break; @@ -713,3 +733,18 @@ bool strv_overlap(char **a, char **b) { return false; } + +static int str_compare(const void *_a, const void *_b) { + const char **a = (const char**) _a, **b = (const char**) _b; + + return strcmp(*a, *b); +} + +char **strv_sort(char **l) { + + if (strv_isempty(l)) + return l; + + qsort(l, strv_length(l), sizeof(char*), str_compare); + return l; +}