]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/strv.c
bootctl: drop redundant parse_argv()
[thirdparty/systemd.git] / src / shared / strv.c
CommitLineData
d6c9574f 1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
60918275 2
a7334b09
LP
3/***
4 This file is part of systemd.
5
6 Copyright 2010 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
5430f7f2
LP
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
a7334b09
LP
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
5430f7f2 16 Lesser General Public License for more details.
a7334b09 17
5430f7f2 18 You should have received a copy of the GNU Lesser General Public License
a7334b09
LP
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
60918275
LP
22#include <stdlib.h>
23#include <stdarg.h>
24#include <string.h>
2e6c9e6b 25#include <errno.h>
60918275
LP
26
27#include "util.h"
28#include "strv.h"
29
30char *strv_find(char **l, const char *name) {
5f9a22c3
LP
31 char **i;
32
60918275
LP
33 assert(name);
34
5f9a22c3
LP
35 STRV_FOREACH(i, l)
36 if (streq(*i, name))
37 return *i;
60918275
LP
38
39 return NULL;
40}
41
a4bfb399
LP
42char *strv_find_prefix(char **l, const char *name) {
43 char **i;
44
45 assert(name);
46
47 STRV_FOREACH(i, l)
48 if (startswith(*i, name))
49 return *i;
50
51 return NULL;
52}
53
28849dba
LP
54char *strv_find_startswith(char **l, const char *name) {
55 char **i, *e;
56
57 assert(name);
58
59 /* Like strv_find_prefix, but actually returns only the
60 * suffix, not the whole item */
61
62 STRV_FOREACH(i, l) {
63 e = startswith(*i, name);
64 if (e)
65 return e;
66 }
67
68 return NULL;
69}
70
dd9c7723 71void strv_clear(char **l) {
60918275
LP
72 char **k;
73
74 if (!l)
75 return;
76
77 for (k = l; *k; k++)
78 free(*k);
79
dd9c7723
TG
80 *l = NULL;
81}
82
83void strv_free(char **l) {
84 strv_clear(l);
60918275
LP
85 free(l);
86}
87
2fd9ae2e 88char **strv_copy(char * const *l) {
60918275
LP
89 char **r, **k;
90
1fd8d04e
LP
91 k = r = new(char*, strv_length(l) + 1);
92 if (!r)
60918275
LP
93 return NULL;
94
ede27aab 95 if (l)
1fd8d04e
LP
96 for (; *l; k++, l++) {
97 *k = strdup(*l);
98 if (!*k) {
99 strv_free(r);
100 return NULL;
101 }
102 }
60918275
LP
103
104 *k = NULL;
105 return r;
60918275
LP
106}
107
2fd9ae2e 108unsigned strv_length(char * const *l) {
60918275
LP
109 unsigned n = 0;
110
111 if (!l)
112 return 0;
113
114 for (; *l; l++)
115 n++;
116
117 return n;
118}
119
257eca1a 120char **strv_new_ap(const char *x, va_list ap) {
60918275
LP
121 const char *s;
122 char **a;
123 unsigned n = 0, i = 0;
257eca1a
LP
124 va_list aq;
125
07719a21
LP
126 /* As a special trick we ignore all listed strings that equal
127 * (const char*) -1. This is supposed to be used with the
128 * STRV_IFNOTNULL() macro to include possibly NULL strings in
129 * the string list. */
130
60918275 131 if (x) {
07719a21 132 n = x == (const char*) -1 ? 0 : 1;
60918275 133
257eca1a 134 va_copy(aq, ap);
07719a21
LP
135 while ((s = va_arg(aq, const char*))) {
136 if (s == (const char*) -1)
137 continue;
138
60918275 139 n++;
07719a21
LP
140 }
141
257eca1a 142 va_end(aq);
60918275
LP
143 }
144
07719a21
LP
145 a = new(char*, n+1);
146 if (!a)
60918275
LP
147 return NULL;
148
149 if (x) {
07719a21
LP
150 if (x != (const char*) -1) {
151 a[i] = strdup(x);
152 if (!a[i])
153 goto fail;
154 i++;
60918275
LP
155 }
156
60918275 157 while ((s = va_arg(ap, const char*))) {
07719a21
LP
158
159 if (s == (const char*) -1)
160 continue;
161
162 a[i] = strdup(s);
163 if (!a[i])
60918275
LP
164 goto fail;
165
166 i++;
167 }
60918275
LP
168 }
169
170 a[i] = NULL;
257eca1a 171
60918275
LP
172 return a;
173
174fail:
1fd8d04e 175 strv_free(a);
60918275
LP
176 return NULL;
177}
034c6ed7 178
257eca1a
LP
179char **strv_new(const char *x, ...) {
180 char **r;
181 va_list ap;
182
183 va_start(ap, x);
184 r = strv_new_ap(x, ap);
185 va_end(ap);
186
187 return r;
188}
189
e3e45d4f
SP
190int strv_extend_strv(char ***a, char **b) {
191 int r;
192 char **s;
07719a21 193
e3e45d4f
SP
194 STRV_FOREACH(s, b) {
195 r = strv_extend(a, *s);
196 if (r < 0)
197 return r;
07719a21 198 }
034c6ed7 199
e3e45d4f 200 return 0;
5f9a22c3
LP
201}
202
e3e45d4f
SP
203int strv_extend_strv_concat(char ***a, char **b, const char *suffix) {
204 int r;
205 char **s;
5f9a22c3 206
e3e45d4f
SP
207 STRV_FOREACH(s, b) {
208 char *v;
5f9a22c3 209
e3e45d4f
SP
210 v = strappend(*s, suffix);
211 if (!v)
212 return -ENOMEM;
5f9a22c3 213
e3e45d4f
SP
214 r = strv_push(a, v);
215 if (r < 0) {
216 free(v);
217 return r;
8ea913b2 218 }
8ea913b2 219 }
5f9a22c3 220
e3e45d4f 221 return 0;
5f9a22c3
LP
222}
223
224char **strv_split(const char *s, const char *separator) {
a2a5291b 225 const char *word, *state;
5f9a22c3
LP
226 size_t l;
227 unsigned n, i;
228 char **r;
229
230 assert(s);
231
232 n = 0;
a2a5291b 233 FOREACH_WORD_SEPARATOR(word, l, s, separator, state)
5f9a22c3
LP
234 n++;
235
1fd8d04e
LP
236 r = new(char*, n+1);
237 if (!r)
5f9a22c3
LP
238 return NULL;
239
240 i = 0;
a2a5291b
ZJS
241 FOREACH_WORD_SEPARATOR(word, l, s, separator, state) {
242 r[i] = strndup(word, l);
1fd8d04e 243 if (!r[i]) {
5f9a22c3
LP
244 strv_free(r);
245 return NULL;
246 }
247
1fd8d04e
LP
248 i++;
249 }
250
5f9a22c3
LP
251 r[i] = NULL;
252 return r;
253}
254
26d04f86
LP
255char **strv_split_newlines(const char *s) {
256 char **l;
257 unsigned n;
258
259 assert(s);
260
261 /* Special version of strv_split() that splits on newlines and
262 * suppresses an empty string at the end */
263
264 l = strv_split(s, NEWLINE);
265 if (!l)
266 return NULL;
267
268 n = strv_length(l);
269 if (n <= 0)
270 return l;
271
272 if (isempty(l[n-1])) {
273 free(l[n-1]);
274 l[n-1] = NULL;
275 }
276
277 return l;
278}
279
f88e6be5
LP
280int strv_split_quoted(char ***t, const char *s, bool relax) {
281 size_t n = 0, allocated = 0;
282 _cleanup_strv_free_ char **l = NULL;
283 int r;
284
285 assert(t);
286 assert(s);
287
288 for (;;) {
289 _cleanup_free_ char *word = NULL;
290
291 r = unquote_first_word(&s, &word, relax);
292 if (r < 0)
293 return r;
294 if (r == 0)
295 break;
296
297 if (!GREEDY_REALLOC(l, allocated, n + 2))
298 return -ENOMEM;
299
300 l[n++] = word;
301 word = NULL;
302
303 l[n] = NULL;
304 }
305
306 if (!l)
307 l = new0(char*, 1);
308
309 *t = l;
310 l = NULL;
311
312 return 0;
313}
314
5f9a22c3
LP
315char *strv_join(char **l, const char *separator) {
316 char *r, *e;
317 char **s;
318 size_t n, k;
319
320 if (!separator)
321 separator = " ";
322
323 k = strlen(separator);
324
325 n = 0;
326 STRV_FOREACH(s, l) {
327 if (n != 0)
328 n += k;
329 n += strlen(*s);
330 }
331
1fd8d04e
LP
332 r = new(char, n+1);
333 if (!r)
5f9a22c3
LP
334 return NULL;
335
336 e = r;
337 STRV_FOREACH(s, l) {
338 if (e != r)
339 e = stpcpy(e, separator);
340
341 e = stpcpy(e, *s);
342 }
343
8d49745c
LP
344 *e = 0;
345
5f9a22c3
LP
346 return r;
347}
348
a6fde353
ZJS
349char *strv_join_quoted(char **l) {
350 char *buf = NULL;
351 char **s;
352 size_t allocated = 0, len = 0;
353
354 STRV_FOREACH(s, l) {
355 /* assuming here that escaped string cannot be more
356 * than twice as long, and reserving space for the
357 * separator and quotes.
358 */
359 _cleanup_free_ char *esc = NULL;
360 size_t needed;
361
362 if (!GREEDY_REALLOC(buf, allocated,
363 len + strlen(*s) * 2 + 3))
364 goto oom;
365
366 esc = cescape(*s);
367 if (!esc)
368 goto oom;
369
370 needed = snprintf(buf + len, allocated - len, "%s\"%s\"",
371 len > 0 ? " " : "", esc);
372 assert(needed < allocated - len);
373 len += needed;
374 }
375
376 if (!buf)
377 buf = malloc0(1);
378
379 return buf;
380
381 oom:
382 free(buf);
383 return NULL;
384}
385
4468addc 386int strv_push(char ***l, char *value) {
5926ccca 387 char **c;
97569e15 388 unsigned n, m;
5926ccca
LP
389
390 if (!value)
391 return 0;
392
82dde599 393 n = strv_length(*l);
97569e15 394
98940a3c 395 /* Increase and check for overflow */
97569e15
LP
396 m = n + 2;
397 if (m < n)
398 return -ENOMEM;
399
14f27b4e 400 c = realloc_multiply(*l, sizeof(char*), m);
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;
413 unsigned n, m;
414
415 if (!a && !b)
416 return 0;
417
418 n = strv_length(*l);
419
420 /* increase and check for overflow */
421 m = n + !!a + !!b + 1;
422 if (m < n)
423 return -ENOMEM;
424
425 c = realloc_multiply(*l, sizeof(char*), m);
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
9a00f57a
LP
439int strv_push_prepend(char ***l, char *value) {
440 char **c;
97569e15 441 unsigned n, m, i;
9a00f57a
LP
442
443 if (!value)
444 return 0;
445
446 n = strv_length(*l);
97569e15
LP
447
448 /* increase and check for overflow */
449 m = n + 2;
450 if (m < n)
451 return -ENOMEM;
452
453 c = new(char*, m);
9a00f57a
LP
454 if (!c)
455 return -ENOMEM;
456
457 for (i = 0; i < n; i++)
458 c[i+1] = (*l)[i];
459
460 c[0] = value;
461 c[n+1] = NULL;
462
463 free(*l);
464 *l = c;
465
466 return 0;
467}
468
6e18964d
ZJS
469int strv_consume(char ***l, char *value) {
470 int r;
471
472 r = strv_push(l, value);
473 if (r < 0)
474 free(value);
475
9a00f57a
LP
476 return r;
477}
478
98940a3c
LP
479int strv_consume_pair(char ***l, char *a, char *b) {
480 int r;
481
482 r = strv_push_pair(l, a, b);
483 if (r < 0) {
484 free(a);
485 free(b);
486 }
487
488 return r;
489}
490
9a00f57a
LP
491int strv_consume_prepend(char ***l, char *value) {
492 int r;
493
494 r = strv_push_prepend(l, value);
495 if (r < 0)
496 free(value);
497
6e18964d
ZJS
498 return r;
499}
500
4468addc
LP
501int strv_extend(char ***l, const char *value) {
502 char *v;
4468addc
LP
503
504 if (!value)
505 return 0;
506
507 v = strdup(value);
508 if (!v)
509 return -ENOMEM;
510
6e18964d 511 return strv_consume(l, v);
4468addc
LP
512}
513
5f9a22c3 514char **strv_uniq(char **l) {
cba8922f
LP
515 char **i;
516
5f9a22c3
LP
517 /* Drops duplicate entries. The first identical string will be
518 * kept, the others dropped */
519
cba8922f 520 STRV_FOREACH(i, l)
5f9a22c3
LP
521 strv_remove(i+1, *i);
522
523 return l;
524}
525
e1dd6790
LP
526bool strv_is_uniq(char **l) {
527 char **i;
528
529 STRV_FOREACH(i, l)
530 if (strv_find(i+1, *i))
531 return false;
532
533 return true;
534}
535
5f9a22c3
LP
536char **strv_remove(char **l, const char *s) {
537 char **f, **t;
538
539 if (!l)
540 return NULL;
541
5d6ab905
LP
542 assert(s);
543
544 /* Drops every occurrence of s in the string list, edits
545 * in-place. */
5f9a22c3 546
e3e45d4f
SP
547 for (f = t = l; *f; f++)
548 if (streq(*f, s))
71ecc858 549 free(*f);
e3e45d4f
SP
550 else
551 *(t++) = *f;
71ecc858
LP
552
553 *t = NULL;
554 return l;
555}
556
21bc923a
LP
557char **strv_parse_nulstr(const char *s, size_t l) {
558 const char *p;
559 unsigned c = 0, i = 0;
560 char **v;
561
562 assert(s || l <= 0);
563
564 if (l <= 0)
49b832c5 565 return new0(char*, 1);
21bc923a
LP
566
567 for (p = s; p < s + l; p++)
568 if (*p == 0)
569 c++;
570
571 if (s[l-1] != 0)
572 c++;
573
1fd8d04e
LP
574 v = new0(char*, c+1);
575 if (!v)
21bc923a
LP
576 return NULL;
577
578 p = s;
579 while (p < s + l) {
580 const char *e;
581
582 e = memchr(p, 0, s + l - p);
583
1fd8d04e
LP
584 v[i] = strndup(p, e ? e - p : s + l - p);
585 if (!v[i]) {
21bc923a
LP
586 strv_free(v);
587 return NULL;
588 }
589
1fd8d04e
LP
590 i++;
591
21bc923a
LP
592 if (!e)
593 break;
594
595 p = e + 1;
596 }
597
598 assert(i == c);
599
600 return v;
601}
0c85a4f3 602
fabe5c0e
LP
603char **strv_split_nulstr(const char *s) {
604 const char *i;
605 char **r = NULL;
606
607 NULSTR_FOREACH(i, s)
608 if (strv_extend(&r, i) < 0) {
609 strv_free(r);
610 return NULL;
611 }
612
613 if (!r)
614 return strv_new(NULL, NULL);
615
616 return r;
617}
618
0c85a4f3 619bool strv_overlap(char **a, char **b) {
e3e45d4f 620 char **i;
0c85a4f3 621
e3e45d4f
SP
622 STRV_FOREACH(i, a)
623 if (strv_contains(b, *i))
624 return true;
0c85a4f3
LP
625
626 return false;
627}
857a493d
LP
628
629static int str_compare(const void *_a, const void *_b) {
630 const char **a = (const char**) _a, **b = (const char**) _b;
631
632 return strcmp(*a, *b);
633}
634
635char **strv_sort(char **l) {
636
637 if (strv_isempty(l))
638 return l;
639
640 qsort(l, strv_length(l), sizeof(char*), str_compare);
641 return l;
642}
7c2d8094 643
0f84a72e
DH
644bool strv_equal(char **a, char **b) {
645 if (!a || !b)
646 return a == b;
647
648 for ( ; *a || *b; ++a, ++b)
649 if (!streq_ptr(*a, *b))
650 return false;
651
652 return true;
653}
654
7c2d8094
TA
655void strv_print(char **l) {
656 char **s;
657
7c2d8094
TA
658 STRV_FOREACH(s, l)
659 puts(*s);
660}
4de33e7f
LP
661
662int strv_extendf(char ***l, const char *format, ...) {
663 va_list ap;
664 char *x;
665 int r;
666
667 va_start(ap, format);
668 r = vasprintf(&x, format, ap);
669 va_end(ap);
670
671 if (r < 0)
672 return -ENOMEM;
673
674 return strv_consume(l, x);
675}
e1dd6790
LP
676
677char **strv_reverse(char **l) {
678 unsigned n, i;
679
680 n = strv_length(l);
681 if (n <= 1)
682 return l;
683
684 for (i = 0; i < n / 2; i++) {
685 char *t;
686
687 t = l[i];
688 l[i] = l[n-1-i];
689 l[n-1-i] = t;
690 }
691
692 return l;
693}
bceccd5e 694
2404701e 695bool strv_fnmatch(char* const* patterns, const char *s, int flags) {
bceccd5e
ZJS
696 char* const* p;
697
698 STRV_FOREACH(p, patterns)
699 if (fnmatch(*p, s, 0) == 0)
700 return true;
701
702 return false;
703}