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