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;
223 strvec = ec_strvec();
224 if (strvec == NULL) {
225 EC_TEST_ERR("cannot create strvec\n");
228 if (ec_strvec_len(strvec) != 0) {
229 EC_TEST_ERR("bad strvec len (0)\n");
232 if (ec_strvec_add(strvec, "0") < 0) {
233 EC_TEST_ERR("cannot add (0) in strvec\n");
236 if (ec_strvec_len(strvec) != 1) {
237 EC_TEST_ERR("bad strvec len (1)\n");
240 if (ec_strvec_add(strvec, "1") < 0) {
241 EC_TEST_ERR("cannot add (1) in strvec\n");
244 if (ec_strvec_len(strvec) != 2) {
245 EC_TEST_ERR("bad strvec len (2)\n");
248 if (strcmp(ec_strvec_val(strvec, 0), "0")) {
249 EC_TEST_ERR("invalid element in strvec (0)\n");
252 if (strcmp(ec_strvec_val(strvec, 1), "1")) {
253 EC_TEST_ERR("invalid element in strvec (1)\n");
256 if (ec_strvec_val(strvec, 2) != NULL) {
257 EC_TEST_ERR("strvec val should be NULL\n");
261 strvec2 = ec_strvec_dup(strvec);
262 if (strvec2 == NULL) {
263 EC_TEST_ERR("cannot create strvec2\n");
266 if (ec_strvec_len(strvec2) != 2) {
267 EC_TEST_ERR("bad strvec2 len (2)\n");
270 if (strcmp(ec_strvec_val(strvec2, 0), "0")) {
271 EC_TEST_ERR("invalid element in strvec2 (0)\n");
274 if (strcmp(ec_strvec_val(strvec2, 1), "1")) {
275 EC_TEST_ERR("invalid element in strvec2 (1)\n");
278 if (ec_strvec_val(strvec2, 2) != NULL) {
279 EC_TEST_ERR("strvec2 val should be NULL\n");
282 ec_strvec_free(strvec2);
284 strvec2 = ec_strvec_ndup(strvec, 0, 0);
285 if (strvec2 == NULL) {
286 EC_TEST_ERR("cannot create strvec2\n");
289 if (ec_strvec_len(strvec2) != 0) {
290 EC_TEST_ERR("bad strvec2 len (0)\n");
293 if (ec_strvec_val(strvec2, 0) != NULL) {
294 EC_TEST_ERR("strvec2 val should be NULL\n");
297 ec_strvec_free(strvec2);
299 strvec2 = ec_strvec_ndup(strvec, 1, 1);
300 if (strvec2 == NULL) {
301 EC_TEST_ERR("cannot create strvec2\n");
304 if (ec_strvec_len(strvec2) != 1) {
305 EC_TEST_ERR("bad strvec2 len (1)\n");
308 if (strcmp(ec_strvec_val(strvec2, 0), "1")) {
309 EC_TEST_ERR("invalid element in strvec2 (1)\n");
312 if (ec_strvec_val(strvec2, 1) != NULL) {
313 EC_TEST_ERR("strvec2 val should be NULL\n");
316 ec_strvec_free(strvec2);
318 strvec2 = ec_strvec_ndup(strvec, 3, 1);
319 if (strvec2 != NULL) {
320 EC_TEST_ERR("strvec2 should be NULL\n");
323 ec_strvec_free(strvec2);
325 strvec2 = EC_STRVEC("0", "1");
326 if (strvec2 == NULL) {
327 EC_TEST_ERR("cannot create strvec from array\n");
330 testres |= EC_TEST_CHECK(ec_strvec_cmp(strvec, strvec2) == 0,
331 "strvec and strvec2 should be equal\n");
332 ec_strvec_free(strvec2);
334 f = open_memstream(&buf, &buflen);
337 ec_strvec_dump(f, strvec);
340 testres |= EC_TEST_CHECK(
341 strstr(buf, "strvec (len=2) [0, 1]"), "bad dump\n");
345 f = open_memstream(&buf, &buflen);
348 ec_strvec_dump(f, NULL);
351 testres |= EC_TEST_CHECK(
352 strstr(buf, "none"), "bad dump\n");
356 ec_strvec_free(strvec);
363 ec_strvec_free(strvec);
364 ec_strvec_free(strvec2);
371 static struct ec_test ec_node_str_test = {
373 .test = ec_strvec_testcase,
376 EC_TEST_REGISTER(ec_node_str_test);