fix minor leaks
[protos/libecoli.git] / src / ecoli_node_many.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright 2016, Olivier MATZ <zer0@droids-corp.org>
3  */
4
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <string.h>
8 #include <assert.h>
9 #include <stdarg.h>
10 #include <errno.h>
11
12 #include <ecoli_malloc.h>
13 #include <ecoli_log.h>
14 #include <ecoli_test.h>
15 #include <ecoli_strvec.h>
16 #include <ecoli_node.h>
17 #include <ecoli_parse.h>
18 #include <ecoli_complete.h>
19 #include <ecoli_node_str.h>
20 #include <ecoli_node_option.h>
21 #include <ecoli_config.h>
22 #include <ecoli_node_many.h>
23
24 EC_LOG_TYPE_REGISTER(node_many);
25
26 struct ec_node_many {
27         struct ec_node gen;
28         unsigned int min;
29         unsigned int max;
30         struct ec_node *child;
31 };
32
33 static int ec_node_many_parse(const struct ec_node *gen_node,
34                         struct ec_parse *state,
35                         const struct ec_strvec *strvec)
36 {
37         struct ec_node_many *node = (struct ec_node_many *)gen_node;
38         struct ec_parse *child_parse;
39         struct ec_strvec *childvec = NULL;
40         size_t off = 0, count;
41         int ret;
42
43         for (count = 0; node->max == 0 || count < node->max; count++) {
44                 childvec = ec_strvec_ndup(strvec, off,
45                         ec_strvec_len(strvec) - off);
46                 if (childvec == NULL)
47                         goto fail;
48
49                 ret = ec_node_parse_child(node->child, state, childvec);
50                 if (ret < 0)
51                         goto fail;
52
53                 ec_strvec_free(childvec);
54                 childvec = NULL;
55
56                 if (ret == EC_PARSE_NOMATCH)
57                         break;
58
59                 /* it matches an empty strvec, no need to continue */
60                 if (ret == 0) {
61                         child_parse = ec_parse_get_last_child(state);
62                         ec_parse_unlink_child(state, child_parse);
63                         ec_parse_free(child_parse);
64                         break;
65                 }
66
67                 off += ret;
68         }
69
70         if (count < node->min) {
71                 ec_parse_free_children(state);
72                 return EC_PARSE_NOMATCH;
73         }
74
75         return off;
76
77 fail:
78         ec_strvec_free(childvec);
79         return -1;
80 }
81
82 static int
83 __ec_node_many_complete(struct ec_node_many *node, unsigned int max,
84                         struct ec_comp *comp,
85                         const struct ec_strvec *strvec)
86 {
87         struct ec_parse *parse = ec_comp_get_state(comp);
88         struct ec_strvec *childvec = NULL;
89         unsigned int i;
90         int ret;
91
92         /* first, try to complete with the child node */
93         ret = ec_node_complete_child(node->child, comp, strvec);
94         if (ret < 0)
95                 goto fail;
96
97         /* we're done, we reached the max number of nodes */
98         if (max == 1)
99                 return 0;
100
101         /* if there is a maximum, decrease it before recursion */
102         if (max != 0)
103                 max--;
104
105         /* then, if the node matches the beginning of the strvec, try to
106          * complete the rest */
107         for (i = 0; i < ec_strvec_len(strvec); i++) {
108                 childvec = ec_strvec_ndup(strvec, 0, i);
109                 if (childvec == NULL)
110                         goto fail;
111
112                 ret = ec_node_parse_child(node->child, parse, childvec);
113                 if (ret < 0)
114                         goto fail;
115
116                 ec_strvec_free(childvec);
117                 childvec = NULL;
118
119                 if ((unsigned int)ret != i) {
120                         if (ret != EC_PARSE_NOMATCH)
121                                 ec_parse_del_last_child(parse);
122                         continue;
123                 }
124
125                 childvec = ec_strvec_ndup(strvec, i, ec_strvec_len(strvec) - i);
126                 if (childvec == NULL) {
127                         ec_parse_del_last_child(parse);
128                         goto fail;
129                 }
130
131                 ret = __ec_node_many_complete(node, max, comp, childvec);
132                 ec_parse_del_last_child(parse);
133                 ec_strvec_free(childvec);
134                 childvec = NULL;
135
136                 if (ret < 0)
137                         goto fail;
138         }
139
140         return 0;
141
142 fail:
143         ec_strvec_free(childvec);
144         return -1;
145 }
146
147 static int
148 ec_node_many_complete(const struct ec_node *gen_node,
149                 struct ec_comp *comp,
150                 const struct ec_strvec *strvec)
151 {
152         struct ec_node_many *node = (struct ec_node_many *)gen_node;
153
154         return __ec_node_many_complete(node, node->max, comp,
155                                 strvec);
156 }
157
158 static void ec_node_many_free_priv(struct ec_node *gen_node)
159 {
160         struct ec_node_many *node = (struct ec_node_many *)gen_node;
161
162         ec_node_free(node->child);
163 }
164
165 static size_t
166 ec_node_many_get_children_count(const struct ec_node *gen_node)
167 {
168         struct ec_node_many *node = (struct ec_node_many *)gen_node;
169
170         if (node->child)
171                 return 1;
172         return 0;
173 }
174
175 static int
176 ec_node_many_get_child(const struct ec_node *gen_node, size_t i,
177                 struct ec_node **child, unsigned int *refs)
178 {
179         struct ec_node_many *node = (struct ec_node_many *)gen_node;
180
181         if (i >= 1)
182                 return -1;
183
184         *child = node->child;
185         *refs = 2;
186         return 0;
187 }
188
189 static const struct ec_config_schema ec_node_many_schema[] = {
190         {
191                 .key = "child",
192                 .desc = "The child node.",
193                 .type = EC_CONFIG_TYPE_NODE,
194         },
195         {
196                 .key = "min",
197                 .desc = "The minimum number of matches (default = 0).",
198                 .type = EC_CONFIG_TYPE_UINT64,
199         },
200         {
201                 .key = "max",
202                 .desc = "The maximum number of matches. If 0, there is "
203                 "no maximum (default = 0).",
204                 .type = EC_CONFIG_TYPE_UINT64,
205         },
206         {
207                 .type = EC_CONFIG_TYPE_NONE,
208         },
209 };
210
211 static int ec_node_many_set_config(struct ec_node *gen_node,
212                                 const struct ec_config *config)
213 {
214         struct ec_node_many *node = (struct ec_node_many *)gen_node;
215         const struct ec_config *child, *min, *max;
216
217         child = ec_config_dict_get(config, "child");
218         if (child == NULL)
219                 goto fail;
220         if (ec_config_get_type(child) != EC_CONFIG_TYPE_NODE) {
221                 errno = EINVAL;
222                 goto fail;
223         }
224         min = ec_config_dict_get(config, "min");
225         if (min != NULL && (ec_config_get_type(min) != EC_CONFIG_TYPE_UINT64 ||
226                                 min->u64 >= UINT_MAX)) {
227                 errno = EINVAL;
228                 goto fail;
229         }
230         max = ec_config_dict_get(config, "max");
231         if (max != NULL && (ec_config_get_type(max) != EC_CONFIG_TYPE_UINT64 ||
232                                 max->u64 >= UINT_MAX)) {
233                 errno = EINVAL;
234                 goto fail;
235         }
236
237         if (node->child != NULL)
238                 ec_node_free(node->child);
239         node->child = ec_node_clone(child->node);
240         if (min == NULL)
241                 node->min = 0;
242         else
243                 node->min = min->u64;
244         if (max == NULL)
245                 node->max = 0;
246         else
247                 node->max = max->u64;
248
249         return 0;
250
251 fail:
252         return -1;
253 }
254
255 static struct ec_node_type ec_node_many_type = {
256         .name = "many",
257         .schema = ec_node_many_schema,
258         .set_config = ec_node_many_set_config,
259         .parse = ec_node_many_parse,
260         .complete = ec_node_many_complete,
261         .size = sizeof(struct ec_node_many),
262         .free_priv = ec_node_many_free_priv,
263         .get_children_count = ec_node_many_get_children_count,
264         .get_child = ec_node_many_get_child,
265 };
266
267 EC_NODE_TYPE_REGISTER(ec_node_many_type);
268
269 int
270 ec_node_many_set_params(struct ec_node *gen_node, struct ec_node *child,
271         unsigned int min, unsigned int max)
272 {
273         const struct ec_config *cur_config = NULL;
274         struct ec_config *config = NULL;
275         int ret;
276
277         if (ec_node_check_type(gen_node, &ec_node_many_type) < 0)
278                 goto fail;
279
280         cur_config = ec_node_get_config(gen_node);
281         if (cur_config == NULL)
282                 config = ec_config_dict();
283         else
284                 config = ec_config_dup(cur_config);
285         if (config == NULL)
286                 goto fail;
287
288         if (ec_config_dict_set(config, "child", ec_config_node(child)) < 0) {
289                 child = NULL; /* freed */
290                 goto fail;
291         }
292         child = NULL; /* freed */
293
294         if (ec_config_dict_set(config, "min", ec_config_u64(min)) < 0)
295                 goto fail;
296         if (ec_config_dict_set(config, "max", ec_config_u64(max)) < 0)
297                 goto fail;
298
299         ret = ec_node_set_config(gen_node, config);
300         config = NULL; /* freed */
301         if (ret < 0)
302                 goto fail;
303
304         return 0;
305
306 fail:
307         ec_config_free(config);
308         ec_node_free(child);
309         return -1;
310 }
311
312 struct ec_node *ec_node_many(const char *id, struct ec_node *child,
313         unsigned int min, unsigned int max)
314 {
315         struct ec_node *gen_node = NULL;
316
317         if (child == NULL)
318                 return NULL;
319
320         gen_node = ec_node_from_type(&ec_node_many_type, id);
321         if (gen_node == NULL)
322                 goto fail;
323
324         if (ec_node_many_set_params(gen_node, child, min, max) < 0) {
325                 child = NULL;
326                 goto fail;
327         }
328         child = NULL;
329
330         return gen_node;
331
332 fail:
333         ec_node_free(gen_node);
334         ec_node_free(child);
335         return NULL;
336 }
337
338 /* LCOV_EXCL_START */
339 static int ec_node_many_testcase(void)
340 {
341         struct ec_node *node;
342         int testres = 0;
343
344         node = ec_node_many(EC_NO_ID, ec_node_str(EC_NO_ID, "foo"), 0, 0);
345         if (node == NULL) {
346                 EC_LOG(EC_LOG_ERR, "cannot create node\n");
347                 return -1;
348         }
349         testres |= EC_TEST_CHECK_PARSE(node, 0);
350         testres |= EC_TEST_CHECK_PARSE(node, 0, "bar");
351         testres |= EC_TEST_CHECK_PARSE(node, 1, "foo", "bar");
352         testres |= EC_TEST_CHECK_PARSE(node, 2, "foo", "foo", "bar");
353         testres |= EC_TEST_CHECK_PARSE(node, 0);
354         ec_node_free(node);
355
356         node = ec_node_many(EC_NO_ID, ec_node_str(EC_NO_ID, "foo"), 1, 0);
357         if (node == NULL) {
358                 EC_LOG(EC_LOG_ERR, "cannot create node\n");
359                 return -1;
360         }
361         testres |= EC_TEST_CHECK_PARSE(node, -1, "bar");
362         testres |= EC_TEST_CHECK_PARSE(node, 1, "foo", "bar");
363         testres |= EC_TEST_CHECK_PARSE(node, 2, "foo", "foo", "bar");
364         testres |= EC_TEST_CHECK_PARSE(node, -1);
365         ec_node_free(node);
366
367         node = ec_node_many(EC_NO_ID, ec_node_str(EC_NO_ID, "foo"), 1, 2);
368         if (node == NULL) {
369                 EC_LOG(EC_LOG_ERR, "cannot create node\n");
370                 return -1;
371         }
372         testres |= EC_TEST_CHECK_PARSE(node, -1, "bar");
373         testres |= EC_TEST_CHECK_PARSE(node, 1, "foo", "bar");
374         testres |= EC_TEST_CHECK_PARSE(node, 2, "foo", "foo", "bar");
375         testres |= EC_TEST_CHECK_PARSE(node, 2, "foo", "foo", "foo");
376         testres |= EC_TEST_CHECK_PARSE(node, -1);
377         ec_node_free(node);
378
379         /* test completion */
380         node = ec_node_many(EC_NO_ID, ec_node_str(EC_NO_ID, "foo"), 2, 4);
381         if (node == NULL) {
382                 EC_LOG(EC_LOG_ERR, "cannot create node\n");
383                 return -1;
384         }
385         testres |= EC_TEST_CHECK_COMPLETE(node,
386                 "", EC_NODE_ENDLIST,
387                 "foo", EC_NODE_ENDLIST);
388         testres |= EC_TEST_CHECK_COMPLETE(node,
389                 "f", EC_NODE_ENDLIST,
390                 "foo", EC_NODE_ENDLIST);
391         testres |= EC_TEST_CHECK_COMPLETE(node,
392                 "foo", EC_NODE_ENDLIST,
393                 "foo", EC_NODE_ENDLIST);
394         testres |= EC_TEST_CHECK_COMPLETE(node,
395                 "foo", "", EC_NODE_ENDLIST,
396                 "foo", EC_NODE_ENDLIST);
397         testres |= EC_TEST_CHECK_COMPLETE(node,
398                 "foo", "foo", "", EC_NODE_ENDLIST,
399                 "foo", EC_NODE_ENDLIST);
400         testres |= EC_TEST_CHECK_COMPLETE(node,
401                 "foo", "foo", "foo", "", EC_NODE_ENDLIST,
402                 "foo", EC_NODE_ENDLIST);
403         testres |= EC_TEST_CHECK_COMPLETE(node,
404                 "foo", "foo", "foo", "foo", "", EC_NODE_ENDLIST,
405                 EC_NODE_ENDLIST);
406         ec_node_free(node);
407
408         return testres;
409 }
410 /* LCOV_EXCL_STOP */
411
412 static struct ec_test ec_node_many_test = {
413         .name = "node_many",
414         .test = ec_node_many_testcase,
415 };
416
417 EC_TEST_REGISTER(ec_node_many_test);