1:255.10-alt1
[systemd_ALT.git] / src / basic / strv.c
blob1065e1bcdefa81936813661d2a4b5931593e5d5b
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 #include <errno.h>
4 #include <fnmatch.h>
5 #include <stdarg.h>
6 #include <stdio.h>
7 #include <stdlib.h>
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"
20 char* strv_find(char * const *l, const char *name) {
21 assert(name);
23 STRV_FOREACH(i, l)
24 if (streq(*i, name))
25 return *i;
27 return NULL;
30 char* strv_find_case(char * const *l, const char *name) {
31 assert(name);
33 STRV_FOREACH(i, l)
34 if (strcaseeq(*i, name))
35 return *i;
37 return NULL;
40 char* strv_find_prefix(char * const *l, const char *name) {
41 assert(name);
43 STRV_FOREACH(i, l)
44 if (startswith(*i, name))
45 return *i;
47 return NULL;
50 char* strv_find_startswith(char * const *l, const char *name) {
51 assert(name);
53 /* Like strv_find_prefix, but actually returns only the
54 * suffix, not the whole item */
56 STRV_FOREACH(i, l) {
57 char *e;
59 e = startswith(*i, name);
60 if (e)
61 return e;
64 return NULL;
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;
74 return NULL;
77 char** strv_free(char **l) {
78 STRV_FOREACH(k, l)
79 free(*k);
81 return mfree(l);
84 char** strv_free_erase(char **l) {
85 STRV_FOREACH(i, l)
86 erase_and_freep(i);
88 return mfree(l);
91 void strv_free_many(char ***strvs, size_t n) {
92 assert(strvs || n == 0);
94 FOREACH_ARRAY (i, strvs, n)
95 strv_free(*i);
97 free(strvs);
100 char** strv_copy_n(char * const *l, size_t m) {
101 _cleanup_strv_free_ char **result = NULL;
102 char **k;
104 result = new(char*, MIN(strv_length(l), m) + 1);
105 if (!result)
106 return NULL;
108 k = result;
109 STRV_FOREACH(i, l) {
110 if (m == 0)
111 break;
113 *k = strdup(*i);
114 if (!*k)
115 return NULL;
116 k++;
118 if (m != SIZE_MAX)
119 m--;
122 *k = NULL;
123 return TAKE_PTR(result);
126 int strv_copy_unless_empty(char * const *l, char ***ret) {
127 assert(ret);
129 if (strv_isempty(l)) {
130 *ret = NULL;
131 return 0;
134 char **copy = strv_copy(l);
135 if (!copy)
136 return -ENOMEM;
138 *ret = TAKE_PTR(copy);
139 return 1;
142 size_t strv_length(char * const *l) {
143 size_t n = 0;
145 STRV_FOREACH(i, l)
146 n++;
148 return n;
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;
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. */
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;
166 n++;
168 va_end(aq);
170 a = new(char*, n+1);
171 if (!a)
172 return NULL;
174 for (const char *s = x; s; s = va_arg(ap, const char*)) {
175 if (s == STRV_IGNORE)
176 continue;
178 a[i] = strdup(s);
179 if (!a[i])
180 return NULL;
182 i++;
185 a[i] = NULL;
187 return TAKE_PTR(a);
190 char** strv_new_internal(const char *x, ...) {
191 char **r;
192 va_list ap;
194 va_start(ap, x);
195 r = strv_new_ap(x, ap);
196 va_end(ap);
198 return r;
201 int strv_extend_strv(char ***a, char * const *b, bool filter_duplicates) {
202 size_t p, q, i = 0;
203 char **t;
205 assert(a);
207 if (strv_isempty(b))
208 return 0;
210 p = strv_length(*a);
211 q = strv_length(b);
213 if (p >= SIZE_MAX - q)
214 return -ENOMEM;
216 t = reallocarray(*a, GREEDY_ALLOC_ROUND_UP(p + q + 1), sizeof(char *));
217 if (!t)
218 return -ENOMEM;
220 t[p] = NULL;
221 *a = t;
223 STRV_FOREACH(s, b) {
224 if (filter_duplicates && strv_contains(t, *s))
225 continue;
227 t[p+i] = strdup(*s);
228 if (!t[p+i])
229 goto rollback;
231 i++;
232 t[p+i] = NULL;
235 assert(i <= q);
237 return (int) i;
239 rollback:
240 free_many_charp(t + p, i);
241 t[p] = NULL;
242 return -ENOMEM;
245 int strv_extend_strv_concat(char ***a, char * const *b, const char *suffix) {
246 int r;
248 STRV_FOREACH(s, b) {
249 char *v;
251 v = strjoin(*s, suffix);
252 if (!v)
253 return -ENOMEM;
255 r = strv_push(a, v);
256 if (r < 0) {
257 free(v);
258 return r;
262 return 0;
265 int strv_split_newlines_full(char ***ret, const char *s, ExtractFlags flags) {
266 _cleanup_strv_free_ char **l = NULL;
267 size_t n;
268 int r;
270 assert(s);
272 /* Special version of strv_split_full() that splits on newlines and
273 * suppresses an empty string at the end. */
275 r = strv_split_full(&l, s, NEWLINE, flags);
276 if (r < 0)
277 return r;
279 n = strv_length(l);
280 if (n > 0 && isempty(l[n - 1])) {
281 l[n - 1] = mfree(l[n - 1]);
282 n--;
285 *ret = TAKE_PTR(l);
286 return n;
289 int strv_split_full(char ***t, const char *s, const char *separators, ExtractFlags flags) {
290 _cleanup_strv_free_ char **l = NULL;
291 size_t n = 0;
292 int r;
294 assert(t);
295 assert(s);
297 for (;;) {
298 _cleanup_free_ char *word = NULL;
300 r = extract_first_word(&s, &word, separators, flags);
301 if (r < 0)
302 return r;
303 if (r == 0)
304 break;
306 if (!GREEDY_REALLOC(l, n + 2))
307 return -ENOMEM;
309 l[n++] = TAKE_PTR(word);
310 l[n] = NULL;
313 if (!l) {
314 l = new0(char*, 1);
315 if (!l)
316 return -ENOMEM;
319 *t = TAKE_PTR(l);
321 return (int) n;
324 int strv_split_and_extend_full(char ***t, const char *s, const char *separators, bool filter_duplicates, ExtractFlags flags) {
325 _cleanup_strv_free_ char **l = NULL;
326 int r;
328 assert(t);
329 assert(s);
331 r = strv_split_full(&l, s, separators, flags);
332 if (r < 0)
333 return r;
335 r = strv_extend_strv(t, l, filter_duplicates);
336 if (r < 0)
337 return r;
339 return (int) strv_length(*t);
342 int strv_split_colon_pairs(char ***t, const char *s) {
343 _cleanup_strv_free_ char **l = NULL;
344 size_t n = 0;
345 int r;
347 assert(t);
348 assert(s);
350 for (;;) {
351 _cleanup_free_ char *first = NULL, *second = NULL, *tuple = NULL, *second_or_empty = NULL;
353 r = extract_first_word(&s, &tuple, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE);
354 if (r < 0)
355 return r;
356 if (r == 0)
357 break;
359 const char *p = tuple;
360 r = extract_many_words(&p, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS,
361 &first, &second, NULL);
362 if (r < 0)
363 return r;
364 if (r == 0)
365 continue;
366 /* Enforce that at most 2 colon-separated words are contained in each group */
367 if (!isempty(p))
368 return -EINVAL;
370 second_or_empty = strdup(strempty(second));
371 if (!second_or_empty)
372 return -ENOMEM;
374 if (!GREEDY_REALLOC(l, n + 3))
375 return -ENOMEM;
377 l[n++] = TAKE_PTR(first);
378 l[n++] = TAKE_PTR(second_or_empty);
380 l[n] = NULL;
383 if (!l) {
384 l = new0(char*, 1);
385 if (!l)
386 return -ENOMEM;
389 *t = TAKE_PTR(l);
391 return (int) n;
394 char* strv_join_full(char * const *l, const char *separator, const char *prefix, bool escape_separator) {
395 char *r, *e;
396 size_t n, k, m;
398 if (!separator)
399 separator = " ";
401 k = strlen(separator);
402 m = strlen_ptr(prefix);
404 if (escape_separator) /* If the separator was multi-char, we wouldn't know how to escape it. */
405 assert(k == 1);
407 n = 0;
408 STRV_FOREACH(s, l) {
409 if (s != l)
410 n += k;
412 bool needs_escaping = escape_separator && strchr(*s, *separator);
414 n += m + strlen(*s) * (1 + needs_escaping);
417 r = new(char, n+1);
418 if (!r)
419 return NULL;
421 e = r;
422 STRV_FOREACH(s, l) {
423 if (s != l)
424 e = stpcpy(e, separator);
426 if (prefix)
427 e = stpcpy(e, prefix);
429 bool needs_escaping = escape_separator && strchr(*s, *separator);
431 if (needs_escaping)
432 for (size_t i = 0; (*s)[i]; i++) {
433 if ((*s)[i] == *separator)
434 *(e++) = '\\';
435 *(e++) = (*s)[i];
437 else
438 e = stpcpy(e, *s);
441 *e = 0;
443 return r;
446 int strv_push_with_size(char ***l, size_t *n, char *value) {
447 /* n is a pointer to a variable to store the size of l.
448 * If not given (i.e. n is NULL or *n is SIZE_MAX), size will be calculated using strv_length().
449 * If n is not NULL, the size after the push will be returned.
450 * If value is empty, no action is taken and *n is not set. */
452 if (!value)
453 return 0;
455 size_t size = n ? *n : SIZE_MAX;
456 if (size == SIZE_MAX)
457 size = strv_length(*l);
459 /* Check for overflow */
460 if (size > SIZE_MAX-2)
461 return -ENOMEM;
463 char **c = reallocarray(*l, GREEDY_ALLOC_ROUND_UP(size + 2), sizeof(char*));
464 if (!c)
465 return -ENOMEM;
467 c[size] = value;
468 c[size+1] = NULL;
470 *l = c;
471 if (n)
472 *n = size + 1;
473 return 0;
476 int strv_push_pair(char ***l, char *a, char *b) {
477 char **c;
478 size_t n;
480 if (!a && !b)
481 return 0;
483 n = strv_length(*l);
485 /* Check for overflow */
486 if (n > SIZE_MAX-3)
487 return -ENOMEM;
489 /* increase and check for overflow */
490 c = reallocarray(*l, GREEDY_ALLOC_ROUND_UP(n + !!a + !!b + 1), sizeof(char*));
491 if (!c)
492 return -ENOMEM;
494 if (a)
495 c[n++] = a;
496 if (b)
497 c[n++] = b;
498 c[n] = NULL;
500 *l = c;
501 return 0;
504 int strv_insert(char ***l, size_t position, char *value) {
505 char **c;
506 size_t n, m;
508 if (!value)
509 return 0;
511 n = strv_length(*l);
512 position = MIN(position, n);
514 /* increase and check for overflow */
515 m = n + 2;
516 if (m < n)
517 return -ENOMEM;
519 c = new(char*, m);
520 if (!c)
521 return -ENOMEM;
523 for (size_t i = 0; i < position; i++)
524 c[i] = (*l)[i];
525 c[position] = value;
526 for (size_t i = position; i < n; i++)
527 c[i+1] = (*l)[i];
528 c[n+1] = NULL;
530 return free_and_replace(*l, c);
533 int strv_consume_with_size(char ***l, size_t *n, char *value) {
534 int r;
536 r = strv_push_with_size(l, n, value);
537 if (r < 0)
538 free(value);
540 return r;
543 int strv_consume_pair(char ***l, char *a, char *b) {
544 int r;
546 r = strv_push_pair(l, a, b);
547 if (r < 0) {
548 free(a);
549 free(b);
552 return r;
555 int strv_consume_prepend(char ***l, char *value) {
556 int r;
558 r = strv_push_prepend(l, value);
559 if (r < 0)
560 free(value);
562 return r;
565 int strv_prepend(char ***l, const char *value) {
566 char *v;
568 if (!value)
569 return 0;
571 v = strdup(value);
572 if (!v)
573 return -ENOMEM;
575 return strv_consume_prepend(l, v);
578 int strv_extend_with_size(char ***l, size_t *n, const char *value) {
579 char *v;
581 if (!value)
582 return 0;
584 v = strdup(value);
585 if (!v)
586 return -ENOMEM;
588 return strv_consume_with_size(l, n, v);
591 int strv_extend_front(char ***l, const char *value) {
592 size_t n, m;
593 char *v, **c;
595 assert(l);
597 /* Like strv_extend(), but prepends rather than appends the new entry */
599 if (!value)
600 return 0;
602 n = strv_length(*l);
604 /* Increase and overflow check. */
605 m = n + 2;
606 if (m < n)
607 return -ENOMEM;
609 v = strdup(value);
610 if (!v)
611 return -ENOMEM;
613 c = reallocarray(*l, m, sizeof(char*));
614 if (!c) {
615 free(v);
616 return -ENOMEM;
619 memmove(c+1, c, n * sizeof(char*));
620 c[0] = v;
621 c[n+1] = NULL;
623 *l = c;
624 return 0;
627 char** strv_uniq(char **l) {
628 /* Drops duplicate entries. The first identical string will be
629 * kept, the others dropped */
631 STRV_FOREACH(i, l)
632 strv_remove(i+1, *i);
634 return l;
637 bool strv_is_uniq(char * const *l) {
638 STRV_FOREACH(i, l)
639 if (strv_contains(i+1, *i))
640 return false;
642 return true;
645 char** strv_remove(char **l, const char *s) {
646 char **f, **t;
648 if (!l)
649 return NULL;
651 assert(s);
653 /* Drops every occurrence of s in the string list, edits
654 * in-place. */
656 for (f = t = l; *f; f++)
657 if (streq(*f, s))
658 free(*f);
659 else
660 *(t++) = *f;
662 *t = NULL;
663 return l;
666 bool strv_overlap(char * const *a, char * const *b) {
667 STRV_FOREACH(i, a)
668 if (strv_contains(b, *i))
669 return true;
671 return false;
674 static int str_compare(char * const *a, char * const *b) {
675 return strcmp(*a, *b);
678 char** strv_sort(char **l) {
679 typesafe_qsort(l, strv_length(l), str_compare);
680 return l;
683 int strv_compare(char * const *a, char * const *b) {
684 int r;
686 if (strv_isempty(a)) {
687 if (strv_isempty(b))
688 return 0;
689 else
690 return -1;
693 if (strv_isempty(b))
694 return 1;
696 for ( ; *a || *b; ++a, ++b) {
697 r = strcmp_ptr(*a, *b);
698 if (r != 0)
699 return r;
702 return 0;
705 void strv_print_full(char * const *l, const char *prefix) {
706 STRV_FOREACH(s, l)
707 printf("%s%s\n", strempty(prefix), *s);
710 int strv_extendf(char ***l, const char *format, ...) {
711 va_list ap;
712 char *x;
713 int r;
715 va_start(ap, format);
716 r = vasprintf(&x, format, ap);
717 va_end(ap);
719 if (r < 0)
720 return -ENOMEM;
722 return strv_consume(l, x);
725 char** strv_reverse(char **l) {
726 size_t n;
728 n = strv_length(l);
729 if (n <= 1)
730 return l;
732 for (size_t i = 0; i < n / 2; i++)
733 SWAP_TWO(l[i], l[n-1-i]);
735 return l;
738 char** strv_shell_escape(char **l, const char *bad) {
739 /* Escapes every character in every string in l that is in bad,
740 * edits in-place, does not roll-back on error. */
742 STRV_FOREACH(s, l) {
743 char *v;
745 v = shell_escape(*s, bad);
746 if (!v)
747 return NULL;
749 free_and_replace(*s, v);
752 return l;
755 bool strv_fnmatch_full(
756 char* const* patterns,
757 const char *s,
758 int flags,
759 size_t *ret_matched_pos) {
761 assert(s);
763 if (patterns)
764 for (size_t i = 0; patterns[i]; i++)
765 /* NB: We treat all fnmatch() errors as equivalent to FNM_NOMATCH, i.e. if fnmatch() fails to
766 * process the pattern for some reason we'll consider this equivalent to non-matching. */
767 if (fnmatch(patterns[i], s, flags) == 0) {
768 if (ret_matched_pos)
769 *ret_matched_pos = i;
770 return true;
773 if (ret_matched_pos)
774 *ret_matched_pos = SIZE_MAX;
776 return false;
779 char** strv_skip(char **l, size_t n) {
781 while (n > 0) {
782 if (strv_isempty(l))
783 return l;
785 l++, n--;
788 return l;
791 int strv_extend_n(char ***l, const char *value, size_t n) {
792 size_t i, k;
793 char **nl;
795 assert(l);
797 if (!value)
798 return 0;
799 if (n == 0)
800 return 0;
802 /* Adds the value n times to l */
804 k = strv_length(*l);
805 if (n >= SIZE_MAX - k)
806 return -ENOMEM;
808 nl = reallocarray(*l, GREEDY_ALLOC_ROUND_UP(k + n + 1), sizeof(char *));
809 if (!nl)
810 return -ENOMEM;
812 *l = nl;
814 for (i = k; i < k + n; i++) {
815 nl[i] = strdup(value);
816 if (!nl[i])
817 goto rollback;
819 nl[i] = NULL;
821 return 0;
823 rollback:
824 for (size_t j = k; j < i; j++)
825 free(nl[j]);
826 nl[k] = NULL;
828 return -ENOMEM;
831 int strv_extend_assignment(char ***l, const char *lhs, const char *rhs) {
832 char *j;
834 assert(l);
835 assert(lhs);
837 if (!rhs) /* value is optional, in which case we suppress the field */
838 return 0;
840 j = strjoin(lhs, "=", rhs);
841 if (!j)
842 return -ENOMEM;
844 return strv_consume(l, j);
847 int fputstrv(FILE *f, char * const *l, const char *separator, bool *space) {
848 bool b = false;
849 int r;
851 /* Like fputs(), but for strv, and with a less stupid argument order */
853 if (!space)
854 space = &b;
856 STRV_FOREACH(s, l) {
857 r = fputs_with_space(f, *s, separator, space);
858 if (r < 0)
859 return r;
862 return 0;
865 static int string_strv_hashmap_put_internal(Hashmap *h, const char *key, const char *value) {
866 char **l;
867 int r;
869 l = hashmap_get(h, key);
870 if (l) {
871 /* A list for this key already exists, let's append to it if it is not listed yet */
872 if (strv_contains(l, value))
873 return 0;
875 r = strv_extend(&l, value);
876 if (r < 0)
877 return r;
879 assert_se(hashmap_update(h, key, l) >= 0);
880 } else {
881 /* No list for this key exists yet, create one */
882 _cleanup_strv_free_ char **l2 = NULL;
883 _cleanup_free_ char *t = NULL;
885 t = strdup(key);
886 if (!t)
887 return -ENOMEM;
889 r = strv_extend(&l2, value);
890 if (r < 0)
891 return r;
893 r = hashmap_put(h, t, l2);
894 if (r < 0)
895 return r;
896 TAKE_PTR(t);
897 TAKE_PTR(l2);
900 return 1;
903 int _string_strv_hashmap_put(Hashmap **h, const char *key, const char *value HASHMAP_DEBUG_PARAMS) {
904 int r;
906 r = _hashmap_ensure_allocated(h, &string_strv_hash_ops HASHMAP_DEBUG_PASS_ARGS);
907 if (r < 0)
908 return r;
910 return string_strv_hashmap_put_internal(*h, key, value);
913 int _string_strv_ordered_hashmap_put(OrderedHashmap **h, const char *key, const char *value HASHMAP_DEBUG_PARAMS) {
914 int r;
916 r = _ordered_hashmap_ensure_allocated(h, &string_strv_hash_ops HASHMAP_DEBUG_PASS_ARGS);
917 if (r < 0)
918 return r;
920 return string_strv_hashmap_put_internal(PLAIN_HASHMAP(*h), key, value);
923 DEFINE_HASH_OPS_FULL(string_strv_hash_ops, char, string_hash_func, string_compare_func, free, char*, strv_free);