From: Olivier Matz Date: Wed, 21 Dec 2016 16:55:02 +0000 (+0100) Subject: save X-Git-Url: http://git.droids-corp.org/?a=commitdiff_plain;h=59b1d3fa9895e47af68a0ab987a2551a16ca09a2;p=protos%2Flibecoli.git save --- 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 e389ed2..0000000 Binary files a/lib/build/test and /dev/null differ 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);