/src/systemd/src/basic/strv.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* SPDX-License-Identifier: LGPL-2.1-or-later */ |
2 | | #pragma once |
3 | | |
4 | | #include <fnmatch.h> |
5 | | #include <stdarg.h> |
6 | | #include <stdbool.h> |
7 | | #include <stddef.h> |
8 | | #include <stdio.h> |
9 | | |
10 | | #include "alloc-util.h" |
11 | | #include "extract-word.h" |
12 | | #include "hashmap.h" |
13 | | #include "macro.h" |
14 | | #include "string-util.h" |
15 | | |
16 | | char* strv_find(char * const *l, const char *name) _pure_; |
17 | | char* strv_find_case(char * const *l, const char *name) _pure_; |
18 | | char* strv_find_prefix(char * const *l, const char *name) _pure_; |
19 | | char* strv_find_startswith(char * const *l, const char *name) _pure_; |
20 | | |
21 | 0 | #define strv_contains(l, s) (!!strv_find((l), (s))) |
22 | | #define strv_contains_case(l, s) (!!strv_find_case((l), (s))) |
23 | | |
24 | | char** strv_free(char **l); |
25 | | DEFINE_TRIVIAL_CLEANUP_FUNC(char**, strv_free); |
26 | 0 | #define _cleanup_strv_free_ _cleanup_(strv_freep) |
27 | | |
28 | | char** strv_free_erase(char **l); |
29 | | DEFINE_TRIVIAL_CLEANUP_FUNC(char**, strv_free_erase); |
30 | | #define _cleanup_strv_free_erase_ _cleanup_(strv_free_erasep) |
31 | | |
32 | | char** strv_copy(char * const *l); |
33 | | size_t strv_length(char * const *l) _pure_; |
34 | | |
35 | | int strv_extend_strv(char ***a, char * const *b, bool filter_duplicates); |
36 | | int strv_extend_strv_concat(char ***a, char * const *b, const char *suffix); |
37 | | int strv_prepend(char ***l, const char *value); |
38 | | |
39 | | /* _with_size() are lower-level functions where the size can be provided externally, |
40 | | * which allows us to skip iterating over the strv to find the end, which saves |
41 | | * a bit of time and reduces the complexity of appending from O(n²) to O(n). */ |
42 | | |
43 | | int strv_extend_with_size(char ***l, size_t *n, const char *value); |
44 | 0 | static inline int strv_extend(char ***l, const char *value) { |
45 | 0 | return strv_extend_with_size(l, NULL, value); |
46 | 0 | } |
47 | | |
48 | | int strv_extendf(char ***l, const char *format, ...) _printf_(2,0); |
49 | | int strv_extend_front(char ***l, const char *value); |
50 | | |
51 | | int strv_push_with_size(char ***l, size_t *n, char *value); |
52 | 0 | static inline int strv_push(char ***l, char *value) { |
53 | 0 | return strv_push_with_size(l, NULL, value); |
54 | 0 | } |
55 | | int strv_push_pair(char ***l, char *a, char *b); |
56 | | |
57 | | int strv_insert(char ***l, size_t position, char *value); |
58 | | |
59 | 0 | static inline int strv_push_prepend(char ***l, char *value) { |
60 | 0 | return strv_insert(l, 0, value); |
61 | 0 | } |
62 | | |
63 | | int strv_consume_with_size(char ***l, size_t *n, char *value); |
64 | 0 | static inline int strv_consume(char ***l, char *value) { |
65 | 0 | return strv_consume_with_size(l, NULL, value); |
66 | 0 | } |
67 | | |
68 | | int strv_consume_pair(char ***l, char *a, char *b); |
69 | | int strv_consume_prepend(char ***l, char *value); |
70 | | |
71 | | char** strv_remove(char **l, const char *s); |
72 | | char** strv_uniq(char **l); |
73 | | bool strv_is_uniq(char * const *l); |
74 | | |
75 | | int strv_compare(char * const *a, char * const *b); |
76 | 0 | static inline bool strv_equal(char * const *a, char * const *b) { |
77 | 0 | return strv_compare(a, b) == 0; |
78 | 0 | } |
79 | | |
80 | | char** strv_new_internal(const char *x, ...) _sentinel_; |
81 | | char** strv_new_ap(const char *x, va_list ap); |
82 | | #define strv_new(...) strv_new_internal(__VA_ARGS__, NULL) |
83 | | |
84 | | #define STRV_IGNORE ((const char *) POINTER_MAX) |
85 | | |
86 | 0 | static inline const char* STRV_IFNOTNULL(const char *x) { |
87 | 0 | return x ? x : STRV_IGNORE; |
88 | 0 | } |
89 | | |
90 | 0 | static inline bool strv_isempty(char * const *l) { |
91 | 0 | return !l || !*l; |
92 | 0 | } |
93 | | |
94 | | int strv_split_full(char ***t, const char *s, const char *separators, ExtractFlags flags); |
95 | 0 | static inline char** strv_split(const char *s, const char *separators) { |
96 | 0 | char **ret; |
97 | 0 |
|
98 | 0 | if (strv_split_full(&ret, s, separators, EXTRACT_RETAIN_ESCAPE) < 0) |
99 | 0 | return NULL; |
100 | 0 |
|
101 | 0 | return ret; |
102 | 0 | } |
103 | | |
104 | | int strv_split_and_extend_full(char ***t, const char *s, const char *separators, bool filter_duplicates, ExtractFlags flags); |
105 | | #define strv_split_and_extend(t, s, sep, dup) strv_split_and_extend_full(t, s, sep, dup, 0) |
106 | | |
107 | | int strv_split_newlines_full(char ***ret, const char *s, ExtractFlags flags); |
108 | 0 | static inline char** strv_split_newlines(const char *s) { |
109 | 0 | char **ret; |
110 | 0 |
|
111 | 0 | if (strv_split_newlines_full(&ret, s, 0) < 0) |
112 | 0 | return NULL; |
113 | 0 |
|
114 | 0 | return ret; |
115 | 0 | } |
116 | | |
117 | | /* Given a string containing white-space separated tuples of words themselves separated by ':', |
118 | | * returns a vector of strings. If the second element in a tuple is missing, the corresponding |
119 | | * string in the vector is an empty string. */ |
120 | | int strv_split_colon_pairs(char ***t, const char *s); |
121 | | |
122 | | char* strv_join_full(char * const *l, const char *separator, const char *prefix, bool escape_separator); |
123 | 0 | static inline char *strv_join(char * const *l, const char *separator) { |
124 | 0 | return strv_join_full(l, separator, NULL, false); |
125 | 0 | } |
126 | | |
127 | | char** strv_parse_nulstr(const char *s, size_t l); |
128 | | char** strv_split_nulstr(const char *s); |
129 | | int strv_make_nulstr(char * const *l, char **p, size_t *n); |
130 | | |
131 | 0 | static inline int strv_from_nulstr(char ***a, const char *nulstr) { |
132 | 0 | char **t; |
133 | 0 |
|
134 | 0 | t = strv_split_nulstr(nulstr); |
135 | 0 | if (!t) |
136 | 0 | return -ENOMEM; |
137 | 0 | *a = t; |
138 | 0 | return 0; |
139 | 0 | } |
140 | | |
141 | | bool strv_overlap(char * const *a, char * const *b) _pure_; |
142 | | |
143 | | #define _STRV_FOREACH_BACKWARDS(s, l, h, i) \ |
144 | 0 | for (typeof(*(l)) *s, *h = (l), *i = ({ \ |
145 | 0 | size_t _len = strv_length(h); \ |
146 | 0 | _len > 0 ? h + _len - 1 : NULL; \ |
147 | 0 | }); \ |
148 | 0 | (s = i); \ |
149 | 0 | i = PTR_SUB1(i, h)) |
150 | | |
151 | | #define STRV_FOREACH_BACKWARDS(s, l) \ |
152 | 0 | _STRV_FOREACH_BACKWARDS(s, l, UNIQ_T(h, UNIQ), UNIQ_T(i, UNIQ)) |
153 | | |
154 | | #define _STRV_FOREACH_PAIR(x, y, l, i) \ |
155 | | for (typeof(*l) *x, *y, *i = (l); \ |
156 | | i && *(x = i) && *(y = i + 1); \ |
157 | | i += 2) |
158 | | |
159 | | #define STRV_FOREACH_PAIR(x, y, l) \ |
160 | | _STRV_FOREACH_PAIR(x, y, l, UNIQ_T(i, UNIQ)) |
161 | | |
162 | | char** strv_sort(char **l); |
163 | | void strv_print(char * const *l); |
164 | | |
165 | | #define strv_from_stdarg_alloca(first) \ |
166 | | ({ \ |
167 | | char **_l; \ |
168 | | \ |
169 | | if (!first) \ |
170 | | _l = (char**) &first; \ |
171 | | else { \ |
172 | | size_t _n; \ |
173 | | va_list _ap; \ |
174 | | \ |
175 | | _n = 1; \ |
176 | | va_start(_ap, first); \ |
177 | | while (va_arg(_ap, char*)) \ |
178 | | _n++; \ |
179 | | va_end(_ap); \ |
180 | | \ |
181 | | _l = newa(char*, _n+1); \ |
182 | | _l[_n = 0] = (char*) first; \ |
183 | | va_start(_ap, first); \ |
184 | | for (;;) { \ |
185 | | _l[++_n] = va_arg(_ap, char*); \ |
186 | | if (!_l[_n]) \ |
187 | | break; \ |
188 | | } \ |
189 | | va_end(_ap); \ |
190 | | } \ |
191 | | _l; \ |
192 | | }) |
193 | | |
194 | | #define STR_IN_SET(x, ...) strv_contains(STRV_MAKE(__VA_ARGS__), x) |
195 | | #define STRPTR_IN_SET(x, ...) \ |
196 | | ({ \ |
197 | | const char* _x = (x); \ |
198 | | _x && strv_contains(STRV_MAKE(__VA_ARGS__), _x); \ |
199 | | }) |
200 | | |
201 | | #define STRCASE_IN_SET(x, ...) strv_contains_case(STRV_MAKE(__VA_ARGS__), x) |
202 | | #define STRCASEPTR_IN_SET(x, ...) \ |
203 | | ({ \ |
204 | | const char* _x = (x); \ |
205 | | _x && strv_contains_case(STRV_MAKE(__VA_ARGS__), _x); \ |
206 | | }) |
207 | | |
208 | | #define STARTSWITH_SET(p, ...) \ |
209 | | ({ \ |
210 | | const char *_p = (p); \ |
211 | | char *_found = NULL; \ |
212 | | STRV_FOREACH(_i, STRV_MAKE(__VA_ARGS__)) { \ |
213 | | _found = startswith(_p, *_i); \ |
214 | | if (_found) \ |
215 | | break; \ |
216 | | } \ |
217 | | _found; \ |
218 | | }) |
219 | | |
220 | | #define ENDSWITH_SET(p, ...) \ |
221 | | ({ \ |
222 | | const char *_p = (p); \ |
223 | | char *_found = NULL; \ |
224 | | STRV_FOREACH(_i, STRV_MAKE(__VA_ARGS__)) { \ |
225 | | _found = endswith(_p, *_i); \ |
226 | | if (_found) \ |
227 | | break; \ |
228 | | } \ |
229 | | _found; \ |
230 | | }) |
231 | | |
232 | | #define _FOREACH_STRING(uniq, x, y, ...) \ |
233 | | for (const char *x, * const*UNIQ_T(l, uniq) = STRV_MAKE_CONST(({ x = y; }), ##__VA_ARGS__); \ |
234 | | x; \ |
235 | | x = *(++UNIQ_T(l, uniq))) |
236 | | |
237 | | #define FOREACH_STRING(x, y, ...) \ |
238 | | _FOREACH_STRING(UNIQ, x, y, ##__VA_ARGS__) |
239 | | |
240 | | char** strv_reverse(char **l); |
241 | | char** strv_shell_escape(char **l, const char *bad); |
242 | | |
243 | | bool strv_fnmatch_full(char* const* patterns, const char *s, int flags, size_t *ret_matched_pos); |
244 | 0 | static inline bool strv_fnmatch(char* const* patterns, const char *s) { |
245 | 0 | return strv_fnmatch_full(patterns, s, 0, NULL); |
246 | 0 | } |
247 | | |
248 | 0 | static inline bool strv_fnmatch_or_empty(char* const* patterns, const char *s, int flags) { |
249 | 0 | assert(s); |
250 | 0 | return strv_isempty(patterns) || |
251 | 0 | strv_fnmatch_full(patterns, s, flags, NULL); |
252 | 0 | } |
253 | | |
254 | | char** strv_skip(char **l, size_t n); |
255 | | |
256 | | int strv_extend_n(char ***l, const char *value, size_t n); |
257 | | |
258 | | int fputstrv(FILE *f, char * const *l, const char *separator, bool *space); |
259 | | |
260 | | #define strv_free_and_replace(a, b) \ |
261 | | free_and_replace_full(a, b, strv_free) |
262 | | |
263 | | extern const struct hash_ops string_strv_hash_ops; |
264 | | int _string_strv_hashmap_put(Hashmap **h, const char *key, const char *value HASHMAP_DEBUG_PARAMS); |
265 | | int _string_strv_ordered_hashmap_put(OrderedHashmap **h, const char *key, const char *value HASHMAP_DEBUG_PARAMS); |
266 | | #define string_strv_hashmap_put(h, k, v) _string_strv_hashmap_put(h, k, v HASHMAP_DEBUG_SRC_ARGS) |
267 | | #define string_strv_ordered_hashmap_put(h, k, v) _string_strv_ordered_hashmap_put(h, k, v HASHMAP_DEBUG_SRC_ARGS) |