]> git.ipfire.org Git - thirdparty/dracut.git/blob - install/strv.c
dracut-install: Globbing support for resolving "firmware:"
[thirdparty/dracut.git] / install / strv.c
1 /***
2 This file is part of systemd.
3
4 Copyright 2010 Lennart Poettering
5
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
10
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
18 ***/
19
20 #include <assert.h>
21 #include <stdlib.h>
22 #include <stdarg.h>
23 #include <string.h>
24 #include <errno.h>
25
26 #include "util.h"
27 #include "strv.h"
28
29 char *strv_find(char **l, const char *name) {
30 char **i;
31
32 assert(name);
33
34 STRV_FOREACH(i, l)
35 if (streq(*i, name))
36 return *i;
37
38 return NULL;
39 }
40
41 char *strv_find_prefix(char **l, const char *name) {
42 char **i;
43
44 assert(name);
45
46 STRV_FOREACH(i, l)
47 if (startswith(*i, name))
48 return *i;
49
50 return NULL;
51 }
52
53 void strv_free(char **l) {
54 char **k;
55
56 if (!l)
57 return;
58
59 for (k = l; *k; k++)
60 free(*k);
61
62 free(l);
63 }
64
65 char **strv_copy(char * const *l) {
66 char **r, **k;
67
68 k = r = new(char*, strv_length(l) + 1);
69 if (!r)
70 return NULL;
71
72 if (l)
73 for (; *l; k++, l++) {
74 *k = strdup(*l);
75 if (!*k) {
76 strv_free(r);
77 return NULL;
78 }
79 }
80
81 *k = NULL;
82 return r;
83 }
84
85 unsigned int strv_length(char * const *l) {
86 unsigned n = 0;
87
88 if (!l)
89 return 0;
90
91 for (; *l; l++)
92 n++;
93
94 return n;
95 }
96
97 char **strv_new_ap(const char *x, va_list ap) {
98 const char *s;
99 char **a;
100 unsigned n = 0, i = 0;
101 va_list aq;
102
103 /* As a special trick we ignore all listed strings that equal
104 * (const char*) -1. This is supposed to be used with the
105 * STRV_IFNOTNULL() macro to include possibly NULL strings in
106 * the string list. */
107
108 if (x) {
109 n = x == (const char*) -1 ? 0 : 1;
110
111 va_copy(aq, ap);
112 while ((s = va_arg(aq, const char*))) {
113 if (s == (const char*) -1)
114 continue;
115
116 n++;
117 }
118
119 va_end(aq);
120 }
121
122 a = new(char*, n+1);
123 if (!a)
124 return NULL;
125
126 if (x) {
127 if (x != (const char*) -1) {
128 a[i] = strdup(x);
129 if (!a[i])
130 goto fail;
131 i++;
132 }
133
134 while ((s = va_arg(ap, const char*))) {
135
136 if (s == (const char*) -1)
137 continue;
138
139 a[i] = strdup(s);
140 if (!a[i])
141 goto fail;
142
143 i++;
144 }
145 }
146
147 a[i] = NULL;
148
149 return a;
150
151 fail:
152 strv_free(a);
153 return NULL;
154 }
155
156 char **strv_new(const char *x, ...) {
157 char **r;
158 va_list ap;
159
160 va_start(ap, x);
161 r = strv_new_ap(x, ap);
162 va_end(ap);
163
164 return r;
165 }
166
167 char **strv_merge(char **a, char **b) {
168 char **r, **k;
169
170 if (!a)
171 return strv_copy(b);
172
173 if (!b)
174 return strv_copy(a);
175
176 r = new(char*, strv_length(a) + strv_length(b) + 1);
177 if (!r)
178 return NULL;
179
180 for (k = r; *a; k++, a++) {
181 *k = strdup(*a);
182 if (!*k)
183 goto fail;
184 }
185
186 for (; *b; k++, b++) {
187 *k = strdup(*b);
188 if (!*k)
189 goto fail;
190 }
191
192 *k = NULL;
193 return r;
194
195 fail:
196 strv_free(r);
197 return NULL;
198 }
199
200 char **strv_merge_concat(char **a, char **b, const char *suffix) {
201 char **r, **k;
202
203 /* Like strv_merge(), but appends suffix to all strings in b, before adding */
204
205 if (!b)
206 return strv_copy(a);
207
208 r = new(char*, strv_length(a) + strv_length(b) + 1);
209 if (!r)
210 return NULL;
211
212 k = r;
213 if (a)
214 for (; *a; k++, a++) {
215 *k = strdup(*a);
216 if (!*k)
217 goto fail;
218 }
219
220 for (; *b; k++, b++) {
221 *k = strappend(*b, suffix);
222 if (!*k)
223 goto fail;
224 }
225
226 *k = NULL;
227 return r;
228
229 fail:
230 strv_free(r);
231 return NULL;
232
233 }
234
235 char **strv_split(const char *s, const char *separator) {
236 char *state;
237 char *w;
238 size_t l;
239 unsigned n, i;
240 char **r;
241
242 assert(s);
243
244 n = 0;
245 FOREACH_WORD_SEPARATOR(w, l, s, separator, state)
246 n++;
247
248 r = new(char*, n+1);
249 if (!r)
250 return NULL;
251
252 i = 0;
253 FOREACH_WORD_SEPARATOR(w, l, s, separator, state) {
254 r[i] = strndup(w, l);
255 if (!r[i]) {
256 strv_free(r);
257 return NULL;
258 }
259
260 i++;
261 }
262
263 r[i] = NULL;
264 return r;
265 }
266
267 char **strv_split_quoted(const char *s) {
268 char *state;
269 char *w;
270 size_t l;
271 unsigned n, i;
272 char **r;
273
274 assert(s);
275
276 n = 0;
277 FOREACH_WORD_QUOTED(w, l, s, state)
278 n++;
279
280 r = new(char*, n+1);
281 if (!r)
282 return NULL;
283
284 i = 0;
285 FOREACH_WORD_QUOTED(w, l, s, state) {
286 r[i] = cunescape_length(w, l);
287 if (!r[i]) {
288 strv_free(r);
289 return NULL;
290 }
291 i++;
292 }
293
294 r[i] = NULL;
295 return r;
296 }
297
298 char **strv_split_newlines(const char *s) {
299 char **l;
300 unsigned int n;
301
302 assert(s);
303
304 /* Special version of strv_split() that splits on newlines and
305 * suppresses an empty string at the end */
306
307 l = strv_split(s, NEWLINE);
308 if (!l)
309 return NULL;
310
311 n = strv_length(l);
312 if (n == 0)
313 return l;
314
315 if (isempty(l[n-1])) {
316 free(l[n-1]);
317 l[n-1] = NULL;
318 }
319
320 return l;
321 }
322
323 char *strv_join(char **l, const char *separator) {
324 char *r, *e;
325 char **s;
326 size_t n, k;
327
328 if (!separator)
329 separator = " ";
330
331 k = strlen(separator);
332
333 n = 0;
334 STRV_FOREACH(s, l) {
335 if (n != 0)
336 n += k;
337 n += strlen(*s);
338 }
339
340 r = new(char, n+1);
341 if (!r)
342 return NULL;
343
344 e = r;
345 STRV_FOREACH(s, l) {
346 if (e != r)
347 e = stpcpy(e, separator);
348
349 e = stpcpy(e, *s);
350 }
351
352 *e = 0;
353
354 return r;
355 }
356
357 char **strv_append(char **l, const char *s) {
358 char **r, **k;
359
360 if (!l)
361 return strv_new(s, NULL);
362
363 if (!s)
364 return strv_copy(l);
365
366 r = new(char*, strv_length(l)+2);
367 if (!r)
368 return NULL;
369
370 for (k = r; *l; k++, l++) {
371 *k = strdup(*l);
372 if (!*k)
373 goto fail;
374 }
375
376 k[0] = strdup(s);
377 if (!k[0])
378 goto fail;
379
380 k[1] = NULL;
381 return r;
382
383 fail:
384 strv_free(r);
385 return NULL;
386 }
387
388 int strv_push(char ***l, char *value) {
389 char **c;
390 unsigned n;
391
392 if (!value)
393 return 0;
394
395 n = strv_length(*l);
396 c = realloc(*l, sizeof(char*) * (n + 2));
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
407 int strv_extend(char ***l, const char *value) {
408 char *v;
409 int r;
410
411 if (!value)
412 return 0;
413
414 v = strdup(value);
415 if (!v)
416 return -ENOMEM;
417
418 r = strv_push(l, v);
419 if (r < 0)
420 free(v);
421
422 return r;
423 }
424
425 char **strv_uniq(char **l) {
426 char **i;
427
428 /* Drops duplicate entries. The first identical string will be
429 * kept, the others dropped */
430
431 STRV_FOREACH(i, l)
432 strv_remove(i+1, *i);
433
434 return l;
435 }
436
437 char **strv_remove(char **l, const char *s) {
438 char **f, **t;
439
440 if (!l)
441 return NULL;
442
443 assert(s);
444
445 /* Drops every occurrence of s in the string list, edits
446 * in-place. */
447
448 for (f = t = l; *f; f++) {
449
450 if (streq(*f, s)) {
451 free(*f);
452 continue;
453 }
454
455 *(t++) = *f;
456 }
457
458 *t = NULL;
459 return l;
460 }
461
462 char **strv_remove_prefix(char **l, const char *s) {
463 char **f, **t;
464
465 if (!l)
466 return NULL;
467
468 assert(s);
469
470 /* Drops every occurrence of a string prefixed with s in the
471 * string list, edits in-place. */
472
473 for (f = t = l; *f; f++) {
474
475 if (startswith(*f, s)) {
476 free(*f);
477 continue;
478 }
479
480 *(t++) = *f;
481 }
482
483 *t = NULL;
484 return l;
485 }
486
487 char **strv_parse_nulstr(const char *s, size_t l) {
488 const char *p;
489 unsigned c = 0, i = 0;
490 char **v;
491
492 assert(s || l == 0);
493
494 if (l == 0)
495 return new0(char*, 1);
496
497 for (p = s; p < s + l; p++)
498 if (*p == 0)
499 c++;
500
501 if (s[l-1] != 0)
502 c++;
503
504 v = new0(char*, c+1);
505 if (!v)
506 return NULL;
507
508 p = s;
509 while (p < s + l) {
510 const char *e;
511
512 e = memchr(p, 0, s + l - p);
513
514 v[i] = strndup(p, e ? e - p : s + l - p);
515 if (!v[i]) {
516 strv_free(v);
517 return NULL;
518 }
519
520 i++;
521
522 if (!e)
523 break;
524
525 p = e + 1;
526 }
527
528 assert(i == c);
529
530 return v;
531 }
532
533 char **strv_split_nulstr(const char *s) {
534 const char *i;
535 char **r = NULL;
536
537 NULSTR_FOREACH(i, s)
538 if (strv_extend(&r, i) < 0) {
539 strv_free(r);
540 return NULL;
541 }
542
543 if (!r)
544 return strv_new(NULL, NULL);
545
546 return r;
547 }
548
549 bool strv_overlap(char **a, char **b) {
550 char **i, **j;
551
552 STRV_FOREACH(i, a) {
553 STRV_FOREACH(j, b) {
554 if (streq(*i, *j))
555 return true;
556 }
557 }
558
559 return false;
560 }
561
562 static int str_compare(const void *_a, const void *_b) {
563 const char **a = (const char**) _a, **b = (const char**) _b;
564
565 return strcmp(*a, *b);
566 }
567
568 char **strv_sort(char **l) {
569
570 if (strv_isempty(l))
571 return l;
572
573 qsort(l, strv_length(l), sizeof(char*), str_compare);
574 return l;
575 }
576
577 void strv_print(char **l) {
578 char **s;
579
580 if (!l)
581 return;
582
583 STRV_FOREACH(s, l)
584 puts(*s);
585 }