chiark / gitweb /
Merge nss-myhostname
[elogind.git] / src / shared / strv.c
index f61680d4763602e843ee02350f0016d433690e4d..6b76d0eaef57616b11f3aa5f32f29de714236605 100644 (file)
@@ -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 <http://www.gnu.org/licenses/>.
 ***/
 
@@ -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;
+}