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