chiark / gitweb /
main: freeze instead of exiting when run as init
[elogind.git] / strv.c
1 /*-*- Mode: C; c-basic-offset: 8 -*-*/
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 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
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(l);
35         assert(name);
36
37         STRV_FOREACH(i, l)
38                 if (streq(*i, name))
39                         return *i;
40
41         return NULL;
42 }
43
44 void 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
56 char **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
69 fail:
70         for (k--, l--; k >= r; k--, l--)
71                 free(*k);
72
73         return NULL;
74 }
75
76 unsigned 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
88 char **strv_new_ap(const char *x, va_list ap) {
89         const char *s;
90         char **a;
91         unsigned n = 0, i = 0;
92         va_list aq;
93
94
95         if (x) {
96                 n = 1;
97
98                 va_copy(aq, ap);
99                 while (va_arg(aq, const char*))
100                         n++;
101                 va_end(aq);
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
115                 while ((s = va_arg(ap, const char*))) {
116                         if (!(a[i] = strdup(s)))
117                                 goto fail;
118
119                         i++;
120                 }
121         }
122
123         a[i] = NULL;
124
125         return a;
126
127 fail:
128
129         for (; i > 0; i--)
130                 if (a[i-1])
131                         free(a[i-1]);
132
133         free(a);
134
135         return NULL;
136 }
137
138 char **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
149 char **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
171 fail:
172         for (k--; k >= r; k--)
173                 free(*k);
174
175         free(r);
176
177         return NULL;
178 }
179
180 char **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
201 fail:
202         for (k--; k >= r; k--)
203                 free(*k);
204
205         free(r);
206
207         return NULL;
208
209 }
210
211 char **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
238 char **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
265 char *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
293         *e = 0;
294
295         return r;
296 }
297
298 char **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;
309
310         for (k = r; *l; k++, l++)
311                 if (!(*k = strdup(*l)))
312                         goto fail;
313
314         if (!(*(k++) = strdup(s)))
315                 goto fail;
316
317         *k = NULL;
318         return r;
319
320 fail:
321         for (k--; k >= r; k--)
322                 free(*k);
323
324         free(r);
325
326         return NULL;
327 }
328
329 char **strv_uniq(char **l) {
330         char **i;
331
332         /* Drops duplicate entries. The first identical string will be
333          * kept, the others dropped */
334
335         STRV_FOREACH(i, l)
336                 strv_remove(i+1, *i);
337
338         return l;
339 }
340
341 char **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         }
358
359         *t = NULL;
360         return l;
361 }
362
363 static 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
392 char **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
429 fail:
430         for (k--; k >= r; k--)
431                 free(*k);
432
433         free(r);
434
435         return NULL;
436 }