]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/strv.c
cgroup: minor optimization
[thirdparty/systemd.git] / src / shared / strv.c
CommitLineData
d6c9574f 1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
60918275 2
a7334b09
LP
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
5430f7f2
LP
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
a7334b09
LP
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
5430f7f2 16 Lesser General Public License for more details.
a7334b09 17
5430f7f2 18 You should have received a copy of the GNU Lesser General Public License
a7334b09
LP
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
60918275
LP
22#include <assert.h>
23#include <stdlib.h>
24#include <stdarg.h>
25#include <string.h>
2e6c9e6b 26#include <errno.h>
60918275
LP
27
28#include "util.h"
29#include "strv.h"
30
31char *strv_find(char **l, const char *name) {
5f9a22c3
LP
32 char **i;
33
60918275
LP
34 assert(name);
35
5f9a22c3
LP
36 STRV_FOREACH(i, l)
37 if (streq(*i, name))
38 return *i;
60918275
LP
39
40 return NULL;
41}
42
a4bfb399
LP
43char *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
60918275
LP
55void 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
67char **strv_copy(char **l) {
68 char **r, **k;
69
1fd8d04e
LP
70 k = r = new(char*, strv_length(l) + 1);
71 if (!r)
60918275
LP
72 return NULL;
73
ede27aab 74 if (l)
1fd8d04e
LP
75 for (; *l; k++, l++) {
76 *k = strdup(*l);
77 if (!*k) {
78 strv_free(r);
79 return NULL;
80 }
81 }
60918275
LP
82
83 *k = NULL;
84 return r;
60918275
LP
85}
86
87unsigned strv_length(char **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
257eca1a 99char **strv_new_ap(const char *x, va_list ap) {
60918275
LP
100 const char *s;
101 char **a;
102 unsigned n = 0, i = 0;
257eca1a
LP
103 va_list aq;
104
07719a21
LP
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
60918275 110 if (x) {
07719a21 111 n = x == (const char*) -1 ? 0 : 1;
60918275 112
257eca1a 113 va_copy(aq, ap);
07719a21
LP
114 while ((s = va_arg(aq, const char*))) {
115 if (s == (const char*) -1)
116 continue;
117
60918275 118 n++;
07719a21
LP
119 }
120
257eca1a 121 va_end(aq);
60918275
LP
122 }
123
07719a21
LP
124 a = new(char*, n+1);
125 if (!a)
60918275
LP
126 return NULL;
127
128 if (x) {
07719a21
LP
129 if (x != (const char*) -1) {
130 a[i] = strdup(x);
131 if (!a[i])
132 goto fail;
133 i++;
60918275
LP
134 }
135
60918275 136 while ((s = va_arg(ap, const char*))) {
07719a21
LP
137
138 if (s == (const char*) -1)
139 continue;
140
141 a[i] = strdup(s);
142 if (!a[i])
60918275
LP
143 goto fail;
144
145 i++;
146 }
60918275
LP
147 }
148
149 a[i] = NULL;
257eca1a 150
60918275
LP
151 return a;
152
153fail:
1fd8d04e 154 strv_free(a);
60918275
LP
155 return NULL;
156}
034c6ed7 157
257eca1a
LP
158char **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
034c6ed7
LP
169char **strv_merge(char **a, char **b) {
170 char **r, **k;
171
172 if (!a)
173 return strv_copy(b);
174
175 if (!b)
176 return strv_copy(a);
177
07719a21
LP
178 r = new(char*, strv_length(a) + strv_length(b) + 1);
179 if (!r)
034c6ed7
LP
180 return NULL;
181
07719a21
LP
182 for (k = r; *a; k++, a++) {
183 *k = strdup(*a);
184 if (!*k)
034c6ed7 185 goto fail;
07719a21
LP
186 }
187
188 for (; *b; k++, b++) {
189 *k = strdup(*b);
190 if (!*k)
034c6ed7 191 goto fail;
07719a21 192 }
034c6ed7
LP
193
194 *k = NULL;
195 return r;
196
197fail:
07719a21 198 strv_free(r);
034c6ed7 199 return NULL;
5f9a22c3
LP
200}
201
202char **strv_merge_concat(char **a, char **b, const char *suffix) {
203 char **r, **k;
204
205 /* Like strv_merge(), but appends suffix to all strings in b, before adding */
206
207 if (!b)
208 return strv_copy(a);
209
f8440af5
LP
210 r = new(char*, strv_length(a) + strv_length(b) + 1);
211 if (!r)
5f9a22c3
LP
212 return NULL;
213
8ea913b2
LP
214 k = r;
215 if (a)
216 for (; *a; k++, a++) {
217 *k = strdup(*a);
218 if (!*k)
219 goto fail;
220 }
221
222 for (; *b; k++, b++) {
223 *k = strappend(*b, suffix);
224 if (!*k)
5f9a22c3 225 goto fail;
8ea913b2 226 }
5f9a22c3
LP
227
228 *k = NULL;
229 return r;
230
231fail:
07719a21 232 strv_free(r);
5f9a22c3
LP
233 return NULL;
234
235}
236
237char **strv_split(const char *s, const char *separator) {
238 char *state;
239 char *w;
240 size_t l;
241 unsigned n, i;
242 char **r;
243
244 assert(s);
245
246 n = 0;
247 FOREACH_WORD_SEPARATOR(w, l, s, separator, state)
248 n++;
249
1fd8d04e
LP
250 r = new(char*, n+1);
251 if (!r)
5f9a22c3
LP
252 return NULL;
253
254 i = 0;
1fd8d04e
LP
255 FOREACH_WORD_SEPARATOR(w, l, s, separator, state) {
256 r[i] = strndup(w, l);
257 if (!r[i]) {
5f9a22c3
LP
258 strv_free(r);
259 return NULL;
260 }
261
1fd8d04e
LP
262 i++;
263 }
264
5f9a22c3
LP
265 r[i] = NULL;
266 return r;
267}
268
269char **strv_split_quoted(const char *s) {
270 char *state;
271 char *w;
272 size_t l;
273 unsigned n, i;
274 char **r;
275
276 assert(s);
277
278 n = 0;
279 FOREACH_WORD_QUOTED(w, l, s, state)
280 n++;
281
1fd8d04e
LP
282 r = new(char*, n+1);
283 if (!r)
5f9a22c3
LP
284 return NULL;
285
286 i = 0;
1fd8d04e
LP
287 FOREACH_WORD_QUOTED(w, l, s, state) {
288 r[i] = cunescape_length(w, l);
289 if (!r[i]) {
5f9a22c3
LP
290 strv_free(r);
291 return NULL;
292 }
1fd8d04e
LP
293 i++;
294 }
5f9a22c3
LP
295
296 r[i] = NULL;
297 return r;
298}
299
26d04f86
LP
300char **strv_split_newlines(const char *s) {
301 char **l;
302 unsigned n;
303
304 assert(s);
305
306 /* Special version of strv_split() that splits on newlines and
307 * suppresses an empty string at the end */
308
309 l = strv_split(s, NEWLINE);
310 if (!l)
311 return NULL;
312
313 n = strv_length(l);
314 if (n <= 0)
315 return l;
316
317 if (isempty(l[n-1])) {
318 free(l[n-1]);
319 l[n-1] = NULL;
320 }
321
322 return l;
323}
324
5f9a22c3
LP
325char *strv_join(char **l, const char *separator) {
326 char *r, *e;
327 char **s;
328 size_t n, k;
329
330 if (!separator)
331 separator = " ";
332
333 k = strlen(separator);
334
335 n = 0;
336 STRV_FOREACH(s, l) {
337 if (n != 0)
338 n += k;
339 n += strlen(*s);
340 }
341
1fd8d04e
LP
342 r = new(char, n+1);
343 if (!r)
5f9a22c3
LP
344 return NULL;
345
346 e = r;
347 STRV_FOREACH(s, l) {
348 if (e != r)
349 e = stpcpy(e, separator);
350
351 e = stpcpy(e, *s);
352 }
353
8d49745c
LP
354 *e = 0;
355
5f9a22c3
LP
356 return r;
357}
358
359char **strv_append(char **l, const char *s) {
360 char **r, **k;
361
362 if (!l)
363 return strv_new(s, NULL);
364
365 if (!s)
366 return strv_copy(l);
367
f8440af5
LP
368 r = new(char*, strv_length(l)+2);
369 if (!r)
5f9a22c3 370 return NULL;
034c6ed7 371
1fd8d04e
LP
372 for (k = r; *l; k++, l++) {
373 *k = strdup(*l);
374 if (!*k)
5f9a22c3 375 goto fail;
1fd8d04e 376 }
2e6c9e6b 377
1fd8d04e
LP
378 k[0] = strdup(s);
379 if (!k[0])
5f9a22c3
LP
380 goto fail;
381
1fd8d04e 382 k[1] = NULL;
5f9a22c3
LP
383 return r;
384
385fail:
1fd8d04e 386 strv_free(r);
5f9a22c3 387 return NULL;
034c6ed7 388}
cba8922f 389
5926ccca
LP
390int strv_extend(char ***l, const char *value) {
391 char **c;
82dde599
LP
392 char *v;
393 unsigned n;
5926ccca
LP
394
395 if (!value)
396 return 0;
397
82dde599
LP
398 v = strdup(value);
399 if (!v)
5926ccca
LP
400 return -ENOMEM;
401
82dde599
LP
402 n = strv_length(*l);
403 c = realloc(*l, sizeof(char*) * (n + 2));
404 if (!c) {
405 free(v);
406 return -ENOMEM;
407 }
408
409 c[n] = v;
410 c[n+1] = NULL;
411
5926ccca
LP
412 *l = c;
413 return 0;
414}
415
5f9a22c3 416char **strv_uniq(char **l) {
cba8922f
LP
417 char **i;
418
5f9a22c3
LP
419 /* Drops duplicate entries. The first identical string will be
420 * kept, the others dropped */
421
cba8922f 422 STRV_FOREACH(i, l)
5f9a22c3
LP
423 strv_remove(i+1, *i);
424
425 return l;
426}
427
428char **strv_remove(char **l, const char *s) {
429 char **f, **t;
430
431 if (!l)
432 return NULL;
433
5d6ab905
LP
434 assert(s);
435
436 /* Drops every occurrence of s in the string list, edits
437 * in-place. */
5f9a22c3
LP
438
439 for (f = t = l; *f; f++) {
440
441 if (streq(*f, s)) {
442 free(*f);
443 continue;
444 }
445
446 *(t++) = *f;
447 }
cba8922f 448
5f9a22c3
LP
449 *t = NULL;
450 return l;
cba8922f 451}
2e6c9e6b 452
71ecc858
LP
453char **strv_remove_prefix(char **l, const char *s) {
454 char **f, **t;
455
456 if (!l)
457 return NULL;
458
459 assert(s);
460
461 /* Drops every occurrence of a string prefixed with s in the
462 * string list, edits in-place. */
463
464 for (f = t = l; *f; f++) {
465
466 if (startswith(*f, s)) {
467 free(*f);
468 continue;
469 }
470
471 *(t++) = *f;
472 }
473
474 *t = NULL;
475 return l;
476}
477
21bc923a
LP
478char **strv_parse_nulstr(const char *s, size_t l) {
479 const char *p;
480 unsigned c = 0, i = 0;
481 char **v;
482
483 assert(s || l <= 0);
484
485 if (l <= 0)
486 return strv_new(NULL, NULL);
487
488 for (p = s; p < s + l; p++)
489 if (*p == 0)
490 c++;
491
492 if (s[l-1] != 0)
493 c++;
494
1fd8d04e
LP
495 v = new0(char*, c+1);
496 if (!v)
21bc923a
LP
497 return NULL;
498
499 p = s;
500 while (p < s + l) {
501 const char *e;
502
503 e = memchr(p, 0, s + l - p);
504
1fd8d04e
LP
505 v[i] = strndup(p, e ? e - p : s + l - p);
506 if (!v[i]) {
21bc923a
LP
507 strv_free(v);
508 return NULL;
509 }
510
1fd8d04e
LP
511 i++;
512
21bc923a
LP
513 if (!e)
514 break;
515
516 p = e + 1;
517 }
518
519 assert(i == c);
520
521 return v;
522}
0c85a4f3 523
fabe5c0e
LP
524char **strv_split_nulstr(const char *s) {
525 const char *i;
526 char **r = NULL;
527
528 NULSTR_FOREACH(i, s)
529 if (strv_extend(&r, i) < 0) {
530 strv_free(r);
531 return NULL;
532 }
533
534 if (!r)
535 return strv_new(NULL, NULL);
536
537 return r;
538}
539
0c85a4f3
LP
540bool strv_overlap(char **a, char **b) {
541 char **i, **j;
542
543 STRV_FOREACH(i, a) {
544 STRV_FOREACH(j, b) {
545 if (streq(*i, *j))
546 return true;
547 }
548 }
549
550 return false;
551}
857a493d
LP
552
553static int str_compare(const void *_a, const void *_b) {
554 const char **a = (const char**) _a, **b = (const char**) _b;
555
556 return strcmp(*a, *b);
557}
558
559char **strv_sort(char **l) {
560
561 if (strv_isempty(l))
562 return l;
563
564 qsort(l, strv_length(l), sizeof(char*), str_compare);
565 return l;
566}
7c2d8094
TA
567
568void strv_print(char **l) {
569 char **s;
570
571 if (!l)
572 return;
573
574 STRV_FOREACH(s, l)
575 puts(*s);
576}