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