1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
6 #include "alloc-util.h"
9 #include "extract-word.h"
14 #include "memory-util.h"
15 #include "sort-util.h"
16 #include "string-util.h"
20 char* strv_find(char * const *l
, const char *name
) {
30 char* strv_find_case(char * const *l
, const char *name
) {
34 if (strcaseeq(*i
, name
))
40 char* strv_find_prefix(char * const *l
, const char *name
) {
44 if (startswith(*i
, name
))
50 char* strv_find_startswith(char * const *l
, const char *name
) {
53 /* Like strv_find_prefix, but actually returns only the
54 * suffix, not the whole item */
59 e
= startswith(*i
, name
);
67 static char* strv_find_closest_prefix(char * const *l
, const char *name
) {
68 size_t best_distance
= SIZE_MAX
;
74 char *e
= startswith(*s
, name
);
79 if (n
< best_distance
) {
88 static char* strv_find_closest_by_levenshtein(char * const *l
, const char *name
) {
89 ssize_t best_distance
= SSIZE_MAX
;
97 distance
= strlevenshtein(*i
, name
);
99 log_debug_errno(distance
, "Failed to determine Levenshtein distance between %s and %s: %m", *i
, name
);
103 if (distance
> 5) /* If the distance is just too far off, don't make a bad suggestion */
106 if (distance
< best_distance
) {
107 best_distance
= distance
;
115 char* strv_find_closest(char * const *l
, const char *name
) {
118 /* Be more helpful to the user, and give a hint what the user might have wanted to type. We search
119 * with two mechanisms: a simple prefix match and – if that didn't yield results –, a Levenshtein
120 * word distance based match. */
122 char *found
= strv_find_closest_prefix(l
, name
);
126 return strv_find_closest_by_levenshtein(l
, name
);
129 char* strv_find_first_field(char * const *needles
, char * const *haystack
) {
130 STRV_FOREACH(k
, needles
) {
131 char *value
= strv_env_pairs_get((char **)haystack
, *k
);
139 char** strv_free(char **l
) {
146 char** strv_free_erase(char **l
) {
153 void strv_free_many(char ***strvs
, size_t n
) {
154 assert(strvs
|| n
== 0);
156 FOREACH_ARRAY (i
, strvs
, n
)
162 char** strv_copy_n(char * const *l
, size_t m
) {
163 _cleanup_strv_free_
char **result
= NULL
;
166 result
= new(char*, MIN(strv_length(l
), m
) + 1);
185 return TAKE_PTR(result
);
188 int strv_copy_unless_empty(char * const *l
, char ***ret
) {
191 if (strv_isempty(l
)) {
196 char **copy
= strv_copy(l
);
200 *ret
= TAKE_PTR(copy
);
204 size_t strv_length(char * const *l
) {
213 char** strv_new_ap(const char *x
, va_list ap
) {
214 _cleanup_strv_free_
char **a
= NULL
;
218 /* As a special trick we ignore all listed strings that equal
219 * STRV_IGNORE. This is supposed to be used with the
220 * STRV_IFNOTNULL() macro to include possibly NULL strings in
221 * the string list. */
224 for (const char *s
= x
; s
; s
= va_arg(aq
, const char*)) {
225 if (s
== STRV_IGNORE
)
236 for (const char *s
= x
; s
; s
= va_arg(ap
, const char*)) {
237 if (s
== STRV_IGNORE
)
252 char** strv_new_internal(const char *x
, ...) {
257 r
= strv_new_ap(x
, ap
);
263 int strv_extend_strv(char ***a
, char * const *b
, bool filter_duplicates
) {
273 if (p
>= SIZE_MAX
- q
)
276 char **t
= reallocarray(*a
, GREEDY_ALLOC_ROUND_UP(p
+ q
+ 1), sizeof(char *));
284 if (filter_duplicates
&& strv_contains(t
, *s
))
300 free_many_charp(t
+ p
, i
);
305 int strv_extend_strv_consume(char ***a
, char **b
, bool filter_duplicates
) {
306 _cleanup_strv_free_
char **b_consume
= b
;
317 strv_free_and_replace(*a
, b_consume
);
319 if (filter_duplicates
)
322 return strv_length(*a
);
325 if (p
>= SIZE_MAX
- q
)
328 char **t
= reallocarray(*a
, GREEDY_ALLOC_ROUND_UP(p
+ q
+ 1), sizeof(char *));
335 if (!filter_duplicates
) {
336 *mempcpy_typesafe(t
+ p
, b
, q
) = NULL
;
342 if (strv_contains(t
, *s
)) {
356 b_consume
= mfree(b_consume
);
361 int strv_extend_strv_biconcat(char ***a
, const char *prefix
, const char* const *b
, const char *suffix
) {
369 v
= strjoin(strempty(prefix
), *s
, suffix
);
373 r
= strv_consume(a
, v
);
381 int strv_split_newlines_full(char ***ret
, const char *s
, ExtractFlags flags
) {
382 _cleanup_strv_free_
char **l
= NULL
;
388 /* Special version of strv_split_full() that splits on newlines and
389 * suppresses an empty string at the end. */
391 r
= strv_split_full(&l
, s
, NEWLINE
, flags
);
396 if (n
> 0 && isempty(l
[n
- 1])) {
397 l
[n
- 1] = mfree(l
[n
- 1]);
405 char** strv_split_newlines(const char *s
) {
408 if (strv_split_newlines_full(&ret
, s
, 0) < 0)
414 int strv_split_full(char ***t
, const char *s
, const char *separators
, ExtractFlags flags
) {
415 _cleanup_strv_free_
char **l
= NULL
;
423 _cleanup_free_
char *word
= NULL
;
425 r
= extract_first_word(&s
, &word
, separators
, flags
);
431 if (!GREEDY_REALLOC(l
, n
+ 2))
434 l
[n
++] = TAKE_PTR(word
);
449 char** strv_split(const char *s
, const char *separators
) {
452 if (strv_split_full(&ret
, s
, separators
, EXTRACT_RETAIN_ESCAPE
) < 0)
458 int strv_split_and_extend_full(char ***t
, const char *s
, const char *separators
, bool filter_duplicates
, ExtractFlags flags
) {
465 r
= strv_split_full(&l
, s
, separators
, flags
);
469 r
= strv_extend_strv_consume(t
, l
, filter_duplicates
);
473 return (int) strv_length(*t
);
476 int strv_split_and_extend(char ***t
, const char *s
, const char *separators
, bool filter_duplicates
) {
477 return strv_split_and_extend_full(t
, s
, separators
, filter_duplicates
, 0);
480 int strv_split_colon_pairs(char ***t
, const char *s
) {
481 _cleanup_strv_free_
char **l
= NULL
;
489 _cleanup_free_
char *first
= NULL
, *second
= NULL
, *tuple
= NULL
, *second_or_empty
= NULL
;
491 r
= extract_first_word(&s
, &tuple
, NULL
, EXTRACT_UNQUOTE
|EXTRACT_RETAIN_ESCAPE
);
497 const char *p
= tuple
;
498 r
= extract_many_words(&p
, ":", EXTRACT_CUNESCAPE
|EXTRACT_UNESCAPE_SEPARATORS
,
504 /* Enforce that at most 2 colon-separated words are contained in each group */
508 second_or_empty
= strdup(strempty(second
));
509 if (!second_or_empty
)
512 if (!GREEDY_REALLOC(l
, n
+ 3))
515 l
[n
++] = TAKE_PTR(first
);
516 l
[n
++] = TAKE_PTR(second_or_empty
);
532 char* strv_join_full(char * const *l
, const char *separator
, const char *prefix
, bool escape_separator
) {
539 k
= strlen(separator
);
540 m
= strlen_ptr(prefix
);
542 if (escape_separator
) /* If the separator was multi-char, we wouldn't know how to escape it. */
550 bool needs_escaping
= escape_separator
&& strchr(*s
, *separator
);
552 n
+= m
+ strlen(*s
) * (1 + needs_escaping
);
562 e
= stpcpy(e
, separator
);
565 e
= stpcpy(e
, prefix
);
567 bool needs_escaping
= escape_separator
&& strchr(*s
, *separator
);
570 for (size_t i
= 0; (*s
)[i
]; i
++) {
571 if ((*s
)[i
] == *separator
)
584 int strv_push_with_size(char ***l
, size_t *n
, char *value
) {
585 /* n is a pointer to a variable to store the size of l.
586 * If not given (i.e. n is NULL or *n is SIZE_MAX), size will be calculated using strv_length().
587 * If n is not NULL, the size after the push will be returned.
588 * If value is empty, no action is taken and *n is not set. */
593 size_t size
= n
? *n
: SIZE_MAX
;
594 if (size
== SIZE_MAX
)
595 size
= strv_length(*l
);
597 /* Check for overflow */
598 if (size
> SIZE_MAX
-2)
601 char **c
= reallocarray(*l
, GREEDY_ALLOC_ROUND_UP(size
+ 2), sizeof(char*));
614 int strv_push_pair(char ***l
, char *a
, char *b
) {
623 /* Check for overflow */
627 /* increase and check for overflow */
628 c
= reallocarray(*l
, GREEDY_ALLOC_ROUND_UP(n
+ !!a
+ !!b
+ 1), sizeof(char*));
642 int strv_insert(char ***l
, size_t position
, char *value
) {
652 position
= MIN(position
, n
);
654 /* check for overflow and increase */
655 if (n
> SIZE_MAX
- 2)
659 c
= reallocarray(*l
, GREEDY_ALLOC_ROUND_UP(m
), sizeof(char*));
664 memmove(c
+ position
+ 1, c
+ position
, (n
- position
) * sizeof(char*));
673 int strv_consume_with_size(char ***l
, size_t *n
, char *value
) {
676 r
= strv_push_with_size(l
, n
, value
);
683 int strv_consume_pair(char ***l
, char *a
, char *b
) {
686 r
= strv_push_pair(l
, a
, b
);
695 int strv_consume_prepend(char ***l
, char *value
) {
698 r
= strv_push_prepend(l
, value
);
705 int strv_prepend(char ***l
, const char *value
) {
715 return strv_consume_prepend(l
, v
);
718 int strv_extend_with_size(char ***l
, size_t *n
, const char *value
) {
728 return strv_consume_with_size(l
, n
, v
);
731 int strv_extend_many_internal(char ***l
, const char *value
, ...) {
738 m
= n
= strv_length(*l
);
742 for (const char *s
= value
; s
!= POINTER_MAX
; s
= va_arg(ap
, const char*)) {
746 if (m
> SIZE_MAX
-1) { /* overflow */
759 char **c
= reallocarray(*l
, GREEDY_ALLOC_ROUND_UP(m
+1), sizeof(char*));
767 for (const char *s
= value
; s
!= POINTER_MAX
; s
= va_arg(ap
, const char*)) {
781 /* rollback on error */
782 for (size_t j
= n
; j
< i
; j
++)
791 char** strv_uniq(char **l
) {
792 /* Drops duplicate entries. The first identical string will be
793 * kept, the others dropped */
796 strv_remove(i
+1, *i
);
801 bool strv_is_uniq(char * const *l
) {
803 if (strv_contains(i
+1, *i
))
809 char** strv_remove(char **l
, const char *s
) {
817 /* Drops every occurrence of s in the string list, edits
820 for (f
= t
= l
; *f
; f
++)
830 bool strv_overlap(char * const *a
, char * const *b
) {
832 if (strv_contains(b
, *i
))
838 static int str_compare(char * const *a
, char * const *b
) {
839 return strcmp(*a
, *b
);
842 char** strv_sort(char **l
) {
843 typesafe_qsort(l
, strv_length(l
), str_compare
);
847 char** strv_sort_uniq(char **l
) {
851 char **tail
= strv_sort(l
), *prev
= NULL
;
853 if (streq_ptr(*i
, prev
))
856 *(tail
++) = prev
= *i
;
862 int strv_compare(char * const *a
, char * const *b
) {
865 if (strv_isempty(a
)) {
875 for ( ; *a
|| *b
; ++a
, ++b
) {
876 r
= strcmp_ptr(*a
, *b
);
884 bool strv_equal_ignore_order(char * const *a
, char * const *b
) {
886 /* Just like strv_equal(), but doesn't care about the order of elements or about redundant entries
887 * (i.e. it's even ok if the number of entries in the array differ, as long as the difference just
888 * consists of repetitions). */
894 if (!strv_contains(b
, *i
))
898 if (!strv_contains(a
, *i
))
904 void strv_print_full(char * const *l
, const char *prefix
) {
906 printf("%s%s\n", strempty(prefix
), *s
);
909 int strv_extendf(char ***l
, const char *format
, ...) {
914 va_start(ap
, format
);
915 r
= vasprintf(&x
, format
, ap
);
921 return strv_consume(l
, x
);
924 char* startswith_strv(const char *s
, char * const *l
) {
926 char *found
= startswith(s
, *i
);
934 char* endswith_strv(const char *s
, char * const *l
) {
936 char *found
= endswith(s
, *i
);
944 char** strv_reverse(char **l
) {
951 for (size_t i
= 0; i
< n
/ 2; i
++)
952 SWAP_TWO(l
[i
], l
[n
-1-i
]);
957 char** strv_shell_escape(char **l
, const char *bad
) {
958 /* Escapes every character in every string in l that is in bad,
959 * edits in-place, does not roll-back on error. */
964 v
= shell_escape(*s
, bad
);
968 free_and_replace(*s
, v
);
974 bool strv_fnmatch_full(
975 char* const* patterns
,
978 size_t *ret_matched_pos
) {
983 for (size_t i
= 0; patterns
[i
]; i
++)
984 /* NB: We treat all fnmatch() errors as equivalent to FNM_NOMATCH, i.e. if fnmatch() fails to
985 * process the pattern for some reason we'll consider this equivalent to non-matching. */
986 if (fnmatch(patterns
[i
], s
, flags
) == 0) {
988 *ret_matched_pos
= i
;
993 *ret_matched_pos
= SIZE_MAX
;
998 char** strv_skip(char **l
, size_t n
) {
1000 if (strv_isempty(l
))
1006 /* To simplify callers, always return NULL instead of a zero-item array. */
1007 if (strv_isempty(l
))
1012 int strv_extend_n(char ***l
, const char *value
, size_t n
) {
1023 /* Adds the value n times to l */
1025 k
= strv_length(*l
);
1026 if (n
>= SIZE_MAX
- k
)
1029 nl
= reallocarray(*l
, GREEDY_ALLOC_ROUND_UP(k
+ n
+ 1), sizeof(char *));
1035 for (i
= k
; i
< k
+ n
; i
++) {
1036 nl
[i
] = strdup(value
);
1045 for (size_t j
= k
; j
< i
; j
++)
1052 int strv_extend_assignment(char ***l
, const char *lhs
, const char *rhs
) {
1058 if (!rhs
) /* value is optional, in which case we suppress the field */
1061 j
= strjoin(lhs
, "=", rhs
);
1065 return strv_consume(l
, j
);
1068 int fputstrv(FILE *f
, char * const *l
, const char *separator
, bool *space
) {
1074 /* Like fputs(), but for strv, and with a less stupid argument order */
1079 STRV_FOREACH(s
, l
) {
1080 r
= fputs_with_separator(f
, *s
, separator
, space
);
1088 void string_strv_hashmap_remove(Hashmap
*h
, const char *key
, const char *value
) {
1092 char **l
= hashmap_get(h
, key
);
1096 strv_remove(l
, value
);
1097 if (!strv_isempty(l
))
1101 _unused_ _cleanup_free_
char *key_free
= NULL
;
1102 strv_free(hashmap_remove2(h
, key
, (void**) &key_free
));
1105 void string_strv_ordered_hashmap_remove(OrderedHashmap
*h
, const char *key
, const char *value
) {
1106 string_strv_hashmap_remove(PLAIN_HASHMAP(h
), key
, value
);
1109 static int string_strv_hashmap_put_internal(Hashmap
*h
, const char *key
, const char *value
) {
1117 l
= hashmap_get(h
, key
);
1119 /* A list for this key already exists, let's append to it if it is not listed yet */
1120 if (strv_contains(l
, value
))
1123 r
= strv_extend(&l
, value
);
1127 assert_se(hashmap_update(h
, key
, l
) >= 0);
1129 /* No list for this key exists yet, create one */
1130 _cleanup_strv_free_
char **l2
= NULL
;
1131 _cleanup_free_
char *t
= NULL
;
1137 r
= strv_extend(&l2
, value
);
1141 r
= hashmap_put(h
, t
, l2
);
1152 int string_strv_hashmap_put(Hashmap
**h
, const char *key
, const char *value
) {
1159 r
= hashmap_ensure_allocated(h
, &string_hash_ops_free_strv_free
);
1163 return string_strv_hashmap_put_internal(*h
, key
, value
);
1166 int string_strv_ordered_hashmap_put(OrderedHashmap
**h
, const char *key
, const char *value
) {
1173 r
= ordered_hashmap_ensure_allocated(h
, &string_hash_ops_free_strv_free
);
1177 return string_strv_hashmap_put_internal(PLAIN_HASHMAP(*h
), key
, value
);
1180 int strv_rebreak_lines(char **l
, size_t width
, char ***ret
) {
1181 _cleanup_strv_free_
char **broken
= NULL
;
1186 /* Implements a simple UTF-8 line breaking algorithm
1188 * Goes through all entries in *l, and line-breaks each line that is longer than the specified
1189 * character width. Breaks at the end of words/beginning of whitespace. Lines that do not contain whitespace are not
1190 * broken. Retains whitespace at beginning of lines, removes it at end of lines. */
1192 if (width
== SIZE_MAX
) { /* NOP? */
1193 broken
= strv_copy(l
);
1197 *ret
= TAKE_PTR(broken
);
1201 STRV_FOREACH(i
, l
) {
1202 const char *start
= *i
, *whitespace_begin
= NULL
, *whitespace_end
= NULL
;
1203 bool in_prefix
= true; /* still in the whitespace in the beginning of the line? */
1206 for (const char *p
= start
; *p
!= 0; p
= utf8_next_char(p
)) {
1207 if (strchr(NEWLINE
, *p
)) {
1209 whitespace_begin
= whitespace_end
= NULL
;
1211 } else if (strchr(WHITESPACE
, *p
)) {
1212 if (!in_prefix
&& (!whitespace_begin
|| whitespace_end
)) {
1213 whitespace_begin
= p
;
1214 whitespace_end
= NULL
;
1217 if (whitespace_begin
&& !whitespace_end
)
1223 int cw
= utf8_char_console_width(p
);
1225 log_debug_errno(cw
, "Comment to line break contains invalid UTF-8, ignoring.");
1231 if (w
> width
&& whitespace_begin
&& whitespace_end
) {
1232 _cleanup_free_
char *truncated
= NULL
;
1234 truncated
= strndup(start
, whitespace_begin
- start
);
1238 r
= strv_consume(&broken
, TAKE_PTR(truncated
));
1242 p
= start
= whitespace_end
;
1243 whitespace_begin
= whitespace_end
= NULL
;
1248 /* Process rest of the line */
1250 if (in_prefix
) /* Never seen anything non-whitespace? Generate empty line! */
1251 r
= strv_extend(&broken
, "");
1252 else if (whitespace_begin
&& !whitespace_end
) { /* Ends in whitespace? Chop it off! */
1253 _cleanup_free_
char *truncated
= strndup(start
, whitespace_begin
- start
);
1257 r
= strv_consume(&broken
, TAKE_PTR(truncated
));
1258 } else /* Otherwise use line as is */
1259 r
= strv_extend(&broken
, start
);
1264 *ret
= TAKE_PTR(broken
);
1268 char** strv_filter_prefix(char * const *l
, const char *prefix
) {
1270 /* Allocates a copy of 'l', but only copies over entries starting with 'prefix' */
1272 if (isempty(prefix
))
1273 return strv_copy(l
);
1275 _cleanup_strv_free_
char **f
= NULL
;
1278 STRV_FOREACH(i
, l
) {
1279 if (!startswith(*i
, prefix
))
1282 if (strv_extend_with_size(&f
, &sz
, *i
) < 0)