Coverage Report

Created: 2026-02-22 06:11

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/util-linux/lib/strv.c
Line
Count
Source
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
static void ul_strv_clear(char **l)
28
0
{
29
0
        char **k;
30
31
0
        if (!l)
32
0
                return;
33
34
0
        for (k = l; *k; k++)
35
0
                free(*k);
36
37
0
        *l = NULL;
38
0
}
39
40
char **ul_strv_free(char **l)
41
0
{
42
0
        ul_strv_clear(l);
43
0
        free(l);
44
0
        return NULL;
45
0
}
46
47
char **ul_strv_copy(char * const *l)
48
0
{
49
0
        char **r, **k;
50
51
0
        k = r = malloc(sizeof(char *) * (ul_strv_length(l) + 1));
52
0
        if (!r)
53
0
                return NULL;
54
55
0
        if (l)
56
0
                for (; *l; k++, l++) {
57
0
                        *k = strdup(*l);
58
0
                        if (!*k) {
59
0
                                ul_strv_free(r);
60
0
                                return NULL;
61
0
                        }
62
0
                }
63
64
0
        *k = NULL;
65
0
        return r;
66
0
}
67
68
0
unsigned ul_strv_length(char * const *l) {
69
0
        unsigned n = 0;
70
71
0
        if (!l)
72
0
                return 0;
73
74
0
        for (; *l; l++)
75
0
                n++;
76
77
0
        return n;
78
0
}
79
80
static char **ul_strv_new_ap(const char *x, va_list ap)
81
0
{
82
0
        const char *s;
83
0
        char **a;
84
0
        unsigned n = 0, i = 0;
85
0
        va_list aq;
86
87
        /* As a special trick we ignore all listed strings that equal
88
         * (const char*) -1. This is supposed to be used with the
89
         * UL_STRV_IFNOTNULL() macro to include possibly NULL strings in
90
         * the string list. */
91
92
0
        if (x) {
93
0
                n = x == (const char*) -1 ? 0 : 1;
94
95
0
                va_copy(aq, ap);
96
0
                while ((s = va_arg(aq, const char*))) {
97
0
                        if (s == (const char*) -1)
98
0
                                continue;
99
100
0
                        n++;
101
0
                }
102
103
0
                va_end(aq);
104
0
        }
105
106
0
        a = malloc(sizeof(char *) * (n + 1));
107
0
        if (!a)
108
0
                return NULL;
109
110
0
        if (x) {
111
0
                if (x != (const char*) -1) {
112
0
                        a[i] = strdup(x);
113
0
                        if (!a[i])
114
0
                                goto fail;
115
0
                        i++;
116
0
                }
117
118
0
                while ((s = va_arg(ap, const char*))) {
119
120
0
                        if (s == (const char*) -1)
121
0
                                continue;
122
123
0
                        a[i] = strdup(s);
124
0
                        if (!a[i])
125
0
                                goto fail;
126
127
0
                        i++;
128
0
                }
129
0
        }
130
131
0
        a[i] = NULL;
132
133
0
        return a;
134
135
0
fail:
136
0
        ul_strv_free(a);
137
0
        return NULL;
138
0
}
139
140
char **ul_strv_new(const char *x, ...)
141
0
{
142
0
        char **r;
143
0
        va_list ap;
144
145
0
        va_start(ap, x);
146
0
        r = ul_strv_new_ap(x, ap);
147
0
        va_end(ap);
148
149
0
        return r;
150
0
}
151
152
int ul_strv_extend_strv(char ***a, char **b)
153
0
{
154
0
        int r;
155
0
        char **s;
156
157
0
        UL_STRV_FOREACH(s, b) {
158
0
                r = ul_strv_extend(a, *s);
159
0
                if (r < 0)
160
0
                        return r;
161
0
        }
162
163
0
        return 0;
164
0
}
165
166
int ul_strv_extend_strv_concat(char ***a, char **b, const char *suffix)
167
0
{
168
0
        int r;
169
0
        char **s;
170
171
0
        UL_STRV_FOREACH(s, b) {
172
0
                char *v;
173
174
0
                v = ul_strconcat(*s, suffix);
175
0
                if (!v)
176
0
                        return -ENOMEM;
177
178
0
                r = ul_strv_push(a, v);
179
0
                if (r < 0) {
180
0
                        free(v);
181
0
                        return r;
182
0
                }
183
0
        }
184
185
0
        return 0;
186
0
}
187
188
189
#define _FOREACH_WORD(word, length, s, separator, quoted, state)        \
190
0
        for ((state) = (s), (word) = ul_split(&(state), &(length), (separator), (quoted)); (word); (word) = ul_split(&(state), &(length), (separator), (quoted)))
191
192
#define FOREACH_WORD_SEPARATOR(word, length, s, separator, state)       \
193
0
        _FOREACH_WORD(word, length, s, separator, false, state)
194
195
196
char **ul_strv_split(const char *s, const char *separator)
197
0
{
198
0
        const char *word, *state;
199
0
        size_t l;
200
0
        unsigned n, i;
201
0
        char **r;
202
203
0
        assert(s);
204
205
0
        n = 0;
206
0
        FOREACH_WORD_SEPARATOR(word, l, s, separator, state)
207
0
                n++;
208
209
0
        r = malloc(sizeof(char *) * (n + 1));
210
0
        if (!r)
211
0
                return NULL;
212
213
0
        i = 0;
214
0
        FOREACH_WORD_SEPARATOR(word, l, s, separator, state) {
215
0
                r[i] = strndup(word, l);
216
0
                if (!r[i]) {
217
0
                        ul_strv_free(r);
218
0
                        return NULL;
219
0
                }
220
221
0
                i++;
222
0
        }
223
224
0
        r[i] = NULL;
225
0
        return r;
226
0
}
227
228
char *ul_strv_join(char **l, const char *separator)
229
0
{
230
0
        char *r, *e;
231
0
        char **s;
232
0
        size_t n, k;
233
234
0
        if (!separator)
235
0
                separator = " ";
236
237
0
        k = strlen(separator);
238
239
0
        n = 0;
240
0
        UL_STRV_FOREACH(s, l) {
241
0
                if (n != 0)
242
0
                        n += k;
243
0
                n += strlen(*s);
244
0
        }
245
246
0
        r = malloc(n + 1);
247
0
        if (!r)
248
0
                return NULL;
249
250
0
        e = r;
251
0
        UL_STRV_FOREACH(s, l) {
252
0
                if (e != r)
253
0
                        e = stpcpy(e, separator);
254
255
0
                e = stpcpy(e, *s);
256
0
        }
257
258
0
        *e = 0;
259
260
0
        return r;
261
0
}
262
263
int ul_strv_push(char ***l, char *value)
264
0
{
265
0
        char **c;
266
0
        unsigned n, m;
267
268
0
        if (!value)
269
0
                return 0;
270
271
0
        n = ul_strv_length(*l);
272
273
        /* Increase and check for overflow */
274
0
        m = n + 2;
275
0
        if (m < n)
276
0
                return -ENOMEM;
277
278
0
        c = reallocarray(*l, m, sizeof(char *));
279
0
        if (!c)
280
0
                return -ENOMEM;
281
282
0
        c[n] = value;
283
0
        c[n+1] = NULL;
284
285
0
        *l = c;
286
0
        return 0;
287
0
}
288
289
int ul_strv_push_prepend(char ***l, char *value)
290
0
{
291
0
        char **c;
292
0
        unsigned n, m, i;
293
294
0
        if (!value)
295
0
                return 0;
296
297
0
        n = ul_strv_length(*l);
298
299
        /* increase and check for overflow */
300
0
        m = n + 2;
301
0
        if (m < n)
302
0
                return -ENOMEM;
303
304
0
        c = malloc(sizeof(char *) * m);
305
0
        if (!c)
306
0
                return -ENOMEM;
307
308
0
        for (i = 0; i < n; i++)
309
0
                c[i+1] = (*l)[i];
310
311
0
        c[0] = value;
312
0
        c[n+1] = NULL;
313
314
0
        free(*l);
315
0
        *l = c;
316
317
0
        return 0;
318
0
}
319
320
int ul_strv_consume(char ***l, char *value)
321
0
{
322
0
        int r;
323
324
0
        r = ul_strv_push(l, value);
325
0
        if (r < 0)
326
0
                free(value);
327
328
0
        return r;
329
0
}
330
331
int ul_strv_consume_prepend(char ***l, char *value)
332
0
{
333
0
        int r;
334
335
0
        r = ul_strv_push_prepend(l, value);
336
0
        if (r < 0)
337
0
                free(value);
338
339
0
        return r;
340
0
}
341
342
int ul_strv_extend(char ***l, const char *value)
343
0
{
344
0
        char *v;
345
346
0
        if (!value)
347
0
                return 0;
348
349
0
        v = strdup(value);
350
0
        if (!v)
351
0
                return -ENOMEM;
352
353
0
        return ul_strv_consume(l, v);
354
0
}
355
356
char **ul_strv_remove(char **l, const char *s)
357
0
{
358
0
        char **f, **t;
359
360
0
        if (!l)
361
0
                return NULL;
362
363
0
        assert(s);
364
365
        /* Drops every occurrence of s in the string list, edits
366
         * in-place. */
367
368
0
        for (f = t = l; *f; f++)
369
0
                if (strcmp(*f, s) == 0)
370
0
                        free(*f);
371
0
                else
372
0
                        *(t++) = *f;
373
374
0
        *t = NULL;
375
0
        return l;
376
0
}
377
378
int ul_strv_extendf(char ***l, const char *format, ...)
379
0
{
380
0
        va_list ap;
381
0
        char *x;
382
0
        int r;
383
384
0
        va_start(ap, format);
385
0
        r = vasprintf(&x, format, ap);
386
0
        va_end(ap);
387
388
0
        if (r < 0)
389
0
                return -ENOMEM;
390
391
0
        return ul_strv_consume(l, x);
392
0
}
393
394
int ul_strv_extendv(char ***l, const char *format, va_list ap)
395
0
{
396
0
        char *x;
397
0
        int r;
398
399
0
        r = vasprintf(&x, format, ap);
400
0
        if (r < 0)
401
0
                return -ENOMEM;
402
403
0
        return ul_strv_consume(l, x);
404
0
}
405
406
char **ul_strv_reverse(char **l)
407
0
{
408
0
        unsigned n, i;
409
410
0
        n = ul_strv_length(l);
411
0
        if (n <= 1)
412
0
                return l;
413
414
0
        for (i = 0; i < n / 2; i++) {
415
0
                char *t;
416
417
0
                t = l[i];
418
0
                l[i] = l[n-1-i];
419
0
                l[n-1-i] = t;
420
0
        }
421
422
0
        return l;
423
0
}