From a936ea741c1135e46e04b4dd75b95adc2ac201cb Mon Sep 17 00:00:00 2001 From: Olivier Matz Date: Fri, 10 Nov 2017 22:05:03 +0100 Subject: [PATCH] save --- lib/Makefile | 3 +- lib/ecoli_completed.c | 25 ++++++++-- lib/ecoli_completed.h | 3 +- lib/ecoli_keyval.c | 5 ++ lib/ecoli_keyval.h | 2 + lib/ecoli_node_cmd.c | 15 +++--- lib/ecoli_node_expr.c | 4 +- lib/ecoli_node_int.c | 106 ++++++++++++++++++++++++++++++++++++------ lib/ecoli_node_int.h | 14 ++++-- lib/ecoli_parsed.c | 9 ++++ lib/ecoli_parsed.h | 2 +- lib/ecoli_vec.c | 1 + lib/ecoli_vec.h | 2 + lib/main-readline.c | 2 +- lib/todo.txt | 3 ++ 15 files changed, 162 insertions(+), 34 deletions(-) diff --git a/lib/Makefile b/lib/Makefile index d6a4e80..b258752 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -50,6 +50,7 @@ srcs += ecoli_malloc.c srcs += ecoli_strvec.c srcs += ecoli_test.c srcs += ecoli_node.c +srcs += ecoli_node_any.c srcs += ecoli_node_cmd.c srcs += ecoli_node_empty.c srcs += ecoli_node_expr.c @@ -78,7 +79,7 @@ ldflags-$(O)test = -rdynamic exe-y-$(O)test = $(srcs) main.c ldflags-$(O)readline = -lreadline -ltermcap -exe-y-$(O)readline = $(srcs) main-readline.c +#exe-y-$(O)readline = $(srcs) main-readline.c include $(ECOLI)/mk/ecoli-post.mk diff --git a/lib/ecoli_completed.c b/lib/ecoli_completed.c index 64bb70d..553eccc 100644 --- a/lib/ecoli_completed.c +++ b/lib/ecoli_completed.c @@ -45,11 +45,22 @@ struct ec_completed *ec_completed(void) completed = ec_calloc(1, sizeof(*completed)); if (completed == NULL) - return NULL; + goto fail; TAILQ_INIT(&completed->nodes); + completed->attrs = ec_keyval(); + if (completed->attrs == NULL) + goto fail; + return completed; + + fail: + if (completed != NULL) + ec_keyval_free(completed->attrs); + ec_free(completed); + + return NULL; } /* XXX on error, states are not freed ? @@ -181,7 +192,11 @@ ec_completed_item(struct ec_parsed *state, const struct ec_node *node) item = ec_calloc(1, sizeof(*item)); if (item == NULL) - return NULL; + goto fail; + + item->attrs = ec_keyval(); + if (item->attrs == NULL) + goto fail; /* get path len */ for (p = state, len = 0; p != NULL; @@ -207,8 +222,9 @@ fail: ec_free(item->path); ec_free(item->str); ec_free(item->display); + ec_keyval_free(item->attrs); } - ec_completed_item_free(item); + ec_free(item); return NULL; } @@ -284,7 +300,6 @@ int ec_completed_item_set_display(struct ec_completed_item *item, fail: ec_free(display_copy); return ret; - } int @@ -333,6 +348,7 @@ void ec_completed_item_free(struct ec_completed_item *item) ec_free(item->str); ec_free(item->display); ec_free(item->path); + ec_keyval_free(item->attrs); ec_free(item); } @@ -385,6 +401,7 @@ void ec_completed_free(struct ec_completed *completed) } ec_free(compnode); } + ec_keyval_free(completed->attrs); ec_free(completed); } diff --git a/lib/ecoli_completed.h b/lib/ecoli_completed.h index 1627cfe..22016e5 100644 --- a/lib/ecoli_completed.h +++ b/lib/ecoli_completed.h @@ -46,7 +46,7 @@ struct ec_completed_item { const struct ec_node *node; char *str; char *display; - /* XXX add a keyval (attrs) */ + struct ec_keyval *attrs; /* reverse order: [0] = last, [len-1] = root */ const struct ec_node **path; @@ -67,6 +67,7 @@ struct ec_completed { unsigned count; unsigned count_match; struct ec_completed_node_list nodes; + struct ec_keyval *attrs; // XXX per node instead? }; /* diff --git a/lib/ecoli_keyval.c b/lib/ecoli_keyval.c index a47ded9..e80dd08 100644 --- a/lib/ecoli_keyval.c +++ b/lib/ecoli_keyval.c @@ -87,6 +87,11 @@ static void ec_keyval_elt_free(struct ec_keyval_elt *elt) elt->free(elt->val); } +bool ec_keyval_has_key(const struct ec_keyval *keyval, const char *key) +{ + return !!ec_keyval_lookup(keyval, key); +} + void *ec_keyval_get(const struct ec_keyval *keyval, const char *key) { struct ec_keyval_elt *elt; diff --git a/lib/ecoli_keyval.h b/lib/ecoli_keyval.h index 82fc9e4..30232d0 100644 --- a/lib/ecoli_keyval.h +++ b/lib/ecoli_keyval.h @@ -29,6 +29,7 @@ #define ECOLI_KEYVAL_ #include +#include typedef void (*ec_keyval_elt_free_t)(void *); @@ -37,6 +38,7 @@ struct ec_keyval; struct ec_keyval *ec_keyval(void); void *ec_keyval_get(const struct ec_keyval *keyval, const char *key); +bool ec_keyval_has_key(const struct ec_keyval *keyval, const char *key); 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); diff --git a/lib/ecoli_node_cmd.c b/lib/ecoli_node_cmd.c index db08cbf..0aca9b1 100644 --- a/lib/ecoli_node_cmd.c +++ b/lib/ecoli_node_cmd.c @@ -85,7 +85,7 @@ ec_node_cmd_eval_var(void **result, void *userctx, for (i = 0; i < node->len; i++) { id = ec_node_id(node->table[i]); - printf("i=%d id=%s\n", i, id); + //printf("i=%d id=%s\n", i, id); if (id == NULL) continue; if (strcmp(str, id)) @@ -104,7 +104,7 @@ ec_node_cmd_eval_var(void **result, void *userctx, return -ENOMEM; } - printf("eval var %s %p\n", str, eval); + //printf("eval var %s %p\n", str, eval); *result = eval; return 0; @@ -141,7 +141,7 @@ ec_node_cmd_eval_post_op(void **result, void *userctx, void *operand, else return -EINVAL; - printf("eval post_op %p\n", eval); + //printf("eval post_op %p\n", eval); *result = eval; return 0; @@ -159,7 +159,7 @@ ec_node_cmd_eval_bin_op(void **result, void *userctx, void *operand1, (void)userctx; - printf("eval bin_op %p %p\n", in1, in2); + //printf("eval bin_op %p %p\n", in1, in2); /* get parsed string vector, it should contain only one str */ vec = ec_parsed_strvec(operator); @@ -192,7 +192,7 @@ ec_node_cmd_eval_bin_op(void **result, void *userctx, void *operand1, return -EINVAL; } - printf("eval bin_op out %p\n", *result); + //printf("eval bin_op out %p\n", *result); return 0; } @@ -226,7 +226,7 @@ ec_node_cmd_eval_parenthesis(void **result, void *userctx, return -EINVAL; } - printf("eval paren\n"); + //printf("eval paren\n"); *result = out; return 0; @@ -374,7 +374,7 @@ static int ec_node_cmd_build(struct ec_node *gen_node) } ec_parsed_free(p); p = NULL; - ec_node_dump(stdout, cmd); + //ec_node_dump(stdout, cmd); ec_node_free(node->expr); node->expr = expr; @@ -413,7 +413,6 @@ int ec_node_cmd_add_child(struct ec_node *gen_node, struct ec_node *child) assert(node != NULL); - printf("add child %s\n", child->id); if (child == NULL) return -EINVAL; diff --git a/lib/ecoli_node_expr.c b/lib/ecoli_node_expr.c index 24bdfd9..9207e4d 100644 --- a/lib/ecoli_node_expr.c +++ b/lib/ecoli_node_expr.c @@ -213,7 +213,7 @@ static int ec_node_expr_build(struct ec_node *gen_node) weak = NULL; node->child = expr; - ec_node_dump(stdout, node->child); //XXX + //ec_node_dump(stdout, node->child); //XXX return 0; @@ -595,7 +595,7 @@ int ec_node_expr_eval(void **user_result, const struct ec_node *node, if (!ec_parsed_matches(parsed)) return -EINVAL; - ec_parsed_dump(stdout, parsed); //XXX + //ec_parsed_dump(stdout, parsed); //XXX ret = eval_expression(&result, userctx, ops, node, parsed); if (ret < 0) return ret; diff --git a/lib/ecoli_node_int.c b/lib/ecoli_node_int.c index b685f16..cb7f60b 100644 --- a/lib/ecoli_node_int.c +++ b/lib/ecoli_node_int.c @@ -47,24 +47,32 @@ EC_LOG_TYPE_REGISTER(node_int); struct ec_node_int { struct ec_node gen; + bool is_signed; bool check_min; - long long int min; bool check_max; - long long int max; + union { + int64_t min; + uint64_t umin; + }; + union { + int64_t max; + uint64_t umax; + }; unsigned int base; }; static int parse_llint(struct ec_node_int *node, const char *str, - long long *val) + int64_t *val) { char *endptr; errno = 0; *val = strtoll(str, &endptr, node->base); - /* out of range */ - if ((errno == ERANGE && (*val == LLONG_MAX || *val == LLONG_MIN)) || - (errno != 0 && *val == 0)) + if (errno == ERANGE && (*val == LLONG_MAX || *val == LLONG_MIN)) + return -1; + + if (errno != 0 && *val == 0) return -1; if (node->check_min && *val < node->min) @@ -79,13 +87,44 @@ static int parse_llint(struct ec_node_int *node, const char *str, return 0; } +static int parse_ullint(struct ec_node_int *node, const char *str, + uint64_t *val) +{ + char *endptr; + + /* since a negative input is silently converted to a positive + * one by strtoull(), first check that it is positive */ + if (strchr(str, '-')) + return -1; + + errno = 0; + *val = strtoull(str, &endptr, node->base); + + if (errno == ERANGE && *val == ULLONG_MAX) + return -1; + + if (errno != 0 && *val == 0) + return -1; + + if (node->check_min && *val < node->umin) + return -1; + + if (node->check_max && *val > node->umax) + return -1; + + if (*endptr != 0) + return -1; + + return 0; +} + static int ec_node_int_parse(const struct ec_node *gen_node, struct ec_parsed *state, const struct ec_strvec *strvec) { struct ec_node_int *node = (struct ec_node_int *)gen_node; const char *str; - long long val; + int64_t val; (void)state; @@ -115,12 +154,15 @@ static struct ec_node_type ec_node_int_type = { EC_NODE_TYPE_REGISTER(ec_node_int_type); -struct ec_node *ec_node_int(const char *id, long long int min, - long long int max, unsigned int base) +struct ec_node *ec_node_int(const char *id, int64_t min, + int64_t max, unsigned int base) { struct ec_node *gen_node = NULL; struct ec_node_int *node = NULL; + if (min > max) + return NULL; + gen_node = __ec_node(&ec_node_int_type, id); if (gen_node == NULL) return NULL; @@ -131,14 +173,39 @@ struct ec_node *ec_node_int(const char *id, long long int min, node->check_max = true; node->max = max; node->base = base; + node->is_signed = true; return &node->gen; } -long long ec_node_int_getval(struct ec_node *gen_node, const char *str) +struct ec_node *ec_node_uint(const char *id, uint64_t min, + uint64_t max, unsigned int base) +{ + struct ec_node *gen_node = NULL; + struct ec_node_int *node = NULL; + + if (min > max) + return NULL; + + gen_node = __ec_node(&ec_node_int_type, id); + if (gen_node == NULL) + return NULL; + node = (struct ec_node_int *)gen_node; + + node->check_min = true; + node->min = min; + node->check_max = true; + node->max = max; + node->base = base; + node->is_signed = true; + + return &node->gen; +} + +int64_t ec_node_int_getval(struct ec_node *gen_node, const char *str) { struct ec_node_int *node = (struct ec_node_int *)gen_node; - long long val = 0; + int64_t val = 0; // XXX check type here // if gen_node->type != int fail @@ -148,6 +215,19 @@ long long ec_node_int_getval(struct ec_node *gen_node, const char *str) return val; } +uint64_t ec_node_uint_getval(struct ec_node *gen_node, const char *str) +{ + struct ec_node_int *node = (struct ec_node_int *)gen_node; + uint64_t val = 0; + + // XXX check type here + // if gen_node->type != int fail + + parse_ullint(node, str, &val); + + return val; +} + /* LCOV_EXCL_START */ static int ec_node_int_testcase(void) { @@ -156,7 +236,7 @@ static int ec_node_int_testcase(void) const char *s; int ret = 0; - node = ec_node_int(NULL, 0, 256, 0); + node = ec_node_uint(NULL, 0, 256, 0); if (node == NULL) { EC_LOG(EC_LOG_ERR, "cannot create node\n"); return -1; @@ -175,7 +255,7 @@ static int ec_node_int_testcase(void) p = ec_node_parse(node, "10"); s = ec_strvec_val(ec_parsed_strvec(p), 0); - EC_TEST_ASSERT(s != NULL && ec_node_int_getval(node, s) == 10); + EC_TEST_ASSERT(s != NULL && ec_node_uint_getval(node, s) == 10); ec_parsed_free(p); ec_node_free(node); diff --git a/lib/ecoli_node_int.h b/lib/ecoli_node_int.h index d03dd3d..b871529 100644 --- a/lib/ecoli_node_int.h +++ b/lib/ecoli_node_int.h @@ -28,12 +28,20 @@ #ifndef ECOLI_NODE_INT_ #define ECOLI_NODE_INT_ +#include + #include // XXX remove min, max, base from new(), and add ec_node_int_set_limits() + // XXX ec_node_int_set_base() ? -struct ec_node *ec_node_int(const char *id, long long int min, - long long int max, unsigned int base); -long long ec_node_int_getval(struct ec_node *node, const char *str); + +struct ec_node *ec_node_int(const char *id, int64_t min, + int64_t max, unsigned int base); +int64_t ec_node_int_getval(struct ec_node *node, const char *str); + +struct ec_node *ec_node_uint(const char *id, uint64_t min, + uint64_t max, unsigned int base); +uint64_t ec_node_uint_getval(struct ec_node *node, const char *str); + #endif diff --git a/lib/ecoli_parsed.c b/lib/ecoli_parsed.c index c717723..e951671 100644 --- a/lib/ecoli_parsed.c +++ b/lib/ecoli_parsed.c @@ -147,9 +147,17 @@ struct ec_parsed *ec_parsed(void) TAILQ_INIT(&parsed->children); + parsed->attrs = ec_keyval(); + if (parsed->attrs == NULL) + goto fail; + return parsed; fail: + if (parsed != NULL) + ec_keyval_free(parsed->attrs); + ec_free(parsed); + return NULL; } @@ -174,6 +182,7 @@ void ec_parsed_free(struct ec_parsed *parsed) ec_parsed_free_children(parsed); ec_strvec_free(parsed->strvec); + ec_keyval_free(parsed->attrs); ec_free(parsed); } diff --git a/lib/ecoli_parsed.h b/lib/ecoli_parsed.h index 1a246ce..459f93d 100644 --- a/lib/ecoli_parsed.h +++ b/lib/ecoli_parsed.h @@ -47,7 +47,7 @@ struct ec_parsed { struct ec_parsed *parent; const struct ec_node *node; struct ec_strvec *strvec; - /* XXX add a keyval (attrs) */ + struct ec_keyval *attrs; }; struct ec_parsed *ec_parsed(void); diff --git a/lib/ecoli_vec.c b/lib/ecoli_vec.c index 001891e..871911d 100644 --- a/lib/ecoli_vec.c +++ b/lib/ecoli_vec.c @@ -93,6 +93,7 @@ int ec_vec_add_by_ref(struct ec_vec *vec, void *ptr) new_vec = ec_realloc(vec->vec, vec->elt_size * (vec->len + 1)); if (new_vec == NULL) return -ENOMEM; + vec->size = vec->len + 1; } vec->vec = new_vec; diff --git a/lib/ecoli_vec.h b/lib/ecoli_vec.h index defd652..493e453 100644 --- a/lib/ecoli_vec.h +++ b/lib/ecoli_vec.h @@ -62,6 +62,8 @@ struct ec_vec *ec_vec_dup(const struct ec_vec *vec); struct ec_vec *ec_vec_ndup(const struct ec_vec *vec, size_t off, size_t len); void ec_vec_free(struct ec_vec *vec); + +__attribute__((pure)) size_t ec_vec_len(const struct ec_vec *vec); #endif diff --git a/lib/main-readline.c b/lib/main-readline.c index 8fecad4..4601ae8 100644 --- a/lib/main-readline.c +++ b/lib/main-readline.c @@ -55,7 +55,7 @@ static char *my_completion_entry(const char *s, int state) { static struct ec_completed *c; static struct ec_completed_iter *iter; - static const struct ec_completed_item *item; + const struct ec_completed_item *item; (void)s; diff --git a/lib/todo.txt b/lib/todo.txt index 37a61d7..8d56dc5 100644 --- a/lib/todo.txt +++ b/lib/todo.txt @@ -9,6 +9,9 @@ X tk_re cleanup / rework ================ +- ec_completed_item_update() +- ec_completed_item_set_display_value() + - add_no_match - add_partial_match - check XXX in code -- 2.20.1