]> git.ipfire.org Git - people/ms/systemd.git/blob - strv.c
strv: introduce strv_env_merge() to merge environment arrays
[people/ms/systemd.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(const char *x, ...) {
89 const char *s;
90 char **a;
91 unsigned n = 0, i = 0;
92 va_list ap;
93
94 if (x) {
95 n = 1;
96
97 va_start(ap, x);
98
99 while (va_arg(ap, const char*))
100 n++;
101
102 va_end(ap);
103 }
104
105 if (!(a = new(char*, n+1)))
106 return NULL;
107
108 if (x) {
109 if (!(a[i] = strdup(x))) {
110 free(a);
111 return NULL;
112 }
113
114 i++;
115
116 va_start(ap, x);
117
118 while ((s = va_arg(ap, const char*))) {
119 if (!(a[i] = strdup(s)))
120 goto fail;
121
122 i++;
123 }
124
125 va_end(ap);
126 }
127
128 a[i] = NULL;
129 return a;
130
131 fail:
132
133 for (; i > 0; i--)
134 if (a[i-1])
135 free(a[i-1]);
136
137 free(a);
138 return NULL;
139 }
140
141 char **strv_merge(char **a, char **b) {
142 char **r, **k;
143
144 if (!a)
145 return strv_copy(b);
146
147 if (!b)
148 return strv_copy(a);
149
150 if (!(r = new(char*, strv_length(a)+strv_length(b)+1)))
151 return NULL;
152
153 for (k = r; *a; k++, a++)
154 if (!(*k = strdup(*a)))
155 goto fail;
156 for (; *b; k++, b++)
157 if (!(*k = strdup(*b)))
158 goto fail;
159
160 *k = NULL;
161 return r;
162
163 fail:
164 for (k--; k >= r; k--)
165 free(*k);
166
167 free(r);
168
169 return NULL;
170 }
171
172 char **strv_merge_concat(char **a, char **b, const char *suffix) {
173 char **r, **k;
174
175 /* Like strv_merge(), but appends suffix to all strings in b, before adding */
176
177 if (!b)
178 return strv_copy(a);
179
180 if (!(r = new(char*, strv_length(a)+strv_length(b)+1)))
181 return NULL;
182
183 for (k = r; *a; k++, a++)
184 if (!(*k = strdup(*a)))
185 goto fail;
186 for (; *b; k++, b++)
187 if (!(*k = strappend(*b, suffix)))
188 goto fail;
189
190 *k = NULL;
191 return r;
192
193 fail:
194 for (k--; k >= r; k--)
195 free(*k);
196
197 free(r);
198
199 return NULL;
200
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 if (!(r = new(char*, n+1)))
217 return NULL;
218
219 i = 0;
220 FOREACH_WORD_SEPARATOR(w, l, s, separator, state)
221 if (!(r[i++] = strndup(w, l))) {
222 strv_free(r);
223 return NULL;
224 }
225
226 r[i] = NULL;
227 return r;
228 }
229
230 char **strv_split_quoted(const char *s) {
231 char *state;
232 char *w;
233 size_t l;
234 unsigned n, i;
235 char **r;
236
237 assert(s);
238
239 n = 0;
240 FOREACH_WORD_QUOTED(w, l, s, state)
241 n++;
242
243 if (!(r = new(char*, n+1)))
244 return NULL;
245
246 i = 0;
247 FOREACH_WORD_QUOTED(w, l, s, state)
248 if (!(r[i++] = strndup(w, l))) {
249 strv_free(r);
250 return NULL;
251 }
252
253 r[i] = NULL;
254 return r;
255 }
256
257 char *strv_join(char **l, const char *separator) {
258 char *r, *e;
259 char **s;
260 size_t n, k;
261
262 if (!separator)
263 separator = " ";
264
265 k = strlen(separator);
266
267 n = 0;
268 STRV_FOREACH(s, l) {
269 if (n != 0)
270 n += k;
271 n += strlen(*s);
272 }
273
274 if (!(r = new(char, n+1)))
275 return NULL;
276
277 e = r;
278 STRV_FOREACH(s, l) {
279 if (e != r)
280 e = stpcpy(e, separator);
281
282 e = stpcpy(e, *s);
283 }
284
285 *e = 0;
286
287 return r;
288 }
289
290 char **strv_append(char **l, const char *s) {
291 char **r, **k;
292
293 if (!l)
294 return strv_new(s, NULL);
295
296 if (!s)
297 return strv_copy(l);
298
299 if (!(r = new(char*, strv_length(l)+2)))
300 return NULL;
301
302 for (k = r; *l; k++, l++)
303 if (!(*k = strdup(*l)))
304 goto fail;
305
306 if (!(*(k++) = strdup(s)))
307 goto fail;
308
309 *k = NULL;
310 return r;
311
312 fail:
313 for (k--; k >= r; k--)
314 free(*k);
315
316 free(r);
317
318 return NULL;
319 }
320
321 char **strv_uniq(char **l) {
322 char **i;
323
324 /* Drops duplicate entries. The first identical string will be
325 * kept, the others dropped */
326
327 STRV_FOREACH(i, l)
328 strv_remove(i+1, *i);
329
330 return l;
331 }
332
333 char **strv_remove(char **l, const char *s) {
334 char **f, **t;
335
336 if (!l)
337 return NULL;
338
339 /* Drops every occurence of s in the string list */
340
341 for (f = t = l; *f; f++) {
342
343 if (streq(*f, s)) {
344 free(*f);
345 continue;
346 }
347
348 *(t++) = *f;
349 }
350
351 *t = NULL;
352 return l;
353 }
354
355 static int env_append(char **r, char ***k, char **a) {
356 assert(r);
357 assert(k);
358 assert(a);
359
360 /* Add the entries of a to *k unless they already exist in *r
361 * in which case they are overriden instead. This assumes
362 * there is enough space in the r */
363
364 for (; *a; a++) {
365 char **j;
366 size_t n = strcspn(*a, "=") + 1;
367
368 for (j = r; j < *k; j++)
369 if (strncmp(*j, *a, n) == 0)
370 break;
371
372 if (j >= *k)
373 (*k)++;
374 else
375 free(*j);
376
377 if (!(*j = strdup(*a)))
378 return -ENOMEM;
379 }
380
381 return 0;
382 }
383
384 char **strv_env_merge(char **x, ...) {
385 size_t n = 0;
386 char **l, **k, **r;
387 va_list ap;
388
389 /* Merges an arbitrary number of environment sets */
390
391 if (x) {
392 n += strv_length(x);
393
394 va_start(ap, x);
395 while ((l = va_arg(ap, char**)))
396 n += strv_length(l);
397 va_end(ap);
398 }
399
400
401 if (!(r = new(char*, n+1)))
402 return NULL;
403
404 k = r;
405
406 if (x) {
407 if (env_append(r, &k, x) < 0)
408 goto fail;
409
410 va_start(ap, x);
411 while ((l = va_arg(ap, char**)))
412 if (env_append(r, &k, l) < 0)
413 goto fail;
414 va_end(ap);
415 }
416
417 *k = NULL;
418
419 return r;
420
421 fail:
422 for (k--; k >= r; k--)
423 free(*k);
424
425 free(r);
426
427 return NULL;
428 }