]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/strv.c
binfmt,tmpfiles,modules-load,sysctl: rework the various early-boot services that...
[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 int strv_extend(char ***l, const char *value) {
374 char **c;
375 char *v;
376 unsigned n;
377
378 if (!value)
379 return 0;
380
381 v = strdup(value);
382 if (!v)
383 return -ENOMEM;
384
385 n = strv_length(*l);
386 c = realloc(*l, sizeof(char*) * (n + 2));
387 if (!c) {
388 free(v);
389 return -ENOMEM;
390 }
391
392 c[n] = v;
393 c[n+1] = NULL;
394
395 *l = c;
396 return 0;
397 }
398
399 char **strv_uniq(char **l) {
400 char **i;
401
402 /* Drops duplicate entries. The first identical string will be
403 * kept, the others dropped */
404
405 STRV_FOREACH(i, l)
406 strv_remove(i+1, *i);
407
408 return l;
409 }
410
411 char **strv_remove(char **l, const char *s) {
412 char **f, **t;
413
414 if (!l)
415 return NULL;
416
417 assert(s);
418
419 /* Drops every occurrence of s in the string list, edits
420 * in-place. */
421
422 for (f = t = l; *f; f++) {
423
424 if (streq(*f, s)) {
425 free(*f);
426 continue;
427 }
428
429 *(t++) = *f;
430 }
431
432 *t = NULL;
433 return l;
434 }
435
436 char **strv_remove_prefix(char **l, const char *s) {
437 char **f, **t;
438
439 if (!l)
440 return NULL;
441
442 assert(s);
443
444 /* Drops every occurrence of a string prefixed with s in the
445 * string list, edits in-place. */
446
447 for (f = t = l; *f; f++) {
448
449 if (startswith(*f, s)) {
450 free(*f);
451 continue;
452 }
453
454 *(t++) = *f;
455 }
456
457 *t = NULL;
458 return l;
459 }
460
461 char **strv_parse_nulstr(const char *s, size_t l) {
462 const char *p;
463 unsigned c = 0, i = 0;
464 char **v;
465
466 assert(s || l <= 0);
467
468 if (l <= 0)
469 return strv_new(NULL, NULL);
470
471 for (p = s; p < s + l; p++)
472 if (*p == 0)
473 c++;
474
475 if (s[l-1] != 0)
476 c++;
477
478 v = new0(char*, c+1);
479 if (!v)
480 return NULL;
481
482 p = s;
483 while (p < s + l) {
484 const char *e;
485
486 e = memchr(p, 0, s + l - p);
487
488 v[i] = strndup(p, e ? e - p : s + l - p);
489 if (!v[i]) {
490 strv_free(v);
491 return NULL;
492 }
493
494 i++;
495
496 if (!e)
497 break;
498
499 p = e + 1;
500 }
501
502 assert(i == c);
503
504 return v;
505 }
506
507 char **strv_split_nulstr(const char *s) {
508 const char *i;
509 char **r = NULL;
510
511 NULSTR_FOREACH(i, s)
512 if (strv_extend(&r, i) < 0) {
513 strv_free(r);
514 return NULL;
515 }
516
517 if (!r)
518 return strv_new(NULL, NULL);
519
520 return r;
521 }
522
523 bool strv_overlap(char **a, char **b) {
524 char **i, **j;
525
526 STRV_FOREACH(i, a) {
527 STRV_FOREACH(j, b) {
528 if (streq(*i, *j))
529 return true;
530 }
531 }
532
533 return false;
534 }
535
536 static int str_compare(const void *_a, const void *_b) {
537 const char **a = (const char**) _a, **b = (const char**) _b;
538
539 return strcmp(*a, *b);
540 }
541
542 char **strv_sort(char **l) {
543
544 if (strv_isempty(l))
545 return l;
546
547 qsort(l, strv_length(l), sizeof(char*), str_compare);
548 return l;
549 }
550
551 void strv_print(char **l) {
552 char **s;
553
554 if (!l)
555 return;
556
557 STRV_FOREACH(s, l)
558 puts(*s);
559 }