# output path with trailing slash
O ?= build/
+# XXX -O0
CFLAGS = -g -O0 -Wall -Werror -W -Wextra -fPIC -Wmissing-prototypes
CFLAGS += -I.
+# XXX coverage
+CFLAGS += --coverage -fprofile-arcs -ftest-coverage
+LDFLAGS += --coverage
+# rm -rf build; rm -rf result; make && ./build/test
+# lcov -d build -c -t build/test -o test.info && genhtml -o result test.info
+
+
srcs :=
srcs += ecoli_completed.c
srcs += ecoli_keyval.c
srcs += ecoli_node_empty.c
srcs += ecoli_node_expr.c
srcs += ecoli_node_expr_test.c
+srcs += ecoli_node_file.c
srcs += ecoli_node_int.c
srcs += ecoli_node_many.c
srcs += ecoli_node_once.c
srcs += ecoli_node_subset.c
srcs += ecoli_node_weakref.c
srcs += ecoli_parsed.c
+srcs += ecoli_vec.c
shlib-y-$(O)libecoli.so := $(srcs)
return completed;
}
-static struct ec_completed_elt *
-ec_completed_elt(const struct ec_node *node, const char *add)
-{
- struct ec_completed_elt *elt = NULL;
-
- elt = ec_calloc(1, sizeof(*elt));
- if (elt == NULL)
- return NULL;
-
- elt->node = node;
- if (add != NULL) {
- elt->add = ec_strdup(add);
- if (elt->add == NULL) {
- ec_completed_elt_free(elt);
- return NULL;
- }
- }
-
- return elt;
-}
-
struct ec_completed *
ec_node_complete_child(struct ec_node *node,
struct ec_parsed *state,
if (ec_strvec_len(strvec) != 1)
return completed;
- if (ec_completed_add_elt(completed, gen_node, NULL) < 0) {
+ if (ec_completed_add_elt(completed, state, gen_node, NULL) < 0) {
ec_completed_free(completed);
return NULL;
}
return i;
}
+static struct ec_completed_elt *
+ec_completed_elt(struct ec_parsed *parsed,
+ const struct ec_node *node, const char *add)
+{
+ struct ec_completed_elt *elt = NULL;
+
+ elt = ec_calloc(1, sizeof(*elt));
+ if (elt == NULL)
+ return NULL;
+
+ if (parsed != NULL) {
+ struct ec_parsed *p;
+ size_t len;
+
+ /* get path len */
+ for (p = parsed, len = 0; p != NULL;
+ p = ec_parsed_get_parent(p), len++)
+ ;
+
+ elt->path = ec_calloc(len, sizeof(*elt->path));
+ if (elt->path == NULL)
+ goto fail;
+
+ elt->pathlen = len;
+
+ /* write path in array */
+ for (p = parsed, len = 0; p != NULL;
+ p = ec_parsed_get_parent(p), len++)
+ elt->path[len] = p->node;
+ }
+
+ elt->node = node;
+ if (add != NULL) {
+ elt->add = ec_strdup(add);
+ if (elt->add == NULL)
+ goto fail;
+ }
+
+ return elt;
+
+fail:
+ if (elt != NULL) {
+ ec_free(elt->path);
+ ec_free(elt->add);
+ }
+ ec_completed_elt_free(elt);
+
+ return NULL;
+}
+
static int __ec_completed_add_elt(struct ec_completed *completed,
struct ec_completed_elt *elt)
{
}
int ec_completed_add_elt(struct ec_completed *completed,
+ struct ec_parsed *parsed,
const struct ec_node *node, const char *add)
{
struct ec_completed_elt *elt;
- elt = ec_completed_elt(node, add);
+ elt = ec_completed_elt(parsed, node, add);
if (elt == NULL)
return -ENOMEM;
void ec_completed_elt_free(struct ec_completed_elt *elt)
{
ec_free(elt->add);
+ ec_free(elt->path);
ec_free(elt);
}
return NULL;
do {
- if (iter->cur == NULL) {
+ if (iter->cur == NULL)
iter->cur = TAILQ_FIRST(&iter->completed->elts);
- } else {
+ else
iter->cur = TAILQ_NEXT(iter->cur, next);
- }
if (iter->cur == NULL)
break;
TAILQ_ENTRY(ec_completed_elt) next;
const struct ec_node *node;
char *add;
+
+ /* reverse order: [0] = last parsed, [len-1] = root */
+ const struct ec_node **path;
+ size_t pathlen;
};
TAILQ_HEAD(ec_completed_elt_list, ec_completed_elt);
/* XXX add completion type: full, partial, none */
int ec_completed_add_elt(struct ec_completed *completed,
+ struct ec_parsed *parsed,
const struct ec_node *node, const char *add);
void ec_completed_elt_free(struct ec_completed_elt *elt);
void ec_completed_merge(struct ec_completed *completed1,
}
}
+/* LCOV_EXCL_START */
static int ec_keyval_testcase(void)
{
struct ec_keyval *keyval;
return 0;
}
+/* LCOV_EXCL_STOP */
static struct ec_test ec_keyval_test = {
.name = "keyval",
return NULL;
}
+/* LCOV_EXCL_START */
static int ec_node_cmd_testcase(void)
{
struct ec_node *node;
return ret;
}
+/* LCOV_EXCL_STOP */
static struct ec_test ec_node_cmd_test = {
.name = "node_cmd",
EC_NODE_TYPE_REGISTER(ec_node_empty_type);
+/* LCOV_EXCL_START */
static int ec_node_empty_testcase(void)
{
struct ec_node *node;
return ret;
}
+/* LCOV_EXCL_STOP */
static struct ec_test ec_node_empty_test = {
.name = "node_empty",
return ret;
}
+/* LCOV_EXCL_START */
static int ec_node_expr_testcase(void)
{
struct ec_node *node = NULL, *lex_node = NULL;
ec_node_free(node);
return -1;
}
+/* LCOV_EXCL_STOP */
static struct ec_test ec_node_expr_test = {
.name = "expr",
return val;
}
+/* LCOV_EXCL_START */
static int ec_node_int_testcase(void)
{
struct ec_parsed *p;
return ret;
}
+/* LCOV_EXCL_STOP */
static struct ec_test ec_node_int_test = {
.name = "node_int",
return &node->gen;
}
+/* LCOV_EXCL_START */
static int ec_node_many_testcase(void)
{
struct ec_node *node;
return ret;
}
+/* LCOV_EXCL_STOP */
static struct ec_test ec_node_many_test = {
.name = "node_many",
return gen_node;
}
+/* LCOV_EXCL_START */
static int ec_node_once_testcase(void)
{
struct ec_node *node;
#endif
return ret;
}
+/* LCOV_EXCL_STOP */
static struct ec_test ec_node_once_test = {
.name = "node_once",
return &node->gen;
}
+/* LCOV_EXCL_START */
static int ec_node_option_testcase(void)
{
struct ec_node *node;
return ret;
}
+/* LCOV_EXCL_STOP */
static struct ec_test ec_node_option_test = {
.name = "node_option",
return NULL;
}
+/* LCOV_EXCL_START */
static int ec_node_or_testcase(void)
{
struct ec_node *node;
return ret;
}
+/* LCOV_EXCL_STOP */
static struct ec_test ec_node_or_test = {
.name = "node_or",
return NULL;
}
+/* LCOV_EXCL_START */
static int ec_node_re_testcase(void)
{
struct ec_node *node;
return ret;
}
+/* LCOV_EXCL_STOP */
static struct ec_test ec_node_re_test = {
.name = "node_re",
return &node->gen;
}
-
+/* LCOV_EXCL_START */
static int ec_node_re_lex_testcase(void)
{
struct ec_node *node;
return ret;
}
+/* LCOV_EXCL_STOP */
static struct ec_test ec_node_re_lex_test = {
.name = "node_re_lex",
return NULL;
}
+/* LCOV_EXCL_START */
static int ec_node_seq_testcase(void)
{
struct ec_node *node;
return ret;
}
+/* LCOV_EXCL_STOP */
static struct ec_test ec_node_seq_test = {
.name = "node_seq",
return &node->gen;
}
+/* LCOV_EXCL_START */
static int ec_node_sh_lex_testcase(void)
{
struct ec_node *node;
ec_node_free(node);
return ret;
}
+/* LCOV_EXCL_STOP */
static struct ec_test ec_node_sh_lex_test = {
.name = "node_sh_lex",
EC_NODE_TYPE_REGISTER(ec_node_space_type);
+/* LCOV_EXCL_START */
static int ec_node_space_testcase(void)
{
struct ec_node *node;
return ret;
}
+/* LCOV_EXCL_STOP */
static struct ec_test ec_node_space_test = {
.name = "space",
else
add = node->string + n;
- if (ec_completed_add_elt(completed, gen_node, add) < 0) {
+ if (ec_completed_add_elt(completed, state, gen_node, add) < 0) {
ec_completed_free(completed);
return NULL;
}
return NULL;
}
+/* LCOV_EXCL_START */
static int ec_node_str_testcase(void)
{
struct ec_node *node;
return ret;
}
+/* LCOV_EXCL_STOP */
static struct ec_test ec_node_str_test = {
.name = "node_str",
return NULL;
}
+/* LCOV_EXCL_START */
static int ec_node_subset_testcase(void)
{
struct ec_node *node;
return ret;
}
+/* LCOV_EXCL_STOP */
static struct ec_test ec_node_subset_test = {
.name = "node_subset",
return gen_node;
}
+/* LCOV_EXCL_START */
static int ec_node_weakref_testcase(void)
{
//XXX weakref testcase
return 0;
}
+/* LCOV_EXCL_STOP */
static struct ec_test ec_node_weakref_test = {
.name = "node_weakref",
return parsed;
}
+struct ec_parsed *ec_parsed_get_parent(struct ec_parsed *parsed)
+{
+ if (parsed == NULL)
+ return NULL;
+
+ return parsed->parent;
+}
+
struct ec_parsed *ec_parsed_find_first(struct ec_parsed *parsed,
const char *id)
{
struct ec_parsed *child);
void ec_parsed_del_child(struct ec_parsed *parsed,
struct ec_parsed *child);
+
struct ec_parsed *ec_parsed_get_root(struct ec_parsed *parsed);
+struct ec_parsed *ec_parsed_get_parent(struct ec_parsed *parsed);
struct ec_parsed *ec_parsed_get_last_child(struct ec_parsed *parsed);
void ec_parsed_del_last_child(struct ec_parsed *parsed);
+int ec_parsed_get_path(struct ec_parsed *parsed, struct ec_node **path);
void ec_parsed_dump(FILE *out, const struct ec_parsed *parsed);
#ifndef ECOLI_STRVEC_
#define ECOLI_STRVEC_
-#include <sys/types.h>
#include <stdio.h>
struct ec_strvec *ec_strvec(void);
}
/* this function builds the help string */
-static char *get_tk_help(const struct ec_node *node)
+static char *get_node_help(const struct ec_completed_elt *elt)
{
- const struct ec_node *node2;
+ const struct ec_node *node;
char *help = NULL;
- char *tk_help = NULL;
-
- for (node2 = node;
- node2 != NULL && tk_help == NULL;
- node2 = ec_node_parent(node2))
- tk_help = ec_keyval_get(ec_node_attrs(node2), "help");
+ const char *node_help = NULL;
+ const char *node_desc = NULL;
+ size_t i;
+
+ for (i = 0; i < elt->pathlen; i++) {
+ node = elt->path[i];
+ if (node_help == NULL)
+ node_help = ec_keyval_get(ec_node_attrs(node), "help");
+ if (node_desc == NULL)
+ node_desc = ec_node_desc(node);
+ }
- if (tk_help == NULL)
- tk_help = "";
+ if (node_help == NULL)
+ node_help = "";
+ if (node_desc == NULL)
+ return NULL;
- if (asprintf(&help, "%-20s %s", ec_node_desc(node), tk_help) < 0)
+ if (asprintf(&help, "%-20s %s", node_desc, node_help) < 0)
return NULL;
return help;
for (i = match + 1, elt = ec_completed_iter_next(iter);
i < count + match + 1 && elt != NULL;
i++, elt = ec_completed_iter_next(iter)) {
- helps[i] = get_tk_help(elt->node);
+ helps[i] = get_node_help(elt);
}
ec_completed_free(c);
cmd = EC_NODE_SEQ(NULL,
ec_node_str(NULL, "hello"),
EC_NODE_OR("name",
- ec_node_str(NULL, "john"),
+ ec_node_str("john", "john"),
ec_node_str(NULL, "johnny"),
ec_node_str(NULL, "mike")
),
goto fail;
ec_keyval_set(ec_node_attrs(cmd), "help",
"say hello to someone several times", NULL);
+ ec_keyval_set(ec_node_attrs(ec_node_find(cmd, "john")),
+ "help", "specific help for john", NULL);
ec_keyval_set(ec_node_attrs(ec_node_find(cmd, "name")),
"help", "the name of the person", NULL);
ec_keyval_set(ec_node_attrs(ec_node_find(cmd, "int")),
goto fail;
- cmd = EC_NODE_CMD(NULL, "good morning bob|bobby|michael [count]",
+ cmd = EC_NODE_CMD(NULL, "good morning name [count]",
+ EC_NODE_CMD("name", "bob|bobby|michael"),
ec_node_int("count", 0, 10, 10));
if (cmd == NULL)
goto fail;
ec_keyval_set(ec_node_attrs(cmd), "help",
"say good morning to someone several times", NULL);
+ ec_keyval_set(ec_node_attrs(ec_node_find(cmd, "name")), "help",
+ "the person to greet", NULL);
+ ec_keyval_set(ec_node_attrs(ec_node_find(cmd, "count")), "help",
+ "how many times to greet", NULL);
if (ec_node_or_add(cmdlist, cmd) < 0)
goto fail;
goto fail;
- cmd = EC_NODE_CMD(NULL, "sell vegetable",
- ec_node_many("vegetable",
+ cmd = EC_NODE_CMD(NULL, "eat vegetables",
+ ec_node_many("vegetables",
EC_NODE_OR(NULL,
- ec_node_once(NULL,
- ec_node_str(NULL, "potatoes")),
+ ec_node_str(NULL, "potatoes"),
ec_node_once(NULL,
ec_node_str(NULL, "carrots")),
ec_node_once(NULL,
if (cmd == NULL)
goto fail;
ec_keyval_set(ec_node_attrs(cmd), "help",
- "sell vegetables", NULL);
+ "eat vegetables (take some more potatoes)", NULL);
if (ec_node_or_add(cmdlist, cmd) < 0)
goto fail;
cmd = EC_NODE_SEQ(NULL,
ec_node_str(NULL, "bye")
);
- ec_keyval_set(ec_node_attrs(cmd), "help", "say bye to someone", NULL);
+ ec_keyval_set(ec_node_attrs(cmd), "help", "say bye", NULL);
if (ec_node_or_add(cmdlist, cmd) < 0)
goto fail;
static void usage(const char *prgname)
{
- /* XXX add a parameter to test only one testcase */
- printf("%s [options]\n"
+ printf("%s [options] [test1 test2 test3...]\n"
" -h\n"
" --"EC_OPT_HELP"\n"
" Show this help.\n"
======
X evaluate expression tree in ec_tk_expr
-- cmd token
+X cmd token
- example
X tk_re
-cleanup
-=======
+cleanup / rework
+================
- check XXX in code
X remove the _new() functions
+- iterate children nodes without chaining them
- add a tk vector type: will be used in several nodes (ex: or, seq, ...)
- check allocation model everywhere
- checkpatch?
- cache results when appropriate?
- size_t or unsigned int?
X rename:
- - ec_tk -> ec_node
- - ec_parsed_tk -> ec_parsed
- - ec_completed_tk -> ec_completed
- - tk, gen_tk, token, ... -> node
- - tokens -> input_str / input_strvec ?
+ X ec_tk -> ec_node
+ X ec_parsed_tk -> ec_parsed
+ X ec_completed_tk -> ec_completed
+ X tk, gen_tk, token, ... -> node
+ X tokens -> input_str / input_strvec ?
- use is_err() or errno for funcs returning ptrs
+- save node path in completion to fix help string
+- code coverage
+- try to hide structures
dependencies
============
-- pass the current parsed state when parsing/completing
+X pass the current parsed state when parsing/completing
+X new node "once"
- new node "condition"
logs