Coverage Report

Created: 2025-06-13 06:36

/src/util-linux/lib/strv.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * SPDX-License-Identifier: LGPL-2.1-or-later
3
 *
4
 * Copyright (C) 2010 Lennart Poettering
5
 * Copyright (C) 2015-2022 Karel Zak <kzak@redhat.com>
6
 *
7
 * This is free software; you can redistribute it and/or modify it
8
 * under the terms of the GNU Lesser General Public License as published by
9
 * the Free Software Foundation; either version 2.1 of the License, or
10
 * (at your option) any later version.
11
 *
12
 *
13
 * Copyright (C) 2015 Karel Zak <kzak@redhat.com>
14
 *    Modified the original version from systemd project for util-linux.
15
 */
16
17
#include <stdlib.h>
18
#include <stdarg.h>
19
#include <string.h>
20
#include <errno.h>
21
#include <stdbool.h>
22
#include <assert.h>
23
24
#include "strutils.h"
25
#include "strv.h"
26
27
0
void strv_clear(char **l) {
28
0
        char **k;
29
30
0
        if (!l)
31
0
                return;
32
33
0
        for (k = l; *k; k++)
34
0
                free(*k);
35
36
0
        *l = NULL;
37
0
}
38
39
0
char **strv_free(char **l) {
40
0
        strv_clear(l);
41
0
        free(l);
42
0
        return NULL;
43
0
}
44
45
0
char **strv_copy(char * const *l) {
46
0
        char **r, **k;
47
48
0
        k = r = malloc(sizeof(char *) * (strv_length(l) + 1));
49
0
        if (!r)
50
0
                return NULL;
51
52
0
        if (l)
53
0
                for (; *l; k++, l++) {
54
0
                        *k = strdup(*l);
55
0
                        if (!*k) {
56
0
                                strv_free(r);
57
0
                                return NULL;
58
0
                        }
59
0
                }
60
61
0
        *k = NULL;
62
0
        return r;
63
0
}
64
65
0
unsigned strv_length(char * const *l) {
66
0
        unsigned n = 0;
67
68
0
        if (!l)
69
0
                return 0;
70
71
0
        for (; *l; l++)
72
0
                n++;
73
74
0
        return n;
75
0
}
76
77
0
static char **strv_new_ap(const char *x, va_list ap) {
78
0
        const char *s;
79
0
        char **a;
80
0
        unsigned n = 0, i = 0;
81
0
        va_list aq;
82
83
        /* As a special trick we ignore all listed strings that equal
84
         * (const char*) -1. This is supposed to be used with the
85
         * STRV_IFNOTNULL() macro to include possibly NULL strings in
86
         * the string list. */
87
88
0
        if (x) {
89
0
                n = x == (const char*) -1 ? 0 : 1;
90
91
0
                va_copy(aq, ap);
92
0
                while ((s = va_arg(aq, const char*))) {
93
0
                        if (s == (const char*) -1)
94
0
                                continue;
95
96
0
                        n++;
97
0
                }
98
99
0
                va_end(aq);
100
0
        }
101
102
0
        a = malloc(sizeof(char *) * (n + 1));
103
0
        if (!a)
104
0
                return NULL;
105
106
0
        if (x) {
107
0
                if (x != (const char*) -1) {
108
0
                        a[i] = strdup(x);
109
0
                        if (!a[i])
110
0
                                goto fail;
111
0
                        i++;
112
0
                }
113
114
0
                while ((s = va_arg(ap, const char*))) {
115
116
0
                        if (s == (const char*) -1)
117
0
                                continue;
118
119
0
                        a[i] = strdup(s);
120
0
                        if (!a[i])
121
0
                                goto fail;
122
123
0
                        i++;
124
0
                }
125
0
        }
126
127
0
        a[i] = NULL;
128
129
0
        return a;
130
131
0
fail:
132
0
        strv_free(a);
133
0
        return NULL;
134
0
}
135
136
0
char **strv_new(const char *x, ...) {
137
0
        char **r;
138
0
        va_list ap;
139
140
0
        va_start(ap, x);
141
0
        r = strv_new_ap(x, ap);
142
0
        va_end(ap);
143
144
0
        return r;
145
0
}
146
147
0
int strv_extend_strv(char ***a, char **b) {
148
0
        int r;
149
0
        char **s;
150
151
0
        STRV_FOREACH(s, b) {
152
0
                r = strv_extend(a, *s);
153
0
                if (r < 0)
154
0
                        return r;
155
0
        }
156
157
0
        return 0;
158
0
}
159
160
0
int strv_extend_strv_concat(char ***a, char **b, const char *suffix) {
161
0
        int r;
162
0
        char **s;
163
164
0
        STRV_FOREACH(s, b) {
165
0
                char *v;
166
167
0
                v = strconcat(*s, suffix);
168
0
                if (!v)
169
0
                        return -ENOMEM;
170
171
0
                r = strv_push(a, v);
172
0
                if (r < 0) {
173
0
                        free(v);
174
0
                        return r;
175
0
                }
176
0
        }
177
178
0
        return 0;
179
0
}
180
181
182
#define _FOREACH_WORD(word, length, s, separator, quoted, state)        \
183
0
        for ((state) = (s), (word) = split(&(state), &(length), (separator), (quoted)); (word); (word) = split(&(state), &(length), (separator), (quoted)))
184
185
#define FOREACH_WORD_SEPARATOR(word, length, s, separator, state)       \
186
0
        _FOREACH_WORD(word, length, s, separator, false, state)
187
188
189
0
char **strv_split(const char *s, const char *separator) {
190
0
        const char *word, *state;
191
0
        size_t l;
192
0
        unsigned n, i;
193
0
        char **r;
194
195
0
        assert(s);
196
197
0
        n = 0;
198
0
        FOREACH_WORD_SEPARATOR(word, l, s, separator, state)
199
0
                n++;
200
201
0
        r = malloc(sizeof(char *) * (n + 1));
202
0
        if (!r)
203
0
                return NULL;
204
205
0
        i = 0;
206
0
        FOREACH_WORD_SEPARATOR(word, l, s, separator, state) {
207
0
                r[i] = strndup(word, l);
208
0
                if (!r[i]) {
209
0
                        strv_free(r);
210
0
                        return NULL;
211
0
                }
212
213
0
                i++;
214
0
        }
215
216
0
        r[i] = NULL;
217
0
        return r;
218
0
}
219
220
0
char *strv_join(char **l, const char *separator) {
221
0
        char *r, *e;
222
0
        char **s;
223
0
        size_t n, k;
224
225
0
        if (!separator)
226
0
                separator = " ";
227
228
0
        k = strlen(separator);
229
230
0
        n = 0;
231
0
        STRV_FOREACH(s, l) {
232
0
                if (n != 0)
233
0
                        n += k;
234
0
                n += strlen(*s);
235
0
        }
236
237
0
        r = malloc(n + 1);
238
0
        if (!r)
239
0
                return NULL;
240
241
0
        e = r;
242
0
        STRV_FOREACH(s, l) {
243
0
                if (e != r)
244
0
                        e = stpcpy(e, separator);
245
246
0
                e = stpcpy(e, *s);
247
0
        }
248
249
0
        *e = 0;
250
251
0
        return r;
252
0
}
253
254
0
int strv_push(char ***l, char *value) {
255
0
        char **c;
256
0
        unsigned n, m;
257
258
0
        if (!value)
259
0
                return 0;
260
261
0
        n = strv_length(*l);
262
263
        /* Increase and check for overflow */
264
0
        m = n + 2;
265
0
        if (m < n)
266
0
                return -ENOMEM;
267
268
0
        c = reallocarray(*l, m, sizeof(char *));
269
0
        if (!c)
270
0
                return -ENOMEM;
271
272
0
        c[n] = value;
273
0
        c[n+1] = NULL;
274
275
0
        *l = c;
276
0
        return 0;
277
0
}
278
279
0
int strv_push_prepend(char ***l, char *value) {
280
0
        char **c;
281
0
        unsigned n, m, i;
282
283
0
        if (!value)
284
0
                return 0;
285
286
0
        n = strv_length(*l);
287
288
        /* increase and check for overflow */
289
0
        m = n + 2;
290
0
        if (m < n)
291
0
                return -ENOMEM;
292
293
0
        c = malloc(sizeof(char *) * m);
294
0
        if (!c)
295
0
                return -ENOMEM;
296
297
0
        for (i = 0; i < n; i++)
298
0
                c[i+1] = (*l)[i];
299
300
0
        c[0] = value;
301
0
        c[n+1] = NULL;
302
303
0
        free(*l);
304
0
        *l = c;
305
306
0
        return 0;
307
0
}
308
309
0
int strv_consume(char ***l, char *value) {
310
0
        int r;
311
312
0
        r = strv_push(l, value);
313
0
        if (r < 0)
314
0
                free(value);
315
316
0
        return r;
317
0
}
318
319
0
int strv_consume_prepend(char ***l, char *value) {
320
0
        int r;
321
322
0
        r = strv_push_prepend(l, value);
323
0
        if (r < 0)
324
0
                free(value);
325
326
0
        return r;
327
0
}
328
329
0
int strv_extend(char ***l, const char *value) {
330
0
        char *v;
331
332
0
        if (!value)
333
0
                return 0;
334
335
0
        v = strdup(value);
336
0
        if (!v)
337
0
                return -ENOMEM;
338
339
0
        return strv_consume(l, v);
340
0
}
341
342
0
char **strv_remove(char **l, const char *s) {
343
0
        char **f, **t;
344
345
0
        if (!l)
346
0
                return NULL;
347
348
0
        assert(s);
349
350
        /* Drops every occurrence of s in the string list, edits
351
         * in-place. */
352
353
0
        for (f = t = l; *f; f++)
354
0
                if (strcmp(*f, s) == 0)
355
0
                        free(*f);
356
0
                else
357
0
                        *(t++) = *f;
358
359
0
        *t = NULL;
360
0
        return l;
361
0
}
362
363
0
int strv_extendf(char ***l, const char *format, ...) {
364
0
        va_list ap;
365
0
        char *x;
366
0
        int r;
367
368
0
        va_start(ap, format);
369
0
        r = vasprintf(&x, format, ap);
370
0
        va_end(ap);
371
372
0
        if (r < 0)
373
0
                return -ENOMEM;
374
375
0
        return strv_consume(l, x);
376
0
}
377
378
0
int strv_extendv(char ***l, const char *format, va_list ap) {
379
0
        char *x;
380
0
        int r;
381
382
0
        r = vasprintf(&x, format, ap);
383
0
        if (r < 0)
384
0
                return -ENOMEM;
385
386
0
        return strv_consume(l, x);
387
0
}
388
389
0
char **strv_reverse(char **l) {
390
0
        unsigned n, i;
391
392
0
        n = strv_length(l);
393
0
        if (n <= 1)
394
0
                return l;
395
396
0
        for (i = 0; i < n / 2; i++) {
397
0
                char *t;
398
399
0
                t = l[i];
400
0
                l[i] = l[n-1-i];
401
0
                l[n-1-i] = t;
402
0
        }
403
404
0
        return l;
405
0
}