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/>.
***/
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) {
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++;
return a;
fail:
-
- for (; i > 0; i--)
- if (a[i-1])
- free(a[i-1]);
-
- free(a);
-
+ strv_free(a);
return NULL;
}
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;
}
return r;
fail:
- for (k--; k >= r; k--)
- free(*k);
-
- free(r);
-
+ strv_free(r);
return NULL;
}
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;
}
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;
n += strlen(*s);
}
- if (!(r = new(char, n+1)))
+ r = new(char, n+1);
+ if (!r)
return NULL;
e = r;
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;
}
return l;
}
+char **strv_remove_prefix(char **l, const char *s) {
+ char **f, **t;
+
+ if (!l)
+ return NULL;
+
+ assert(s);
+
+ /* Drops every occurrence of a string prefixed with s in the
+ * string list, edits in-place. */
+
+ for (f = t = l; *f; f++) {
+
+ if (startswith(*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);
else
free(*j);
- if (!(*j = strdup(*a)))
+ *j = strdup(*a);
+ if (!*j)
return -ENOMEM;
}
}
va_end(ap);
- if (!(r = new(char*, n+1)))
+ r = new(char*, n+1);
+ if (!r)
return NULL;
k = r;
fail:
va_end(ap);
-
- for (k--; k >= r; k--)
- free(*k);
-
- free(r);
+ strv_free(r);
return NULL;
}
/* 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;
return r;
fail:
- for (k--; k >= r; k--)
- free(*k);
-
- free(r);
-
+ strv_free(r);
return NULL;
}
if (s[l-1] != 0)
c++;
- if (!(v = new0(char*, c+1)))
+ v = new0(char*, c+1);
+ if (!v)
return NULL;
p = s;
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;
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;
+}