]>
Commit | Line | Data |
---|---|---|
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 | ||
07630cea | 22 | #include <errno.h> |
11c3a366 | 23 | #include <fnmatch.h> |
60918275 | 24 | #include <stdarg.h> |
11c3a366 | 25 | #include <stdio.h> |
07630cea | 26 | #include <stdlib.h> |
60918275 LP |
27 | #include <string.h> |
28 | ||
b5efdb8a | 29 | #include "alloc-util.h" |
4f5dd394 | 30 | #include "escape.h" |
11c3a366 | 31 | #include "extract-word.h" |
07630cea | 32 | #include "string-util.h" |
60918275 | 33 | #include "strv.h" |
cf0fbc49 | 34 | #include "util.h" |
60918275 LP |
35 | |
36 | char *strv_find(char **l, const char *name) { | |
5f9a22c3 LP |
37 | char **i; |
38 | ||
60918275 LP |
39 | assert(name); |
40 | ||
5f9a22c3 LP |
41 | STRV_FOREACH(i, l) |
42 | if (streq(*i, name)) | |
43 | return *i; | |
60918275 LP |
44 | |
45 | return NULL; | |
46 | } | |
47 | ||
a4bfb399 LP |
48 | char *strv_find_prefix(char **l, const char *name) { |
49 | char **i; | |
50 | ||
51 | assert(name); | |
52 | ||
53 | STRV_FOREACH(i, l) | |
54 | if (startswith(*i, name)) | |
55 | return *i; | |
56 | ||
57 | return NULL; | |
58 | } | |
59 | ||
28849dba LP |
60 | char *strv_find_startswith(char **l, const char *name) { |
61 | char **i, *e; | |
62 | ||
63 | assert(name); | |
64 | ||
65 | /* Like strv_find_prefix, but actually returns only the | |
66 | * suffix, not the whole item */ | |
67 | ||
68 | STRV_FOREACH(i, l) { | |
69 | e = startswith(*i, name); | |
70 | if (e) | |
71 | return e; | |
72 | } | |
73 | ||
74 | return NULL; | |
75 | } | |
76 | ||
dd9c7723 | 77 | void strv_clear(char **l) { |
60918275 LP |
78 | char **k; |
79 | ||
80 | if (!l) | |
81 | return; | |
82 | ||
83 | for (k = l; *k; k++) | |
84 | free(*k); | |
85 | ||
dd9c7723 TG |
86 | *l = NULL; |
87 | } | |
88 | ||
33c2ce7b | 89 | char **strv_free(char **l) { |
dd9c7723 | 90 | strv_clear(l); |
60918275 | 91 | free(l); |
33c2ce7b | 92 | return NULL; |
60918275 LP |
93 | } |
94 | ||
ab84f5b9 ZJS |
95 | char **strv_free_erase(char **l) { |
96 | char **i; | |
97 | ||
98 | STRV_FOREACH(i, l) | |
99 | string_erase(*i); | |
100 | ||
101 | return strv_free(l); | |
102 | } | |
103 | ||
2fd9ae2e | 104 | char **strv_copy(char * const *l) { |
60918275 LP |
105 | char **r, **k; |
106 | ||
1fd8d04e LP |
107 | k = r = new(char*, strv_length(l) + 1); |
108 | if (!r) | |
60918275 LP |
109 | return NULL; |
110 | ||
ede27aab | 111 | if (l) |
1fd8d04e LP |
112 | for (; *l; k++, l++) { |
113 | *k = strdup(*l); | |
114 | if (!*k) { | |
115 | strv_free(r); | |
116 | return NULL; | |
117 | } | |
118 | } | |
60918275 LP |
119 | |
120 | *k = NULL; | |
121 | return r; | |
60918275 LP |
122 | } |
123 | ||
2fd9ae2e | 124 | unsigned strv_length(char * const *l) { |
60918275 LP |
125 | unsigned n = 0; |
126 | ||
127 | if (!l) | |
128 | return 0; | |
129 | ||
130 | for (; *l; l++) | |
131 | n++; | |
132 | ||
133 | return n; | |
134 | } | |
135 | ||
257eca1a | 136 | char **strv_new_ap(const char *x, va_list ap) { |
60918275 LP |
137 | const char *s; |
138 | char **a; | |
139 | unsigned n = 0, i = 0; | |
257eca1a LP |
140 | va_list aq; |
141 | ||
07719a21 LP |
142 | /* As a special trick we ignore all listed strings that equal |
143 | * (const char*) -1. This is supposed to be used with the | |
144 | * STRV_IFNOTNULL() macro to include possibly NULL strings in | |
145 | * the string list. */ | |
146 | ||
60918275 | 147 | if (x) { |
07719a21 | 148 | n = x == (const char*) -1 ? 0 : 1; |
60918275 | 149 | |
257eca1a | 150 | va_copy(aq, ap); |
07719a21 LP |
151 | while ((s = va_arg(aq, const char*))) { |
152 | if (s == (const char*) -1) | |
153 | continue; | |
154 | ||
60918275 | 155 | n++; |
07719a21 LP |
156 | } |
157 | ||
257eca1a | 158 | va_end(aq); |
60918275 LP |
159 | } |
160 | ||
07719a21 LP |
161 | a = new(char*, n+1); |
162 | if (!a) | |
60918275 LP |
163 | return NULL; |
164 | ||
165 | if (x) { | |
07719a21 LP |
166 | if (x != (const char*) -1) { |
167 | a[i] = strdup(x); | |
168 | if (!a[i]) | |
169 | goto fail; | |
170 | i++; | |
60918275 LP |
171 | } |
172 | ||
60918275 | 173 | while ((s = va_arg(ap, const char*))) { |
07719a21 LP |
174 | |
175 | if (s == (const char*) -1) | |
176 | continue; | |
177 | ||
178 | a[i] = strdup(s); | |
179 | if (!a[i]) | |
60918275 LP |
180 | goto fail; |
181 | ||
182 | i++; | |
183 | } | |
60918275 LP |
184 | } |
185 | ||
186 | a[i] = NULL; | |
257eca1a | 187 | |
60918275 LP |
188 | return a; |
189 | ||
190 | fail: | |
1fd8d04e | 191 | strv_free(a); |
60918275 LP |
192 | return NULL; |
193 | } | |
034c6ed7 | 194 | |
257eca1a LP |
195 | char **strv_new(const char *x, ...) { |
196 | char **r; | |
197 | va_list ap; | |
198 | ||
199 | va_start(ap, x); | |
200 | r = strv_new_ap(x, ap); | |
201 | va_end(ap); | |
202 | ||
203 | return r; | |
204 | } | |
205 | ||
e287086b LP |
206 | int strv_extend_strv(char ***a, char **b, bool filter_duplicates) { |
207 | char **s, **t; | |
208 | size_t p, q, i = 0, j; | |
209 | ||
210 | assert(a); | |
211 | ||
212 | if (strv_isempty(b)) | |
213 | return 0; | |
214 | ||
215 | p = strv_length(*a); | |
216 | q = strv_length(b); | |
217 | ||
218 | t = realloc(*a, sizeof(char*) * (p + q + 1)); | |
219 | if (!t) | |
220 | return -ENOMEM; | |
221 | ||
222 | t[p] = NULL; | |
223 | *a = t; | |
07719a21 | 224 | |
e3e45d4f | 225 | STRV_FOREACH(s, b) { |
e287086b LP |
226 | |
227 | if (filter_duplicates && strv_contains(t, *s)) | |
228 | continue; | |
229 | ||
230 | t[p+i] = strdup(*s); | |
231 | if (!t[p+i]) | |
232 | goto rollback; | |
233 | ||
234 | i++; | |
235 | t[p+i] = NULL; | |
07719a21 | 236 | } |
034c6ed7 | 237 | |
e287086b LP |
238 | assert(i <= q); |
239 | ||
240 | return (int) i; | |
241 | ||
242 | rollback: | |
243 | for (j = 0; j < i; j++) | |
244 | free(t[p + j]); | |
245 | ||
246 | t[p] = NULL; | |
247 | return -ENOMEM; | |
5f9a22c3 LP |
248 | } |
249 | ||
e3e45d4f SP |
250 | int strv_extend_strv_concat(char ***a, char **b, const char *suffix) { |
251 | int r; | |
252 | char **s; | |
5f9a22c3 | 253 | |
e3e45d4f SP |
254 | STRV_FOREACH(s, b) { |
255 | char *v; | |
5f9a22c3 | 256 | |
e3e45d4f SP |
257 | v = strappend(*s, suffix); |
258 | if (!v) | |
259 | return -ENOMEM; | |
5f9a22c3 | 260 | |
e3e45d4f SP |
261 | r = strv_push(a, v); |
262 | if (r < 0) { | |
263 | free(v); | |
264 | return r; | |
8ea913b2 | 265 | } |
8ea913b2 | 266 | } |
5f9a22c3 | 267 | |
e3e45d4f | 268 | return 0; |
5f9a22c3 LP |
269 | } |
270 | ||
271 | char **strv_split(const char *s, const char *separator) { | |
a2a5291b | 272 | const char *word, *state; |
5f9a22c3 LP |
273 | size_t l; |
274 | unsigned n, i; | |
275 | char **r; | |
276 | ||
277 | assert(s); | |
278 | ||
279 | n = 0; | |
a2a5291b | 280 | FOREACH_WORD_SEPARATOR(word, l, s, separator, state) |
5f9a22c3 LP |
281 | n++; |
282 | ||
1fd8d04e LP |
283 | r = new(char*, n+1); |
284 | if (!r) | |
5f9a22c3 LP |
285 | return NULL; |
286 | ||
287 | i = 0; | |
a2a5291b ZJS |
288 | FOREACH_WORD_SEPARATOR(word, l, s, separator, state) { |
289 | r[i] = strndup(word, l); | |
1fd8d04e | 290 | if (!r[i]) { |
5f9a22c3 LP |
291 | strv_free(r); |
292 | return NULL; | |
293 | } | |
294 | ||
1fd8d04e LP |
295 | i++; |
296 | } | |
297 | ||
5f9a22c3 LP |
298 | r[i] = NULL; |
299 | return r; | |
300 | } | |
301 | ||
26d04f86 LP |
302 | char **strv_split_newlines(const char *s) { |
303 | char **l; | |
304 | unsigned n; | |
305 | ||
306 | assert(s); | |
307 | ||
308 | /* Special version of strv_split() that splits on newlines and | |
309 | * suppresses an empty string at the end */ | |
310 | ||
311 | l = strv_split(s, NEWLINE); | |
312 | if (!l) | |
313 | return NULL; | |
314 | ||
315 | n = strv_length(l); | |
316 | if (n <= 0) | |
317 | return l; | |
318 | ||
ece174c5 | 319 | if (isempty(l[n - 1])) |
a1e58e8e | 320 | l[n - 1] = mfree(l[n - 1]); |
26d04f86 LP |
321 | |
322 | return l; | |
323 | } | |
324 | ||
8adaf7bd | 325 | int strv_split_extract(char ***t, const char *s, const char *separators, ExtractFlags flags) { |
f88e6be5 | 326 | _cleanup_strv_free_ char **l = NULL; |
8dd4c05b | 327 | size_t n = 0, allocated = 0; |
f88e6be5 LP |
328 | int r; |
329 | ||
330 | assert(t); | |
331 | assert(s); | |
332 | ||
333 | for (;;) { | |
334 | _cleanup_free_ char *word = NULL; | |
335 | ||
8adaf7bd | 336 | r = extract_first_word(&s, &word, separators, flags); |
f88e6be5 LP |
337 | if (r < 0) |
338 | return r; | |
ece174c5 | 339 | if (r == 0) |
f88e6be5 LP |
340 | break; |
341 | ||
342 | if (!GREEDY_REALLOC(l, allocated, n + 2)) | |
343 | return -ENOMEM; | |
344 | ||
345 | l[n++] = word; | |
346 | word = NULL; | |
347 | ||
348 | l[n] = NULL; | |
349 | } | |
350 | ||
8dd4c05b | 351 | if (!l) { |
f88e6be5 | 352 | l = new0(char*, 1); |
8dd4c05b LP |
353 | if (!l) |
354 | return -ENOMEM; | |
355 | } | |
f88e6be5 LP |
356 | |
357 | *t = l; | |
358 | l = NULL; | |
359 | ||
8dd4c05b | 360 | return (int) n; |
f88e6be5 LP |
361 | } |
362 | ||
5f9a22c3 LP |
363 | char *strv_join(char **l, const char *separator) { |
364 | char *r, *e; | |
365 | char **s; | |
366 | size_t n, k; | |
367 | ||
368 | if (!separator) | |
369 | separator = " "; | |
370 | ||
371 | k = strlen(separator); | |
372 | ||
373 | n = 0; | |
374 | STRV_FOREACH(s, l) { | |
375 | if (n != 0) | |
376 | n += k; | |
377 | n += strlen(*s); | |
378 | } | |
379 | ||
1fd8d04e LP |
380 | r = new(char, n+1); |
381 | if (!r) | |
5f9a22c3 LP |
382 | return NULL; |
383 | ||
384 | e = r; | |
385 | STRV_FOREACH(s, l) { | |
386 | if (e != r) | |
387 | e = stpcpy(e, separator); | |
388 | ||
389 | e = stpcpy(e, *s); | |
390 | } | |
391 | ||
8d49745c LP |
392 | *e = 0; |
393 | ||
5f9a22c3 LP |
394 | return r; |
395 | } | |
396 | ||
a6fde353 ZJS |
397 | char *strv_join_quoted(char **l) { |
398 | char *buf = NULL; | |
399 | char **s; | |
400 | size_t allocated = 0, len = 0; | |
401 | ||
402 | STRV_FOREACH(s, l) { | |
403 | /* assuming here that escaped string cannot be more | |
404 | * than twice as long, and reserving space for the | |
405 | * separator and quotes. | |
406 | */ | |
407 | _cleanup_free_ char *esc = NULL; | |
408 | size_t needed; | |
409 | ||
410 | if (!GREEDY_REALLOC(buf, allocated, | |
411 | len + strlen(*s) * 2 + 3)) | |
412 | goto oom; | |
413 | ||
414 | esc = cescape(*s); | |
415 | if (!esc) | |
416 | goto oom; | |
417 | ||
418 | needed = snprintf(buf + len, allocated - len, "%s\"%s\"", | |
419 | len > 0 ? " " : "", esc); | |
420 | assert(needed < allocated - len); | |
421 | len += needed; | |
422 | } | |
423 | ||
424 | if (!buf) | |
425 | buf = malloc0(1); | |
426 | ||
427 | return buf; | |
428 | ||
429 | oom: | |
430 | free(buf); | |
431 | return NULL; | |
432 | } | |
433 | ||
4468addc | 434 | int strv_push(char ***l, char *value) { |
5926ccca | 435 | char **c; |
97569e15 | 436 | unsigned n, m; |
5926ccca LP |
437 | |
438 | if (!value) | |
439 | return 0; | |
440 | ||
82dde599 | 441 | n = strv_length(*l); |
97569e15 | 442 | |
98940a3c | 443 | /* Increase and check for overflow */ |
97569e15 LP |
444 | m = n + 2; |
445 | if (m < n) | |
446 | return -ENOMEM; | |
447 | ||
14f27b4e | 448 | c = realloc_multiply(*l, sizeof(char*), m); |
4468addc | 449 | if (!c) |
82dde599 | 450 | return -ENOMEM; |
82dde599 | 451 | |
4468addc | 452 | c[n] = value; |
82dde599 LP |
453 | c[n+1] = NULL; |
454 | ||
5926ccca LP |
455 | *l = c; |
456 | return 0; | |
457 | } | |
458 | ||
98940a3c LP |
459 | int strv_push_pair(char ***l, char *a, char *b) { |
460 | char **c; | |
461 | unsigned n, m; | |
462 | ||
463 | if (!a && !b) | |
464 | return 0; | |
465 | ||
466 | n = strv_length(*l); | |
467 | ||
468 | /* increase and check for overflow */ | |
469 | m = n + !!a + !!b + 1; | |
470 | if (m < n) | |
471 | return -ENOMEM; | |
472 | ||
473 | c = realloc_multiply(*l, sizeof(char*), m); | |
474 | if (!c) | |
475 | return -ENOMEM; | |
476 | ||
477 | if (a) | |
478 | c[n++] = a; | |
479 | if (b) | |
480 | c[n++] = b; | |
481 | c[n] = NULL; | |
482 | ||
483 | *l = c; | |
484 | return 0; | |
485 | } | |
486 | ||
9a00f57a LP |
487 | int strv_push_prepend(char ***l, char *value) { |
488 | char **c; | |
97569e15 | 489 | unsigned n, m, i; |
9a00f57a LP |
490 | |
491 | if (!value) | |
492 | return 0; | |
493 | ||
494 | n = strv_length(*l); | |
97569e15 LP |
495 | |
496 | /* increase and check for overflow */ | |
497 | m = n + 2; | |
498 | if (m < n) | |
499 | return -ENOMEM; | |
500 | ||
501 | c = new(char*, m); | |
9a00f57a LP |
502 | if (!c) |
503 | return -ENOMEM; | |
504 | ||
505 | for (i = 0; i < n; i++) | |
506 | c[i+1] = (*l)[i]; | |
507 | ||
508 | c[0] = value; | |
509 | c[n+1] = NULL; | |
510 | ||
511 | free(*l); | |
512 | *l = c; | |
513 | ||
514 | return 0; | |
515 | } | |
516 | ||
6e18964d ZJS |
517 | int strv_consume(char ***l, char *value) { |
518 | int r; | |
519 | ||
520 | r = strv_push(l, value); | |
521 | if (r < 0) | |
522 | free(value); | |
523 | ||
9a00f57a LP |
524 | return r; |
525 | } | |
526 | ||
98940a3c LP |
527 | int strv_consume_pair(char ***l, char *a, char *b) { |
528 | int r; | |
529 | ||
530 | r = strv_push_pair(l, a, b); | |
531 | if (r < 0) { | |
532 | free(a); | |
533 | free(b); | |
534 | } | |
535 | ||
536 | return r; | |
537 | } | |
538 | ||
9a00f57a LP |
539 | int strv_consume_prepend(char ***l, char *value) { |
540 | int r; | |
541 | ||
542 | r = strv_push_prepend(l, value); | |
543 | if (r < 0) | |
544 | free(value); | |
545 | ||
6e18964d ZJS |
546 | return r; |
547 | } | |
548 | ||
4468addc LP |
549 | int strv_extend(char ***l, const char *value) { |
550 | char *v; | |
4468addc LP |
551 | |
552 | if (!value) | |
553 | return 0; | |
554 | ||
555 | v = strdup(value); | |
556 | if (!v) | |
557 | return -ENOMEM; | |
558 | ||
6e18964d | 559 | return strv_consume(l, v); |
4468addc LP |
560 | } |
561 | ||
5f9a22c3 | 562 | char **strv_uniq(char **l) { |
cba8922f LP |
563 | char **i; |
564 | ||
5f9a22c3 LP |
565 | /* Drops duplicate entries. The first identical string will be |
566 | * kept, the others dropped */ | |
567 | ||
cba8922f | 568 | STRV_FOREACH(i, l) |
5f9a22c3 LP |
569 | strv_remove(i+1, *i); |
570 | ||
571 | return l; | |
572 | } | |
573 | ||
e1dd6790 LP |
574 | bool strv_is_uniq(char **l) { |
575 | char **i; | |
576 | ||
577 | STRV_FOREACH(i, l) | |
578 | if (strv_find(i+1, *i)) | |
579 | return false; | |
580 | ||
581 | return true; | |
582 | } | |
583 | ||
5f9a22c3 LP |
584 | char **strv_remove(char **l, const char *s) { |
585 | char **f, **t; | |
586 | ||
587 | if (!l) | |
588 | return NULL; | |
589 | ||
5d6ab905 LP |
590 | assert(s); |
591 | ||
592 | /* Drops every occurrence of s in the string list, edits | |
593 | * in-place. */ | |
5f9a22c3 | 594 | |
e3e45d4f SP |
595 | for (f = t = l; *f; f++) |
596 | if (streq(*f, s)) | |
71ecc858 | 597 | free(*f); |
e3e45d4f SP |
598 | else |
599 | *(t++) = *f; | |
71ecc858 LP |
600 | |
601 | *t = NULL; | |
602 | return l; | |
603 | } | |
604 | ||
21bc923a LP |
605 | char **strv_parse_nulstr(const char *s, size_t l) { |
606 | const char *p; | |
607 | unsigned c = 0, i = 0; | |
608 | char **v; | |
609 | ||
610 | assert(s || l <= 0); | |
611 | ||
612 | if (l <= 0) | |
49b832c5 | 613 | return new0(char*, 1); |
21bc923a LP |
614 | |
615 | for (p = s; p < s + l; p++) | |
616 | if (*p == 0) | |
617 | c++; | |
618 | ||
619 | if (s[l-1] != 0) | |
620 | c++; | |
621 | ||
1fd8d04e LP |
622 | v = new0(char*, c+1); |
623 | if (!v) | |
21bc923a LP |
624 | return NULL; |
625 | ||
626 | p = s; | |
627 | while (p < s + l) { | |
628 | const char *e; | |
629 | ||
630 | e = memchr(p, 0, s + l - p); | |
631 | ||
1fd8d04e LP |
632 | v[i] = strndup(p, e ? e - p : s + l - p); |
633 | if (!v[i]) { | |
21bc923a LP |
634 | strv_free(v); |
635 | return NULL; | |
636 | } | |
637 | ||
1fd8d04e LP |
638 | i++; |
639 | ||
21bc923a LP |
640 | if (!e) |
641 | break; | |
642 | ||
643 | p = e + 1; | |
644 | } | |
645 | ||
646 | assert(i == c); | |
647 | ||
648 | return v; | |
649 | } | |
0c85a4f3 | 650 | |
fabe5c0e LP |
651 | char **strv_split_nulstr(const char *s) { |
652 | const char *i; | |
653 | char **r = NULL; | |
654 | ||
655 | NULSTR_FOREACH(i, s) | |
656 | if (strv_extend(&r, i) < 0) { | |
657 | strv_free(r); | |
658 | return NULL; | |
659 | } | |
660 | ||
661 | if (!r) | |
662 | return strv_new(NULL, NULL); | |
663 | ||
664 | return r; | |
665 | } | |
666 | ||
e287086b LP |
667 | int strv_make_nulstr(char **l, char **p, size_t *q) { |
668 | size_t n_allocated = 0, n = 0; | |
669 | _cleanup_free_ char *m = NULL; | |
670 | char **i; | |
671 | ||
672 | assert(p); | |
673 | assert(q); | |
674 | ||
675 | STRV_FOREACH(i, l) { | |
676 | size_t z; | |
677 | ||
678 | z = strlen(*i); | |
679 | ||
680 | if (!GREEDY_REALLOC(m, n_allocated, n + z + 1)) | |
681 | return -ENOMEM; | |
682 | ||
683 | memcpy(m + n, *i, z + 1); | |
684 | n += z + 1; | |
685 | } | |
686 | ||
687 | if (!m) { | |
688 | m = new0(char, 1); | |
689 | if (!m) | |
690 | return -ENOMEM; | |
691 | n = 0; | |
692 | } | |
693 | ||
694 | *p = m; | |
695 | *q = n; | |
696 | ||
697 | m = NULL; | |
698 | ||
699 | return 0; | |
700 | } | |
701 | ||
0c85a4f3 | 702 | bool strv_overlap(char **a, char **b) { |
e3e45d4f | 703 | char **i; |
0c85a4f3 | 704 | |
e3e45d4f SP |
705 | STRV_FOREACH(i, a) |
706 | if (strv_contains(b, *i)) | |
707 | return true; | |
0c85a4f3 LP |
708 | |
709 | return false; | |
710 | } | |
857a493d LP |
711 | |
712 | static int str_compare(const void *_a, const void *_b) { | |
713 | const char **a = (const char**) _a, **b = (const char**) _b; | |
714 | ||
715 | return strcmp(*a, *b); | |
716 | } | |
717 | ||
718 | char **strv_sort(char **l) { | |
719 | ||
720 | if (strv_isempty(l)) | |
721 | return l; | |
722 | ||
723 | qsort(l, strv_length(l), sizeof(char*), str_compare); | |
724 | return l; | |
725 | } | |
7c2d8094 | 726 | |
0f84a72e | 727 | bool strv_equal(char **a, char **b) { |
e287086b LP |
728 | |
729 | if (strv_isempty(a)) | |
730 | return strv_isempty(b); | |
731 | ||
732 | if (strv_isempty(b)) | |
733 | return false; | |
0f84a72e DH |
734 | |
735 | for ( ; *a || *b; ++a, ++b) | |
736 | if (!streq_ptr(*a, *b)) | |
737 | return false; | |
738 | ||
739 | return true; | |
740 | } | |
741 | ||
7c2d8094 TA |
742 | void strv_print(char **l) { |
743 | char **s; | |
744 | ||
7c2d8094 TA |
745 | STRV_FOREACH(s, l) |
746 | puts(*s); | |
747 | } | |
4de33e7f LP |
748 | |
749 | int strv_extendf(char ***l, const char *format, ...) { | |
750 | va_list ap; | |
751 | char *x; | |
752 | int r; | |
753 | ||
754 | va_start(ap, format); | |
755 | r = vasprintf(&x, format, ap); | |
756 | va_end(ap); | |
757 | ||
758 | if (r < 0) | |
759 | return -ENOMEM; | |
760 | ||
761 | return strv_consume(l, x); | |
762 | } | |
e1dd6790 LP |
763 | |
764 | char **strv_reverse(char **l) { | |
765 | unsigned n, i; | |
766 | ||
767 | n = strv_length(l); | |
768 | if (n <= 1) | |
769 | return l; | |
770 | ||
771 | for (i = 0; i < n / 2; i++) { | |
772 | char *t; | |
773 | ||
774 | t = l[i]; | |
775 | l[i] = l[n-1-i]; | |
776 | l[n-1-i] = t; | |
777 | } | |
778 | ||
779 | return l; | |
780 | } | |
bceccd5e | 781 | |
04c14b25 RM |
782 | char **strv_shell_escape(char **l, const char *bad) { |
783 | char **s; | |
784 | ||
785 | /* Escapes every character in every string in l that is in bad, | |
786 | * edits in-place, does not roll-back on error. */ | |
787 | ||
788 | STRV_FOREACH(s, l) { | |
789 | char *v; | |
790 | ||
791 | v = shell_escape(*s, bad); | |
792 | if (!v) | |
793 | return NULL; | |
794 | ||
795 | free(*s); | |
796 | *s = v; | |
797 | } | |
798 | ||
799 | return l; | |
800 | } | |
801 | ||
2404701e | 802 | bool strv_fnmatch(char* const* patterns, const char *s, int flags) { |
bceccd5e ZJS |
803 | char* const* p; |
804 | ||
805 | STRV_FOREACH(p, patterns) | |
806 | if (fnmatch(*p, s, 0) == 0) | |
807 | return true; | |
808 | ||
809 | return false; | |
810 | } | |
fe382237 LP |
811 | |
812 | char ***strv_free_free(char ***l) { | |
813 | char ***i; | |
814 | ||
815 | if (!l) | |
816 | return NULL; | |
817 | ||
818 | for (i = l; *i; i++) | |
819 | strv_free(*i); | |
820 | ||
821 | free(l); | |
822 | return NULL; | |
823 | } | |
e3ead6bb LP |
824 | |
825 | char **strv_skip(char **l, size_t n) { | |
826 | ||
827 | while (n > 0) { | |
828 | if (strv_isempty(l)) | |
829 | return l; | |
830 | ||
831 | l++, n--; | |
832 | } | |
833 | ||
834 | return l; | |
835 | } | |
8dd4c05b LP |
836 | |
837 | int strv_extend_n(char ***l, const char *value, size_t n) { | |
838 | size_t i, j, k; | |
839 | char **nl; | |
840 | ||
841 | assert(l); | |
842 | ||
843 | if (!value) | |
844 | return 0; | |
845 | if (n == 0) | |
846 | return 0; | |
847 | ||
848 | /* Adds the value value n times to l */ | |
849 | ||
850 | k = strv_length(*l); | |
851 | ||
852 | nl = realloc(*l, sizeof(char*) * (k + n + 1)); | |
853 | if (!nl) | |
854 | return -ENOMEM; | |
855 | ||
856 | *l = nl; | |
857 | ||
858 | for (i = k; i < k + n; i++) { | |
859 | nl[i] = strdup(value); | |
860 | if (!nl[i]) | |
861 | goto rollback; | |
862 | } | |
863 | ||
864 | nl[i] = NULL; | |
865 | return 0; | |
866 | ||
867 | rollback: | |
6fff8ac4 | 868 | for (j = k; j < i; j++) |
8dd4c05b LP |
869 | free(nl[j]); |
870 | ||
871 | nl[k] = NULL; | |
5b700370 | 872 | return -ENOMEM; |
8dd4c05b | 873 | } |
3df9bec5 LP |
874 | |
875 | int fputstrv(FILE *f, char **l, const char *separator, bool *space) { | |
876 | bool b = false; | |
877 | char **s; | |
878 | int r; | |
879 | ||
880 | /* Like fputs(), but for strv, and with a less stupid argument order */ | |
881 | ||
882 | if (!f) | |
883 | f = stdout; | |
884 | if (!separator) | |
885 | separator = " "; | |
886 | if (!space) | |
887 | space = &b; | |
888 | ||
889 | STRV_FOREACH(s, l) { | |
890 | if (*space) { | |
891 | r = fputs(separator, f); | |
892 | if (r < 0) | |
893 | return r; | |
894 | } | |
895 | ||
896 | r = fputs(*s, f); | |
897 | if (r < 0) | |
898 | return r; | |
899 | ||
900 | *space = true; | |
901 | } | |
902 | ||
903 | return 0; | |
904 | } |