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