From 59b1d3fa9895e47af68a0ab987a2551a16ca09a2 Mon Sep 17 00:00:00 2001 From: Olivier Matz Date: Wed, 21 Dec 2016 17:55:02 +0100 Subject: [PATCH] save --- lib/Makefile | 2 +- lib/build/test | Bin 145552 -> 0 bytes lib/ecoli_keyval.c | 22 +-- lib/ecoli_strvec.c | 80 +++++++---- lib/ecoli_strvec.h | 14 +- lib/ecoli_tk.c | 34 +++-- lib/ecoli_tk.h | 9 +- lib/ecoli_tk_expr.c | 331 +++++++++++++++++++++++++++++++++++++++++++ lib/ecoli_tk_expr.h | 45 ++++++ lib/ecoli_tk_int.c | 8 +- lib/ecoli_tk_many.c | 42 ++++-- lib/ecoli_tk_or.c | 7 +- lib/ecoli_tk_seq.c | 54 ++++--- lib/ecoli_tk_shlex.c | 2 +- lib/ecoli_tk_space.c | 2 +- lib/ecoli_tk_str.c | 12 +- lib/main.c | 17 +++ 17 files changed, 570 insertions(+), 111 deletions(-) delete mode 100755 lib/build/test create mode 100644 lib/ecoli_tk_expr.c create mode 100644 lib/ecoli_tk_expr.h diff --git a/lib/Makefile b/lib/Makefile index 9bbd73b..ba88840 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -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 +srcs += ecoli_tk_shlex.c ecoli_tk_expr.c shlib-y-$(O)libecoli.so := $(srcs) ldflags-$(O)test = -rdynamic diff --git a/lib/build/test b/lib/build/test deleted file mode 100755 index e389ed25681e7c31cbaf9569e3d6dd08dce9392b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 145552 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 diff --git a/lib/ecoli_keyval.c b/lib/ecoli_keyval.c index 8275715..7f87b01 100644 --- a/lib/ecoli_keyval.c +++ b/lib/ecoli_keyval.c @@ -35,17 +35,17 @@ #include #include -struct ec_keyval { - size_t len; - struct ec_keyval_elt *vec; -}; - struct ec_keyval_elt { char *key; void *val; ec_keyval_elt_free_t free; }; +struct ec_keyval { + size_t len; + struct ec_keyval_elt *vec; +}; + struct ec_keyval *ec_keyval_new(void) { struct ec_keyval *keyval; @@ -118,8 +118,7 @@ int ec_keyval_del(struct ec_keyval *keyval, const char *key) int ec_keyval_set(struct ec_keyval *keyval, const char *key, void *val, ec_keyval_elt_free_t free_cb) { - struct ec_keyval_elt *new_vec; - struct ec_keyval_elt *elt; + struct ec_keyval_elt *elt, *new_vec; assert(keyval != NULL); assert(key != NULL); @@ -129,20 +128,25 @@ int ec_keyval_set(struct ec_keyval *keyval, const char *key, void *val, new_vec = ec_realloc(keyval->vec, sizeof(*keyval->vec) * (keyval->len + 1)); if (new_vec == NULL) - return -ENOMEM; + goto fail; keyval->vec = new_vec; elt = &new_vec[keyval->len]; elt->key = ec_strdup(key); if (elt->key == NULL) - return -ENOMEM; + goto fail; elt->val = val; elt->free = free_cb; keyval->len++; return 0; + +fail: + if (free_cb) + free_cb(val); + return -ENOMEM; } void ec_keyval_free(struct ec_keyval *keyval) diff --git a/lib/ecoli_strvec.c b/lib/ecoli_strvec.c index da15502..3cc2055 100644 --- a/lib/ecoli_strvec.c +++ b/lib/ecoli_strvec.c @@ -26,11 +26,23 @@ */ #include +#include #include +#include #include #include +struct ec_strvec_elt { + unsigned int refcnt; + char *str; +}; + +struct ec_strvec { + size_t len; + struct ec_strvec_elt **vec; +}; + struct ec_strvec *ec_strvec_new(void) { struct ec_strvec *strvec; @@ -44,23 +56,33 @@ struct ec_strvec *ec_strvec_new(void) int ec_strvec_add(struct ec_strvec *strvec, const char *s) { - char **new_vec; + struct ec_strvec_elt *elt, **new_vec; new_vec = ec_realloc(strvec->vec, sizeof(*strvec->vec) * (strvec->len + 1)); if (new_vec == NULL) - return -1; + return -ENOMEM; strvec->vec = new_vec; - strvec->vec[strvec->len] = ec_strdup(s); - if (strvec->vec[strvec->len] == NULL) - return -1; + elt = ec_malloc(sizeof(*elt)); + if (elt == NULL) + return -ENOMEM; + + elt->str = ec_strdup(s); + if (elt->str == NULL) { + ec_free(elt); + return -ENOMEM; + } + elt->refcnt = 1; + + new_vec[strvec->len] = elt; strvec->len++; return 0; } -struct ec_strvec *ec_strvec_ndup(const struct ec_strvec *strvec, size_t len) +struct ec_strvec *ec_strvec_ndup(const struct ec_strvec *strvec, size_t off, + size_t len) { struct ec_strvec *copy = NULL; size_t i, veclen; @@ -69,20 +91,22 @@ struct ec_strvec *ec_strvec_ndup(const struct ec_strvec *strvec, size_t len) if (copy == NULL) goto fail; + veclen = ec_strvec_len(strvec); + if (off >= veclen) + len = 0; + else if (off + len > veclen) + len -= (veclen - off); + if (len == 0) return copy; - veclen = ec_strvec_len(strvec); - if (len > veclen) - len = veclen; copy->vec = ec_calloc(len, sizeof(*copy->vec)); if (copy->vec == NULL) goto fail; for (i = 0; i < len; i++) { - copy->vec[i] = ec_strdup(strvec->vec[i]); - if (copy->vec[i] == NULL) - goto fail; + copy->vec[i] = strvec->vec[i + off]; + copy->vec[i]->refcnt++; copy->len++; } @@ -95,18 +119,25 @@ fail: struct ec_strvec *ec_strvec_dup(const struct ec_strvec *strvec) { - return ec_strvec_ndup(strvec, ec_strvec_len(strvec)); + return ec_strvec_ndup(strvec, 0, ec_strvec_len(strvec)); } void ec_strvec_free(struct ec_strvec *strvec) { + struct ec_strvec_elt *elt; size_t i; if (strvec == NULL) return; - for (i = 0; i < ec_strvec_len(strvec); i++) - ec_free(ec_strvec_val(strvec, i)); + for (i = 0; i < ec_strvec_len(strvec); i++) { + elt = strvec->vec[i]; + elt->refcnt--; + if (elt->refcnt == 0) { + ec_free(elt->str); + ec_free(elt); + } + } ec_free(strvec->vec); ec_free(strvec); @@ -122,22 +153,10 @@ char *ec_strvec_val(const struct ec_strvec *strvec, size_t idx) if (strvec == NULL || idx >= strvec->len) return NULL; - return strvec->vec[idx]; -} - -int ec_strvec_slice(struct ec_strvec *strvec, const struct ec_strvec *from, - size_t off) -{ - if (off > from->len) - return -1; - - strvec->len = from->len - off; - strvec->vec = &from->vec[off]; - - return 0; + return strvec->vec[idx]->str; } -void ec_strvec_dump(const struct ec_strvec *strvec, FILE *out) +void ec_strvec_dump(FILE *out, const struct ec_strvec *strvec) { size_t i; @@ -148,7 +167,8 @@ void ec_strvec_dump(const struct ec_strvec *strvec, FILE *out) fprintf(out, "strvec:\n"); for (i = 0; i < ec_strvec_len(strvec); i++) - fprintf(out, " %zd: %s\n", i, strvec->vec[i]); + fprintf(out, " %zd: %s (refcnt=%d)\n", i, + strvec->vec[i]->str, strvec->vec[i]->refcnt); } /* XXX test case */ diff --git a/lib/ecoli_strvec.h b/lib/ecoli_strvec.h index a606177..6178777 100644 --- a/lib/ecoli_strvec.h +++ b/lib/ecoli_strvec.h @@ -28,22 +28,14 @@ #ifndef ECOLI_STRVEC_ #define ECOLI_STRVEC_ -#include - -struct ec_strvec { - size_t len; - char **vec; -}; - struct ec_strvec *ec_strvec_new(void); int ec_strvec_add(struct ec_strvec *strvec, const char *s); struct ec_strvec *ec_strvec_dup(const struct ec_strvec *strvec); -struct ec_strvec *ec_strvec_ndup(const struct ec_strvec *strvec, size_t len); +struct ec_strvec *ec_strvec_ndup(const struct ec_strvec *strvec, + size_t off, size_t len); void ec_strvec_free(struct ec_strvec *strvec); size_t ec_strvec_len(const struct ec_strvec *strvec); char *ec_strvec_val(const struct ec_strvec *strvec, size_t idx); -int ec_strvec_slice(struct ec_strvec *strvec, const struct ec_strvec *from, - size_t off); -void ec_strvec_dump(const struct ec_strvec *strvec, FILE *out); +void ec_strvec_dump(FILE *out, const struct ec_strvec *strvec); #endif diff --git a/lib/ecoli_tk.c b/lib/ecoli_tk.c index fec8492..db28b53 100644 --- a/lib/ecoli_tk.c +++ b/lib/ecoli_tk.c @@ -50,6 +50,7 @@ struct ec_tk *ec_tk_new(const char *id, const struct ec_tk_ops *ops, TAILQ_INIT(&tk->children); tk->ops = ops; + tk->refcnt = 1; if (id != NULL) { tk->id = ec_strdup(id); @@ -69,9 +70,6 @@ struct ec_tk *ec_tk_new(const char *id, const struct ec_tk_ops *ops, return tk; fail: - ec_free(tk->attrs); - ec_free(tk->desc); - ec_free(tk->id); ec_tk_free(tk); return NULL; } @@ -81,6 +79,9 @@ void ec_tk_free(struct ec_tk *tk) if (tk == NULL) return; + if (--tk->refcnt > 0) + return; + if (tk->ops != NULL && tk->ops->free_priv != NULL) tk->ops->free_priv(tk); ec_free(tk->id); @@ -89,6 +90,13 @@ void ec_tk_free(struct ec_tk *tk) ec_free(tk); } +struct ec_tk *ec_tk_clone(struct ec_tk *tk) +{ + if (tk != NULL) + tk->refcnt++; + return tk; +} + struct ec_tk *ec_tk_find(struct ec_tk *tk, const char *id) { struct ec_tk *child, *ret; @@ -213,22 +221,27 @@ static void __ec_parsed_tk_dump(FILE *out, const struct ec_parsed_tk *parsed_tk, size_t indent) { struct ec_parsed_tk *child; + const struct ec_strvec *vec; size_t i; - const char *s, *id = "None", *typename = "None"; + const char *id = "None", *typename = "None"; /* XXX enhance */ for (i = 0; i < indent; i++) fprintf(out, " "); - s = ec_parsed_tk_to_string(parsed_tk); if (parsed_tk->tk != NULL) { if (parsed_tk->tk->id != NULL) id = parsed_tk->tk->id; typename = parsed_tk->tk->ops->typename; } - /* XXX we only display the first token */ - fprintf(out, "tk_type=%s, id=%s, s=<%s>\n", typename, id, s); + fprintf(out, "tk_type=%s id=%s vec=[", typename, id); + vec = ec_parsed_tk_strvec(parsed_tk); + for (i = 0; i < ec_strvec_len(vec); i++) + fprintf(out, "%s<%s>", + i == 0 ? "" : ",", + ec_strvec_val(vec, i)); + fprintf(out, "]\n"); TAILQ_FOREACH(child, &parsed_tk->children, next) __ec_parsed_tk_dump(out, child, indent + 2); @@ -276,14 +289,13 @@ struct ec_parsed_tk *ec_parsed_tk_find_first(struct ec_parsed_tk *parsed_tk, return NULL; } -/* XXX return NUL if it matches several tokens? - or add a parameter to join() the tokens ? */ -const char *ec_parsed_tk_to_string(const struct ec_parsed_tk *parsed_tk) +const struct ec_strvec *ec_parsed_tk_strvec( + const struct ec_parsed_tk *parsed_tk) { if (parsed_tk == NULL || parsed_tk->strvec == NULL) return NULL; - return ec_strvec_val(parsed_tk->strvec, 0); + return parsed_tk->strvec; } /* number of parsed tokens */ diff --git a/lib/ecoli_tk.h b/lib/ecoli_tk.h index 5d1bafb..b417a03 100644 --- a/lib/ecoli_tk.h +++ b/lib/ecoli_tk.h @@ -63,6 +63,7 @@ struct ec_tk { struct ec_keyval *attrs; /* XXX ensure parent and child are properly set in all nodes */ struct ec_tk *parent; + unsigned int refcnt; TAILQ_ENTRY(ec_tk) next; struct ec_tk_list children; @@ -94,6 +95,12 @@ struct ec_parsed_tk { }; struct ec_parsed_tk *ec_parsed_tk_new(void); +void ec_parsed_tk_free(struct ec_parsed_tk *parsed_tk); +struct ec_tk *ec_tk_clone(struct ec_tk *tk); +void ec_parsed_tk_free_children(struct ec_parsed_tk *parsed_tk); + +const struct ec_strvec *ec_parsed_tk_strvec( + const struct ec_parsed_tk *parsed_tk); void ec_parsed_tk_set_match(struct ec_parsed_tk *parsed_tk, const struct ec_tk *tk, struct ec_strvec *strvec); @@ -114,9 +121,7 @@ struct ec_parsed_tk *ec_tk_parse_tokens(const struct ec_tk *tk, void ec_parsed_tk_add_child(struct ec_parsed_tk *parsed_tk, struct ec_parsed_tk *child); -void ec_parsed_tk_free_children(struct ec_parsed_tk *parsed_tk); void ec_parsed_tk_dump(FILE *out, const struct ec_parsed_tk *parsed_tk); -void ec_parsed_tk_free(struct ec_parsed_tk *parsed_tk); struct ec_parsed_tk *ec_parsed_tk_find_first(struct ec_parsed_tk *parsed_tk, const char *id); diff --git a/lib/ecoli_tk_expr.c b/lib/ecoli_tk_expr.c new file mode 100644 index 0000000..5625727 --- /dev/null +++ b/lib/ecoli_tk_expr.c @@ -0,0 +1,331 @@ +/* + * Copyright (c) 2016, 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. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct ec_tk_expr { + struct ec_tk gen; + struct ec_tk *child; + 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; +}; + +static struct ec_parsed_tk *ec_tk_expr_parse(const struct ec_tk *gen_tk, + const struct ec_strvec *strvec) +{ + struct ec_tk_expr *tk = (struct ec_tk_expr *)gen_tk; + + return ec_tk_parse_tokens(tk->child, strvec); +} + +static struct ec_completed_tk *ec_tk_expr_complete(const struct ec_tk *gen_tk, + const struct ec_strvec *strvec) +{ + struct ec_tk_expr *tk = (struct ec_tk_expr *)gen_tk; + + return ec_tk_complete_tokens(tk->child, strvec); +} + +static void ec_tk_expr_free_priv(struct ec_tk *gen_tk) +{ + struct ec_tk_expr *tk = (struct ec_tk_expr *)gen_tk; + + ec_tk_free(tk->child); +} + +static struct ec_tk_ops ec_tk_expr_ops = { + .typename = "expr", + .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_expr *tk = NULL; + struct ec_tk *gen_tk = NULL; + + gen_tk = ec_tk_new(id, &ec_tk_expr_ops, sizeof(*tk)); + if (gen_tk == NULL) + return NULL; + tk = (struct ec_tk_expr *)gen_tk; + + return gen_tk; +} + +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; + + if (val_tk == NULL) + return -EINVAL; + if (tk->val_tk != NULL) + return -EEXIST; + + tk->val_tk = val_tk; + + return 0; +} + +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; + + // XXX check tk type + + /* XXX use assert or check like this ? */ + if (tk == NULL || op == NULL) + return -EINVAL; + + bin_ops = ec_realloc(tk->bin_ops, + (tk->bin_ops_len + 1) * sizeof(*tk->bin_ops)); + if (bin_ops == NULL) + return -1; + + tk->bin_ops = bin_ops; + bin_ops[tk->bin_ops_len] = op; + tk->bin_ops_len++; + + return 0; +} + +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; + + // XXX check tk type + + /* XXX use assert or check like this ? */ + if (tk == NULL || op == NULL) + return -EINVAL; + + pre_ops = ec_realloc(tk->pre_ops, + (tk->pre_ops_len + 1) * sizeof(*tk->pre_ops)); + if (pre_ops == NULL) + return -1; + + tk->pre_ops = pre_ops; + pre_ops[tk->pre_ops_len] = op; + tk->pre_ops_len++; + + return 0; +} + +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; + + // XXX check tk type + + /* XXX use assert or check like this ? */ + if (tk == NULL || op == NULL) + return -EINVAL; + + post_ops = ec_realloc(tk->post_ops, + (tk->post_ops_len + 1) * sizeof(*tk->post_ops)); + if (post_ops == NULL) + return -1; + + tk->post_ops = post_ops; + post_ops[tk->post_ops_len] = op; + tk->post_ops_len++; + + return 0; +} + +int ec_tk_expr_start(struct ec_tk *gen_tk) +{ + struct ec_tk_expr *tk = (struct ec_tk_expr *)gen_tk; + + 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; + + return 0; +} + +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; + + gen_tk = ec_tk_expr_new(id); + if (gen_tk == NULL) + 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) + goto fail; + + op = ec_strdup(bin_ops); + if (op == NULL) + goto fail; + op[1] = '\0'; + + /* we match: + * ( )* + */ + child = ec_tk_seq_new_list(NULL, + ec_tk_clone(sub_expr), + ec_tk_many_new(NULL, + ec_tk_seq_new_list(NULL, + ec_tk_str_new(NULL, op), + ec_tk_clone(sub_expr), + EC_TK_ENDLIST + ), + 0, 0 + ), + EC_TK_ENDLIST + ); + ec_free(op); + op = NULL; + + /* remove initial reference */ + ec_tk_free(sub_expr); + + if (child == NULL) + goto fail; + + ec_tk_free(val_tk); + } + + tk->child = child; + + return &tk->gen; + +fail: + ec_free(op); + ec_tk_free(child); + ec_tk_free(val_tk); + ec_tk_free(gen_tk); + return NULL; +} + +static int ec_tk_expr_testcase(void) +{ + struct ec_tk *tk, *tk2, *val_tk; + int ret = 0; + + val_tk = ec_tk_str_new(NULL, "val"); + tk = ec_tk_seq_new_list(NULL, + ec_tk_clone(val_tk), + ec_tk_many_new(NULL, + ec_tk_seq_new_list(NULL, + ec_tk_str_new(NULL, "*"), + ec_tk_clone(val_tk), + 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), + ec_tk_many_new(NULL, + ec_tk_seq_new_list(NULL, + ec_tk_str_new(NULL, "+"), + ec_tk_clone(tk), + EC_TK_ENDLIST + ), + 0, 0 + ), + EC_TK_ENDLIST + ); + + +// "/*-+"); + if (tk2 == NULL) { + ec_log(EC_LOG_ERR, "cannot create tk\n"); + 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); + + 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", + 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_ENDLIST); + ec_tk_free(tk); + + return ret; +} + +static struct ec_test ec_tk_expr_test = { + .name = "tk_expr", + .test = ec_tk_expr_testcase, +}; + +EC_REGISTER_TEST(ec_tk_expr_test); diff --git a/lib/ecoli_tk_expr.h b/lib/ecoli_tk_expr.h new file mode 100644 index 0000000..73bce00 --- /dev/null +++ b/lib/ecoli_tk_expr.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2016, 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_EXPR_ +#define ECOLI_TK_EXPR_ + +#include + +/* 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); +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); + + +#endif diff --git a/lib/ecoli_tk_int.c b/lib/ecoli_tk_int.c index 57971ee..5e404e9 100644 --- a/lib/ecoli_tk_int.c +++ b/lib/ecoli_tk_int.c @@ -88,7 +88,7 @@ static struct ec_parsed_tk *ec_tk_int_parse(const struct ec_tk *gen_tk, if (parse_llint(tk, str, &val) < 0) return parsed_tk; - match_strvec = ec_strvec_ndup(strvec, 1); + match_strvec = ec_strvec_ndup(strvec, 0, 1); if (match_strvec == NULL) goto fail; @@ -156,12 +156,12 @@ static int ec_tk_int_testcase(void) ret |= EC_TEST_CHECK_TK_PARSE(tk, -1, "0x101", EC_TK_ENDLIST); p = ec_tk_parse(tk, "0"); - s = ec_parsed_tk_to_string(p); + s = ec_strvec_val(ec_parsed_tk_strvec(p), 0); EC_TEST_ASSERT(s != NULL && ec_tk_int_getval(tk, s) == 0); ec_parsed_tk_free(p); p = ec_tk_parse(tk, "10"); - s = ec_parsed_tk_to_string(p); + s = ec_strvec_val(ec_parsed_tk_strvec(p), 0); EC_TEST_ASSERT(s != NULL && ec_tk_int_getval(tk, s) == 10); ec_parsed_tk_free(p); ec_tk_free(tk); @@ -178,7 +178,7 @@ static int ec_tk_int_testcase(void) ret |= EC_TEST_CHECK_TK_PARSE(tk, -1, "-2", EC_TK_ENDLIST); p = ec_tk_parse(tk, "10"); - s = ec_parsed_tk_to_string(p); + s = ec_strvec_val(ec_parsed_tk_strvec(p), 0); EC_TEST_ASSERT(s != NULL && ec_tk_int_getval(tk, s) == 16); ec_parsed_tk_free(p); ec_tk_free(tk); diff --git a/lib/ecoli_tk_many.c b/lib/ecoli_tk_many.c index 6d0b501..d93a6de 100644 --- a/lib/ecoli_tk_many.c +++ b/lib/ecoli_tk_many.c @@ -53,7 +53,7 @@ static struct ec_parsed_tk *ec_tk_many_parse(const struct ec_tk *gen_tk, struct ec_tk_many *tk = (struct ec_tk_many *)gen_tk; struct ec_parsed_tk *parsed_tk, *child_parsed_tk; struct ec_strvec *match_strvec; - struct ec_strvec childvec; + struct ec_strvec *childvec = NULL; size_t off = 0, len, count; parsed_tk = ec_parsed_tk_new(); @@ -61,13 +61,18 @@ static struct ec_parsed_tk *ec_tk_many_parse(const struct ec_tk *gen_tk, goto fail; for (count = 0; tk->max == 0 || count < tk->max; count++) { - if (ec_strvec_slice(&childvec, strvec, off) < 0) + childvec = ec_strvec_ndup(strvec, off, + ec_strvec_len(strvec) - off); + if (childvec == NULL) goto fail; - child_parsed_tk = ec_tk_parse_tokens(tk->child, &childvec); + child_parsed_tk = ec_tk_parse_tokens(tk->child, childvec); if (child_parsed_tk == NULL) goto fail; + ec_strvec_free(childvec); + childvec = NULL; + if (!ec_parsed_tk_matches(child_parsed_tk)) { ec_parsed_tk_free(child_parsed_tk); break; @@ -90,7 +95,7 @@ static struct ec_parsed_tk *ec_tk_many_parse(const struct ec_tk *gen_tk, return parsed_tk; } - match_strvec = ec_strvec_ndup(strvec, off); + match_strvec = ec_strvec_ndup(strvec, 0, off); if (match_strvec == NULL) goto fail; @@ -98,7 +103,8 @@ static struct ec_parsed_tk *ec_tk_many_parse(const struct ec_tk *gen_tk, return parsed_tk; - fail: +fail: + ec_strvec_free(childvec); ec_parsed_tk_free(parsed_tk); return NULL; } @@ -109,7 +115,7 @@ static struct ec_completed_tk *ec_tk_many_complete(const struct ec_tk *gen_tk, { struct ec_tk_many *tk = (struct ec_tk_many *)gen_tk; struct ec_completed_tk *completed_tk, *child_completed_tk; - struct ec_strvec childvec; + struct ec_strvec *childvec; struct ec_parsed_tk *parsed_tk; size_t len = 0; unsigned int i; @@ -122,20 +128,25 @@ static struct ec_completed_tk *ec_tk_many_complete(const struct ec_tk *gen_tk, return completed_tk; for (i = 0; i < tk->len; i++) { - if (ec_strvec_slice(&childvec, strvec, len) < 0) - return completed_tk; /* XXX fail ? */ + childvec = ec_strvec_ndup(strvec, len, + ec_strvec_len(strvec) - len); + if (childvec == NULL) + goto fail; // XXX fail ? child_completed_tk = ec_tk_complete_tokens(tk->table[i], - &childvec); - if (child_completed_tk == NULL) { - ec_completed_tk_free(completed_tk); - return NULL; - } + childvec); + if (child_completed_tk == NULL) + goto fail; + ec_completed_tk_merge(completed_tk, child_completed_tk); - parsed_tk = ec_tk_parse_tokens(tk->table[i], &childvec); + parsed_tk = ec_tk_parse_tokens(tk->table[i], childvec); if (parsed_tk == NULL) goto fail; + + ec_strvec_free(childvec); + childvec = NULL; + if (!ec_parsed_tk_matches(parsed_tk)) { ec_parsed_tk_free(parsed_tk); break; @@ -148,7 +159,8 @@ static struct ec_completed_tk *ec_tk_many_complete(const struct ec_tk *gen_tk, return completed_tk; fail: - /* XXX */ + ec_strvec_free(childvec); + ec_completed_tk_free(completed_tk); return NULL; } #endif diff --git a/lib/ecoli_tk_or.c b/lib/ecoli_tk_or.c index 2889147..55f3e69 100644 --- a/lib/ecoli_tk_or.c +++ b/lib/ecoli_tk_or.c @@ -157,10 +157,13 @@ struct ec_tk *ec_tk_or_new_list(const char *id, ...) for (child = va_arg(ap, struct ec_tk *); child != EC_TK_ENDLIST; child = va_arg(ap, struct ec_tk *)) { - /* on error, don't quit the loop to avoid leaks */ - if (child == NULL || ec_tk_or_add(&tk->gen, child) < 0) + /* on error, don't quit the loop to avoid leaks */ + if (fail == 1 || child == NULL || + ec_tk_or_add(&tk->gen, child) < 0) { fail = 1; + ec_tk_free(child); + } } if (fail == 1) diff --git a/lib/ecoli_tk_seq.c b/lib/ecoli_tk_seq.c index e606a09..6feb17d 100644 --- a/lib/ecoli_tk_seq.c +++ b/lib/ecoli_tk_seq.c @@ -52,7 +52,7 @@ static struct ec_parsed_tk *ec_tk_seq_parse(const struct ec_tk *gen_tk, struct ec_tk_seq *tk = (struct ec_tk_seq *)gen_tk; struct ec_parsed_tk *parsed_tk, *child_parsed_tk; struct ec_strvec *match_strvec; - struct ec_strvec childvec; + struct ec_strvec *childvec = NULL; size_t len = 0; unsigned int i; @@ -61,12 +61,18 @@ static struct ec_parsed_tk *ec_tk_seq_parse(const struct ec_tk *gen_tk, goto fail; for (i = 0; i < tk->len; i++) { - if (ec_strvec_slice(&childvec, strvec, len) < 0) + childvec = ec_strvec_ndup(strvec, len, + ec_strvec_len(strvec) - len); + if (childvec == NULL) goto fail; - child_parsed_tk = ec_tk_parse_tokens(tk->table[i], &childvec); + child_parsed_tk = ec_tk_parse_tokens(tk->table[i], childvec); if (child_parsed_tk == NULL) goto fail; + + ec_strvec_free(childvec); + childvec = NULL; + if (!ec_parsed_tk_matches(child_parsed_tk)) { ec_parsed_tk_free(child_parsed_tk); ec_parsed_tk_free_children(parsed_tk); @@ -77,7 +83,7 @@ static struct ec_parsed_tk *ec_tk_seq_parse(const struct ec_tk *gen_tk, len += ec_parsed_tk_len(child_parsed_tk); } - match_strvec = ec_strvec_ndup(strvec, len); + match_strvec = ec_strvec_ndup(strvec, 0, len); if (match_strvec == NULL) goto fail; @@ -85,7 +91,8 @@ static struct ec_parsed_tk *ec_tk_seq_parse(const struct ec_tk *gen_tk, return parsed_tk; - fail: +fail: + ec_strvec_free(childvec); ec_parsed_tk_free(parsed_tk); return NULL; } @@ -95,7 +102,7 @@ static struct ec_completed_tk *ec_tk_seq_complete(const struct ec_tk *gen_tk, { struct ec_tk_seq *tk = (struct ec_tk_seq *)gen_tk; struct ec_completed_tk *completed_tk, *child_completed_tk; - struct ec_strvec childvec; + struct ec_strvec *childvec = NULL; struct ec_parsed_tk *parsed_tk; size_t len = 0; unsigned int i; @@ -108,20 +115,25 @@ static struct ec_completed_tk *ec_tk_seq_complete(const struct ec_tk *gen_tk, return completed_tk; for (i = 0; i < tk->len && len < ec_strvec_len(strvec); i++) { - if (ec_strvec_slice(&childvec, strvec, len) < 0) + childvec = ec_strvec_ndup(strvec, len, + ec_strvec_len(strvec) - len); + if (childvec == NULL) goto fail; child_completed_tk = ec_tk_complete_tokens(tk->table[i], - &childvec); - if (child_completed_tk == NULL) { - ec_completed_tk_free(completed_tk); - return NULL; - } + childvec); + if (child_completed_tk == NULL) + goto fail; + ec_completed_tk_merge(completed_tk, child_completed_tk); - parsed_tk = ec_tk_parse_tokens(tk->table[i], &childvec); + parsed_tk = ec_tk_parse_tokens(tk->table[i], childvec); if (parsed_tk == NULL) goto fail; + + ec_strvec_free(childvec); + childvec = NULL; + if (!ec_parsed_tk_matches(parsed_tk)) { ec_parsed_tk_free(parsed_tk); break; @@ -134,7 +146,8 @@ static struct ec_completed_tk *ec_tk_seq_complete(const struct ec_tk *gen_tk, return completed_tk; fail: - /* XXX */ + ec_strvec_free(childvec); + ec_completed_tk_free(completed_tk); return NULL; } @@ -180,15 +193,18 @@ struct ec_tk *ec_tk_seq_new_list(const char *id, ...) tk = (struct ec_tk_seq *)ec_tk_seq_new(id); if (tk == NULL) - goto fail; + fail = 1; for (child = va_arg(ap, struct ec_tk *); child != EC_TK_ENDLIST; child = va_arg(ap, struct ec_tk *)) { - /* on error, don't quit the loop to avoid leaks */ - if (child == NULL || ec_tk_seq_add(&tk->gen, child) < 0) + /* on error, don't quit the loop to avoid leaks */ + if (fail == 1 || child == NULL || + ec_tk_seq_add(&tk->gen, child) < 0) { fail = 1; + ec_tk_free(child); + } } if (fail == 1) @@ -219,10 +235,10 @@ int ec_tk_seq_add(struct ec_tk *gen_tk, struct ec_tk *child) tk->table = table; table[tk->len] = child; - tk->len ++; + tk->len++; child->parent = gen_tk; - TAILQ_INSERT_TAIL(&gen_tk->children, child, next); + TAILQ_INSERT_TAIL(&gen_tk->children, child, next); // XXX really needed? return 0; } diff --git a/lib/ecoli_tk_shlex.c b/lib/ecoli_tk_shlex.c index ba6d20a..0b53968 100644 --- a/lib/ecoli_tk_shlex.c +++ b/lib/ecoli_tk_shlex.c @@ -267,7 +267,7 @@ static struct ec_parsed_tk *ec_tk_shlex_parse(const struct ec_tk *gen_tk, new_vec = NULL; ec_parsed_tk_add_child(parsed_tk, child_parsed_tk); - match_strvec = ec_strvec_ndup(strvec, 1); + 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); diff --git a/lib/ecoli_tk_space.c b/lib/ecoli_tk_space.c index 8ec1650..33f33d8 100644 --- a/lib/ecoli_tk_space.c +++ b/lib/ecoli_tk_space.c @@ -62,7 +62,7 @@ static struct ec_parsed_tk *ec_tk_space_parse(const struct ec_tk *gen_tk, if (len == 0 || len != strlen(str)) return parsed_tk; - match_strvec = ec_strvec_ndup(strvec, 1); + match_strvec = ec_strvec_ndup(strvec, 0, 1); if (match_strvec == NULL) goto fail; diff --git a/lib/ecoli_tk_str.c b/lib/ecoli_tk_str.c index 6c650d3..f3999ff 100644 --- a/lib/ecoli_tk_str.c +++ b/lib/ecoli_tk_str.c @@ -61,7 +61,7 @@ static struct ec_parsed_tk *ec_tk_str_parse(const struct ec_tk *gen_tk, if (strcmp(str, tk->string) != 0) return parsed_tk; - match_strvec = ec_strvec_ndup(strvec, 1); + match_strvec = ec_strvec_ndup(strvec, 0, 1); if (match_strvec == NULL) goto fail; @@ -138,25 +138,27 @@ static const struct ec_tk_ops ec_tk_str_ops = { struct ec_tk *ec_tk_str_new(const char *id, const char *str) { + struct ec_tk *gen_tk = NULL; struct ec_tk_str *tk = NULL; char *s = NULL; - tk = (struct ec_tk_str *)ec_tk_new(id, &ec_tk_str_ops, sizeof(*tk)); - if (tk == NULL) + gen_tk = ec_tk_new(id, &ec_tk_str_ops, sizeof(*tk)); + if (gen_tk == NULL) goto fail; s = ec_strdup(str); if (s == NULL) goto fail; + tk = (struct ec_tk_str *)gen_tk; tk->string = s; tk->len = strlen(s); - return &tk->gen; + return gen_tk; fail: ec_free(s); - ec_free(tk); + ec_tk_free(gen_tk); return NULL; } diff --git a/lib/main.c b/lib/main.c index d3d35b3..deffea3 100644 --- a/lib/main.c +++ b/lib/main.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -40,21 +41,25 @@ static int log_level = EC_LOG_INFO; static int alloc_fail_proba = 0; +static int seed = 0; static const char ec_short_options[] = "h" /* help */ "l:" /* log-level */ "r:" /* random-alloc-fail */ + "s:" /* seed */ ; #define EC_OPT_HELP "help" #define EC_OPT_LOG_LEVEL "log-level" #define EC_OPT_RANDOM_ALLOC_FAIL "random-alloc-fail" +#define EC_OPT_SEED "seed" static const struct option ec_long_options[] = { {EC_OPT_HELP, 1, NULL, 'h'}, {EC_OPT_LOG_LEVEL, 1, NULL, 'l'}, {EC_OPT_RANDOM_ALLOC_FAIL, 1, NULL, 'r'}, + {EC_OPT_SEED, 1, NULL, 's'}, {NULL, 0, NULL, 0} }; @@ -72,6 +77,9 @@ static void usage(const char *prgname) " Cause malloc to fail randomly. This helps to debug\n" " leaks or crashes in error cases. The probability is\n" " between 0 and 100.\n" + " -s \n" + " --seed=\n" + " Seeds the random number generator. Default is 0.\n" , prgname); } @@ -123,6 +131,14 @@ static void parse_args(int argc, char **argv) } break; + case 's': /* seed */ + if (parse_int(optarg, 0, INT_MAX, &seed, 10) < 0) { + printf("Invalid seed value\n"); + usage(argv[0]); + exit(1); + } + break; + default: usage(argv[0]); exit(1); @@ -341,6 +357,7 @@ int main(int argc, char **argv) int ret, leaks; parse_args(argc, argv); + srandom(seed); ec_log_register(debug_log, NULL); -- 2.20.1