]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/strv.c
relicense to LGPLv2.1 (with exceptions)
[thirdparty/systemd.git] / src / shared / strv.c
CommitLineData
d6c9574f 1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
60918275 2
a7334b09
LP
3/***
4 This file is part of systemd.
5
6 Copyright 2010 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
5430f7f2
LP
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
a7334b09
LP
11 (at your option) any later version.
12
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
5430f7f2 16 Lesser General Public License for more details.
a7334b09 17
5430f7f2 18 You should have received a copy of the GNU Lesser General Public License
a7334b09
LP
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
60918275
LP
22#include <assert.h>
23#include <stdlib.h>
24#include <stdarg.h>
25#include <string.h>
2e6c9e6b 26#include <errno.h>
60918275
LP
27
28#include "util.h"
29#include "strv.h"
30
31char *strv_find(char **l, const char *name) {
5f9a22c3
LP
32 char **i;
33
60918275
LP
34 assert(name);
35
5f9a22c3
LP
36 STRV_FOREACH(i, l)
37 if (streq(*i, name))
38 return *i;
60918275
LP
39
40 return NULL;
41}
42
a4bfb399
LP
43char *strv_find_prefix(char **l, const char *name) {
44 char **i;
45
46 assert(name);
47
48 STRV_FOREACH(i, l)
49 if (startswith(*i, name))
50 return *i;
51
52 return NULL;
53}
54
60918275
LP
55void strv_free(char **l) {
56 char **k;
57
58 if (!l)
59 return;
60
61 for (k = l; *k; k++)
62 free(*k);
63
64 free(l);
65}
66
67char **strv_copy(char **l) {
68 char **r, **k;
69
f8440af5
LP
70 k = r = new(char*, strv_length(l)+1);
71 if (!k)
60918275
LP
72 return NULL;
73
ede27aab 74 if (l)
aa4355f2 75 for (; *l; k++, l++)
ede27aab
LP
76 if (!(*k = strdup(*l)))
77 goto fail;
60918275
LP
78
79 *k = NULL;
80 return r;
81
82fail:
da19d5c1 83 for (k--; k >= r; k--)
60918275
LP
84 free(*k);
85
da19d5c1
LP
86 free(r);
87
60918275
LP
88 return NULL;
89}
90
91unsigned strv_length(char **l) {
92 unsigned n = 0;
93
94 if (!l)
95 return 0;
96
97 for (; *l; l++)
98 n++;
99
100 return n;
101}
102
257eca1a 103char **strv_new_ap(const char *x, va_list ap) {
60918275
LP
104 const char *s;
105 char **a;
106 unsigned n = 0, i = 0;
257eca1a
LP
107 va_list aq;
108
60918275
LP
109 if (x) {
110 n = 1;
111
257eca1a
LP
112 va_copy(aq, ap);
113 while (va_arg(aq, const char*))
60918275 114 n++;
257eca1a 115 va_end(aq);
60918275
LP
116 }
117
118 if (!(a = new(char*, n+1)))
119 return NULL;
120
121 if (x) {
122 if (!(a[i] = strdup(x))) {
123 free(a);
124 return NULL;
125 }
126
127 i++;
128
60918275
LP
129 while ((s = va_arg(ap, const char*))) {
130 if (!(a[i] = strdup(s)))
131 goto fail;
132
133 i++;
134 }
60918275
LP
135 }
136
137 a[i] = NULL;
257eca1a 138
60918275
LP
139 return a;
140
141fail:
142
143 for (; i > 0; i--)
144 if (a[i-1])
145 free(a[i-1]);
146
147 free(a);
257eca1a 148
60918275
LP
149 return NULL;
150}
034c6ed7 151
257eca1a
LP
152char **strv_new(const char *x, ...) {
153 char **r;
154 va_list ap;
155
156 va_start(ap, x);
157 r = strv_new_ap(x, ap);
158 va_end(ap);
159
160 return r;
161}
162
034c6ed7
LP
163char **strv_merge(char **a, char **b) {
164 char **r, **k;
165
166 if (!a)
167 return strv_copy(b);
168
169 if (!b)
170 return strv_copy(a);
171
172 if (!(r = new(char*, strv_length(a)+strv_length(b)+1)))
173 return NULL;
174
175 for (k = r; *a; k++, a++)
176 if (!(*k = strdup(*a)))
177 goto fail;
178 for (; *b; k++, b++)
179 if (!(*k = strdup(*b)))
180 goto fail;
181
182 *k = NULL;
183 return r;
184
185fail:
186 for (k--; k >= r; k--)
187 free(*k);
188
100a76ee
LP
189 free(r);
190
034c6ed7 191 return NULL;
5f9a22c3
LP
192}
193
194char **strv_merge_concat(char **a, char **b, const char *suffix) {
195 char **r, **k;
196
197 /* Like strv_merge(), but appends suffix to all strings in b, before adding */
198
199 if (!b)
200 return strv_copy(a);
201
f8440af5
LP
202 r = new(char*, strv_length(a) + strv_length(b) + 1);
203 if (!r)
5f9a22c3
LP
204 return NULL;
205
8ea913b2
LP
206 k = r;
207 if (a)
208 for (; *a; k++, a++) {
209 *k = strdup(*a);
210 if (!*k)
211 goto fail;
212 }
213
214 for (; *b; k++, b++) {
215 *k = strappend(*b, suffix);
216 if (!*k)
5f9a22c3 217 goto fail;
8ea913b2 218 }
5f9a22c3
LP
219
220 *k = NULL;
221 return r;
222
223fail:
224 for (k--; k >= r; k--)
225 free(*k);
226
100a76ee
LP
227 free(r);
228
5f9a22c3
LP
229 return NULL;
230
231}
232
233char **strv_split(const char *s, const char *separator) {
234 char *state;
235 char *w;
236 size_t l;
237 unsigned n, i;
238 char **r;
239
240 assert(s);
241
242 n = 0;
243 FOREACH_WORD_SEPARATOR(w, l, s, separator, state)
244 n++;
245
246 if (!(r = new(char*, n+1)))
247 return NULL;
248
249 i = 0;
250 FOREACH_WORD_SEPARATOR(w, l, s, separator, state)
251 if (!(r[i++] = strndup(w, l))) {
252 strv_free(r);
253 return NULL;
254 }
255
256 r[i] = NULL;
257 return r;
258}
259
260char **strv_split_quoted(const char *s) {
261 char *state;
262 char *w;
263 size_t l;
264 unsigned n, i;
265 char **r;
266
267 assert(s);
268
269 n = 0;
270 FOREACH_WORD_QUOTED(w, l, s, state)
271 n++;
272
273 if (!(r = new(char*, n+1)))
274 return NULL;
275
276 i = 0;
277 FOREACH_WORD_QUOTED(w, l, s, state)
f60f22df 278 if (!(r[i++] = cunescape_length(w, l))) {
5f9a22c3
LP
279 strv_free(r);
280 return NULL;
281 }
282
283 r[i] = NULL;
284 return r;
285}
286
287char *strv_join(char **l, const char *separator) {
288 char *r, *e;
289 char **s;
290 size_t n, k;
291
292 if (!separator)
293 separator = " ";
294
295 k = strlen(separator);
296
297 n = 0;
298 STRV_FOREACH(s, l) {
299 if (n != 0)
300 n += k;
301 n += strlen(*s);
302 }
303
304 if (!(r = new(char, n+1)))
305 return NULL;
306
307 e = r;
308 STRV_FOREACH(s, l) {
309 if (e != r)
310 e = stpcpy(e, separator);
311
312 e = stpcpy(e, *s);
313 }
314
8d49745c
LP
315 *e = 0;
316
5f9a22c3
LP
317 return r;
318}
319
320char **strv_append(char **l, const char *s) {
321 char **r, **k;
322
323 if (!l)
324 return strv_new(s, NULL);
325
326 if (!s)
327 return strv_copy(l);
328
f8440af5
LP
329 r = new(char*, strv_length(l)+2);
330 if (!r)
5f9a22c3 331 return NULL;
034c6ed7 332
5f9a22c3
LP
333 for (k = r; *l; k++, l++)
334 if (!(*k = strdup(*l)))
335 goto fail;
2e6c9e6b 336
5f9a22c3
LP
337 if (!(*(k++) = strdup(s)))
338 goto fail;
339
340 *k = NULL;
341 return r;
342
343fail:
344 for (k--; k >= r; k--)
345 free(*k);
346
100a76ee
LP
347 free(r);
348
5f9a22c3 349 return NULL;
034c6ed7 350}
cba8922f 351
5f9a22c3 352char **strv_uniq(char **l) {
cba8922f
LP
353 char **i;
354
5f9a22c3
LP
355 /* Drops duplicate entries. The first identical string will be
356 * kept, the others dropped */
357
cba8922f 358 STRV_FOREACH(i, l)
5f9a22c3
LP
359 strv_remove(i+1, *i);
360
361 return l;
362}
363
364char **strv_remove(char **l, const char *s) {
365 char **f, **t;
366
367 if (!l)
368 return NULL;
369
5d6ab905
LP
370 assert(s);
371
372 /* Drops every occurrence of s in the string list, edits
373 * in-place. */
5f9a22c3
LP
374
375 for (f = t = l; *f; f++) {
376
377 if (streq(*f, s)) {
378 free(*f);
379 continue;
380 }
381
382 *(t++) = *f;
383 }
cba8922f 384
5f9a22c3
LP
385 *t = NULL;
386 return l;
cba8922f 387}
2e6c9e6b 388
71ecc858
LP
389char **strv_remove_prefix(char **l, const char *s) {
390 char **f, **t;
391
392 if (!l)
393 return NULL;
394
395 assert(s);
396
397 /* Drops every occurrence of a string prefixed with s in the
398 * string list, edits in-place. */
399
400 for (f = t = l; *f; f++) {
401
402 if (startswith(*f, s)) {
403 free(*f);
404 continue;
405 }
406
407 *(t++) = *f;
408 }
409
410 *t = NULL;
411 return l;
412}
413
2e6c9e6b
LP
414static int env_append(char **r, char ***k, char **a) {
415 assert(r);
416 assert(k);
5b6319dc
LP
417
418 if (!a)
419 return 0;
2e6c9e6b
LP
420
421 /* Add the entries of a to *k unless they already exist in *r
35b8ca3a 422 * in which case they are overridden instead. This assumes
a6ff950e 423 * there is enough space in the r array. */
2e6c9e6b
LP
424
425 for (; *a; a++) {
426 char **j;
5d6ab905
LP
427 size_t n;
428
429 n = strcspn(*a, "=");
430
431 if ((*a)[n] == '=')
432 n++;
2e6c9e6b
LP
433
434 for (j = r; j < *k; j++)
435 if (strncmp(*j, *a, n) == 0)
436 break;
437
438 if (j >= *k)
439 (*k)++;
440 else
441 free(*j);
442
443 if (!(*j = strdup(*a)))
444 return -ENOMEM;
445 }
446
447 return 0;
448}
449
5b6319dc 450char **strv_env_merge(unsigned n_lists, ...) {
2e6c9e6b
LP
451 size_t n = 0;
452 char **l, **k, **r;
453 va_list ap;
5b6319dc 454 unsigned i;
2e6c9e6b
LP
455
456 /* Merges an arbitrary number of environment sets */
457
5b6319dc
LP
458 va_start(ap, n_lists);
459 for (i = 0; i < n_lists; i++) {
460 l = va_arg(ap, char**);
461 n += strv_length(l);
2e6c9e6b 462 }
5b6319dc 463 va_end(ap);
2e6c9e6b
LP
464
465 if (!(r = new(char*, n+1)))
466 return NULL;
467
468 k = r;
469
5b6319dc
LP
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)
2e6c9e6b 474 goto fail;
2e6c9e6b 475 }
5b6319dc 476 va_end(ap);
2e6c9e6b
LP
477
478 *k = NULL;
479
480 return r;
481
482fail:
da19d5c1
LP
483 va_end(ap);
484
2e6c9e6b
LP
485 for (k--; k >= r; k--)
486 free(*k);
487
488 free(r);
489
490 return NULL;
491}
1137a57c
LP
492
493static bool env_match(const char *t, const char *pattern) {
494 assert(t);
495 assert(pattern);
496
497 /* pattern a matches string a
498 * a matches a=
499 * a matches a=b
500 * a= matches a=
501 * a=b matches a=b
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 */
506
507 if (streq(t, pattern))
508 return true;
509
510 if (!strchr(pattern, '=')) {
511 size_t l = strlen(pattern);
512
513 return strncmp(t, pattern, l) == 0 && t[l] == '=';
514 }
515
516 return false;
517}
518
5b6319dc 519char **strv_env_delete(char **x, unsigned n_lists, ...) {
700de555
LP
520 size_t n, i = 0;
521 char **k, **r;
1137a57c
LP
522 va_list ap;
523
35b8ca3a 524 /* Deletes every entry from x that is mentioned in the other
1137a57c
LP
525 * string lists */
526
527 n = strv_length(x);
528
700de555
LP
529 r = new(char*, n+1);
530 if (!r)
1137a57c
LP
531 return NULL;
532
533 STRV_FOREACH(k, x) {
700de555
LP
534 unsigned v;
535
5b6319dc 536 va_start(ap, n_lists);
700de555
LP
537 for (v = 0; v < n_lists; v++) {
538 char **l, **j;
1137a57c 539
5b6319dc 540 l = va_arg(ap, char**);
1137a57c
LP
541 STRV_FOREACH(j, l)
542 if (env_match(*k, *j))
700de555 543 goto skip;
5b6319dc 544 }
1137a57c
LP
545 va_end(ap);
546
700de555
LP
547 r[i] = strdup(*k);
548 if (!r[i]) {
1137a57c
LP
549 strv_free(r);
550 return NULL;
551 }
552
700de555 553 i++;
1137a57c
LP
554 continue;
555
700de555 556 skip:
1137a57c
LP
557 va_end(ap);
558 }
559
560 r[i] = NULL;
561
562 assert(i <= n);
563
564 return r;
565}
ddb26e18 566
7640a5de
LP
567char **strv_env_unset(char **l, const char *p) {
568
569 char **f, **t;
570
571 if (!l)
572 return NULL;
573
574 assert(p);
575
576 /* Drops every occurrence of the env var setting p in the
577 * string list. edits in-place. */
578
579 for (f = t = l; *f; f++) {
580
581 if (env_match(*f, p)) {
582 free(*f);
583 continue;
584 }
585
586 *(t++) = *f;
587 }
588
589 *t = NULL;
590 return l;
591}
592
ddb26e18
LP
593char **strv_env_set(char **x, const char *p) {
594
595 char **k, **r;
e1830b12
LP
596 char* m[2] = { (char*) p, NULL };
597
598 /* Overrides the env var setting of p, returns a new copy */
ddb26e18
LP
599
600 if (!(r = new(char*, strv_length(x)+2)))
601 return NULL;
602
603 k = r;
604 if (env_append(r, &k, x) < 0)
605 goto fail;
606
e1830b12 607 if (env_append(r, &k, m) < 0)
ddb26e18
LP
608 goto fail;
609
610 *k = NULL;
611
612 return r;
613
614fail:
615 for (k--; k >= r; k--)
616 free(*k);
617
618 free(r);
619
620 return NULL;
621
622}
fab56fc5
LP
623
624char *strv_env_get_with_length(char **l, const char *name, size_t k) {
625 char **i;
626
627 assert(name);
628
629 STRV_FOREACH(i, l)
630 if (strncmp(*i, name, k) == 0 &&
631 (*i)[k] == '=')
632 return *i + k + 1;
633
634 return NULL;
635}
636
637char *strv_env_get(char **l, const char *name) {
638 return strv_env_get_with_length(l, name, strlen(name));
639}
a6ff950e
LP
640
641char **strv_env_clean(char **l) {
642 char **r, **ret;
643
644 for (r = ret = l; *l; l++) {
645 const char *equal;
646
647 equal = strchr(*l, '=');
648
649 if (equal && equal[1] == 0) {
650 free(*l);
651 continue;
652 }
653
654 *(r++) = *l;
655 }
656
657 *r = NULL;
658
659 return ret;
660}
21bc923a
LP
661
662char **strv_parse_nulstr(const char *s, size_t l) {
663 const char *p;
664 unsigned c = 0, i = 0;
665 char **v;
666
667 assert(s || l <= 0);
668
669 if (l <= 0)
670 return strv_new(NULL, NULL);
671
672 for (p = s; p < s + l; p++)
673 if (*p == 0)
674 c++;
675
676 if (s[l-1] != 0)
677 c++;
678
679 if (!(v = new0(char*, c+1)))
680 return NULL;
681
682 p = s;
683 while (p < s + l) {
684 const char *e;
685
686 e = memchr(p, 0, s + l - p);
687
688 if (!(v[i++] = strndup(p, e ? e - p : s + l - p))) {
689 strv_free(v);
690 return NULL;
691 }
692
693 if (!e)
694 break;
695
696 p = e + 1;
697 }
698
699 assert(i == c);
700
701 return v;
702}
0c85a4f3
LP
703
704bool strv_overlap(char **a, char **b) {
705 char **i, **j;
706
707 STRV_FOREACH(i, a) {
708 STRV_FOREACH(j, b) {
709 if (streq(*i, *j))
710 return true;
711 }
712 }
713
714 return false;
715}