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