CFLAGS += -I.
srcs := ecoli_tk.c ecoli_malloc.c ecoli_log.c ecoli_strvec.c
-srcs += ecoli_keyval.c
-srcs += ecoli_tk_str.c ecoli_tk_seq.c
-srcs += ecoli_tk_space.c ecoli_tk_or.c ecoli_test.c
-srcs += ecoli_tk_empty.c ecoli_tk_int.c
-srcs += ecoli_tk_option.c ecoli_tk_many.c
-srcs += ecoli_tk_shlex.c ecoli_tk_expr.c ecoli_tk_bypass.c
+srcs += ecoli_keyval.c ecoli_test.c
+srcs += ecoli_tk_str.c ecoli_tk_seq.c ecoli_tk_space.c ecoli_tk_or.c
+srcs += ecoli_tk_empty.c ecoli_tk_int.c ecoli_tk_option.c ecoli_tk_many.c
+srcs += ecoli_tk_shlex.c ecoli_tk_expr.c ecoli_tk_bypass.c ecoli_tk_re_lex.c
shlib-y-$(O)libecoli.so := $(srcs)
ldflags-$(O)test = -rdynamic
TAILQ_INSERT_TAIL(&test_list, test, next);
}
-int ec_test_check_tk_parse(const struct ec_tk *tk, int expected, ...)
+int ec_test_check_tk_parse(struct ec_tk *tk, int expected, ...)
{
struct ec_parsed_tk *p;
struct ec_strvec *vec = NULL;
int ec_test_all(void);
/* expected == -1 means no match */
-int ec_test_check_tk_parse(const struct ec_tk *tk, int expected, ...);
+int ec_test_check_tk_parse(struct ec_tk *tk, int expected, ...);
#define EC_TEST_ERR(fmt, ...) \
ec_log(EC_LOG_ERR, "%s:%d: error: " fmt "\n", \
EC_TEST_ERR("assertion failure: " #cond); \
} while (0)
-#define EC_TEST_CHECK_TK_PARSE(tk, input, expected...) ({ \
- int ret_ = ec_test_check_tk_parse(tk, input, expected); \
+/* tk, input, [expected1, expected2, ...] */
+#define EC_TEST_CHECK_TK_PARSE(tk, args...) ({ \
+ int ret_ = ec_test_check_tk_parse(tk, args, EC_TK_ENDLIST); \
if (ret_) \
EC_TEST_ERR("parse test failed"); \
ret_; \
#include <ecoli_malloc.h>
#include <ecoli_strvec.h>
#include <ecoli_keyval.h>
+#include <ecoli_log.h>
#include <ecoli_tk.h>
struct ec_tk *ec_tk_new(const char *id, const struct ec_tk_ops *ops,
assert(size >= sizeof(*tk));
+ ec_log(EC_LOG_DEBUG, "create node type=%s id=%s\n", ops->typename, id);
+
tk = ec_calloc(1, size);
if (tk == NULL)
goto fail;
return tk->parent;
}
-struct ec_parsed_tk *ec_tk_parse(const struct ec_tk *tk, const char *str)
+struct ec_parsed_tk *ec_tk_parse(struct ec_tk *tk, const char *str)
{
struct ec_strvec *strvec = NULL;
struct ec_parsed_tk *parsed_tk;
return NULL;
}
-struct ec_parsed_tk *ec_tk_parse_tokens(const struct ec_tk *tk,
+struct ec_parsed_tk *ec_tk_parse_tokens(struct ec_tk *tk,
const struct ec_strvec *strvec)
{
struct ec_parsed_tk *parsed_tk;
+ int ret;
+
+ /* build the node if required */
+ if (tk->ops->build != NULL) {
+ if ((tk->flags & EC_TK_F_BUILT) == 0) {
+ ret = tk->ops->build(tk);
+ if (ret < 0) {
+ errno = -ret;
+ return NULL;
+ }
+ }
+ }
+ tk->flags |= EC_TK_F_BUILT;
if (tk->ops->parse == NULL) {
errno = ENOTSUP;
struct ec_strvec;
struct ec_keyval;
+/* return 0 on success, else -errno. */
+typedef int (*ec_tk_build_t)(struct ec_tk *tk);
+
typedef struct ec_parsed_tk *(*ec_tk_parse_t)(const struct ec_tk *tk,
const struct ec_strvec *strvec);
typedef struct ec_completed_tk *(*ec_tk_complete_t)(const struct ec_tk *tk,
struct ec_tk_ops {
const char *typename;
+ ec_tk_build_t build; /* (re)build the node, called by generic parse */
ec_tk_parse_t parse;
ec_tk_complete_t complete;
ec_tk_desc_t desc;
/* XXX ensure parent and child are properly set in all nodes */
struct ec_tk *parent;
unsigned int refcnt;
-#define EC_TK_F_INITIALIZED 0x0001
+#define EC_TK_F_BUILT 0x0001 /** set if configuration is built */
unsigned int flags;
TAILQ_ENTRY(ec_tk) next;
/* a NULL return value is an error, with errno set
ENOTSUP: no ->parse() operation
*/
-struct ec_parsed_tk *ec_tk_parse(const struct ec_tk *tk, const char *str);
+struct ec_parsed_tk *ec_tk_parse(struct ec_tk *tk, const char *str);
/* mostly internal to tokens */
/* XXX it should not reset cache
* ... not sure... it is used by tests */
-struct ec_parsed_tk *ec_tk_parse_tokens(const struct ec_tk *tk,
+struct ec_parsed_tk *ec_tk_parse_tokens(struct ec_tk *tk,
const struct ec_strvec *strvec);
void ec_parsed_tk_add_child(struct ec_parsed_tk *parsed_tk,
.free_priv = ec_tk_bypass_free_priv,
};
-struct ec_tk *ec_tk_bypass_new(const char *id)
+struct ec_tk *ec_tk_bypass_empty(const char *id)
{
struct ec_tk_bypass *tk = NULL;
if (child == NULL)
return -EINVAL;
- if (gen_tk->flags & EC_TK_F_INITIALIZED) {
- ec_tk_free(child);
- return -EPERM;
- }
+ gen_tk->flags &= ~EC_TK_F_BUILT;
tk->child = child;
struct ec_tk_bypass *tk = (struct ec_tk_bypass *)gen_tk;
struct ec_tk *child;
- if (gen_tk->flags & EC_TK_F_INITIALIZED)
- return NULL;
-
child = tk->child;
tk->child = NULL;
- return child;
-}
-
-int ec_tk_bypass_start(struct ec_tk *gen_tk)
-{
- struct ec_tk_bypass *tk = (struct ec_tk_bypass *)gen_tk;
-
- if (gen_tk->flags & EC_TK_F_INITIALIZED)
- return -EPERM;
- if (tk->child == NULL)
- return -EINVAL;
-
- gen_tk->flags |= EC_TK_F_INITIALIZED;
-
- return 0;
-}
+ gen_tk->flags &= ~EC_TK_F_BUILT;
+ TAILQ_REMOVE(&gen_tk->children, child, next); // XXX really needed?
-int ec_tk_bypass_stop(struct ec_tk *gen_tk)
-{
- if (!(gen_tk->flags & EC_TK_F_INITIALIZED))
- return -EPERM;
-
- gen_tk->flags &= (~EC_TK_F_INITIALIZED);
-
- return 0;
+ return child;
}
struct ec_tk *ec_tk_bypass(const char *id, struct ec_tk *child)
if (child == NULL)
return NULL;
- gen_tk = ec_tk_bypass_new(id);
+ gen_tk = ec_tk_bypass_empty(id);
if (gen_tk == NULL) {
ec_tk_free(child);
return NULL;
}
ec_tk_bypass_set(gen_tk, child);
- ec_tk_bypass_start(gen_tk);
return gen_tk;
}
struct ec_tk *ec_tk_bypass(const char *id, struct ec_tk *child);
-struct ec_tk *ec_tk_bypass_new(const char *id);
+struct ec_tk *ec_tk_bypass_empty(const char *id);
/* child is consumed */
/* all token given in the list will be freed when freeing this one */
ec_log(EC_LOG_ERR, "cannot create tk\n");
return -1;
}
- ret |= EC_TEST_CHECK_TK_PARSE(tk, 0, "foo", EC_TK_ENDLIST);
- ret |= EC_TEST_CHECK_TK_PARSE(tk, 0, EC_TK_ENDLIST);
- ret |= EC_TEST_CHECK_TK_PARSE(tk, 0, "foo", "bar", EC_TK_ENDLIST);
+ ret |= EC_TEST_CHECK_TK_PARSE(tk, 0, "foo");
+ ret |= EC_TEST_CHECK_TK_PARSE(tk, 0);
+ ret |= EC_TEST_CHECK_TK_PARSE(tk, 0, "foo", "bar");
ec_tk_free(tk);
/* never completes */
/*
- * Copyright (c) 2016, Olivier MATZ <zer0@droids-corp.org>
+ * Copyright (c) 2016-2017, Olivier MATZ <zer0@droids-corp.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
struct ec_tk_expr {
struct ec_tk gen;
+
+ /* the built node */
struct ec_tk *child;
- struct ec_tk *val_tk;
+ /* the configuration nodes */
+ struct ec_tk *val_tk;
struct ec_tk **bin_ops;
unsigned int bin_ops_len;
-
struct ec_tk **pre_ops;
unsigned int pre_ops_len;
-
struct ec_tk **post_ops;
unsigned int post_ops_len;
-
struct ec_tk **open_ops;
struct ec_tk **close_ops;
unsigned int paren_len;
static void ec_tk_expr_free_priv(struct ec_tk *gen_tk)
{
struct ec_tk_expr *tk = (struct ec_tk_expr *)gen_tk;
+ struct ec_tk *final;
unsigned int i;
- ec_tk_free(tk->child);
+ ec_log(EC_LOG_DEBUG, "free %p %p %p\n", tk, tk->child, tk->val_tk);
ec_tk_free(tk->val_tk);
for (i = 0; i < tk->bin_ops_len; i++)
ec_tk_free(tk->bin_ops[i]);
+ ec_free(tk->bin_ops);
for (i = 0; i < tk->pre_ops_len; i++)
ec_tk_free(tk->pre_ops[i]);
+ ec_free(tk->pre_ops);
for (i = 0; i < tk->post_ops_len; i++)
ec_tk_free(tk->post_ops[i]);
+ ec_free(tk->post_ops);
for (i = 0; i < tk->paren_len; i++) {
ec_tk_free(tk->open_ops[i]);
ec_tk_free(tk->close_ops[i]);
}
+ ec_free(tk->open_ops);
+ ec_free(tk->close_ops);
+
+ /* break the graph loop, and free the nodes */
+ if (tk->child != NULL) {
+ final = ec_tk_bypass_pop(tk->child);
+ ec_tk_free(tk->child);
+ ec_tk_free(final);
+ }
+}
+
+static int ec_tk_expr_build(struct ec_tk *gen_tk)
+{
+ struct ec_tk_expr *tk = (struct ec_tk_expr *)gen_tk;
+ struct ec_tk *term = NULL, *expr = NULL, *next = NULL,
+ *pre_op = NULL, *post_op = NULL,
+ *post = NULL, *final = NULL;
+ unsigned int i;
+ int ret;
+
+ if (tk->val_tk == NULL)
+ return -EINVAL;
+ if (tk->bin_ops_len == 0 && tk->pre_ops_len == 0 &&
+ tk->post_ops_len == 0)
+ return -EINVAL;
+
+ /* create the object, we will initialize it later: this is
+ * needed because we have a circular dependency */
+ ret = -ENOMEM;
+ expr = ec_tk_bypass_empty("expr");
+ if (expr == NULL)
+ goto fail;
+
+ /* prefix unary operators */
+ pre_op = ec_tk_or("pre-op");
+ if (pre_op == NULL)
+ goto fail;
+ for (i = 0; i < tk->pre_ops_len; i++) {
+ if (ec_tk_or_add(pre_op, ec_tk_clone(tk->pre_ops[i])) < 0)
+ goto fail;
+ }
+
+ /* suffix unary operators */
+ post_op = ec_tk_or("post-op");
+ if (post_op == NULL)
+ goto fail;
+ for (i = 0; i < tk->post_ops_len; i++) {
+ if (ec_tk_or_add(post_op, ec_tk_clone(tk->post_ops[i])) < 0)
+ goto fail;
+ }
+
+ term = ec_tk_or("term");
+ if (term == NULL)
+ goto fail;
+ if (ec_tk_or_add(term, ec_tk_clone(tk->val_tk)) < 0)
+ goto fail;
+ if (ec_tk_or_add(term,
+ EC_TK_SEQ(NULL,
+ ec_tk_clone(pre_op),
+ ec_tk_clone(expr))) < 0)
+ goto fail;
+ for (i = 0; i < tk->paren_len; i++) {
+ if (ec_tk_or_add(term, EC_TK_SEQ(NULL,
+ ec_tk_clone(tk->open_ops[i]),
+ ec_tk_clone(expr),
+ ec_tk_clone(tk->close_ops[i]))) < 0)
+ goto fail;
+ }
+
+ for (i = 0; i < tk->bin_ops_len; i++) {
+ next = EC_TK_SEQ("next",
+ ec_tk_clone(term),
+ ec_tk_many(NULL,
+ EC_TK_SEQ(NULL,
+ ec_tk_clone(tk->bin_ops[i]),
+ ec_tk_clone(term)
+ ),
+ 0, 0
+ )
+ );
+ ec_tk_free(term);
+ term = next;
+ if (term == NULL)
+ goto fail;
+ }
+
+ final = EC_TK_SEQ("final",
+ ec_tk_clone(term),
+ ec_tk_many(NULL, ec_tk_clone(post_op), 0, 0)
+ );
+ if (final == NULL)
+ goto fail;
+
+ /* free the initial references */
+ ec_tk_free(pre_op);
+ pre_op = NULL;
+ ec_tk_free(post_op);
+ post_op = NULL;
+ ec_tk_free(term);
+ term = NULL;
+ ec_tk_free(post);
+ post = NULL;
+
+ if (ec_tk_bypass_set(expr, ec_tk_clone(final)) < 0)
+ goto fail;
+
+ ec_tk_free(final);
+ final = NULL;
+
+ tk->child = expr;
+
+ return 0;
+
+fail:
+ ec_tk_free(term);
+ ec_tk_free(expr);
+ ec_tk_free(pre_op);
+ ec_tk_free(post_op);
+ ec_tk_free(post);
+ ec_tk_free(final);
+
+ return ret;
}
static struct ec_tk_ops ec_tk_expr_ops = {
.typename = "expr",
+ .build = ec_tk_expr_build,
.parse = ec_tk_expr_parse,
.complete = ec_tk_expr_complete,
.free_priv = ec_tk_expr_free_priv,
};
-struct ec_tk *ec_tk_expr_new(const char *id)
+struct ec_tk *ec_tk_expr(const char *id)
{
struct ec_tk_expr *tk = NULL;
struct ec_tk *gen_tk = NULL;
int ec_tk_expr_set_val_tk(struct ec_tk *gen_tk, struct ec_tk *val_tk)
{
struct ec_tk_expr *tk = (struct ec_tk_expr *)gen_tk;
+ int ret;
+ ret = -EINVAL;
if (val_tk == NULL)
- return -EINVAL;
+ goto fail;
+ ret = -EPERM;
+ if (gen_tk->flags & EC_TK_F_BUILT)
+ goto fail;
+ ret = -EEXIST;
if (tk->val_tk != NULL)
- return -EEXIST;
+ goto fail;
tk->val_tk = val_tk;
+ gen_tk->flags &= ~EC_TK_F_BUILT;
return 0;
+
+fail:
+ ec_tk_free(val_tk);
+ return ret;
}
+/* add a binary operator */
int ec_tk_expr_add_bin_op(struct ec_tk *gen_tk, struct ec_tk *op)
{
struct ec_tk_expr *tk = (struct ec_tk_expr *)gen_tk;
struct ec_tk **bin_ops;
+ int ret;
// XXX check tk type
+ ret = -EINVAL;
if (tk == NULL || op == NULL)
- return -EINVAL;
- if (gen_tk->flags & EC_TK_F_INITIALIZED)
- return -EPERM;
+ goto fail;
+ ret = -EPERM;
+ if (gen_tk->flags & EC_TK_F_BUILT)
+ goto fail;
+ ret = -ENOMEM;
bin_ops = ec_realloc(tk->bin_ops,
(tk->bin_ops_len + 1) * sizeof(*tk->bin_ops));
if (bin_ops == NULL)
- return -1;
+ goto fail;;
tk->bin_ops = bin_ops;
bin_ops[tk->bin_ops_len] = op;
tk->bin_ops_len++;
+ gen_tk->flags &= ~EC_TK_F_BUILT;
return 0;
+
+fail:
+ ec_tk_free(op);
+ return ret;
}
+/* add a unary pre-operator */
int ec_tk_expr_add_pre_op(struct ec_tk *gen_tk, struct ec_tk *op)
{
struct ec_tk_expr *tk = (struct ec_tk_expr *)gen_tk;
struct ec_tk **pre_ops;
+ int ret;
// XXX check tk type
+ ret = -EINVAL;
if (tk == NULL || op == NULL)
- return -EINVAL;
- if (gen_tk->flags & EC_TK_F_INITIALIZED)
- return -EPERM;
+ goto fail;
+ ret = -EPERM;
+ if (gen_tk->flags & EC_TK_F_BUILT)
+ goto fail;
+ ret = -ENOMEM;
pre_ops = ec_realloc(tk->pre_ops,
(tk->pre_ops_len + 1) * sizeof(*tk->pre_ops));
if (pre_ops == NULL)
- return -1;
+ goto fail;
tk->pre_ops = pre_ops;
pre_ops[tk->pre_ops_len] = op;
tk->pre_ops_len++;
+ gen_tk->flags &= ~EC_TK_F_BUILT;
return 0;
+
+fail:
+ ec_tk_free(op);
+ return ret;
}
+/* add a unary post-operator */
int ec_tk_expr_add_post_op(struct ec_tk *gen_tk, struct ec_tk *op)
{
struct ec_tk_expr *tk = (struct ec_tk_expr *)gen_tk;
struct ec_tk **post_ops;
+ int ret;
// XXX check tk type
+ ret = -EINVAL;
if (tk == NULL || op == NULL)
- return -EINVAL;
- if (gen_tk->flags & EC_TK_F_INITIALIZED)
- return -EPERM;
+ goto fail;
+ ret = -EPERM;
+ if (gen_tk->flags & EC_TK_F_BUILT)
+ goto fail;
+ ret = -ENOMEM;
post_ops = ec_realloc(tk->post_ops,
(tk->post_ops_len + 1) * sizeof(*tk->post_ops));
if (post_ops == NULL)
- return -1;
+ goto fail;
tk->post_ops = post_ops;
post_ops[tk->post_ops_len] = op;
tk->post_ops_len++;
+ gen_tk->flags &= ~EC_TK_F_BUILT;
return 0;
+
+fail:
+ ec_tk_free(op);
+ return ret;
}
+/* add parenthesis symbols */
int ec_tk_expr_add_parenthesis(struct ec_tk *gen_tk,
struct ec_tk *open, struct ec_tk *close)
{
struct ec_tk_expr *tk = (struct ec_tk_expr *)gen_tk;
struct ec_tk **open_ops, **close_ops;
+ int ret;
// XXX check tk type
+ ret = -EINVAL;
if (tk == NULL || open == NULL || close == NULL)
- return -EINVAL;
- if (gen_tk->flags & EC_TK_F_INITIALIZED)
- return -EPERM;
+ goto fail;
+ ret = -EPERM;
+ if (gen_tk->flags & EC_TK_F_BUILT)
+ goto fail;;
+ ret = -ENOMEM;
open_ops = ec_realloc(tk->open_ops,
(tk->paren_len + 1) * sizeof(*tk->open_ops));
if (open_ops == NULL)
- return -1;
+ goto fail;
close_ops = ec_realloc(tk->close_ops,
(tk->paren_len + 1) * sizeof(*tk->close_ops));
if (close_ops == NULL)
- return -1;
+ goto fail;
tk->open_ops = open_ops;
tk->close_ops = close_ops;
open_ops[tk->paren_len] = open;
close_ops[tk->paren_len] = close;
tk->paren_len++;
-
- return 0;
-}
-
-int ec_tk_expr_start(struct ec_tk *gen_tk)
-{
- struct ec_tk_expr *tk = (struct ec_tk_expr *)gen_tk;
- struct ec_tk *term = NULL, *prev = NULL, *expr = NULL,
- *pre_op = NULL, *post_op = NULL,
- *post = NULL, *final = NULL, *next = NULL;
- unsigned int i;
-
- if (tk->val_tk == NULL)
- return -EINVAL;
- if (gen_tk->flags & EC_TK_F_INITIALIZED)
- return -EPERM;
- if (tk->bin_ops_len == 0 && tk->pre_ops_len == 0 &&
- tk->post_ops_len == 0)
- return -EINVAL;
-
- /* create the object, we will initialize it later: this is
- * needed because we have a circular dependency */
- expr = ec_tk_bypass_new("expr");
-
- /* prefix unary operators */
- pre_op = ec_tk_or_new("pre-op");
- for (i = 0; i < tk->pre_ops_len; i++) {
- if (ec_tk_or_add(pre_op, ec_tk_clone(tk->pre_ops[i])) < 0)
- goto fail;
- }
- if (ec_tk_or_start(pre_op) < 0)
- goto fail;
-
- /* suffix unary operators */
- post_op = ec_tk_or_new("post-op");
- for (i = 0; i < tk->post_ops_len; i++) {
- if (ec_tk_or_add(post_op, ec_tk_clone(tk->post_ops[i])) < 0)
- goto fail;
- }
- if (ec_tk_or_start(post_op) < 0)
- goto fail;
-
- term = ec_tk_or_new("term");
- if (ec_tk_or_add(term, ec_tk_clone(tk->val_tk)) < 0)
- goto fail;
- if (ec_tk_or_add(term,
- ec_tk_seq(NULL,
- ec_tk_clone(pre_op),
- ec_tk_clone(expr),
- EC_TK_ENDLIST)) < 0)
- goto fail;
- for (i = 0; i < tk->paren_len; i++) {
- if (ec_tk_or_add(term, ec_tk_seq(NULL,
- ec_tk_clone(tk->open_ops[i]),
- ec_tk_clone(expr),
- ec_tk_clone(tk->close_ops[i]),
- EC_TK_ENDLIST)) < 0)
- goto fail;
- }
-
- prev = term;
- term = NULL;
- for (i = 0; i < tk->bin_ops_len; i++) {
- next = ec_tk_seq("next",
- ec_tk_clone(prev),
- ec_tk_many_new(NULL,
- ec_tk_seq(NULL,
- ec_tk_clone(tk->bin_ops[i]),
- ec_tk_clone(prev),
- EC_TK_ENDLIST
- ),
- 0, 0
- ),
- EC_TK_ENDLIST
- );
- prev = next;
- }
-
- final = ec_tk_seq("final",
- ec_tk_clone(next),
- ec_tk_many_new(NULL, ec_tk_clone(post_op), 0, 0),
- EC_TK_ENDLIST
- );
-
- /* free the initial references */
- ec_tk_free(pre_op);
- pre_op = NULL;
- ec_tk_free(post_op);
- post_op = NULL;
- ec_tk_free(term);
- term = NULL;
- ec_tk_free(post);
- post = NULL;
-
- if (ec_tk_bypass_set(expr, ec_tk_clone(final)) < 0)
- goto fail;
-
- ec_tk_free(final);
- final = NULL;
-
- tk->child = expr;
-
- gen_tk->flags |= EC_TK_F_INITIALIZED;
+ gen_tk->flags &= ~EC_TK_F_BUILT;
return 0;
fail:
- ec_tk_free(term);
- ec_tk_free(expr);
- ec_tk_free(pre_op);
- ec_tk_free(post_op);
- ec_tk_free(post);
- ec_tk_free(final);
-
- return -1;
+ ec_tk_free(open);
+ ec_tk_free(close);
+ return ret;
}
static int ec_tk_expr_testcase_manual(void)
/* create the object, we will initialize it later: this is
* needed because we have a circular dependency */
- ec_log(EC_LOG_INFO, "%d\n", __LINE__);
- expr = ec_tk_bypass_new("expr");
+ expr = ec_tk_bypass_empty("expr");
+ if (expr == NULL)
+ return -1;
- ec_log(EC_LOG_INFO, "%d\n", __LINE__);
/* reverse bits */
- pre_op = ec_tk_or("pre-op",
- ec_tk_str(NULL, "~"),
- EC_TK_ENDLIST
+ pre_op = EC_TK_OR("pre-op",
+ ec_tk_str(NULL, "~")
);
- ec_log(EC_LOG_INFO, "%d\n", __LINE__);
/* factorial */
- post_op = ec_tk_or("post-op",
- ec_tk_str(NULL, "!"),
- EC_TK_ENDLIST
+ post_op = EC_TK_OR("post-op",
+ ec_tk_str(NULL, "!")
);
- ec_log(EC_LOG_INFO, "%d\n", __LINE__);
val = ec_tk_int("val", 0, UCHAR_MAX, 0);
- ec_log(EC_LOG_INFO, "%d\n", __LINE__);
- term = ec_tk_or("term",
+ term = EC_TK_OR("term",
val,
- ec_tk_seq(NULL,
+ EC_TK_SEQ(NULL,
ec_tk_str(NULL, "("),
ec_tk_clone(expr),
- ec_tk_str(NULL, ")"),
- EC_TK_ENDLIST
+ ec_tk_str(NULL, ")")
),
- ec_tk_seq(NULL,
+ EC_TK_SEQ(NULL,
ec_tk_clone(pre_op),
- ec_tk_clone(expr),
- EC_TK_ENDLIST
- ),
- EC_TK_ENDLIST
+ ec_tk_clone(expr)
+ )
);
val = NULL;
- ec_log(EC_LOG_INFO, "%d\n", __LINE__);
-
- factor = ec_tk_seq("factor",
+ factor = EC_TK_SEQ("factor",
ec_tk_clone(term),
- ec_tk_many_new(NULL,
- ec_tk_seq(NULL,
+ ec_tk_many(NULL,
+ EC_TK_SEQ(NULL,
ec_tk_str(NULL, "+"),
- ec_tk_clone(term),
- EC_TK_ENDLIST
+ ec_tk_clone(term)
),
0, 0
- ),
- EC_TK_ENDLIST
+ )
);
- post = ec_tk_seq("post",
+ post = EC_TK_SEQ("post",
ec_tk_clone(factor),
- ec_tk_many_new(NULL,
- ec_tk_seq(NULL,
+ ec_tk_many(NULL,
+ EC_TK_SEQ(NULL,
ec_tk_str(NULL, "*"),
- ec_tk_clone(factor),
- EC_TK_ENDLIST
+ ec_tk_clone(factor)
),
0, 0
- ),
- EC_TK_ENDLIST
+ )
);
- ec_log(EC_LOG_INFO, "%d\n", __LINE__);
- final = ec_tk_seq("final",
+ final = EC_TK_SEQ("final",
ec_tk_clone(post),
- ec_tk_many_new(NULL, ec_tk_clone(post_op), 0, 0),
- EC_TK_ENDLIST
+ ec_tk_many(NULL, ec_tk_clone(post_op), 0, 0)
);
- ec_log(EC_LOG_INFO, "%d\n", __LINE__);
/* free the initial references */
ec_tk_free(pre_op);
pre_op = NULL;
ec_tk_free(post);
post = NULL;
- ec_log(EC_LOG_INFO, "%d\n", __LINE__);
if (ec_tk_bypass_set(expr, ec_tk_clone(final)) < 0)
goto fail;
- ec_log(EC_LOG_INFO, "%d\n", __LINE__);
ec_tk_free(final);
final = NULL;
- ec_log(EC_LOG_INFO, "%d\n", __LINE__);
-
- ret |= EC_TEST_CHECK_TK_PARSE(expr, 1, "1", EC_TK_ENDLIST);
- ret |= EC_TEST_CHECK_TK_PARSE(expr, 1, "1", "*", EC_TK_ENDLIST);
- ret |= EC_TEST_CHECK_TK_PARSE(expr, 3, "1", "*", "1", EC_TK_ENDLIST);
- ret |= EC_TEST_CHECK_TK_PARSE(expr, 3, "1", "+", "1", EC_TK_ENDLIST);
- ret |= EC_TEST_CHECK_TK_PARSE(expr, 5, "1", "*", "1", "+", "1",
- EC_TK_ENDLIST);
+ ret |= EC_TEST_CHECK_TK_PARSE(expr, 1, "1");
+ ret |= EC_TEST_CHECK_TK_PARSE(expr, 1, "1", "*");
+ ret |= EC_TEST_CHECK_TK_PARSE(expr, 3, "1", "*", "1");
+ ret |= EC_TEST_CHECK_TK_PARSE(expr, 3, "1", "+", "1");
+ ret |= EC_TEST_CHECK_TK_PARSE(expr, 5, "1", "*", "1", "+", "1");
ret |= EC_TEST_CHECK_TK_PARSE(
- expr, 10, "~", "(", "1", "*", "(", "1", "+", "1", ")", ")",
- EC_TK_ENDLIST);
- ret |= EC_TEST_CHECK_TK_PARSE(expr, 4, "1", "+", "~", "1",
- EC_TK_ENDLIST);
+ expr, 10, "~", "(", "1", "*", "(", "1", "+", "1", ")", ")");
+ ret |= EC_TEST_CHECK_TK_PARSE(expr, 4, "1", "+", "~", "1");
final = ec_tk_bypass_pop(expr);
ec_tk_free(expr);
return ret;
fail:
- ec_log(EC_LOG_INFO, "%d term %p\n", __LINE__, term);
ec_tk_free(term);
- ec_log(EC_LOG_INFO, "%d factor %p\n", __LINE__, factor);
ec_tk_free(factor);
- ec_log(EC_LOG_INFO, "%d expr %p\n", __LINE__, expr);
ec_tk_free(expr);
- ec_log(EC_LOG_INFO, "%d val %p\n", __LINE__, val);
ec_tk_free(val);
- ec_log(EC_LOG_INFO, "%d pre_op %p\n", __LINE__, pre_op);
ec_tk_free(pre_op);
- ec_log(EC_LOG_INFO, "%d post_op %p\n", __LINE__, post_op);
ec_tk_free(post_op);
- ec_log(EC_LOG_INFO, "%d post %p\n", __LINE__, post);
ec_tk_free(post);
- ec_log(EC_LOG_INFO, "%d final %p\n", __LINE__, final);
ec_tk_free(final);
- ec_log(EC_LOG_INFO, "%d\n", __LINE__);
return 0;
}
if (ret < 0)
return ret;
- tk = ec_tk_expr_new(NULL);
+ tk = ec_tk_expr(NULL);
+ if (tk == NULL)
+ return -1;
+
ec_tk_expr_set_val_tk(tk, ec_tk_int(NULL, 0, UCHAR_MAX, 0));
ec_tk_expr_add_bin_op(tk, ec_tk_str(NULL, "+"));
ec_tk_expr_add_bin_op(tk, ec_tk_str(NULL, "*"));
ec_tk_expr_add_pre_op(tk, ec_tk_str(NULL, "!"));
ec_tk_expr_add_parenthesis(tk, ec_tk_str(NULL, "("),
ec_tk_str(NULL, ")"));
- ec_tk_expr_start(tk); // XXX start -> commit ?
-
- ret |= EC_TEST_CHECK_TK_PARSE(tk, 1, "1", EC_TK_ENDLIST);
- ret |= EC_TEST_CHECK_TK_PARSE(tk, 1, "1", "*", EC_TK_ENDLIST);
- ret |= EC_TEST_CHECK_TK_PARSE(tk, 3, "1", "*", "1", EC_TK_ENDLIST);
- ret |= EC_TEST_CHECK_TK_PARSE(tk, 3, "1", "+", "1", EC_TK_ENDLIST);
- ret |= EC_TEST_CHECK_TK_PARSE(tk, 5, "1", "*", "1", "+", "1",
- EC_TK_ENDLIST);
+ ret |= EC_TEST_CHECK_TK_PARSE(tk, 1, "1");
+ ret |= EC_TEST_CHECK_TK_PARSE(tk, 1, "1", "*");
+ ret |= EC_TEST_CHECK_TK_PARSE(tk, 3, "1", "*", "1");
+ ret |= EC_TEST_CHECK_TK_PARSE(tk, 3, "1", "+", "1");
+ ret |= EC_TEST_CHECK_TK_PARSE(tk, 5, "1", "*", "1", "+", "1");
ret |= EC_TEST_CHECK_TK_PARSE(
- tk, 10, "~", "(", "1", "*", "(", "1", "+", "1", ")", ")",
- EC_TK_ENDLIST);
- ret |= EC_TEST_CHECK_TK_PARSE(tk, 4, "1", "+", "~", "1",
- EC_TK_ENDLIST);
+ tk, 10, "~", "(", "1", "*", "(", "1", "+", "1", ")", ")");
+ ret |= EC_TEST_CHECK_TK_PARSE(tk, 4, "1", "+", "~", "1");
ec_tk_free(tk);
return ret;
/* XXX remove the _new for all other tokens */
-struct ec_tk *ec_tk_expr(const char *id, struct ec_tk *val_tk,
- const char *bin_ops);
-
-struct ec_tk *ec_tk_expr_new(const char *id);
+struct ec_tk *ec_tk_expr(const char *id);
int ec_tk_expr_add_bin_op(struct ec_tk *gen_tk, struct ec_tk *op);
int ec_tk_expr_add_pre_op(struct ec_tk *gen_tk, struct ec_tk *op);
int ec_tk_expr_add_post_op(struct ec_tk *gen_tk, struct ec_tk *op);
tk->min = min;
tk->max = max;
tk->base = base;
- gen_tk->flags |= EC_TK_F_INITIALIZED;
return &tk->gen;
}
ec_log(EC_LOG_ERR, "cannot create tk\n");
return -1;
}
- ret |= EC_TEST_CHECK_TK_PARSE(tk, 1, "0", EC_TK_ENDLIST);
- ret |= EC_TEST_CHECK_TK_PARSE(tk, 1, "256", "foo", EC_TK_ENDLIST);
- ret |= EC_TEST_CHECK_TK_PARSE(tk, 1, "0x100", EC_TK_ENDLIST);
- ret |= EC_TEST_CHECK_TK_PARSE(tk, 1, " 1", EC_TK_ENDLIST);
- ret |= EC_TEST_CHECK_TK_PARSE(tk, -1, "-1", EC_TK_ENDLIST);
- ret |= EC_TEST_CHECK_TK_PARSE(tk, -1, "0x101", EC_TK_ENDLIST);
+ ret |= EC_TEST_CHECK_TK_PARSE(tk, 1, "0");
+ ret |= EC_TEST_CHECK_TK_PARSE(tk, 1, "256", "foo");
+ ret |= EC_TEST_CHECK_TK_PARSE(tk, 1, "0x100");
+ ret |= EC_TEST_CHECK_TK_PARSE(tk, 1, " 1");
+ ret |= EC_TEST_CHECK_TK_PARSE(tk, -1, "-1");
+ ret |= EC_TEST_CHECK_TK_PARSE(tk, -1, "0x101");
p = ec_tk_parse(tk, "0");
s = ec_strvec_val(ec_parsed_tk_strvec(p), 0);
ec_log(EC_LOG_ERR, "cannot create tk\n");
return -1;
}
- ret |= EC_TEST_CHECK_TK_PARSE(tk, 1, "0", EC_TK_ENDLIST);
- ret |= EC_TEST_CHECK_TK_PARSE(tk, 1, "-1", EC_TK_ENDLIST);
- ret |= EC_TEST_CHECK_TK_PARSE(tk, 1, "7fffffffffffffff", EC_TK_ENDLIST);
- ret |= EC_TEST_CHECK_TK_PARSE(tk, 1, "0x7fffffffffffffff", EC_TK_ENDLIST);
- ret |= EC_TEST_CHECK_TK_PARSE(tk, -1, "-2", EC_TK_ENDLIST);
+ ret |= EC_TEST_CHECK_TK_PARSE(tk, 1, "0");
+ ret |= EC_TEST_CHECK_TK_PARSE(tk, 1, "-1");
+ ret |= EC_TEST_CHECK_TK_PARSE(tk, 1, "7fffffffffffffff");
+ ret |= EC_TEST_CHECK_TK_PARSE(tk, 1, "0x7fffffffffffffff");
+ ret |= EC_TEST_CHECK_TK_PARSE(tk, -1, "-2");
p = ec_tk_parse(tk, "10");
s = ec_strvec_val(ec_parsed_tk_strvec(p), 0);
ec_log(EC_LOG_ERR, "cannot create tk\n");
return -1;
}
- ret |= EC_TEST_CHECK_TK_PARSE(tk, 1, "0", EC_TK_ENDLIST);
- ret |= EC_TEST_CHECK_TK_PARSE(tk, 1, "-1", EC_TK_ENDLIST);
- ret |= EC_TEST_CHECK_TK_PARSE(tk, 1, "-9223372036854775808",
- EC_TK_ENDLIST);
- ret |= EC_TEST_CHECK_TK_PARSE(tk, -1, "0x0", EC_TK_ENDLIST);
- ret |= EC_TEST_CHECK_TK_PARSE(tk, -1, "1", EC_TK_ENDLIST);
+ ret |= EC_TEST_CHECK_TK_PARSE(tk, 1, "0");
+ ret |= EC_TEST_CHECK_TK_PARSE(tk, 1, "-1");
+ ret |= EC_TEST_CHECK_TK_PARSE(tk, 1, "-9223372036854775808");
+ ret |= EC_TEST_CHECK_TK_PARSE(tk, -1, "0x0");
+ ret |= EC_TEST_CHECK_TK_PARSE(tk, -1, "1");
ec_tk_free(tk);
/* test completion */
.free_priv = ec_tk_many_free_priv,
};
-struct ec_tk *ec_tk_many_new(const char *id, struct ec_tk *child,
+struct ec_tk *ec_tk_many(const char *id, struct ec_tk *child,
unsigned int min, unsigned int max)
{
struct ec_tk_many *tk = NULL;
struct ec_tk *tk;
int ret = 0;
- tk = ec_tk_many_new(NULL, ec_tk_str(NULL, "foo"), 0, 0);
+ tk = ec_tk_many(NULL, ec_tk_str(NULL, "foo"), 0, 0);
if (tk == NULL) {
ec_log(EC_LOG_ERR, "cannot create tk\n");
return -1;
}
- ret |= EC_TEST_CHECK_TK_PARSE(tk, 0, "bar", EC_TK_ENDLIST);
- ret |= EC_TEST_CHECK_TK_PARSE(tk, 1, "foo", "bar", EC_TK_ENDLIST);
- ret |= EC_TEST_CHECK_TK_PARSE(tk, 2, "foo", "foo", "bar",
- EC_TK_ENDLIST);
- ret |= EC_TEST_CHECK_TK_PARSE(tk, 0, EC_TK_ENDLIST);
+ ret |= EC_TEST_CHECK_TK_PARSE(tk, 0, "bar");
+ ret |= EC_TEST_CHECK_TK_PARSE(tk, 1, "foo", "bar");
+ ret |= EC_TEST_CHECK_TK_PARSE(tk, 2, "foo", "foo", "bar");
+ ret |= EC_TEST_CHECK_TK_PARSE(tk, 0);
ec_tk_free(tk);
- tk = ec_tk_many_new(NULL, ec_tk_str(NULL, "foo"), 1, 0);
+ tk = ec_tk_many(NULL, ec_tk_str(NULL, "foo"), 1, 0);
if (tk == NULL) {
ec_log(EC_LOG_ERR, "cannot create tk\n");
return -1;
}
- ret |= EC_TEST_CHECK_TK_PARSE(tk, -1, "bar", EC_TK_ENDLIST);
- ret |= EC_TEST_CHECK_TK_PARSE(tk, 1, "foo", "bar", EC_TK_ENDLIST);
- ret |= EC_TEST_CHECK_TK_PARSE(tk, 2, "foo", "foo", "bar",
- EC_TK_ENDLIST);
- ret |= EC_TEST_CHECK_TK_PARSE(tk, -1, EC_TK_ENDLIST);
+ ret |= EC_TEST_CHECK_TK_PARSE(tk, -1, "bar");
+ ret |= EC_TEST_CHECK_TK_PARSE(tk, 1, "foo", "bar");
+ ret |= EC_TEST_CHECK_TK_PARSE(tk, 2, "foo", "foo", "bar");
+ ret |= EC_TEST_CHECK_TK_PARSE(tk, -1);
ec_tk_free(tk);
- tk = ec_tk_many_new(NULL, ec_tk_str(NULL, "foo"), 1, 2);
+ tk = ec_tk_many(NULL, ec_tk_str(NULL, "foo"), 1, 2);
if (tk == NULL) {
ec_log(EC_LOG_ERR, "cannot create tk\n");
return -1;
}
- ret |= EC_TEST_CHECK_TK_PARSE(tk, -1, "bar", EC_TK_ENDLIST);
- ret |= EC_TEST_CHECK_TK_PARSE(tk, 1, "foo", "bar", EC_TK_ENDLIST);
- ret |= EC_TEST_CHECK_TK_PARSE(tk, 2, "foo", "foo", "bar",
- EC_TK_ENDLIST);
- ret |= EC_TEST_CHECK_TK_PARSE(tk, 2, "foo", "foo", "foo",
- EC_TK_ENDLIST);
- ret |= EC_TEST_CHECK_TK_PARSE(tk, -1, EC_TK_ENDLIST);
+ ret |= EC_TEST_CHECK_TK_PARSE(tk, -1, "bar");
+ ret |= EC_TEST_CHECK_TK_PARSE(tk, 1, "foo", "bar");
+ ret |= EC_TEST_CHECK_TK_PARSE(tk, 2, "foo", "foo", "bar");
+ ret |= EC_TEST_CHECK_TK_PARSE(tk, 2, "foo", "foo", "foo");
+ ret |= EC_TEST_CHECK_TK_PARSE(tk, -1);
ec_tk_free(tk);
/* test completion */
/*
* if min == max == 0, there is no limit
*/
-struct ec_tk *ec_tk_many_new(const char *id, struct ec_tk *child,
+struct ec_tk *ec_tk_many(const char *id, struct ec_tk *child,
unsigned int min, unsigned int max);
#endif
ec_log(EC_LOG_ERR, "cannot create tk\n");
return -1;
}
- ret |= EC_TEST_CHECK_TK_PARSE(tk, 1, "foo", EC_TK_ENDLIST);
- ret |= EC_TEST_CHECK_TK_PARSE(tk, 1, "foo", "bar", EC_TK_ENDLIST);
- ret |= EC_TEST_CHECK_TK_PARSE(tk, 0, "bar", EC_TK_ENDLIST);
- ret |= EC_TEST_CHECK_TK_PARSE(tk, 0, EC_TK_ENDLIST);
+ ret |= EC_TEST_CHECK_TK_PARSE(tk, 1, "foo");
+ ret |= EC_TEST_CHECK_TK_PARSE(tk, 1, "foo", "bar");
+ ret |= EC_TEST_CHECK_TK_PARSE(tk, 0, "bar");
+ ret |= EC_TEST_CHECK_TK_PARSE(tk, 0);
ec_tk_free(tk);
/* test completion */
.free_priv = ec_tk_or_free_priv,
};
-struct ec_tk *ec_tk_or_new(const char *id)
-{
- struct ec_tk_or *tk = NULL;
-
- tk = (struct ec_tk_or *)ec_tk_new(id, &ec_tk_or_ops, sizeof(*tk));
- if (tk == NULL)
- return NULL;
-
- tk->table = NULL;
- tk->len = 0;
-
- return &tk->gen;
-}
-
int ec_tk_or_add(struct ec_tk *gen_tk, struct ec_tk *child)
{
struct ec_tk_or *tk = (struct ec_tk_or *)gen_tk;
if (child == NULL)
return -EINVAL;
- if (gen_tk->flags & EC_TK_F_INITIALIZED) {
- ec_tk_free(child);
- return -EPERM;
- }
+ gen_tk->flags &= ~EC_TK_F_BUILT;
table = ec_realloc(tk->table, (tk->len + 1) * sizeof(*tk->table));
if (table == NULL) {
return 0;
}
-int ec_tk_or_start(struct ec_tk *gen_tk)
+struct ec_tk *ec_tk_or(const char *id)
{
- if (gen_tk->flags & EC_TK_F_INITIALIZED)
- return -EPERM;
+ struct ec_tk *gen_tk = NULL;
+ struct ec_tk_or *tk = NULL;
+
+ gen_tk = ec_tk_new(id, &ec_tk_or_ops, sizeof(*tk));
+ if (gen_tk == NULL)
+ return NULL;
- gen_tk->flags |= EC_TK_F_INITIALIZED;
+ tk = (struct ec_tk_or *)gen_tk;
+ tk->table = NULL;
+ tk->len = 0;
- return 0;
+ return gen_tk;
}
-struct ec_tk *ec_tk_or(const char *id, ...)
+struct ec_tk *__ec_tk_or(const char *id, ...)
{
+ struct ec_tk *gen_tk = NULL;
struct ec_tk_or *tk = NULL;
struct ec_tk *child;
va_list ap;
va_start(ap, id);
- tk = (struct ec_tk_or *)ec_tk_or_new(id);
+ gen_tk = ec_tk_or(id);
+ tk = (struct ec_tk_or *)gen_tk;
if (tk == NULL)
- fail = 1;
+ fail = 1;;
for (child = va_arg(ap, struct ec_tk *);
child != EC_TK_ENDLIST;
/* on error, don't quit the loop to avoid leaks */
if (fail == 1 || child == NULL ||
- ec_tk_or_add(&tk->gen, child) < 0) {
+ ec_tk_or_add(gen_tk, child) < 0) {
fail = 1;
ec_tk_free(child);
}
goto fail;
va_end(ap);
- return &tk->gen;
+ return gen_tk;
fail:
- ec_tk_free(&tk->gen); /* will also free children */
+ ec_tk_free(gen_tk); /* will also free children */
va_end(ap);
return NULL;
}
struct ec_tk *tk;
int ret = 0;
- tk = ec_tk_or(NULL,
+ tk = EC_TK_OR(NULL,
ec_tk_str(NULL, "foo"),
- ec_tk_str(NULL, "bar"),
- EC_TK_ENDLIST);
+ ec_tk_str(NULL, "bar")
+ );
if (tk == NULL) {
ec_log(EC_LOG_ERR, "cannot create tk\n");
return -1;
}
- ret |= EC_TEST_CHECK_TK_PARSE(tk, 1, "foo", EC_TK_ENDLIST);
- ret |= EC_TEST_CHECK_TK_PARSE(tk, 1, "bar", EC_TK_ENDLIST);
- ret |= EC_TEST_CHECK_TK_PARSE(tk, 1, "foo", "bar", EC_TK_ENDLIST);
- ret |= EC_TEST_CHECK_TK_PARSE(tk, -1, " ", EC_TK_ENDLIST);
- ret |= EC_TEST_CHECK_TK_PARSE(tk, -1, "foox", EC_TK_ENDLIST);
- ret |= EC_TEST_CHECK_TK_PARSE(tk, -1, "toto", EC_TK_ENDLIST);
- ret |= EC_TEST_CHECK_TK_PARSE(tk, -1, "", EC_TK_ENDLIST);
+ ret |= EC_TEST_CHECK_TK_PARSE(tk, 1, "foo");
+ ret |= EC_TEST_CHECK_TK_PARSE(tk, 1, "bar");
+ ret |= EC_TEST_CHECK_TK_PARSE(tk, 1, "foo", "bar");
+ ret |= EC_TEST_CHECK_TK_PARSE(tk, -1, " ");
+ ret |= EC_TEST_CHECK_TK_PARSE(tk, -1, "foox");
+ ret |= EC_TEST_CHECK_TK_PARSE(tk, -1, "toto");
+ ret |= EC_TEST_CHECK_TK_PARSE(tk, -1, "");
ec_tk_free(tk);
/* test completion */
- tk = ec_tk_or(NULL,
+ tk = EC_TK_OR(NULL,
ec_tk_str(NULL, "foo"),
ec_tk_str(NULL, "bar"),
ec_tk_str(NULL, "bar2"),
ec_tk_str(NULL, "toto"),
- ec_tk_str(NULL, "titi"),
- EC_TK_ENDLIST);
+ ec_tk_str(NULL, "titi")
+ );
if (tk == NULL) {
ec_log(EC_LOG_ERR, "cannot create tk\n");
return -1;
#include <ecoli_tk.h>
+#define EC_TK_OR(args...) __ec_tk_or(args, EC_TK_ENDLIST)
+
/* list must be terminated with EC_TK_ENDLIST */
/* all token given in the list will be freed when freeing this one */
-struct ec_tk *ec_tk_or(const char *id, ...);
+/* avoid using this function directly, prefer the macro EC_TK_OR() or
+ * ec_tk_or() + ec_tk_or_add() */
+struct ec_tk *__ec_tk_or(const char *id, ...);
-struct ec_tk *ec_tk_or_new(const char *id);
+struct ec_tk *ec_tk_or(const char *id);
/* child is consumed */
/* all token given in the list will be freed when freeing this one */
int ec_tk_or_add(struct ec_tk *tk, struct ec_tk *child);
-int ec_tk_or_start(struct ec_tk *tk);
#endif
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+#include <regex.h>
+#include <errno.h>
+
+#include <ecoli_malloc.h>
+#include <ecoli_log.h>
+#include <ecoli_test.h>
+#include <ecoli_strvec.h>
+#include <ecoli_tk.h>
+#include <ecoli_tk_many.h>
+#include <ecoli_tk_or.h>
+#include <ecoli_tk_str.h>
+#include <ecoli_tk_int.h>
+#include <ecoli_tk_re_lex.h>
+
+struct regexp_pattern {
+ char *pattern;
+ regex_t r;
+ bool keep;
+};
+
+struct ec_tk_re_lex {
+ struct ec_tk gen;
+ struct ec_tk *child;
+ struct regexp_pattern *table;
+ size_t len;
+};
+
+static struct ec_strvec *
+tokenize(struct regexp_pattern *table, size_t table_len, const char *str)
+{
+ struct ec_strvec *strvec = NULL;
+ char *dup = NULL;
+ char c;
+ size_t len, off = 0;
+ size_t i;
+ int ret;
+ regmatch_t pos;
+
+ dup = ec_strdup(str);
+ if (dup == NULL)
+ goto fail;
+
+ strvec = ec_strvec_new();
+ if (strvec == NULL)
+ goto fail;
+
+ len = strlen(dup);
+ while (off < len) {
+ for (i = 0; i < table_len; i++) {
+ ret = regexec(&table[i].r, &dup[off], 1, &pos, 0);
+ if (ret != 0)
+ continue;
+ if (pos.rm_so != 0 || pos.rm_eo == 0) {
+ ret = -1;
+ continue;
+ }
+
+ if (table[i].keep == 0)
+ break;
+
+ c = dup[pos.rm_eo + off];
+ dup[pos.rm_eo + off] = '\0';
+ ec_log(EC_LOG_DEBUG, "re_lex match <%s>\n", &dup[off]);
+ if (ec_strvec_add(strvec, &dup[off]) < 0)
+ goto fail;
+
+ dup[pos.rm_eo + off] = c;
+ break;
+ }
+
+ if (ret != 0)
+ goto fail;
+
+ off += pos.rm_eo;
+ }
+
+ ec_free(dup);
+ return strvec;
+
+fail:
+ ec_free(dup);
+ ec_strvec_free(strvec);
+ return NULL;
+}
+
+static struct ec_parsed_tk *ec_tk_re_lex_parse(const struct ec_tk *gen_tk,
+ const struct ec_strvec *strvec)
+{
+ struct ec_tk_re_lex *tk = (struct ec_tk_re_lex *)gen_tk;
+ struct ec_strvec *new_vec = NULL, *match_strvec;
+ struct ec_parsed_tk *parsed_tk = NULL, *child_parsed_tk;
+ const char *str;
+
+ parsed_tk = ec_parsed_tk_new();
+ if (parsed_tk == NULL)
+ return NULL;
+
+ if (ec_strvec_len(strvec) == 0)
+ return parsed_tk;
+
+ str = ec_strvec_val(strvec, 0);
+ new_vec = tokenize(tk->table, tk->len, str);
+ if (new_vec == NULL)
+ goto fail;
+
+ child_parsed_tk = ec_tk_parse_tokens(tk->child, new_vec);
+ if (child_parsed_tk == NULL)
+ goto fail;
+
+ if (!ec_parsed_tk_matches(child_parsed_tk) ||
+ ec_parsed_tk_len(child_parsed_tk) !=
+ ec_strvec_len(new_vec)) {
+ ec_strvec_free(new_vec);
+ ec_parsed_tk_free(child_parsed_tk);
+ return parsed_tk;
+ }
+ ec_strvec_free(new_vec);
+ new_vec = NULL;
+
+ ec_parsed_tk_add_child(parsed_tk, child_parsed_tk);
+ match_strvec = ec_strvec_ndup(strvec, 0, 1);
+ if (match_strvec == NULL)
+ goto fail;
+ ec_parsed_tk_set_match(parsed_tk, gen_tk, match_strvec);
+
+ return parsed_tk;
+
+ fail:
+ ec_strvec_free(new_vec);
+ ec_parsed_tk_free(parsed_tk);
+
+ return NULL;
+}
+
+static void ec_tk_re_lex_free_priv(struct ec_tk *gen_tk)
+{
+ struct ec_tk_re_lex *tk = (struct ec_tk_re_lex *)gen_tk;
+ unsigned int i;
+
+ for (i = 0; i < tk->len; i++) {
+ ec_free(tk->table[i].pattern);
+ regfree(&tk->table[i].r);
+ }
+
+ ec_free(tk->table);
+ ec_tk_free(tk->child);
+}
+
+static struct ec_tk_ops ec_tk_re_lex_ops = {
+ .typename = "re_lex",
+ .parse = ec_tk_re_lex_parse,
+ //.complete = ec_tk_re_lex_complete,
+ .free_priv = ec_tk_re_lex_free_priv,
+};
+
+int ec_tk_re_lex_add(struct ec_tk *gen_tk, const char *pattern, int keep)
+{
+ struct ec_tk_re_lex *tk = (struct ec_tk_re_lex *)gen_tk;
+ struct regexp_pattern *table;
+ int ret;
+ char *pat_dup = NULL;
+
+ ret = -ENOMEM;
+ pat_dup = ec_strdup(pattern);
+ if (pat_dup == NULL)
+ goto fail;
+
+ ret = -ENOMEM;
+ table = ec_realloc(tk->table, sizeof(*table) * (tk->len + 1));
+ if (table == NULL)
+ goto fail;
+
+ ret = regcomp(&table[tk->len].r, pattern, REG_EXTENDED);
+ if (ret != 0) {
+ ec_log(EC_LOG_ERR,
+ "Regular expression compilation failed: %d\n",
+ ret);
+ if (ret == REG_ESPACE)
+ ret = -ENOMEM;
+ else
+ ret = -EINVAL;
+
+ goto fail;
+ }
+
+ table[tk->len].pattern = pat_dup;
+ table[tk->len].keep = keep;
+ tk->len++;
+ tk->table = table;
+
+ return 0;
+
+fail:
+ ec_free(pat_dup);
+ return ret;
+}
+
+struct ec_tk *ec_tk_re_lex(const char *id, struct ec_tk *child)
+{
+ struct ec_tk_re_lex *tk = NULL;
+
+ if (child == NULL)
+ return NULL;
+
+ tk = (struct ec_tk_re_lex *)ec_tk_new(id, &ec_tk_re_lex_ops,
+ sizeof(*tk));
+ if (tk == NULL) {
+ ec_tk_free(child);
+ return NULL;
+ }
+
+ tk->child = child;
+
+ return &tk->gen;
+}
+
+
+static int ec_tk_re_lex_testcase(void)
+{
+ struct ec_tk *tk;
+ int ret = 0;
+
+ tk = ec_tk_re_lex(NULL,
+ ec_tk_many(NULL,
+ EC_TK_OR(NULL,
+ ec_tk_str(NULL, "foo"),
+ ec_tk_str(NULL, "bar"),
+ ec_tk_int(NULL, 0, 1000, 0)
+ ), 0, 0
+ )
+ );
+ if (tk == NULL) {
+ ec_log(EC_LOG_ERR, "cannot create tk\n");
+ return -1;
+ }
+
+ /* XXX add ^ automatically */
+ ret |= ec_tk_re_lex_add(tk, "^[a-zA-Z]+", 1);
+ ret |= ec_tk_re_lex_add(tk, "^[0-9]+", 1);
+ ret |= ec_tk_re_lex_add(tk, "^=", 1);
+ ret |= ec_tk_re_lex_add(tk, "^-", 1);
+ ret |= ec_tk_re_lex_add(tk, "^\\+", 1);
+ ret |= ec_tk_re_lex_add(tk, "^[ ]+", 0);
+ if (ret != 0) {
+ ec_log(EC_LOG_ERR, "cannot add regexp to token\n");
+ return -1;
+ }
+
+ ret |= EC_TEST_CHECK_TK_PARSE(tk, 1, " foo bar 324 bar234");
+ ret |= EC_TEST_CHECK_TK_PARSE(tk, 1, "foo bar324");
+ ret |= EC_TEST_CHECK_TK_PARSE(tk, 1, "");
+ ret |= EC_TEST_CHECK_TK_PARSE(tk, -1, "foobar");
+
+ ec_tk_free(tk);
+
+ return ret;
+}
+
+static struct ec_test ec_tk_re_lex_test = {
+ .name = "tk_re_lex",
+ .test = ec_tk_re_lex_testcase,
+};
+
+EC_REGISTER_TEST(ec_tk_re_lex_test);
--- /dev/null
+/*
+ * Copyright (c) 2016-2017, Olivier MATZ <zer0@droids-corp.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ECOLI_TK_RE_LEX_
+#define ECOLI_TK_RE_LEX_
+
+#include <ecoli_tk.h>
+
+struct ec_tk *ec_tk_re_lex_new(const char *id, struct ec_tk *child);
+
+#endif
.free_priv = ec_tk_seq_free_priv,
};
-struct ec_tk *ec_tk_seq_new(const char *id)
-{
- struct ec_tk_seq *tk = NULL;
-
- tk = (struct ec_tk_seq *)ec_tk_new(id, &ec_tk_seq_ops, sizeof(*tk));
- if (tk == NULL)
- return NULL;
-
- tk->table = NULL;
- tk->len = 0;
-
- return &tk->gen;
-}
-
int ec_tk_seq_add(struct ec_tk *gen_tk, struct ec_tk *child)
{
struct ec_tk_seq *tk = (struct ec_tk_seq *)gen_tk;
if (child == NULL)
return -EINVAL;
- if (gen_tk->flags & EC_TK_F_INITIALIZED) {
- ec_tk_free(child);
- return -EPERM;
- }
+ gen_tk->flags &= ~EC_TK_F_BUILT;
table = ec_realloc(tk->table, (tk->len + 1) * sizeof(*tk->table));
if (table == NULL) {
return 0;
}
-int ec_tk_seq_start(struct ec_tk *gen_tk)
+struct ec_tk *ec_tk_seq(const char *id)
{
- if (gen_tk->flags & EC_TK_F_INITIALIZED)
- return -EPERM;
+ struct ec_tk *gen_tk = NULL;
+ struct ec_tk_seq *tk = NULL;
- gen_tk->flags |= EC_TK_F_INITIALIZED;
+ gen_tk = ec_tk_new(id, &ec_tk_seq_ops, sizeof(*tk));
+ if (gen_tk == NULL)
+ return NULL;
- return 0;
+ tk = (struct ec_tk_seq *)gen_tk;
+ tk->table = NULL;
+ tk->len = 0;
+
+ return gen_tk;
}
-struct ec_tk *ec_tk_seq(const char *id, ...)
+struct ec_tk *__ec_tk_seq(const char *id, ...)
{
+ struct ec_tk *gen_tk = NULL;
struct ec_tk_seq *tk = NULL;
struct ec_tk *child;
va_list ap;
va_start(ap, id);
- tk = (struct ec_tk_seq *)ec_tk_seq_new(id);
+ gen_tk = ec_tk_seq(id);
+ tk = (struct ec_tk_seq *)gen_tk;
if (tk == NULL)
- fail = 1;
+ fail = 1;;
for (child = va_arg(ap, struct ec_tk *);
child != EC_TK_ENDLIST;
goto fail;
va_end(ap);
- return &tk->gen;
+ return gen_tk;
fail:
- ec_tk_free(&tk->gen); /* will also free children */
+ ec_tk_free(gen_tk); /* will also free children */
va_end(ap);
return NULL;
}
struct ec_tk *tk;
int ret = 0;
- tk = ec_tk_seq(NULL,
+ tk = EC_TK_SEQ(NULL,
ec_tk_str(NULL, "foo"),
- ec_tk_str(NULL, "bar"),
- EC_TK_ENDLIST);
+ ec_tk_str(NULL, "bar")
+ );
if (tk == NULL) {
ec_log(EC_LOG_ERR, "cannot create tk\n");
return -1;
}
- ret |= EC_TEST_CHECK_TK_PARSE(tk, 2, "foo", "bar", EC_TK_ENDLIST);
- ret |= EC_TEST_CHECK_TK_PARSE(tk, 2, "foo", "bar", "toto",
- EC_TK_ENDLIST);
- ret |= EC_TEST_CHECK_TK_PARSE(tk, -1, "foo", EC_TK_ENDLIST);
- ret |= EC_TEST_CHECK_TK_PARSE(tk, -1, "foox", "bar", EC_TK_ENDLIST);
- ret |= EC_TEST_CHECK_TK_PARSE(tk, -1, "foo", "barx", EC_TK_ENDLIST);
- ret |= EC_TEST_CHECK_TK_PARSE(tk, -1, "bar", "foo", EC_TK_ENDLIST);
- ret |= EC_TEST_CHECK_TK_PARSE(tk, -1, "", "foo", EC_TK_ENDLIST);
+ ret |= EC_TEST_CHECK_TK_PARSE(tk, 2, "foo", "bar");
+ ret |= EC_TEST_CHECK_TK_PARSE(tk, 2, "foo", "bar", "toto");
+ ret |= EC_TEST_CHECK_TK_PARSE(tk, -1, "foo");
+ ret |= EC_TEST_CHECK_TK_PARSE(tk, -1, "foox", "bar");
+ ret |= EC_TEST_CHECK_TK_PARSE(tk, -1, "foo", "barx");
+ ret |= EC_TEST_CHECK_TK_PARSE(tk, -1, "bar", "foo");
+ ret |= EC_TEST_CHECK_TK_PARSE(tk, -1, "", "foo");
ec_tk_free(tk);
/* test completion */
- tk = ec_tk_seq(NULL,
+ tk = EC_TK_SEQ(NULL,
ec_tk_str(NULL, "foo"),
ec_tk_option_new(NULL, ec_tk_str(NULL, "toto")),
- ec_tk_str(NULL, "bar"),
- EC_TK_ENDLIST);
+ ec_tk_str(NULL, "bar")
+ );
if (tk == NULL) {
ec_log(EC_LOG_ERR, "cannot create tk\n");
return -1;
#include <ecoli_tk.h>
+#define EC_TK_SEQ(args...) __ec_tk_seq(args, EC_TK_ENDLIST)
/* list must be terminated with EC_TK_ENDLIST */
-struct ec_tk *ec_tk_seq(const char *id, ...);
+/* all token given in the list will be freed when freeing this one */
+/* avoid using this function directly, prefer the macro EC_TK_SEQ() or
+ * ec_tk_seq() + ec_tk_seq_add() */
+struct ec_tk *__ec_tk_seq(const char *id, ...);
-struct ec_tk *ec_tk_seq_new(const char *id);
+struct ec_tk *ec_tk_seq(const char *id);
/* child is consumed */
/* all token given in the list will be freed when freeing this one */
int ec_tk_seq_add(struct ec_tk *tk, struct ec_tk *child);
-int ec_tk_seq_start(struct ec_tk *tk);
-
#endif
concat = NULL;
}
+ /* XXX remove all printf comments */
// printf("str off=%zd len=%zd\n", off, len);
off += len;
}
int ret = 0;
tk = ec_tk_shlex_new(NULL,
- ec_tk_seq(NULL,
+ EC_TK_SEQ(NULL,
ec_tk_str(NULL, "foo"),
ec_tk_option_new(NULL,
ec_tk_str(NULL, "toto")
),
- ec_tk_str(NULL, "bar"),
- EC_TK_ENDLIST
+ ec_tk_str(NULL, "bar")
)
);
if (tk == NULL) {
ec_log(EC_LOG_ERR, "cannot create tk\n");
return -1;
}
- ret |= EC_TEST_CHECK_TK_PARSE(tk, 1, "foo bar", EC_TK_ENDLIST);
- ret |= EC_TEST_CHECK_TK_PARSE(tk, 1, " foo bar", EC_TK_ENDLIST);
- ret |= EC_TEST_CHECK_TK_PARSE(tk, 1, " 'foo' \"bar\"", EC_TK_ENDLIST);
- ret |= EC_TEST_CHECK_TK_PARSE(tk, 1, " 'f'oo 'toto' bar",
- EC_TK_ENDLIST);
+ ret |= EC_TEST_CHECK_TK_PARSE(tk, 1, "foo bar");
+ ret |= EC_TEST_CHECK_TK_PARSE(tk, 1, " foo bar");
+ ret |= EC_TEST_CHECK_TK_PARSE(tk, 1, " 'foo' \"bar\"");
+ ret |= EC_TEST_CHECK_TK_PARSE(tk, 1, " 'f'oo 'toto' bar");
ec_tk_free(tk);
/* test completion */
tk = ec_tk_shlex_new(NULL,
- ec_tk_seq(NULL,
+ EC_TK_SEQ(NULL,
ec_tk_str(NULL, "foo"),
ec_tk_option_new(NULL,
ec_tk_str(NULL, "toto")
),
ec_tk_str(NULL, "bar"),
- ec_tk_str(NULL, "titi"),
- EC_TK_ENDLIST
+ ec_tk_str(NULL, "titi")
)
);
if (tk == NULL) {
ec_log(EC_LOG_ERR, "cannot create tk\n");
return -1;
}
- ret |= EC_TEST_CHECK_TK_PARSE(tk, 1, " ", EC_TK_ENDLIST);
- ret |= EC_TEST_CHECK_TK_PARSE(tk, 1, " ", "foo", EC_TK_ENDLIST);
- ret |= EC_TEST_CHECK_TK_PARSE(tk, -1, "", EC_TK_ENDLIST);
- ret |= EC_TEST_CHECK_TK_PARSE(tk, -1, " foo", EC_TK_ENDLIST);
- ret |= EC_TEST_CHECK_TK_PARSE(tk, -1, "foo ", EC_TK_ENDLIST);
+ ret |= EC_TEST_CHECK_TK_PARSE(tk, 1, " ");
+ ret |= EC_TEST_CHECK_TK_PARSE(tk, 1, " ", "foo");
+ ret |= EC_TEST_CHECK_TK_PARSE(tk, -1, "");
+ ret |= EC_TEST_CHECK_TK_PARSE(tk, -1, " foo");
+ ret |= EC_TEST_CHECK_TK_PARSE(tk, -1, "foo ");
ec_tk_free(tk);
/* test completion */
return -EINVAL;
if (tk->string != NULL)
return -EEXIST;
- if (gen_tk->flags & EC_TK_F_INITIALIZED)
- return -EPERM;
tk->string = ec_strdup(str);
if (tk->string == NULL)
return 0;
}
-int ec_tk_str_start(struct ec_tk *gen_tk)
-{
- if (gen_tk->flags & EC_TK_F_INITIALIZED)
- return -EPERM;
-
- gen_tk->flags |= EC_TK_F_INITIALIZED;
-
- return 0;
-}
-
struct ec_tk *ec_tk_str(const char *id, const char *str)
{
struct ec_tk *gen_tk = NULL;
if (ec_tk_str_set_str(gen_tk, str) < 0)
goto fail;
- if (ec_tk_str_start(gen_tk) < 0)
- goto fail;
-
return gen_tk;
fail:
ec_log(EC_LOG_ERR, "cannot create tk\n");
return -1;
}
- ret |= EC_TEST_CHECK_TK_PARSE(tk, 1, "foo", EC_TK_ENDLIST);
- ret |= EC_TEST_CHECK_TK_PARSE(tk, 1, "foo", "bar", EC_TK_ENDLIST);
- ret |= EC_TEST_CHECK_TK_PARSE(tk, -1, "foobar", EC_TK_ENDLIST);
- ret |= EC_TEST_CHECK_TK_PARSE(tk, -1, " foo", EC_TK_ENDLIST);
- ret |= EC_TEST_CHECK_TK_PARSE(tk, -1, "", EC_TK_ENDLIST);
+ ret |= EC_TEST_CHECK_TK_PARSE(tk, 1, "foo");
+ ret |= EC_TEST_CHECK_TK_PARSE(tk, 1, "foo", "bar");
+ ret |= EC_TEST_CHECK_TK_PARSE(tk, -1, "foobar");
+ ret |= EC_TEST_CHECK_TK_PARSE(tk, -1, " foo");
+ ret |= EC_TEST_CHECK_TK_PARSE(tk, -1, "");
ec_tk_free(tk);
tk = ec_tk_str(NULL, "Здравствуйте");
ec_log(EC_LOG_ERR, "cannot create tk\n");
return -1;
}
- ret |= EC_TEST_CHECK_TK_PARSE(tk, 1, "Здравствуйте", EC_TK_ENDLIST);
+ ret |= EC_TEST_CHECK_TK_PARSE(tk, 1, "Здравствуйте");
ret |= EC_TEST_CHECK_TK_PARSE(tk, 1, "Здравствуйте",
- "John!", EC_TK_ENDLIST);
- ret |= EC_TEST_CHECK_TK_PARSE(tk, -1, "foo", EC_TK_ENDLIST);
- ret |= EC_TEST_CHECK_TK_PARSE(tk, -1, "", EC_TK_ENDLIST);
+ "John!");
+ ret |= EC_TEST_CHECK_TK_PARSE(tk, -1, "foo");
+ ret |= EC_TEST_CHECK_TK_PARSE(tk, -1, "");
ec_tk_free(tk);
/* an empty token string always matches */
ec_log(EC_LOG_ERR, "cannot create tk\n");
return -1;
}
- ret |= EC_TEST_CHECK_TK_PARSE(tk, 1, "", EC_TK_ENDLIST);
- ret |= EC_TEST_CHECK_TK_PARSE(tk, 1, "", "foo", EC_TK_ENDLIST);
- ret |= EC_TEST_CHECK_TK_PARSE(tk, -1, "foo", EC_TK_ENDLIST);
+ ret |= EC_TEST_CHECK_TK_PARSE(tk, 1, "");
+ ret |= EC_TEST_CHECK_TK_PARSE(tk, 1, "", "foo");
+ ret |= EC_TEST_CHECK_TK_PARSE(tk, -1, "foo");
ec_tk_free(tk);
/* test completion */
struct ec_tk *ec_tk_str(const char *id, const char *str);
struct ec_tk *ec_tk_str_new(const char *id);
+
+/* str is duplicated */
int ec_tk_str_set_str(struct ec_tk *tk, const char *str);
-int ec_tk_str_start(struct ec_tk *tk);
#endif
{
struct ec_tk *cmdlist = NULL, *cmd = NULL;
- cmdlist = ec_tk_or_new(NULL);
+ cmdlist = ec_tk_or(NULL);
if (cmdlist == NULL)
goto fail;
- cmd = ec_tk_seq(NULL,
+ cmd = EC_TK_SEQ(NULL,
ec_tk_str(NULL, "hello"),
- ec_tk_or(NULL,
- ec_tk_or("name",
+ EC_TK_OR(NULL,
+ EC_TK_OR("name",
ec_tk_str(NULL, "john"),
ec_tk_str(NULL, "johnny"),
- ec_tk_str(NULL, "mike"),
- EC_TK_ENDLIST
+ ec_tk_str(NULL, "mike")
),
- ec_tk_int("int", 0, 10, 10),
- EC_TK_ENDLIST
- ),
- EC_TK_ENDLIST
+ ec_tk_int("int", 0, 10, 10)
+ )
);
ec_keyval_set(ec_tk_attrs(cmd), "help", "say hello to someone", NULL);
ec_keyval_set(ec_tk_attrs(ec_tk_find(cmd, "name")),
if (ec_tk_or_add(cmdlist, cmd) < 0)
goto fail;
- cmd = ec_tk_seq(NULL,
- ec_tk_str(NULL, "bye"),
- EC_TK_ENDLIST
+ cmd = EC_TK_SEQ(NULL,
+ ec_tk_str(NULL, "bye")
);
ec_keyval_set(ec_tk_attrs(cmd), "help", "say bye to someone", NULL);
if (ec_tk_or_add(cmdlist, cmd) < 0)
" Show this help.\n"
" -l <level>\n"
" --"EC_OPT_LOG_LEVEL"=<level>\n"
- " Set log level (0 = no log, 6 = verbose).\n"
+ " Set log level (0 = no log, 7 = verbose).\n"
" -r <probability>\n"
" --"EC_OPT_RANDOM_ALLOC_FAIL"=<probability>\n"
" Cause malloc to fail randomly. This helps to debug\n"
--- /dev/null
+#!/bin/sh
+
+set -e
+
+SEED=100
+while [ ${SEED} -gt 0 ]; do
+ CMD="./build/test --random-alloc-fail=10 --seed=${SEED}"
+ ${CMD} --log-level=0 || (
+ echo "=== test failed, replay seed=${SEED} with logs ===" &&
+ ${CMD} --log-level=6 ||
+ echo "=== test failed: ${CMD}" &&
+ false
+ )
+
+ SEED=$((SEED-1)) && continue
+done