From a5446c41e019dadff4138e778470fef063666310 Mon Sep 17 00:00:00 2001 From: Olivier Matz Date: Wed, 21 Dec 2016 20:10:49 +0100 Subject: [PATCH] save --- lib/ecoli_tk.h | 2 + lib/ecoli_tk_expr.c | 292 ++++++++++++++++++++++++++++++------------ lib/ecoli_tk_expr.h | 2 + lib/ecoli_tk_int.c | 17 ++- lib/ecoli_tk_int.h | 2 +- lib/ecoli_tk_many.c | 6 +- lib/ecoli_tk_option.c | 4 +- lib/ecoli_tk_or.c | 80 +++++++----- lib/ecoli_tk_or.h | 6 +- lib/ecoli_tk_seq.c | 78 ++++++----- lib/ecoli_tk_seq.h | 6 +- lib/ecoli_tk_shlex.c | 18 +-- lib/ecoli_tk_str.c | 65 ++++++++-- lib/ecoli_tk_str.h | 6 +- lib/main-readline.c | 20 +-- 15 files changed, 407 insertions(+), 197 deletions(-) diff --git a/lib/ecoli_tk.h b/lib/ecoli_tk.h index b417a03..b3f43bc 100644 --- a/lib/ecoli_tk.h +++ b/lib/ecoli_tk.h @@ -64,6 +64,8 @@ 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 + unsigned int flags; TAILQ_ENTRY(ec_tk) next; struct ec_tk_list children; diff --git a/lib/ecoli_tk_expr.c b/lib/ecoli_tk_expr.c index 5625727..2117d36 100644 --- a/lib/ecoli_tk_expr.c +++ b/lib/ecoli_tk_expr.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -38,8 +39,10 @@ #include #include #include +#include #include #include +#include #include struct ec_tk_expr { @@ -49,10 +52,16 @@ struct ec_tk_expr { 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 struct ec_parsed_tk *ec_tk_expr_parse(const struct ec_tk *gen_tk, @@ -119,9 +128,10 @@ int ec_tk_expr_add_bin_op(struct ec_tk *gen_tk, struct ec_tk *op) // XXX check tk type - /* XXX use assert or check like this ? */ if (tk == NULL || op == NULL) return -EINVAL; + if (gen_tk->flags & EC_TK_F_INITIALIZED) + return -EPERM; bin_ops = ec_realloc(tk->bin_ops, (tk->bin_ops_len + 1) * sizeof(*tk->bin_ops)); @@ -142,9 +152,10 @@ int ec_tk_expr_add_pre_op(struct ec_tk *gen_tk, struct ec_tk *op) // XXX check tk type - /* XXX use assert or check like this ? */ if (tk == NULL || op == NULL) return -EINVAL; + if (gen_tk->flags & EC_TK_F_INITIALIZED) + return -EPERM; pre_ops = ec_realloc(tk->pre_ops, (tk->pre_ops_len + 1) * sizeof(*tk->pre_ops)); @@ -165,9 +176,10 @@ int ec_tk_expr_add_post_op(struct ec_tk *gen_tk, struct ec_tk *op) // XXX check tk type - /* XXX use assert or check like this ? */ if (tk == NULL || op == NULL) return -EINVAL; + if (gen_tk->flags & EC_TK_F_INITIALIZED) + return -EPERM; post_ops = ec_realloc(tk->post_ops, (tk->post_ops_len + 1) * sizeof(*tk->post_ops)); @@ -181,112 +193,199 @@ int ec_tk_expr_add_post_op(struct ec_tk *gen_tk, struct ec_tk *op) return 0; } +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; + + // XXX check tk type + + if (tk == NULL || open == NULL || close == NULL) + return -EINVAL; + if (gen_tk->flags & EC_TK_F_INITIALIZED) + return -EPERM; + + open_ops = ec_realloc(tk->open_ops, + (tk->paren_len + 1) * sizeof(*tk->open_ops)); + if (open_ops == NULL) + return -1; + close_ops = ec_realloc(tk->close_ops, + (tk->paren_len + 1) * sizeof(*tk->close_ops)); + if (close_ops == NULL) + return -1; + + 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, + *val = NULL, *pre_op = NULL, *post_op = NULL, + *post = NULL, *final = NULL, *next = NULL; + unsigned int i; if (tk->val_tk == NULL) return -EINVAL; - if (tk->bin_ops_len == 0 || tk->pre_ops_len == 0 || + 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; - return 0; -} + /* create the object, we will initialize it later: this is + * needed because we have a circular dependency */ + expr = ec_tk_seq_new("expr"); -struct ec_tk *ec_tk_expr(const char *id, struct ec_tk *val_tk, - const char *bin_ops) -{ - struct ec_tk_expr *tk = NULL; - struct ec_tk *gen_tk = NULL, *child = NULL, *sub_expr = NULL; - char *op = NULL; + val = ec_tk_int("val", 0, UCHAR_MAX, 0); - gen_tk = ec_tk_expr_new(id); - if (gen_tk == NULL) + /* 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; - tk = (struct ec_tk_expr *)gen_tk; - if (bin_ops == NULL || bin_ops[0] == '\0') { - child = val_tk; - } else { - /* recursively create an expr tk without the first operator */ - sub_expr = ec_tk_expr(NULL, - ec_tk_clone(val_tk), - &bin_ops[1]); - if (sub_expr == NULL) + /* 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; - op = ec_strdup(bin_ops); - if (op == NULL) + term = ec_tk_or_new("term"); + if (ec_tk_or_add(term, ec_tk_clone(val)) < 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; - op[1] = '\0'; + } - /* we match: - * ( )* - */ - child = ec_tk_seq_new_list(NULL, - ec_tk_clone(sub_expr), + 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_new_list(NULL, - ec_tk_str_new(NULL, op), - ec_tk_clone(sub_expr), + ec_tk_seq(NULL, + ec_tk_clone(tk->bin_ops[i]), + ec_tk_clone(prev), EC_TK_ENDLIST ), 0, 0 ), EC_TK_ENDLIST ); - ec_free(op); - op = NULL; - - /* remove initial reference */ - ec_tk_free(sub_expr); + prev = next; + } - if (child == NULL) - goto fail; + final = ec_tk_seq("final", + ec_tk_clone(next), + ec_tk_many_new(NULL, ec_tk_clone(post_op), 0, 0), + EC_TK_ENDLIST + ); - ec_tk_free(val_tk); - } + tk->child = final; - tk->child = child; + gen_tk->flags |= EC_TK_F_INITIALIZED; - return &tk->gen; + return 0; fail: - ec_free(op); - ec_tk_free(child); - ec_tk_free(val_tk); - ec_tk_free(gen_tk); - return NULL; + ec_tk_free(val); + ec_tk_free(pre_op); + ec_tk_free(post_op); + ec_tk_free(term); + ec_tk_free(post); + return -1; } static int ec_tk_expr_testcase(void) { - struct ec_tk *tk, *tk2, *val_tk; + struct ec_tk *term, *factor, *expr, *tk, *val, + *pre_op, *post_op, *post, *final; int ret = 0; - val_tk = ec_tk_str_new(NULL, "val"); - tk = ec_tk_seq_new_list(NULL, - ec_tk_clone(val_tk), + // XXX check all APIs: pointers are "moved", they are freed by + // the callee + + /* Example that generates an expression "manually". We keep it + * here for reference. */ + + /* 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); + + /* reverse bits */ + pre_op = ec_tk_or("pre-op", + ec_tk_str(NULL, "~"), + EC_TK_ENDLIST + ); + + /* factorial */ + post_op = ec_tk_or("post-op", + ec_tk_str(NULL, "!"), + EC_TK_ENDLIST + ); + + term = ec_tk_or("term", + ec_tk_clone(val), + ec_tk_seq(NULL, + ec_tk_str(NULL, "("), + ec_tk_clone(expr), + ec_tk_str(NULL, ")"), + EC_TK_ENDLIST + ), + ec_tk_seq(NULL, + ec_tk_clone(pre_op), + ec_tk_clone(expr), + EC_TK_ENDLIST + ), + EC_TK_ENDLIST + ); + + factor = ec_tk_seq("factor", + ec_tk_clone(term), ec_tk_many_new(NULL, - ec_tk_seq_new_list(NULL, - ec_tk_str_new(NULL, "*"), - ec_tk_clone(val_tk), + ec_tk_seq(NULL, + ec_tk_str(NULL, "+"), + ec_tk_clone(term), EC_TK_ENDLIST ), 0, 0 ), EC_TK_ENDLIST ); - ec_tk_free(val_tk); - val_tk = NULL; - tk2 = ec_tk_seq_new_list(NULL, - ec_tk_clone(tk), + post = ec_tk_seq("post", + ec_tk_clone(factor), ec_tk_many_new(NULL, - ec_tk_seq_new_list(NULL, - ec_tk_str_new(NULL, "+"), - ec_tk_clone(tk), + ec_tk_seq(NULL, + ec_tk_str(NULL, "*"), + ec_tk_clone(factor), EC_TK_ENDLIST ), 0, 0 @@ -294,29 +393,62 @@ static int ec_tk_expr_testcase(void) EC_TK_ENDLIST ); + final = ec_tk_seq("final", + ec_tk_clone(post), + ec_tk_many_new(NULL, ec_tk_clone(post_op), 0, 0), + EC_TK_ENDLIST + ); -// "/*-+"); - if (tk2 == NULL) { - ec_log(EC_LOG_ERR, "cannot create tk\n"); + /* free the initial references */ + ec_tk_free(val); + ec_tk_free(pre_op); + ec_tk_free(post_op); + ec_tk_free(term); + ec_tk_free(factor); + ec_tk_free(post); + + if (ec_tk_seq_add(expr, ec_tk_clone(final)) < 0) { + ec_tk_free(final); + ec_tk_free(expr); return -1; } - ret |= EC_TEST_CHECK_TK_PARSE(tk, 1, "val", EC_TK_ENDLIST); - ret |= EC_TEST_CHECK_TK_PARSE(tk, 1, "val", "*", EC_TK_ENDLIST); - ret |= EC_TEST_CHECK_TK_PARSE(tk, 3, "val", "*", "val", EC_TK_ENDLIST); + ec_tk_free(final); - ret |= EC_TEST_CHECK_TK_PARSE(tk2, 1, "val", EC_TK_ENDLIST); - ret |= EC_TEST_CHECK_TK_PARSE(tk2, 1, "val", "*", EC_TK_ENDLIST); - ret |= EC_TEST_CHECK_TK_PARSE(tk2, 3, "val", "*", "val", EC_TK_ENDLIST); - ret |= EC_TEST_CHECK_TK_PARSE(tk2, 3, "val", "+", "val", EC_TK_ENDLIST); - ret |= EC_TEST_CHECK_TK_PARSE(tk2, 5, "val", "*", "val", "+", "val", + 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, 10, "~", "(", "1", "*", "(", "1", "+", "1", ")", ")", + EC_TK_ENDLIST); + ret |= EC_TEST_CHECK_TK_PARSE(expr, 4, "1", "+", "~", "1", EC_TK_ENDLIST); - ec_tk_free(tk); - ec_tk_free(tk2); - - tk = ec_tk_expr(NULL, ec_tk_str_new(NULL, "val"), "*+"); - ret |= EC_TEST_CHECK_TK_PARSE(tk, 5, "val", "*", "val", "+", "val", + ec_tk_free(expr); + + tk = ec_tk_expr_new(NULL); + 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_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); + + 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, 10, "~", "(", "1", "*", "(", "1", "+", "1", ")", ")", + EC_TK_ENDLIST); + ret |= EC_TEST_CHECK_TK_PARSE(expr, 4, "1", "+", "~", "1", EC_TK_ENDLIST); ec_tk_free(tk); diff --git a/lib/ecoli_tk_expr.h b/lib/ecoli_tk_expr.h index 73bce00..84a1228 100644 --- a/lib/ecoli_tk_expr.h +++ b/lib/ecoli_tk_expr.h @@ -40,6 +40,8 @@ struct ec_tk *ec_tk_expr_new(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); +int ec_tk_expr_add_parenthesis(struct ec_tk *gen_tk, + struct ec_tk *open, struct ec_tk *close); #endif diff --git a/lib/ecoli_tk_int.c b/lib/ecoli_tk_int.c index 5e404e9..247426a 100644 --- a/lib/ecoli_tk_int.c +++ b/lib/ecoli_tk_int.c @@ -107,18 +107,21 @@ static struct ec_tk_ops ec_tk_int_ops = { .complete = ec_tk_default_complete, }; -struct ec_tk *ec_tk_int_new(const char *id, long long int min, +struct ec_tk *ec_tk_int(const char *id, long long int min, long long int max, unsigned int base) { + struct ec_tk *gen_tk = NULL; struct ec_tk_int *tk = NULL; - tk = (struct ec_tk_int *)ec_tk_new(id, &ec_tk_int_ops, sizeof(*tk)); - if (tk == NULL) + gen_tk = ec_tk_new(id, &ec_tk_int_ops, sizeof(*tk)); + if (gen_tk == NULL) return NULL; + tk = (struct ec_tk_int *)gen_tk; tk->min = min; tk->max = max; tk->base = base; + gen_tk->flags |= EC_TK_F_INITIALIZED; return &tk->gen; } @@ -143,7 +146,7 @@ static int ec_tk_int_testcase(void) const char *s; int ret = 0; - tk = ec_tk_int_new(NULL, 0, 256, 0); + tk = ec_tk_int(NULL, 0, 256, 0); if (tk == NULL) { ec_log(EC_LOG_ERR, "cannot create tk\n"); return -1; @@ -166,7 +169,7 @@ static int ec_tk_int_testcase(void) ec_parsed_tk_free(p); ec_tk_free(tk); - tk = ec_tk_int_new(NULL, -1, LLONG_MAX, 16); + tk = ec_tk_int(NULL, -1, LLONG_MAX, 16); if (tk == NULL) { ec_log(EC_LOG_ERR, "cannot create tk\n"); return -1; @@ -183,7 +186,7 @@ static int ec_tk_int_testcase(void) ec_parsed_tk_free(p); ec_tk_free(tk); - tk = ec_tk_int_new(NULL, LLONG_MIN, 0, 10); + tk = ec_tk_int(NULL, LLONG_MIN, 0, 10); if (tk == NULL) { ec_log(EC_LOG_ERR, "cannot create tk\n"); return -1; @@ -197,7 +200,7 @@ static int ec_tk_int_testcase(void) ec_tk_free(tk); /* test completion */ - tk = ec_tk_int_new(NULL, 0, 10, 0); + tk = ec_tk_int(NULL, 0, 10, 0); if (tk == NULL) { ec_log(EC_LOG_ERR, "cannot create tk\n"); return -1; diff --git a/lib/ecoli_tk_int.h b/lib/ecoli_tk_int.h index 147e2d0..b7fa6a6 100644 --- a/lib/ecoli_tk_int.h +++ b/lib/ecoli_tk_int.h @@ -30,7 +30,7 @@ #include -struct ec_tk *ec_tk_int_new(const char *id, long long int min, +struct ec_tk *ec_tk_int(const char *id, long long int min, long long int max, unsigned int base); long long ec_tk_int_getval(struct ec_tk *tk, const char *str); diff --git a/lib/ecoli_tk_many.c b/lib/ecoli_tk_many.c index d93a6de..3c37450 100644 --- a/lib/ecoli_tk_many.c +++ b/lib/ecoli_tk_many.c @@ -207,7 +207,7 @@ static int ec_tk_many_testcase(void) struct ec_tk *tk; int ret = 0; - tk = ec_tk_many_new(NULL, ec_tk_str_new(NULL, "foo"), 0, 0); + tk = ec_tk_many_new(NULL, ec_tk_str(NULL, "foo"), 0, 0); if (tk == NULL) { ec_log(EC_LOG_ERR, "cannot create tk\n"); return -1; @@ -219,7 +219,7 @@ static int ec_tk_many_testcase(void) ret |= EC_TEST_CHECK_TK_PARSE(tk, 0, EC_TK_ENDLIST); ec_tk_free(tk); - tk = ec_tk_many_new(NULL, ec_tk_str_new(NULL, "foo"), 1, 0); + tk = ec_tk_many_new(NULL, ec_tk_str(NULL, "foo"), 1, 0); if (tk == NULL) { ec_log(EC_LOG_ERR, "cannot create tk\n"); return -1; @@ -231,7 +231,7 @@ static int ec_tk_many_testcase(void) ret |= EC_TEST_CHECK_TK_PARSE(tk, -1, EC_TK_ENDLIST); ec_tk_free(tk); - tk = ec_tk_many_new(NULL, ec_tk_str_new(NULL, "foo"), 1, 2); + tk = ec_tk_many_new(NULL, ec_tk_str(NULL, "foo"), 1, 2); if (tk == NULL) { ec_log(EC_LOG_ERR, "cannot create tk\n"); return -1; diff --git a/lib/ecoli_tk_option.c b/lib/ecoli_tk_option.c index 5427e19..ab82d47 100644 --- a/lib/ecoli_tk_option.c +++ b/lib/ecoli_tk_option.c @@ -125,7 +125,7 @@ static int ec_tk_option_testcase(void) struct ec_tk *tk; int ret = 0; - tk = ec_tk_option_new(NULL, ec_tk_str_new(NULL, "foo")); + tk = ec_tk_option_new(NULL, ec_tk_str(NULL, "foo")); if (tk == NULL) { ec_log(EC_LOG_ERR, "cannot create tk\n"); return -1; @@ -137,7 +137,7 @@ static int ec_tk_option_testcase(void) ec_tk_free(tk); /* test completion */ - tk = ec_tk_option_new(NULL, ec_tk_str_new(NULL, "foo")); + tk = ec_tk_option_new(NULL, ec_tk_str(NULL, "foo")); if (tk == NULL) { ec_log(EC_LOG_ERR, "cannot create tk\n"); return -1; diff --git a/lib/ecoli_tk_or.c b/lib/ecoli_tk_or.c index 55f3e69..d3e2d20 100644 --- a/lib/ecoli_tk_or.c +++ b/lib/ecoli_tk_or.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -141,7 +142,42 @@ struct ec_tk *ec_tk_or_new(const char *id) return &tk->gen; } -struct ec_tk *ec_tk_or_new_list(const char *id, ...) +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; + struct ec_tk **table; + + assert(tk != NULL); + assert(child != NULL); + + if (gen_tk->flags & EC_TK_F_INITIALIZED) + return -EPERM; + + table = ec_realloc(tk->table, (tk->len + 1) * sizeof(*tk->table)); + if (table == NULL) + return -1; + + tk->table = table; + table[tk->len] = child; + tk->len++; + + child->parent = gen_tk; + TAILQ_INSERT_TAIL(&gen_tk->children, child, next); + + return 0; +} + +int ec_tk_or_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_or(const char *id, ...) { struct ec_tk_or *tk = NULL; struct ec_tk *child; @@ -152,7 +188,7 @@ struct ec_tk *ec_tk_or_new_list(const char *id, ...) tk = (struct ec_tk_or *)ec_tk_or_new(id); if (tk == NULL) - goto fail; + fail = 1; for (child = va_arg(ap, struct ec_tk *); child != EC_TK_ENDLIST; @@ -178,36 +214,14 @@ fail: return NULL; } -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; - struct ec_tk **table; - - assert(tk != NULL); - assert(child != NULL); - - table = ec_realloc(tk->table, (tk->len + 1) * sizeof(*tk->table)); - if (table == NULL) - return -1; - - tk->table = table; - table[tk->len] = child; - tk->len ++; - - child->parent = gen_tk; - TAILQ_INSERT_TAIL(&gen_tk->children, child, next); - - return 0; -} - static int ec_tk_or_testcase(void) { struct ec_tk *tk; int ret = 0; - tk = ec_tk_or_new_list(NULL, - ec_tk_str_new(NULL, "foo"), - ec_tk_str_new(NULL, "bar"), + tk = ec_tk_or(NULL, + ec_tk_str(NULL, "foo"), + ec_tk_str(NULL, "bar"), EC_TK_ENDLIST); if (tk == NULL) { ec_log(EC_LOG_ERR, "cannot create tk\n"); @@ -223,12 +237,12 @@ static int ec_tk_or_testcase(void) ec_tk_free(tk); /* test completion */ - tk = ec_tk_or_new_list(NULL, - ec_tk_str_new(NULL, "foo"), - ec_tk_str_new(NULL, "bar"), - ec_tk_str_new(NULL, "bar2"), - ec_tk_str_new(NULL, "toto"), - ec_tk_str_new(NULL, "titi"), + 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); if (tk == NULL) { ec_log(EC_LOG_ERR, "cannot create tk\n"); diff --git a/lib/ecoli_tk_or.h b/lib/ecoli_tk_or.h index 07d4cea..e11d96b 100644 --- a/lib/ecoli_tk_or.h +++ b/lib/ecoli_tk_or.h @@ -30,13 +30,13 @@ #include -struct ec_tk *ec_tk_or_new(const char *id); - /* 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_new_list(const char *id, ...); +struct ec_tk *ec_tk_or(const char *id, ...); +struct ec_tk *ec_tk_or_new(const char *id); /* 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_seq.c b/lib/ecoli_tk_seq.c index 6feb17d..3cfc061 100644 --- a/lib/ecoli_tk_seq.c +++ b/lib/ecoli_tk_seq.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -182,7 +183,44 @@ struct ec_tk *ec_tk_seq_new(const char *id) return &tk->gen; } -struct ec_tk *ec_tk_seq_new_list(const char *id, ...) +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; + struct ec_tk **table; + + // XXX check tk type + + assert(tk != NULL); + assert(child != NULL); + + if (gen_tk->flags & EC_TK_F_INITIALIZED) + return -EPERM; + + table = ec_realloc(tk->table, (tk->len + 1) * sizeof(*tk->table)); + if (table == NULL) + return -1; + + tk->table = table; + table[tk->len] = child; + tk->len++; + + child->parent = gen_tk; + TAILQ_INSERT_TAIL(&gen_tk->children, child, next); // XXX really needed? + + return 0; +} + +int ec_tk_seq_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_seq(const char *id, ...) { struct ec_tk_seq *tk = NULL; struct ec_tk *child; @@ -219,38 +257,14 @@ fail: return NULL; } -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; - struct ec_tk **table; - - // XXX check tk type - - assert(tk != NULL); - assert(child != NULL); - - table = ec_realloc(tk->table, (tk->len + 1) * sizeof(*tk->table)); - if (table == NULL) - return -1; - - tk->table = table; - table[tk->len] = child; - tk->len++; - - child->parent = gen_tk; - TAILQ_INSERT_TAIL(&gen_tk->children, child, next); // XXX really needed? - - return 0; -} - static int ec_tk_seq_testcase(void) { struct ec_tk *tk; int ret = 0; - tk = ec_tk_seq_new_list(NULL, - ec_tk_str_new(NULL, "foo"), - ec_tk_str_new(NULL, "bar"), + tk = ec_tk_seq(NULL, + ec_tk_str(NULL, "foo"), + ec_tk_str(NULL, "bar"), EC_TK_ENDLIST); if (tk == NULL) { ec_log(EC_LOG_ERR, "cannot create tk\n"); @@ -267,10 +281,10 @@ static int ec_tk_seq_testcase(void) ec_tk_free(tk); /* test completion */ - tk = ec_tk_seq_new_list(NULL, - ec_tk_str_new(NULL, "foo"), - ec_tk_option_new(NULL, ec_tk_str_new(NULL, "toto")), - ec_tk_str_new(NULL, "bar"), + 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); if (tk == NULL) { ec_log(EC_LOG_ERR, "cannot create tk\n"); diff --git a/lib/ecoli_tk_seq.h b/lib/ecoli_tk_seq.h index 2385da2..03c5834 100644 --- a/lib/ecoli_tk_seq.h +++ b/lib/ecoli_tk_seq.h @@ -30,11 +30,13 @@ #include -struct ec_tk *ec_tk_seq_new(const char *id); /* list must be terminated with EC_TK_ENDLIST */ -struct ec_tk *ec_tk_seq_new_list(const char *id, ...); +struct ec_tk *ec_tk_seq(const char *id, ...); +struct ec_tk *ec_tk_seq_new(const char *id); int ec_tk_seq_add(struct ec_tk *tk, struct ec_tk *child); +int ec_tk_seq_start(struct ec_tk *tk); + #endif diff --git a/lib/ecoli_tk_shlex.c b/lib/ecoli_tk_shlex.c index 0b53968..0becba5 100644 --- a/lib/ecoli_tk_shlex.c +++ b/lib/ecoli_tk_shlex.c @@ -402,12 +402,12 @@ static int ec_tk_shlex_testcase(void) int ret = 0; tk = ec_tk_shlex_new(NULL, - ec_tk_seq_new_list(NULL, - ec_tk_str_new(NULL, "foo"), + ec_tk_seq(NULL, + ec_tk_str(NULL, "foo"), ec_tk_option_new(NULL, - ec_tk_str_new(NULL, "toto") + ec_tk_str(NULL, "toto") ), - ec_tk_str_new(NULL, "bar"), + ec_tk_str(NULL, "bar"), EC_TK_ENDLIST ) ); @@ -424,13 +424,13 @@ static int ec_tk_shlex_testcase(void) /* test completion */ tk = ec_tk_shlex_new(NULL, - ec_tk_seq_new_list(NULL, - ec_tk_str_new(NULL, "foo"), + ec_tk_seq(NULL, + ec_tk_str(NULL, "foo"), ec_tk_option_new(NULL, - ec_tk_str_new(NULL, "toto") + ec_tk_str(NULL, "toto") ), - ec_tk_str_new(NULL, "bar"), - ec_tk_str_new(NULL, "titi"), + ec_tk_str(NULL, "bar"), + ec_tk_str(NULL, "titi"), EC_TK_ENDLIST ) ); diff --git a/lib/ecoli_tk_str.c b/lib/ecoli_tk_str.c index f3999ff..2904713 100644 --- a/lib/ecoli_tk_str.c +++ b/lib/ecoli_tk_str.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -136,28 +137,64 @@ static const struct ec_tk_ops ec_tk_str_ops = { .free_priv = ec_tk_str_free_priv, }; -struct ec_tk *ec_tk_str_new(const char *id, const char *str) +struct ec_tk *ec_tk_str_new(const char *id) { struct ec_tk *gen_tk = NULL; - struct ec_tk_str *tk = NULL; - char *s = NULL; - gen_tk = ec_tk_new(id, &ec_tk_str_ops, sizeof(*tk)); + gen_tk = ec_tk_new(id, &ec_tk_str_ops, sizeof(struct ec_tk_str)); + if (gen_tk == NULL) + return NULL; + + return gen_tk; +} + +int ec_tk_str_set_str(struct ec_tk *gen_tk, const char *str) +{ + struct ec_tk_str *tk = (struct ec_tk_str *)gen_tk; + + if (str == NULL) + 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 -ENOMEM; + + tk->len = strlen(tk->string); + + 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; + + gen_tk = ec_tk_str_new(id); if (gen_tk == NULL) goto fail; - s = ec_strdup(str); - if (s == NULL) + if (ec_tk_str_set_str(gen_tk, str) < 0) goto fail; - tk = (struct ec_tk_str *)gen_tk; - tk->string = s; - tk->len = strlen(s); + if (ec_tk_str_start(gen_tk) < 0) + goto fail; return gen_tk; fail: - ec_free(s); ec_tk_free(gen_tk); return NULL; } @@ -167,7 +204,7 @@ static int ec_tk_str_testcase(void) struct ec_tk *tk; int ret = 0; - tk = ec_tk_str_new(NULL, "foo"); + tk = ec_tk_str(NULL, "foo"); if (tk == NULL) { ec_log(EC_LOG_ERR, "cannot create tk\n"); return -1; @@ -179,7 +216,7 @@ static int ec_tk_str_testcase(void) ret |= EC_TEST_CHECK_TK_PARSE(tk, -1, "", EC_TK_ENDLIST); ec_tk_free(tk); - tk = ec_tk_str_new(NULL, "Здравствуйте"); + tk = ec_tk_str(NULL, "Здравствуйте"); if (tk == NULL) { ec_log(EC_LOG_ERR, "cannot create tk\n"); return -1; @@ -192,7 +229,7 @@ static int ec_tk_str_testcase(void) ec_tk_free(tk); /* an empty token string always matches */ - tk = ec_tk_str_new(NULL, ""); + tk = ec_tk_str(NULL, ""); if (tk == NULL) { ec_log(EC_LOG_ERR, "cannot create tk\n"); return -1; @@ -203,7 +240,7 @@ static int ec_tk_str_testcase(void) ec_tk_free(tk); /* test completion */ - tk = ec_tk_str_new(NULL, "foo"); + tk = ec_tk_str(NULL, "foo"); if (tk == NULL) { ec_log(EC_LOG_ERR, "cannot create tk\n"); return -1; diff --git a/lib/ecoli_tk_str.h b/lib/ecoli_tk_str.h index 00632ec..4371823 100644 --- a/lib/ecoli_tk_str.h +++ b/lib/ecoli_tk_str.h @@ -30,6 +30,10 @@ #include -struct ec_tk *ec_tk_str_new(const char *id, const char *str); +struct ec_tk *ec_tk_str(const char *id, const char *str); + +struct ec_tk *ec_tk_str_new(const char *id); +int ec_tk_str_set_str(struct ec_tk *tk, const char *str); +int ec_tk_str_start(struct ec_tk *tk); #endif diff --git a/lib/main-readline.c b/lib/main-readline.c index 8c5ffc5..7432f3c 100644 --- a/lib/main-readline.c +++ b/lib/main-readline.c @@ -175,16 +175,16 @@ static int create_commands(void) if (cmdlist == NULL) goto fail; - cmd = ec_tk_seq_new_list(NULL, - ec_tk_str_new(NULL, "hello"), - ec_tk_or_new_list(NULL, - ec_tk_or_new_list("name", - ec_tk_str_new(NULL, "john"), - ec_tk_str_new(NULL, "johnny"), - ec_tk_str_new(NULL, "mike"), + cmd = ec_tk_seq(NULL, + ec_tk_str(NULL, "hello"), + 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_int_new("int", 0, 10, 10), + ec_tk_int("int", 0, 10, 10), EC_TK_ENDLIST ), EC_TK_ENDLIST @@ -197,8 +197,8 @@ static int create_commands(void) if (ec_tk_or_add(cmdlist, cmd) < 0) goto fail; - cmd = ec_tk_seq_new_list(NULL, - ec_tk_str_new(NULL, "bye"), + cmd = ec_tk_seq(NULL, + ec_tk_str(NULL, "bye"), EC_TK_ENDLIST ); ec_keyval_set(ec_tk_attrs(cmd), "help", "say bye to someone", NULL); -- 2.39.5