]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/strv.c
man: document ARM root partition types
[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 * const *l) {
68 char **r, **k;
69
70 k = r = new(char*, strv_length(l) + 1);
71 if (!r)
72 return NULL;
73
74 if (l)
75 for (; *l; k++, l++) {
76 *k = strdup(*l);
77 if (!*k) {
78 strv_free(r);
79 return NULL;
80 }
81 }
82
83 *k = NULL;
84 return r;
85 }
86
87 unsigned strv_length(char * const *l) {
88 unsigned n = 0;
89
90 if (!l)
91 return 0;
92
93 for (; *l; l++)
94 n++;
95
96 return n;
97 }
98
99 char **strv_new_ap(const char *x, va_list ap) {
100 const char *s;
101 char **a;
102 unsigned n = 0, i = 0;
103 va_list aq;
104
105 /* As a special trick we ignore all listed strings that equal
106 * (const char*) -1. This is supposed to be used with the
107 * STRV_IFNOTNULL() macro to include possibly NULL strings in
108 * the string list. */
109
110 if (x) {
111 n = x == (const char*) -1 ? 0 : 1;
112
113 va_copy(aq, ap);
114 while ((s = va_arg(aq, const char*))) {
115 if (s == (const char*) -1)
116 continue;
117
118 n++;
119 }
120
121 va_end(aq);
122 }
123
124 a = new(char*, n+1);
125 if (!a)
126 return NULL;
127
128 if (x) {
129 if (x != (const char*) -1) {
130 a[i] = strdup(x);
131 if (!a[i])
132 goto fail;
133 i++;
134 }
135
136 while ((s = va_arg(ap, const char*))) {
137
138 if (s == (const char*) -1)
139 continue;
140
141 a[i] = strdup(s);
142 if (!a[i])
143 goto fail;
144
145 i++;
146 }
147 }
148
149 a[i] = NULL;
150
151 return a;
152
153 fail:
154 strv_free(a);
155 return NULL;
156 }
157
158 char **strv_new(const char *x, ...) {
159 char **r;
160 va_list ap;
161
162 va_start(ap, x);
163 r = strv_new_ap(x, ap);
164 va_end(ap);
165
166 return r;
167 }
168
169 int strv_extend_strv(char ***a, char **b) {
170 int r;
171 char **s;
172
173 STRV_FOREACH(s, b) {
174 r = strv_extend(a, *s);
175 if (r < 0)
176 return r;
177 }
178
179 return 0;
180 }
181
182 int strv_extend_strv_concat(char ***a, char **b, const char *suffix) {
183 int r;
184 char **s;
185
186 STRV_FOREACH(s, b) {
187 char *v;
188
189 v = strappend(*s, suffix);
190 if (!v)
191 return -ENOMEM;
192
193 r = strv_push(a, v);
194 if (r < 0) {
195 free(v);
196 return r;
197 }
198 }
199
200 return 0;
201 }
202
203 char **strv_split(const char *s, const char *separator) {
204 char *state;
205 char *w;
206 size_t l;
207 unsigned n, i;
208 char **r;
209
210 assert(s);
211
212 n = 0;
213 FOREACH_WORD_SEPARATOR(w, l, s, separator, state)
214 n++;
215
216 r = new(char*, n+1);
217 if (!r)
218 return NULL;
219
220 i = 0;
221 FOREACH_WORD_SEPARATOR(w, l, s, separator, state) {
222 r[i] = strndup(w, l);
223 if (!r[i]) {
224 strv_free(r);
225 return NULL;
226 }
227
228 i++;
229 }
230
231 r[i] = NULL;
232 return r;
233 }
234
235 char **strv_split_quoted(const char *s) {
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_QUOTED(w, l, s, state)
246 n++;
247
248 r = new(char*, n+1);
249 if (!r)
250 return NULL;
251
252 i = 0;
253 FOREACH_WORD_QUOTED(w, l, s, state) {
254 r[i] = cunescape_length(w, l);
255 if (!r[i]) {
256 strv_free(r);
257 return NULL;
258 }
259 i++;
260 }
261
262 r[i] = NULL;
263 return r;
264 }
265
266 char **strv_split_newlines(const char *s) {
267 char **l;
268 unsigned n;
269
270 assert(s);
271
272 /* Special version of strv_split() that splits on newlines and
273 * suppresses an empty string at the end */
274
275 l = strv_split(s, NEWLINE);
276 if (!l)
277 return NULL;
278
279 n = strv_length(l);
280 if (n <= 0)
281 return l;
282
283 if (isempty(l[n-1])) {
284 free(l[n-1]);
285 l[n-1] = NULL;
286 }
287
288 return l;
289 }
290
291 char *strv_join(char **l, const char *separator) {
292 char *r, *e;
293 char **s;
294 size_t n, k;
295
296 if (!separator)
297 separator = " ";
298
299 k = strlen(separator);
300
301 n = 0;
302 STRV_FOREACH(s, l) {
303 if (n != 0)
304 n += k;
305 n += strlen(*s);
306 }
307
308 r = new(char, n+1);
309 if (!r)
310 return NULL;
311
312 e = r;
313 STRV_FOREACH(s, l) {
314 if (e != r)
315 e = stpcpy(e, separator);
316
317 e = stpcpy(e, *s);
318 }
319
320 *e = 0;
321
322 return r;
323 }
324
325 char *strv_join_quoted(char **l) {
326 char *buf = NULL;
327 char **s;
328 size_t allocated = 0, len = 0;
329
330 STRV_FOREACH(s, l) {
331 /* assuming here that escaped string cannot be more
332 * than twice as long, and reserving space for the
333 * separator and quotes.
334 */
335 _cleanup_free_ char *esc = NULL;
336 size_t needed;
337
338 if (!GREEDY_REALLOC(buf, allocated,
339 len + strlen(*s) * 2 + 3))
340 goto oom;
341
342 esc = cescape(*s);
343 if (!esc)
344 goto oom;
345
346 needed = snprintf(buf + len, allocated - len, "%s\"%s\"",
347 len > 0 ? " " : "", esc);
348 assert(needed < allocated - len);
349 len += needed;
350 }
351
352 if (!buf)
353 buf = malloc0(1);
354
355 return buf;
356
357 oom:
358 free(buf);
359 return NULL;
360 }
361
362 int strv_push(char ***l, char *value) {
363 char **c;
364 unsigned n;
365
366 if (!value)
367 return 0;
368
369 n = strv_length(*l);
370 c = realloc(*l, sizeof(char*) * (n + 2));
371 if (!c)
372 return -ENOMEM;
373
374 c[n] = value;
375 c[n+1] = NULL;
376
377 *l = c;
378 return 0;
379 }
380
381 int strv_consume(char ***l, char *value) {
382 int r;
383
384 r = strv_push(l, value);
385 if (r < 0)
386 free(value);
387
388 return r;
389 }
390
391 int strv_extend(char ***l, const char *value) {
392 char *v;
393
394 if (!value)
395 return 0;
396
397 v = strdup(value);
398 if (!v)
399 return -ENOMEM;
400
401 return strv_consume(l, v);
402 }
403
404 char **strv_uniq(char **l) {
405 char **i;
406
407 /* Drops duplicate entries. The first identical string will be
408 * kept, the others dropped */
409
410 STRV_FOREACH(i, l)
411 strv_remove(i+1, *i);
412
413 return l;
414 }
415
416 char **strv_remove(char **l, const char *s) {
417 char **f, **t;
418
419 if (!l)
420 return NULL;
421
422 assert(s);
423
424 /* Drops every occurrence of s in the string list, edits
425 * in-place. */
426
427 for (f = t = l; *f; f++)
428 if (streq(*f, s))
429 free(*f);
430 else
431 *(t++) = *f;
432
433 *t = NULL;
434 return l;
435 }
436
437 char **strv_parse_nulstr(const char *s, size_t l) {
438 const char *p;
439 unsigned c = 0, i = 0;
440 char **v;
441
442 assert(s || l <= 0);
443
444 if (l <= 0)
445 return new0(char*, 1);
446
447 for (p = s; p < s + l; p++)
448 if (*p == 0)
449 c++;
450
451 if (s[l-1] != 0)
452 c++;
453
454 v = new0(char*, c+1);
455 if (!v)
456 return NULL;
457
458 p = s;
459 while (p < s + l) {
460 const char *e;
461
462 e = memchr(p, 0, s + l - p);
463
464 v[i] = strndup(p, e ? e - p : s + l - p);
465 if (!v[i]) {
466 strv_free(v);
467 return NULL;
468 }
469
470 i++;
471
472 if (!e)
473 break;
474
475 p = e + 1;
476 }
477
478 assert(i == c);
479
480 return v;
481 }
482
483 char **strv_split_nulstr(const char *s) {
484 const char *i;
485 char **r = NULL;
486
487 NULSTR_FOREACH(i, s)
488 if (strv_extend(&r, i) < 0) {
489 strv_free(r);
490 return NULL;
491 }
492
493 if (!r)
494 return strv_new(NULL, NULL);
495
496 return r;
497 }
498
499 bool strv_overlap(char **a, char **b) {
500 char **i;
501
502 STRV_FOREACH(i, a)
503 if (strv_contains(b, *i))
504 return true;
505
506 return false;
507 }
508
509 static int str_compare(const void *_a, const void *_b) {
510 const char **a = (const char**) _a, **b = (const char**) _b;
511
512 return strcmp(*a, *b);
513 }
514
515 char **strv_sort(char **l) {
516
517 if (strv_isempty(l))
518 return l;
519
520 qsort(l, strv_length(l), sizeof(char*), str_compare);
521 return l;
522 }
523
524 void strv_print(char **l) {
525 char **s;
526
527 STRV_FOREACH(s, l)
528 puts(*s);
529 }
530
531 int strv_extendf(char ***l, const char *format, ...) {
532 va_list ap;
533 char *x;
534 int r;
535
536 va_start(ap, format);
537 r = vasprintf(&x, format, ap);
538 va_end(ap);
539
540 if (r < 0)
541 return -ENOMEM;
542
543 return strv_consume(l, x);
544 }