1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright 2016, Olivier MATZ <zer0@droids-corp.org>
10 #include <ecoli_malloc.h>
11 #include <ecoli_test.h>
12 #include <ecoli_log.h>
13 #include <ecoli_strvec.h>
15 EC_LOG_TYPE_REGISTER(strvec);
17 struct ec_strvec_elt {
24 struct ec_strvec_elt **vec;
27 struct ec_strvec *ec_strvec(void)
29 struct ec_strvec *strvec;
31 strvec = ec_calloc(1, sizeof(*strvec));
38 int ec_strvec_add(struct ec_strvec *strvec, const char *s)
40 struct ec_strvec_elt *elt, **new_vec;
42 new_vec = ec_realloc(strvec->vec,
43 sizeof(*strvec->vec) * (strvec->len + 1));
47 strvec->vec = new_vec;
49 elt = ec_malloc(sizeof(*elt));
53 elt->str = ec_strdup(s);
54 if (elt->str == NULL) {
60 new_vec[strvec->len] = elt;
65 struct ec_strvec *ec_strvec_from_array(const char * const *strarr,
68 struct ec_strvec *strvec = NULL;
72 for (i = 0; i < n; i++) {
73 if (ec_strvec_add(strvec, strarr[i]) < 0)
80 ec_strvec_free(strvec);
84 int ec_strvec_del_last(struct ec_strvec *strvec)
86 struct ec_strvec_elt *elt;
88 if (strvec->len == 0) {
93 elt = strvec->vec[strvec->len - 1];
95 if (elt->refcnt == 0) {
103 struct ec_strvec *ec_strvec_ndup(const struct ec_strvec *strvec, size_t off,
106 struct ec_strvec *copy = NULL;
109 veclen = ec_strvec_len(strvec);
110 if (off + len > veclen)
120 copy->vec = ec_calloc(len, sizeof(*copy->vec));
121 if (copy->vec == NULL)
124 for (i = 0; i < len; i++) {
125 copy->vec[i] = strvec->vec[i + off];
126 copy->vec[i]->refcnt++;
133 ec_strvec_free(copy);
137 struct ec_strvec *ec_strvec_dup(const struct ec_strvec *strvec)
139 return ec_strvec_ndup(strvec, 0, ec_strvec_len(strvec));
142 void ec_strvec_free(struct ec_strvec *strvec)
144 struct ec_strvec_elt *elt;
150 for (i = 0; i < ec_strvec_len(strvec); i++) {
151 elt = strvec->vec[i];
153 if (elt->refcnt == 0) {
159 ec_free(strvec->vec);
163 size_t ec_strvec_len(const struct ec_strvec *strvec)
168 const char *ec_strvec_val(const struct ec_strvec *strvec, size_t idx)
170 if (strvec == NULL || idx >= strvec->len)
173 return strvec->vec[idx]->str;
176 int ec_strvec_cmp(const struct ec_strvec *strvec1,
177 const struct ec_strvec *strvec2)
181 if (ec_strvec_len(strvec1) != ec_strvec_len(strvec2))
184 for (i = 0; i < ec_strvec_len(strvec1); i++) {
185 if (strcmp(ec_strvec_val(strvec1, i),
186 ec_strvec_val(strvec2, i)))
193 void ec_strvec_dump(FILE *out, const struct ec_strvec *strvec)
197 if (strvec == NULL) {
198 fprintf(out, "none\n");
202 fprintf(out, "strvec (len=%zu) [", strvec->len);
203 for (i = 0; i < ec_strvec_len(strvec); i++) {
205 fprintf(out, "%s", strvec->vec[i]->str);
207 fprintf(out, ", %s", strvec->vec[i]->str);
213 /* LCOV_EXCL_START */
214 static int ec_strvec_testcase(void)
216 struct ec_strvec *strvec = NULL;
217 struct ec_strvec *strvec2 = NULL;
219 strvec = ec_strvec();
220 if (strvec == NULL) {
221 EC_TEST_ERR("cannot create strvec\n");
224 if (ec_strvec_len(strvec) != 0) {
225 EC_TEST_ERR("bad strvec len (0)\n");
228 if (ec_strvec_add(strvec, "0") < 0) {
229 EC_TEST_ERR("cannot add (0) in strvec\n");
232 if (ec_strvec_len(strvec) != 1) {
233 EC_TEST_ERR("bad strvec len (1)\n");
236 if (ec_strvec_add(strvec, "1") < 0) {
237 EC_TEST_ERR("cannot add (1) in strvec\n");
240 if (ec_strvec_len(strvec) != 2) {
241 EC_TEST_ERR("bad strvec len (2)\n");
244 if (strcmp(ec_strvec_val(strvec, 0), "0")) {
245 EC_TEST_ERR("invalid element in strvec (0)\n");
248 if (strcmp(ec_strvec_val(strvec, 1), "1")) {
249 EC_TEST_ERR("invalid element in strvec (1)\n");
252 if (ec_strvec_val(strvec, 2) != NULL) {
253 EC_TEST_ERR("strvec val should be NULL\n");
257 strvec2 = ec_strvec_dup(strvec);
258 if (strvec2 == NULL) {
259 EC_TEST_ERR("cannot create strvec2\n");
262 if (ec_strvec_len(strvec2) != 2) {
263 EC_TEST_ERR("bad strvec2 len (2)\n");
266 if (strcmp(ec_strvec_val(strvec2, 0), "0")) {
267 EC_TEST_ERR("invalid element in strvec2 (0)\n");
270 if (strcmp(ec_strvec_val(strvec2, 1), "1")) {
271 EC_TEST_ERR("invalid element in strvec2 (1)\n");
274 if (ec_strvec_val(strvec2, 2) != NULL) {
275 EC_TEST_ERR("strvec2 val should be NULL\n");
278 ec_strvec_free(strvec2);
280 strvec2 = ec_strvec_ndup(strvec, 0, 0);
281 if (strvec2 == NULL) {
282 EC_TEST_ERR("cannot create strvec2\n");
285 if (ec_strvec_len(strvec2) != 0) {
286 EC_TEST_ERR("bad strvec2 len (0)\n");
289 if (ec_strvec_val(strvec2, 0) != NULL) {
290 EC_TEST_ERR("strvec2 val should be NULL\n");
293 ec_strvec_free(strvec2);
295 strvec2 = ec_strvec_ndup(strvec, 1, 1);
296 if (strvec2 == NULL) {
297 EC_TEST_ERR("cannot create strvec2\n");
300 if (ec_strvec_len(strvec2) != 1) {
301 EC_TEST_ERR("bad strvec2 len (1)\n");
304 if (strcmp(ec_strvec_val(strvec2, 0), "1")) {
305 EC_TEST_ERR("invalid element in strvec2 (1)\n");
308 if (ec_strvec_val(strvec2, 1) != NULL) {
309 EC_TEST_ERR("strvec2 val should be NULL\n");
312 ec_strvec_free(strvec2);
314 strvec2 = ec_strvec_ndup(strvec, 3, 1);
315 if (strvec2 != NULL) {
316 EC_TEST_ERR("strvec2 should be NULL\n");
319 ec_strvec_free(strvec2);
321 ec_strvec_dump(stdout, strvec);
322 ec_strvec_dump(stdout, NULL);
324 ec_strvec_free(strvec);
329 ec_strvec_free(strvec);
330 ec_strvec_free(strvec2);
335 static struct ec_test ec_node_str_test = {
337 .test = ec_strvec_testcase,
340 EC_TEST_REGISTER(ec_node_str_test);