]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
lib/strv: add new functions (from systemd)
authorKarel Zak <kzak@redhat.com>
Fri, 15 May 2015 12:57:04 +0000 (14:57 +0200)
committerKarel Zak <kzak@redhat.com>
Fri, 15 May 2015 12:57:04 +0000 (14:57 +0200)
Signed-off-by: Karel Zak <kzak@redhat.com>
include/Makemodule.am
include/strutils.h
include/strv.h [new file with mode: 0644]
lib/Makemodule.am
lib/strutils.c
lib/strv.c [new file with mode: 0644]
lib/sysfs.c

index f4556a687665a9df1960d0899bbbe6c73080b9b2..be94f8a87c2a442d0166d59b6df6a247f935c9a5 100644 (file)
@@ -47,6 +47,7 @@ dist_noinst_HEADERS += \
        include/setproctitle.h \
        include/statfs_magic.h \
        include/strutils.h \
+       include/strv.h \
        include/swapheader.h \
        include/swapprober.h \
        include/sysfs.h \
index 8235b501782998a4cbe0391ef2bb152419b4a536..9eb9c81271fea3bc50e337040cf2e7c746b1167c 100644 (file)
@@ -203,4 +203,8 @@ static inline size_t ltrim_whitespace(unsigned char *str)
        return len;
 }
 
+extern char *strnappend(const char *s, const char *suffix, size_t b);
+extern char *strappend(const char *s, const char *suffix);
+extern const char *split(const char **state, size_t *l, const char *separator, int quoted);
+
 #endif
diff --git a/include/strv.h b/include/strv.h
new file mode 100644 (file)
index 0000000..5286298
--- /dev/null
@@ -0,0 +1,54 @@
+#ifndef UTIL_LINUX_STRV
+#define UTIL_LINUX_STRV
+
+#include <stdarg.h>
+
+#include "c.h"
+
+char **strv_free(char **l);
+void strv_clear(char **l);
+char **strv_copy(char * const *l);
+unsigned strv_length(char * const *l);
+
+int strv_extend_strv(char ***a, char **b);
+int strv_extend_strv_concat(char ***a, char **b, const char *suffix);
+int strv_extend(char ***l, const char *value);
+int strv_extendf(char ***l, const char *format, ...)
+                       __attribute__ ((__format__ (__printf__, 2, 0)));
+int strv_push(char ***l, char *value);
+int strv_push_prepend(char ***l, char *value);
+int strv_consume(char ***l, char *value);
+int strv_consume_prepend(char ***l, char *value);
+
+char **strv_remove(char **l, const char *s);
+
+char **strv_new(const char *x, ...);
+char **strv_new_ap(const char *x, va_list ap);
+
+static inline const char* STRV_IFNOTNULL(const char *x) {
+        return x ? x : (const char *) -1;
+}
+
+static inline int strv_isempty(char * const *l) {
+        return !l || !*l;
+}
+
+char **strv_split(const char *s, const char *separator);
+char *strv_join(char **l, const char *separator);
+
+#define STRV_FOREACH(s, l)                      \
+        for ((s) = (l); (s) && *(s); (s)++)
+
+#define STRV_FOREACH_BACKWARDS(s, l)            \
+        STRV_FOREACH(s, l)                      \
+                ;                               \
+        for ((s)--; (l) && ((s) >= (l)); (s)--)
+
+
+#define STRV_MAKE_EMPTY ((char*[1]) { NULL })
+
+char **strv_reverse(char **l);
+
+#endif /* UTIL_LINUX_STRV */
+
+
index a33f0a089d3e772ac8789e897e3e6f917671148d..566c527a0862ed1d79c994f79025f4ab09f9214a 100644 (file)
@@ -24,6 +24,7 @@ libcommon_la_SOURCES = \
        lib/timeutils.c \
        lib/ttyutils.c \
        lib/exec_shell.c \
+       lib/strv.c \
        lib/readutmp.c
 
 if LINUX
index b8fd2eb5688b4437d38daecfe2f36c8038745eac..cc90e043da222d8c505e19af8da0c3d1fa28e883 100644 (file)
@@ -760,6 +760,106 @@ int streq_except_trailing_slash(const char *s1, const char *s2)
 }
 
 
+char *strnappend(const char *s, const char *suffix, size_t b)
+{
+        size_t a;
+        char *r;
+
+        if (!s && !suffix)
+                return strdup("");
+        if (!s)
+                return strndup(suffix, b);
+        if (!suffix)
+                return strdup(s);
+
+        assert(s);
+        assert(suffix);
+
+        a = strlen(s);
+        if (b > ((size_t) -1) - a)
+                return NULL;
+
+        r = malloc(a + b + 1);
+        if (!r)
+                return NULL;
+
+        memcpy(r, s, a);
+        memcpy(r + a, suffix, b);
+        r[a+b] = 0;
+
+        return r;
+}
+
+char *strappend(const char *s, const char *suffix)
+{
+        return strnappend(s, suffix, suffix ? strlen(suffix) : 0);
+}
+
+
+static size_t strcspn_escaped(const char *s, const char *reject)
+{
+        int escaped = 0;
+        int n;
+
+        for (n=0; s[n]; n++) {
+                if (escaped)
+                        escaped = 0;
+                else if (s[n] == '\\')
+                        escaped = 1;
+                else if (strchr(reject, s[n]))
+                        break;
+        }
+
+        /* if s ends in \, return index of previous char */
+        return n - escaped;
+}
+
+/* Split a string into words. */
+const char *split(const char **state, size_t *l, const char *separator, int quoted)
+{
+        const char *current;
+
+        current = *state;
+
+        if (!*current) {
+                assert(**state == '\0');
+                return NULL;
+        }
+
+        current += strspn(current, separator);
+        if (!*current) {
+                *state = current;
+                return NULL;
+        }
+
+        if (quoted && strchr("\'\"", *current)) {
+                char quotechars[2] = {*current, '\0'};
+
+                *l = strcspn_escaped(current + 1, quotechars);
+                if (current[*l + 1] == '\0' || current[*l + 1] != quotechars[0] ||
+                    (current[*l + 2] && !strchr(separator, current[*l + 2]))) {
+                        /* right quote missing or garbage at the end */
+                        *state = current;
+                        return NULL;
+                }
+                *state = current++ + *l + 2;
+        } else if (quoted) {
+                *l = strcspn_escaped(current, separator);
+                if (current[*l] && !strchr(separator, current[*l])) {
+                        /* unfinished escape */
+                        *state = current;
+                        return NULL;
+                }
+                *state = current + *l;
+        } else {
+                *l = strcspn(current, separator);
+                *state = current + *l;
+        }
+
+        return current;
+}
+
+
 #ifdef TEST_PROGRAM
 
 int main(int argc, char *argv[])
diff --git a/lib/strv.c b/lib/strv.c
new file mode 100644 (file)
index 0000000..e030033
--- /dev/null
@@ -0,0 +1,392 @@
+/*
+ *
+ * Copyright 2010 Lennart Poettering
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * 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.
+ *
+ *
+ * Copyright (C) 2015 Karel Zak <kzak@redhat.com>
+ *    Modified the original version from systemd project for util-linux.
+ */
+
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <assert.h>
+
+#include "strutils.h"
+#include "strv.h"
+
+void strv_clear(char **l) {
+        char **k;
+
+        if (!l)
+                return;
+
+        for (k = l; *k; k++)
+                free(*k);
+
+        *l = NULL;
+}
+
+char **strv_free(char **l) {
+        strv_clear(l);
+        free(l);
+        return NULL;
+}
+
+char **strv_copy(char * const *l) {
+        char **r, **k;
+
+        k = r = malloc(sizeof(char *) * (strv_length(l) + 1));
+        if (!r)
+                return NULL;
+
+        if (l)
+                for (; *l; k++, l++) {
+                        *k = strdup(*l);
+                        if (!*k) {
+                                strv_free(r);
+                                return NULL;
+                        }
+                }
+
+        *k = NULL;
+        return r;
+}
+
+unsigned strv_length(char * const *l) {
+        unsigned n = 0;
+
+        if (!l)
+                return 0;
+
+        for (; *l; l++)
+                n++;
+
+        return n;
+}
+
+char **strv_new_ap(const char *x, va_list ap) {
+        const char *s;
+        char **a;
+        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 = x == (const char*) -1 ? 0 : 1;
+
+                va_copy(aq, ap);
+                while ((s = va_arg(aq, const char*))) {
+                        if (s == (const char*) -1)
+                                continue;
+
+                        n++;
+                }
+
+                va_end(aq);
+        }
+
+        a = malloc(sizeof(char *) * (n + 1));
+        if (!a)
+                return NULL;
+
+        if (x) {
+                if (x != (const char*) -1) {
+                        a[i] = strdup(x);
+                        if (!a[i])
+                                goto fail;
+                        i++;
+                }
+
+                while ((s = va_arg(ap, const char*))) {
+
+                        if (s == (const char*) -1)
+                                continue;
+
+                        a[i] = strdup(s);
+                        if (!a[i])
+                                goto fail;
+
+                        i++;
+                }
+        }
+
+        a[i] = NULL;
+
+        return a;
+
+fail:
+        strv_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;
+}
+
+int strv_extend_strv(char ***a, char **b) {
+        int r;
+        char **s;
+
+        STRV_FOREACH(s, b) {
+                r = strv_extend(a, *s);
+                if (r < 0)
+                        return r;
+        }
+
+        return 0;
+}
+
+int strv_extend_strv_concat(char ***a, char **b, const char *suffix) {
+        int r;
+        char **s;
+
+        STRV_FOREACH(s, b) {
+                char *v;
+
+                v = strappend(*s, suffix);
+                if (!v)
+                        return -ENOMEM;
+
+                r = strv_push(a, v);
+                if (r < 0) {
+                        free(v);
+                        return r;
+                }
+        }
+
+        return 0;
+}
+
+
+#define _FOREACH_WORD(word, length, s, separator, quoted, state)        \
+        for ((state) = (s), (word) = split(&(state), &(length), (separator), (quoted)); (word); (word) = split(&(state), &(length), (separator), (quoted)))
+
+#define FOREACH_WORD_SEPARATOR(word, length, s, separator, state)       \
+        _FOREACH_WORD(word, length, s, separator, false, state)
+
+
+char **strv_split(const char *s, const char *separator) {
+        const char *word, *state;
+        size_t l;
+        unsigned n, i;
+        char **r;
+
+        assert(s);
+
+        n = 0;
+        FOREACH_WORD_SEPARATOR(word, l, s, separator, state)
+                n++;
+
+        r = malloc(sizeof(char *) * (n + 1));
+        if (!r)
+                return NULL;
+
+        i = 0;
+        FOREACH_WORD_SEPARATOR(word, l, s, separator, state) {
+                r[i] = strndup(word, l);
+                if (!r[i]) {
+                        strv_free(r);
+                        return NULL;
+                }
+
+                i++;
+        }
+
+        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);
+        }
+
+        r = malloc(n + 1);
+        if (!r)
+                return NULL;
+
+        e = r;
+        STRV_FOREACH(s, l) {
+                if (e != r)
+                        e = stpcpy(e, separator);
+
+                e = stpcpy(e, *s);
+        }
+
+        *e = 0;
+
+        return r;
+}
+
+int strv_push(char ***l, char *value) {
+        char **c;
+        unsigned n, m;
+
+        if (!value)
+                return 0;
+
+        n = strv_length(*l);
+
+        /* Increase and check for overflow */
+        m = n + 2;
+        if (m < n)
+                return -ENOMEM;
+
+        c = realloc(*l, sizeof(char *) * m);
+        if (!c)
+                return -ENOMEM;
+
+        c[n] = value;
+        c[n+1] = NULL;
+
+        *l = c;
+        return 0;
+}
+
+int strv_push_prepend(char ***l, char *value) {
+        char **c;
+        unsigned n, m, i;
+
+        if (!value)
+                return 0;
+
+        n = strv_length(*l);
+
+        /* increase and check for overflow */
+        m = n + 2;
+        if (m < n)
+                return -ENOMEM;
+
+        c = malloc(sizeof(char *) * m);
+        if (!c)
+                return -ENOMEM;
+
+        for (i = 0; i < n; i++)
+                c[i+1] = (*l)[i];
+
+        c[0] = value;
+        c[n+1] = NULL;
+
+        free(*l);
+        *l = c;
+
+        return 0;
+}
+
+int strv_consume(char ***l, char *value) {
+        int r;
+
+        r = strv_push(l, value);
+        if (r < 0)
+                free(value);
+
+        return r;
+}
+
+int strv_consume_prepend(char ***l, char *value) {
+        int r;
+
+        r = strv_push_prepend(l, value);
+        if (r < 0)
+                free(value);
+
+        return r;
+}
+
+int strv_extend(char ***l, const char *value) {
+        char *v;
+
+        if (!value)
+                return 0;
+
+        v = strdup(value);
+        if (!v)
+                return -ENOMEM;
+
+        return strv_consume(l, v);
+}
+
+char **strv_remove(char **l, const char *s) {
+        char **f, **t;
+
+        if (!l)
+                return NULL;
+
+        assert(s);
+
+        /* Drops every occurrence of s in the string list, edits
+         * in-place. */
+
+        for (f = t = l; *f; f++)
+                if (strcmp(*f, s) == 0)
+                        free(*f);
+                else
+                        *(t++) = *f;
+
+        *t = NULL;
+        return l;
+}
+
+int strv_extendf(char ***l, const char *format, ...) {
+        va_list ap;
+        char *x;
+        int r;
+
+        va_start(ap, format);
+        r = vasprintf(&x, format, ap);
+        va_end(ap);
+
+        if (r < 0)
+                return -ENOMEM;
+
+        return strv_consume(l, x);
+}
+
+char **strv_reverse(char **l) {
+        unsigned n, i;
+
+        n = strv_length(l);
+        if (n <= 1)
+                return l;
+
+        for (i = 0; i < n / 2; i++) {
+                char *t;
+
+                t = l[i];
+                l[i] = l[n-1-i];
+                l[n-1-i] = t;
+        }
+
+        return l;
+}
index 1b2019112d4180e15901a676f8eea25234d18f94..759d97be6170b6c4c3511b059e06868677b8e238 100644 (file)
@@ -457,11 +457,12 @@ int sysfs_write_u64(struct sysfs_cxt *cxt, const char *attr, uint64_t num)
 
 char *sysfs_strdup(struct sysfs_cxt *cxt, const char *attr)
 {
-       char buf[1024];
+       char buf[BUFSIZ];
        return sysfs_scanf(cxt, attr, "%1023[^\n]", buf) == 1 ?
                                                strdup(buf) : NULL;
 }
 
+
 int sysfs_count_dirents(struct sysfs_cxt *cxt, const char *attr)
 {
        DIR *dir;