chiark / gitweb /
main: parse our own command line and the kernel command line
[elogind.git] / strv.c
diff --git a/strv.c b/strv.c
index faa878c006748c0e0fc21f4c7ea004636224c73f..b5459a9867175763647adee4302f6e16cfc48cbb 100644 (file)
--- 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 <http://www.gnu.org/licenses/>.
+***/
+
 #include <assert.h>
 #include <stdlib.h>
 #include <stdarg.h>
 #include <string.h>
+#include <errno.h>
 
 #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;
 }
@@ -142,6 +164,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;
+
+}
+
+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)
+                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);
+        }
+
+
+        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;
 }