]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/basic/strv.c
tree-wide: use free_and_replace() more
[thirdparty/systemd.git] / src / basic / strv.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
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"
2ed74695 10#include "env-util.h"
4f5dd394 11#include "escape.h"
11c3a366 12#include "extract-word.h"
d390f8ef 13#include "fileio.h"
309c6b19 14#include "memory-util.h"
d8b4d14d 15#include "nulstr-util.h"
760877e9 16#include "sort-util.h"
07630cea 17#include "string-util.h"
60918275
LP
18#include "strv.h"
19
14337c37 20char* strv_find(char * const *l, const char *name) {
60918275
LP
21 assert(name);
22
5f9a22c3
LP
23 STRV_FOREACH(i, l)
24 if (streq(*i, name))
25 return *i;
60918275
LP
26
27 return NULL;
28}
29
14337c37 30char* strv_find_case(char * const *l, const char *name) {
ddd6a22a
LP
31 assert(name);
32
33 STRV_FOREACH(i, l)
34 if (strcaseeq(*i, name))
35 return *i;
36
37 return NULL;
38}
39
14337c37 40char* strv_find_prefix(char * const *l, const char *name) {
a4bfb399
LP
41 assert(name);
42
43 STRV_FOREACH(i, l)
44 if (startswith(*i, name))
45 return *i;
46
47 return NULL;
48}
49
14337c37 50char* strv_find_startswith(char * const *l, const char *name) {
28849dba
LP
51 assert(name);
52
53 /* Like strv_find_prefix, but actually returns only the
54 * suffix, not the whole item */
55
56 STRV_FOREACH(i, l) {
de010b0b
YW
57 char *e;
58
28849dba
LP
59 e = startswith(*i, name);
60 if (e)
61 return e;
62 }
63
64 return NULL;
65}
66
2ed74695
LB
67char* strv_find_first_field(char * const *needles, char * const *haystack) {
68 STRV_FOREACH(k, needles) {
69 char *value = strv_env_pairs_get((char **)haystack, *k);
70 if (value)
71 return value;
72 }
73
74 return NULL;
75}
76
14337c37 77char** strv_free(char **l) {
d0b4f13e 78 STRV_FOREACH(k, l)
60918275
LP
79 free(*k);
80
6b430fdb 81 return mfree(l);
60918275
LP
82}
83
14337c37 84char** strv_free_erase(char **l) {
ab84f5b9 85 STRV_FOREACH(i, l)
309c6b19 86 erase_and_freep(i);
ab84f5b9 87
309c6b19 88 return mfree(l);
ab84f5b9
ZJS
89}
90
4ea517a6 91char** strv_copy_n(char * const *l, size_t m) {
9eb81481 92 _cleanup_strv_free_ char **result = NULL;
de010b0b 93 char **k;
60918275 94
4ea517a6 95 result = new(char*, MIN(strv_length(l), m) + 1);
9eb81481 96 if (!result)
60918275
LP
97 return NULL;
98
9eb81481
YW
99 k = result;
100 STRV_FOREACH(i, l) {
4ea517a6
LP
101 if (m == 0)
102 break;
103
9eb81481
YW
104 *k = strdup(*i);
105 if (!*k)
106 return NULL;
107 k++;
4ea517a6
LP
108
109 if (m != SIZE_MAX)
110 m--;
9eb81481 111 }
60918275
LP
112
113 *k = NULL;
9eb81481 114 return TAKE_PTR(result);
60918275
LP
115}
116
da6053d0
LP
117size_t strv_length(char * const *l) {
118 size_t n = 0;
60918275 119
d0b4f13e 120 STRV_FOREACH(i, l)
60918275
LP
121 n++;
122
123 return n;
124}
125
14337c37 126char** strv_new_ap(const char *x, va_list ap) {
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
3d2b1fa4
RV
136 va_copy(aq, ap);
137 for (const char *s = x; s; s = va_arg(aq, const char*)) {
138 if (s == STRV_IGNORE)
139 continue;
07719a21 140
3d2b1fa4 141 n++;
60918275 142 }
3d2b1fa4 143 va_end(aq);
60918275 144
07719a21
LP
145 a = new(char*, n+1);
146 if (!a)
60918275
LP
147 return NULL;
148
3d2b1fa4
RV
149 for (const char *s = x; s; s = va_arg(ap, const char*)) {
150 if (s == STRV_IGNORE)
151 continue;
07719a21 152
3d2b1fa4
RV
153 a[i] = strdup(s);
154 if (!a[i])
155 return NULL;
60918275 156
3d2b1fa4 157 i++;
60918275
LP
158 }
159
160 a[i] = NULL;
257eca1a 161
01111587 162 return TAKE_PTR(a);
60918275 163}
034c6ed7 164
14337c37 165char** strv_new_internal(const char *x, ...) {
257eca1a
LP
166 char **r;
167 va_list ap;
168
169 va_start(ap, x);
170 r = strv_new_ap(x, ap);
171 va_end(ap);
172
173 return r;
174}
175
479ddcdf 176int strv_extend_strv(char ***a, char * const *b, bool filter_duplicates) {
14337c37 177 size_t p, q, i = 0;
de010b0b 178 char **t;
e287086b
LP
179
180 assert(a);
181
182 if (strv_isempty(b))
183 return 0;
184
185 p = strv_length(*a);
186 q = strv_length(b);
187
60476376
LP
188 if (p >= SIZE_MAX - q)
189 return -ENOMEM;
190
191 t = reallocarray(*a, GREEDY_ALLOC_ROUND_UP(p + q + 1), sizeof(char *));
e287086b
LP
192 if (!t)
193 return -ENOMEM;
194
195 t[p] = NULL;
196 *a = t;
07719a21 197
e3e45d4f 198 STRV_FOREACH(s, b) {
e287086b
LP
199 if (filter_duplicates && strv_contains(t, *s))
200 continue;
201
202 t[p+i] = strdup(*s);
203 if (!t[p+i])
204 goto rollback;
205
206 i++;
207 t[p+i] = NULL;
07719a21 208 }
034c6ed7 209
e287086b
LP
210 assert(i <= q);
211
212 return (int) i;
213
214rollback:
14337c37 215 for (size_t j = 0; j < i; j++)
e287086b
LP
216 free(t[p + j]);
217
218 t[p] = NULL;
219 return -ENOMEM;
5f9a22c3
LP
220}
221
479ddcdf 222int strv_extend_strv_concat(char ***a, char * const *b, const char *suffix) {
e3e45d4f 223 int r;
5f9a22c3 224
e3e45d4f
SP
225 STRV_FOREACH(s, b) {
226 char *v;
5f9a22c3 227
b910cc72 228 v = strjoin(*s, suffix);
e3e45d4f
SP
229 if (!v)
230 return -ENOMEM;
5f9a22c3 231
e3e45d4f
SP
232 r = strv_push(a, v);
233 if (r < 0) {
234 free(v);
235 return r;
8ea913b2 236 }
8ea913b2 237 }
5f9a22c3 238
e3e45d4f 239 return 0;
5f9a22c3
LP
240}
241
f385c447
YW
242int strv_split_newlines_full(char ***ret, const char *s, ExtractFlags flags) {
243 _cleanup_strv_free_ char **l = NULL;
da6053d0 244 size_t n;
f385c447 245 int r;
26d04f86
LP
246
247 assert(s);
248
f385c447
YW
249 /* Special version of strv_split_full() that splits on newlines and
250 * suppresses an empty string at the end. */
26d04f86 251
f385c447
YW
252 r = strv_split_full(&l, s, NEWLINE, flags);
253 if (r < 0)
254 return r;
26d04f86
LP
255
256 n = strv_length(l);
f385c447 257 if (n > 0 && isempty(l[n - 1])) {
a1e58e8e 258 l[n - 1] = mfree(l[n - 1]);
f385c447
YW
259 n--;
260 }
26d04f86 261
f385c447
YW
262 *ret = TAKE_PTR(l);
263 return n;
26d04f86
LP
264}
265
90e30d76 266int strv_split_full(char ***t, const char *s, const char *separators, ExtractFlags flags) {
f88e6be5 267 _cleanup_strv_free_ char **l = NULL;
319a4f4b 268 size_t n = 0;
f88e6be5
LP
269 int r;
270
271 assert(t);
272 assert(s);
273
274 for (;;) {
275 _cleanup_free_ char *word = NULL;
276
8adaf7bd 277 r = extract_first_word(&s, &word, separators, flags);
f88e6be5
LP
278 if (r < 0)
279 return r;
ece174c5 280 if (r == 0)
f88e6be5
LP
281 break;
282
319a4f4b 283 if (!GREEDY_REALLOC(l, n + 2))
f88e6be5
LP
284 return -ENOMEM;
285
ae2a15bc 286 l[n++] = TAKE_PTR(word);
f88e6be5
LP
287 l[n] = NULL;
288 }
289
8dd4c05b 290 if (!l) {
f88e6be5 291 l = new0(char*, 1);
8dd4c05b
LP
292 if (!l)
293 return -ENOMEM;
294 }
f88e6be5 295
ae2a15bc 296 *t = TAKE_PTR(l);
f88e6be5 297
8dd4c05b 298 return (int) n;
f88e6be5
LP
299}
300
3c318caa
FS
301int strv_split_and_extend_full(char ***t, const char *s, const char *separators, bool filter_duplicates, ExtractFlags flags) {
302 _cleanup_strv_free_ char **l = NULL;
303 int r;
304
305 assert(t);
306 assert(s);
307
308 r = strv_split_full(&l, s, separators, flags);
309 if (r < 0)
310 return r;
311
312 r = strv_extend_strv(t, l, filter_duplicates);
313 if (r < 0)
314 return r;
315
316 return (int) strv_length(*t);
317}
318
a082edd5
LB
319int strv_split_colon_pairs(char ***t, const char *s) {
320 _cleanup_strv_free_ char **l = NULL;
319a4f4b 321 size_t n = 0;
a082edd5
LB
322 int r;
323
324 assert(t);
325 assert(s);
326
327 for (;;) {
328 _cleanup_free_ char *first = NULL, *second = NULL, *tuple = NULL, *second_or_empty = NULL;
329
330 r = extract_first_word(&s, &tuple, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE);
331 if (r < 0)
332 return r;
333 if (r == 0)
334 break;
335
336 const char *p = tuple;
337 r = extract_many_words(&p, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS,
338 &first, &second, NULL);
339 if (r < 0)
340 return r;
341 if (r == 0)
342 continue;
343 /* Enforce that at most 2 colon-separated words are contained in each group */
344 if (!isempty(p))
345 return -EINVAL;
346
347 second_or_empty = strdup(strempty(second));
348 if (!second_or_empty)
349 return -ENOMEM;
350
319a4f4b 351 if (!GREEDY_REALLOC(l, n + 3))
a082edd5
LB
352 return -ENOMEM;
353
354 l[n++] = TAKE_PTR(first);
355 l[n++] = TAKE_PTR(second_or_empty);
356
357 l[n] = NULL;
358 }
359
360 if (!l) {
361 l = new0(char*, 1);
362 if (!l)
363 return -ENOMEM;
364 }
365
366 *t = TAKE_PTR(l);
367
368 return (int) n;
369}
370
e5f2d77b 371char* strv_join_full(char * const *l, const char *separator, const char *prefix, bool escape_separator) {
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 380
e5f2d77b 381 if (escape_separator) /* If the separator was multi-char, we wouldn't know how to escape it. */
d4d9f034
ZJS
382 assert(k == 1);
383
5f9a22c3
LP
384 n = 0;
385 STRV_FOREACH(s, l) {
afe773b0 386 if (s != l)
5f9a22c3 387 n += k;
d4d9f034 388
e5f2d77b 389 bool needs_escaping = escape_separator && strchr(*s, *separator);
d4d9f034
ZJS
390
391 n += m + strlen(*s) * (1 + needs_escaping);
5f9a22c3
LP
392 }
393
1fd8d04e
LP
394 r = new(char, n+1);
395 if (!r)
5f9a22c3
LP
396 return NULL;
397
398 e = r;
399 STRV_FOREACH(s, l) {
afe773b0 400 if (s != l)
5f9a22c3
LP
401 e = stpcpy(e, separator);
402
2b9a7d2e
YW
403 if (prefix)
404 e = stpcpy(e, prefix);
405
e5f2d77b 406 bool needs_escaping = escape_separator && strchr(*s, *separator);
d4d9f034
ZJS
407
408 if (needs_escaping)
409 for (size_t i = 0; (*s)[i]; i++) {
e5f2d77b 410 if ((*s)[i] == *separator)
d4d9f034
ZJS
411 *(e++) = '\\';
412 *(e++) = (*s)[i];
413 }
414 else
415 e = stpcpy(e, *s);
5f9a22c3
LP
416 }
417
8d49745c
LP
418 *e = 0;
419
5f9a22c3
LP
420 return r;
421}
422
3ec3ae68
ZJS
423int strv_push_with_size(char ***l, size_t *n, char *value) {
424 /* n is a pointer to a variable to store the size of l.
425 * If not given (i.e. n is NULL or *n is SIZE_MAX), size will be calculated using strv_length().
426 * If n is not NULL, the size after the push will be returned.
427 * If value is empty, no action is taken and *n is not set. */
5926ccca
LP
428
429 if (!value)
430 return 0;
431
3ec3ae68
ZJS
432 size_t size = n ? *n : SIZE_MAX;
433 if (size == SIZE_MAX)
434 size = strv_length(*l);
97569e15 435
60476376 436 /* Check for overflow */
3ec3ae68 437 if (size > SIZE_MAX-2)
97569e15
LP
438 return -ENOMEM;
439
3ec3ae68 440 char **c = reallocarray(*l, GREEDY_ALLOC_ROUND_UP(size + 2), sizeof(char*));
4468addc 441 if (!c)
82dde599 442 return -ENOMEM;
82dde599 443
3ec3ae68
ZJS
444 c[size] = value;
445 c[size+1] = NULL;
82dde599 446
5926ccca 447 *l = c;
3ec3ae68
ZJS
448 if (n)
449 *n = size + 1;
5926ccca
LP
450 return 0;
451}
452
98940a3c
LP
453int strv_push_pair(char ***l, char *a, char *b) {
454 char **c;
60476376 455 size_t n;
98940a3c
LP
456
457 if (!a && !b)
458 return 0;
459
460 n = strv_length(*l);
461
60476376
LP
462 /* Check for overflow */
463 if (n > SIZE_MAX-3)
98940a3c
LP
464 return -ENOMEM;
465
60476376
LP
466 /* increase and check for overflow */
467 c = reallocarray(*l, GREEDY_ALLOC_ROUND_UP(n + !!a + !!b + 1), sizeof(char*));
98940a3c
LP
468 if (!c)
469 return -ENOMEM;
470
471 if (a)
472 c[n++] = a;
473 if (b)
474 c[n++] = b;
475 c[n] = NULL;
476
477 *l = c;
478 return 0;
479}
480
da6053d0 481int strv_insert(char ***l, size_t position, char *value) {
9a00f57a 482 char **c;
14337c37 483 size_t n, m;
9a00f57a
LP
484
485 if (!value)
486 return 0;
487
488 n = strv_length(*l);
6e888894 489 position = MIN(position, n);
97569e15
LP
490
491 /* increase and check for overflow */
492 m = n + 2;
493 if (m < n)
494 return -ENOMEM;
495
496 c = new(char*, m);
9a00f57a
LP
497 if (!c)
498 return -ENOMEM;
499
14337c37 500 for (size_t i = 0; i < position; i++)
6e888894
ZJS
501 c[i] = (*l)[i];
502 c[position] = value;
14337c37 503 for (size_t i = position; i < n; i++)
9a00f57a 504 c[i+1] = (*l)[i];
9a00f57a
LP
505 c[n+1] = NULL;
506
14337c37 507 return free_and_replace(*l, c);
9a00f57a
LP
508}
509
3ec3ae68 510int strv_consume_with_size(char ***l, size_t *n, char *value) {
6e18964d
ZJS
511 int r;
512
3ec3ae68 513 r = strv_push_with_size(l, n, value);
6e18964d
ZJS
514 if (r < 0)
515 free(value);
516
9a00f57a
LP
517 return r;
518}
519
98940a3c
LP
520int strv_consume_pair(char ***l, char *a, char *b) {
521 int r;
522
523 r = strv_push_pair(l, a, b);
524 if (r < 0) {
525 free(a);
526 free(b);
527 }
528
529 return r;
530}
531
9a00f57a
LP
532int strv_consume_prepend(char ***l, char *value) {
533 int r;
534
535 r = strv_push_prepend(l, value);
536 if (r < 0)
537 free(value);
538
6e18964d
ZJS
539 return r;
540}
541
82443be5 542int strv_prepend(char ***l, const char *value) {
543 char *v;
544
545 if (!value)
546 return 0;
547
548 v = strdup(value);
549 if (!v)
550 return -ENOMEM;
551
552 return strv_consume_prepend(l, v);
553}
554
3ec3ae68 555int strv_extend_with_size(char ***l, size_t *n, const char *value) {
4468addc 556 char *v;
4468addc
LP
557
558 if (!value)
559 return 0;
560
561 v = strdup(value);
562 if (!v)
563 return -ENOMEM;
564
3ec3ae68 565 return strv_consume_with_size(l, n, v);
4468addc
LP
566}
567
4f4afc88
LP
568int strv_extend_front(char ***l, const char *value) {
569 size_t n, m;
570 char *v, **c;
571
572 assert(l);
573
574 /* Like strv_extend(), but prepends rather than appends the new entry */
575
bcab914f
LP
576 if (!value)
577 return 0;
578
4f4afc88
LP
579 n = strv_length(*l);
580
581 /* Increase and overflow check. */
582 m = n + 2;
583 if (m < n)
584 return -ENOMEM;
585
bcab914f
LP
586 v = strdup(value);
587 if (!v)
588 return -ENOMEM;
4f4afc88 589
aa484f35 590 c = reallocarray(*l, m, sizeof(char*));
4f4afc88
LP
591 if (!c) {
592 free(v);
593 return -ENOMEM;
594 }
595
596 memmove(c+1, c, n * sizeof(char*));
597 c[0] = v;
598 c[n+1] = NULL;
599
600 *l = c;
601 return 0;
602}
603
14337c37 604char** strv_uniq(char **l) {
5f9a22c3
LP
605 /* Drops duplicate entries. The first identical string will be
606 * kept, the others dropped */
607
cba8922f 608 STRV_FOREACH(i, l)
5f9a22c3
LP
609 strv_remove(i+1, *i);
610
611 return l;
612}
613
479ddcdf 614bool strv_is_uniq(char * const *l) {
e1dd6790 615 STRV_FOREACH(i, l)
d29cc4d6 616 if (strv_contains(i+1, *i))
e1dd6790
LP
617 return false;
618
619 return true;
620}
621
14337c37 622char** strv_remove(char **l, const char *s) {
5f9a22c3
LP
623 char **f, **t;
624
625 if (!l)
626 return NULL;
627
5d6ab905
LP
628 assert(s);
629
630 /* Drops every occurrence of s in the string list, edits
631 * in-place. */
5f9a22c3 632
e3e45d4f
SP
633 for (f = t = l; *f; f++)
634 if (streq(*f, s))
71ecc858 635 free(*f);
e3e45d4f
SP
636 else
637 *(t++) = *f;
71ecc858
LP
638
639 *t = NULL;
640 return l;
641}
642
479ddcdf 643bool strv_overlap(char * const *a, char * const *b) {
e3e45d4f
SP
644 STRV_FOREACH(i, a)
645 if (strv_contains(b, *i))
646 return true;
0c85a4f3
LP
647
648 return false;
649}
857a493d 650
93bab288 651static int str_compare(char * const *a, char * const *b) {
857a493d
LP
652 return strcmp(*a, *b);
653}
654
14337c37 655char** strv_sort(char **l) {
93bab288 656 typesafe_qsort(l, strv_length(l), str_compare);
857a493d
LP
657 return l;
658}
7c2d8094 659
8b75798d
YW
660int strv_compare(char * const *a, char * const *b) {
661 int r;
e287086b 662
8b75798d
YW
663 if (strv_isempty(a)) {
664 if (strv_isempty(b))
665 return 0;
666 else
667 return -1;
668 }
e287086b
LP
669
670 if (strv_isempty(b))
8b75798d 671 return 1;
0f84a72e 672
8b75798d
YW
673 for ( ; *a || *b; ++a, ++b) {
674 r = strcmp_ptr(*a, *b);
675 if (r != 0)
676 return r;
677 }
0f84a72e 678
8b75798d 679 return 0;
0f84a72e
DH
680}
681
00546c18 682void strv_print_full(char * const *l, const char *prefix) {
7c2d8094 683 STRV_FOREACH(s, l)
00546c18 684 printf("%s%s\n", strempty(prefix), *s);
7c2d8094 685}
4de33e7f
LP
686
687int strv_extendf(char ***l, const char *format, ...) {
688 va_list ap;
689 char *x;
690 int r;
691
692 va_start(ap, format);
693 r = vasprintf(&x, format, ap);
694 va_end(ap);
695
696 if (r < 0)
697 return -ENOMEM;
698
699 return strv_consume(l, x);
700}
e1dd6790 701
14337c37
ZJS
702char** strv_reverse(char **l) {
703 size_t n;
e1dd6790
LP
704
705 n = strv_length(l);
706 if (n <= 1)
707 return l;
708
14337c37 709 for (size_t i = 0; i < n / 2; i++)
8a3134b2 710 SWAP_TWO(l[i], l[n-1-i]);
e1dd6790
LP
711
712 return l;
713}
bceccd5e 714
14337c37 715char** strv_shell_escape(char **l, const char *bad) {
04c14b25
RM
716 /* Escapes every character in every string in l that is in bad,
717 * edits in-place, does not roll-back on error. */
718
719 STRV_FOREACH(s, l) {
720 char *v;
721
722 v = shell_escape(*s, bad);
723 if (!v)
724 return NULL;
725
d6f2cd67 726 free_and_replace(*s, v);
04c14b25
RM
727 }
728
729 return l;
730}
731
bcfc0e88
LP
732bool strv_fnmatch_full(
733 char* const* patterns,
734 const char *s,
735 int flags,
736 size_t *ret_matched_pos) {
737
738 assert(s);
739
740 if (patterns)
741 for (size_t i = 0; patterns[i]; i++)
742 /* NB: We treat all fnmatch() errors as equivalent to FNM_NOMATCH, i.e. if fnmatch() fails to
743 * process the pattern for some reason we'll consider this equivalent to non-matching. */
744 if (fnmatch(patterns[i], s, flags) == 0) {
745 if (ret_matched_pos)
746 *ret_matched_pos = i;
747 return true;
748 }
749
750 if (ret_matched_pos)
751 *ret_matched_pos = SIZE_MAX;
bceccd5e
ZJS
752
753 return false;
754}
fe382237 755
14337c37 756char** strv_skip(char **l, size_t n) {
e3ead6bb
LP
757
758 while (n > 0) {
759 if (strv_isempty(l))
760 return l;
761
762 l++, n--;
763 }
764
765 return l;
766}
8dd4c05b
LP
767
768int strv_extend_n(char ***l, const char *value, size_t n) {
14337c37 769 size_t i, k;
8dd4c05b
LP
770 char **nl;
771
772 assert(l);
773
774 if (!value)
775 return 0;
776 if (n == 0)
777 return 0;
778
61233823 779 /* Adds the value n times to l */
8dd4c05b
LP
780
781 k = strv_length(*l);
60476376
LP
782 if (n >= SIZE_MAX - k)
783 return -ENOMEM;
8dd4c05b 784
60476376 785 nl = reallocarray(*l, GREEDY_ALLOC_ROUND_UP(k + n + 1), sizeof(char *));
8dd4c05b
LP
786 if (!nl)
787 return -ENOMEM;
788
789 *l = nl;
790
791 for (i = k; i < k + n; i++) {
792 nl[i] = strdup(value);
793 if (!nl[i])
794 goto rollback;
795 }
8dd4c05b 796 nl[i] = NULL;
14337c37 797
8dd4c05b
LP
798 return 0;
799
800rollback:
14337c37 801 for (size_t j = k; j < i; j++)
8dd4c05b 802 free(nl[j]);
8dd4c05b 803 nl[k] = NULL;
14337c37 804
5b700370 805 return -ENOMEM;
8dd4c05b 806}
3df9bec5 807
6658f7c7
DDM
808int strv_extend_assignment(char ***l, const char *lhs, const char *rhs) {
809 char *j;
810
811 assert(l);
812 assert(lhs);
813
814 if (!rhs) /* value is optional, in which case we suppress the field */
815 return 0;
816
817 j = strjoin(lhs, "=", rhs);
818 if (!j)
819 return -ENOMEM;
820
821 return strv_consume(l, j);
822}
823
479ddcdf 824int fputstrv(FILE *f, char * const *l, const char *separator, bool *space) {
3df9bec5 825 bool b = false;
3df9bec5
LP
826 int r;
827
828 /* Like fputs(), but for strv, and with a less stupid argument order */
829
3df9bec5
LP
830 if (!space)
831 space = &b;
832
833 STRV_FOREACH(s, l) {
d390f8ef 834 r = fputs_with_space(f, *s, separator, space);
3df9bec5
LP
835 if (r < 0)
836 return r;
3df9bec5
LP
837 }
838
839 return 0;
840}
cde79109
ZJS
841
842static int string_strv_hashmap_put_internal(Hashmap *h, const char *key, const char *value) {
843 char **l;
844 int r;
845
846 l = hashmap_get(h, key);
847 if (l) {
848 /* A list for this key already exists, let's append to it if it is not listed yet */
849 if (strv_contains(l, value))
850 return 0;
851
852 r = strv_extend(&l, value);
853 if (r < 0)
854 return r;
855
856 assert_se(hashmap_update(h, key, l) >= 0);
857 } else {
858 /* No list for this key exists yet, create one */
859 _cleanup_strv_free_ char **l2 = NULL;
860 _cleanup_free_ char *t = NULL;
861
862 t = strdup(key);
863 if (!t)
864 return -ENOMEM;
865
866 r = strv_extend(&l2, value);
867 if (r < 0)
868 return r;
869
870 r = hashmap_put(h, t, l2);
871 if (r < 0)
872 return r;
873 TAKE_PTR(t);
874 TAKE_PTR(l2);
875 }
876
877 return 1;
878}
879
856e5195 880int _string_strv_hashmap_put(Hashmap **h, const char *key, const char *value HASHMAP_DEBUG_PARAMS) {
cde79109
ZJS
881 int r;
882
856e5195 883 r = _hashmap_ensure_allocated(h, &string_strv_hash_ops HASHMAP_DEBUG_PASS_ARGS);
cde79109
ZJS
884 if (r < 0)
885 return r;
886
887 return string_strv_hashmap_put_internal(*h, key, value);
888}
889
856e5195 890int _string_strv_ordered_hashmap_put(OrderedHashmap **h, const char *key, const char *value HASHMAP_DEBUG_PARAMS) {
cde79109
ZJS
891 int r;
892
856e5195 893 r = _ordered_hashmap_ensure_allocated(h, &string_strv_hash_ops HASHMAP_DEBUG_PASS_ARGS);
cde79109
ZJS
894 if (r < 0)
895 return r;
896
897 return string_strv_hashmap_put_internal(PLAIN_HASHMAP(*h), key, value);
898}
899
900DEFINE_HASH_OPS_FULL(string_strv_hash_ops, char, string_hash_func, string_compare_func, free, char*, strv_free);