2 * Copyright (c) 2016, Olivier MATZ <zer0@droids-corp.org>
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the University of California, Berkeley nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 #include <sys/types.h>
33 #include <ecoli_malloc.h>
34 #include <ecoli_test.h>
35 #include <ecoli_log.h>
36 #include <ecoli_strvec.h>
38 EC_LOG_TYPE_REGISTER(strvec);
40 struct ec_strvec_elt {
47 struct ec_strvec_elt **vec;
50 struct ec_strvec *ec_strvec(void)
52 struct ec_strvec *strvec;
54 strvec = ec_calloc(1, sizeof(*strvec));
61 int ec_strvec_add(struct ec_strvec *strvec, const char *s)
63 struct ec_strvec_elt *elt, **new_vec;
65 new_vec = ec_realloc(strvec->vec,
66 sizeof(*strvec->vec) * (strvec->len + 1));
70 strvec->vec = new_vec;
72 elt = ec_malloc(sizeof(*elt));
76 elt->str = ec_strdup(s);
77 if (elt->str == NULL) {
83 new_vec[strvec->len] = elt;
88 struct ec_strvec *ec_strvec_from_array(const char * const *strarr,
91 struct ec_strvec *strvec = NULL;
95 for (i = 0; i < n; i++) {
96 if (ec_strvec_add(strvec, strarr[i]) < 0)
103 ec_strvec_free(strvec);
107 int ec_strvec_del_last(struct ec_strvec *strvec)
109 struct ec_strvec_elt *elt;
111 if (strvec->len == 0) {
116 elt = strvec->vec[strvec->len - 1];
118 if (elt->refcnt == 0) {
126 struct ec_strvec *ec_strvec_ndup(const struct ec_strvec *strvec, size_t off,
129 struct ec_strvec *copy = NULL;
132 veclen = ec_strvec_len(strvec);
133 if (off + len > veclen)
143 copy->vec = ec_calloc(len, sizeof(*copy->vec));
144 if (copy->vec == NULL)
147 for (i = 0; i < len; i++) {
148 copy->vec[i] = strvec->vec[i + off];
149 copy->vec[i]->refcnt++;
156 ec_strvec_free(copy);
160 struct ec_strvec *ec_strvec_dup(const struct ec_strvec *strvec)
162 return ec_strvec_ndup(strvec, 0, ec_strvec_len(strvec));
165 void ec_strvec_free(struct ec_strvec *strvec)
167 struct ec_strvec_elt *elt;
173 for (i = 0; i < ec_strvec_len(strvec); i++) {
174 elt = strvec->vec[i];
176 if (elt->refcnt == 0) {
182 ec_free(strvec->vec);
186 size_t ec_strvec_len(const struct ec_strvec *strvec)
191 const char *ec_strvec_val(const struct ec_strvec *strvec, size_t idx)
193 if (strvec == NULL || idx >= strvec->len)
196 return strvec->vec[idx]->str;
199 int ec_strvec_cmp(const struct ec_strvec *strvec1,
200 const struct ec_strvec *strvec2)
204 if (ec_strvec_len(strvec1) != ec_strvec_len(strvec2))
207 for (i = 0; i < ec_strvec_len(strvec1); i++) {
208 if (strcmp(ec_strvec_val(strvec1, i),
209 ec_strvec_val(strvec2, i)))
216 void ec_strvec_dump(FILE *out, const struct ec_strvec *strvec)
220 if (strvec == NULL) {
221 fprintf(out, "none\n");
225 fprintf(out, "strvec (len=%zu) [", strvec->len);
226 for (i = 0; i < ec_strvec_len(strvec); i++) {
228 fprintf(out, "%s", strvec->vec[i]->str);
230 fprintf(out, ", %s", strvec->vec[i]->str);
236 /* LCOV_EXCL_START */
237 static int ec_strvec_testcase(void)
239 struct ec_strvec *strvec = NULL;
240 struct ec_strvec *strvec2 = NULL;
242 strvec = ec_strvec();
243 if (strvec == NULL) {
244 EC_TEST_ERR("cannot create strvec\n");
247 if (ec_strvec_len(strvec) != 0) {
248 EC_TEST_ERR("bad strvec len (0)\n");
251 if (ec_strvec_add(strvec, "0") < 0) {
252 EC_TEST_ERR("cannot add (0) in strvec\n");
255 if (ec_strvec_len(strvec) != 1) {
256 EC_TEST_ERR("bad strvec len (1)\n");
259 if (ec_strvec_add(strvec, "1") < 0) {
260 EC_TEST_ERR("cannot add (1) in strvec\n");
263 if (ec_strvec_len(strvec) != 2) {
264 EC_TEST_ERR("bad strvec len (2)\n");
267 if (strcmp(ec_strvec_val(strvec, 0), "0")) {
268 EC_TEST_ERR("invalid element in strvec (0)\n");
271 if (strcmp(ec_strvec_val(strvec, 1), "1")) {
272 EC_TEST_ERR("invalid element in strvec (1)\n");
275 if (ec_strvec_val(strvec, 2) != NULL) {
276 EC_TEST_ERR("strvec val should be NULL\n");
280 strvec2 = ec_strvec_dup(strvec);
281 if (strvec2 == NULL) {
282 EC_TEST_ERR("cannot create strvec2\n");
285 if (ec_strvec_len(strvec2) != 2) {
286 EC_TEST_ERR("bad strvec2 len (2)\n");
289 if (strcmp(ec_strvec_val(strvec2, 0), "0")) {
290 EC_TEST_ERR("invalid element in strvec2 (0)\n");
293 if (strcmp(ec_strvec_val(strvec2, 1), "1")) {
294 EC_TEST_ERR("invalid element in strvec2 (1)\n");
297 if (ec_strvec_val(strvec2, 2) != NULL) {
298 EC_TEST_ERR("strvec2 val should be NULL\n");
301 ec_strvec_free(strvec2);
303 strvec2 = ec_strvec_ndup(strvec, 0, 0);
304 if (strvec2 == NULL) {
305 EC_TEST_ERR("cannot create strvec2\n");
308 if (ec_strvec_len(strvec2) != 0) {
309 EC_TEST_ERR("bad strvec2 len (0)\n");
312 if (ec_strvec_val(strvec2, 0) != NULL) {
313 EC_TEST_ERR("strvec2 val should be NULL\n");
316 ec_strvec_free(strvec2);
318 strvec2 = ec_strvec_ndup(strvec, 1, 1);
319 if (strvec2 == NULL) {
320 EC_TEST_ERR("cannot create strvec2\n");
323 if (ec_strvec_len(strvec2) != 1) {
324 EC_TEST_ERR("bad strvec2 len (1)\n");
327 if (strcmp(ec_strvec_val(strvec2, 0), "1")) {
328 EC_TEST_ERR("invalid element in strvec2 (1)\n");
331 if (ec_strvec_val(strvec2, 1) != NULL) {
332 EC_TEST_ERR("strvec2 val should be NULL\n");
335 ec_strvec_free(strvec2);
337 strvec2 = ec_strvec_ndup(strvec, 3, 1);
338 if (strvec2 != NULL) {
339 EC_TEST_ERR("strvec2 should be NULL\n");
342 ec_strvec_free(strvec2);
344 ec_strvec_dump(stdout, strvec);
345 ec_strvec_dump(stdout, NULL);
347 ec_strvec_free(strvec);
352 ec_strvec_free(strvec);
353 ec_strvec_free(strvec2);
358 static struct ec_test ec_node_str_test = {
360 .test = ec_strvec_testcase,
363 EC_TEST_REGISTER(ec_node_str_test);