save
[protos/libecoli.git] / lib / ecoli_strvec.c
1 /*
2  * Copyright (c) 2016, Olivier MATZ <zer0@droids-corp.org>
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *
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.
15  *
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.
26  */
27
28 #include <sys/types.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <errno.h>
32
33 #include <ecoli_malloc.h>
34 #include <ecoli_test.h>
35 #include <ecoli_log.h>
36 #include <ecoli_vec.h>
37 #include <ecoli_strvec.h>
38
39 EC_LOG_TYPE_REGISTER(strvec);
40
41 struct ec_strvec_elt {
42         unsigned int refcnt;
43         char *str;
44 };
45
46 struct ec_strvec;
47
48 static void ec_strvec_elt_free(void *ptr)
49 {
50         struct ec_strvec_elt **p_elt = ptr;
51         struct ec_strvec_elt *elt = *p_elt;
52
53         elt->refcnt--;
54         if (elt->refcnt == 0) {
55                 ec_free(elt->str);
56                 ec_free(elt);
57         }
58 }
59
60 static void ec_strvec_elt_copy(void *dst, void *src)
61 {
62         struct ec_strvec_elt **p_elt_dst = dst, **p_elt_src = src;
63         struct ec_strvec_elt *elt = *p_elt_src;
64
65         elt->refcnt++;
66         *p_elt_dst = elt;
67 }
68
69 struct ec_strvec *ec_strvec(void)
70 {
71         struct ec_vec *vec;
72
73         vec = ec_vec(sizeof(struct ec_strvec_elt *), 0,
74                 ec_strvec_elt_copy, ec_strvec_elt_free);
75
76         return (struct ec_strvec *)vec;
77 }
78
79 int ec_strvec_add(struct ec_strvec *strvec, const char *s)
80 {
81         struct ec_strvec_elt *elt = NULL;
82
83         elt = ec_malloc(sizeof(*elt));
84         if (elt == NULL)
85                 goto fail;
86
87         elt->str = ec_strdup(s);
88         if (elt->str == NULL)
89                 goto fail;
90         elt->refcnt = 1;
91
92         if (ec_vec_add_ptr((struct ec_vec *)strvec, elt) < 0)
93                 goto fail;
94
95         return 0;
96
97 fail:
98         ec_free(elt);
99         return -1;
100 }
101
102 struct ec_strvec *ec_strvec_ndup(const struct ec_strvec *strvec, size_t off,
103         size_t len)
104 {
105         return (struct ec_strvec *)ec_vec_ndup((struct ec_vec *)strvec,
106                                         off, len);
107 }
108
109 struct ec_strvec *ec_strvec_dup(const struct ec_strvec *strvec)
110 {
111         return (struct ec_strvec *)ec_vec_dup((struct ec_vec *)strvec);
112 }
113
114 void ec_strvec_free(struct ec_strvec *strvec)
115 {
116         ec_vec_free((struct ec_vec *)strvec);
117 }
118
119 size_t ec_strvec_len(const struct ec_strvec *strvec)
120 {
121         return ec_vec_len((struct ec_vec *)strvec);
122 }
123
124 const char *ec_strvec_val(const struct ec_strvec *strvec, size_t idx)
125 {
126         struct ec_strvec_elt *elt;
127
128         if (ec_vec_get(&elt, (struct ec_vec *)strvec, idx) < 0)
129                 return NULL;
130
131         return elt->str;
132 }
133
134 void ec_strvec_dump(FILE *out, const struct ec_strvec *strvec)
135 {
136         const char *s;
137         size_t i;
138
139         if (strvec == NULL) {
140                 fprintf(out, "none\n");
141                 return;
142         }
143
144         fprintf(out, "strvec (len=%zu) [", ec_strvec_len(strvec));
145         for (i = 0; i < ec_strvec_len(strvec); i++) {
146                 s = ec_strvec_val(strvec, i);
147                 if (i == 0)
148                         fprintf(out, "%s", s);
149                 else
150                         fprintf(out, ", %s", s);
151         }
152         fprintf(out, "]\n");
153
154 }
155
156 /* LCOV_EXCL_START */
157 static int ec_strvec_testcase(void)
158 {
159         struct ec_strvec *strvec = NULL;
160         struct ec_strvec *strvec2 = NULL;
161
162         strvec = ec_strvec();
163         if (strvec == NULL) {
164                 EC_TEST_ERR("cannot create strvec\n");
165                 goto fail;
166         }
167         if (ec_strvec_len(strvec) != 0) {
168                 EC_TEST_ERR("bad strvec len (0)\n");
169                 goto fail;
170         }
171         if (ec_strvec_add(strvec, "0") < 0) {
172                 EC_TEST_ERR("cannot add (0) in strvec\n");
173                 goto fail;
174         }
175         if (ec_strvec_len(strvec) != 1) {
176                 EC_TEST_ERR("bad strvec len (1)\n");
177                 goto fail;
178         }
179         if (ec_strvec_add(strvec, "1") < 0) {
180                 EC_TEST_ERR("cannot add (1) in strvec\n");
181                 goto fail;
182         }
183         if (ec_strvec_len(strvec) != 2) {
184                 EC_TEST_ERR("bad strvec len (2)\n");
185                 goto fail;
186         }
187         if (strcmp(ec_strvec_val(strvec, 0), "0")) {
188                 EC_TEST_ERR("invalid element in strvec (0)\n");
189                 goto fail;
190         }
191         if (strcmp(ec_strvec_val(strvec, 1), "1")) {
192                 EC_TEST_ERR("invalid element in strvec (1)\n");
193                 goto fail;
194         }
195         if (ec_strvec_val(strvec, 2) != NULL) {
196                 EC_TEST_ERR("strvec val should be NULL\n");
197                 goto fail;
198         }
199
200         strvec2 = ec_strvec_dup(strvec);
201         if (strvec2 == NULL) {
202                 EC_TEST_ERR("cannot create strvec2\n");
203                 goto fail;
204         }
205         if (ec_strvec_len(strvec2) != 2) {
206                 EC_TEST_ERR("bad strvec2 len (2)\n");
207                 goto fail;
208         }
209         if (strcmp(ec_strvec_val(strvec2, 0), "0")) {
210                 EC_TEST_ERR("invalid element in strvec2 (0)\n");
211                 goto fail;
212         }
213         if (strcmp(ec_strvec_val(strvec2, 1), "1")) {
214                 EC_TEST_ERR("invalid element in strvec2 (1)\n");
215                 goto fail;
216         }
217         if (ec_strvec_val(strvec2, 2) != NULL) {
218                 EC_TEST_ERR("strvec2 val should be NULL\n");
219                 goto fail;
220         }
221         ec_strvec_free(strvec2);
222
223         strvec2 = ec_strvec_ndup(strvec, 0, 0);
224         if (strvec2 == NULL) {
225                 EC_TEST_ERR("cannot create strvec2\n");
226                 goto fail;
227         }
228         if (ec_strvec_len(strvec2) != 0) {
229                 EC_TEST_ERR("bad strvec2 len (0)\n");
230                 goto fail;
231         }
232         if (ec_strvec_val(strvec2, 0) != NULL) {
233                 EC_TEST_ERR("strvec2 val should be NULL\n");
234                 goto fail;
235         }
236         ec_strvec_free(strvec2);
237
238         strvec2 = ec_strvec_ndup(strvec, 1, 1);
239         if (strvec2 == NULL) {
240                 EC_TEST_ERR("cannot create strvec2\n");
241                 goto fail;
242         }
243         if (ec_strvec_len(strvec2) != 1) {
244                 EC_TEST_ERR("bad strvec2 len (1)\n");
245                 goto fail;
246         }
247         if (strcmp(ec_strvec_val(strvec2, 0), "1")) {
248                 EC_TEST_ERR("invalid element in strvec2 (1)\n");
249                 goto fail;
250         }
251         if (ec_strvec_val(strvec2, 1) != NULL) {
252                 EC_TEST_ERR("strvec2 val should be NULL\n");
253                 goto fail;
254         }
255         ec_strvec_free(strvec2);
256
257         strvec2 = ec_strvec_ndup(strvec, 3, 1);
258         if (strvec2 != NULL) {
259                 EC_TEST_ERR("strvec2 should be NULL\n");
260                 goto fail;
261         }
262         ec_strvec_free(strvec2);
263
264         ec_strvec_dump(stdout, strvec);
265         ec_strvec_dump(stdout, NULL);
266
267         ec_strvec_free(strvec);
268
269         return 0;
270
271 fail:
272         ec_strvec_free(strvec);
273         ec_strvec_free(strvec2);
274         return -1;
275 }
276 /* LCOV_EXCL_STOP */
277
278 static struct ec_test ec_node_str_test = {
279         .name = "strvec",
280         .test = ec_strvec_testcase,
281 };
282
283 EC_TEST_REGISTER(ec_node_str_test);