chiark / gitweb /
strv: make sure empty string lists result in a valid empty string in strv_join()
[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
27 #include "util.h"
28 #include "strv.h"
29
30 char *strv_find(char **l, const char *name) {
31         char **i;
32
33         assert(l);
34         assert(name);
35
36         STRV_FOREACH(i, l)
37                 if (streq(*i, name))
38                         return *i;
39
40         return NULL;
41 }
42
43 void strv_free(char **l) {
44         char **k;
45
46         if (!l)
47                 return;
48
49         for (k = l; *k; k++)
50                 free(*k);
51
52         free(l);
53 }
54
55 char **strv_copy(char **l) {
56         char **r, **k;
57
58         if (!(r = new(char*, strv_length(l)+1)))
59                 return NULL;
60
61         for (k = r; *l; k++, l++)
62                 if (!(*k = strdup(*l)))
63                         goto fail;
64
65         *k = NULL;
66         return r;
67
68 fail:
69         for (k--, l--; k >= r; k--, l--)
70                 free(*k);
71
72         return NULL;
73 }
74
75 unsigned strv_length(char **l) {
76         unsigned n = 0;
77
78         if (!l)
79                 return 0;
80
81         for (; *l; l++)
82                 n++;
83
84         return n;
85 }
86
87 char **strv_new(const char *x, ...) {
88         const char *s;
89         char **a;
90         unsigned n = 0, i = 0;
91         va_list ap;
92
93         if (x) {
94                 n = 1;
95
96                 va_start(ap, x);
97
98                 while (va_arg(ap, const char*))
99                         n++;
100
101                 va_end(ap);
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                 va_start(ap, x);
116
117                 while ((s = va_arg(ap, const char*))) {
118                         if (!(a[i] = strdup(s)))
119                                 goto fail;
120
121                         i++;
122                 }
123
124                 va_end(ap);
125         }
126
127         a[i] = NULL;
128         return a;
129
130 fail:
131
132         for (; i > 0; i--)
133                 if (a[i-1])
134                         free(a[i-1]);
135
136         free(a);
137         return NULL;
138 }
139
140 char **strv_merge(char **a, char **b) {
141         char **r, **k;
142
143         if (!a)
144                 return strv_copy(b);
145
146         if (!b)
147                 return strv_copy(a);
148
149         if (!(r = new(char*, strv_length(a)+strv_length(b)+1)))
150                 return NULL;
151
152         for (k = r; *a; k++, a++)
153                 if (!(*k = strdup(*a)))
154                         goto fail;
155         for (; *b; k++, b++)
156                 if (!(*k = strdup(*b)))
157                         goto fail;
158
159         *k = NULL;
160         return r;
161
162 fail:
163         for (k--; k >= r; k--)
164                 free(*k);
165
166         free(r);
167
168         return NULL;
169 }
170
171 char **strv_merge_concat(char **a, char **b, const char *suffix) {
172         char **r, **k;
173
174         /* Like strv_merge(), but appends suffix to all strings in b, before adding */
175
176         if (!b)
177                 return strv_copy(a);
178
179         if (!(r = new(char*, strv_length(a)+strv_length(b)+1)))
180                 return NULL;
181
182         for (k = r; *a; k++, a++)
183                 if (!(*k = strdup(*a)))
184                         goto fail;
185         for (; *b; k++, b++)
186                 if (!(*k = strappend(*b, suffix)))
187                         goto fail;
188
189         *k = NULL;
190         return r;
191
192 fail:
193         for (k--; k >= r; k--)
194                 free(*k);
195
196         free(r);
197
198         return NULL;
199
200 }
201
202 char **strv_split(const char *s, const char *separator) {
203         char *state;
204         char *w;
205         size_t l;
206         unsigned n, i;
207         char **r;
208
209         assert(s);
210
211         n = 0;
212         FOREACH_WORD_SEPARATOR(w, l, s, separator, state)
213                 n++;
214
215         if (!(r = new(char*, n+1)))
216                 return NULL;
217
218         i = 0;
219         FOREACH_WORD_SEPARATOR(w, l, s, separator, state)
220                 if (!(r[i++] = strndup(w, l))) {
221                         strv_free(r);
222                         return NULL;
223                 }
224
225         r[i] = NULL;
226         return r;
227 }
228
229 char **strv_split_quoted(const char *s) {
230         char *state;
231         char *w;
232         size_t l;
233         unsigned n, i;
234         char **r;
235
236         assert(s);
237
238         n = 0;
239         FOREACH_WORD_QUOTED(w, l, s, state)
240                 n++;
241
242         if (!(r = new(char*, n+1)))
243                 return NULL;
244
245         i = 0;
246         FOREACH_WORD_QUOTED(w, l, s, state)
247                 if (!(r[i++] = strndup(w, l))) {
248                         strv_free(r);
249                         return NULL;
250                 }
251
252         r[i] = NULL;
253         return r;
254 }
255
256 char *strv_join(char **l, const char *separator) {
257         char *r, *e;
258         char **s;
259         size_t n, k;
260
261         if (!separator)
262                 separator = " ";
263
264         k = strlen(separator);
265
266         n = 0;
267         STRV_FOREACH(s, l) {
268                 if (n != 0)
269                         n += k;
270                 n += strlen(*s);
271         }
272
273         if (!(r = new(char, n+1)))
274                 return NULL;
275
276         e = r;
277         STRV_FOREACH(s, l) {
278                 if (e != r)
279                         e = stpcpy(e, separator);
280
281                 e = stpcpy(e, *s);
282         }
283
284         *e = 0;
285
286         return r;
287 }
288
289 char **strv_append(char **l, const char *s) {
290         char **r, **k;
291
292         if (!l)
293                 return strv_new(s, NULL);
294
295         if (!s)
296                 return strv_copy(l);
297
298         if (!(r = new(char*, strv_length(l)+2)))
299                 return NULL;
300
301         for (k = r; *l; k++, l++)
302                 if (!(*k = strdup(*l)))
303                         goto fail;
304         if (!(*(k++) = strdup(s)))
305                 goto fail;
306
307         *k = NULL;
308         return r;
309
310 fail:
311         for (k--; k >= r; k--)
312                 free(*k);
313
314         free(r);
315
316         return NULL;
317 }
318
319 char **strv_uniq(char **l) {
320         char **i;
321
322         /* Drops duplicate entries. The first identical string will be
323          * kept, the others dropped */
324
325         STRV_FOREACH(i, l)
326                 strv_remove(i+1, *i);
327
328         return l;
329 }
330
331 char **strv_remove(char **l, const char *s) {
332         char **f, **t;
333
334         if (!l)
335                 return NULL;
336
337         /* Drops every occurence of s in the string list */
338
339         for (f = t = l; *f; f++) {
340
341                 if (streq(*f, s)) {
342                         free(*f);
343                         continue;
344                 }
345
346                 *(t++) = *f;
347         }
348
349         *t = NULL;
350         return l;
351 }