]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/basic/strv.c
tree-wide: use strv_contains() in more places
[thirdparty/systemd.git] / src / basic / strv.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <errno.h>
4 #include <fnmatch.h>
5 #include <stdarg.h>
6 #include <stdio.h>
7 #include <stdlib.h>
8
9 #include "alloc-util.h"
10 #include "escape.h"
11 #include "extract-word.h"
12 #include "fileio.h"
13 #include "memory-util.h"
14 #include "nulstr-util.h"
15 #include "sort-util.h"
16 #include "string-util.h"
17 #include "strv.h"
18
19 char* strv_find(char * const *l, const char *name) {
20 char * const *i;
21
22 assert(name);
23
24 STRV_FOREACH(i, l)
25 if (streq(*i, name))
26 return *i;
27
28 return NULL;
29 }
30
31 char* strv_find_case(char * const *l, const char *name) {
32 char * const *i;
33
34 assert(name);
35
36 STRV_FOREACH(i, l)
37 if (strcaseeq(*i, name))
38 return *i;
39
40 return NULL;
41 }
42
43 char* strv_find_prefix(char * const *l, const char *name) {
44 char * const *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
55 char* strv_find_startswith(char * const *l, const char *name) {
56 char * const *i, *e;
57
58 assert(name);
59
60 /* Like strv_find_prefix, but actually returns only the
61 * suffix, not the whole item */
62
63 STRV_FOREACH(i, l) {
64 e = startswith(*i, name);
65 if (e)
66 return e;
67 }
68
69 return NULL;
70 }
71
72 char** strv_free(char **l) {
73 if (!l)
74 return NULL;
75
76 for (char **k = l; *k; k++)
77 free(*k);
78
79 return mfree(l);
80 }
81
82 char** strv_free_erase(char **l) {
83 char **i;
84
85 STRV_FOREACH(i, l)
86 erase_and_freep(i);
87
88 return mfree(l);
89 }
90
91 char** strv_copy(char * const *l) {
92 char **r, **k;
93
94 k = r = new(char*, strv_length(l) + 1);
95 if (!r)
96 return NULL;
97
98 if (l)
99 for (; *l; k++, l++) {
100 *k = strdup(*l);
101 if (!*k) {
102 strv_free(r);
103 return NULL;
104 }
105 }
106
107 *k = NULL;
108 return r;
109 }
110
111 size_t strv_length(char * const *l) {
112 size_t n = 0;
113
114 if (!l)
115 return 0;
116
117 for (; *l; l++)
118 n++;
119
120 return n;
121 }
122
123 char** strv_new_ap(const char *x, va_list ap) {
124 _cleanup_strv_free_ char **a = NULL;
125 size_t n = 0, i = 0;
126 va_list aq;
127
128 /* As a special trick we ignore all listed strings that equal
129 * STRV_IGNORE. This is supposed to be used with the
130 * STRV_IFNOTNULL() macro to include possibly NULL strings in
131 * the string list. */
132
133 va_copy(aq, ap);
134 for (const char *s = x; s; s = va_arg(aq, const char*)) {
135 if (s == STRV_IGNORE)
136 continue;
137
138 n++;
139 }
140 va_end(aq);
141
142 a = new(char*, n+1);
143 if (!a)
144 return NULL;
145
146 for (const char *s = x; s; s = va_arg(ap, const char*)) {
147 if (s == STRV_IGNORE)
148 continue;
149
150 a[i] = strdup(s);
151 if (!a[i])
152 return NULL;
153
154 i++;
155 }
156
157 a[i] = NULL;
158
159 return TAKE_PTR(a);
160 }
161
162 char** strv_new_internal(const char *x, ...) {
163 char **r;
164 va_list ap;
165
166 va_start(ap, x);
167 r = strv_new_ap(x, ap);
168 va_end(ap);
169
170 return r;
171 }
172
173 int strv_extend_strv(char ***a, char * const *b, bool filter_duplicates) {
174 char * const *s, **t;
175 size_t p, q, i = 0;
176
177 assert(a);
178
179 if (strv_isempty(b))
180 return 0;
181
182 p = strv_length(*a);
183 q = strv_length(b);
184
185 if (p >= SIZE_MAX - q)
186 return -ENOMEM;
187
188 t = reallocarray(*a, GREEDY_ALLOC_ROUND_UP(p + q + 1), sizeof(char *));
189 if (!t)
190 return -ENOMEM;
191
192 t[p] = NULL;
193 *a = t;
194
195 STRV_FOREACH(s, b) {
196 if (filter_duplicates && strv_contains(t, *s))
197 continue;
198
199 t[p+i] = strdup(*s);
200 if (!t[p+i])
201 goto rollback;
202
203 i++;
204 t[p+i] = NULL;
205 }
206
207 assert(i <= q);
208
209 return (int) i;
210
211 rollback:
212 for (size_t j = 0; j < i; j++)
213 free(t[p + j]);
214
215 t[p] = NULL;
216 return -ENOMEM;
217 }
218
219 int strv_extend_strv_concat(char ***a, char * const *b, const char *suffix) {
220 char * const *s;
221 int r;
222
223 STRV_FOREACH(s, b) {
224 char *v;
225
226 v = strjoin(*s, suffix);
227 if (!v)
228 return -ENOMEM;
229
230 r = strv_push(a, v);
231 if (r < 0) {
232 free(v);
233 return r;
234 }
235 }
236
237 return 0;
238 }
239
240 int strv_split_newlines_full(char ***ret, const char *s, ExtractFlags flags) {
241 _cleanup_strv_free_ char **l = NULL;
242 size_t n;
243 int r;
244
245 assert(s);
246
247 /* Special version of strv_split_full() that splits on newlines and
248 * suppresses an empty string at the end. */
249
250 r = strv_split_full(&l, s, NEWLINE, flags);
251 if (r < 0)
252 return r;
253
254 n = strv_length(l);
255 if (n > 0 && isempty(l[n - 1])) {
256 l[n - 1] = mfree(l[n - 1]);
257 n--;
258 }
259
260 *ret = TAKE_PTR(l);
261 return n;
262 }
263
264 int strv_split_full(char ***t, const char *s, const char *separators, ExtractFlags flags) {
265 _cleanup_strv_free_ char **l = NULL;
266 size_t n = 0;
267 int r;
268
269 assert(t);
270 assert(s);
271
272 for (;;) {
273 _cleanup_free_ char *word = NULL;
274
275 r = extract_first_word(&s, &word, separators, flags);
276 if (r < 0)
277 return r;
278 if (r == 0)
279 break;
280
281 if (!GREEDY_REALLOC(l, n + 2))
282 return -ENOMEM;
283
284 l[n++] = TAKE_PTR(word);
285 l[n] = NULL;
286 }
287
288 if (!l) {
289 l = new0(char*, 1);
290 if (!l)
291 return -ENOMEM;
292 }
293
294 *t = TAKE_PTR(l);
295
296 return (int) n;
297 }
298
299 int strv_split_and_extend_full(char ***t, const char *s, const char *separators, bool filter_duplicates, ExtractFlags flags) {
300 _cleanup_strv_free_ char **l = NULL;
301 int r;
302
303 assert(t);
304 assert(s);
305
306 r = strv_split_full(&l, s, separators, flags);
307 if (r < 0)
308 return r;
309
310 r = strv_extend_strv(t, l, filter_duplicates);
311 if (r < 0)
312 return r;
313
314 return (int) strv_length(*t);
315 }
316
317 int strv_split_colon_pairs(char ***t, const char *s) {
318 _cleanup_strv_free_ char **l = NULL;
319 size_t n = 0;
320 int r;
321
322 assert(t);
323 assert(s);
324
325 for (;;) {
326 _cleanup_free_ char *first = NULL, *second = NULL, *tuple = NULL, *second_or_empty = NULL;
327
328 r = extract_first_word(&s, &tuple, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE);
329 if (r < 0)
330 return r;
331 if (r == 0)
332 break;
333
334 const char *p = tuple;
335 r = extract_many_words(&p, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS,
336 &first, &second, NULL);
337 if (r < 0)
338 return r;
339 if (r == 0)
340 continue;
341 /* Enforce that at most 2 colon-separated words are contained in each group */
342 if (!isempty(p))
343 return -EINVAL;
344
345 second_or_empty = strdup(strempty(second));
346 if (!second_or_empty)
347 return -ENOMEM;
348
349 if (!GREEDY_REALLOC(l, n + 3))
350 return -ENOMEM;
351
352 l[n++] = TAKE_PTR(first);
353 l[n++] = TAKE_PTR(second_or_empty);
354
355 l[n] = NULL;
356 }
357
358 if (!l) {
359 l = new0(char*, 1);
360 if (!l)
361 return -ENOMEM;
362 }
363
364 *t = TAKE_PTR(l);
365
366 return (int) n;
367 }
368
369 char* strv_join_full(char * const *l, const char *separator, const char *prefix, bool unescape_separators) {
370 char * const *s;
371 char *r, *e;
372 size_t n, k, m;
373
374 if (!separator)
375 separator = " ";
376
377 k = strlen(separator);
378 m = strlen_ptr(prefix);
379
380 if (unescape_separators) /* If there separator is multi-char, we won't know how to escape it. */
381 assert(k == 1);
382
383 n = 0;
384 STRV_FOREACH(s, l) {
385 if (s != l)
386 n += k;
387
388 bool needs_escaping = unescape_separators && strchr(*s, separator[0]);
389
390 n += m + strlen(*s) * (1 + needs_escaping);
391 }
392
393 r = new(char, n+1);
394 if (!r)
395 return NULL;
396
397 e = r;
398 STRV_FOREACH(s, l) {
399 if (s != l)
400 e = stpcpy(e, separator);
401
402 if (prefix)
403 e = stpcpy(e, prefix);
404
405 bool needs_escaping = unescape_separators && strchr(*s, separator[0]);
406
407 if (needs_escaping)
408 for (size_t i = 0; (*s)[i]; i++) {
409 if ((*s)[i] == separator[0])
410 *(e++) = '\\';
411 *(e++) = (*s)[i];
412 }
413 else
414 e = stpcpy(e, *s);
415 }
416
417 *e = 0;
418
419 return r;
420 }
421
422 int strv_push(char ***l, char *value) {
423 char **c;
424 size_t n;
425
426 if (!value)
427 return 0;
428
429 n = strv_length(*l);
430
431 /* Check for overflow */
432 if (n > SIZE_MAX-2)
433 return -ENOMEM;
434
435 c = reallocarray(*l, GREEDY_ALLOC_ROUND_UP(n + 2), sizeof(char*));
436 if (!c)
437 return -ENOMEM;
438
439 c[n] = value;
440 c[n+1] = NULL;
441
442 *l = c;
443 return 0;
444 }
445
446 int strv_push_pair(char ***l, char *a, char *b) {
447 char **c;
448 size_t n;
449
450 if (!a && !b)
451 return 0;
452
453 n = strv_length(*l);
454
455 /* Check for overflow */
456 if (n > SIZE_MAX-3)
457 return -ENOMEM;
458
459 /* increase and check for overflow */
460 c = reallocarray(*l, GREEDY_ALLOC_ROUND_UP(n + !!a + !!b + 1), sizeof(char*));
461 if (!c)
462 return -ENOMEM;
463
464 if (a)
465 c[n++] = a;
466 if (b)
467 c[n++] = b;
468 c[n] = NULL;
469
470 *l = c;
471 return 0;
472 }
473
474 int strv_insert(char ***l, size_t position, char *value) {
475 char **c;
476 size_t n, m;
477
478 if (!value)
479 return 0;
480
481 n = strv_length(*l);
482 position = MIN(position, n);
483
484 /* increase and check for overflow */
485 m = n + 2;
486 if (m < n)
487 return -ENOMEM;
488
489 c = new(char*, m);
490 if (!c)
491 return -ENOMEM;
492
493 for (size_t i = 0; i < position; i++)
494 c[i] = (*l)[i];
495 c[position] = value;
496 for (size_t i = position; i < n; i++)
497 c[i+1] = (*l)[i];
498 c[n+1] = NULL;
499
500 return free_and_replace(*l, c);
501 }
502
503 int strv_consume(char ***l, char *value) {
504 int r;
505
506 r = strv_push(l, value);
507 if (r < 0)
508 free(value);
509
510 return r;
511 }
512
513 int strv_consume_pair(char ***l, char *a, char *b) {
514 int r;
515
516 r = strv_push_pair(l, a, b);
517 if (r < 0) {
518 free(a);
519 free(b);
520 }
521
522 return r;
523 }
524
525 int strv_consume_prepend(char ***l, char *value) {
526 int r;
527
528 r = strv_push_prepend(l, value);
529 if (r < 0)
530 free(value);
531
532 return r;
533 }
534
535 int strv_prepend(char ***l, const char *value) {
536 char *v;
537
538 if (!value)
539 return 0;
540
541 v = strdup(value);
542 if (!v)
543 return -ENOMEM;
544
545 return strv_consume_prepend(l, v);
546 }
547
548 int strv_extend(char ***l, const char *value) {
549 char *v;
550
551 if (!value)
552 return 0;
553
554 v = strdup(value);
555 if (!v)
556 return -ENOMEM;
557
558 return strv_consume(l, v);
559 }
560
561 int strv_extend_front(char ***l, const char *value) {
562 size_t n, m;
563 char *v, **c;
564
565 assert(l);
566
567 /* Like strv_extend(), but prepends rather than appends the new entry */
568
569 if (!value)
570 return 0;
571
572 n = strv_length(*l);
573
574 /* Increase and overflow check. */
575 m = n + 2;
576 if (m < n)
577 return -ENOMEM;
578
579 v = strdup(value);
580 if (!v)
581 return -ENOMEM;
582
583 c = reallocarray(*l, m, sizeof(char*));
584 if (!c) {
585 free(v);
586 return -ENOMEM;
587 }
588
589 memmove(c+1, c, n * sizeof(char*));
590 c[0] = v;
591 c[n+1] = NULL;
592
593 *l = c;
594 return 0;
595 }
596
597 char** strv_uniq(char **l) {
598 char **i;
599
600 /* Drops duplicate entries. The first identical string will be
601 * kept, the others dropped */
602
603 STRV_FOREACH(i, l)
604 strv_remove(i+1, *i);
605
606 return l;
607 }
608
609 bool strv_is_uniq(char * const *l) {
610 char * const *i;
611
612 STRV_FOREACH(i, l)
613 if (strv_contains(i+1, *i))
614 return false;
615
616 return true;
617 }
618
619 char** strv_remove(char **l, const char *s) {
620 char **f, **t;
621
622 if (!l)
623 return NULL;
624
625 assert(s);
626
627 /* Drops every occurrence of s in the string list, edits
628 * in-place. */
629
630 for (f = t = l; *f; f++)
631 if (streq(*f, s))
632 free(*f);
633 else
634 *(t++) = *f;
635
636 *t = NULL;
637 return l;
638 }
639
640 char** strv_parse_nulstr(const char *s, size_t l) {
641 /* l is the length of the input data, which will be split at NULs into
642 * elements of the resulting strv. Hence, the number of items in the resulting strv
643 * will be equal to one plus the number of NUL bytes in the l bytes starting at s,
644 * unless s[l-1] is NUL, in which case the final empty string is not stored in
645 * the resulting strv, and length is equal to the number of NUL bytes.
646 *
647 * Note that contrary to a normal nulstr which cannot contain empty strings, because
648 * the input data is terminated by any two consequent NUL bytes, this parser accepts
649 * empty strings in s.
650 */
651
652 size_t c = 0, i = 0;
653 char **v;
654
655 assert(s || l <= 0);
656
657 if (l <= 0)
658 return new0(char*, 1);
659
660 for (const char *p = s; p < s + l; p++)
661 if (*p == 0)
662 c++;
663
664 if (s[l-1] != 0)
665 c++;
666
667 v = new0(char*, c+1);
668 if (!v)
669 return NULL;
670
671 for (const char *p = s; p < s + l; ) {
672 const char *e;
673
674 e = memchr(p, 0, s + l - p);
675
676 v[i] = strndup(p, e ? e - p : s + l - p);
677 if (!v[i]) {
678 strv_free(v);
679 return NULL;
680 }
681
682 i++;
683
684 if (!e)
685 break;
686
687 p = e + 1;
688 }
689
690 assert(i == c);
691
692 return v;
693 }
694
695 char** strv_split_nulstr(const char *s) {
696 const char *i;
697 char **r = NULL;
698
699 NULSTR_FOREACH(i, s)
700 if (strv_extend(&r, i) < 0) {
701 strv_free(r);
702 return NULL;
703 }
704
705 if (!r)
706 return strv_new(NULL);
707
708 return r;
709 }
710
711 int strv_make_nulstr(char * const *l, char **ret, size_t *ret_size) {
712 /* A valid nulstr with two NULs at the end will be created, but
713 * q will be the length without the two trailing NULs. Thus the output
714 * string is a valid nulstr and can be iterated over using NULSTR_FOREACH,
715 * and can also be parsed by strv_parse_nulstr as long as the length
716 * is provided separately.
717 */
718
719 _cleanup_free_ char *m = NULL;
720 char * const *i;
721 size_t n = 0;
722
723 assert(ret);
724 assert(ret_size);
725
726 STRV_FOREACH(i, l) {
727 size_t z;
728
729 z = strlen(*i);
730
731 if (!GREEDY_REALLOC(m, n + z + 2))
732 return -ENOMEM;
733
734 memcpy(m + n, *i, z + 1);
735 n += z + 1;
736 }
737
738 if (!m) {
739 m = new0(char, 1);
740 if (!m)
741 return -ENOMEM;
742 n = 1;
743 } else
744 /* make sure there is a second extra NUL at the end of resulting nulstr */
745 m[n] = '\0';
746
747 assert(n > 0);
748 *ret = m;
749 *ret_size = n - 1;
750
751 m = NULL;
752
753 return 0;
754 }
755
756 bool strv_overlap(char * const *a, char * const *b) {
757 char * const *i;
758
759 STRV_FOREACH(i, a)
760 if (strv_contains(b, *i))
761 return true;
762
763 return false;
764 }
765
766 static int str_compare(char * const *a, char * const *b) {
767 return strcmp(*a, *b);
768 }
769
770 char** strv_sort(char **l) {
771 typesafe_qsort(l, strv_length(l), str_compare);
772 return l;
773 }
774
775 int strv_compare(char * const *a, char * const *b) {
776 int r;
777
778 if (strv_isempty(a)) {
779 if (strv_isempty(b))
780 return 0;
781 else
782 return -1;
783 }
784
785 if (strv_isempty(b))
786 return 1;
787
788 for ( ; *a || *b; ++a, ++b) {
789 r = strcmp_ptr(*a, *b);
790 if (r != 0)
791 return r;
792 }
793
794 return 0;
795 }
796
797 void strv_print(char * const *l) {
798 char * const *s;
799
800 STRV_FOREACH(s, l)
801 puts(*s);
802 }
803
804 int strv_extendf(char ***l, const char *format, ...) {
805 va_list ap;
806 char *x;
807 int r;
808
809 va_start(ap, format);
810 r = vasprintf(&x, format, ap);
811 va_end(ap);
812
813 if (r < 0)
814 return -ENOMEM;
815
816 return strv_consume(l, x);
817 }
818
819 char** strv_reverse(char **l) {
820 size_t n;
821
822 n = strv_length(l);
823 if (n <= 1)
824 return l;
825
826 for (size_t i = 0; i < n / 2; i++)
827 SWAP_TWO(l[i], l[n-1-i]);
828
829 return l;
830 }
831
832 char** strv_shell_escape(char **l, const char *bad) {
833 char **s;
834
835 /* Escapes every character in every string in l that is in bad,
836 * edits in-place, does not roll-back on error. */
837
838 STRV_FOREACH(s, l) {
839 char *v;
840
841 v = shell_escape(*s, bad);
842 if (!v)
843 return NULL;
844
845 free(*s);
846 *s = v;
847 }
848
849 return l;
850 }
851
852 bool strv_fnmatch_full(char* const* patterns, const char *s, int flags, size_t *matched_pos) {
853 for (size_t i = 0; patterns && patterns[i]; i++)
854 if (fnmatch(patterns[i], s, flags) == 0) {
855 if (matched_pos)
856 *matched_pos = i;
857 return true;
858 }
859
860 return false;
861 }
862
863 char** strv_skip(char **l, size_t n) {
864
865 while (n > 0) {
866 if (strv_isempty(l))
867 return l;
868
869 l++, n--;
870 }
871
872 return l;
873 }
874
875 int strv_extend_n(char ***l, const char *value, size_t n) {
876 size_t i, k;
877 char **nl;
878
879 assert(l);
880
881 if (!value)
882 return 0;
883 if (n == 0)
884 return 0;
885
886 /* Adds the value n times to l */
887
888 k = strv_length(*l);
889 if (n >= SIZE_MAX - k)
890 return -ENOMEM;
891
892 nl = reallocarray(*l, GREEDY_ALLOC_ROUND_UP(k + n + 1), sizeof(char *));
893 if (!nl)
894 return -ENOMEM;
895
896 *l = nl;
897
898 for (i = k; i < k + n; i++) {
899 nl[i] = strdup(value);
900 if (!nl[i])
901 goto rollback;
902 }
903 nl[i] = NULL;
904
905 return 0;
906
907 rollback:
908 for (size_t j = k; j < i; j++)
909 free(nl[j]);
910 nl[k] = NULL;
911
912 return -ENOMEM;
913 }
914
915 int fputstrv(FILE *f, char * const *l, const char *separator, bool *space) {
916 bool b = false;
917 char * const *s;
918 int r;
919
920 /* Like fputs(), but for strv, and with a less stupid argument order */
921
922 if (!space)
923 space = &b;
924
925 STRV_FOREACH(s, l) {
926 r = fputs_with_space(f, *s, separator, space);
927 if (r < 0)
928 return r;
929 }
930
931 return 0;
932 }
933
934 static int string_strv_hashmap_put_internal(Hashmap *h, const char *key, const char *value) {
935 char **l;
936 int r;
937
938 l = hashmap_get(h, key);
939 if (l) {
940 /* A list for this key already exists, let's append to it if it is not listed yet */
941 if (strv_contains(l, value))
942 return 0;
943
944 r = strv_extend(&l, value);
945 if (r < 0)
946 return r;
947
948 assert_se(hashmap_update(h, key, l) >= 0);
949 } else {
950 /* No list for this key exists yet, create one */
951 _cleanup_strv_free_ char **l2 = NULL;
952 _cleanup_free_ char *t = NULL;
953
954 t = strdup(key);
955 if (!t)
956 return -ENOMEM;
957
958 r = strv_extend(&l2, value);
959 if (r < 0)
960 return r;
961
962 r = hashmap_put(h, t, l2);
963 if (r < 0)
964 return r;
965 TAKE_PTR(t);
966 TAKE_PTR(l2);
967 }
968
969 return 1;
970 }
971
972 int _string_strv_hashmap_put(Hashmap **h, const char *key, const char *value HASHMAP_DEBUG_PARAMS) {
973 int r;
974
975 r = _hashmap_ensure_allocated(h, &string_strv_hash_ops HASHMAP_DEBUG_PASS_ARGS);
976 if (r < 0)
977 return r;
978
979 return string_strv_hashmap_put_internal(*h, key, value);
980 }
981
982 int _string_strv_ordered_hashmap_put(OrderedHashmap **h, const char *key, const char *value HASHMAP_DEBUG_PARAMS) {
983 int r;
984
985 r = _ordered_hashmap_ensure_allocated(h, &string_strv_hash_ops HASHMAP_DEBUG_PASS_ARGS);
986 if (r < 0)
987 return r;
988
989 return string_strv_hashmap_put_internal(PLAIN_HASHMAP(*h), key, value);
990 }
991
992 DEFINE_HASH_OPS_FULL(string_strv_hash_ops, char, string_hash_func, string_compare_func, free, char*, strv_free);