save
authorOlivier Matz <zer0@droids-corp.org>
Thu, 26 Jan 2017 18:07:37 +0000 (19:07 +0100)
committerOlivier Matz <zer0@droids-corp.org>
Thu, 26 Jan 2017 18:07:37 +0000 (19:07 +0100)
27 files changed:
lib/Makefile
lib/ecoli_test.c
lib/ecoli_test.h
lib/ecoli_tk.c
lib/ecoli_tk.h
lib/ecoli_tk_bypass.c
lib/ecoli_tk_bypass.h
lib/ecoli_tk_empty.c
lib/ecoli_tk_expr.c
lib/ecoli_tk_expr.h
lib/ecoli_tk_int.c
lib/ecoli_tk_many.c
lib/ecoli_tk_many.h
lib/ecoli_tk_option.c
lib/ecoli_tk_or.c
lib/ecoli_tk_or.h
lib/ecoli_tk_re_lex.c [new file with mode: 0644]
lib/ecoli_tk_re_lex.h [new file with mode: 0644]
lib/ecoli_tk_seq.c
lib/ecoli_tk_seq.h
lib/ecoli_tk_shlex.c
lib/ecoli_tk_space.c
lib/ecoli_tk_str.c
lib/ecoli_tk_str.h
lib/main-readline.c
lib/main.c
lib/test.sh [new file with mode: 0755]

index ba852eb..db3763c 100644 (file)
@@ -34,12 +34,10 @@ CFLAGS  = -g -O0 -Wall -Werror -W -fPIC
 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
index 4a7de26..fc82c69 100644 (file)
@@ -44,7 +44,7 @@ void ec_test_register(struct ec_test *test)
        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;
index 40ddefa..a05d4cf 100644 (file)
@@ -68,7 +68,7 @@ void ec_test_register(struct ec_test *test);
 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",                   \
@@ -80,8 +80,9 @@ int ec_test_check_tk_parse(const struct ec_tk *tk, int expected, ...);
                        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_;                                                           \
index 615ed85..624a5b9 100644 (file)
@@ -34,6 +34,7 @@
 #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,
@@ -44,6 +45,8 @@ 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;
@@ -131,7 +134,7 @@ struct ec_tk *ec_tk_parent(const struct ec_tk *tk)
        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;
@@ -156,10 +159,23 @@ struct ec_parsed_tk *ec_tk_parse(const struct ec_tk *tk, const char *str)
        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;
index b3f43bc..a86266c 100644 (file)
@@ -39,6 +39,9 @@ struct ec_parsed_tk;
 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,
@@ -48,6 +51,7 @@ typedef void (*ec_tk_free_priv_t)(struct ec_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;
@@ -64,7 +68,7 @@ struct ec_tk {
        /* 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;
@@ -113,12 +117,12 @@ void ec_parsed_tk_set_match(struct ec_parsed_tk *parsed_tk,
 /* 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,
index d2fe401..e71a14c 100644 (file)
@@ -76,7 +76,7 @@ static struct ec_tk_ops ec_tk_bypass_ops = {
        .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;
 
@@ -101,10 +101,7 @@ int ec_tk_bypass_set(struct ec_tk *gen_tk, struct ec_tk *child)
        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;
 
@@ -119,37 +116,13 @@ struct ec_tk *ec_tk_bypass_pop(struct ec_tk *gen_tk)
        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)
@@ -159,14 +132,13 @@ 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;
 }
index c20064a..92f84d9 100644 (file)
@@ -63,7 +63,7 @@
 
 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 */
index 196041c..ee6a4e6 100644 (file)
@@ -87,9 +87,9 @@ static int ec_tk_empty_testcase(void)
                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 */
index fe1b23f..4b54b9f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * 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;
@@ -84,31 +84,158 @@ static struct ec_completed_tk *ec_tk_expr_complete(const struct ec_tk *gen_tk,
 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;
@@ -124,231 +251,170 @@ struct ec_tk *ec_tk_expr_new(const char *id)
 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)
@@ -365,79 +431,62 @@ 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;
@@ -450,27 +499,20 @@ static int ec_tk_expr_testcase_manual(void)
        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);
@@ -479,23 +521,14 @@ static int ec_tk_expr_testcase_manual(void)
        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;
 }
 
@@ -508,7 +541,10 @@ static int ec_tk_expr_testcase(void)
        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, "*"));
@@ -516,19 +552,14 @@ static int ec_tk_expr_testcase(void)
        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;
index 84a1228..ca28e68 100644 (file)
 /* 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);
index 247426a..bd0155d 100644 (file)
@@ -121,7 +121,6 @@ struct ec_tk *ec_tk_int(const char *id, long long int min,
        tk->min = min;
        tk->max = max;
        tk->base = base;
-       gen_tk->flags |= EC_TK_F_INITIALIZED;
 
        return &tk->gen;
 }
@@ -151,12 +150,12 @@ static int ec_tk_int_testcase(void)
                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);
@@ -174,11 +173,11 @@ static int ec_tk_int_testcase(void)
                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);
@@ -191,12 +190,11 @@ static int ec_tk_int_testcase(void)
                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 */
index 3c37450..ecd54b8 100644 (file)
@@ -180,7 +180,7 @@ static struct ec_tk_ops ec_tk_many_ops = {
        .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;
@@ -207,42 +207,38 @@ static int ec_tk_many_testcase(void)
        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 */
index ed32075..107e4c7 100644 (file)
@@ -31,7 +31,7 @@
 /*
  * 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
index ab82d47..1170f7e 100644 (file)
@@ -130,10 +130,10 @@ static int ec_tk_option_testcase(void)
                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 */
index 04701e6..47264c5 100644 (file)
@@ -128,20 +128,6 @@ static struct ec_tk_ops ec_tk_or_ops = {
        .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;
@@ -152,10 +138,7 @@ int ec_tk_or_add(struct ec_tk *gen_tk, struct ec_tk *child)
        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) {
@@ -173,18 +156,25 @@ int ec_tk_or_add(struct ec_tk *gen_tk, struct ec_tk *child)
        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;
@@ -192,9 +182,10 @@ struct ec_tk *ec_tk_or(const char *id, ...)
 
        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;
@@ -202,7 +193,7 @@ struct ec_tk *ec_tk_or(const char *id, ...)
 
                /* 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);
                }
@@ -212,10 +203,10 @@ struct ec_tk *ec_tk_or(const char *id, ...)
                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;
 }
@@ -225,31 +216,31 @@ static int ec_tk_or_testcase(void)
        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;
index 6f11735..a4e1555 100644 (file)
 
 #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
diff --git a/lib/ecoli_tk_re_lex.c b/lib/ecoli_tk_re_lex.c
new file mode 100644 (file)
index 0000000..5dd273d
--- /dev/null
@@ -0,0 +1,268 @@
+#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);
diff --git a/lib/ecoli_tk_re_lex.h b/lib/ecoli_tk_re_lex.h
new file mode 100644 (file)
index 0000000..877a41a
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * 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
index 889ea34..807ff22 100644 (file)
@@ -169,20 +169,6 @@ static struct ec_tk_ops ec_tk_seq_ops = {
        .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;
@@ -195,10 +181,7 @@ int ec_tk_seq_add(struct ec_tk *gen_tk, struct ec_tk *child)
        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) {
@@ -216,18 +199,25 @@ int ec_tk_seq_add(struct ec_tk *gen_tk, struct ec_tk *child)
        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;
@@ -235,9 +225,10 @@ struct ec_tk *ec_tk_seq(const char *id, ...)
 
        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;
@@ -255,10 +246,10 @@ struct ec_tk *ec_tk_seq(const char *id, ...)
                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;
 }
@@ -268,30 +259,29 @@ static int ec_tk_seq_testcase(void)
        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;
index 5340fbf..ffc9fa3 100644 (file)
 
 #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
index 0becba5..a7bb6ff 100644 (file)
@@ -212,6 +212,7 @@ static struct ec_strvec *tokenize(const char *str, int completion,
                        concat = NULL;
                }
 
+               /* XXX remove all printf comments */
 //             printf("str off=%zd len=%zd\n", off, len);
                off += len;
        }
@@ -402,36 +403,33 @@ static int ec_tk_shlex_testcase(void)
        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) {
index 33f33d8..fc3a5b3 100644 (file)
@@ -96,11 +96,11 @@ static int ec_tk_space_testcase(void)
                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 */
index 2904713..0644905 100644 (file)
@@ -156,8 +156,6 @@ int ec_tk_str_set_str(struct ec_tk *gen_tk, const char *str)
                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)
@@ -168,16 +166,6 @@ int ec_tk_str_set_str(struct ec_tk *gen_tk, const char *str)
        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;
@@ -189,9 +177,6 @@ struct ec_tk *ec_tk_str(const char *id, const char *str)
        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:
@@ -209,11 +194,11 @@ static int ec_tk_str_testcase(void)
                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, "Здравствуйте");
@@ -221,11 +206,11 @@ static int ec_tk_str_testcase(void)
                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 */
@@ -234,9 +219,9 @@ static int ec_tk_str_testcase(void)
                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 */
index 4371823..d4e2503 100644 (file)
@@ -33,7 +33,8 @@
 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
index db1574e..9489b70 100644 (file)
@@ -171,23 +171,20 @@ static int create_commands(void)
 {
        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")),
@@ -197,9 +194,8 @@ static int create_commands(void)
        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)
index deffea3..d716fec 100644 (file)
@@ -71,7 +71,7 @@ static void usage(const char *prgname)
                "      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"
diff --git a/lib/test.sh b/lib/test.sh
new file mode 100755 (executable)
index 0000000..b71086e
--- /dev/null
@@ -0,0 +1,16 @@
+#!/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