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