1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright 2016, Olivier MATZ <zer0@droids-corp.org>
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>
24 EC_LOG_TYPE_REGISTER(node_many);
30 struct ec_node *child;
33 static int ec_node_many_parse(const struct ec_node *gen_node,
34 struct ec_parse *state,
35 const struct ec_strvec *strvec)
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;
43 for (count = 0; node->max == 0 || count < node->max; count++) {
44 childvec = ec_strvec_ndup(strvec, off,
45 ec_strvec_len(strvec) - off);
49 ret = ec_node_parse_child(node->child, state, childvec);
53 ec_strvec_free(childvec);
56 if (ret == EC_PARSE_NOMATCH)
59 /* it matches an empty strvec, no need to continue */
61 child_parse = ec_parse_get_last_child(state);
62 ec_parse_unlink_child(state, child_parse);
63 ec_parse_free(child_parse);
70 if (count < node->min) {
71 ec_parse_free_children(state);
72 return EC_PARSE_NOMATCH;
78 ec_strvec_free(childvec);
83 __ec_node_many_complete(struct ec_node_many *node, unsigned int max,
85 const struct ec_strvec *strvec)
87 struct ec_parse *parse = ec_comp_get_state(comp);
88 struct ec_strvec *childvec = NULL;
92 /* first, try to complete with the child node */
93 ret = ec_node_complete_child(node->child, comp, strvec);
97 /* we're done, we reached the max number of nodes */
101 /* if there is a maximum, decrease it before recursion */
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)
112 ret = ec_node_parse_child(node->child, parse, childvec);
116 ec_strvec_free(childvec);
119 if ((unsigned int)ret != i) {
120 if (ret != EC_PARSE_NOMATCH)
121 ec_parse_del_last_child(parse);
125 childvec = ec_strvec_ndup(strvec, i, ec_strvec_len(strvec) - i);
126 if (childvec == NULL) {
127 ec_parse_del_last_child(parse);
131 ret = __ec_node_many_complete(node, max, comp, childvec);
132 ec_parse_del_last_child(parse);
133 ec_strvec_free(childvec);
143 ec_strvec_free(childvec);
148 ec_node_many_complete(const struct ec_node *gen_node,
149 struct ec_comp *comp,
150 const struct ec_strvec *strvec)
152 struct ec_node_many *node = (struct ec_node_many *)gen_node;
154 return __ec_node_many_complete(node, node->max, comp,
158 static void ec_node_many_free_priv(struct ec_node *gen_node)
160 struct ec_node_many *node = (struct ec_node_many *)gen_node;
162 ec_node_free(node->child);
166 ec_node_many_get_children_count(const struct ec_node *gen_node)
168 struct ec_node_many *node = (struct ec_node_many *)gen_node;
176 ec_node_many_get_child(const struct ec_node *gen_node, size_t i,
177 struct ec_node **child, unsigned int *refs)
179 struct ec_node_many *node = (struct ec_node_many *)gen_node;
184 *child = node->child;
189 static const struct ec_config_schema ec_node_many_schema[] = {
192 .desc = "The child node.",
193 .type = EC_CONFIG_TYPE_NODE,
197 .desc = "The minimum number of matches (default = 0).",
198 .type = EC_CONFIG_TYPE_UINT64,
202 .desc = "The maximum number of matches. If 0, there is "
203 "no maximum (default = 0).",
204 .type = EC_CONFIG_TYPE_UINT64,
207 .type = EC_CONFIG_TYPE_NONE,
211 static int ec_node_many_set_config(struct ec_node *gen_node,
212 const struct ec_config *config)
214 struct ec_node_many *node = (struct ec_node_many *)gen_node;
215 const struct ec_config *child, *min, *max;
217 child = ec_config_dict_get(config, "child");
220 if (ec_config_get_type(child) != EC_CONFIG_TYPE_NODE) {
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)) {
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)) {
237 if (node->child != NULL)
238 ec_node_free(node->child);
239 node->child = ec_node_clone(child->node);
243 node->min = min->u64;
247 node->max = max->u64;
255 static struct ec_node_type ec_node_many_type = {
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,
267 EC_NODE_TYPE_REGISTER(ec_node_many_type);
270 ec_node_many_set_params(struct ec_node *gen_node, struct ec_node *child,
271 unsigned int min, unsigned int max)
273 const struct ec_config *cur_config = NULL;
274 struct ec_config *config = NULL;
277 if (ec_node_check_type(gen_node, &ec_node_many_type) < 0)
280 cur_config = ec_node_get_config(gen_node);
281 if (cur_config == NULL)
282 config = ec_config_dict();
284 config = ec_config_dup(cur_config);
288 if (ec_config_dict_set(config, "child", ec_config_node(child)) < 0) {
289 child = NULL; /* freed */
292 child = NULL; /* freed */
294 if (ec_config_dict_set(config, "min", ec_config_u64(min)) < 0)
296 if (ec_config_dict_set(config, "max", ec_config_u64(max)) < 0)
299 ret = ec_node_set_config(gen_node, config);
300 config = NULL; /* freed */
307 ec_config_free(config);
312 struct ec_node *ec_node_many(const char *id, struct ec_node *child,
313 unsigned int min, unsigned int max)
315 struct ec_node *gen_node = NULL;
320 gen_node = ec_node_from_type(&ec_node_many_type, id);
321 if (gen_node == NULL)
324 if (ec_node_many_set_params(gen_node, child, min, max) < 0) {
337 /* LCOV_EXCL_START */
338 static int ec_node_many_testcase(void)
340 struct ec_node *node;
343 node = ec_node_many(EC_NO_ID, ec_node_str(EC_NO_ID, "foo"), 0, 0);
345 EC_LOG(EC_LOG_ERR, "cannot create node\n");
348 testres |= EC_TEST_CHECK_PARSE(node, 0);
349 testres |= EC_TEST_CHECK_PARSE(node, 0, "bar");
350 testres |= EC_TEST_CHECK_PARSE(node, 1, "foo", "bar");
351 testres |= EC_TEST_CHECK_PARSE(node, 2, "foo", "foo", "bar");
352 testres |= EC_TEST_CHECK_PARSE(node, 0);
355 node = ec_node_many(EC_NO_ID, ec_node_str(EC_NO_ID, "foo"), 1, 0);
357 EC_LOG(EC_LOG_ERR, "cannot create node\n");
360 testres |= EC_TEST_CHECK_PARSE(node, -1, "bar");
361 testres |= EC_TEST_CHECK_PARSE(node, 1, "foo", "bar");
362 testres |= EC_TEST_CHECK_PARSE(node, 2, "foo", "foo", "bar");
363 testres |= EC_TEST_CHECK_PARSE(node, -1);
366 node = ec_node_many(EC_NO_ID, ec_node_str(EC_NO_ID, "foo"), 1, 2);
368 EC_LOG(EC_LOG_ERR, "cannot create node\n");
371 testres |= EC_TEST_CHECK_PARSE(node, -1, "bar");
372 testres |= EC_TEST_CHECK_PARSE(node, 1, "foo", "bar");
373 testres |= EC_TEST_CHECK_PARSE(node, 2, "foo", "foo", "bar");
374 testres |= EC_TEST_CHECK_PARSE(node, 2, "foo", "foo", "foo");
375 testres |= EC_TEST_CHECK_PARSE(node, -1);
378 /* test completion */
379 node = ec_node_many(EC_NO_ID, ec_node_str(EC_NO_ID, "foo"), 2, 4);
381 EC_LOG(EC_LOG_ERR, "cannot create node\n");
384 testres |= EC_TEST_CHECK_COMPLETE(node,
386 "foo", EC_NODE_ENDLIST);
387 testres |= EC_TEST_CHECK_COMPLETE(node,
388 "f", EC_NODE_ENDLIST,
389 "foo", EC_NODE_ENDLIST);
390 testres |= EC_TEST_CHECK_COMPLETE(node,
391 "foo", EC_NODE_ENDLIST,
392 "foo", EC_NODE_ENDLIST);
393 testres |= EC_TEST_CHECK_COMPLETE(node,
394 "foo", "", EC_NODE_ENDLIST,
395 "foo", EC_NODE_ENDLIST);
396 testres |= EC_TEST_CHECK_COMPLETE(node,
397 "foo", "foo", "", EC_NODE_ENDLIST,
398 "foo", EC_NODE_ENDLIST);
399 testres |= EC_TEST_CHECK_COMPLETE(node,
400 "foo", "foo", "foo", "", EC_NODE_ENDLIST,
401 "foo", EC_NODE_ENDLIST);
402 testres |= EC_TEST_CHECK_COMPLETE(node,
403 "foo", "foo", "foo", "foo", "", EC_NODE_ENDLIST,
411 static struct ec_test ec_node_many_test = {
413 .test = ec_node_many_testcase,
416 EC_TEST_REGISTER(ec_node_many_test);