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 582645 : char *strv_find(char **l, const char *name) {
21 : char **i;
22 :
23 582645 : assert(name);
24 :
25 10431683 : STRV_FOREACH(i, l)
26 9849837 : if (streq(*i, name))
27 799 : return *i;
28 :
29 581846 : return NULL;
30 : }
31 :
32 5 : char *strv_find_prefix(char **l, const char *name) {
33 : char **i;
34 :
35 5 : assert(name);
36 :
37 11 : STRV_FOREACH(i, l)
38 9 : if (startswith(*i, name))
39 3 : return *i;
40 :
41 2 : return NULL;
42 : }
43 :
44 5 : char *strv_find_startswith(char **l, const char *name) {
45 : char **i, *e;
46 :
47 5 : assert(name);
48 :
49 : /* Like strv_find_prefix, but actually returns only the
50 : * suffix, not the whole item */
51 :
52 11 : STRV_FOREACH(i, l) {
53 9 : e = startswith(*i, name);
54 9 : if (e)
55 3 : return e;
56 : }
57 :
58 2 : return NULL;
59 : }
60 :
61 118682 : void strv_clear(char **l) {
62 : char **k;
63 :
64 118682 : if (!l)
65 24474 : return;
66 :
67 219802 : for (k = l; *k; k++)
68 125594 : free(*k);
69 :
70 94208 : *l = NULL;
71 : }
72 :
73 30264 : char **strv_free(char **l) {
74 30264 : strv_clear(l);
75 30264 : return mfree(l);
76 : }
77 :
78 9 : char **strv_free_erase(char **l) {
79 : char **i;
80 :
81 36 : STRV_FOREACH(i, l)
82 27 : erase_and_freep(i);
83 :
84 9 : return mfree(l);
85 : }
86 :
87 957 : char **strv_copy(char * const *l) {
88 : char **r, **k;
89 :
90 957 : k = r = new(char*, strv_length(l) + 1);
91 957 : if (!r)
92 0 : return NULL;
93 :
94 957 : if (l)
95 13886 : for (; *l; k++, l++) {
96 12930 : *k = strdup(*l);
97 12930 : if (!*k) {
98 0 : strv_free(r);
99 0 : return NULL;
100 : }
101 : }
102 :
103 957 : *k = NULL;
104 957 : return r;
105 : }
106 :
107 107414 : size_t strv_length(char * const *l) {
108 107414 : size_t n = 0;
109 :
110 107414 : if (!l)
111 4303 : return 0;
112 :
113 204280 : for (; *l; l++)
114 101169 : n++;
115 :
116 103111 : return n;
117 : }
118 :
119 332 : char **strv_new_ap(const char *x, va_list ap) {
120 : const char *s;
121 332 : _cleanup_strv_free_ char **a = NULL;
122 332 : 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 332 : if (x) {
131 330 : n = x == STRV_IGNORE ? 0 : 1;
132 :
133 330 : va_copy(aq, ap);
134 4242 : while ((s = va_arg(aq, const char*))) {
135 3912 : if (s == STRV_IGNORE)
136 245 : continue;
137 :
138 3667 : n++;
139 : }
140 :
141 330 : va_end(aq);
142 : }
143 :
144 332 : a = new(char*, n+1);
145 332 : if (!a)
146 0 : return NULL;
147 :
148 332 : if (x) {
149 330 : if (x != STRV_IGNORE) {
150 328 : a[i] = strdup(x);
151 328 : if (!a[i])
152 0 : return NULL;
153 328 : i++;
154 : }
155 :
156 4242 : while ((s = va_arg(ap, const char*))) {
157 :
158 3912 : if (s == STRV_IGNORE)
159 245 : continue;
160 :
161 3667 : a[i] = strdup(s);
162 3667 : if (!a[i])
163 0 : return NULL;
164 :
165 3667 : i++;
166 : }
167 : }
168 :
169 332 : a[i] = NULL;
170 :
171 332 : return TAKE_PTR(a);
172 : }
173 :
174 328 : char **strv_new_internal(const char *x, ...) {
175 : char **r;
176 : va_list ap;
177 :
178 328 : va_start(ap, x);
179 328 : r = strv_new_ap(x, ap);
180 328 : va_end(ap);
181 :
182 328 : return r;
183 : }
184 :
185 16 : int strv_extend_strv(char ***a, char **b, bool filter_duplicates) {
186 : char **s, **t;
187 16 : size_t p, q, i = 0, j;
188 :
189 16 : assert(a);
190 :
191 16 : if (strv_isempty(b))
192 2 : return 0;
193 :
194 14 : p = strv_length(*a);
195 14 : q = strv_length(b);
196 :
197 14 : t = reallocarray(*a, p + q + 1, sizeof(char *));
198 14 : if (!t)
199 0 : return -ENOMEM;
200 :
201 14 : t[p] = NULL;
202 14 : *a = t;
203 :
204 55 : STRV_FOREACH(s, b) {
205 :
206 41 : if (filter_duplicates && strv_contains(t, *s))
207 1 : continue;
208 :
209 40 : t[p+i] = strdup(*s);
210 40 : if (!t[p+i])
211 0 : goto rollback;
212 :
213 40 : i++;
214 40 : t[p+i] = NULL;
215 : }
216 :
217 14 : assert(i <= q);
218 :
219 14 : 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 92 : int strv_extend_strv_concat(char ***a, char **b, const char *suffix) {
230 : int r;
231 : char **s;
232 :
233 278 : STRV_FOREACH(s, b) {
234 : char *v;
235 :
236 186 : v = strjoin(*s, suffix);
237 186 : if (!v)
238 0 : return -ENOMEM;
239 :
240 186 : r = strv_push(a, v);
241 186 : if (r < 0) {
242 0 : free(v);
243 0 : return r;
244 : }
245 : }
246 :
247 92 : return 0;
248 : }
249 :
250 184 : 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 184 : assert(s);
257 :
258 184 : if (!separator)
259 14 : separator = WHITESPACE;
260 :
261 184 : s += strspn(s, separator);
262 184 : if (isempty(s))
263 13 : return new0(char*, 1);
264 :
265 171 : n = 0;
266 523 : _FOREACH_WORD(word, l, s, separator, flags, state)
267 352 : n++;
268 :
269 171 : r = new(char*, n+1);
270 171 : if (!r)
271 0 : return NULL;
272 :
273 171 : i = 0;
274 523 : _FOREACH_WORD(word, l, s, separator, flags, state) {
275 352 : r[i] = strndup(word, l);
276 352 : if (!r[i]) {
277 0 : strv_free(r);
278 0 : return NULL;
279 : }
280 :
281 352 : i++;
282 : }
283 :
284 171 : r[i] = NULL;
285 171 : return r;
286 : }
287 :
288 8 : char **strv_split_newlines(const char *s) {
289 : char **l;
290 : size_t n;
291 :
292 8 : assert(s);
293 :
294 : /* Special version of strv_split() that splits on newlines and
295 : * suppresses an empty string at the end */
296 :
297 8 : l = strv_split(s, NEWLINE);
298 8 : if (!l)
299 0 : return NULL;
300 :
301 8 : n = strv_length(l);
302 8 : if (n <= 0)
303 0 : return l;
304 :
305 8 : if (isempty(l[n - 1]))
306 0 : l[n - 1] = mfree(l[n - 1]);
307 :
308 8 : return l;
309 : }
310 :
311 746 : int strv_split_extract(char ***t, const char *s, const char *separators, ExtractFlags flags) {
312 746 : _cleanup_strv_free_ char **l = NULL;
313 746 : size_t n = 0, allocated = 0;
314 : int r;
315 :
316 746 : assert(t);
317 746 : assert(s);
318 :
319 3523 : for (;;) {
320 4269 : _cleanup_free_ char *word = NULL;
321 :
322 4269 : r = extract_first_word(&s, &word, separators, flags);
323 4269 : if (r < 0)
324 7 : return r;
325 4262 : if (r == 0)
326 739 : break;
327 :
328 3523 : if (!GREEDY_REALLOC(l, allocated, n + 2))
329 0 : return -ENOMEM;
330 :
331 3523 : l[n++] = TAKE_PTR(word);
332 :
333 3523 : l[n] = NULL;
334 : }
335 :
336 739 : if (!l) {
337 3 : l = new0(char*, 1);
338 3 : if (!l)
339 0 : return -ENOMEM;
340 : }
341 :
342 739 : *t = TAKE_PTR(l);
343 :
344 739 : return (int) n;
345 : }
346 :
347 602 : 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 602 : if (!separator)
353 2 : separator = " ";
354 :
355 602 : k = strlen(separator);
356 602 : m = strlen_ptr(prefix);
357 :
358 602 : n = 0;
359 1451 : STRV_FOREACH(s, l) {
360 849 : if (s != l)
361 266 : n += k;
362 849 : n += m + strlen(*s);
363 : }
364 :
365 602 : r = new(char, n+1);
366 602 : if (!r)
367 0 : return NULL;
368 :
369 602 : e = r;
370 1451 : STRV_FOREACH(s, l) {
371 849 : if (s != l)
372 266 : e = stpcpy(e, separator);
373 :
374 849 : if (prefix)
375 13 : e = stpcpy(e, prefix);
376 :
377 849 : e = stpcpy(e, *s);
378 : }
379 :
380 602 : *e = 0;
381 :
382 602 : return r;
383 : }
384 :
385 103093 : int strv_push(char ***l, char *value) {
386 : char **c;
387 : size_t n, m;
388 :
389 103093 : if (!value)
390 0 : return 0;
391 :
392 103093 : n = strv_length(*l);
393 :
394 : /* Increase and check for overflow */
395 103093 : m = n + 2;
396 103093 : if (m < n)
397 0 : return -ENOMEM;
398 :
399 103093 : c = reallocarray(*l, m, sizeof(char*));
400 103093 : if (!c)
401 0 : return -ENOMEM;
402 :
403 103093 : c[n] = value;
404 103093 : c[n+1] = NULL;
405 :
406 103093 : *l = c;
407 103093 : return 0;
408 : }
409 :
410 12 : int strv_push_pair(char ***l, char *a, char *b) {
411 : char **c;
412 : size_t n, m;
413 :
414 12 : if (!a && !b)
415 0 : return 0;
416 :
417 12 : n = strv_length(*l);
418 :
419 : /* increase and check for overflow */
420 12 : m = n + !!a + !!b + 1;
421 12 : if (m < n)
422 0 : return -ENOMEM;
423 :
424 12 : c = reallocarray(*l, m, sizeof(char*));
425 12 : if (!c)
426 0 : return -ENOMEM;
427 :
428 12 : if (a)
429 12 : c[n++] = a;
430 12 : if (b)
431 12 : c[n++] = b;
432 12 : c[n] = NULL;
433 :
434 12 : *l = c;
435 12 : return 0;
436 : }
437 :
438 19 : int strv_insert(char ***l, size_t position, char *value) {
439 : char **c;
440 : size_t n, m, i;
441 :
442 19 : if (!value)
443 1 : return 0;
444 :
445 18 : n = strv_length(*l);
446 18 : position = MIN(position, n);
447 :
448 : /* increase and check for overflow */
449 18 : m = n + 2;
450 18 : if (m < n)
451 0 : return -ENOMEM;
452 :
453 18 : c = new(char*, m);
454 18 : if (!c)
455 0 : return -ENOMEM;
456 :
457 34 : for (i = 0; i < position; i++)
458 16 : c[i] = (*l)[i];
459 18 : c[position] = value;
460 33 : for (i = position; i < n; i++)
461 15 : c[i+1] = (*l)[i];
462 :
463 18 : c[n+1] = NULL;
464 :
465 18 : free(*l);
466 18 : *l = c;
467 :
468 18 : return 0;
469 : }
470 :
471 102748 : int strv_consume(char ***l, char *value) {
472 : int r;
473 :
474 102748 : r = strv_push(l, value);
475 102748 : if (r < 0)
476 0 : free(value);
477 :
478 102748 : 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 1 : int strv_consume_prepend(char ***l, char *value) {
494 : int r;
495 :
496 1 : r = strv_push_prepend(l, value);
497 1 : if (r < 0)
498 0 : free(value);
499 :
500 1 : return r;
501 : }
502 :
503 1683 : int strv_extend(char ***l, const char *value) {
504 : char *v;
505 :
506 1683 : if (!value)
507 1 : return 0;
508 :
509 1682 : v = strdup(value);
510 1682 : if (!v)
511 0 : return -ENOMEM;
512 :
513 1682 : 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 1283 : 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 16271 : STRV_FOREACH(i, l)
559 14988 : strv_remove(i+1, *i);
560 :
561 1283 : return l;
562 : }
563 :
564 4 : bool strv_is_uniq(char **l) {
565 : char **i;
566 :
567 8 : STRV_FOREACH(i, l)
568 5 : if (strv_find(i+1, *i))
569 1 : return false;
570 :
571 3 : return true;
572 : }
573 :
574 14988 : char **strv_remove(char **l, const char *s) {
575 : char **f, **t;
576 :
577 14988 : if (!l)
578 0 : return NULL;
579 :
580 14988 : assert(s);
581 :
582 : /* Drops every occurrence of s in the string list, edits
583 : * in-place. */
584 :
585 114245 : for (f = t = l; *f; f++)
586 99257 : if (streq(*f, s))
587 968 : free(*f);
588 : else
589 98289 : *(t++) = *f;
590 :
591 14988 : *t = NULL;
592 14988 : return l;
593 : }
594 :
595 9 : 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 9 : size_t c = 0, i = 0;
609 : char **v;
610 :
611 9 : assert(s || l <= 0);
612 :
613 9 : if (l <= 0)
614 2 : return new0(char*, 1);
615 :
616 197 : for (p = s; p < s + l; p++)
617 190 : if (*p == 0)
618 20 : c++;
619 :
620 7 : if (s[l-1] != 0)
621 4 : c++;
622 :
623 7 : v = new0(char*, c+1);
624 7 : if (!v)
625 0 : return NULL;
626 :
627 7 : p = s;
628 27 : while (p < s + l) {
629 : const char *e;
630 :
631 24 : e = memchr(p, 0, s + l - p);
632 :
633 24 : v[i] = strndup(p, e ? e - p : s + l - p);
634 24 : if (!v[i]) {
635 0 : strv_free(v);
636 0 : return NULL;
637 : }
638 :
639 24 : i++;
640 :
641 24 : if (!e)
642 4 : break;
643 :
644 20 : p = e + 1;
645 : }
646 :
647 7 : assert(i == c);
648 :
649 7 : return v;
650 : }
651 :
652 59 : char **strv_split_nulstr(const char *s) {
653 : const char *i;
654 59 : char **r = NULL;
655 :
656 289 : NULSTR_FOREACH(i, s)
657 230 : if (strv_extend(&r, i) < 0) {
658 0 : strv_free(r);
659 0 : return NULL;
660 : }
661 :
662 59 : if (!r)
663 0 : return strv_new(NULL);
664 :
665 59 : return r;
666 : }
667 :
668 10 : 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 10 : size_t n_allocated = 0, n = 0;
677 10 : _cleanup_free_ char *m = NULL;
678 : char **i;
679 :
680 10 : assert(p);
681 10 : assert(q);
682 :
683 22 : STRV_FOREACH(i, l) {
684 : size_t z;
685 :
686 12 : z = strlen(*i);
687 :
688 12 : if (!GREEDY_REALLOC(m, n_allocated, n + z + 2))
689 0 : return -ENOMEM;
690 :
691 12 : memcpy(m + n, *i, z + 1);
692 12 : n += z + 1;
693 : }
694 :
695 10 : if (!m) {
696 4 : m = new0(char, 1);
697 4 : if (!m)
698 0 : return -ENOMEM;
699 4 : n = 1;
700 : } else
701 : /* make sure there is a second extra NUL at the end of resulting nulstr */
702 6 : m[n] = '\0';
703 :
704 10 : assert(n > 0);
705 10 : *p = m;
706 10 : *q = n - 1;
707 :
708 10 : m = NULL;
709 :
710 10 : return 0;
711 : }
712 :
713 2 : bool strv_overlap(char **a, char **b) {
714 : char **i;
715 :
716 6 : STRV_FOREACH(i, a)
717 5 : if (strv_contains(b, *i))
718 1 : return true;
719 :
720 1 : return false;
721 : }
722 :
723 13465 : static int str_compare(char * const *a, char * const *b) {
724 13465 : return strcmp(*a, *b);
725 : }
726 :
727 21 : char **strv_sort(char **l) {
728 21 : typesafe_qsort(l, strv_length(l), str_compare);
729 21 : return l;
730 : }
731 :
732 1274 : bool strv_equal(char **a, char **b) {
733 :
734 1274 : if (strv_isempty(a))
735 1205 : return strv_isempty(b);
736 :
737 69 : if (strv_isempty(b))
738 1 : return false;
739 :
740 246 : for ( ; *a || *b; ++a, ++b)
741 180 : if (!streq_ptr(*a, *b))
742 2 : return false;
743 :
744 66 : return true;
745 : }
746 :
747 5 : void strv_print(char **l) {
748 : char **s;
749 :
750 22 : STRV_FOREACH(s, l)
751 17 : puts(*s);
752 5 : }
753 :
754 2 : int strv_extendf(char ***l, const char *format, ...) {
755 : va_list ap;
756 : char *x;
757 : int r;
758 :
759 2 : va_start(ap, format);
760 2 : r = vasprintf(&x, format, ap);
761 2 : va_end(ap);
762 :
763 2 : if (r < 0)
764 0 : return -ENOMEM;
765 :
766 2 : return strv_consume(l, x);
767 : }
768 :
769 4 : char **strv_reverse(char **l) {
770 : size_t n, i;
771 :
772 4 : n = strv_length(l);
773 4 : if (n <= 1)
774 2 : return l;
775 :
776 4 : for (i = 0; i < n / 2; i++)
777 2 : SWAP_TWO(l[i], l[n-1-i]);
778 :
779 2 : return l;
780 : }
781 :
782 1 : 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 4 : STRV_FOREACH(s, l) {
789 : char *v;
790 :
791 3 : v = shell_escape(*s, bad);
792 3 : if (!v)
793 0 : return NULL;
794 :
795 3 : free(*s);
796 3 : *s = v;
797 : }
798 :
799 1 : return l;
800 : }
801 :
802 3 : bool strv_fnmatch(char* const* patterns, const char *s, int flags) {
803 : char* const* p;
804 :
805 4 : STRV_FOREACH(p, patterns)
806 2 : if (fnmatch(*p, s, flags) == 0)
807 1 : return true;
808 :
809 2 : return false;
810 : }
811 :
812 1 : char ***strv_free_free(char ***l) {
813 : char ***i;
814 :
815 1 : if (!l)
816 0 : return NULL;
817 :
818 3 : for (i = l; *i; i++)
819 2 : strv_free(*i);
820 :
821 1 : return mfree(l);
822 : }
823 :
824 13 : char **strv_skip(char **l, size_t n) {
825 :
826 28 : while (n > 0) {
827 20 : if (strv_isempty(l))
828 5 : return l;
829 :
830 15 : l++, n--;
831 : }
832 :
833 8 : return l;
834 : }
835 :
836 4 : int strv_extend_n(char ***l, const char *value, size_t n) {
837 : size_t i, j, k;
838 : char **nl;
839 :
840 4 : assert(l);
841 :
842 4 : if (!value)
843 0 : return 0;
844 4 : if (n == 0)
845 1 : return 0;
846 :
847 : /* Adds the value n times to l */
848 :
849 3 : k = strv_length(*l);
850 :
851 3 : nl = reallocarray(*l, k + n + 1, sizeof(char *));
852 3 : if (!nl)
853 0 : return -ENOMEM;
854 :
855 3 : *l = nl;
856 :
857 9 : for (i = k; i < k + n; i++) {
858 6 : nl[i] = strdup(value);
859 6 : if (!nl[i])
860 0 : goto rollback;
861 : }
862 :
863 3 : nl[i] = NULL;
864 3 : 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 844 : static int string_strv_hashmap_put_internal(Hashmap *h, const char *key, const char *value) {
894 : char **l;
895 : int r;
896 :
897 844 : l = hashmap_get(h, key);
898 844 : if (l) {
899 : /* A list for this key already exists, let's append to it if it is not listed yet */
900 98 : if (strv_contains(l, value))
901 12 : return 0;
902 :
903 86 : r = strv_extend(&l, value);
904 86 : if (r < 0)
905 0 : return r;
906 :
907 86 : assert_se(hashmap_update(h, key, l) >= 0);
908 : } else {
909 : /* No list for this key exists yet, create one */
910 746 : _cleanup_strv_free_ char **l2 = NULL;
911 746 : _cleanup_free_ char *t = NULL;
912 :
913 746 : t = strdup(key);
914 746 : if (!t)
915 0 : return -ENOMEM;
916 :
917 746 : r = strv_extend(&l2, value);
918 746 : if (r < 0)
919 0 : return r;
920 :
921 746 : r = hashmap_put(h, t, l2);
922 746 : if (r < 0)
923 0 : return r;
924 746 : TAKE_PTR(t);
925 746 : TAKE_PTR(l2);
926 : }
927 :
928 832 : return 1;
929 : }
930 :
931 834 : int string_strv_hashmap_put(Hashmap **h, const char *key, const char *value) {
932 : int r;
933 :
934 834 : r = hashmap_ensure_allocated(h, &string_strv_hash_ops);
935 834 : if (r < 0)
936 0 : return r;
937 :
938 834 : return string_strv_hashmap_put_internal(*h, key, value);
939 : }
940 :
941 10 : int string_strv_ordered_hashmap_put(OrderedHashmap **h, const char *key, const char *value) {
942 : int r;
943 :
944 10 : r = ordered_hashmap_ensure_allocated(h, &string_strv_hash_ops);
945 10 : if (r < 0)
946 0 : return r;
947 :
948 10 : return string_strv_hashmap_put_internal(PLAIN_HASHMAP(*h), key, value);
949 : }
950 :
951 1492 : DEFINE_HASH_OPS_FULL(string_strv_hash_ops, char, string_hash_func, string_compare_func, free, char*, strv_free);
|