1 /***
2 This file is part of eudev, forked from systemd.
3
4 Copyright 2010 Lennart Poettering
5
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
10
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
18 ***/
19
20 #include <assert.h>
21 #include <stdlib.h>
22 #include <stdarg.h>
23 #include <string.h>
24 #include <errno.h>
25
26 #include "util.h"
27 #include "strv.h"
28
strv_clear(char ** l)29 void strv_clear(char **l) {
30 char **k;
31
32 if (!l)
33 return;
34
35 for (k = l; *k; k++)
36 free(*k);
37
38 *l = NULL;
39 }
40
strv_free(char ** l)41 char **strv_free(char **l) {
42 strv_clear(l);
43 free(l);
44 return NULL;
45 }
46
strv_copy(char * const * l)47 char **strv_copy(char * const *l) {
48 char **r, **k;
49
50 k = r = new(char*, strv_length(l) + 1);
51 if (!r)
52 return NULL;
53
54 if (l)
55 for (; *l; k++, l++) {
56 *k = strdup(*l);
57 if (!*k) {
58 strv_free(r);
59 return NULL;
60 }
61 }
62
63 *k = NULL;
64 return r;
65 }
66
strv_length(char * const * l)67 unsigned strv_length(char * const *l) {
68 unsigned n = 0;
69
70 if (!l)
71 return 0;
72
73 for (; *l; l++)
74 n++;
75
76 return n;
77 }
78
strv_new_ap(const char * x,va_list ap)79 char **strv_new_ap(const char *x, va_list ap) {
80 const char *s;
81 char **a;
82 unsigned n = 0, i = 0;
83 va_list aq;
84
85 /* As a special trick we ignore all listed strings that equal
86 * (const char*) -1. This is supposed to be used with the
87 * STRV_IFNOTNULL() macro to include possibly NULL strings in
88 * the string list. */
89
90 if (x) {
91 n = x == (const char*) -1 ? 0 : 1;
92
93 va_copy(aq, ap);
94 while ((s = va_arg(aq, const char*))) {
95 if (s == (const char*) -1)
96 continue;
97
98 n++;
99 }
100
101 va_end(aq);
102 }
103
104 a = new(char*, n+1);
105 if (!a)
106 return NULL;
107
108 if (x) {
109 if (x != (const char*) -1) {
110 a[i] = strdup(x);
111 if (!a[i])
112 goto fail;
113 i++;
114 }
115
116 while ((s = va_arg(ap, const char*))) {
117
118 if (s == (const char*) -1)
119 continue;
120
121 a[i] = strdup(s);
122 if (!a[i])
123 goto fail;
124
125 i++;
126 }
127 }
128
129 a[i] = NULL;
130
131 return a;
132
133 fail:
134 strv_free(a);
135 return NULL;
136 }
137
strv_new(const char * x,...)138 char **strv_new(const char *x, ...) {
139 char **r;
140 va_list ap;
141
142 va_start(ap, x);
143 r = strv_new_ap(x, ap);
144 va_end(ap);
145
146 return r;
147 }
148
strv_push(char *** l,char * value)149 int strv_push(char ***l, char *value) {
150 char **c;
151 unsigned n, m;
152
153 if (!value)
154 return 0;
155
156 n = strv_length(*l);
157
158 /* increase and check for overflow */
159 m = n + 2;
160 if (m < n)
161 return -ENOMEM;
162
163 c = realloc_multiply(*l, sizeof(char*), m);
164 if (!c)
165 return -ENOMEM;
166
167 c[n] = value;
168 c[n+1] = NULL;
169
170 *l = c;
171 return 0;
172 }
173
strv_consume(char *** l,char * value)174 int strv_consume(char ***l, char *value) {
175 int r;
176
177 r = strv_push(l, value);
178 if (r < 0)
179 free(value);
180
181 return r;
182 }
183
strv_extend(char *** l,const char * value)184 int strv_extend(char ***l, const char *value) {
185 char *v;
186
187 if (!value)
188 return 0;
189
190 v = strdup(value);
191 if (!v)
192 return -ENOMEM;
193
194 return strv_consume(l, v);
195 }
196
strv_uniq(char ** l)197 char **strv_uniq(char **l) {
198 char **i;
199
200 /* Drops duplicate entries. The first identical string will be
201 * kept, the others dropped */
202
203 STRV_FOREACH(i, l)
204 strv_remove(i+1, *i);
205
206 return l;
207 }
208
strv_remove(char ** l,const char * s)209 char **strv_remove(char **l, const char *s) {
210 char **f, **t;
211
212 if (!l)
213 return NULL;
214
215 assert(s);
216
217 /* Drops every occurrence of s in the string list, edits
218 * in-place. */
219
220 for (f = t = l; *f; f++)
221 if (streq(*f, s))
222 free(*f);
223 else
224 *(t++) = *f;
225
226 *t = NULL;
227 return l;
228 }
229