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