]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/strv.c
strv: cleanup error path loops
[thirdparty/systemd.git] / src / shared / strv.c
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
55 void strv_free(char **l) {
56 char **k;
57
58 if (!l)
59 return;
60
61 for (k = l; *k; k++)
62 free(*k);
63
64 free(l);
65 }
66
67 void strv_freep(char ***l) {
68 if (!l)
69 return;
70
71 strv_free(*l);
72 *l = NULL;
73 }
74
75 char **strv_copy(char **l) {
76 char **r, **k;
77
78 k = r = new(char*, strv_length(l) + 1);
79 if (!r)
80 return NULL;
81
82 if (l)
83 for (; *l; k++, l++) {
84 *k = strdup(*l);
85 if (!*k) {
86 strv_free(r);
87 return NULL;
88 }
89 }
90
91 *k = NULL;
92 return r;
93 }
94
95 unsigned strv_length(char **l) {
96 unsigned n = 0;
97
98 if (!l)
99 return 0;
100
101 for (; *l; l++)
102 n++;
103
104 return n;
105 }
106
107 char **strv_new_ap(const char *x, va_list ap) {
108 const char *s;
109 char **a;
110 unsigned n = 0, i = 0;
111 va_list aq;
112
113 /* As a special trick we ignore all listed strings that equal
114 * (const char*) -1. This is supposed to be used with the
115 * STRV_IFNOTNULL() macro to include possibly NULL strings in
116 * the string list. */
117
118 if (x) {
119 n = x == (const char*) -1 ? 0 : 1;
120
121 va_copy(aq, ap);
122 while ((s = va_arg(aq, const char*))) {
123 if (s == (const char*) -1)
124 continue;
125
126 n++;
127 }
128
129 va_end(aq);
130 }
131
132 a = new(char*, n+1);
133 if (!a)
134 return NULL;
135
136 if (x) {
137 if (x != (const char*) -1) {
138 a[i] = strdup(x);
139 if (!a[i])
140 goto fail;
141 i++;
142 }
143
144 while ((s = va_arg(ap, const char*))) {
145
146 if (s == (const char*) -1)
147 continue;
148
149 a[i] = strdup(s);
150 if (!a[i])
151 goto fail;
152
153 i++;
154 }
155 }
156
157 a[i] = NULL;
158
159 return a;
160
161 fail:
162 strv_free(a);
163 return NULL;
164 }
165
166 char **strv_new(const char *x, ...) {
167 char **r;
168 va_list ap;
169
170 va_start(ap, x);
171 r = strv_new_ap(x, ap);
172 va_end(ap);
173
174 return r;
175 }
176
177 char **strv_merge(char **a, char **b) {
178 char **r, **k;
179
180 if (!a)
181 return strv_copy(b);
182
183 if (!b)
184 return strv_copy(a);
185
186 r = new(char*, strv_length(a) + strv_length(b) + 1);
187 if (!r)
188 return NULL;
189
190 for (k = r; *a; k++, a++) {
191 *k = strdup(*a);
192 if (!*k)
193 goto fail;
194 }
195
196 for (; *b; k++, b++) {
197 *k = strdup(*b);
198 if (!*k)
199 goto fail;
200 }
201
202 *k = NULL;
203 return r;
204
205 fail:
206 strv_free(r);
207 return NULL;
208 }
209
210 char **strv_merge_concat(char **a, char **b, const char *suffix) {
211 char **r, **k;
212
213 /* Like strv_merge(), but appends suffix to all strings in b, before adding */
214
215 if (!b)
216 return strv_copy(a);
217
218 r = new(char*, strv_length(a) + strv_length(b) + 1);
219 if (!r)
220 return NULL;
221
222 k = r;
223 if (a)
224 for (; *a; k++, a++) {
225 *k = strdup(*a);
226 if (!*k)
227 goto fail;
228 }
229
230 for (; *b; k++, b++) {
231 *k = strappend(*b, suffix);
232 if (!*k)
233 goto fail;
234 }
235
236 *k = NULL;
237 return r;
238
239 fail:
240 strv_free(r);
241 return NULL;
242
243 }
244
245 char **strv_split(const char *s, const char *separator) {
246 char *state;
247 char *w;
248 size_t l;
249 unsigned n, i;
250 char **r;
251
252 assert(s);
253
254 n = 0;
255 FOREACH_WORD_SEPARATOR(w, l, s, separator, state)
256 n++;
257
258 r = new(char*, n+1);
259 if (!r)
260 return NULL;
261
262 i = 0;
263 FOREACH_WORD_SEPARATOR(w, l, s, separator, state) {
264 r[i] = strndup(w, l);
265 if (!r[i]) {
266 strv_free(r);
267 return NULL;
268 }
269
270 i++;
271 }
272
273 r[i] = NULL;
274 return r;
275 }
276
277 char **strv_split_quoted(const char *s) {
278 char *state;
279 char *w;
280 size_t l;
281 unsigned n, i;
282 char **r;
283
284 assert(s);
285
286 n = 0;
287 FOREACH_WORD_QUOTED(w, l, s, state)
288 n++;
289
290 r = new(char*, n+1);
291 if (!r)
292 return NULL;
293
294 i = 0;
295 FOREACH_WORD_QUOTED(w, l, s, state) {
296 r[i] = cunescape_length(w, l);
297 if (!r[i]) {
298 strv_free(r);
299 return NULL;
300 }
301 i++;
302 }
303
304 r[i] = NULL;
305 return r;
306 }
307
308 char *strv_join(char **l, const char *separator) {
309 char *r, *e;
310 char **s;
311 size_t n, k;
312
313 if (!separator)
314 separator = " ";
315
316 k = strlen(separator);
317
318 n = 0;
319 STRV_FOREACH(s, l) {
320 if (n != 0)
321 n += k;
322 n += strlen(*s);
323 }
324
325 r = new(char, n+1);
326 if (!r)
327 return NULL;
328
329 e = r;
330 STRV_FOREACH(s, l) {
331 if (e != r)
332 e = stpcpy(e, separator);
333
334 e = stpcpy(e, *s);
335 }
336
337 *e = 0;
338
339 return r;
340 }
341
342 char **strv_append(char **l, const char *s) {
343 char **r, **k;
344
345 if (!l)
346 return strv_new(s, NULL);
347
348 if (!s)
349 return strv_copy(l);
350
351 r = new(char*, strv_length(l)+2);
352 if (!r)
353 return NULL;
354
355 for (k = r; *l; k++, l++) {
356 *k = strdup(*l);
357 if (!*k)
358 goto fail;
359 }
360
361 k[0] = strdup(s);
362 if (!k[0])
363 goto fail;
364
365 k[1] = NULL;
366 return r;
367
368 fail:
369 strv_free(r);
370 return NULL;
371 }
372
373 char **strv_uniq(char **l) {
374 char **i;
375
376 /* Drops duplicate entries. The first identical string will be
377 * kept, the others dropped */
378
379 STRV_FOREACH(i, l)
380 strv_remove(i+1, *i);
381
382 return l;
383 }
384
385 char **strv_remove(char **l, const char *s) {
386 char **f, **t;
387
388 if (!l)
389 return NULL;
390
391 assert(s);
392
393 /* Drops every occurrence of s in the string list, edits
394 * in-place. */
395
396 for (f = t = l; *f; f++) {
397
398 if (streq(*f, s)) {
399 free(*f);
400 continue;
401 }
402
403 *(t++) = *f;
404 }
405
406 *t = NULL;
407 return l;
408 }
409
410 char **strv_remove_prefix(char **l, const char *s) {
411 char **f, **t;
412
413 if (!l)
414 return NULL;
415
416 assert(s);
417
418 /* Drops every occurrence of a string prefixed with s in the
419 * string list, edits in-place. */
420
421 for (f = t = l; *f; f++) {
422
423 if (startswith(*f, s)) {
424 free(*f);
425 continue;
426 }
427
428 *(t++) = *f;
429 }
430
431 *t = NULL;
432 return l;
433 }
434
435 static int env_append(char **r, char ***k, char **a) {
436 assert(r);
437 assert(k);
438
439 if (!a)
440 return 0;
441
442 /* Add the entries of a to *k unless they already exist in *r
443 * in which case they are overridden instead. This assumes
444 * there is enough space in the r array. */
445
446 for (; *a; a++) {
447 char **j;
448 size_t n;
449
450 n = strcspn(*a, "=");
451
452 if ((*a)[n] == '=')
453 n++;
454
455 for (j = r; j < *k; j++)
456 if (strncmp(*j, *a, n) == 0)
457 break;
458
459 if (j >= *k)
460 (*k)++;
461 else
462 free(*j);
463
464 *j = strdup(*a);
465 if (!*j)
466 return -ENOMEM;
467 }
468
469 return 0;
470 }
471
472 char **strv_env_merge(unsigned n_lists, ...) {
473 size_t n = 0;
474 char **l, **k, **r;
475 va_list ap;
476 unsigned i;
477
478 /* Merges an arbitrary number of environment sets */
479
480 va_start(ap, n_lists);
481 for (i = 0; i < n_lists; i++) {
482 l = va_arg(ap, char**);
483 n += strv_length(l);
484 }
485 va_end(ap);
486
487 r = new(char*, n+1);
488 if (!r)
489 return NULL;
490
491 k = r;
492
493 va_start(ap, n_lists);
494 for (i = 0; i < n_lists; i++) {
495 l = va_arg(ap, char**);
496 if (env_append(r, &k, l) < 0)
497 goto fail;
498 }
499 va_end(ap);
500
501 *k = NULL;
502
503 return r;
504
505 fail:
506 va_end(ap);
507 strv_free(r);
508
509 return NULL;
510 }
511
512 static bool env_match(const char *t, const char *pattern) {
513 assert(t);
514 assert(pattern);
515
516 /* pattern a matches string a
517 * a matches a=
518 * a matches a=b
519 * a= matches a=
520 * a=b matches a=b
521 * a= does not match a
522 * a=b does not match a=
523 * a=b does not match a
524 * a=b does not match a=c */
525
526 if (streq(t, pattern))
527 return true;
528
529 if (!strchr(pattern, '=')) {
530 size_t l = strlen(pattern);
531
532 return strncmp(t, pattern, l) == 0 && t[l] == '=';
533 }
534
535 return false;
536 }
537
538 char **strv_env_delete(char **x, unsigned n_lists, ...) {
539 size_t n, i = 0;
540 char **k, **r;
541 va_list ap;
542
543 /* Deletes every entry from x that is mentioned in the other
544 * string lists */
545
546 n = strv_length(x);
547
548 r = new(char*, n+1);
549 if (!r)
550 return NULL;
551
552 STRV_FOREACH(k, x) {
553 unsigned v;
554
555 va_start(ap, n_lists);
556 for (v = 0; v < n_lists; v++) {
557 char **l, **j;
558
559 l = va_arg(ap, char**);
560 STRV_FOREACH(j, l)
561 if (env_match(*k, *j))
562 goto skip;
563 }
564 va_end(ap);
565
566 r[i] = strdup(*k);
567 if (!r[i]) {
568 strv_free(r);
569 return NULL;
570 }
571
572 i++;
573 continue;
574
575 skip:
576 va_end(ap);
577 }
578
579 r[i] = NULL;
580
581 assert(i <= n);
582
583 return r;
584 }
585
586 char **strv_env_unset(char **l, const char *p) {
587
588 char **f, **t;
589
590 if (!l)
591 return NULL;
592
593 assert(p);
594
595 /* Drops every occurrence of the env var setting p in the
596 * string list. edits in-place. */
597
598 for (f = t = l; *f; f++) {
599
600 if (env_match(*f, p)) {
601 free(*f);
602 continue;
603 }
604
605 *(t++) = *f;
606 }
607
608 *t = NULL;
609 return l;
610 }
611
612 char **strv_env_set(char **x, const char *p) {
613
614 char **k, **r;
615 char* m[2] = { (char*) p, NULL };
616
617 /* Overrides the env var setting of p, returns a new copy */
618
619 r = new(char*, strv_length(x)+2);
620 if (!r)
621 return NULL;
622
623 k = r;
624 if (env_append(r, &k, x) < 0)
625 goto fail;
626
627 if (env_append(r, &k, m) < 0)
628 goto fail;
629
630 *k = NULL;
631
632 return r;
633
634 fail:
635 strv_free(r);
636 return NULL;
637
638 }
639
640 char *strv_env_get_with_length(char **l, const char *name, size_t k) {
641 char **i;
642
643 assert(name);
644
645 STRV_FOREACH(i, l)
646 if (strncmp(*i, name, k) == 0 &&
647 (*i)[k] == '=')
648 return *i + k + 1;
649
650 return NULL;
651 }
652
653 char *strv_env_get(char **l, const char *name) {
654 return strv_env_get_with_length(l, name, strlen(name));
655 }
656
657 char **strv_env_clean(char **l) {
658 char **r, **ret;
659
660 for (r = ret = l; *l; l++) {
661 const char *equal;
662
663 equal = strchr(*l, '=');
664
665 if (equal && equal[1] == 0) {
666 free(*l);
667 continue;
668 }
669
670 *(r++) = *l;
671 }
672
673 *r = NULL;
674
675 return ret;
676 }
677
678 char **strv_parse_nulstr(const char *s, size_t l) {
679 const char *p;
680 unsigned c = 0, i = 0;
681 char **v;
682
683 assert(s || l <= 0);
684
685 if (l <= 0)
686 return strv_new(NULL, NULL);
687
688 for (p = s; p < s + l; p++)
689 if (*p == 0)
690 c++;
691
692 if (s[l-1] != 0)
693 c++;
694
695 v = new0(char*, c+1);
696 if (!v)
697 return NULL;
698
699 p = s;
700 while (p < s + l) {
701 const char *e;
702
703 e = memchr(p, 0, s + l - p);
704
705 v[i] = strndup(p, e ? e - p : s + l - p);
706 if (!v[i]) {
707 strv_free(v);
708 return NULL;
709 }
710
711 i++;
712
713 if (!e)
714 break;
715
716 p = e + 1;
717 }
718
719 assert(i == c);
720
721 return v;
722 }
723
724 bool strv_overlap(char **a, char **b) {
725 char **i, **j;
726
727 STRV_FOREACH(i, a) {
728 STRV_FOREACH(j, b) {
729 if (streq(*i, *j))
730 return true;
731 }
732 }
733
734 return false;
735 }
736
737 static int str_compare(const void *_a, const void *_b) {
738 const char **a = (const char**) _a, **b = (const char**) _b;
739
740 return strcmp(*a, *b);
741 }
742
743 char **strv_sort(char **l) {
744
745 if (strv_isempty(l))
746 return l;
747
748 qsort(l, strv_length(l), sizeof(char*), str_compare);
749 return l;
750 }