]>
Commit | Line | Data |
---|---|---|
663996b3 MS |
1 | /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ |
2 | ||
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 | |
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 | |
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 | |
16 | Lesser General Public License for more details. | |
17 | ||
18 | You should have received a copy of the GNU Lesser General Public License | |
19 | along with systemd; If not, see <http://www.gnu.org/licenses/>. | |
20 | ***/ | |
21 | ||
22 | #include <assert.h> | |
23 | #include <stdlib.h> | |
24 | #include <stdarg.h> | |
25 | #include <string.h> | |
26 | #include <errno.h> | |
27 | ||
28 | #include "util.h" | |
29 | #include "strv.h" | |
30 | ||
31 | char *strv_find(char **l, const char *name) { | |
32 | char **i; | |
33 | ||
34 | assert(name); | |
35 | ||
36 | STRV_FOREACH(i, l) | |
37 | if (streq(*i, name)) | |
38 | return *i; | |
39 | ||
40 | return NULL; | |
41 | } | |
42 | ||
43 | char *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 | ||
5eef597e MP |
55 | char *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 | ||
663996b3 MS |
72 | void 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 | ||
84 | char **strv_copy(char * const *l) { | |
85 | char **r, **k; | |
86 | ||
87 | k = r = new(char*, strv_length(l) + 1); | |
88 | if (!r) | |
89 | return NULL; | |
90 | ||
91 | if (l) | |
92 | for (; *l; k++, l++) { | |
93 | *k = strdup(*l); | |
94 | if (!*k) { | |
95 | strv_free(r); | |
96 | return NULL; | |
97 | } | |
98 | } | |
99 | ||
100 | *k = NULL; | |
101 | return r; | |
102 | } | |
103 | ||
104 | unsigned strv_length(char * const *l) { | |
105 | unsigned n = 0; | |
106 | ||
107 | if (!l) | |
108 | return 0; | |
109 | ||
110 | for (; *l; l++) | |
111 | n++; | |
112 | ||
113 | return n; | |
114 | } | |
115 | ||
116 | char **strv_new_ap(const char *x, va_list ap) { | |
117 | const char *s; | |
118 | char **a; | |
119 | unsigned n = 0, i = 0; | |
120 | va_list aq; | |
121 | ||
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 | ||
127 | if (x) { | |
128 | n = x == (const char*) -1 ? 0 : 1; | |
129 | ||
130 | va_copy(aq, ap); | |
131 | while ((s = va_arg(aq, const char*))) { | |
132 | if (s == (const char*) -1) | |
133 | continue; | |
134 | ||
135 | n++; | |
136 | } | |
137 | ||
138 | va_end(aq); | |
139 | } | |
140 | ||
141 | a = new(char*, n+1); | |
142 | if (!a) | |
143 | return NULL; | |
144 | ||
145 | if (x) { | |
146 | if (x != (const char*) -1) { | |
147 | a[i] = strdup(x); | |
148 | if (!a[i]) | |
149 | goto fail; | |
150 | i++; | |
151 | } | |
152 | ||
153 | while ((s = va_arg(ap, const char*))) { | |
154 | ||
155 | if (s == (const char*) -1) | |
156 | continue; | |
157 | ||
158 | a[i] = strdup(s); | |
159 | if (!a[i]) | |
160 | goto fail; | |
161 | ||
162 | i++; | |
163 | } | |
164 | } | |
165 | ||
166 | a[i] = NULL; | |
167 | ||
168 | return a; | |
169 | ||
170 | fail: | |
171 | strv_free(a); | |
172 | return NULL; | |
173 | } | |
174 | ||
175 | char **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 | ||
60f067b4 JS |
186 | int strv_extend_strv(char ***a, char **b) { |
187 | int r; | |
188 | char **s; | |
663996b3 | 189 | |
60f067b4 JS |
190 | STRV_FOREACH(s, b) { |
191 | r = strv_extend(a, *s); | |
192 | if (r < 0) | |
193 | return r; | |
663996b3 MS |
194 | } |
195 | ||
60f067b4 | 196 | return 0; |
663996b3 MS |
197 | } |
198 | ||
60f067b4 JS |
199 | int strv_extend_strv_concat(char ***a, char **b, const char *suffix) { |
200 | int r; | |
201 | char **s; | |
663996b3 | 202 | |
60f067b4 JS |
203 | STRV_FOREACH(s, b) { |
204 | char *v; | |
663996b3 | 205 | |
60f067b4 JS |
206 | v = strappend(*s, suffix); |
207 | if (!v) | |
208 | return -ENOMEM; | |
663996b3 | 209 | |
60f067b4 JS |
210 | r = strv_push(a, v); |
211 | if (r < 0) { | |
212 | free(v); | |
213 | return r; | |
663996b3 | 214 | } |
663996b3 MS |
215 | } |
216 | ||
60f067b4 | 217 | return 0; |
663996b3 MS |
218 | } |
219 | ||
220 | char **strv_split(const char *s, const char *separator) { | |
5eef597e | 221 | const char *word, *state; |
663996b3 MS |
222 | size_t l; |
223 | unsigned n, i; | |
224 | char **r; | |
225 | ||
226 | assert(s); | |
227 | ||
228 | n = 0; | |
5eef597e | 229 | FOREACH_WORD_SEPARATOR(word, l, s, separator, state) |
663996b3 MS |
230 | n++; |
231 | ||
232 | r = new(char*, n+1); | |
233 | if (!r) | |
234 | return NULL; | |
235 | ||
236 | i = 0; | |
5eef597e MP |
237 | FOREACH_WORD_SEPARATOR(word, l, s, separator, state) { |
238 | r[i] = strndup(word, l); | |
663996b3 MS |
239 | if (!r[i]) { |
240 | strv_free(r); | |
241 | return NULL; | |
242 | } | |
243 | ||
244 | i++; | |
245 | } | |
246 | ||
247 | r[i] = NULL; | |
248 | return r; | |
249 | } | |
250 | ||
663996b3 MS |
251 | char **strv_split_newlines(const char *s) { |
252 | char **l; | |
253 | unsigned n; | |
254 | ||
255 | assert(s); | |
256 | ||
257 | /* Special version of strv_split() that splits on newlines and | |
258 | * suppresses an empty string at the end */ | |
259 | ||
260 | l = strv_split(s, NEWLINE); | |
261 | if (!l) | |
262 | return NULL; | |
263 | ||
264 | n = strv_length(l); | |
265 | if (n <= 0) | |
266 | return l; | |
267 | ||
268 | if (isempty(l[n-1])) { | |
269 | free(l[n-1]); | |
270 | l[n-1] = NULL; | |
271 | } | |
272 | ||
273 | return l; | |
274 | } | |
275 | ||
f47781d8 MP |
276 | int strv_split_quoted(char ***t, const char *s, bool relax) { |
277 | size_t n = 0, allocated = 0; | |
278 | _cleanup_strv_free_ char **l = NULL; | |
279 | int r; | |
280 | ||
281 | assert(t); | |
282 | assert(s); | |
283 | ||
284 | for (;;) { | |
285 | _cleanup_free_ char *word = NULL; | |
286 | ||
287 | r = unquote_first_word(&s, &word, relax); | |
288 | if (r < 0) | |
289 | return r; | |
290 | if (r == 0) | |
291 | break; | |
292 | ||
293 | if (!GREEDY_REALLOC(l, allocated, n + 2)) | |
294 | return -ENOMEM; | |
295 | ||
296 | l[n++] = word; | |
297 | word = NULL; | |
298 | ||
299 | l[n] = NULL; | |
300 | } | |
301 | ||
302 | if (!l) | |
303 | l = new0(char*, 1); | |
304 | ||
305 | *t = l; | |
306 | l = NULL; | |
307 | ||
308 | return 0; | |
309 | } | |
310 | ||
663996b3 MS |
311 | char *strv_join(char **l, const char *separator) { |
312 | char *r, *e; | |
313 | char **s; | |
314 | size_t n, k; | |
315 | ||
316 | if (!separator) | |
317 | separator = " "; | |
318 | ||
319 | k = strlen(separator); | |
320 | ||
321 | n = 0; | |
322 | STRV_FOREACH(s, l) { | |
323 | if (n != 0) | |
324 | n += k; | |
325 | n += strlen(*s); | |
326 | } | |
327 | ||
328 | r = new(char, n+1); | |
329 | if (!r) | |
330 | return NULL; | |
331 | ||
332 | e = r; | |
333 | STRV_FOREACH(s, l) { | |
334 | if (e != r) | |
335 | e = stpcpy(e, separator); | |
336 | ||
337 | e = stpcpy(e, *s); | |
338 | } | |
339 | ||
340 | *e = 0; | |
341 | ||
342 | return r; | |
343 | } | |
344 | ||
14228c0d MB |
345 | char *strv_join_quoted(char **l) { |
346 | char *buf = NULL; | |
347 | char **s; | |
348 | size_t allocated = 0, len = 0; | |
349 | ||
350 | STRV_FOREACH(s, l) { | |
351 | /* assuming here that escaped string cannot be more | |
352 | * than twice as long, and reserving space for the | |
353 | * separator and quotes. | |
354 | */ | |
355 | _cleanup_free_ char *esc = NULL; | |
356 | size_t needed; | |
357 | ||
358 | if (!GREEDY_REALLOC(buf, allocated, | |
359 | len + strlen(*s) * 2 + 3)) | |
360 | goto oom; | |
361 | ||
362 | esc = cescape(*s); | |
363 | if (!esc) | |
364 | goto oom; | |
365 | ||
366 | needed = snprintf(buf + len, allocated - len, "%s\"%s\"", | |
367 | len > 0 ? " " : "", esc); | |
368 | assert(needed < allocated - len); | |
369 | len += needed; | |
370 | } | |
371 | ||
372 | if (!buf) | |
373 | buf = malloc0(1); | |
374 | ||
375 | return buf; | |
376 | ||
377 | oom: | |
378 | free(buf); | |
379 | return NULL; | |
380 | } | |
381 | ||
663996b3 MS |
382 | int strv_push(char ***l, char *value) { |
383 | char **c; | |
5eef597e | 384 | unsigned n, m; |
663996b3 MS |
385 | |
386 | if (!value) | |
387 | return 0; | |
388 | ||
389 | n = strv_length(*l); | |
5eef597e | 390 | |
f47781d8 | 391 | /* Increase and check for overflow */ |
5eef597e MP |
392 | m = n + 2; |
393 | if (m < n) | |
394 | return -ENOMEM; | |
395 | ||
396 | c = realloc_multiply(*l, sizeof(char*), m); | |
663996b3 MS |
397 | if (!c) |
398 | return -ENOMEM; | |
399 | ||
400 | c[n] = value; | |
401 | c[n+1] = NULL; | |
402 | ||
403 | *l = c; | |
404 | return 0; | |
405 | } | |
406 | ||
f47781d8 MP |
407 | int strv_push_pair(char ***l, char *a, char *b) { |
408 | char **c; | |
409 | unsigned n, m; | |
410 | ||
411 | if (!a && !b) | |
412 | return 0; | |
413 | ||
414 | n = strv_length(*l); | |
415 | ||
416 | /* increase and check for overflow */ | |
417 | m = n + !!a + !!b + 1; | |
418 | if (m < n) | |
419 | return -ENOMEM; | |
420 | ||
421 | c = realloc_multiply(*l, sizeof(char*), m); | |
422 | if (!c) | |
423 | return -ENOMEM; | |
424 | ||
425 | if (a) | |
426 | c[n++] = a; | |
427 | if (b) | |
428 | c[n++] = b; | |
429 | c[n] = NULL; | |
430 | ||
431 | *l = c; | |
432 | return 0; | |
433 | } | |
434 | ||
e842803a MB |
435 | int strv_push_prepend(char ***l, char *value) { |
436 | char **c; | |
5eef597e | 437 | unsigned n, m, i; |
e842803a MB |
438 | |
439 | if (!value) | |
440 | return 0; | |
441 | ||
442 | n = strv_length(*l); | |
5eef597e MP |
443 | |
444 | /* increase and check for overflow */ | |
445 | m = n + 2; | |
446 | if (m < n) | |
447 | return -ENOMEM; | |
448 | ||
449 | c = new(char*, m); | |
e842803a MB |
450 | if (!c) |
451 | return -ENOMEM; | |
452 | ||
453 | for (i = 0; i < n; i++) | |
454 | c[i+1] = (*l)[i]; | |
455 | ||
456 | c[0] = value; | |
457 | c[n+1] = NULL; | |
458 | ||
459 | free(*l); | |
460 | *l = c; | |
461 | ||
462 | return 0; | |
463 | } | |
464 | ||
60f067b4 JS |
465 | int strv_consume(char ***l, char *value) { |
466 | int r; | |
467 | ||
468 | r = strv_push(l, value); | |
469 | if (r < 0) | |
470 | free(value); | |
471 | ||
e842803a MB |
472 | return r; |
473 | } | |
474 | ||
f47781d8 MP |
475 | int strv_consume_pair(char ***l, char *a, char *b) { |
476 | int r; | |
477 | ||
478 | r = strv_push_pair(l, a, b); | |
479 | if (r < 0) { | |
480 | free(a); | |
481 | free(b); | |
482 | } | |
483 | ||
484 | return r; | |
485 | } | |
486 | ||
e842803a MB |
487 | int strv_consume_prepend(char ***l, char *value) { |
488 | int r; | |
489 | ||
490 | r = strv_push_prepend(l, value); | |
491 | if (r < 0) | |
492 | free(value); | |
493 | ||
60f067b4 JS |
494 | return r; |
495 | } | |
496 | ||
663996b3 MS |
497 | int strv_extend(char ***l, const char *value) { |
498 | char *v; | |
663996b3 MS |
499 | |
500 | if (!value) | |
501 | return 0; | |
502 | ||
503 | v = strdup(value); | |
504 | if (!v) | |
505 | return -ENOMEM; | |
506 | ||
60f067b4 | 507 | return strv_consume(l, v); |
663996b3 MS |
508 | } |
509 | ||
510 | char **strv_uniq(char **l) { | |
511 | char **i; | |
512 | ||
513 | /* Drops duplicate entries. The first identical string will be | |
514 | * kept, the others dropped */ | |
515 | ||
516 | STRV_FOREACH(i, l) | |
517 | strv_remove(i+1, *i); | |
518 | ||
519 | return l; | |
520 | } | |
521 | ||
522 | char **strv_remove(char **l, const char *s) { | |
523 | char **f, **t; | |
524 | ||
525 | if (!l) | |
526 | return NULL; | |
527 | ||
528 | assert(s); | |
529 | ||
530 | /* Drops every occurrence of s in the string list, edits | |
531 | * in-place. */ | |
532 | ||
60f067b4 JS |
533 | for (f = t = l; *f; f++) |
534 | if (streq(*f, s)) | |
663996b3 | 535 | free(*f); |
60f067b4 JS |
536 | else |
537 | *(t++) = *f; | |
663996b3 MS |
538 | |
539 | *t = NULL; | |
540 | return l; | |
541 | } | |
542 | ||
543 | char **strv_parse_nulstr(const char *s, size_t l) { | |
544 | const char *p; | |
545 | unsigned c = 0, i = 0; | |
546 | char **v; | |
547 | ||
548 | assert(s || l <= 0); | |
549 | ||
550 | if (l <= 0) | |
60f067b4 | 551 | return new0(char*, 1); |
663996b3 MS |
552 | |
553 | for (p = s; p < s + l; p++) | |
554 | if (*p == 0) | |
555 | c++; | |
556 | ||
557 | if (s[l-1] != 0) | |
558 | c++; | |
559 | ||
560 | v = new0(char*, c+1); | |
561 | if (!v) | |
562 | return NULL; | |
563 | ||
564 | p = s; | |
565 | while (p < s + l) { | |
566 | const char *e; | |
567 | ||
568 | e = memchr(p, 0, s + l - p); | |
569 | ||
570 | v[i] = strndup(p, e ? e - p : s + l - p); | |
571 | if (!v[i]) { | |
572 | strv_free(v); | |
573 | return NULL; | |
574 | } | |
575 | ||
576 | i++; | |
577 | ||
578 | if (!e) | |
579 | break; | |
580 | ||
581 | p = e + 1; | |
582 | } | |
583 | ||
584 | assert(i == c); | |
585 | ||
586 | return v; | |
587 | } | |
588 | ||
589 | char **strv_split_nulstr(const char *s) { | |
590 | const char *i; | |
591 | char **r = NULL; | |
592 | ||
593 | NULSTR_FOREACH(i, s) | |
594 | if (strv_extend(&r, i) < 0) { | |
595 | strv_free(r); | |
596 | return NULL; | |
597 | } | |
598 | ||
599 | if (!r) | |
600 | return strv_new(NULL, NULL); | |
601 | ||
602 | return r; | |
603 | } | |
604 | ||
605 | bool strv_overlap(char **a, char **b) { | |
60f067b4 | 606 | char **i; |
663996b3 | 607 | |
60f067b4 JS |
608 | STRV_FOREACH(i, a) |
609 | if (strv_contains(b, *i)) | |
610 | return true; | |
663996b3 MS |
611 | |
612 | return false; | |
613 | } | |
614 | ||
615 | static int str_compare(const void *_a, const void *_b) { | |
616 | const char **a = (const char**) _a, **b = (const char**) _b; | |
617 | ||
618 | return strcmp(*a, *b); | |
619 | } | |
620 | ||
621 | char **strv_sort(char **l) { | |
622 | ||
623 | if (strv_isempty(l)) | |
624 | return l; | |
625 | ||
626 | qsort(l, strv_length(l), sizeof(char*), str_compare); | |
627 | return l; | |
628 | } | |
629 | ||
f47781d8 MP |
630 | bool strv_equal(char **a, char **b) { |
631 | if (!a || !b) | |
632 | return a == b; | |
633 | ||
634 | for ( ; *a || *b; ++a, ++b) | |
635 | if (!streq_ptr(*a, *b)) | |
636 | return false; | |
637 | ||
638 | return true; | |
639 | } | |
640 | ||
663996b3 MS |
641 | void strv_print(char **l) { |
642 | char **s; | |
643 | ||
663996b3 MS |
644 | STRV_FOREACH(s, l) |
645 | puts(*s); | |
646 | } | |
60f067b4 JS |
647 | |
648 | int strv_extendf(char ***l, const char *format, ...) { | |
649 | va_list ap; | |
650 | char *x; | |
651 | int r; | |
652 | ||
653 | va_start(ap, format); | |
654 | r = vasprintf(&x, format, ap); | |
655 | va_end(ap); | |
656 | ||
657 | if (r < 0) | |
658 | return -ENOMEM; | |
659 | ||
660 | return strv_consume(l, x); | |
661 | } |