]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/basic/strv.c
tree-wide: replace strv_split_full() with strv_split_extract() everywhere
[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
26d04f86
LP
259char **strv_split_newlines(const char *s) {
260 char **l;
da6053d0 261 size_t n;
26d04f86
LP
262
263 assert(s);
264
265 /* Special version of strv_split() that splits on newlines and
266 * suppresses an empty string at the end */
267
268 l = strv_split(s, NEWLINE);
269 if (!l)
270 return NULL;
271
272 n = strv_length(l);
273 if (n <= 0)
274 return l;
275
ece174c5 276 if (isempty(l[n - 1]))
a1e58e8e 277 l[n - 1] = mfree(l[n - 1]);
26d04f86
LP
278
279 return l;
280}
281
8adaf7bd 282int strv_split_extract(char ***t, const char *s, const char *separators, ExtractFlags flags) {
f88e6be5 283 _cleanup_strv_free_ char **l = NULL;
8dd4c05b 284 size_t n = 0, allocated = 0;
f88e6be5
LP
285 int r;
286
287 assert(t);
288 assert(s);
289
290 for (;;) {
291 _cleanup_free_ char *word = NULL;
292
8adaf7bd 293 r = extract_first_word(&s, &word, separators, flags);
f88e6be5
LP
294 if (r < 0)
295 return r;
ece174c5 296 if (r == 0)
f88e6be5
LP
297 break;
298
299 if (!GREEDY_REALLOC(l, allocated, n + 2))
300 return -ENOMEM;
301
ae2a15bc 302 l[n++] = TAKE_PTR(word);
f88e6be5
LP
303
304 l[n] = NULL;
305 }
306
8dd4c05b 307 if (!l) {
f88e6be5 308 l = new0(char*, 1);
8dd4c05b
LP
309 if (!l)
310 return -ENOMEM;
311 }
f88e6be5 312
ae2a15bc 313 *t = TAKE_PTR(l);
f88e6be5 314
8dd4c05b 315 return (int) n;
f88e6be5
LP
316}
317
a082edd5
LB
318int strv_split_colon_pairs(char ***t, const char *s) {
319 _cleanup_strv_free_ char **l = NULL;
320 size_t n = 0, allocated = 0;
321 int r;
322
323 assert(t);
324 assert(s);
325
326 for (;;) {
327 _cleanup_free_ char *first = NULL, *second = NULL, *tuple = NULL, *second_or_empty = NULL;
328
329 r = extract_first_word(&s, &tuple, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE);
330 if (r < 0)
331 return r;
332 if (r == 0)
333 break;
334
335 const char *p = tuple;
336 r = extract_many_words(&p, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS,
337 &first, &second, NULL);
338 if (r < 0)
339 return r;
340 if (r == 0)
341 continue;
342 /* Enforce that at most 2 colon-separated words are contained in each group */
343 if (!isempty(p))
344 return -EINVAL;
345
346 second_or_empty = strdup(strempty(second));
347 if (!second_or_empty)
348 return -ENOMEM;
349
350 if (!GREEDY_REALLOC(l, allocated, n + 3))
351 return -ENOMEM;
352
353 l[n++] = TAKE_PTR(first);
354 l[n++] = TAKE_PTR(second_or_empty);
355
356 l[n] = NULL;
357 }
358
359 if (!l) {
360 l = new0(char*, 1);
361 if (!l)
362 return -ENOMEM;
363 }
364
365 *t = TAKE_PTR(l);
366
367 return (int) n;
368}
369
479ddcdf
YW
370char *strv_join_prefix(char * const *l, const char *separator, const char *prefix) {
371 char * const *s;
5f9a22c3 372 char *r, *e;
2b9a7d2e 373 size_t n, k, m;
5f9a22c3
LP
374
375 if (!separator)
376 separator = " ";
377
378 k = strlen(separator);
2b9a7d2e 379 m = strlen_ptr(prefix);
5f9a22c3
LP
380
381 n = 0;
382 STRV_FOREACH(s, l) {
afe773b0 383 if (s != l)
5f9a22c3 384 n += k;
2b9a7d2e 385 n += m + strlen(*s);
5f9a22c3
LP
386 }
387
1fd8d04e
LP
388 r = new(char, n+1);
389 if (!r)
5f9a22c3
LP
390 return NULL;
391
392 e = r;
393 STRV_FOREACH(s, l) {
afe773b0 394 if (s != l)
5f9a22c3
LP
395 e = stpcpy(e, separator);
396
2b9a7d2e
YW
397 if (prefix)
398 e = stpcpy(e, prefix);
399
5f9a22c3
LP
400 e = stpcpy(e, *s);
401 }
402
8d49745c
LP
403 *e = 0;
404
5f9a22c3
LP
405 return r;
406}
407
4468addc 408int strv_push(char ***l, char *value) {
5926ccca 409 char **c;
60476376 410 size_t n;
5926ccca
LP
411
412 if (!value)
413 return 0;
414
82dde599 415 n = strv_length(*l);
97569e15 416
60476376
LP
417 /* Check for overflow */
418 if (n > SIZE_MAX-2)
97569e15
LP
419 return -ENOMEM;
420
60476376 421 c = reallocarray(*l, GREEDY_ALLOC_ROUND_UP(n + 2), sizeof(char*));
4468addc 422 if (!c)
82dde599 423 return -ENOMEM;
82dde599 424
4468addc 425 c[n] = value;
82dde599
LP
426 c[n+1] = NULL;
427
5926ccca
LP
428 *l = c;
429 return 0;
430}
431
98940a3c
LP
432int strv_push_pair(char ***l, char *a, char *b) {
433 char **c;
60476376 434 size_t n;
98940a3c
LP
435
436 if (!a && !b)
437 return 0;
438
439 n = strv_length(*l);
440
60476376
LP
441 /* Check for overflow */
442 if (n > SIZE_MAX-3)
98940a3c
LP
443 return -ENOMEM;
444
60476376
LP
445 /* increase and check for overflow */
446 c = reallocarray(*l, GREEDY_ALLOC_ROUND_UP(n + !!a + !!b + 1), sizeof(char*));
98940a3c
LP
447 if (!c)
448 return -ENOMEM;
449
450 if (a)
451 c[n++] = a;
452 if (b)
453 c[n++] = b;
454 c[n] = NULL;
455
456 *l = c;
457 return 0;
458}
459
da6053d0 460int strv_insert(char ***l, size_t position, char *value) {
9a00f57a 461 char **c;
da6053d0 462 size_t n, m, i;
9a00f57a
LP
463
464 if (!value)
465 return 0;
466
467 n = strv_length(*l);
6e888894 468 position = MIN(position, n);
97569e15
LP
469
470 /* increase and check for overflow */
471 m = n + 2;
472 if (m < n)
473 return -ENOMEM;
474
475 c = new(char*, m);
9a00f57a
LP
476 if (!c)
477 return -ENOMEM;
478
6e888894
ZJS
479 for (i = 0; i < position; i++)
480 c[i] = (*l)[i];
481 c[position] = value;
482 for (i = position; i < n; i++)
9a00f57a
LP
483 c[i+1] = (*l)[i];
484
9a00f57a
LP
485 c[n+1] = NULL;
486
487 free(*l);
488 *l = c;
489
490 return 0;
491}
492
6e18964d
ZJS
493int strv_consume(char ***l, char *value) {
494 int r;
495
496 r = strv_push(l, value);
497 if (r < 0)
498 free(value);
499
9a00f57a
LP
500 return r;
501}
502
98940a3c
LP
503int strv_consume_pair(char ***l, char *a, char *b) {
504 int r;
505
506 r = strv_push_pair(l, a, b);
507 if (r < 0) {
508 free(a);
509 free(b);
510 }
511
512 return r;
513}
514
9a00f57a
LP
515int strv_consume_prepend(char ***l, char *value) {
516 int r;
517
518 r = strv_push_prepend(l, value);
519 if (r < 0)
520 free(value);
521
6e18964d
ZJS
522 return r;
523}
524
4468addc
LP
525int strv_extend(char ***l, const char *value) {
526 char *v;
4468addc
LP
527
528 if (!value)
529 return 0;
530
531 v = strdup(value);
532 if (!v)
533 return -ENOMEM;
534
6e18964d 535 return strv_consume(l, v);
4468addc
LP
536}
537
4f4afc88
LP
538int strv_extend_front(char ***l, const char *value) {
539 size_t n, m;
540 char *v, **c;
541
542 assert(l);
543
544 /* Like strv_extend(), but prepends rather than appends the new entry */
545
bcab914f
LP
546 if (!value)
547 return 0;
548
4f4afc88
LP
549 n = strv_length(*l);
550
551 /* Increase and overflow check. */
552 m = n + 2;
553 if (m < n)
554 return -ENOMEM;
555
bcab914f
LP
556 v = strdup(value);
557 if (!v)
558 return -ENOMEM;
4f4afc88 559
aa484f35 560 c = reallocarray(*l, m, sizeof(char*));
4f4afc88
LP
561 if (!c) {
562 free(v);
563 return -ENOMEM;
564 }
565
566 memmove(c+1, c, n * sizeof(char*));
567 c[0] = v;
568 c[n+1] = NULL;
569
570 *l = c;
571 return 0;
572}
573
5f9a22c3 574char **strv_uniq(char **l) {
cba8922f
LP
575 char **i;
576
5f9a22c3
LP
577 /* Drops duplicate entries. The first identical string will be
578 * kept, the others dropped */
579
cba8922f 580 STRV_FOREACH(i, l)
5f9a22c3
LP
581 strv_remove(i+1, *i);
582
583 return l;
584}
585
479ddcdf
YW
586bool strv_is_uniq(char * const *l) {
587 char * const *i;
e1dd6790
LP
588
589 STRV_FOREACH(i, l)
590 if (strv_find(i+1, *i))
591 return false;
592
593 return true;
594}
595
5f9a22c3
LP
596char **strv_remove(char **l, const char *s) {
597 char **f, **t;
598
599 if (!l)
600 return NULL;
601
5d6ab905
LP
602 assert(s);
603
604 /* Drops every occurrence of s in the string list, edits
605 * in-place. */
5f9a22c3 606
e3e45d4f
SP
607 for (f = t = l; *f; f++)
608 if (streq(*f, s))
71ecc858 609 free(*f);
e3e45d4f
SP
610 else
611 *(t++) = *f;
71ecc858
LP
612
613 *t = NULL;
614 return l;
615}
616
21bc923a 617char **strv_parse_nulstr(const char *s, size_t l) {
b60df13b
ZJS
618 /* l is the length of the input data, which will be split at NULs into
619 * elements of the resulting strv. Hence, the number of items in the resulting strv
620 * will be equal to one plus the number of NUL bytes in the l bytes starting at s,
621 * unless s[l-1] is NUL, in which case the final empty string is not stored in
622 * the resulting strv, and length is equal to the number of NUL bytes.
623 *
624 * Note that contrary to a normal nulstr which cannot contain empty strings, because
625 * the input data is terminated by any two consequent NUL bytes, this parser accepts
626 * empty strings in s.
627 */
628
21bc923a 629 const char *p;
da6053d0 630 size_t c = 0, i = 0;
21bc923a
LP
631 char **v;
632
633 assert(s || l <= 0);
634
635 if (l <= 0)
49b832c5 636 return new0(char*, 1);
21bc923a
LP
637
638 for (p = s; p < s + l; p++)
639 if (*p == 0)
640 c++;
641
642 if (s[l-1] != 0)
643 c++;
644
1fd8d04e
LP
645 v = new0(char*, c+1);
646 if (!v)
21bc923a
LP
647 return NULL;
648
649 p = s;
650 while (p < s + l) {
651 const char *e;
652
653 e = memchr(p, 0, s + l - p);
654
1fd8d04e
LP
655 v[i] = strndup(p, e ? e - p : s + l - p);
656 if (!v[i]) {
21bc923a
LP
657 strv_free(v);
658 return NULL;
659 }
660
1fd8d04e
LP
661 i++;
662
21bc923a
LP
663 if (!e)
664 break;
665
666 p = e + 1;
667 }
668
669 assert(i == c);
670
671 return v;
672}
0c85a4f3 673
fabe5c0e
LP
674char **strv_split_nulstr(const char *s) {
675 const char *i;
676 char **r = NULL;
677
678 NULSTR_FOREACH(i, s)
679 if (strv_extend(&r, i) < 0) {
680 strv_free(r);
681 return NULL;
682 }
683
684 if (!r)
bea1a013 685 return strv_new(NULL);
fabe5c0e
LP
686
687 return r;
688}
689
479ddcdf 690int strv_make_nulstr(char * const *l, char **ret, size_t *ret_size) {
b60df13b
ZJS
691 /* A valid nulstr with two NULs at the end will be created, but
692 * q will be the length without the two trailing NULs. Thus the output
693 * string is a valid nulstr and can be iterated over using NULSTR_FOREACH,
694 * and can also be parsed by strv_parse_nulstr as long as the length
695 * is provided separately.
696 */
697
e287086b
LP
698 size_t n_allocated = 0, n = 0;
699 _cleanup_free_ char *m = NULL;
479ddcdf 700 char * const *i;
e287086b 701
479ddcdf
YW
702 assert(ret);
703 assert(ret_size);
e287086b
LP
704
705 STRV_FOREACH(i, l) {
706 size_t z;
707
708 z = strlen(*i);
709
b60df13b 710 if (!GREEDY_REALLOC(m, n_allocated, n + z + 2))
e287086b
LP
711 return -ENOMEM;
712
713 memcpy(m + n, *i, z + 1);
714 n += z + 1;
715 }
716
717 if (!m) {
718 m = new0(char, 1);
719 if (!m)
720 return -ENOMEM;
b60df13b
ZJS
721 n = 1;
722 } else
723 /* make sure there is a second extra NUL at the end of resulting nulstr */
724 m[n] = '\0';
e287086b 725
b60df13b 726 assert(n > 0);
479ddcdf
YW
727 *ret = m;
728 *ret_size = n - 1;
e287086b
LP
729
730 m = NULL;
731
732 return 0;
733}
734
479ddcdf
YW
735bool strv_overlap(char * const *a, char * const *b) {
736 char * const *i;
0c85a4f3 737
e3e45d4f
SP
738 STRV_FOREACH(i, a)
739 if (strv_contains(b, *i))
740 return true;
0c85a4f3
LP
741
742 return false;
743}
857a493d 744
93bab288 745static int str_compare(char * const *a, char * const *b) {
857a493d
LP
746 return strcmp(*a, *b);
747}
748
749char **strv_sort(char **l) {
93bab288 750 typesafe_qsort(l, strv_length(l), str_compare);
857a493d
LP
751 return l;
752}
7c2d8094 753
8b75798d
YW
754int strv_compare(char * const *a, char * const *b) {
755 int r;
e287086b 756
8b75798d
YW
757 if (strv_isempty(a)) {
758 if (strv_isempty(b))
759 return 0;
760 else
761 return -1;
762 }
e287086b
LP
763
764 if (strv_isempty(b))
8b75798d 765 return 1;
0f84a72e 766
8b75798d
YW
767 for ( ; *a || *b; ++a, ++b) {
768 r = strcmp_ptr(*a, *b);
769 if (r != 0)
770 return r;
771 }
0f84a72e 772
8b75798d 773 return 0;
0f84a72e
DH
774}
775
479ddcdf
YW
776void strv_print(char * const *l) {
777 char * const *s;
7c2d8094 778
7c2d8094
TA
779 STRV_FOREACH(s, l)
780 puts(*s);
781}
4de33e7f
LP
782
783int strv_extendf(char ***l, const char *format, ...) {
784 va_list ap;
785 char *x;
786 int r;
787
788 va_start(ap, format);
789 r = vasprintf(&x, format, ap);
790 va_end(ap);
791
792 if (r < 0)
793 return -ENOMEM;
794
795 return strv_consume(l, x);
796}
e1dd6790
LP
797
798char **strv_reverse(char **l) {
da6053d0 799 size_t n, i;
e1dd6790
LP
800
801 n = strv_length(l);
802 if (n <= 1)
803 return l;
804
fc549b96 805 for (i = 0; i < n / 2; i++)
8a3134b2 806 SWAP_TWO(l[i], l[n-1-i]);
e1dd6790
LP
807
808 return l;
809}
bceccd5e 810
04c14b25
RM
811char **strv_shell_escape(char **l, const char *bad) {
812 char **s;
813
814 /* Escapes every character in every string in l that is in bad,
815 * edits in-place, does not roll-back on error. */
816
817 STRV_FOREACH(s, l) {
818 char *v;
819
820 v = shell_escape(*s, bad);
821 if (!v)
822 return NULL;
823
824 free(*s);
825 *s = v;
826 }
827
828 return l;
829}
830
0ef84b80
ZJS
831bool strv_fnmatch_full(char* const* patterns, const char *s, int flags, size_t *matched_pos) {
832 for (size_t i = 0; patterns && patterns[i]; i++)
833 if (fnmatch(patterns[i], s, flags) == 0) {
834 if (matched_pos)
835 *matched_pos = i;
bceccd5e 836 return true;
0ef84b80 837 }
bceccd5e
ZJS
838
839 return false;
840}
fe382237
LP
841
842char ***strv_free_free(char ***l) {
843 char ***i;
844
845 if (!l)
846 return NULL;
847
848 for (i = l; *i; i++)
849 strv_free(*i);
850
6b430fdb 851 return mfree(l);
fe382237 852}
e3ead6bb
LP
853
854char **strv_skip(char **l, size_t n) {
855
856 while (n > 0) {
857 if (strv_isempty(l))
858 return l;
859
860 l++, n--;
861 }
862
863 return l;
864}
8dd4c05b
LP
865
866int strv_extend_n(char ***l, const char *value, size_t n) {
867 size_t i, j, k;
868 char **nl;
869
870 assert(l);
871
872 if (!value)
873 return 0;
874 if (n == 0)
875 return 0;
876
61233823 877 /* Adds the value n times to l */
8dd4c05b
LP
878
879 k = strv_length(*l);
60476376
LP
880 if (n >= SIZE_MAX - k)
881 return -ENOMEM;
8dd4c05b 882
60476376 883 nl = reallocarray(*l, GREEDY_ALLOC_ROUND_UP(k + n + 1), sizeof(char *));
8dd4c05b
LP
884 if (!nl)
885 return -ENOMEM;
886
887 *l = nl;
888
889 for (i = k; i < k + n; i++) {
890 nl[i] = strdup(value);
891 if (!nl[i])
892 goto rollback;
893 }
894
895 nl[i] = NULL;
896 return 0;
897
898rollback:
6fff8ac4 899 for (j = k; j < i; j++)
8dd4c05b
LP
900 free(nl[j]);
901
902 nl[k] = NULL;
5b700370 903 return -ENOMEM;
8dd4c05b 904}
3df9bec5 905
479ddcdf 906int fputstrv(FILE *f, char * const *l, const char *separator, bool *space) {
3df9bec5 907 bool b = false;
479ddcdf 908 char * const *s;
3df9bec5
LP
909 int r;
910
911 /* Like fputs(), but for strv, and with a less stupid argument order */
912
3df9bec5
LP
913 if (!space)
914 space = &b;
915
916 STRV_FOREACH(s, l) {
d390f8ef 917 r = fputs_with_space(f, *s, separator, space);
3df9bec5
LP
918 if (r < 0)
919 return r;
3df9bec5
LP
920 }
921
922 return 0;
923}
cde79109
ZJS
924
925static int string_strv_hashmap_put_internal(Hashmap *h, const char *key, const char *value) {
926 char **l;
927 int r;
928
929 l = hashmap_get(h, key);
930 if (l) {
931 /* A list for this key already exists, let's append to it if it is not listed yet */
932 if (strv_contains(l, value))
933 return 0;
934
935 r = strv_extend(&l, value);
936 if (r < 0)
937 return r;
938
939 assert_se(hashmap_update(h, key, l) >= 0);
940 } else {
941 /* No list for this key exists yet, create one */
942 _cleanup_strv_free_ char **l2 = NULL;
943 _cleanup_free_ char *t = NULL;
944
945 t = strdup(key);
946 if (!t)
947 return -ENOMEM;
948
949 r = strv_extend(&l2, value);
950 if (r < 0)
951 return r;
952
953 r = hashmap_put(h, t, l2);
954 if (r < 0)
955 return r;
956 TAKE_PTR(t);
957 TAKE_PTR(l2);
958 }
959
960 return 1;
961}
962
856e5195 963int _string_strv_hashmap_put(Hashmap **h, const char *key, const char *value HASHMAP_DEBUG_PARAMS) {
cde79109
ZJS
964 int r;
965
856e5195 966 r = _hashmap_ensure_allocated(h, &string_strv_hash_ops HASHMAP_DEBUG_PASS_ARGS);
cde79109
ZJS
967 if (r < 0)
968 return r;
969
970 return string_strv_hashmap_put_internal(*h, key, value);
971}
972
856e5195 973int _string_strv_ordered_hashmap_put(OrderedHashmap **h, const char *key, const char *value HASHMAP_DEBUG_PARAMS) {
cde79109
ZJS
974 int r;
975
856e5195 976 r = _ordered_hashmap_ensure_allocated(h, &string_strv_hash_ops HASHMAP_DEBUG_PASS_ARGS);
cde79109
ZJS
977 if (r < 0)
978 return r;
979
980 return string_strv_hashmap_put_internal(PLAIN_HASHMAP(*h), key, value);
981}
982
983DEFINE_HASH_OPS_FULL(string_strv_hash_ops, char, string_hash_func, string_compare_func, free, char*, strv_free);