1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright 2016, Olivier MATZ <zer0@droids-corp.org>
14 #include <ecoli_malloc.h>
15 #include <ecoli_log.h>
16 #include <ecoli_test.h>
17 #include <ecoli_strvec.h>
18 #include <ecoli_node.h>
19 #include <ecoli_parse.h>
20 #include <ecoli_complete.h>
21 #include <ecoli_node_expr.h>
22 #include <ecoli_node_str.h>
23 #include <ecoli_node_or.h>
24 #include <ecoli_node_subset.h>
25 #include <ecoli_node_int.h>
26 #include <ecoli_node_many.h>
27 #include <ecoli_node_seq.h>
28 #include <ecoli_node_option.h>
29 #include <ecoli_node_re.h>
30 #include <ecoli_node_re_lex.h>
31 #include <ecoli_node_cmd.h>
33 EC_LOG_TYPE_REGISTER(node_cmd);
37 char *cmd_str; /* the command string. */
38 struct ec_node *cmd; /* the command node. */
39 struct ec_node *lex; /* the lexer node. */
40 struct ec_node *expr; /* the expression parser. */
41 struct ec_node **table; /* table of node referenced in command. */
42 unsigned int len; /* len of the table. */
46 ec_node_cmd_eval_var(void **result, void *userctx,
47 const struct ec_parse *var)
49 const struct ec_strvec *vec;
50 struct ec_node_cmd *node = userctx;
51 struct ec_node *eval = NULL;
57 /* get parsed string vector, it should contain only one str */
58 vec = ec_parse_strvec(var);
59 if (ec_strvec_len(vec) != 1) {
63 str = ec_strvec_val(vec, 0);
65 for (i = 0; i < node->len; i++) {
66 id = ec_node_id(node->table[i]);
71 /* if id matches, use a node provided by the user... */
72 eval = ec_node_clone(node->table[i]);
78 /* ...or create a string node */
80 eval = ec_node_str(EC_NO_ID, str);
91 ec_node_cmd_eval_pre_op(void **result, void *userctx, void *operand,
92 const struct ec_parse *operator)
104 ec_node_cmd_eval_post_op(void **result, void *userctx, void *operand,
105 const struct ec_parse *operator)
107 const struct ec_strvec *vec;
108 struct ec_node *in = operand;;
109 struct ec_node *out = NULL;;
113 /* get parsed string vector, it should contain only one str */
114 vec = ec_parse_strvec(operator);
115 if (ec_strvec_len(vec) != 1) {
120 if (!strcmp(ec_strvec_val(vec, 0), "*")) {
121 out = ec_node_many(EC_NO_ID,
122 ec_node_clone(in), 0, 0);
136 ec_node_cmd_eval_bin_op(void **result, void *userctx, void *operand1,
137 const struct ec_parse *operator, void *operand2)
140 const struct ec_strvec *vec;
141 struct ec_node *out = NULL;
142 struct ec_node *in1 = operand1;
143 struct ec_node *in2 = operand2;
147 /* get parsed string vector, it should contain only one str */
148 vec = ec_parse_strvec(operator);
149 if (ec_strvec_len(vec) > 1) {
154 if (ec_strvec_len(vec) == 0) {
155 if (!strcmp(in1->type->name, "seq")) {
156 if (ec_node_seq_add(in1, ec_node_clone(in2)) < 0)
161 out = EC_NODE_SEQ(EC_NO_ID, ec_node_clone(in1),
169 } else if (!strcmp(ec_strvec_val(vec, 0), "|")) {
170 if (!strcmp(in2->type->name, "or")) {
171 if (ec_node_or_add(in2, ec_node_clone(in1)) < 0)
175 } else if (!strcmp(in1->type->name, "or")) {
176 if (ec_node_or_add(in1, ec_node_clone(in2)) < 0)
181 out = EC_NODE_OR(EC_NO_ID, ec_node_clone(in1),
189 } else if (!strcmp(ec_strvec_val(vec, 0), ",")) {
190 if (!strcmp(in2->type->name, "subset")) {
191 if (ec_node_subset_add(in2, ec_node_clone(in1)) < 0)
195 } else if (!strcmp(in1->type->name, "subset")) {
196 if (ec_node_subset_add(in1, ec_node_clone(in2)) < 0)
201 out = EC_NODE_SUBSET(EC_NO_ID, ec_node_clone(in1),
218 ec_node_cmd_eval_parenthesis(void **result, void *userctx,
219 const struct ec_parse *open_paren,
220 const struct ec_parse *close_paren,
223 const struct ec_strvec *vec;
224 struct ec_node *in = value;;
225 struct ec_node *out = NULL;;
230 /* get parsed string vector, it should contain only one str */
231 vec = ec_parse_strvec(open_paren);
232 if (ec_strvec_len(vec) != 1) {
237 if (!strcmp(ec_strvec_val(vec, 0), "[")) {
238 out = ec_node_option(EC_NO_ID, ec_node_clone(in));
242 } else if (!strcmp(ec_strvec_val(vec, 0), "(")) {
255 ec_node_cmd_eval_free(void *result, void *userctx)
261 static const struct ec_node_expr_eval_ops test_ops = {
262 .eval_var = ec_node_cmd_eval_var,
263 .eval_pre_op = ec_node_cmd_eval_pre_op,
264 .eval_post_op = ec_node_cmd_eval_post_op,
265 .eval_bin_op = ec_node_cmd_eval_bin_op,
266 .eval_parenthesis = ec_node_cmd_eval_parenthesis,
267 .eval_free = ec_node_cmd_eval_free,
270 static int ec_node_cmd_build(struct ec_node_cmd *node)
272 struct ec_node *expr = NULL, *lex = NULL, *cmd = NULL;
273 struct ec_parse *p = NULL;
277 ec_node_free(node->expr);
279 ec_node_free(node->lex);
281 ec_node_free(node->cmd);
284 /* build the expression parser */
285 expr = ec_node("expr", "expr");
288 ret = ec_node_expr_set_val_node(expr, ec_node_re(EC_NO_ID,
292 ret = ec_node_expr_add_bin_op(expr, ec_node_str(EC_NO_ID, ","));
295 ret = ec_node_expr_add_bin_op(expr, ec_node_str(EC_NO_ID, "|"));
298 ret = ec_node_expr_add_bin_op(expr, ec_node("empty", EC_NO_ID));
301 ret = ec_node_expr_add_post_op(expr, ec_node_str(EC_NO_ID, "+"));
304 ret = ec_node_expr_add_post_op(expr, ec_node_str(EC_NO_ID, "*"));
307 ret = ec_node_expr_add_parenthesis(expr, ec_node_str(EC_NO_ID, "["),
308 ec_node_str(EC_NO_ID, "]"));
311 ec_node_expr_add_parenthesis(expr, ec_node_str(EC_NO_ID, "("),
312 ec_node_str(EC_NO_ID, ")"));
316 /* prepend a lexer to the expression node */
317 lex = ec_node_re_lex(EC_NO_ID, ec_node_clone(expr));
321 ret = ec_node_re_lex_add(lex, "[a-zA-Z0-9]+", 1);
324 ret = ec_node_re_lex_add(lex, "[*|,()]", 1);
327 ret = ec_node_re_lex_add(lex, "\\[", 1);
330 ret = ec_node_re_lex_add(lex, "\\]", 1);
333 ret = ec_node_re_lex_add(lex, "[ ]+", 0);
337 /* parse the command expression */
338 p = ec_node_parse(lex, node->cmd_str);
342 if (!ec_parse_matches(p)) {
346 if (!ec_parse_has_child(p)) {
351 ret = ec_node_expr_eval(&result, expr, ec_parse_get_first_child(p),
375 ec_node_cmd_parse(const struct ec_node *gen_node, struct ec_parse *state,
376 const struct ec_strvec *strvec)
378 struct ec_node_cmd *node = (struct ec_node_cmd *)gen_node;
380 return ec_node_parse_child(node->cmd, state, strvec);
384 ec_node_cmd_complete(const struct ec_node *gen_node,
385 struct ec_comp *comp,
386 const struct ec_strvec *strvec)
388 struct ec_node_cmd *node = (struct ec_node_cmd *)gen_node;
390 return ec_node_complete_child(node->cmd, comp, strvec);
393 static void ec_node_cmd_free_priv(struct ec_node *gen_node)
395 struct ec_node_cmd *node = (struct ec_node_cmd *)gen_node;
398 ec_free(node->cmd_str);
399 ec_node_free(node->cmd);
400 ec_node_free(node->expr);
401 ec_node_free(node->lex);
402 for (i = 0; i < node->len; i++)
403 ec_node_free(node->table[i]);
404 ec_free(node->table);
408 static struct ec_node_type ec_node_cmd_type = {
410 .parse = ec_node_cmd_parse,
411 .complete = ec_node_cmd_complete,
412 .size = sizeof(struct ec_node_cmd),
413 .free_priv = ec_node_cmd_free_priv,
416 EC_NODE_TYPE_REGISTER(ec_node_cmd_type);
418 int ec_node_cmd_add_child(struct ec_node *gen_node, struct ec_node *child)
420 struct ec_node_cmd *node = (struct ec_node_cmd *)gen_node;
421 struct ec_node **table;
424 assert(node != NULL);
431 if (ec_node_check_type(gen_node, &ec_node_cmd_type) < 0)
434 if (node->cmd == NULL) {
435 ret = ec_node_cmd_build(node);
440 table = ec_realloc(node->table, (node->len + 1) * sizeof(*node->table));
446 if (ec_node_add_child(gen_node, child) < 0)
449 table[node->len] = child;
459 struct ec_node *__ec_node_cmd(const char *id, const char *cmd, ...)
461 struct ec_node *gen_node = NULL;
462 struct ec_node_cmd *node = NULL;
463 struct ec_node *child;
467 gen_node = __ec_node(&ec_node_cmd_type, id);
468 if (gen_node == NULL)
472 node = (struct ec_node_cmd *)gen_node;
473 node->cmd_str = ec_strdup(cmd);
474 if (node->cmd_str == NULL)
480 for (child = va_arg(ap, struct ec_node *);
481 child != EC_NODE_ENDLIST;
482 child = va_arg(ap, struct ec_node *)) {
484 /* on error, don't quit the loop to avoid leaks */
485 if (fail == 1 || child == NULL ||
486 ec_node_cmd_add_child(&node->gen, child) < 0) {
497 if (ec_node_cmd_build(node) < 0)
503 ec_node_free(gen_node); /* will also free children */
507 struct ec_node *ec_node_cmd(const char *id, const char *cmd_str)
509 return __ec_node_cmd(id, cmd_str, EC_NODE_ENDLIST);
512 /* LCOV_EXCL_START */
513 static int ec_node_cmd_testcase(void)
515 struct ec_node *node;
518 node = EC_NODE_CMD(EC_NO_ID,
519 "command [option] (subset1, subset2, subset3, subset4) x|y z*",
520 ec_node_int("x", 0, 10, 10),
521 ec_node_int("y", 20, 30, 10)
524 EC_LOG(EC_LOG_ERR, "cannot create node\n");
527 testres |= EC_TEST_CHECK_PARSE(node, 2, "command", "1");
528 testres |= EC_TEST_CHECK_PARSE(node, 3, "command", "subset1", "1");
529 testres |= EC_TEST_CHECK_PARSE(node, 4, "command", "subset3", "subset2",
531 testres |= EC_TEST_CHECK_PARSE(node, 5, "command", "subset2", "subset3",
533 testres |= EC_TEST_CHECK_PARSE(node, 6, "command", "subset3", "subset1",
534 "subset4", "subset2", "4");
535 testres |= EC_TEST_CHECK_PARSE(node, 2, "command", "23");
536 testres |= EC_TEST_CHECK_PARSE(node, 3, "command", "option", "23");
537 testres |= EC_TEST_CHECK_PARSE(node, 5, "command", "option", "23",
539 testres |= EC_TEST_CHECK_PARSE(node, -1, "command", "15");
540 testres |= EC_TEST_CHECK_PARSE(node, -1, "foo");
543 node = EC_NODE_CMD(EC_NO_ID, "good morning [count] bob|bobby|michael",
544 ec_node_int("count", 0, 10, 10));
546 EC_LOG(EC_LOG_ERR, "cannot create node\n");
549 testres |= EC_TEST_CHECK_PARSE(node, 4, "good", "morning", "1", "bob");
551 testres |= EC_TEST_CHECK_COMPLETE(node,
553 "good", EC_NODE_ENDLIST);
554 testres |= EC_TEST_CHECK_COMPLETE(node,
555 "g", EC_NODE_ENDLIST,
556 "good", EC_NODE_ENDLIST);
557 testres |= EC_TEST_CHECK_COMPLETE(node,
558 "good", "morning", "", EC_NODE_ENDLIST,
559 "bob", "bobby", "michael", EC_NODE_ENDLIST);
563 node = EC_NODE_CMD(EC_NO_ID, "[foo [bar]]");
565 EC_LOG(EC_LOG_ERR, "cannot create node\n");
568 testres |= EC_TEST_CHECK_PARSE(node, 0);
569 testres |= EC_TEST_CHECK_PARSE(node, 1, "foo");
570 testres |= EC_TEST_CHECK_PARSE(node, 2, "foo", "bar");
571 testres |= EC_TEST_CHECK_PARSE(node, 0, "x");
578 static struct ec_test ec_node_cmd_test = {
580 .test = ec_node_cmd_testcase,
583 EC_TEST_REGISTER(ec_node_cmd_test);