Branch data Line data Source code
1 : : /* SPDX-License-Identifier: LGPL-2.1+ */
2 : :
3 : : #include <errno.h>
4 : : #include <fnmatch.h>
5 : : #include <stdarg.h>
6 : : #include <stdio.h>
7 : : #include <stdlib.h>
8 : : #include <string.h>
9 : :
10 : : #include "alloc-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 : 2330779 : char *strv_find(char **l, const char *name) {
21 : : char **i;
22 : :
23 [ - + ]: 2330779 : assert(name);
24 : :
25 [ + + + + ]: 41730576 : STRV_FOREACH(i, l)
26 [ + + ]: 39402981 : if (streq(*i, name))
27 : 3184 : return *i;
28 : :
29 : 2327595 : return NULL;
30 : : }
31 : :
32 : 20 : char *strv_find_prefix(char **l, const char *name) {
33 : : char **i;
34 : :
35 [ - + ]: 20 : assert(name);
36 : :
37 [ + - + + ]: 44 : STRV_FOREACH(i, l)
38 [ + + ]: 36 : if (startswith(*i, name))
39 : 12 : return *i;
40 : :
41 : 8 : return NULL;
42 : : }
43 : :
44 : 20 : char *strv_find_startswith(char **l, const char *name) {
45 : : char **i, *e;
46 : :
47 [ - + ]: 20 : assert(name);
48 : :
49 : : /* Like strv_find_prefix, but actually returns only the
50 : : * suffix, not the whole item */
51 : :
52 [ + - + + ]: 44 : STRV_FOREACH(i, l) {
53 : 36 : e = startswith(*i, name);
54 [ + + ]: 36 : if (e)
55 : 12 : return e;
56 : : }
57 : :
58 : 8 : return NULL;
59 : : }
60 : :
61 : 475123 : void strv_clear(char **l) {
62 : : char **k;
63 : :
64 [ + + ]: 475123 : if (!l)
65 : 98293 : return;
66 : :
67 [ + + ]: 879505 : for (k = l; *k; k++)
68 : 502675 : free(*k);
69 : :
70 : 376830 : *l = NULL;
71 : : }
72 : :
73 : 121451 : char **strv_free(char **l) {
74 : 121451 : strv_clear(l);
75 : 121451 : return mfree(l);
76 : : }
77 : :
78 : 36 : char **strv_free_erase(char **l) {
79 : : char **i;
80 : :
81 [ + - + + ]: 144 : STRV_FOREACH(i, l)
82 : 108 : erase_and_freep(i);
83 : :
84 : 36 : return mfree(l);
85 : : }
86 : :
87 : 3828 : char **strv_copy(char * const *l) {
88 : : char **r, **k;
89 : :
90 : 3828 : k = r = new(char*, strv_length(l) + 1);
91 [ - + ]: 3828 : if (!r)
92 : 0 : return NULL;
93 : :
94 [ + + ]: 3828 : if (l)
95 [ + + ]: 55544 : for (; *l; k++, l++) {
96 : 51720 : *k = strdup(*l);
97 [ - + ]: 51720 : if (!*k) {
98 : 0 : strv_free(r);
99 : 0 : return NULL;
100 : : }
101 : : }
102 : :
103 : 3828 : *k = NULL;
104 : 3828 : return r;
105 : : }
106 : :
107 : 429655 : size_t strv_length(char * const *l) {
108 : 429655 : size_t n = 0;
109 : :
110 [ + + ]: 429655 : if (!l)
111 : 17212 : return 0;
112 : :
113 [ + + ]: 817115 : for (; *l; l++)
114 : 404672 : n++;
115 : :
116 : 412443 : return n;
117 : : }
118 : :
119 : 1328 : char **strv_new_ap(const char *x, va_list ap) {
120 : : const char *s;
121 : 1328 : _cleanup_strv_free_ char **a = NULL;
122 : 1328 : size_t n = 0, i = 0;
123 : : va_list aq;
124 : :
125 : : /* As a special trick we ignore all listed strings that equal
126 : : * STRV_IGNORE. This is supposed to be used with the
127 : : * STRV_IFNOTNULL() macro to include possibly NULL strings in
128 : : * the string list. */
129 : :
130 [ + + ]: 1328 : if (x) {
131 : 1320 : n = x == STRV_IGNORE ? 0 : 1;
132 : :
133 : 1320 : va_copy(aq, ap);
134 [ + + ]: 16968 : while ((s = va_arg(aq, const char*))) {
135 [ + + ]: 15648 : if (s == STRV_IGNORE)
136 : 980 : continue;
137 : :
138 : 14668 : n++;
139 : : }
140 : :
141 : 1320 : va_end(aq);
142 : : }
143 : :
144 : 1328 : a = new(char*, n+1);
145 [ - + ]: 1328 : if (!a)
146 : 0 : return NULL;
147 : :
148 [ + + ]: 1328 : if (x) {
149 [ + + ]: 1320 : if (x != STRV_IGNORE) {
150 : 1312 : a[i] = strdup(x);
151 [ - + ]: 1312 : if (!a[i])
152 : 0 : return NULL;
153 : 1312 : i++;
154 : : }
155 : :
156 [ + + ]: 16968 : while ((s = va_arg(ap, const char*))) {
157 : :
158 [ + + ]: 15648 : if (s == STRV_IGNORE)
159 : 980 : continue;
160 : :
161 : 14668 : a[i] = strdup(s);
162 [ - + ]: 14668 : if (!a[i])
163 : 0 : return NULL;
164 : :
165 : 14668 : i++;
166 : : }
167 : : }
168 : :
169 : 1328 : a[i] = NULL;
170 : :
171 : 1328 : return TAKE_PTR(a);
172 : : }
173 : :
174 : 1312 : char **strv_new_internal(const char *x, ...) {
175 : : char **r;
176 : : va_list ap;
177 : :
178 : 1312 : va_start(ap, x);
179 : 1312 : r = strv_new_ap(x, ap);
180 : 1312 : va_end(ap);
181 : :
182 : 1312 : return r;
183 : : }
184 : :
185 : 64 : int strv_extend_strv(char ***a, char **b, bool filter_duplicates) {
186 : : char **s, **t;
187 : 64 : size_t p, q, i = 0, j;
188 : :
189 [ - + ]: 64 : assert(a);
190 : :
191 [ + + ]: 64 : if (strv_isempty(b))
192 : 8 : return 0;
193 : :
194 : 56 : p = strv_length(*a);
195 : 56 : q = strv_length(b);
196 : :
197 : 56 : t = reallocarray(*a, p + q + 1, sizeof(char *));
198 [ - + ]: 56 : if (!t)
199 : 0 : return -ENOMEM;
200 : :
201 : 56 : t[p] = NULL;
202 : 56 : *a = t;
203 : :
204 [ + - + + ]: 220 : STRV_FOREACH(s, b) {
205 : :
206 [ + + + + ]: 164 : if (filter_duplicates && strv_contains(t, *s))
207 : 4 : continue;
208 : :
209 : 160 : t[p+i] = strdup(*s);
210 [ - + ]: 160 : if (!t[p+i])
211 : 0 : goto rollback;
212 : :
213 : 160 : i++;
214 : 160 : t[p+i] = NULL;
215 : : }
216 : :
217 [ - + ]: 56 : assert(i <= q);
218 : :
219 : 56 : return (int) i;
220 : :
221 : 0 : rollback:
222 [ # # ]: 0 : for (j = 0; j < i; j++)
223 : 0 : free(t[p + j]);
224 : :
225 : 0 : t[p] = NULL;
226 : 0 : return -ENOMEM;
227 : : }
228 : :
229 : 368 : int strv_extend_strv_concat(char ***a, char **b, const char *suffix) {
230 : : int r;
231 : : char **s;
232 : :
233 [ + + + + ]: 1112 : STRV_FOREACH(s, b) {
234 : : char *v;
235 : :
236 : 744 : v = strjoin(*s, suffix);
237 [ - + ]: 744 : if (!v)
238 : 0 : return -ENOMEM;
239 : :
240 : 744 : r = strv_push(a, v);
241 [ - + ]: 744 : if (r < 0) {
242 : 0 : free(v);
243 : 0 : return r;
244 : : }
245 : : }
246 : :
247 : 368 : return 0;
248 : : }
249 : :
250 : 736 : char **strv_split_full(const char *s, const char *separator, SplitFlags flags) {
251 : : const char *word, *state;
252 : : size_t l;
253 : : size_t n, i;
254 : : char **r;
255 : :
256 [ - + ]: 736 : assert(s);
257 : :
258 [ + + ]: 736 : if (!separator)
259 : 56 : separator = WHITESPACE;
260 : :
261 : 736 : s += strspn(s, separator);
262 [ + + ]: 736 : if (isempty(s))
263 : 52 : return new0(char*, 1);
264 : :
265 : 684 : n = 0;
266 [ + + ]: 2092 : _FOREACH_WORD(word, l, s, separator, flags, state)
267 : 1408 : n++;
268 : :
269 : 684 : r = new(char*, n+1);
270 [ - + ]: 684 : if (!r)
271 : 0 : return NULL;
272 : :
273 : 684 : i = 0;
274 [ + + ]: 2092 : _FOREACH_WORD(word, l, s, separator, flags, state) {
275 : 1408 : r[i] = strndup(word, l);
276 [ - + ]: 1408 : if (!r[i]) {
277 : 0 : strv_free(r);
278 : 0 : return NULL;
279 : : }
280 : :
281 : 1408 : i++;
282 : : }
283 : :
284 : 684 : r[i] = NULL;
285 : 684 : return r;
286 : : }
287 : :
288 : 32 : char **strv_split_newlines(const char *s) {
289 : : char **l;
290 : : size_t n;
291 : :
292 [ - + ]: 32 : assert(s);
293 : :
294 : : /* Special version of strv_split() that splits on newlines and
295 : : * suppresses an empty string at the end */
296 : :
297 : 32 : l = strv_split(s, NEWLINE);
298 [ - + ]: 32 : if (!l)
299 : 0 : return NULL;
300 : :
301 : 32 : n = strv_length(l);
302 [ - + ]: 32 : if (n <= 0)
303 : 0 : return l;
304 : :
305 [ - + ]: 32 : if (isempty(l[n - 1]))
306 : 0 : l[n - 1] = mfree(l[n - 1]);
307 : :
308 : 32 : return l;
309 : : }
310 : :
311 : 2984 : int strv_split_extract(char ***t, const char *s, const char *separators, ExtractFlags flags) {
312 : 2984 : _cleanup_strv_free_ char **l = NULL;
313 : 2984 : size_t n = 0, allocated = 0;
314 : : int r;
315 : :
316 [ - + ]: 2984 : assert(t);
317 [ - + ]: 2984 : assert(s);
318 : :
319 : 14092 : for (;;) {
320 [ + + + ]: 17076 : _cleanup_free_ char *word = NULL;
321 : :
322 : 17076 : r = extract_first_word(&s, &word, separators, flags);
323 [ + + ]: 17076 : if (r < 0)
324 : 28 : return r;
325 [ + + ]: 17048 : if (r == 0)
326 : 2956 : break;
327 : :
328 [ - + ]: 14092 : if (!GREEDY_REALLOC(l, allocated, n + 2))
329 : 0 : return -ENOMEM;
330 : :
331 : 14092 : l[n++] = TAKE_PTR(word);
332 : :
333 : 14092 : l[n] = NULL;
334 : : }
335 : :
336 [ + + ]: 2956 : if (!l) {
337 : 12 : l = new0(char*, 1);
338 [ - + ]: 12 : if (!l)
339 : 0 : return -ENOMEM;
340 : : }
341 : :
342 : 2956 : *t = TAKE_PTR(l);
343 : :
344 : 2956 : return (int) n;
345 : : }
346 : :
347 : 2408 : char *strv_join_prefix(char **l, const char *separator, const char *prefix) {
348 : : char *r, *e;
349 : : char **s;
350 : : size_t n, k, m;
351 : :
352 [ + + ]: 2408 : if (!separator)
353 : 8 : separator = " ";
354 : :
355 : 2408 : k = strlen(separator);
356 : 2408 : m = strlen_ptr(prefix);
357 : :
358 : 2408 : n = 0;
359 [ + + + + ]: 5804 : STRV_FOREACH(s, l) {
360 [ + + ]: 3396 : if (s != l)
361 : 1064 : n += k;
362 : 3396 : n += m + strlen(*s);
363 : : }
364 : :
365 : 2408 : r = new(char, n+1);
366 [ - + ]: 2408 : if (!r)
367 : 0 : return NULL;
368 : :
369 : 2408 : e = r;
370 [ + + + + ]: 5804 : STRV_FOREACH(s, l) {
371 [ + + ]: 3396 : if (s != l)
372 : 1064 : e = stpcpy(e, separator);
373 : :
374 [ + + ]: 3396 : if (prefix)
375 : 52 : e = stpcpy(e, prefix);
376 : :
377 : 3396 : e = stpcpy(e, *s);
378 : : }
379 : :
380 : 2408 : *e = 0;
381 : :
382 : 2408 : return r;
383 : : }
384 : :
385 : 412372 : int strv_push(char ***l, char *value) {
386 : : char **c;
387 : : size_t n, m;
388 : :
389 [ - + ]: 412372 : if (!value)
390 : 0 : return 0;
391 : :
392 : 412372 : n = strv_length(*l);
393 : :
394 : : /* Increase and check for overflow */
395 : 412372 : m = n + 2;
396 [ - + ]: 412372 : if (m < n)
397 : 0 : return -ENOMEM;
398 : :
399 : 412372 : c = reallocarray(*l, m, sizeof(char*));
400 [ - + ]: 412372 : if (!c)
401 : 0 : return -ENOMEM;
402 : :
403 : 412372 : c[n] = value;
404 : 412372 : c[n+1] = NULL;
405 : :
406 : 412372 : *l = c;
407 : 412372 : return 0;
408 : : }
409 : :
410 : 48 : int strv_push_pair(char ***l, char *a, char *b) {
411 : : char **c;
412 : : size_t n, m;
413 : :
414 [ - + # # ]: 48 : if (!a && !b)
415 : 0 : return 0;
416 : :
417 : 48 : n = strv_length(*l);
418 : :
419 : : /* increase and check for overflow */
420 : 48 : m = n + !!a + !!b + 1;
421 [ - + ]: 48 : if (m < n)
422 : 0 : return -ENOMEM;
423 : :
424 : 48 : c = reallocarray(*l, m, sizeof(char*));
425 [ - + ]: 48 : if (!c)
426 : 0 : return -ENOMEM;
427 : :
428 [ + - ]: 48 : if (a)
429 : 48 : c[n++] = a;
430 [ + - ]: 48 : if (b)
431 : 48 : c[n++] = b;
432 : 48 : c[n] = NULL;
433 : :
434 : 48 : *l = c;
435 : 48 : return 0;
436 : : }
437 : :
438 : 76 : int strv_insert(char ***l, size_t position, char *value) {
439 : : char **c;
440 : : size_t n, m, i;
441 : :
442 [ + + ]: 76 : if (!value)
443 : 4 : return 0;
444 : :
445 : 72 : n = strv_length(*l);
446 : 72 : position = MIN(position, n);
447 : :
448 : : /* increase and check for overflow */
449 : 72 : m = n + 2;
450 [ - + ]: 72 : if (m < n)
451 : 0 : return -ENOMEM;
452 : :
453 : 72 : c = new(char*, m);
454 [ - + ]: 72 : if (!c)
455 : 0 : return -ENOMEM;
456 : :
457 [ + + ]: 136 : for (i = 0; i < position; i++)
458 : 64 : c[i] = (*l)[i];
459 : 72 : c[position] = value;
460 [ + + ]: 132 : for (i = position; i < n; i++)
461 : 60 : c[i+1] = (*l)[i];
462 : :
463 : 72 : c[n+1] = NULL;
464 : :
465 : 72 : free(*l);
466 : 72 : *l = c;
467 : :
468 : 72 : return 0;
469 : : }
470 : :
471 : 410992 : int strv_consume(char ***l, char *value) {
472 : : int r;
473 : :
474 : 410992 : r = strv_push(l, value);
475 [ - + ]: 410992 : if (r < 0)
476 : 0 : free(value);
477 : :
478 : 410992 : return r;
479 : : }
480 : :
481 : 0 : int strv_consume_pair(char ***l, char *a, char *b) {
482 : : int r;
483 : :
484 : 0 : r = strv_push_pair(l, a, b);
485 [ # # ]: 0 : if (r < 0) {
486 : 0 : free(a);
487 : 0 : free(b);
488 : : }
489 : :
490 : 0 : return r;
491 : : }
492 : :
493 : 4 : int strv_consume_prepend(char ***l, char *value) {
494 : : int r;
495 : :
496 : 4 : r = strv_push_prepend(l, value);
497 [ - + ]: 4 : if (r < 0)
498 : 0 : free(value);
499 : :
500 : 4 : return r;
501 : : }
502 : :
503 : 6732 : int strv_extend(char ***l, const char *value) {
504 : : char *v;
505 : :
506 [ + + ]: 6732 : if (!value)
507 : 4 : return 0;
508 : :
509 : 6728 : v = strdup(value);
510 [ - + ]: 6728 : if (!v)
511 : 0 : return -ENOMEM;
512 : :
513 : 6728 : return strv_consume(l, v);
514 : : }
515 : :
516 : 0 : int strv_extend_front(char ***l, const char *value) {
517 : : size_t n, m;
518 : : char *v, **c;
519 : :
520 [ # # ]: 0 : assert(l);
521 : :
522 : : /* Like strv_extend(), but prepends rather than appends the new entry */
523 : :
524 [ # # ]: 0 : if (!value)
525 : 0 : return 0;
526 : :
527 : 0 : n = strv_length(*l);
528 : :
529 : : /* Increase and overflow check. */
530 : 0 : m = n + 2;
531 [ # # ]: 0 : if (m < n)
532 : 0 : return -ENOMEM;
533 : :
534 : 0 : v = strdup(value);
535 [ # # ]: 0 : if (!v)
536 : 0 : return -ENOMEM;
537 : :
538 : 0 : c = reallocarray(*l, m, sizeof(char*));
539 [ # # ]: 0 : if (!c) {
540 : 0 : free(v);
541 : 0 : return -ENOMEM;
542 : : }
543 : :
544 : 0 : memmove(c+1, c, n * sizeof(char*));
545 : 0 : c[0] = v;
546 : 0 : c[n+1] = NULL;
547 : :
548 : 0 : *l = c;
549 : 0 : return 0;
550 : : }
551 : :
552 : 5132 : char **strv_uniq(char **l) {
553 : : char **i;
554 : :
555 : : /* Drops duplicate entries. The first identical string will be
556 : : * kept, the others dropped */
557 : :
558 [ + + + + ]: 65084 : STRV_FOREACH(i, l)
559 : 59952 : strv_remove(i+1, *i);
560 : :
561 : 5132 : return l;
562 : : }
563 : :
564 : 16 : bool strv_is_uniq(char **l) {
565 : : char **i;
566 : :
567 [ + - + + ]: 32 : STRV_FOREACH(i, l)
568 [ + + ]: 20 : if (strv_find(i+1, *i))
569 : 4 : return false;
570 : :
571 : 12 : return true;
572 : : }
573 : :
574 : 59952 : char **strv_remove(char **l, const char *s) {
575 : : char **f, **t;
576 : :
577 [ - + ]: 59952 : if (!l)
578 : 0 : return NULL;
579 : :
580 [ - + ]: 59952 : assert(s);
581 : :
582 : : /* Drops every occurrence of s in the string list, edits
583 : : * in-place. */
584 : :
585 [ + + ]: 456980 : for (f = t = l; *f; f++)
586 [ + + ]: 397028 : if (streq(*f, s))
587 : 3872 : free(*f);
588 : : else
589 : 393156 : *(t++) = *f;
590 : :
591 : 59952 : *t = NULL;
592 : 59952 : return l;
593 : : }
594 : :
595 : 36 : char **strv_parse_nulstr(const char *s, size_t l) {
596 : : /* l is the length of the input data, which will be split at NULs into
597 : : * elements of the resulting strv. Hence, the number of items in the resulting strv
598 : : * will be equal to one plus the number of NUL bytes in the l bytes starting at s,
599 : : * unless s[l-1] is NUL, in which case the final empty string is not stored in
600 : : * the resulting strv, and length is equal to the number of NUL bytes.
601 : : *
602 : : * Note that contrary to a normal nulstr which cannot contain empty strings, because
603 : : * the input data is terminated by any two consequent NUL bytes, this parser accepts
604 : : * empty strings in s.
605 : : */
606 : :
607 : : const char *p;
608 : 36 : size_t c = 0, i = 0;
609 : : char **v;
610 : :
611 [ - + # # ]: 36 : assert(s || l <= 0);
612 : :
613 [ + + ]: 36 : if (l <= 0)
614 : 8 : return new0(char*, 1);
615 : :
616 [ + + ]: 788 : for (p = s; p < s + l; p++)
617 [ + + ]: 760 : if (*p == 0)
618 : 80 : c++;
619 : :
620 [ + + ]: 28 : if (s[l-1] != 0)
621 : 16 : c++;
622 : :
623 [ + - ]: 28 : v = new0(char*, c+1);
624 [ - + ]: 28 : if (!v)
625 : 0 : return NULL;
626 : :
627 : 28 : p = s;
628 [ + + ]: 108 : while (p < s + l) {
629 : : const char *e;
630 : :
631 : 96 : e = memchr(p, 0, s + l - p);
632 : :
633 [ + + ]: 96 : v[i] = strndup(p, e ? e - p : s + l - p);
634 [ - + ]: 96 : if (!v[i]) {
635 : 0 : strv_free(v);
636 : 0 : return NULL;
637 : : }
638 : :
639 : 96 : i++;
640 : :
641 [ + + ]: 96 : if (!e)
642 : 16 : break;
643 : :
644 : 80 : p = e + 1;
645 : : }
646 : :
647 [ - + ]: 28 : assert(i == c);
648 : :
649 : 28 : return v;
650 : : }
651 : :
652 : 236 : char **strv_split_nulstr(const char *s) {
653 : : const char *i;
654 : 236 : char **r = NULL;
655 : :
656 [ + - + + ]: 1156 : NULSTR_FOREACH(i, s)
657 [ - + ]: 920 : if (strv_extend(&r, i) < 0) {
658 : 0 : strv_free(r);
659 : 0 : return NULL;
660 : : }
661 : :
662 [ - + ]: 236 : if (!r)
663 : 0 : return strv_new(NULL);
664 : :
665 : 236 : return r;
666 : : }
667 : :
668 : 40 : int strv_make_nulstr(char **l, char **p, size_t *q) {
669 : : /* A valid nulstr with two NULs at the end will be created, but
670 : : * q will be the length without the two trailing NULs. Thus the output
671 : : * string is a valid nulstr and can be iterated over using NULSTR_FOREACH,
672 : : * and can also be parsed by strv_parse_nulstr as long as the length
673 : : * is provided separately.
674 : : */
675 : :
676 : 40 : size_t n_allocated = 0, n = 0;
677 : 40 : _cleanup_free_ char *m = NULL;
678 : : char **i;
679 : :
680 [ - + ]: 40 : assert(p);
681 [ - + ]: 40 : assert(q);
682 : :
683 [ + + + + ]: 88 : STRV_FOREACH(i, l) {
684 : : size_t z;
685 : :
686 : 48 : z = strlen(*i);
687 : :
688 [ - + ]: 48 : if (!GREEDY_REALLOC(m, n_allocated, n + z + 2))
689 : 0 : return -ENOMEM;
690 : :
691 : 48 : memcpy(m + n, *i, z + 1);
692 : 48 : n += z + 1;
693 : : }
694 : :
695 [ + + ]: 40 : if (!m) {
696 : 16 : m = new0(char, 1);
697 [ - + ]: 16 : if (!m)
698 : 0 : return -ENOMEM;
699 : 16 : n = 1;
700 : : } else
701 : : /* make sure there is a second extra NUL at the end of resulting nulstr */
702 : 24 : m[n] = '\0';
703 : :
704 [ - + ]: 40 : assert(n > 0);
705 : 40 : *p = m;
706 : 40 : *q = n - 1;
707 : :
708 : 40 : m = NULL;
709 : :
710 : 40 : return 0;
711 : : }
712 : :
713 : 8 : bool strv_overlap(char **a, char **b) {
714 : : char **i;
715 : :
716 [ + - + + ]: 24 : STRV_FOREACH(i, a)
717 [ + + ]: 20 : if (strv_contains(b, *i))
718 : 4 : return true;
719 : :
720 : 4 : return false;
721 : : }
722 : :
723 : 54096 : static int str_compare(char * const *a, char * const *b) {
724 : 54096 : return strcmp(*a, *b);
725 : : }
726 : :
727 : 83 : char **strv_sort(char **l) {
728 : 83 : typesafe_qsort(l, strv_length(l), str_compare);
729 : 83 : return l;
730 : : }
731 : :
732 : 5140 : bool strv_equal(char **a, char **b) {
733 : :
734 [ + + ]: 5140 : if (strv_isempty(a))
735 : 4868 : return strv_isempty(b);
736 : :
737 [ + + ]: 272 : if (strv_isempty(b))
738 : 4 : return false;
739 : :
740 [ + + + + ]: 972 : for ( ; *a || *b; ++a, ++b)
741 [ + + ]: 712 : if (!streq_ptr(*a, *b))
742 : 8 : return false;
743 : :
744 : 260 : return true;
745 : : }
746 : :
747 : 20 : void strv_print(char **l) {
748 : : char **s;
749 : :
750 [ + - + + ]: 88 : STRV_FOREACH(s, l)
751 : 68 : puts(*s);
752 : 20 : }
753 : :
754 : 8 : int strv_extendf(char ***l, const char *format, ...) {
755 : : va_list ap;
756 : : char *x;
757 : : int r;
758 : :
759 : 8 : va_start(ap, format);
760 : 8 : r = vasprintf(&x, format, ap);
761 : 8 : va_end(ap);
762 : :
763 [ - + ]: 8 : if (r < 0)
764 : 0 : return -ENOMEM;
765 : :
766 : 8 : return strv_consume(l, x);
767 : : }
768 : :
769 : 16 : char **strv_reverse(char **l) {
770 : : size_t n, i;
771 : :
772 : 16 : n = strv_length(l);
773 [ + + ]: 16 : if (n <= 1)
774 : 8 : return l;
775 : :
776 [ + + ]: 16 : for (i = 0; i < n / 2; i++)
777 : 8 : SWAP_TWO(l[i], l[n-1-i]);
778 : :
779 : 8 : return l;
780 : : }
781 : :
782 : 4 : char **strv_shell_escape(char **l, const char *bad) {
783 : : char **s;
784 : :
785 : : /* Escapes every character in every string in l that is in bad,
786 : : * edits in-place, does not roll-back on error. */
787 : :
788 [ + - + + ]: 16 : STRV_FOREACH(s, l) {
789 : : char *v;
790 : :
791 : 12 : v = shell_escape(*s, bad);
792 [ - + ]: 12 : if (!v)
793 : 0 : return NULL;
794 : :
795 : 12 : free(*s);
796 : 12 : *s = v;
797 : : }
798 : :
799 : 4 : return l;
800 : : }
801 : :
802 : 12 : bool strv_fnmatch(char* const* patterns, const char *s, int flags) {
803 : : char* const* p;
804 : :
805 [ + - + + ]: 16 : STRV_FOREACH(p, patterns)
806 [ + + ]: 8 : if (fnmatch(*p, s, flags) == 0)
807 : 4 : return true;
808 : :
809 : 8 : return false;
810 : : }
811 : :
812 : 4 : char ***strv_free_free(char ***l) {
813 : : char ***i;
814 : :
815 [ - + ]: 4 : if (!l)
816 : 0 : return NULL;
817 : :
818 [ + + ]: 12 : for (i = l; *i; i++)
819 : 8 : strv_free(*i);
820 : :
821 : 4 : return mfree(l);
822 : : }
823 : :
824 : 52 : char **strv_skip(char **l, size_t n) {
825 : :
826 [ + + ]: 112 : while (n > 0) {
827 [ + + ]: 80 : if (strv_isempty(l))
828 : 20 : return l;
829 : :
830 : 60 : l++, n--;
831 : : }
832 : :
833 : 32 : return l;
834 : : }
835 : :
836 : 16 : int strv_extend_n(char ***l, const char *value, size_t n) {
837 : : size_t i, j, k;
838 : : char **nl;
839 : :
840 [ - + ]: 16 : assert(l);
841 : :
842 [ - + ]: 16 : if (!value)
843 : 0 : return 0;
844 [ + + ]: 16 : if (n == 0)
845 : 4 : return 0;
846 : :
847 : : /* Adds the value n times to l */
848 : :
849 : 12 : k = strv_length(*l);
850 : :
851 : 12 : nl = reallocarray(*l, k + n + 1, sizeof(char *));
852 [ - + ]: 12 : if (!nl)
853 : 0 : return -ENOMEM;
854 : :
855 : 12 : *l = nl;
856 : :
857 [ + + ]: 36 : for (i = k; i < k + n; i++) {
858 : 24 : nl[i] = strdup(value);
859 [ - + ]: 24 : if (!nl[i])
860 : 0 : goto rollback;
861 : : }
862 : :
863 : 12 : nl[i] = NULL;
864 : 12 : return 0;
865 : :
866 : 0 : rollback:
867 [ # # ]: 0 : for (j = k; j < i; j++)
868 : 0 : free(nl[j]);
869 : :
870 : 0 : nl[k] = NULL;
871 : 0 : return -ENOMEM;
872 : : }
873 : :
874 : 0 : int fputstrv(FILE *f, char **l, const char *separator, bool *space) {
875 : 0 : bool b = false;
876 : : char **s;
877 : : int r;
878 : :
879 : : /* Like fputs(), but for strv, and with a less stupid argument order */
880 : :
881 [ # # ]: 0 : if (!space)
882 : 0 : space = &b;
883 : :
884 [ # # # # ]: 0 : STRV_FOREACH(s, l) {
885 : 0 : r = fputs_with_space(f, *s, separator, space);
886 [ # # ]: 0 : if (r < 0)
887 : 0 : return r;
888 : : }
889 : :
890 : 0 : return 0;
891 : : }
892 : :
893 : 3356 : static int string_strv_hashmap_put_internal(Hashmap *h, const char *key, const char *value) {
894 : : char **l;
895 : : int r;
896 : :
897 : 3356 : l = hashmap_get(h, key);
898 [ + + ]: 3356 : if (l) {
899 : : /* A list for this key already exists, let's append to it if it is not listed yet */
900 [ + + ]: 376 : if (strv_contains(l, value))
901 : 36 : return 0;
902 : :
903 : 340 : r = strv_extend(&l, value);
904 [ - + ]: 340 : if (r < 0)
905 : 0 : return r;
906 : :
907 [ - + ]: 340 : assert_se(hashmap_update(h, key, l) >= 0);
908 : : } else {
909 : : /* No list for this key exists yet, create one */
910 [ + - ]: 2980 : _cleanup_strv_free_ char **l2 = NULL;
911 [ + - ]: 2980 : _cleanup_free_ char *t = NULL;
912 : :
913 : 2980 : t = strdup(key);
914 [ - + ]: 2980 : if (!t)
915 : 0 : return -ENOMEM;
916 : :
917 : 2980 : r = strv_extend(&l2, value);
918 [ - + ]: 2980 : if (r < 0)
919 : 0 : return r;
920 : :
921 : 2980 : r = hashmap_put(h, t, l2);
922 [ - + ]: 2980 : if (r < 0)
923 : 0 : return r;
924 : 2980 : TAKE_PTR(t);
925 : 2980 : TAKE_PTR(l2);
926 : : }
927 : :
928 : 3320 : return 1;
929 : : }
930 : :
931 : 3326 : int string_strv_hashmap_put(Hashmap **h, const char *key, const char *value) {
932 : : int r;
933 : :
934 : 3326 : r = hashmap_ensure_allocated(h, &string_strv_hash_ops);
935 [ - + ]: 3326 : if (r < 0)
936 : 0 : return r;
937 : :
938 : 3326 : return string_strv_hashmap_put_internal(*h, key, value);
939 : : }
940 : :
941 : 30 : int string_strv_ordered_hashmap_put(OrderedHashmap **h, const char *key, const char *value) {
942 : : int r;
943 : :
944 : 30 : r = ordered_hashmap_ensure_allocated(h, &string_strv_hash_ops);
945 [ - + ]: 30 : if (r < 0)
946 : 0 : return r;
947 : :
948 : 30 : return string_strv_hashmap_put_internal(PLAIN_HASHMAP(*h), key, value);
949 : : }
950 : :
951 : 5960 : DEFINE_HASH_OPS_FULL(string_strv_hash_ops, char, string_hash_func, string_compare_func, free, char*, strv_free);
|