]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/strv.c
man: add examples for coredumpctl
[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 <assert.h>
23#include <stdlib.h>
24#include <stdarg.h>
25#include <string.h>
2e6c9e6b 26#include <errno.h>
60918275
LP
27
28#include "util.h"
29#include "strv.h"
30
31char *strv_find(char **l, const char *name) {
5f9a22c3
LP
32 char **i;
33
60918275
LP
34 assert(name);
35
5f9a22c3
LP
36 STRV_FOREACH(i, l)
37 if (streq(*i, name))
38 return *i;
60918275
LP
39
40 return NULL;
41}
42
a4bfb399
LP
43char *strv_find_prefix(char **l, const char *name) {
44 char **i;
45
46 assert(name);
47
48 STRV_FOREACH(i, l)
49 if (startswith(*i, name))
50 return *i;
51
52 return NULL;
53}
54
28849dba
LP
55char *strv_find_startswith(char **l, const char *name) {
56 char **i, *e;
57
58 assert(name);
59
60 /* Like strv_find_prefix, but actually returns only the
61 * suffix, not the whole item */
62
63 STRV_FOREACH(i, l) {
64 e = startswith(*i, name);
65 if (e)
66 return e;
67 }
68
69 return NULL;
70}
71
60918275
LP
72void strv_free(char **l) {
73 char **k;
74
75 if (!l)
76 return;
77
78 for (k = l; *k; k++)
79 free(*k);
80
81 free(l);
82}
83
2fd9ae2e 84char **strv_copy(char * const *l) {
60918275
LP
85 char **r, **k;
86
1fd8d04e
LP
87 k = r = new(char*, strv_length(l) + 1);
88 if (!r)
60918275
LP
89 return NULL;
90
ede27aab 91 if (l)
1fd8d04e
LP
92 for (; *l; k++, l++) {
93 *k = strdup(*l);
94 if (!*k) {
95 strv_free(r);
96 return NULL;
97 }
98 }
60918275
LP
99
100 *k = NULL;
101 return r;
60918275
LP
102}
103
2fd9ae2e 104unsigned strv_length(char * const *l) {
60918275
LP
105 unsigned n = 0;
106
107 if (!l)
108 return 0;
109
110 for (; *l; l++)
111 n++;
112
113 return n;
114}
115
257eca1a 116char **strv_new_ap(const char *x, va_list ap) {
60918275
LP
117 const char *s;
118 char **a;
119 unsigned n = 0, i = 0;
257eca1a
LP
120 va_list aq;
121
07719a21
LP
122 /* As a special trick we ignore all listed strings that equal
123 * (const char*) -1. This is supposed to be used with the
124 * STRV_IFNOTNULL() macro to include possibly NULL strings in
125 * the string list. */
126
60918275 127 if (x) {
07719a21 128 n = x == (const char*) -1 ? 0 : 1;
60918275 129
257eca1a 130 va_copy(aq, ap);
07719a21
LP
131 while ((s = va_arg(aq, const char*))) {
132 if (s == (const char*) -1)
133 continue;
134
60918275 135 n++;
07719a21
LP
136 }
137
257eca1a 138 va_end(aq);
60918275
LP
139 }
140
07719a21
LP
141 a = new(char*, n+1);
142 if (!a)
60918275
LP
143 return NULL;
144
145 if (x) {
07719a21
LP
146 if (x != (const char*) -1) {
147 a[i] = strdup(x);
148 if (!a[i])
149 goto fail;
150 i++;
60918275
LP
151 }
152
60918275 153 while ((s = va_arg(ap, const char*))) {
07719a21
LP
154
155 if (s == (const char*) -1)
156 continue;
157
158 a[i] = strdup(s);
159 if (!a[i])
60918275
LP
160 goto fail;
161
162 i++;
163 }
60918275
LP
164 }
165
166 a[i] = NULL;
257eca1a 167
60918275
LP
168 return a;
169
170fail:
1fd8d04e 171 strv_free(a);
60918275
LP
172 return NULL;
173}
034c6ed7 174
257eca1a
LP
175char **strv_new(const char *x, ...) {
176 char **r;
177 va_list ap;
178
179 va_start(ap, x);
180 r = strv_new_ap(x, ap);
181 va_end(ap);
182
183 return r;
184}
185
e3e45d4f
SP
186int strv_extend_strv(char ***a, char **b) {
187 int r;
188 char **s;
07719a21 189
e3e45d4f
SP
190 STRV_FOREACH(s, b) {
191 r = strv_extend(a, *s);
192 if (r < 0)
193 return r;
07719a21 194 }
034c6ed7 195
e3e45d4f 196 return 0;
5f9a22c3
LP
197}
198
e3e45d4f
SP
199int strv_extend_strv_concat(char ***a, char **b, const char *suffix) {
200 int r;
201 char **s;
5f9a22c3 202
e3e45d4f
SP
203 STRV_FOREACH(s, b) {
204 char *v;
5f9a22c3 205
e3e45d4f
SP
206 v = strappend(*s, suffix);
207 if (!v)
208 return -ENOMEM;
5f9a22c3 209
e3e45d4f
SP
210 r = strv_push(a, v);
211 if (r < 0) {
212 free(v);
213 return r;
8ea913b2 214 }
8ea913b2 215 }
5f9a22c3 216
e3e45d4f 217 return 0;
5f9a22c3
LP
218}
219
220char **strv_split(const char *s, const char *separator) {
a2a5291b 221 const char *word, *state;
5f9a22c3
LP
222 size_t l;
223 unsigned n, i;
224 char **r;
225
226 assert(s);
227
228 n = 0;
a2a5291b 229 FOREACH_WORD_SEPARATOR(word, l, s, separator, state)
5f9a22c3
LP
230 n++;
231
1fd8d04e
LP
232 r = new(char*, n+1);
233 if (!r)
5f9a22c3
LP
234 return NULL;
235
236 i = 0;
a2a5291b
ZJS
237 FOREACH_WORD_SEPARATOR(word, l, s, separator, state) {
238 r[i] = strndup(word, l);
1fd8d04e 239 if (!r[i]) {
5f9a22c3
LP
240 strv_free(r);
241 return NULL;
242 }
243
1fd8d04e
LP
244 i++;
245 }
246
5f9a22c3
LP
247 r[i] = NULL;
248 return r;
249}
250
b2fadec6 251int strv_split_quoted(char ***t, const char *s) {
a2a5291b 252 const char *word, *state;
5f9a22c3
LP
253 size_t l;
254 unsigned n, i;
255 char **r;
256
257 assert(s);
258
259 n = 0;
a2a5291b 260 FOREACH_WORD_QUOTED(word, l, s, state)
5f9a22c3 261 n++;
b2fadec6 262 if (!isempty(state))
a2a5291b 263 /* bad syntax */
b2fadec6 264 return -EINVAL;
5f9a22c3 265
1fd8d04e
LP
266 r = new(char*, n+1);
267 if (!r)
b2fadec6 268 return -ENOMEM;
5f9a22c3
LP
269
270 i = 0;
a2a5291b
ZJS
271 FOREACH_WORD_QUOTED(word, l, s, state) {
272 r[i] = cunescape_length(word, l);
1fd8d04e 273 if (!r[i]) {
5f9a22c3 274 strv_free(r);
b2fadec6 275 return -ENOMEM;
5f9a22c3 276 }
1fd8d04e
LP
277 i++;
278 }
5f9a22c3
LP
279
280 r[i] = NULL;
b2fadec6
ZJS
281 *t = r;
282 return 0;
5f9a22c3
LP
283}
284
26d04f86
LP
285char **strv_split_newlines(const char *s) {
286 char **l;
287 unsigned n;
288
289 assert(s);
290
291 /* Special version of strv_split() that splits on newlines and
292 * suppresses an empty string at the end */
293
294 l = strv_split(s, NEWLINE);
295 if (!l)
296 return NULL;
297
298 n = strv_length(l);
299 if (n <= 0)
300 return l;
301
302 if (isempty(l[n-1])) {
303 free(l[n-1]);
304 l[n-1] = NULL;
305 }
306
307 return l;
308}
309
5f9a22c3
LP
310char *strv_join(char **l, const char *separator) {
311 char *r, *e;
312 char **s;
313 size_t n, k;
314
315 if (!separator)
316 separator = " ";
317
318 k = strlen(separator);
319
320 n = 0;
321 STRV_FOREACH(s, l) {
322 if (n != 0)
323 n += k;
324 n += strlen(*s);
325 }
326
1fd8d04e
LP
327 r = new(char, n+1);
328 if (!r)
5f9a22c3
LP
329 return NULL;
330
331 e = r;
332 STRV_FOREACH(s, l) {
333 if (e != r)
334 e = stpcpy(e, separator);
335
336 e = stpcpy(e, *s);
337 }
338
8d49745c
LP
339 *e = 0;
340
5f9a22c3
LP
341 return r;
342}
343
a6fde353
ZJS
344char *strv_join_quoted(char **l) {
345 char *buf = NULL;
346 char **s;
347 size_t allocated = 0, len = 0;
348
349 STRV_FOREACH(s, l) {
350 /* assuming here that escaped string cannot be more
351 * than twice as long, and reserving space for the
352 * separator and quotes.
353 */
354 _cleanup_free_ char *esc = NULL;
355 size_t needed;
356
357 if (!GREEDY_REALLOC(buf, allocated,
358 len + strlen(*s) * 2 + 3))
359 goto oom;
360
361 esc = cescape(*s);
362 if (!esc)
363 goto oom;
364
365 needed = snprintf(buf + len, allocated - len, "%s\"%s\"",
366 len > 0 ? " " : "", esc);
367 assert(needed < allocated - len);
368 len += needed;
369 }
370
371 if (!buf)
372 buf = malloc0(1);
373
374 return buf;
375
376 oom:
377 free(buf);
378 return NULL;
379}
380
4468addc 381int strv_push(char ***l, char *value) {
5926ccca 382 char **c;
82dde599 383 unsigned n;
5926ccca
LP
384
385 if (!value)
386 return 0;
387
82dde599
LP
388 n = strv_length(*l);
389 c = realloc(*l, sizeof(char*) * (n + 2));
4468addc 390 if (!c)
82dde599 391 return -ENOMEM;
82dde599 392
4468addc 393 c[n] = value;
82dde599
LP
394 c[n+1] = NULL;
395
5926ccca
LP
396 *l = c;
397 return 0;
398}
399
9a00f57a
LP
400int strv_push_prepend(char ***l, char *value) {
401 char **c;
402 unsigned n, i;
403
404 if (!value)
405 return 0;
406
407 n = strv_length(*l);
408 c = new(char*, n + 2);
409 if (!c)
410 return -ENOMEM;
411
412 for (i = 0; i < n; i++)
413 c[i+1] = (*l)[i];
414
415 c[0] = value;
416 c[n+1] = NULL;
417
418 free(*l);
419 *l = c;
420
421 return 0;
422}
423
6e18964d
ZJS
424int strv_consume(char ***l, char *value) {
425 int r;
426
427 r = strv_push(l, value);
428 if (r < 0)
429 free(value);
430
9a00f57a
LP
431 return r;
432}
433
434int strv_consume_prepend(char ***l, char *value) {
435 int r;
436
437 r = strv_push_prepend(l, value);
438 if (r < 0)
439 free(value);
440
6e18964d
ZJS
441 return r;
442}
443
4468addc
LP
444int strv_extend(char ***l, const char *value) {
445 char *v;
4468addc
LP
446
447 if (!value)
448 return 0;
449
450 v = strdup(value);
451 if (!v)
452 return -ENOMEM;
453
6e18964d 454 return strv_consume(l, v);
4468addc
LP
455}
456
5f9a22c3 457char **strv_uniq(char **l) {
cba8922f
LP
458 char **i;
459
5f9a22c3
LP
460 /* Drops duplicate entries. The first identical string will be
461 * kept, the others dropped */
462
cba8922f 463 STRV_FOREACH(i, l)
5f9a22c3
LP
464 strv_remove(i+1, *i);
465
466 return l;
467}
468
469char **strv_remove(char **l, const char *s) {
470 char **f, **t;
471
472 if (!l)
473 return NULL;
474
5d6ab905
LP
475 assert(s);
476
477 /* Drops every occurrence of s in the string list, edits
478 * in-place. */
5f9a22c3 479
e3e45d4f
SP
480 for (f = t = l; *f; f++)
481 if (streq(*f, s))
71ecc858 482 free(*f);
e3e45d4f
SP
483 else
484 *(t++) = *f;
71ecc858
LP
485
486 *t = NULL;
487 return l;
488}
489
21bc923a
LP
490char **strv_parse_nulstr(const char *s, size_t l) {
491 const char *p;
492 unsigned c = 0, i = 0;
493 char **v;
494
495 assert(s || l <= 0);
496
497 if (l <= 0)
49b832c5 498 return new0(char*, 1);
21bc923a
LP
499
500 for (p = s; p < s + l; p++)
501 if (*p == 0)
502 c++;
503
504 if (s[l-1] != 0)
505 c++;
506
1fd8d04e
LP
507 v = new0(char*, c+1);
508 if (!v)
21bc923a
LP
509 return NULL;
510
511 p = s;
512 while (p < s + l) {
513 const char *e;
514
515 e = memchr(p, 0, s + l - p);
516
1fd8d04e
LP
517 v[i] = strndup(p, e ? e - p : s + l - p);
518 if (!v[i]) {
21bc923a
LP
519 strv_free(v);
520 return NULL;
521 }
522
1fd8d04e
LP
523 i++;
524
21bc923a
LP
525 if (!e)
526 break;
527
528 p = e + 1;
529 }
530
531 assert(i == c);
532
533 return v;
534}
0c85a4f3 535
fabe5c0e
LP
536char **strv_split_nulstr(const char *s) {
537 const char *i;
538 char **r = NULL;
539
540 NULSTR_FOREACH(i, s)
541 if (strv_extend(&r, i) < 0) {
542 strv_free(r);
543 return NULL;
544 }
545
546 if (!r)
547 return strv_new(NULL, NULL);
548
549 return r;
550}
551
0c85a4f3 552bool strv_overlap(char **a, char **b) {
e3e45d4f 553 char **i;
0c85a4f3 554
e3e45d4f
SP
555 STRV_FOREACH(i, a)
556 if (strv_contains(b, *i))
557 return true;
0c85a4f3
LP
558
559 return false;
560}
857a493d
LP
561
562static int str_compare(const void *_a, const void *_b) {
563 const char **a = (const char**) _a, **b = (const char**) _b;
564
565 return strcmp(*a, *b);
566}
567
568char **strv_sort(char **l) {
569
570 if (strv_isempty(l))
571 return l;
572
573 qsort(l, strv_length(l), sizeof(char*), str_compare);
574 return l;
575}
7c2d8094
TA
576
577void strv_print(char **l) {
578 char **s;
579
7c2d8094
TA
580 STRV_FOREACH(s, l)
581 puts(*s);
582}
4de33e7f
LP
583
584int strv_extendf(char ***l, const char *format, ...) {
585 va_list ap;
586 char *x;
587 int r;
588
589 va_start(ap, format);
590 r = vasprintf(&x, format, ap);
591 va_end(ap);
592
593 if (r < 0)
594 return -ENOMEM;
595
596 return strv_consume(l, x);
597}