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_strvec.h>
35 #include <ecoli_test.h>
36 #include <ecoli_log.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_ndup(const struct ec_strvec *strvec, size_t off,
91 struct ec_strvec *copy = NULL;
94 if (off + len > ec_strvec_len(strvec)) {
106 copy->vec = ec_calloc(len, sizeof(*copy->vec));
107 if (copy->vec == NULL)
110 for (i = 0; i < len; i++) {
111 copy->vec[i] = strvec->vec[i + off];
112 copy->vec[i]->refcnt++;
119 ec_strvec_free(copy);
123 struct ec_strvec *ec_strvec_dup(const struct ec_strvec *strvec)
125 return ec_strvec_ndup(strvec, 0, ec_strvec_len(strvec));
128 void ec_strvec_free(struct ec_strvec *strvec)
130 struct ec_strvec_elt *elt;
136 for (i = 0; i < ec_strvec_len(strvec); i++) {
137 elt = strvec->vec[i];
139 if (elt->refcnt == 0) {
145 ec_free(strvec->vec);
149 size_t ec_strvec_len(const struct ec_strvec *strvec)
157 const char *ec_strvec_val(const struct ec_strvec *strvec, size_t idx)
159 if (strvec == NULL || idx >= strvec->len)
162 return strvec->vec[idx]->str;
165 void ec_strvec_dump(FILE *out, const struct ec_strvec *strvec)
169 if (strvec == NULL) {
170 fprintf(out, "none\n");
174 fprintf(out, "strvec (len=%zu) [", strvec->len);
175 for (i = 0; i < ec_strvec_len(strvec); i++) {
177 fprintf(out, "%s", strvec->vec[i]->str);
179 fprintf(out, ", %s", strvec->vec[i]->str);
185 /* LCOV_EXCL_START */
186 static int ec_strvec_testcase(void)
188 struct ec_strvec *strvec = NULL;
189 struct ec_strvec *strvec2 = NULL;
191 strvec = ec_strvec();
192 if (strvec == NULL) {
193 EC_TEST_ERR("cannot create strvec\n");
196 if (ec_strvec_len(strvec) != 0) {
197 EC_TEST_ERR("bad strvec len (0)\n");
200 if (ec_strvec_add(strvec, "0") < 0) {
201 EC_TEST_ERR("cannot add (0) in strvec\n");
204 if (ec_strvec_len(strvec) != 1) {
205 EC_TEST_ERR("bad strvec len (1)\n");
208 if (ec_strvec_add(strvec, "1") < 0) {
209 EC_TEST_ERR("cannot add (1) in strvec\n");
212 if (ec_strvec_len(strvec) != 2) {
213 EC_TEST_ERR("bad strvec len (2)\n");
216 if (strcmp(ec_strvec_val(strvec, 0), "0")) {
217 EC_TEST_ERR("invalid element in strvec (0)\n");
220 if (strcmp(ec_strvec_val(strvec, 1), "1")) {
221 EC_TEST_ERR("invalid element in strvec (1)\n");
224 if (ec_strvec_val(strvec, 2) != NULL) {
225 EC_TEST_ERR("strvec val should be NULL\n");
229 strvec2 = ec_strvec_dup(strvec);
230 if (strvec2 == NULL) {
231 EC_TEST_ERR("cannot create strvec2\n");
234 if (ec_strvec_len(strvec2) != 2) {
235 EC_TEST_ERR("bad strvec2 len (2)\n");
238 if (strcmp(ec_strvec_val(strvec2, 0), "0")) {
239 EC_TEST_ERR("invalid element in strvec2 (0)\n");
242 if (strcmp(ec_strvec_val(strvec2, 1), "1")) {
243 EC_TEST_ERR("invalid element in strvec2 (1)\n");
246 if (ec_strvec_val(strvec2, 2) != NULL) {
247 EC_TEST_ERR("strvec2 val should be NULL\n");
250 ec_strvec_free(strvec2);
252 strvec2 = ec_strvec_ndup(strvec, 0, 0);
253 if (strvec2 == NULL) {
254 EC_TEST_ERR("cannot create strvec2\n");
257 if (ec_strvec_len(strvec2) != 0) {
258 EC_TEST_ERR("bad strvec2 len (0)\n");
261 if (ec_strvec_val(strvec2, 0) != NULL) {
262 EC_TEST_ERR("strvec2 val should be NULL\n");
265 ec_strvec_free(strvec2);
267 strvec2 = ec_strvec_ndup(strvec, 1, 1);
268 if (strvec2 == NULL) {
269 EC_TEST_ERR("cannot create strvec2\n");
272 if (ec_strvec_len(strvec2) != 1) {
273 EC_TEST_ERR("bad strvec2 len (1)\n");
276 if (strcmp(ec_strvec_val(strvec2, 0), "1")) {
277 EC_TEST_ERR("invalid element in strvec2 (1)\n");
280 if (ec_strvec_val(strvec2, 1) != NULL) {
281 EC_TEST_ERR("strvec2 val should be NULL\n");
284 ec_strvec_free(strvec2);
286 strvec2 = ec_strvec_ndup(strvec, 3, 1);
287 if (strvec2 != NULL) {
288 EC_TEST_ERR("strvec2 should be NULL\n");
291 ec_strvec_free(strvec2);
293 ec_strvec_dump(stdout, strvec);
294 ec_strvec_dump(stdout, NULL);
296 ec_strvec_free(strvec);
301 ec_strvec_free(strvec);
302 ec_strvec_free(strvec2);
307 static struct ec_test ec_node_str_test = {
309 .test = ec_strvec_testcase,
312 EC_TEST_REGISTER(ec_node_str_test);