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