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
#include <ecoli_test.h>
#include <ecoli_keyval.h>
-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;
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);
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)
*/
#include <sys/types.h>
+#include <stdio.h>
#include <stdlib.h>
+#include <errno.h>
#include <ecoli_malloc.h>
#include <ecoli_strvec.h>
+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;
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;
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++;
}
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);
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;
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 */
#ifndef ECOLI_STRVEC_
#define ECOLI_STRVEC_
-#include <stdio.h>
-
-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
TAILQ_INIT(&tk->children);
tk->ops = ops;
+ tk->refcnt = 1;
if (id != NULL) {
tk->id = ec_strdup(id);
return tk;
fail:
- ec_free(tk->attrs);
- ec_free(tk->desc);
- ec_free(tk->id);
ec_tk_free(tk);
return NULL;
}
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);
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;
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);
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 */
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;
};
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);
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);
--- /dev/null
+/*
+ * Copyright (c) 2016, Olivier MATZ <zer0@droids-corp.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <stdarg.h>
+#include <errno.h>
+
+#include <ecoli_malloc.h>
+#include <ecoli_log.h>
+#include <ecoli_test.h>
+#include <ecoli_strvec.h>
+#include <ecoli_tk.h>
+#include <ecoli_tk_str.h>
+#include <ecoli_tk_seq.h>
+#include <ecoli_tk_many.h>
+#include <ecoli_tk_expr.h>
+
+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:
+ * <subexpr> (<op> <subexpr>)*
+ */
+ 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);
--- /dev/null
+/*
+ * Copyright (c) 2016, Olivier MATZ <zer0@droids-corp.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ECOLI_TK_EXPR_
+#define ECOLI_TK_EXPR_
+
+#include <ecoli_tk.h>
+
+/* 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
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;
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);
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);
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();
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;
return parsed_tk;
}
- match_strvec = ec_strvec_ndup(strvec, off);
+ match_strvec = ec_strvec_ndup(strvec, 0, off);
if (match_strvec == NULL)
goto fail;
return parsed_tk;
- fail:
+fail:
+ ec_strvec_free(childvec);
ec_parsed_tk_free(parsed_tk);
return NULL;
}
{
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;
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;
return completed_tk;
fail:
- /* XXX */
+ ec_strvec_free(childvec);
+ ec_completed_tk_free(completed_tk);
return NULL;
}
#endif
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)
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;
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);
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;
return parsed_tk;
- fail:
+fail:
+ ec_strvec_free(childvec);
ec_parsed_tk_free(parsed_tk);
return NULL;
}
{
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;
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;
return completed_tk;
fail:
- /* XXX */
+ ec_strvec_free(childvec);
+ ec_completed_tk_free(completed_tk);
return NULL;
}
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)
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;
}
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);
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;
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;
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;
}
#include <stdio.h>
#include <assert.h>
#include <getopt.h>
+#include <limits.h>
#include <execinfo.h>
#include <ecoli_log.h>
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}
};
" 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 <seed>\n"
+ " --seed=<seed>\n"
+ " Seeds the random number generator. Default is 0.\n"
, prgname);
}
}
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);
int ret, leaks;
parse_args(argc, argv);
+ srandom(seed);
ec_log_register(debug_log, NULL);