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;
75 for (i = 0; i < n; i++) {
76 if (ec_strvec_add(strvec, strarr[i]) < 0)
83 ec_strvec_free(strvec);
87 int ec_strvec_del_last(struct ec_strvec *strvec)
89 struct ec_strvec_elt *elt;
91 if (strvec->len == 0) {
96 elt = strvec->vec[strvec->len - 1];
98 if (elt->refcnt == 0) {
106 struct ec_strvec *ec_strvec_ndup(const struct ec_strvec *strvec, size_t off,
109 struct ec_strvec *copy = NULL;
112 veclen = ec_strvec_len(strvec);
113 if (off + len > veclen)
123 copy->vec = ec_calloc(len, sizeof(*copy->vec));
124 if (copy->vec == NULL)
127 for (i = 0; i < len; i++) {
128 copy->vec[i] = strvec->vec[i + off];
129 copy->vec[i]->refcnt++;
136 ec_strvec_free(copy);
140 struct ec_strvec *ec_strvec_dup(const struct ec_strvec *strvec)
142 return ec_strvec_ndup(strvec, 0, ec_strvec_len(strvec));
145 void ec_strvec_free(struct ec_strvec *strvec)
147 struct ec_strvec_elt *elt;
153 for (i = 0; i < ec_strvec_len(strvec); i++) {
154 elt = strvec->vec[i];
156 if (elt->refcnt == 0) {
162 ec_free(strvec->vec);
166 size_t ec_strvec_len(const struct ec_strvec *strvec)
171 const char *ec_strvec_val(const struct ec_strvec *strvec, size_t idx)
173 if (strvec == NULL || idx >= strvec->len)
176 return strvec->vec[idx]->str;
179 int ec_strvec_cmp(const struct ec_strvec *strvec1,
180 const struct ec_strvec *strvec2)
184 if (ec_strvec_len(strvec1) != ec_strvec_len(strvec2))
187 for (i = 0; i < ec_strvec_len(strvec1); i++) {
188 if (strcmp(ec_strvec_val(strvec1, i),
189 ec_strvec_val(strvec2, i)))
196 void ec_strvec_dump(FILE *out, const struct ec_strvec *strvec)
200 if (strvec == NULL) {
201 fprintf(out, "none\n");
205 fprintf(out, "strvec (len=%zu) [", strvec->len);
206 for (i = 0; i < ec_strvec_len(strvec); i++) {
208 fprintf(out, "%s", strvec->vec[i]->str);
210 fprintf(out, ", %s", strvec->vec[i]->str);
216 /* LCOV_EXCL_START */
217 static int ec_strvec_testcase(void)
219 struct ec_strvec *strvec = NULL;
220 struct ec_strvec *strvec2 = NULL;
226 strvec = ec_strvec();
227 if (strvec == NULL) {
228 EC_TEST_ERR("cannot create strvec\n");
231 if (ec_strvec_len(strvec) != 0) {
232 EC_TEST_ERR("bad strvec len (0)\n");
235 if (ec_strvec_add(strvec, "0") < 0) {
236 EC_TEST_ERR("cannot add (0) in strvec\n");
239 if (ec_strvec_len(strvec) != 1) {
240 EC_TEST_ERR("bad strvec len (1)\n");
243 if (ec_strvec_add(strvec, "1") < 0) {
244 EC_TEST_ERR("cannot add (1) in strvec\n");
247 if (ec_strvec_len(strvec) != 2) {
248 EC_TEST_ERR("bad strvec len (2)\n");
251 if (strcmp(ec_strvec_val(strvec, 0), "0")) {
252 EC_TEST_ERR("invalid element in strvec (0)\n");
255 if (strcmp(ec_strvec_val(strvec, 1), "1")) {
256 EC_TEST_ERR("invalid element in strvec (1)\n");
259 if (ec_strvec_val(strvec, 2) != NULL) {
260 EC_TEST_ERR("strvec val should be NULL\n");
264 strvec2 = ec_strvec_dup(strvec);
265 if (strvec2 == NULL) {
266 EC_TEST_ERR("cannot create strvec2\n");
269 if (ec_strvec_len(strvec2) != 2) {
270 EC_TEST_ERR("bad strvec2 len (2)\n");
273 if (strcmp(ec_strvec_val(strvec2, 0), "0")) {
274 EC_TEST_ERR("invalid element in strvec2 (0)\n");
277 if (strcmp(ec_strvec_val(strvec2, 1), "1")) {
278 EC_TEST_ERR("invalid element in strvec2 (1)\n");
281 if (ec_strvec_val(strvec2, 2) != NULL) {
282 EC_TEST_ERR("strvec2 val should be NULL\n");
285 ec_strvec_free(strvec2);
287 strvec2 = ec_strvec_ndup(strvec, 0, 0);
288 if (strvec2 == NULL) {
289 EC_TEST_ERR("cannot create strvec2\n");
292 if (ec_strvec_len(strvec2) != 0) {
293 EC_TEST_ERR("bad strvec2 len (0)\n");
296 if (ec_strvec_val(strvec2, 0) != NULL) {
297 EC_TEST_ERR("strvec2 val should be NULL\n");
300 ec_strvec_free(strvec2);
302 strvec2 = ec_strvec_ndup(strvec, 1, 1);
303 if (strvec2 == NULL) {
304 EC_TEST_ERR("cannot create strvec2\n");
307 if (ec_strvec_len(strvec2) != 1) {
308 EC_TEST_ERR("bad strvec2 len (1)\n");
311 if (strcmp(ec_strvec_val(strvec2, 0), "1")) {
312 EC_TEST_ERR("invalid element in strvec2 (1)\n");
315 if (ec_strvec_val(strvec2, 1) != NULL) {
316 EC_TEST_ERR("strvec2 val should be NULL\n");
319 ec_strvec_free(strvec2);
321 strvec2 = ec_strvec_ndup(strvec, 3, 1);
322 if (strvec2 != NULL) {
323 EC_TEST_ERR("strvec2 should be NULL\n");
326 ec_strvec_free(strvec2);
328 strvec2 = EC_STRVEC("0", "1");
329 if (strvec2 == NULL) {
330 EC_TEST_ERR("cannot create strvec from array\n");
333 testres |= EC_TEST_CHECK(ec_strvec_cmp(strvec, strvec2) == 0,
334 "strvec and strvec2 should be equal\n");
335 ec_strvec_free(strvec2);
337 f = open_memstream(&buf, &buflen);
340 ec_strvec_dump(f, strvec);
343 testres |= EC_TEST_CHECK(
344 strstr(buf, "strvec (len=2) [0, 1]"), "bad dump\n");
348 ec_strvec_del_last(strvec);
349 strvec2 = EC_STRVEC("0");
350 if (strvec2 == NULL) {
351 EC_TEST_ERR("cannot create strvec from array\n");
354 testres |= EC_TEST_CHECK(ec_strvec_cmp(strvec, strvec2) == 0,
355 "strvec and strvec2 should be equal\n");
356 ec_strvec_free(strvec2);
358 f = open_memstream(&buf, &buflen);
361 ec_strvec_dump(f, NULL);
364 testres |= EC_TEST_CHECK(
365 strstr(buf, "none"), "bad dump\n");
369 ec_strvec_free(strvec);
376 ec_strvec_free(strvec);
377 ec_strvec_free(strvec2);
384 static struct ec_test ec_node_str_test = {
386 .test = ec_strvec_testcase,
389 EC_TEST_REGISTER(ec_node_str_test);