1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2010 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
31 char *strv_find(char **l, const char *name) {
43 char *strv_find_prefix(char **l, const char *name) {
49 if (startswith(*i, name))
55 void strv_free(char **l) {
67 char **strv_copy(char **l) {
70 k = r = new(char*, strv_length(l)+1);
76 if (!(*k = strdup(*l)))
83 for (k--; k >= r; k--)
91 unsigned strv_length(char **l) {
103 char **strv_new_ap(const char *x, va_list ap) {
106 unsigned n = 0, i = 0;
113 while (va_arg(aq, const char*))
118 if (!(a = new(char*, n+1)))
122 if (!(a[i] = strdup(x))) {
129 while ((s = va_arg(ap, const char*))) {
130 if (!(a[i] = strdup(s)))
152 char **strv_new(const char *x, ...) {
157 r = strv_new_ap(x, ap);
163 char **strv_merge(char **a, char **b) {
172 if (!(r = new(char*, strv_length(a)+strv_length(b)+1)))
175 for (k = r; *a; k++, a++)
176 if (!(*k = strdup(*a)))
179 if (!(*k = strdup(*b)))
186 for (k--; k >= r; k--)
194 char **strv_merge_concat(char **a, char **b, const char *suffix) {
197 /* Like strv_merge(), but appends suffix to all strings in b, before adding */
202 r = new(char*, strv_length(a) + strv_length(b) + 1);
208 for (; *a; k++, a++) {
214 for (; *b; k++, b++) {
215 *k = strappend(*b, suffix);
224 for (k--; k >= r; k--)
233 char **strv_split(const char *s, const char *separator) {
243 FOREACH_WORD_SEPARATOR(w, l, s, separator, state)
246 if (!(r = new(char*, n+1)))
250 FOREACH_WORD_SEPARATOR(w, l, s, separator, state)
251 if (!(r[i++] = strndup(w, l))) {
260 char **strv_split_quoted(const char *s) {
270 FOREACH_WORD_QUOTED(w, l, s, state)
273 if (!(r = new(char*, n+1)))
277 FOREACH_WORD_QUOTED(w, l, s, state)
278 if (!(r[i++] = cunescape_length(w, l))) {
287 char *strv_join(char **l, const char *separator) {
295 k = strlen(separator);
304 if (!(r = new(char, n+1)))
310 e = stpcpy(e, separator);
320 char **strv_append(char **l, const char *s) {
324 return strv_new(s, NULL);
329 r = new(char*, strv_length(l)+2);
333 for (k = r; *l; k++, l++)
334 if (!(*k = strdup(*l)))
337 if (!(*(k++) = strdup(s)))
344 for (k--; k >= r; k--)
352 char **strv_uniq(char **l) {
355 /* Drops duplicate entries. The first identical string will be
356 * kept, the others dropped */
359 strv_remove(i+1, *i);
364 char **strv_remove(char **l, const char *s) {
372 /* Drops every occurrence of s in the string list, edits
375 for (f = t = l; *f; f++) {
389 char **strv_remove_prefix(char **l, const char *s) {
397 /* Drops every occurrence of a string prefixed with s in the
398 * string list, edits in-place. */
400 for (f = t = l; *f; f++) {
402 if (startswith(*f, s)) {
414 static int env_append(char **r, char ***k, char **a) {
421 /* Add the entries of a to *k unless they already exist in *r
422 * in which case they are overridden instead. This assumes
423 * there is enough space in the r array. */
429 n = strcspn(*a, "=");
434 for (j = r; j < *k; j++)
435 if (strncmp(*j, *a, n) == 0)
443 if (!(*j = strdup(*a)))
450 char **strv_env_merge(unsigned n_lists, ...) {
456 /* Merges an arbitrary number of environment sets */
458 va_start(ap, n_lists);
459 for (i = 0; i < n_lists; i++) {
460 l = va_arg(ap, char**);
465 if (!(r = new(char*, n+1)))
470 va_start(ap, n_lists);
471 for (i = 0; i < n_lists; i++) {
472 l = va_arg(ap, char**);
473 if (env_append(r, &k, l) < 0)
485 for (k--; k >= r; k--)
493 static bool env_match(const char *t, const char *pattern) {
497 /* pattern a matches string a
502 * a= does not match a
503 * a=b does not match a=
504 * a=b does not match a
505 * a=b does not match a=c */
507 if (streq(t, pattern))
510 if (!strchr(pattern, '=')) {
511 size_t l = strlen(pattern);
513 return strncmp(t, pattern, l) == 0 && t[l] == '=';
519 char **strv_env_delete(char **x, unsigned n_lists, ...) {
524 /* Deletes every entry from x that is mentioned in the other
536 va_start(ap, n_lists);
537 for (v = 0; v < n_lists; v++) {
540 l = va_arg(ap, char**);
542 if (env_match(*k, *j))
567 char **strv_env_unset(char **l, const char *p) {
576 /* Drops every occurrence of the env var setting p in the
577 * string list. edits in-place. */
579 for (f = t = l; *f; f++) {
581 if (env_match(*f, p)) {
593 char **strv_env_set(char **x, const char *p) {
596 char* m[2] = { (char*) p, NULL };
598 /* Overrides the env var setting of p, returns a new copy */
600 if (!(r = new(char*, strv_length(x)+2)))
604 if (env_append(r, &k, x) < 0)
607 if (env_append(r, &k, m) < 0)
615 for (k--; k >= r; k--)
624 char *strv_env_get_with_length(char **l, const char *name, size_t k) {
630 if (strncmp(*i, name, k) == 0 &&
637 char *strv_env_get(char **l, const char *name) {
638 return strv_env_get_with_length(l, name, strlen(name));
641 char **strv_env_clean(char **l) {
644 for (r = ret = l; *l; l++) {
647 equal = strchr(*l, '=');
649 if (equal && equal[1] == 0) {
662 char **strv_parse_nulstr(const char *s, size_t l) {
664 unsigned c = 0, i = 0;
670 return strv_new(NULL, NULL);
672 for (p = s; p < s + l; p++)
679 if (!(v = new0(char*, c+1)))
686 e = memchr(p, 0, s + l - p);
688 if (!(v[i++] = strndup(p, e ? e - p : s + l - p))) {
704 bool strv_overlap(char **a, char **b) {