]>
Commit | Line | Data |
---|---|---|
2f461da2 HH |
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 | ||
e7ba1392 | 85 | unsigned int strv_length(char * const *l) { |
2f461da2 HH |
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; | |
e7ba1392 | 300 | unsigned int n; |
2f461da2 HH |
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); | |
e7ba1392 | 312 | if (n == 0) |
2f461da2 HH |
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 | ||
e7ba1392 | 492 | assert(s || l == 0); |
2f461da2 | 493 | |
e7ba1392 | 494 | if (l == 0) |
2f461da2 HH |
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 | } |