]> git.ipfire.org Git - people/ms/systemd.git/blob - strv.c
strv: add various strv calls
[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
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 return NULL;
167 }
168
169 char **strv_merge_concat(char **a, char **b, const char *suffix) {
170 char **r, **k;
171
172 /* Like strv_merge(), but appends suffix to all strings in b, before adding */
173
174 if (!b)
175 return strv_copy(a);
176
177 if (!(r = new(char*, strv_length(a)+strv_length(b)+1)))
178 return NULL;
179
180 for (k = r; *a; k++, a++)
181 if (!(*k = strdup(*a)))
182 goto fail;
183 for (; *b; k++, b++)
184 if (!(*k = strappend(*b, suffix)))
185 goto fail;
186
187 *k = NULL;
188 return r;
189
190 fail:
191 for (k--; k >= r; k--)
192 free(*k);
193
194 return NULL;
195
196 }
197
198 char **strv_split(const char *s, const char *separator) {
199 char *state;
200 char *w;
201 size_t l;
202 unsigned n, i;
203 char **r;
204
205 assert(s);
206
207 n = 0;
208 FOREACH_WORD_SEPARATOR(w, l, s, separator, state)
209 n++;
210
211 if (!(r = new(char*, n+1)))
212 return NULL;
213
214 i = 0;
215 FOREACH_WORD_SEPARATOR(w, l, s, separator, state)
216 if (!(r[i++] = strndup(w, l))) {
217 strv_free(r);
218 return NULL;
219 }
220
221 r[i] = NULL;
222 return r;
223 }
224
225 char **strv_split_quoted(const char *s) {
226 char *state;
227 char *w;
228 size_t l;
229 unsigned n, i;
230 char **r;
231
232 assert(s);
233
234 n = 0;
235 FOREACH_WORD_QUOTED(w, l, s, state)
236 n++;
237
238 if (!(r = new(char*, n+1)))
239 return NULL;
240
241 i = 0;
242 FOREACH_WORD_QUOTED(w, l, s, state)
243 if (!(r[i++] = strndup(w, l))) {
244 strv_free(r);
245 return NULL;
246 }
247
248 r[i] = NULL;
249 return r;
250 }
251
252 char *strv_join(char **l, const char *separator) {
253 char *r, *e;
254 char **s;
255 size_t n, k;
256
257 if (!separator)
258 separator = " ";
259
260 k = strlen(separator);
261
262 n = 0;
263 STRV_FOREACH(s, l) {
264 if (n != 0)
265 n += k;
266 n += strlen(*s);
267 }
268
269 if (!(r = new(char, n+1)))
270 return NULL;
271
272 e = r;
273 STRV_FOREACH(s, l) {
274 if (e != r)
275 e = stpcpy(e, separator);
276
277 e = stpcpy(e, *s);
278 }
279
280 return r;
281 }
282
283 char **strv_append(char **l, const char *s) {
284 char **r, **k;
285
286 if (!l)
287 return strv_new(s, NULL);
288
289 if (!s)
290 return strv_copy(l);
291
292 if (!(r = new(char*, strv_length(l)+2)))
293 return NULL;
294
295 for (k = r; *l; k++, l++)
296 if (!(*k = strdup(*l)))
297 goto fail;
298 if (!(*(k++) = strdup(s)))
299 goto fail;
300
301 *k = NULL;
302 return r;
303
304 fail:
305 for (k--; k >= r; k--)
306 free(*k);
307
308 return NULL;
309 }
310
311 char **strv_uniq(char **l) {
312 char **i;
313
314 /* Drops duplicate entries. The first identical string will be
315 * kept, the others dropped */
316
317 STRV_FOREACH(i, l)
318 strv_remove(i+1, *i);
319
320 return l;
321 }
322
323 char **strv_remove(char **l, const char *s) {
324 char **f, **t;
325
326 if (!l)
327 return NULL;
328
329 /* Drops every occurence of s in the string list */
330
331 for (f = t = l; *f; f++) {
332
333 if (streq(*f, s)) {
334 free(*f);
335 continue;
336 }
337
338 *(t++) = *f;
339 }
340
341 *t = NULL;
342 return l;
343 }