]> git.ipfire.org Git - thirdparty/systemd.git/blame - strv.c
strv: fix three minor OOM-triggered memory leaks
[thirdparty/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>
26
27#include "util.h"
28#include "strv.h"
29
30char *strv_find(char **l, const char *name) {
5f9a22c3
LP
31 char **i;
32
60918275
LP
33 assert(l);
34 assert(name);
35
5f9a22c3
LP
36 STRV_FOREACH(i, l)
37 if (streq(*i, name))
38 return *i;
60918275
LP
39
40 return NULL;
41}
42
43void 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
55char **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
68fail:
69 for (k--, l--; k >= r; k--, l--)
70 free(*k);
71
72 return NULL;
73}
74
75unsigned 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
87char **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
130fail:
131
132 for (; i > 0; i--)
133 if (a[i-1])
134 free(a[i-1]);
135
136 free(a);
137 return NULL;
138}
034c6ed7
LP
139
140char **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
162fail:
163 for (k--; k >= r; k--)
164 free(*k);
165
100a76ee
LP
166 free(r);
167
034c6ed7 168 return NULL;
5f9a22c3
LP
169}
170
171char **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
192fail:
193 for (k--; k >= r; k--)
194 free(*k);
195
100a76ee
LP
196 free(r);
197
5f9a22c3
LP
198 return NULL;
199
200}
201
202char **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
229char **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
256char *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 return r;
285}
286
287char **strv_append(char **l, const char *s) {
288 char **r, **k;
289
290 if (!l)
291 return strv_new(s, NULL);
292
293 if (!s)
294 return strv_copy(l);
295
296 if (!(r = new(char*, strv_length(l)+2)))
297 return NULL;
034c6ed7 298
5f9a22c3
LP
299 for (k = r; *l; k++, l++)
300 if (!(*k = strdup(*l)))
301 goto fail;
302 if (!(*(k++) = strdup(s)))
303 goto fail;
304
305 *k = NULL;
306 return r;
307
308fail:
309 for (k--; k >= r; k--)
310 free(*k);
311
100a76ee
LP
312 free(r);
313
5f9a22c3 314 return NULL;
034c6ed7 315}
cba8922f 316
5f9a22c3 317char **strv_uniq(char **l) {
cba8922f
LP
318 char **i;
319
5f9a22c3
LP
320 /* Drops duplicate entries. The first identical string will be
321 * kept, the others dropped */
322
cba8922f 323 STRV_FOREACH(i, l)
5f9a22c3
LP
324 strv_remove(i+1, *i);
325
326 return l;
327}
328
329char **strv_remove(char **l, const char *s) {
330 char **f, **t;
331
332 if (!l)
333 return NULL;
334
335 /* Drops every occurence of s in the string list */
336
337 for (f = t = l; *f; f++) {
338
339 if (streq(*f, s)) {
340 free(*f);
341 continue;
342 }
343
344 *(t++) = *f;
345 }
cba8922f 346
5f9a22c3
LP
347 *t = NULL;
348 return l;
cba8922f 349}