From: Olivier Matz Date: Thu, 26 Jan 2017 18:07:37 +0000 (+0100) Subject: save X-Git-Url: http://git.droids-corp.org/?a=commitdiff_plain;h=9360afe4c5e6bd0c849786467a64636b64cae10e;p=protos%2Flibecoli.git save --- diff --git a/lib/Makefile b/lib/Makefile index ba852eb..db3763c 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -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 diff --git a/lib/ecoli_test.c b/lib/ecoli_test.c index 4a7de26..fc82c69 100644 --- a/lib/ecoli_test.c +++ b/lib/ecoli_test.c @@ -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; diff --git a/lib/ecoli_test.h b/lib/ecoli_test.h index 40ddefa..a05d4cf 100644 --- a/lib/ecoli_test.h +++ b/lib/ecoli_test.h @@ -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_; \ diff --git a/lib/ecoli_tk.c b/lib/ecoli_tk.c index 615ed85..624a5b9 100644 --- a/lib/ecoli_tk.c +++ b/lib/ecoli_tk.c @@ -34,6 +34,7 @@ #include #include #include +#include #include 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; diff --git a/lib/ecoli_tk.h b/lib/ecoli_tk.h index b3f43bc..a86266c 100644 --- a/lib/ecoli_tk.h +++ b/lib/ecoli_tk.h @@ -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, diff --git a/lib/ecoli_tk_bypass.c b/lib/ecoli_tk_bypass.c index d2fe401..e71a14c 100644 --- a/lib/ecoli_tk_bypass.c +++ b/lib/ecoli_tk_bypass.c @@ -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; } diff --git a/lib/ecoli_tk_bypass.h b/lib/ecoli_tk_bypass.h index c20064a..92f84d9 100644 --- a/lib/ecoli_tk_bypass.h +++ b/lib/ecoli_tk_bypass.h @@ -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 */ diff --git a/lib/ecoli_tk_empty.c b/lib/ecoli_tk_empty.c index 196041c..ee6a4e6 100644 --- a/lib/ecoli_tk_empty.c +++ b/lib/ecoli_tk_empty.c @@ -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 */ diff --git a/lib/ecoli_tk_expr.c b/lib/ecoli_tk_expr.c index fe1b23f..4b54b9f 100644 --- a/lib/ecoli_tk_expr.c +++ b/lib/ecoli_tk_expr.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Olivier MATZ + * Copyright (c) 2016-2017, Olivier MATZ * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -48,18 +48,18 @@ 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; diff --git a/lib/ecoli_tk_expr.h b/lib/ecoli_tk_expr.h index 84a1228..ca28e68 100644 --- a/lib/ecoli_tk_expr.h +++ b/lib/ecoli_tk_expr.h @@ -33,10 +33,7 @@ /* 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); diff --git a/lib/ecoli_tk_int.c b/lib/ecoli_tk_int.c index 247426a..bd0155d 100644 --- a/lib/ecoli_tk_int.c +++ b/lib/ecoli_tk_int.c @@ -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 */ diff --git a/lib/ecoli_tk_many.c b/lib/ecoli_tk_many.c index 3c37450..ecd54b8 100644 --- a/lib/ecoli_tk_many.c +++ b/lib/ecoli_tk_many.c @@ -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 */ diff --git a/lib/ecoli_tk_many.h b/lib/ecoli_tk_many.h index ed32075..107e4c7 100644 --- a/lib/ecoli_tk_many.h +++ b/lib/ecoli_tk_many.h @@ -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 diff --git a/lib/ecoli_tk_option.c b/lib/ecoli_tk_option.c index ab82d47..1170f7e 100644 --- a/lib/ecoli_tk_option.c +++ b/lib/ecoli_tk_option.c @@ -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 */ diff --git a/lib/ecoli_tk_or.c b/lib/ecoli_tk_or.c index 04701e6..47264c5 100644 --- a/lib/ecoli_tk_or.c +++ b/lib/ecoli_tk_or.c @@ -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; diff --git a/lib/ecoli_tk_or.h b/lib/ecoli_tk_or.h index 6f11735..a4e1555 100644 --- a/lib/ecoli_tk_or.h +++ b/lib/ecoli_tk_or.h @@ -30,16 +30,19 @@ #include +#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 index 0000000..5dd273d --- /dev/null +++ b/lib/ecoli_tk_re_lex.c @@ -0,0 +1,268 @@ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 index 0000000..877a41a --- /dev/null +++ b/lib/ecoli_tk_re_lex.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2016-2017, Olivier MATZ + * + * 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 + +struct ec_tk *ec_tk_re_lex_new(const char *id, struct ec_tk *child); + +#endif diff --git a/lib/ecoli_tk_seq.c b/lib/ecoli_tk_seq.c index 889ea34..807ff22 100644 --- a/lib/ecoli_tk_seq.c +++ b/lib/ecoli_tk_seq.c @@ -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; diff --git a/lib/ecoli_tk_seq.h b/lib/ecoli_tk_seq.h index 5340fbf..ffc9fa3 100644 --- a/lib/ecoli_tk_seq.h +++ b/lib/ecoli_tk_seq.h @@ -30,16 +30,18 @@ #include +#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 diff --git a/lib/ecoli_tk_shlex.c b/lib/ecoli_tk_shlex.c index 0becba5..a7bb6ff 100644 --- a/lib/ecoli_tk_shlex.c +++ b/lib/ecoli_tk_shlex.c @@ -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) { diff --git a/lib/ecoli_tk_space.c b/lib/ecoli_tk_space.c index 33f33d8..fc3a5b3 100644 --- a/lib/ecoli_tk_space.c +++ b/lib/ecoli_tk_space.c @@ -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 */ diff --git a/lib/ecoli_tk_str.c b/lib/ecoli_tk_str.c index 2904713..0644905 100644 --- a/lib/ecoli_tk_str.c +++ b/lib/ecoli_tk_str.c @@ -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 */ diff --git a/lib/ecoli_tk_str.h b/lib/ecoli_tk_str.h index 4371823..d4e2503 100644 --- a/lib/ecoli_tk_str.h +++ b/lib/ecoli_tk_str.h @@ -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 diff --git a/lib/main-readline.c b/lib/main-readline.c index db1574e..9489b70 100644 --- a/lib/main-readline.c +++ b/lib/main-readline.c @@ -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) diff --git a/lib/main.c b/lib/main.c index deffea3..d716fec 100644 --- a/lib/main.c +++ b/lib/main.c @@ -71,7 +71,7 @@ static void usage(const char *prgname) " Show this help.\n" " -l \n" " --"EC_OPT_LOG_LEVEL"=\n" - " Set log level (0 = no log, 6 = verbose).\n" + " Set log level (0 = no log, 7 = verbose).\n" " -r \n" " --"EC_OPT_RANDOM_ALLOC_FAIL"=\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 index 0000000..b71086e --- /dev/null +++ b/lib/test.sh @@ -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