]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/basic/strv.c
tree-wide: remove Lennart's copyright lines
[thirdparty/systemd.git] / src / basic / strv.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
a7334b09 2
07630cea 3#include <errno.h>
11c3a366 4#include <fnmatch.h>
60918275 5#include <stdarg.h>
11c3a366 6#include <stdio.h>
07630cea 7#include <stdlib.h>
60918275
LP
8#include <string.h>
9
b5efdb8a 10#include "alloc-util.h"
4f5dd394 11#include "escape.h"
11c3a366 12#include "extract-word.h"
d390f8ef 13#include "fileio.h"
07630cea 14#include "string-util.h"
60918275 15#include "strv.h"
cf0fbc49 16#include "util.h"
60918275
LP
17
18char *strv_find(char **l, const char *name) {
5f9a22c3
LP
19 char **i;
20
60918275
LP
21 assert(name);
22
5f9a22c3
LP
23 STRV_FOREACH(i, l)
24 if (streq(*i, name))
25 return *i;
60918275
LP
26
27 return NULL;
28}
29
a4bfb399
LP
30char *strv_find_prefix(char **l, const char *name) {
31 char **i;
32
33 assert(name);
34
35 STRV_FOREACH(i, l)
36 if (startswith(*i, name))
37 return *i;
38
39 return NULL;
40}
41
28849dba
LP
42char *strv_find_startswith(char **l, const char *name) {
43 char **i, *e;
44
45 assert(name);
46
47 /* Like strv_find_prefix, but actually returns only the
48 * suffix, not the whole item */
49
50 STRV_FOREACH(i, l) {
51 e = startswith(*i, name);
52 if (e)
53 return e;
54 }
55
56 return NULL;
57}
58
dd9c7723 59void strv_clear(char **l) {
60918275
LP
60 char **k;
61
62 if (!l)
63 return;
64
65 for (k = l; *k; k++)
66 free(*k);
67
dd9c7723
TG
68 *l = NULL;
69}
70
33c2ce7b 71char **strv_free(char **l) {
dd9c7723 72 strv_clear(l);
6b430fdb 73 return mfree(l);
60918275
LP
74}
75
ab84f5b9
ZJS
76char **strv_free_erase(char **l) {
77 char **i;
78
79 STRV_FOREACH(i, l)
80 string_erase(*i);
81
82 return strv_free(l);
83}
84
2fd9ae2e 85char **strv_copy(char * const *l) {
60918275
LP
86 char **r, **k;
87
1fd8d04e
LP
88 k = r = new(char*, strv_length(l) + 1);
89 if (!r)
60918275
LP
90 return NULL;
91
ede27aab 92 if (l)
1fd8d04e
LP
93 for (; *l; k++, l++) {
94 *k = strdup(*l);
95 if (!*k) {
96 strv_free(r);
97 return NULL;
98 }
99 }
60918275
LP
100
101 *k = NULL;
102 return r;
60918275
LP
103}
104
da6053d0
LP
105size_t strv_length(char * const *l) {
106 size_t n = 0;
60918275
LP
107
108 if (!l)
109 return 0;
110
111 for (; *l; l++)
112 n++;
113
114 return n;
115}
116
257eca1a 117char **strv_new_ap(const char *x, va_list ap) {
60918275 118 const char *s;
01111587 119 _cleanup_strv_free_ char **a = NULL;
da6053d0 120 size_t n = 0, i = 0;
257eca1a
LP
121 va_list aq;
122
07719a21 123 /* As a special trick we ignore all listed strings that equal
f9d14060 124 * STRV_IGNORE. This is supposed to be used with the
07719a21
LP
125 * STRV_IFNOTNULL() macro to include possibly NULL strings in
126 * the string list. */
127
60918275 128 if (x) {
f9d14060 129 n = x == STRV_IGNORE ? 0 : 1;
60918275 130
257eca1a 131 va_copy(aq, ap);
07719a21 132 while ((s = va_arg(aq, const char*))) {
f9d14060 133 if (s == STRV_IGNORE)
07719a21
LP
134 continue;
135
60918275 136 n++;
07719a21
LP
137 }
138
257eca1a 139 va_end(aq);
60918275
LP
140 }
141
07719a21
LP
142 a = new(char*, n+1);
143 if (!a)
60918275
LP
144 return NULL;
145
146 if (x) {
f9d14060 147 if (x != STRV_IGNORE) {
07719a21
LP
148 a[i] = strdup(x);
149 if (!a[i])
01111587 150 return NULL;
07719a21 151 i++;
60918275
LP
152 }
153
60918275 154 while ((s = va_arg(ap, const char*))) {
07719a21 155
f9d14060 156 if (s == STRV_IGNORE)
07719a21
LP
157 continue;
158
159 a[i] = strdup(s);
160 if (!a[i])
01111587 161 return NULL;
60918275
LP
162
163 i++;
164 }
60918275
LP
165 }
166
167 a[i] = NULL;
257eca1a 168
01111587 169 return TAKE_PTR(a);
60918275 170}
034c6ed7 171
257eca1a
LP
172char **strv_new(const char *x, ...) {
173 char **r;
174 va_list ap;
175
176 va_start(ap, x);
177 r = strv_new_ap(x, ap);
178 va_end(ap);
179
180 return r;
181}
182
e287086b
LP
183int strv_extend_strv(char ***a, char **b, bool filter_duplicates) {
184 char **s, **t;
185 size_t p, q, i = 0, j;
186
187 assert(a);
188
189 if (strv_isempty(b))
190 return 0;
191
192 p = strv_length(*a);
193 q = strv_length(b);
194
62d74c78 195 t = reallocarray(*a, p + q + 1, sizeof(char *));
e287086b
LP
196 if (!t)
197 return -ENOMEM;
198
199 t[p] = NULL;
200 *a = t;
07719a21 201
e3e45d4f 202 STRV_FOREACH(s, b) {
e287086b
LP
203
204 if (filter_duplicates && strv_contains(t, *s))
205 continue;
206
207 t[p+i] = strdup(*s);
208 if (!t[p+i])
209 goto rollback;
210
211 i++;
212 t[p+i] = NULL;
07719a21 213 }
034c6ed7 214
e287086b
LP
215 assert(i <= q);
216
217 return (int) i;
218
219rollback:
220 for (j = 0; j < i; j++)
221 free(t[p + j]);
222
223 t[p] = NULL;
224 return -ENOMEM;
5f9a22c3
LP
225}
226
e3e45d4f
SP
227int strv_extend_strv_concat(char ***a, char **b, const char *suffix) {
228 int r;
229 char **s;
5f9a22c3 230
e3e45d4f
SP
231 STRV_FOREACH(s, b) {
232 char *v;
5f9a22c3 233
e3e45d4f
SP
234 v = strappend(*s, suffix);
235 if (!v)
236 return -ENOMEM;
5f9a22c3 237
e3e45d4f
SP
238 r = strv_push(a, v);
239 if (r < 0) {
240 free(v);
241 return r;
8ea913b2 242 }
8ea913b2 243 }
5f9a22c3 244
e3e45d4f 245 return 0;
5f9a22c3
LP
246}
247
248char **strv_split(const char *s, const char *separator) {
a2a5291b 249 const char *word, *state;
5f9a22c3 250 size_t l;
da6053d0 251 size_t n, i;
5f9a22c3
LP
252 char **r;
253
254 assert(s);
255
256 n = 0;
a2a5291b 257 FOREACH_WORD_SEPARATOR(word, l, s, separator, state)
5f9a22c3
LP
258 n++;
259
1fd8d04e
LP
260 r = new(char*, n+1);
261 if (!r)
5f9a22c3
LP
262 return NULL;
263
264 i = 0;
a2a5291b
ZJS
265 FOREACH_WORD_SEPARATOR(word, l, s, separator, state) {
266 r[i] = strndup(word, l);
1fd8d04e 267 if (!r[i]) {
5f9a22c3
LP
268 strv_free(r);
269 return NULL;
270 }
271
1fd8d04e
LP
272 i++;
273 }
274
5f9a22c3
LP
275 r[i] = NULL;
276 return r;
277}
278
26d04f86
LP
279char **strv_split_newlines(const char *s) {
280 char **l;
da6053d0 281 size_t n;
26d04f86
LP
282
283 assert(s);
284
285 /* Special version of strv_split() that splits on newlines and
286 * suppresses an empty string at the end */
287
288 l = strv_split(s, NEWLINE);
289 if (!l)
290 return NULL;
291
292 n = strv_length(l);
293 if (n <= 0)
294 return l;
295
ece174c5 296 if (isempty(l[n - 1]))
a1e58e8e 297 l[n - 1] = mfree(l[n - 1]);
26d04f86
LP
298
299 return l;
300}
301
8adaf7bd 302int strv_split_extract(char ***t, const char *s, const char *separators, ExtractFlags flags) {
f88e6be5 303 _cleanup_strv_free_ char **l = NULL;
8dd4c05b 304 size_t n = 0, allocated = 0;
f88e6be5
LP
305 int r;
306
307 assert(t);
308 assert(s);
309
310 for (;;) {
311 _cleanup_free_ char *word = NULL;
312
8adaf7bd 313 r = extract_first_word(&s, &word, separators, flags);
f88e6be5
LP
314 if (r < 0)
315 return r;
ece174c5 316 if (r == 0)
f88e6be5
LP
317 break;
318
319 if (!GREEDY_REALLOC(l, allocated, n + 2))
320 return -ENOMEM;
321
ae2a15bc 322 l[n++] = TAKE_PTR(word);
f88e6be5
LP
323
324 l[n] = NULL;
325 }
326
8dd4c05b 327 if (!l) {
f88e6be5 328 l = new0(char*, 1);
8dd4c05b
LP
329 if (!l)
330 return -ENOMEM;
331 }
f88e6be5 332
ae2a15bc 333 *t = TAKE_PTR(l);
f88e6be5 334
8dd4c05b 335 return (int) n;
f88e6be5
LP
336}
337
5f9a22c3
LP
338char *strv_join(char **l, const char *separator) {
339 char *r, *e;
340 char **s;
341 size_t n, k;
342
343 if (!separator)
344 separator = " ";
345
346 k = strlen(separator);
347
348 n = 0;
349 STRV_FOREACH(s, l) {
afe773b0 350 if (s != l)
5f9a22c3
LP
351 n += k;
352 n += strlen(*s);
353 }
354
1fd8d04e
LP
355 r = new(char, n+1);
356 if (!r)
5f9a22c3
LP
357 return NULL;
358
359 e = r;
360 STRV_FOREACH(s, l) {
afe773b0 361 if (s != l)
5f9a22c3
LP
362 e = stpcpy(e, separator);
363
364 e = stpcpy(e, *s);
365 }
366
8d49745c
LP
367 *e = 0;
368
5f9a22c3
LP
369 return r;
370}
371
4468addc 372int strv_push(char ***l, char *value) {
5926ccca 373 char **c;
da6053d0 374 size_t n, m;
5926ccca
LP
375
376 if (!value)
377 return 0;
378
82dde599 379 n = strv_length(*l);
97569e15 380
98940a3c 381 /* Increase and check for overflow */
97569e15
LP
382 m = n + 2;
383 if (m < n)
384 return -ENOMEM;
385
aa484f35 386 c = reallocarray(*l, m, sizeof(char*));
4468addc 387 if (!c)
82dde599 388 return -ENOMEM;
82dde599 389
4468addc 390 c[n] = value;
82dde599
LP
391 c[n+1] = NULL;
392
5926ccca
LP
393 *l = c;
394 return 0;
395}
396
98940a3c
LP
397int strv_push_pair(char ***l, char *a, char *b) {
398 char **c;
da6053d0 399 size_t n, m;
98940a3c
LP
400
401 if (!a && !b)
402 return 0;
403
404 n = strv_length(*l);
405
406 /* increase and check for overflow */
407 m = n + !!a + !!b + 1;
408 if (m < n)
409 return -ENOMEM;
410
aa484f35 411 c = reallocarray(*l, m, sizeof(char*));
98940a3c
LP
412 if (!c)
413 return -ENOMEM;
414
415 if (a)
416 c[n++] = a;
417 if (b)
418 c[n++] = b;
419 c[n] = NULL;
420
421 *l = c;
422 return 0;
423}
424
da6053d0 425int strv_insert(char ***l, size_t position, char *value) {
9a00f57a 426 char **c;
da6053d0 427 size_t n, m, i;
9a00f57a
LP
428
429 if (!value)
430 return 0;
431
432 n = strv_length(*l);
6e888894 433 position = MIN(position, n);
97569e15
LP
434
435 /* increase and check for overflow */
436 m = n + 2;
437 if (m < n)
438 return -ENOMEM;
439
440 c = new(char*, m);
9a00f57a
LP
441 if (!c)
442 return -ENOMEM;
443
6e888894
ZJS
444 for (i = 0; i < position; i++)
445 c[i] = (*l)[i];
446 c[position] = value;
447 for (i = position; i < n; i++)
9a00f57a
LP
448 c[i+1] = (*l)[i];
449
9a00f57a
LP
450 c[n+1] = NULL;
451
452 free(*l);
453 *l = c;
454
455 return 0;
456}
457
6e18964d
ZJS
458int strv_consume(char ***l, char *value) {
459 int r;
460
461 r = strv_push(l, value);
462 if (r < 0)
463 free(value);
464
9a00f57a
LP
465 return r;
466}
467
98940a3c
LP
468int strv_consume_pair(char ***l, char *a, char *b) {
469 int r;
470
471 r = strv_push_pair(l, a, b);
472 if (r < 0) {
473 free(a);
474 free(b);
475 }
476
477 return r;
478}
479
9a00f57a
LP
480int strv_consume_prepend(char ***l, char *value) {
481 int r;
482
483 r = strv_push_prepend(l, value);
484 if (r < 0)
485 free(value);
486
6e18964d
ZJS
487 return r;
488}
489
4468addc
LP
490int strv_extend(char ***l, const char *value) {
491 char *v;
4468addc
LP
492
493 if (!value)
494 return 0;
495
496 v = strdup(value);
497 if (!v)
498 return -ENOMEM;
499
6e18964d 500 return strv_consume(l, v);
4468addc
LP
501}
502
4f4afc88
LP
503int strv_extend_front(char ***l, const char *value) {
504 size_t n, m;
505 char *v, **c;
506
507 assert(l);
508
509 /* Like strv_extend(), but prepends rather than appends the new entry */
510
bcab914f
LP
511 if (!value)
512 return 0;
513
4f4afc88
LP
514 n = strv_length(*l);
515
516 /* Increase and overflow check. */
517 m = n + 2;
518 if (m < n)
519 return -ENOMEM;
520
bcab914f
LP
521 v = strdup(value);
522 if (!v)
523 return -ENOMEM;
4f4afc88 524
aa484f35 525 c = reallocarray(*l, m, sizeof(char*));
4f4afc88
LP
526 if (!c) {
527 free(v);
528 return -ENOMEM;
529 }
530
531 memmove(c+1, c, n * sizeof(char*));
532 c[0] = v;
533 c[n+1] = NULL;
534
535 *l = c;
536 return 0;
537}
538
5f9a22c3 539char **strv_uniq(char **l) {
cba8922f
LP
540 char **i;
541
5f9a22c3
LP
542 /* Drops duplicate entries. The first identical string will be
543 * kept, the others dropped */
544
cba8922f 545 STRV_FOREACH(i, l)
5f9a22c3
LP
546 strv_remove(i+1, *i);
547
548 return l;
549}
550
e1dd6790
LP
551bool strv_is_uniq(char **l) {
552 char **i;
553
554 STRV_FOREACH(i, l)
555 if (strv_find(i+1, *i))
556 return false;
557
558 return true;
559}
560
5f9a22c3
LP
561char **strv_remove(char **l, const char *s) {
562 char **f, **t;
563
564 if (!l)
565 return NULL;
566
5d6ab905
LP
567 assert(s);
568
569 /* Drops every occurrence of s in the string list, edits
570 * in-place. */
5f9a22c3 571
e3e45d4f
SP
572 for (f = t = l; *f; f++)
573 if (streq(*f, s))
71ecc858 574 free(*f);
e3e45d4f
SP
575 else
576 *(t++) = *f;
71ecc858
LP
577
578 *t = NULL;
579 return l;
580}
581
21bc923a 582char **strv_parse_nulstr(const char *s, size_t l) {
b60df13b
ZJS
583 /* l is the length of the input data, which will be split at NULs into
584 * elements of the resulting strv. Hence, the number of items in the resulting strv
585 * will be equal to one plus the number of NUL bytes in the l bytes starting at s,
586 * unless s[l-1] is NUL, in which case the final empty string is not stored in
587 * the resulting strv, and length is equal to the number of NUL bytes.
588 *
589 * Note that contrary to a normal nulstr which cannot contain empty strings, because
590 * the input data is terminated by any two consequent NUL bytes, this parser accepts
591 * empty strings in s.
592 */
593
21bc923a 594 const char *p;
da6053d0 595 size_t c = 0, i = 0;
21bc923a
LP
596 char **v;
597
598 assert(s || l <= 0);
599
600 if (l <= 0)
49b832c5 601 return new0(char*, 1);
21bc923a
LP
602
603 for (p = s; p < s + l; p++)
604 if (*p == 0)
605 c++;
606
607 if (s[l-1] != 0)
608 c++;
609
1fd8d04e
LP
610 v = new0(char*, c+1);
611 if (!v)
21bc923a
LP
612 return NULL;
613
614 p = s;
615 while (p < s + l) {
616 const char *e;
617
618 e = memchr(p, 0, s + l - p);
619
1fd8d04e
LP
620 v[i] = strndup(p, e ? e - p : s + l - p);
621 if (!v[i]) {
21bc923a
LP
622 strv_free(v);
623 return NULL;
624 }
625
1fd8d04e
LP
626 i++;
627
21bc923a
LP
628 if (!e)
629 break;
630
631 p = e + 1;
632 }
633
634 assert(i == c);
635
636 return v;
637}
0c85a4f3 638
fabe5c0e
LP
639char **strv_split_nulstr(const char *s) {
640 const char *i;
641 char **r = NULL;
642
643 NULSTR_FOREACH(i, s)
644 if (strv_extend(&r, i) < 0) {
645 strv_free(r);
646 return NULL;
647 }
648
649 if (!r)
650 return strv_new(NULL, NULL);
651
652 return r;
653}
654
e287086b 655int strv_make_nulstr(char **l, char **p, size_t *q) {
b60df13b
ZJS
656 /* A valid nulstr with two NULs at the end will be created, but
657 * q will be the length without the two trailing NULs. Thus the output
658 * string is a valid nulstr and can be iterated over using NULSTR_FOREACH,
659 * and can also be parsed by strv_parse_nulstr as long as the length
660 * is provided separately.
661 */
662
e287086b
LP
663 size_t n_allocated = 0, n = 0;
664 _cleanup_free_ char *m = NULL;
665 char **i;
666
667 assert(p);
668 assert(q);
669
670 STRV_FOREACH(i, l) {
671 size_t z;
672
673 z = strlen(*i);
674
b60df13b 675 if (!GREEDY_REALLOC(m, n_allocated, n + z + 2))
e287086b
LP
676 return -ENOMEM;
677
678 memcpy(m + n, *i, z + 1);
679 n += z + 1;
680 }
681
682 if (!m) {
683 m = new0(char, 1);
684 if (!m)
685 return -ENOMEM;
b60df13b
ZJS
686 n = 1;
687 } else
688 /* make sure there is a second extra NUL at the end of resulting nulstr */
689 m[n] = '\0';
e287086b 690
b60df13b 691 assert(n > 0);
e287086b 692 *p = m;
b60df13b 693 *q = n - 1;
e287086b
LP
694
695 m = NULL;
696
697 return 0;
698}
699
0c85a4f3 700bool strv_overlap(char **a, char **b) {
e3e45d4f 701 char **i;
0c85a4f3 702
e3e45d4f
SP
703 STRV_FOREACH(i, a)
704 if (strv_contains(b, *i))
705 return true;
0c85a4f3
LP
706
707 return false;
708}
857a493d
LP
709
710static int str_compare(const void *_a, const void *_b) {
711 const char **a = (const char**) _a, **b = (const char**) _b;
712
713 return strcmp(*a, *b);
714}
715
716char **strv_sort(char **l) {
f6d703c3 717 qsort_safe(l, strv_length(l), sizeof(char*), str_compare);
857a493d
LP
718 return l;
719}
7c2d8094 720
0f84a72e 721bool strv_equal(char **a, char **b) {
e287086b
LP
722
723 if (strv_isempty(a))
724 return strv_isempty(b);
725
726 if (strv_isempty(b))
727 return false;
0f84a72e
DH
728
729 for ( ; *a || *b; ++a, ++b)
730 if (!streq_ptr(*a, *b))
731 return false;
732
733 return true;
734}
735
7c2d8094
TA
736void strv_print(char **l) {
737 char **s;
738
7c2d8094
TA
739 STRV_FOREACH(s, l)
740 puts(*s);
741}
4de33e7f
LP
742
743int strv_extendf(char ***l, const char *format, ...) {
744 va_list ap;
745 char *x;
746 int r;
747
748 va_start(ap, format);
749 r = vasprintf(&x, format, ap);
750 va_end(ap);
751
752 if (r < 0)
753 return -ENOMEM;
754
755 return strv_consume(l, x);
756}
e1dd6790
LP
757
758char **strv_reverse(char **l) {
da6053d0 759 size_t n, i;
e1dd6790
LP
760
761 n = strv_length(l);
762 if (n <= 1)
763 return l;
764
fc549b96 765 for (i = 0; i < n / 2; i++)
8a3134b2 766 SWAP_TWO(l[i], l[n-1-i]);
e1dd6790
LP
767
768 return l;
769}
bceccd5e 770
04c14b25
RM
771char **strv_shell_escape(char **l, const char *bad) {
772 char **s;
773
774 /* Escapes every character in every string in l that is in bad,
775 * edits in-place, does not roll-back on error. */
776
777 STRV_FOREACH(s, l) {
778 char *v;
779
780 v = shell_escape(*s, bad);
781 if (!v)
782 return NULL;
783
784 free(*s);
785 *s = v;
786 }
787
788 return l;
789}
790
2404701e 791bool strv_fnmatch(char* const* patterns, const char *s, int flags) {
bceccd5e
ZJS
792 char* const* p;
793
794 STRV_FOREACH(p, patterns)
2027927b 795 if (fnmatch(*p, s, flags) == 0)
bceccd5e
ZJS
796 return true;
797
798 return false;
799}
fe382237
LP
800
801char ***strv_free_free(char ***l) {
802 char ***i;
803
804 if (!l)
805 return NULL;
806
807 for (i = l; *i; i++)
808 strv_free(*i);
809
6b430fdb 810 return mfree(l);
fe382237 811}
e3ead6bb
LP
812
813char **strv_skip(char **l, size_t n) {
814
815 while (n > 0) {
816 if (strv_isempty(l))
817 return l;
818
819 l++, n--;
820 }
821
822 return l;
823}
8dd4c05b
LP
824
825int strv_extend_n(char ***l, const char *value, size_t n) {
826 size_t i, j, k;
827 char **nl;
828
829 assert(l);
830
831 if (!value)
832 return 0;
833 if (n == 0)
834 return 0;
835
61233823 836 /* Adds the value n times to l */
8dd4c05b
LP
837
838 k = strv_length(*l);
839
62d74c78 840 nl = reallocarray(*l, k + n + 1, sizeof(char *));
8dd4c05b
LP
841 if (!nl)
842 return -ENOMEM;
843
844 *l = nl;
845
846 for (i = k; i < k + n; i++) {
847 nl[i] = strdup(value);
848 if (!nl[i])
849 goto rollback;
850 }
851
852 nl[i] = NULL;
853 return 0;
854
855rollback:
6fff8ac4 856 for (j = k; j < i; j++)
8dd4c05b
LP
857 free(nl[j]);
858
859 nl[k] = NULL;
5b700370 860 return -ENOMEM;
8dd4c05b 861}
3df9bec5
LP
862
863int fputstrv(FILE *f, char **l, const char *separator, bool *space) {
864 bool b = false;
865 char **s;
866 int r;
867
868 /* Like fputs(), but for strv, and with a less stupid argument order */
869
3df9bec5
LP
870 if (!space)
871 space = &b;
872
873 STRV_FOREACH(s, l) {
d390f8ef 874 r = fputs_with_space(f, *s, separator, space);
3df9bec5
LP
875 if (r < 0)
876 return r;
3df9bec5
LP
877 }
878
879 return 0;
880}