]> git.ipfire.org Git - people/ms/systemd.git/blame - strv.c
environment: allow control of the environment block via D-Bus
[people/ms/systemd.git] / strv.c
CommitLineData
60918275
LP
1/*-*- Mode: C; c-basic-offset: 8 -*-*/
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
9 under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 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 General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
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(l);
35 assert(name);
36
5f9a22c3
LP
37 STRV_FOREACH(i, l)
38 if (streq(*i, name))
39 return *i;
60918275
LP
40
41 return NULL;
42}
43
44void strv_free(char **l) {
45 char **k;
46
47 if (!l)
48 return;
49
50 for (k = l; *k; k++)
51 free(*k);
52
53 free(l);
54}
55
56char **strv_copy(char **l) {
57 char **r, **k;
58
59 if (!(r = new(char*, strv_length(l)+1)))
60 return NULL;
61
62 for (k = r; *l; k++, l++)
63 if (!(*k = strdup(*l)))
64 goto fail;
65
66 *k = NULL;
67 return r;
68
69fail:
70 for (k--, l--; k >= r; k--, l--)
71 free(*k);
72
73 return NULL;
74}
75
76unsigned strv_length(char **l) {
77 unsigned n = 0;
78
79 if (!l)
80 return 0;
81
82 for (; *l; l++)
83 n++;
84
85 return n;
86}
87
257eca1a 88char **strv_new_ap(const char *x, va_list ap) {
60918275
LP
89 const char *s;
90 char **a;
91 unsigned n = 0, i = 0;
257eca1a
LP
92 va_list aq;
93
60918275
LP
94
95 if (x) {
96 n = 1;
97
257eca1a
LP
98 va_copy(aq, ap);
99 while (va_arg(aq, const char*))
60918275 100 n++;
257eca1a 101 va_end(aq);
60918275
LP
102 }
103
104 if (!(a = new(char*, n+1)))
105 return NULL;
106
107 if (x) {
108 if (!(a[i] = strdup(x))) {
109 free(a);
110 return NULL;
111 }
112
113 i++;
114
60918275
LP
115 while ((s = va_arg(ap, const char*))) {
116 if (!(a[i] = strdup(s)))
117 goto fail;
118
119 i++;
120 }
60918275
LP
121 }
122
123 a[i] = NULL;
257eca1a 124
60918275
LP
125 return a;
126
127fail:
128
129 for (; i > 0; i--)
130 if (a[i-1])
131 free(a[i-1]);
132
133 free(a);
257eca1a 134
60918275
LP
135 return NULL;
136}
034c6ed7 137
257eca1a
LP
138char **strv_new(const char *x, ...) {
139 char **r;
140 va_list ap;
141
142 va_start(ap, x);
143 r = strv_new_ap(x, ap);
144 va_end(ap);
145
146 return r;
147}
148
034c6ed7
LP
149char **strv_merge(char **a, char **b) {
150 char **r, **k;
151
152 if (!a)
153 return strv_copy(b);
154
155 if (!b)
156 return strv_copy(a);
157
158 if (!(r = new(char*, strv_length(a)+strv_length(b)+1)))
159 return NULL;
160
161 for (k = r; *a; k++, a++)
162 if (!(*k = strdup(*a)))
163 goto fail;
164 for (; *b; k++, b++)
165 if (!(*k = strdup(*b)))
166 goto fail;
167
168 *k = NULL;
169 return r;
170
171fail:
172 for (k--; k >= r; k--)
173 free(*k);
174
100a76ee
LP
175 free(r);
176
034c6ed7 177 return NULL;
5f9a22c3
LP
178}
179
180char **strv_merge_concat(char **a, char **b, const char *suffix) {
181 char **r, **k;
182
183 /* Like strv_merge(), but appends suffix to all strings in b, before adding */
184
185 if (!b)
186 return strv_copy(a);
187
188 if (!(r = new(char*, strv_length(a)+strv_length(b)+1)))
189 return NULL;
190
191 for (k = r; *a; k++, a++)
192 if (!(*k = strdup(*a)))
193 goto fail;
194 for (; *b; k++, b++)
195 if (!(*k = strappend(*b, suffix)))
196 goto fail;
197
198 *k = NULL;
199 return r;
200
201fail:
202 for (k--; k >= r; k--)
203 free(*k);
204
100a76ee
LP
205 free(r);
206
5f9a22c3
LP
207 return NULL;
208
209}
210
211char **strv_split(const char *s, const char *separator) {
212 char *state;
213 char *w;
214 size_t l;
215 unsigned n, i;
216 char **r;
217
218 assert(s);
219
220 n = 0;
221 FOREACH_WORD_SEPARATOR(w, l, s, separator, state)
222 n++;
223
224 if (!(r = new(char*, n+1)))
225 return NULL;
226
227 i = 0;
228 FOREACH_WORD_SEPARATOR(w, l, s, separator, state)
229 if (!(r[i++] = strndup(w, l))) {
230 strv_free(r);
231 return NULL;
232 }
233
234 r[i] = NULL;
235 return r;
236}
237
238char **strv_split_quoted(const char *s) {
239 char *state;
240 char *w;
241 size_t l;
242 unsigned n, i;
243 char **r;
244
245 assert(s);
246
247 n = 0;
248 FOREACH_WORD_QUOTED(w, l, s, state)
249 n++;
250
251 if (!(r = new(char*, n+1)))
252 return NULL;
253
254 i = 0;
255 FOREACH_WORD_QUOTED(w, l, s, state)
256 if (!(r[i++] = strndup(w, l))) {
257 strv_free(r);
258 return NULL;
259 }
260
261 r[i] = NULL;
262 return r;
263}
264
265char *strv_join(char **l, const char *separator) {
266 char *r, *e;
267 char **s;
268 size_t n, k;
269
270 if (!separator)
271 separator = " ";
272
273 k = strlen(separator);
274
275 n = 0;
276 STRV_FOREACH(s, l) {
277 if (n != 0)
278 n += k;
279 n += strlen(*s);
280 }
281
282 if (!(r = new(char, n+1)))
283 return NULL;
284
285 e = r;
286 STRV_FOREACH(s, l) {
287 if (e != r)
288 e = stpcpy(e, separator);
289
290 e = stpcpy(e, *s);
291 }
292
8d49745c
LP
293 *e = 0;
294
5f9a22c3
LP
295 return r;
296}
297
298char **strv_append(char **l, const char *s) {
299 char **r, **k;
300
301 if (!l)
302 return strv_new(s, NULL);
303
304 if (!s)
305 return strv_copy(l);
306
307 if (!(r = new(char*, strv_length(l)+2)))
308 return NULL;
034c6ed7 309
5f9a22c3
LP
310 for (k = r; *l; k++, l++)
311 if (!(*k = strdup(*l)))
312 goto fail;
2e6c9e6b 313
5f9a22c3
LP
314 if (!(*(k++) = strdup(s)))
315 goto fail;
316
317 *k = NULL;
318 return r;
319
320fail:
321 for (k--; k >= r; k--)
322 free(*k);
323
100a76ee
LP
324 free(r);
325
5f9a22c3 326 return NULL;
034c6ed7 327}
cba8922f 328
5f9a22c3 329char **strv_uniq(char **l) {
cba8922f
LP
330 char **i;
331
5f9a22c3
LP
332 /* Drops duplicate entries. The first identical string will be
333 * kept, the others dropped */
334
cba8922f 335 STRV_FOREACH(i, l)
5f9a22c3
LP
336 strv_remove(i+1, *i);
337
338 return l;
339}
340
341char **strv_remove(char **l, const char *s) {
342 char **f, **t;
343
344 if (!l)
345 return NULL;
346
347 /* Drops every occurence of s in the string list */
348
349 for (f = t = l; *f; f++) {
350
351 if (streq(*f, s)) {
352 free(*f);
353 continue;
354 }
355
356 *(t++) = *f;
357 }
cba8922f 358
5f9a22c3
LP
359 *t = NULL;
360 return l;
cba8922f 361}
2e6c9e6b
LP
362
363static int env_append(char **r, char ***k, char **a) {
364 assert(r);
365 assert(k);
366 assert(a);
367
368 /* Add the entries of a to *k unless they already exist in *r
369 * in which case they are overriden instead. This assumes
370 * there is enough space in the r */
371
372 for (; *a; a++) {
373 char **j;
374 size_t n = strcspn(*a, "=") + 1;
375
376 for (j = r; j < *k; j++)
377 if (strncmp(*j, *a, n) == 0)
378 break;
379
380 if (j >= *k)
381 (*k)++;
382 else
383 free(*j);
384
385 if (!(*j = strdup(*a)))
386 return -ENOMEM;
387 }
388
389 return 0;
390}
391
392char **strv_env_merge(char **x, ...) {
393 size_t n = 0;
394 char **l, **k, **r;
395 va_list ap;
396
397 /* Merges an arbitrary number of environment sets */
398
399 if (x) {
400 n += strv_length(x);
401
402 va_start(ap, x);
403 while ((l = va_arg(ap, char**)))
404 n += strv_length(l);
405 va_end(ap);
406 }
407
408
409 if (!(r = new(char*, n+1)))
410 return NULL;
411
412 k = r;
413
414 if (x) {
415 if (env_append(r, &k, x) < 0)
416 goto fail;
417
418 va_start(ap, x);
419 while ((l = va_arg(ap, char**)))
420 if (env_append(r, &k, l) < 0)
421 goto fail;
422 va_end(ap);
423 }
424
425 *k = NULL;
426
427 return r;
428
429fail:
430 for (k--; k >= r; k--)
431 free(*k);
432
433 free(r);
434
435 return NULL;
436}
1137a57c
LP
437
438static bool env_match(const char *t, const char *pattern) {
439 assert(t);
440 assert(pattern);
441
442 /* pattern a matches string a
443 * a matches a=
444 * a matches a=b
445 * a= matches a=
446 * a=b matches a=b
447 * a= does not match a
448 * a=b does not match a=
449 * a=b does not match a
450 * a=b does not match a=c */
451
452 if (streq(t, pattern))
453 return true;
454
455 if (!strchr(pattern, '=')) {
456 size_t l = strlen(pattern);
457
458 return strncmp(t, pattern, l) == 0 && t[l] == '=';
459 }
460
461 return false;
462}
463
464char **strv_env_delete(char **x, ...) {
465 size_t n = 0, i = 0;
466 char **l, **k, **r, **j;
467 va_list ap;
468
469 /* Deletes every entry fromx that is mentioned in the other
470 * string lists */
471
472 n = strv_length(x);
473
474 if (!(r = new(char*, n+1)))
475 return NULL;
476
477 STRV_FOREACH(k, x) {
478 va_start(ap, x);
479
480 while ((l = va_arg(ap, char**)))
481 STRV_FOREACH(j, l)
482 if (env_match(*k, *j))
483 goto delete;
484
485 va_end(ap);
486
487 if (!(r[i++] = strdup(*k))) {
488 strv_free(r);
489 return NULL;
490 }
491
492 continue;
493
494 delete:
495 va_end(ap);
496 }
497
498 r[i] = NULL;
499
500 assert(i <= n);
501
502 return r;
503}