]> git.droids-corp.org - protos/libecoli.git/commitdiff
save
authorOlivier Matz <zer0@droids-corp.org>
Thu, 12 Jan 2017 19:24:49 +0000 (20:24 +0100)
committerOlivier Matz <zer0@droids-corp.org>
Thu, 12 Jan 2017 19:24:49 +0000 (20:24 +0100)
lib/Makefile
lib/ecoli_tk.c
lib/ecoli_tk_bypass.c [new file with mode: 0644]
lib/ecoli_tk_bypass.h [new file with mode: 0644]
lib/ecoli_tk_expr.c
lib/ecoli_tk_or.c
lib/ecoli_tk_or.h
lib/ecoli_tk_seq.c
lib/ecoli_tk_seq.h
lib/main-readline.c

index ba88840345917e8cc043ab47d56d770285a96e3f..ba852eb24e39516bce84651d413d0e0f77ba32d7 100644 (file)
@@ -39,7 +39,7 @@ 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
+srcs += ecoli_tk_shlex.c ecoli_tk_expr.c ecoli_tk_bypass.c
 shlib-y-$(O)libecoli.so := $(srcs)
 
 ldflags-$(O)test = -rdynamic
index db28b53e58e912154faad482be67e22f166d9b63..615ed85302a4707ff0d84fc598d78d9a696a7ff4 100644 (file)
@@ -79,6 +79,8 @@ void ec_tk_free(struct ec_tk *tk)
        if (tk == NULL)
                return;
 
+       assert(tk->refcnt > 0);
+
        if (--tk->refcnt > 0)
                return;
 
diff --git a/lib/ecoli_tk_bypass.c b/lib/ecoli_tk_bypass.c
new file mode 100644 (file)
index 0000000..d2fe401
--- /dev/null
@@ -0,0 +1,184 @@
+/*
+ * Copyright (c) 2016, 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <stdarg.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_str.h>
+#include <ecoli_tk_option.h>
+#include <ecoli_tk_bypass.h>
+
+struct ec_tk_bypass {
+       struct ec_tk gen;
+       struct ec_tk *child;
+};
+
+static struct ec_parsed_tk *ec_tk_bypass_parse(const struct ec_tk *gen_tk,
+       const struct ec_strvec *strvec)
+{
+       struct ec_tk_bypass *tk = (struct ec_tk_bypass *)gen_tk;
+
+       return ec_tk_parse_tokens(tk->child, strvec);
+}
+
+static struct ec_completed_tk *ec_tk_bypass_complete(const struct ec_tk *gen_tk,
+       const struct ec_strvec *strvec)
+{
+       struct ec_tk_bypass *tk = (struct ec_tk_bypass *)gen_tk;
+
+       return ec_tk_complete_tokens(tk->child, strvec);
+}
+
+static void ec_tk_bypass_free_priv(struct ec_tk *gen_tk)
+{
+       struct ec_tk_bypass *tk = (struct ec_tk_bypass *)gen_tk;
+
+       ec_tk_free(tk->child);
+}
+
+static struct ec_tk_ops ec_tk_bypass_ops = {
+       .typename = "bypass",
+       .parse = ec_tk_bypass_parse,
+       .complete = ec_tk_bypass_complete,
+       .free_priv = ec_tk_bypass_free_priv,
+};
+
+struct ec_tk *ec_tk_bypass_new(const char *id)
+{
+       struct ec_tk_bypass *tk = NULL;
+
+       tk = (struct ec_tk_bypass *)ec_tk_new(id,
+               &ec_tk_bypass_ops, sizeof(*tk));
+       if (tk == NULL)
+               return NULL;
+
+       tk->child = NULL;
+
+       return &tk->gen;
+}
+
+int ec_tk_bypass_set(struct ec_tk *gen_tk, struct ec_tk *child)
+{
+       struct ec_tk_bypass *tk = (struct ec_tk_bypass *)gen_tk;
+
+       // XXX check tk type
+
+       assert(tk != NULL);
+
+       if (child == NULL)
+               return -EINVAL;
+
+       if (gen_tk->flags & EC_TK_F_INITIALIZED) {
+               ec_tk_free(child);
+               return -EPERM;
+       }
+
+       tk->child = child;
+
+       child->parent = gen_tk;
+       TAILQ_INSERT_TAIL(&gen_tk->children, child, next); // XXX really needed?
+
+       return 0;
+}
+
+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;
+}
+
+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;
+}
+
+struct ec_tk *ec_tk_bypass(const char *id, struct ec_tk *child)
+{
+       struct ec_tk *gen_tk = NULL;
+
+       if (child == NULL)
+               return NULL;
+
+       gen_tk = ec_tk_bypass_new(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;
+}
+
+static int ec_tk_bypass_testcase(void)
+{
+       return 0;
+}
+
+static struct ec_test ec_tk_bypass_test = {
+       .name = "tk_bypass",
+       .test = ec_tk_bypass_testcase,
+};
+
+EC_REGISTER_TEST(ec_tk_bypass_test);
diff --git a/lib/ecoli_tk_bypass.h b/lib/ecoli_tk_bypass.h
new file mode 100644 (file)
index 0000000..c20064a
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2016, 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_BYPASS_
+#define ECOLI_TK_BYPASS_
+
+#include <ecoli_tk.h>
+
+/// XXX rename in loop ?
+//  XXX + provide the helper to free ?
+
+/* a tk that just behaves like its child
+ * useful to create cyclic graphs of tokens:
+ *   creating a loop (with clones) result in something that is not
+ *   freeable, due to reference counters
+ * bypass node can solve the issue: before freeing the graph,
+ * the loop can be cut, falling back to a valid tree that can
+ * be freed.
+ *
+ * Example:
+ *   seq = seq()
+ *   i = int()
+ *   seq_add(seq, i)
+ *   seq_add(seq, clone(seq))
+ *     FAIL, cannot be freed
+ *
+ *   seq = seq()
+ *   bypass = bypass(clone(seq))
+ *   i = int()
+ *   seq_add(seq, i)
+ *   seq_add(seq, bypass)
+ *
+ *   TO FREE:
+ *     seq2 = bypass_del(bypass) // breaks the loop (seq2 == seq)
+ *     free(bypass)
+ *     free(seq2)
+ *     free(seq)
+ */
+
+struct ec_tk *ec_tk_bypass(const char *id, struct ec_tk *child);
+
+struct ec_tk *ec_tk_bypass_new(const char *id);
+
+/* child is consumed */
+/* all token given in the list will be freed when freeing this one */
+int ec_tk_bypass_set(struct ec_tk *tk, struct ec_tk *child);
+
+struct ec_tk *ec_tk_bypass_pop(struct ec_tk *gen_tk);
+
+#endif
index 2117d36577d9be5ac0f407ebe2e44c81ab13cc7f..fe1b23fdb3839bf992a9cc8c7fe2dc45f6b8c2e5 100644 (file)
@@ -44,6 +44,7 @@
 #include <ecoli_tk_many.h>
 #include <ecoli_tk_or.h>
 #include <ecoli_tk_expr.h>
+#include <ecoli_tk_bypass.h>
 
 struct ec_tk_expr {
        struct ec_tk gen;
@@ -83,8 +84,21 @@ 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;
+       unsigned int i;
 
        ec_tk_free(tk->child);
+       ec_tk_free(tk->val_tk);
+
+       for (i = 0; i < tk->bin_ops_len; i++)
+               ec_tk_free(tk->bin_ops[i]);
+       for (i = 0; i < tk->pre_ops_len; i++)
+               ec_tk_free(tk->pre_ops[i]);
+       for (i = 0; i < tk->post_ops_len; i++)
+               ec_tk_free(tk->post_ops[i]);
+       for (i = 0; i < tk->paren_len; i++) {
+               ec_tk_free(tk->open_ops[i]);
+               ec_tk_free(tk->close_ops[i]);
+       }
 }
 
 static struct ec_tk_ops ec_tk_expr_ops = {
@@ -228,7 +242,7 @@ 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,
-               *val = NULL, *pre_op = NULL, *post_op = NULL,
+               *pre_op = NULL, *post_op = NULL,
                *post = NULL, *final = NULL, *next = NULL;
        unsigned int i;
 
@@ -242,9 +256,7 @@ int ec_tk_expr_start(struct ec_tk *gen_tk)
 
        /* create the object, we will initialize it later: this is
         * needed because we have a circular dependency */
-       expr = ec_tk_seq_new("expr");
-
-       val = ec_tk_int("val", 0, UCHAR_MAX, 0);
+       expr = ec_tk_bypass_new("expr");
 
        /* prefix unary operators */
        pre_op = ec_tk_or_new("pre-op");
@@ -265,7 +277,7 @@ int ec_tk_expr_start(struct ec_tk *gen_tk)
                goto fail;
 
        term = ec_tk_or_new("term");
-       if (ec_tk_or_add(term, ec_tk_clone(val)) < 0)
+       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,
@@ -306,25 +318,43 @@ int ec_tk_expr_start(struct ec_tk *gen_tk)
                EC_TK_ENDLIST
        );
 
-       tk->child = final;
+       /* 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;
 
        return 0;
 
 fail:
-       ec_tk_free(val);
+       ec_tk_free(term);
+       ec_tk_free(expr);
        ec_tk_free(pre_op);
        ec_tk_free(post_op);
-       ec_tk_free(term);
        ec_tk_free(post);
+       ec_tk_free(final);
+
        return -1;
 }
 
-static int ec_tk_expr_testcase(void)
+static int ec_tk_expr_testcase_manual(void)
 {
-       struct ec_tk *term, *factor, *expr, *tk, *val,
-               *pre_op, *post_op, *post, *final;
+       struct ec_tk *term = NULL, *factor = NULL, *expr = NULL, *val = NULL,
+               *pre_op = NULL, *post_op = NULL, *post = NULL, *final = NULL;
        int ret = 0;
 
        // XXX check all APIs: pointers are "moved", they are freed by
@@ -335,24 +365,28 @@ static int ec_tk_expr_testcase(void)
 
        /* create the object, we will initialize it later: this is
         * needed because we have a circular dependency */
-       expr = ec_tk_seq_new("expr");
-
-       val = ec_tk_int("val", 0, UCHAR_MAX, 0);
+       ec_log(EC_LOG_INFO, "%d\n", __LINE__);
+       expr = ec_tk_bypass_new("expr");
 
+       ec_log(EC_LOG_INFO, "%d\n", __LINE__);
        /* reverse bits */
        pre_op = ec_tk_or("pre-op",
                ec_tk_str(NULL, "~"),
                EC_TK_ENDLIST
        );
+       ec_log(EC_LOG_INFO, "%d\n", __LINE__);
 
        /* factorial */
        post_op = ec_tk_or("post-op",
                ec_tk_str(NULL, "!"),
                EC_TK_ENDLIST
        );
+       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",
-               ec_tk_clone(val),
+               val,
                ec_tk_seq(NULL,
                        ec_tk_str(NULL, "("),
                        ec_tk_clone(expr),
@@ -366,6 +400,9 @@ static int ec_tk_expr_testcase(void)
                ),
                EC_TK_ENDLIST
        );
+       val = NULL;
+
+       ec_log(EC_LOG_INFO, "%d\n", __LINE__);
 
        factor = ec_tk_seq("factor",
                ec_tk_clone(term),
@@ -393,27 +430,35 @@ static int ec_tk_expr_testcase(void)
                EC_TK_ENDLIST
        );
 
+       ec_log(EC_LOG_INFO, "%d\n", __LINE__);
        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_log(EC_LOG_INFO, "%d\n", __LINE__);
        /* free the initial references */
-       ec_tk_free(val);
        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(factor);
+       factor = NULL;
        ec_tk_free(post);
+       post = NULL;
 
-       if (ec_tk_seq_add(expr, ec_tk_clone(final)) < 0) {
-               ec_tk_free(final);
-               ec_tk_free(expr);
-               return -1;
-       }
+       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);
@@ -427,7 +472,41 @@ static int ec_tk_expr_testcase(void)
        ret |= EC_TEST_CHECK_TK_PARSE(expr, 4, "1", "+", "~", "1",
                EC_TK_ENDLIST);
 
+       final = ec_tk_bypass_pop(expr);
        ec_tk_free(expr);
+       ec_tk_free(final);
+
+       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;
+}
+
+static int ec_tk_expr_testcase(void)
+{
+       struct ec_tk *tk;
+       int ret;
+
+       ret = ec_tk_expr_testcase_manual();
+       if (ret < 0)
+               return ret;
 
        tk = ec_tk_expr_new(NULL);
        ec_tk_expr_set_val_tk(tk, ec_tk_int(NULL, 0, UCHAR_MAX, 0));
@@ -437,18 +516,18 @@ 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);
+       ec_tk_expr_start(tk); // XXX start -> commit ?
 
-       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",
+       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(
-               expr, 10, "~", "(", "1", "*", "(", "1", "+", "1", ")", ")",
+               tk, 10, "~", "(", "1", "*", "(", "1", "+", "1", ")", ")",
                EC_TK_ENDLIST);
-       ret |= EC_TEST_CHECK_TK_PARSE(expr, 4, "1", "+", "~", "1",
+       ret |= EC_TEST_CHECK_TK_PARSE(tk, 4, "1", "+", "~", "1",
                EC_TK_ENDLIST);
        ec_tk_free(tk);
 
index d3e2d201baab16b932a5bcc9d753b6ed3f3470cc..04701e69fe0bd0d201b81d7acfc257240bb8d09a 100644 (file)
@@ -148,14 +148,20 @@ int ec_tk_or_add(struct ec_tk *gen_tk, struct ec_tk *child)
        struct ec_tk **table;
 
        assert(tk != NULL);
-       assert(child != NULL);
 
-       if (gen_tk->flags & EC_TK_F_INITIALIZED)
+       if (child == NULL)
+               return -EINVAL;
+
+       if (gen_tk->flags & EC_TK_F_INITIALIZED) {
+               ec_tk_free(child);
                return -EPERM;
+       }
 
        table = ec_realloc(tk->table, (tk->len + 1) * sizeof(*tk->table));
-       if (table == NULL)
+       if (table == NULL) {
+               ec_tk_free(child);
                return -1;
+       }
 
        tk->table = table;
        table[tk->len] = child;
index e11d96bfe36397969d889118cec5449ca9ba82ee..6f117358d1a09d3d0db2f6d87366b9c3a6ab3a53 100644 (file)
 struct ec_tk *ec_tk_or(const char *id, ...);
 
 struct ec_tk *ec_tk_or_new(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
index 3cfc06194cf2540f6b93eef83e4e4e779dc54cfd..889ea34370f2a70c42826220ea579ad12cd27dbb 100644 (file)
@@ -191,14 +191,20 @@ int ec_tk_seq_add(struct ec_tk *gen_tk, struct ec_tk *child)
        // XXX check tk type
 
        assert(tk != NULL);
-       assert(child != NULL);
 
-       if (gen_tk->flags & EC_TK_F_INITIALIZED)
+       if (child == NULL)
+               return -EINVAL;
+
+       if (gen_tk->flags & EC_TK_F_INITIALIZED) {
+               ec_tk_free(child);
                return -EPERM;
+       }
 
        table = ec_realloc(tk->table, (tk->len + 1) * sizeof(*tk->table));
-       if (table == NULL)
+       if (table == NULL) {
+               ec_tk_free(child);
                return -1;
+       }
 
        tk->table = table;
        table[tk->len] = child;
index 03c5834baaa031438e1de17a391b08c44c452de6..5340fbf71ae795116b77b5a1bfb3660f9c8916c3 100644 (file)
 struct ec_tk *ec_tk_seq(const char *id, ...);
 
 struct ec_tk *ec_tk_seq_new(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);
 
+int ec_tk_seq_start(struct ec_tk *tk);
 
 #endif
index 7432f3c57ffc47a782ac499643bc8477033ada18..db1574e50088526698acad3e666c4a495cb62998 100644 (file)
@@ -213,7 +213,6 @@ static int create_commands(void)
 
  fail:
        fprintf(stderr, "cannot initialize tokens\n");
-       ec_tk_free(cmd);
        ec_tk_free(cmdlist);
        return -1;
 }