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