From 450515ddeece572a2d58509a01f3e27c0fb75bb2 Mon Sep 17 00:00:00 2001 From: Olivier Matz Date: Thu, 25 Jan 2018 20:22:20 +0100 Subject: [PATCH] save state in completed objects --- lib/ecoli_completed.c | 207 ++++++++++++++++++++------------------- lib/ecoli_completed.h | 31 ++++-- lib/ecoli_node.h | 5 +- lib/ecoli_node_cmd.c | 3 +- lib/ecoli_node_expr.c | 3 +- lib/ecoli_node_file.c | 5 +- lib/ecoli_node_many.c | 10 +- lib/ecoli_node_once.c | 4 +- lib/ecoli_node_option.c | 3 +- lib/ecoli_node_or.c | 3 +- lib/ecoli_node_seq.c | 11 ++- lib/ecoli_node_sh_lex.c | 3 +- lib/ecoli_node_str.c | 7 +- lib/ecoli_node_subset.c | 9 +- lib/ecoli_node_weakref.c | 3 +- lib/ecoli_parsed.c | 94 ++++++++++++------ lib/ecoli_parsed.h | 2 +- lib/ecoli_test.c | 6 +- lib/main-readline.c | 30 +++--- lib/todo.txt | 2 + 20 files changed, 244 insertions(+), 197 deletions(-) diff --git a/lib/ecoli_completed.c b/lib/ecoli_completed.c index a39c719..6820971 100644 --- a/lib/ecoli_completed.c +++ b/lib/ecoli_completed.c @@ -43,13 +43,10 @@ struct ec_completed_item { TAILQ_ENTRY(ec_completed_item) next; enum ec_completed_type type; const struct ec_node *node; + struct ec_completed_group *grp; char *str; char *display; struct ec_keyval *attrs; - - /* reverse order: [0] = last, [len-1] = root */ - const struct ec_node **path; - size_t pathlen; }; struct ec_completed *ec_completed(void) @@ -60,12 +57,14 @@ struct ec_completed *ec_completed(void) if (completed == NULL) goto fail; - TAILQ_INIT(&completed->nodes); + TAILQ_INIT(&completed->groups); completed->attrs = ec_keyval(); if (completed->attrs == NULL) goto fail; + completed->cur_state = NULL; + return completed; fail: @@ -76,15 +75,17 @@ struct ec_completed *ec_completed(void) return NULL; } -/* XXX on error, states are not freed ? - * they can be left in a bad state and should not be reused */ +struct ec_parsed *ec_completed_cur_parse_state(struct ec_completed *completed) +{ + return completed->cur_state; +} + int -ec_node_complete_child(struct ec_node *node, - struct ec_completed *completed, - struct ec_parsed *parsed_state, - const struct ec_strvec *strvec) +ec_node_complete_child(struct ec_node *node, struct ec_completed *completed, + const struct ec_strvec *strvec) { - struct ec_parsed *child_state = NULL; + struct ec_parsed *child_state, *cur_state; + struct ec_completed_group *cur_group; int ret; /* build the node if required */ @@ -100,13 +101,31 @@ ec_node_complete_child(struct ec_node *node, if (node->type->complete == NULL) return -ENOTSUP; + /* save previous parse state, prepare child state */ + cur_state = completed->cur_state; child_state = ec_parsed(); if (child_state == NULL) return -ENOMEM; + + if (cur_state != NULL) + ec_parsed_add_child(cur_state, child_state); ec_parsed_set_node(child_state, node); - ec_parsed_add_child(parsed_state, child_state); + completed->cur_state = child_state; + cur_group = completed->cur_group; + completed->cur_group = NULL; + + /* complete */ + ret = node->type->complete(node, completed, strvec); + + /* restore parent parse state */ + if (cur_state != NULL) { + ec_parsed_del_child(cur_state, child_state); + assert(!ec_parsed_has_child(child_state)); + } + ec_parsed_free(child_state); + completed->cur_state = cur_state; + completed->cur_group = cur_group; - ret = node->type->complete(node, completed, child_state, strvec); if (ret < 0) return ret; @@ -115,42 +134,28 @@ ec_node_complete_child(struct ec_node *node, ec_node_dump(stdout, node); ec_strvec_dump(stdout, strvec); ec_completed_dump(stdout, completed); - ec_parsed_dump(stdout, parsed_state); #endif - ec_parsed_del_child(parsed_state, child_state); - assert(!ec_parsed_has_child(child_state)); - ec_parsed_free(child_state); - return 0; } struct ec_completed *ec_node_complete_strvec(struct ec_node *node, const struct ec_strvec *strvec) { - struct ec_parsed *parsed_state = NULL; struct ec_completed *completed = NULL; int ret; - parsed_state = ec_parsed(); - if (parsed_state == NULL) - goto fail; - completed = ec_completed(); if (completed == NULL) goto fail; - ret = ec_node_complete_child(node, completed, - parsed_state, strvec); + ret = ec_node_complete_child(node, completed, strvec); if (ret < 0) goto fail; - ec_parsed_free(parsed_state); - return completed; fail: - ec_parsed_free(parsed_state); ec_completed_free(completed); return NULL; } @@ -181,27 +186,35 @@ struct ec_completed *ec_node_complete(struct ec_node *node, return NULL; } -static struct ec_completed_node * -ec_completed_node(const struct ec_node *node) +static struct ec_completed_group * +ec_completed_group(const struct ec_node *node, struct ec_parsed *parsed) { - struct ec_completed_node *compnode = NULL; + struct ec_completed_group *grp = NULL; - compnode = ec_calloc(1, sizeof(*compnode)); - if (compnode == NULL) + grp = ec_calloc(1, sizeof(*grp)); + if (grp == NULL) return NULL; - compnode->node = node; - TAILQ_INIT(&compnode->items); + grp->state = ec_parsed_dup(parsed); + if (grp->state == NULL) + goto fail; + + grp->node = node; + TAILQ_INIT(&grp->items); + + return grp; - return compnode; +fail: + if (grp != NULL) + ec_parsed_free(grp->state); + ec_free(grp); + return NULL; } struct ec_completed_item * -ec_completed_item(struct ec_parsed *state, const struct ec_node *node) +ec_completed_item(const struct ec_node *node) { struct ec_completed_item *item = NULL; - struct ec_parsed *p; - size_t len; item = ec_calloc(1, sizeof(*item)); if (item == NULL) @@ -211,28 +224,13 @@ ec_completed_item(struct ec_parsed *state, const struct ec_node *node) if (item->attrs == NULL) goto fail; - /* get path len */ - for (p = state, len = 0; p != NULL; - p = ec_parsed_get_parent(p), len++) - ; - /* allocate room for path */ - item->path = ec_calloc(len, sizeof(*item->path)); - if (item->path == NULL) - goto fail; - item->pathlen = len; - /* write path in array */ - for (p = state, len = 0; p != NULL; - p = ec_parsed_get_parent(p), len++) - item->path[len] = ec_parsed_get_node(p); - - item->type = EC_NO_MATCH; + item->type = EC_COMP_UNKNOWN; item->node = node; return item; fail: if (item != NULL) { - ec_free(item->path); ec_free(item->str); ec_free(item->display); ec_keyval_free(item->attrs); @@ -256,11 +254,11 @@ ec_completed_item_set(struct ec_completed_item *item, return -EEXIST; switch (type) { - case EC_NO_MATCH: + case EC_COMP_UNKNOWN: if (str != NULL) return -EINVAL; break; - case EC_MATCH: + case EC_COMP_FULL: case EC_PARTIAL_MATCH: if (str == NULL) return -EINVAL; @@ -297,7 +295,7 @@ int ec_completed_item_set_display(struct ec_completed_item *item, int ret = 0; if (item == NULL || display == NULL || - item->type == EC_NO_MATCH || item->str == NULL) + item->type == EC_COMP_UNKNOWN || item->str == NULL) return -EINVAL; ret = -ENOMEM; @@ -315,19 +313,18 @@ fail: return ret; } +// XXX refactor ec_completed_item(), ec_completed_item_add(), ec_completed_item_set* int ec_completed_item_add(struct ec_completed *completed, struct ec_completed_item *item) { - struct ec_completed_node *compnode = NULL; - if (completed == NULL || item == NULL || item->node == NULL) return -EINVAL; switch (item->type) { - case EC_NO_MATCH: + case EC_COMP_UNKNOWN: break; - case EC_MATCH: + case EC_COMP_FULL: case EC_PARTIAL_MATCH: completed->count_match++; //XXX break; @@ -335,20 +332,19 @@ ec_completed_item_add(struct ec_completed *completed, return -EINVAL; } - /* find the compnode entry corresponding to this node */ - TAILQ_FOREACH(compnode, &completed->nodes, next) { - if (compnode->node == item->node) - break; - } - if (compnode == NULL) { - compnode = ec_completed_node(item->node); - if (compnode == NULL) + if (completed->cur_group == NULL) { + struct ec_completed_group *grp; + + grp = ec_completed_group(item->node, completed->cur_state); + if (grp == NULL) return -ENOMEM; - TAILQ_INSERT_TAIL(&completed->nodes, compnode, next); + TAILQ_INSERT_TAIL(&completed->groups, grp, next); + completed->cur_group = grp; } completed->count++; - TAILQ_INSERT_TAIL(&compnode->items, item, next); + TAILQ_INSERT_TAIL(&completed->cur_group->items, item, next); + item->grp = completed->cur_group; return 0; } @@ -377,6 +373,12 @@ ec_completed_item_get_node(const struct ec_completed_item *item) return item->node; } +const struct ec_completed_group * +ec_completed_item_get_grp(const struct ec_completed_item *item) +{ + return item->grp; +} + void ec_completed_item_free(struct ec_completed_item *item) { if (item == NULL) @@ -384,7 +386,6 @@ 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); } @@ -393,7 +394,6 @@ void ec_completed_item_free(struct ec_completed_item *item) int ec_node_default_complete(const struct ec_node *gen_node, // XXX rename in nomatch struct ec_completed *completed, - struct ec_parsed *parsed_state, const struct ec_strvec *strvec) { struct ec_completed_item *item = NULL; @@ -402,10 +402,10 @@ ec_node_default_complete(const struct ec_node *gen_node, // XXX rename in nomatc if (ec_strvec_len(strvec) != 1) return 0; - item = ec_completed_item(parsed_state, gen_node); + item = ec_completed_item(gen_node); if (item == NULL) return -ENOMEM; - ret = ec_completed_item_set(item, EC_NO_MATCH, NULL); + ret = ec_completed_item_set(item, EC_COMP_UNKNOWN, NULL); if (ret < 0) { ec_completed_item_free(item); return ret; @@ -419,24 +419,33 @@ ec_node_default_complete(const struct ec_node *gen_node, // XXX rename in nomatc return 0; } -void ec_completed_free(struct ec_completed *completed) +static void ec_completed_group_free(struct ec_completed_group *grp) { - struct ec_completed_node *compnode; struct ec_completed_item *item; - if (completed == NULL) + if (grp == NULL) return; - while (!TAILQ_EMPTY(&completed->nodes)) { - compnode = TAILQ_FIRST(&completed->nodes); - TAILQ_REMOVE(&completed->nodes, compnode, next); + while (!TAILQ_EMPTY(&grp->items)) { + item = TAILQ_FIRST(&grp->items); + TAILQ_REMOVE(&grp->items, item, next); + ec_completed_item_free(item); + } + ec_parsed_free(ec_parsed_get_root(grp->state)); + ec_free(grp); +} - while (!TAILQ_EMPTY(&compnode->items)) { - item = TAILQ_FIRST(&compnode->items); - TAILQ_REMOVE(&compnode->items, item, next); - ec_completed_item_free(item); - } - ec_free(compnode); +void ec_completed_free(struct ec_completed *completed) +{ + struct ec_completed_group *grp; + + if (completed == NULL) + return; + + while (!TAILQ_EMPTY(&completed->groups)) { + grp = TAILQ_FIRST(&completed->groups); + TAILQ_REMOVE(&completed->groups, grp, next); + ec_completed_group_free(grp); } ec_keyval_free(completed->attrs); ec_free(completed); @@ -444,7 +453,7 @@ void ec_completed_free(struct ec_completed *completed) void ec_completed_dump(FILE *out, const struct ec_completed *completed) { - struct ec_completed_node *compnode; + struct ec_completed_group *grp; struct ec_completed_item *item; if (completed == NULL || completed->count == 0) { @@ -455,15 +464,15 @@ void ec_completed_dump(FILE *out, const struct ec_completed *completed) fprintf(out, "completion: count=%u match=%u\n", completed->count, completed->count_match); - TAILQ_FOREACH(compnode, &completed->nodes, next) { + TAILQ_FOREACH(grp, &completed->groups, next) { fprintf(out, "node=%p, node_type=%s\n", - compnode->node, compnode->node->type->name); - TAILQ_FOREACH(item, &compnode->items, next) { + grp->node, grp->node->type->name); + TAILQ_FOREACH(item, &grp->items, next) { const char *typestr; switch (item->type) { - case EC_NO_MATCH: typestr = "no-match"; break; - case EC_MATCH: typestr = "match"; break; + case EC_COMP_UNKNOWN: typestr = "no-match"; break; + case EC_COMP_FULL: typestr = "match"; break; case EC_PARTIAL_MATCH: typestr = "partial-match"; break; default: typestr = "unknown"; break; } @@ -483,9 +492,9 @@ unsigned int ec_completed_count( if (completed == NULL) return count; - if (type & EC_MATCH) + if (type & EC_COMP_FULL) count += completed->count_match; - if (type & EC_NO_MATCH) + if (type & EC_COMP_UNKNOWN) count += (completed->count - completed->count_match); //XXX return count; @@ -513,7 +522,7 @@ const struct ec_completed_item *ec_completed_iter_next( struct ec_completed_iter *iter) { const struct ec_completed *completed = iter->completed; - const struct ec_completed_node *cur_node; + const struct ec_completed_group *cur_node; const struct ec_completed_item *cur_match; if (completed == NULL) @@ -524,7 +533,7 @@ const struct ec_completed_item *ec_completed_iter_next( /* first call */ if (cur_node == NULL) { - TAILQ_FOREACH(cur_node, &completed->nodes, next) { + TAILQ_FOREACH(cur_node, &completed->groups, next) { TAILQ_FOREACH(cur_match, &cur_node->items, next) { if (cur_match != NULL && cur_match->type & iter->type) diff --git a/lib/ecoli_completed.h b/lib/ecoli_completed.h index 4054a1a..c054994 100644 --- a/lib/ecoli_completed.h +++ b/lib/ecoli_completed.h @@ -44,8 +44,8 @@ struct ec_node; enum ec_completed_type { - EC_NO_MATCH, - EC_MATCH, + EC_COMP_UNKNOWN, + EC_COMP_FULL, EC_PARTIAL_MATCH, }; @@ -53,18 +53,21 @@ struct ec_completed_item; TAILQ_HEAD(ec_completed_item_list, ec_completed_item); -struct ec_completed_node { - TAILQ_ENTRY(ec_completed_node) next; +struct ec_completed_group { + TAILQ_ENTRY(ec_completed_group) next; const struct ec_node *node; struct ec_completed_item_list items; + struct ec_parsed *state; }; -TAILQ_HEAD(ec_completed_node_list, ec_completed_node); +TAILQ_HEAD(ec_completed_group_list, ec_completed_group); struct ec_completed { unsigned count; unsigned count_match; - struct ec_completed_node_list nodes; + struct ec_parsed *cur_state; + struct ec_completed_group *cur_group; + struct ec_completed_group_list groups; struct ec_keyval *attrs; // XXX per node instead? }; @@ -80,7 +83,6 @@ struct ec_completed *ec_node_complete_strvec(struct ec_node *node, /* internal: used by nodes */ int ec_node_complete_child(struct ec_node *node, struct ec_completed *completed, - struct ec_parsed *parsed_state, const struct ec_strvec *strvec); /** @@ -106,13 +108,15 @@ void ec_completed_dump(FILE *out, const struct ec_completed *completed); +struct ec_parsed *ec_completed_cur_parse_state(struct ec_completed *completed); + /** * Create a completion item. * * */ struct ec_completed_item * -ec_completed_item(struct ec_parsed *state, const struct ec_node *node); +ec_completed_item(const struct ec_node *node); /** * Set type and value of a completion item. @@ -146,6 +150,14 @@ ec_completed_item_get_str(const struct ec_completed_item *item); const char * ec_completed_item_get_display(const struct ec_completed_item *item); +/** + * Get the group of a completion item. + * + * + */ +const struct ec_completed_group * +ec_completed_item_get_grp(const struct ec_completed_item *item); + /** * Get the type of a completion item. * @@ -185,7 +197,6 @@ int ec_completed_item_set_display(struct ec_completed_item *item, int ec_node_default_complete(const struct ec_node *gen_node, struct ec_completed *completed, - struct ec_parsed *state, const struct ec_strvec *strvec); /** @@ -205,7 +216,7 @@ unsigned int ec_completed_count( struct ec_completed_iter { enum ec_completed_type type; const struct ec_completed *completed; - const struct ec_completed_node *cur_node; + const struct ec_completed_group *cur_node; const struct ec_completed_item *cur_match; }; diff --git a/lib/ecoli_node.h b/lib/ecoli_node.h index 11e9936..8fe2d76 100644 --- a/lib/ecoli_node.h +++ b/lib/ecoli_node.h @@ -96,7 +96,6 @@ typedef int (*ec_node_parse_t)(const struct ec_node *node, const struct ec_strvec *strvec); typedef int (*ec_node_complete_t)(const struct ec_node *node, struct ec_completed *completed_state, - struct ec_parsed *parsed_state, const struct ec_strvec *strvec); typedef size_t (*ec_node_get_max_parse_len_t)(const struct ec_node *node); typedef const char * (*ec_node_desc_t)(const struct ec_node *); @@ -108,8 +107,8 @@ typedef void (*ec_node_free_priv_t)(struct ec_node *); */ struct ec_node_type { TAILQ_ENTRY(ec_node_type) next; /**< Next in list. */ - const char *name; /**< Node type name. */ - ec_node_build_t build; /* (re)build the node, called by generic parse */ + const char *name; /**< Node type name. */ + ec_node_build_t build; /**< (Re)build the node */ ec_node_parse_t parse; ec_node_complete_t complete; ec_node_get_max_parse_len_t get_max_parse_len; diff --git a/lib/ecoli_node_cmd.c b/lib/ecoli_node_cmd.c index 3068fc0..b698f75 100644 --- a/lib/ecoli_node_cmd.c +++ b/lib/ecoli_node_cmd.c @@ -260,12 +260,11 @@ ec_node_cmd_parse(const struct ec_node *gen_node, struct ec_parsed *state, static int ec_node_cmd_complete(const struct ec_node *gen_node, struct ec_completed *completed, - struct ec_parsed *parsed, const struct ec_strvec *strvec) { struct ec_node_cmd *node = (struct ec_node_cmd *)gen_node; - return ec_node_complete_child(node->cmd, completed, parsed, strvec); + return ec_node_complete_child(node->cmd, completed, strvec); } static void ec_node_cmd_free_priv(struct ec_node *gen_node) diff --git a/lib/ecoli_node_expr.c b/lib/ecoli_node_expr.c index 58d4969..129163e 100644 --- a/lib/ecoli_node_expr.c +++ b/lib/ecoli_node_expr.c @@ -80,12 +80,11 @@ static int ec_node_expr_parse(const struct ec_node *gen_node, static int ec_node_expr_complete(const struct ec_node *gen_node, struct ec_completed *completed, - struct ec_parsed *parsed, const struct ec_strvec *strvec) { struct ec_node_expr *node = (struct ec_node_expr *)gen_node; - return ec_node_complete_child(node->child, completed, parsed, strvec); + return ec_node_complete_child(node->child, completed, strvec); } static void ec_node_expr_free_priv(struct ec_node *gen_node) diff --git a/lib/ecoli_node_file.c b/lib/ecoli_node_file.c index 0a78cba..951c494 100644 --- a/lib/ecoli_node_file.c +++ b/lib/ecoli_node_file.c @@ -116,7 +116,6 @@ static int split_path(const char *path, char **dname_p, char **bname_p) static int ec_node_file_complete(const struct ec_node *gen_node, struct ec_completed *completed, - struct ec_parsed *state, const struct ec_strvec *strvec) { struct ec_completed_item *item = NULL; @@ -200,7 +199,7 @@ ec_node_file_complete(const struct ec_node *gen_node, is_dir = 0; } - item = ec_completed_item(state, gen_node); + item = ec_completed_item(gen_node); if (item == NULL) { ret = -ENOMEM; goto out; @@ -230,7 +229,7 @@ ec_node_file_complete(const struct ec_node *gen_node, ret = -errno; goto out; } - ret = ec_completed_item_set(item, EC_MATCH, + ret = ec_completed_item_set(item, EC_COMP_FULL, comp_str); if (ret < 0) goto out; diff --git a/lib/ecoli_node_many.c b/lib/ecoli_node_many.c index cc5f738..8395bd1 100644 --- a/lib/ecoli_node_many.c +++ b/lib/ecoli_node_many.c @@ -106,15 +106,15 @@ fail: static int __ec_node_many_complete(struct ec_node_many *node, unsigned int max, struct ec_completed *completed, - struct ec_parsed *parsed, const struct ec_strvec *strvec) { + struct ec_parsed *parsed = ec_completed_cur_parse_state(completed); struct ec_strvec *childvec = NULL; unsigned int i; int ret; /* first, try to complete with the child node */ - ret = ec_node_complete_child(node->child, completed, parsed, strvec); + ret = ec_node_complete_child(node->child, completed, strvec); if (ret < 0) goto fail; @@ -152,8 +152,7 @@ __ec_node_many_complete(struct ec_node_many *node, unsigned int max, goto fail; } - ret = __ec_node_many_complete(node, max, completed, - parsed, childvec); + ret = __ec_node_many_complete(node, max, completed, childvec); ec_parsed_del_last_child(parsed); ec_strvec_free(childvec); childvec = NULL; @@ -172,13 +171,12 @@ fail: static int ec_node_many_complete(const struct ec_node *gen_node, struct ec_completed *completed, - struct ec_parsed *parsed, const struct ec_strvec *strvec) { struct ec_node_many *node = (struct ec_node_many *)gen_node; return __ec_node_many_complete(node, node->max, completed, - parsed, strvec); + strvec); } static void ec_node_many_free_priv(struct ec_node *gen_node) diff --git a/lib/ecoli_node_once.c b/lib/ecoli_node_once.c index 0df4bcd..2020088 100644 --- a/lib/ecoli_node_once.c +++ b/lib/ecoli_node_once.c @@ -90,10 +90,10 @@ ec_node_once_parse(const struct ec_node *gen_node, static int ec_node_once_complete(const struct ec_node *gen_node, struct ec_completed *completed, - struct ec_parsed *parsed, const struct ec_strvec *strvec) { struct ec_node_once *node = (struct ec_node_once *)gen_node; + struct ec_parsed *parsed = ec_completed_cur_parse_state(completed); unsigned int count; int ret; @@ -104,7 +104,7 @@ ec_node_once_complete(const struct ec_node *gen_node, if (count > 0) return 0; - ret = ec_node_complete_child(node->child, completed, parsed, strvec); + ret = ec_node_complete_child(node->child, completed, strvec); if (ret < 0) return ret; diff --git a/lib/ecoli_node_option.c b/lib/ecoli_node_option.c index ab4f9f3..3f79754 100644 --- a/lib/ecoli_node_option.c +++ b/lib/ecoli_node_option.c @@ -69,12 +69,11 @@ ec_node_option_parse(const struct ec_node *gen_node, static int ec_node_option_complete(const struct ec_node *gen_node, struct ec_completed *completed, - struct ec_parsed *parsed, const struct ec_strvec *strvec) { struct ec_node_option *node = (struct ec_node_option *)gen_node; - return ec_node_complete_child(node->child, completed, parsed, strvec); + return ec_node_complete_child(node->child, completed, strvec); } static void ec_node_option_free_priv(struct ec_node *gen_node) diff --git a/lib/ecoli_node_or.c b/lib/ecoli_node_or.c index 963f970..7e6b49e 100644 --- a/lib/ecoli_node_or.c +++ b/lib/ecoli_node_or.c @@ -72,7 +72,6 @@ ec_node_or_parse(const struct ec_node *gen_node, static int ec_node_or_complete(const struct ec_node *gen_node, struct ec_completed *completed, - struct ec_parsed *parsed, const struct ec_strvec *strvec) { struct ec_node_or *node = (struct ec_node_or *)gen_node; @@ -81,7 +80,7 @@ ec_node_or_complete(const struct ec_node *gen_node, for (n = 0; n < node->len; n++) { ret = ec_node_complete_child(node->table[n], - completed, parsed, strvec); + completed, strvec); if (ret < 0) return ret; } diff --git a/lib/ecoli_node_seq.c b/lib/ecoli_node_seq.c index 2b33503..6025fd7 100644 --- a/lib/ecoli_node_seq.c +++ b/lib/ecoli_node_seq.c @@ -98,9 +98,9 @@ fail: static int __ec_node_seq_complete(struct ec_node **table, size_t table_len, struct ec_completed *completed, - struct ec_parsed *parsed, const struct ec_strvec *strvec) { + struct ec_parsed *parsed = ec_completed_cur_parse_state(completed); struct ec_strvec *childvec = NULL; unsigned int i; int ret; @@ -120,7 +120,7 @@ __ec_node_seq_complete(struct ec_node **table, size_t table_len, */ /* first, try to complete with the first node of the table */ - ret = ec_node_complete_child(table[0], completed, parsed, strvec); + ret = ec_node_complete_child(table[0], completed, strvec); if (ret < 0) goto fail; @@ -152,7 +152,7 @@ __ec_node_seq_complete(struct ec_node **table, size_t table_len, ret = __ec_node_seq_complete(&table[1], table_len - 1, - completed, parsed, childvec); + completed, childvec); ec_parsed_del_last_child(parsed); ec_strvec_free(childvec); childvec = NULL; @@ -171,13 +171,12 @@ fail: static int ec_node_seq_complete(const struct ec_node *gen_node, struct ec_completed *completed, - struct ec_parsed *parsed, const struct ec_strvec *strvec) { struct ec_node_seq *node = (struct ec_node_seq *)gen_node; return __ec_node_seq_complete(node->table, node->len, completed, - parsed, strvec); + strvec); } static size_t ec_node_seq_get_max_parse_len(const struct ec_node *gen_node) @@ -322,6 +321,8 @@ static int ec_node_seq_testcase(void) ret |= EC_TEST_CHECK_COMPLETE(node, "", EC_NODE_ENDLIST, "foo", EC_NODE_ENDLIST); + ec_node_free(node); + return 0; ret |= EC_TEST_CHECK_COMPLETE(node, "f", EC_NODE_ENDLIST, "foo", EC_NODE_ENDLIST); diff --git a/lib/ecoli_node_sh_lex.c b/lib/ecoli_node_sh_lex.c index 94d0d73..1a5e4ab 100644 --- a/lib/ecoli_node_sh_lex.c +++ b/lib/ecoli_node_sh_lex.c @@ -280,7 +280,6 @@ ec_node_sh_lex_parse(const struct ec_node *gen_node, static int ec_node_sh_lex_complete(const struct ec_node *gen_node, struct ec_completed *completed, - struct ec_parsed *parsed, const struct ec_strvec *strvec) { struct ec_node_sh_lex *node = (struct ec_node_sh_lex *)gen_node; @@ -301,7 +300,7 @@ ec_node_sh_lex_complete(const struct ec_node *gen_node, // XXX: complete should add the quotes for !EC_PARTIAL // XXX: if no quotes, replace " " by "\ " - ret = ec_node_complete_child(node->child, completed, parsed, new_vec); + ret = ec_node_complete_child(node->child, completed, new_vec); if (ret < 0) goto fail; diff --git a/lib/ecoli_node_str.c b/lib/ecoli_node_str.c index 483f63c..6c47980 100644 --- a/lib/ecoli_node_str.c +++ b/lib/ecoli_node_str.c @@ -70,7 +70,6 @@ ec_node_str_parse(const struct ec_node *gen_node, static int ec_node_str_complete(const struct ec_node *gen_node, struct ec_completed *completed, - struct ec_parsed *parsed, const struct ec_strvec *strvec) { struct ec_completed_item *item = NULL; @@ -79,8 +78,6 @@ ec_node_str_complete(const struct ec_node *gen_node, size_t n = 0; int ret; - (void)parsed; - if (ec_strvec_len(strvec) != 1) return 0; @@ -94,10 +91,10 @@ ec_node_str_complete(const struct ec_node *gen_node, if (str[n] != '\0') return 0; // XXX add a no_match instead? - item = ec_completed_item(parsed, gen_node); + item = ec_completed_item(gen_node); if (item == NULL) return -ENOMEM; - ret = ec_completed_item_set(item, EC_MATCH, node->string); + ret = ec_completed_item_set(item, EC_COMP_FULL, node->string); if (ret < 0) { ec_completed_item_free(item); return ret; diff --git a/lib/ecoli_node_subset.c b/lib/ecoli_node_subset.c index 18de0cb..b56bf81 100644 --- a/lib/ecoli_node_subset.c +++ b/lib/ecoli_node_subset.c @@ -179,9 +179,9 @@ ec_node_subset_parse(const struct ec_node *gen_node, static int __ec_node_subset_complete(struct ec_node **table, size_t table_len, struct ec_completed *completed, - struct ec_parsed *parsed, const struct ec_strvec *strvec) { + struct ec_parsed *parsed = ec_completed_cur_parse_state(completed); struct ec_strvec *childvec = NULL; struct ec_node *save; size_t i, len; @@ -202,7 +202,7 @@ __ec_node_subset_complete(struct ec_node **table, size_t table_len, continue; ret = ec_node_complete_child(table[i], - completed, parsed, strvec); + completed, strvec); if (ret < 0) goto fail; } @@ -231,7 +231,7 @@ __ec_node_subset_complete(struct ec_node **table, size_t table_len, save = table[i]; table[i] = NULL; ret = __ec_node_subset_complete(table, table_len, - completed, parsed, childvec); + completed, childvec); table[i] = save; ec_strvec_free(childvec); childvec = NULL; @@ -250,13 +250,12 @@ fail: static int ec_node_subset_complete(const struct ec_node *gen_node, struct ec_completed *completed, - struct ec_parsed *parsed, const struct ec_strvec *strvec) { struct ec_node_subset *node = (struct ec_node_subset *)gen_node; return __ec_node_subset_complete(node->table, node->len, completed, - parsed, strvec); + strvec); } static void ec_node_subset_free_priv(struct ec_node *gen_node) diff --git a/lib/ecoli_node_weakref.c b/lib/ecoli_node_weakref.c index eacec4c..516b0bb 100644 --- a/lib/ecoli_node_weakref.c +++ b/lib/ecoli_node_weakref.c @@ -63,12 +63,11 @@ ec_node_weakref_parse(const struct ec_node *gen_node, static int ec_node_weakref_complete(const struct ec_node *gen_node, struct ec_completed *completed, - struct ec_parsed *parsed, const struct ec_strvec *strvec) { struct ec_node_weakref *node = (struct ec_node_weakref *)gen_node; - return ec_node_complete_child(node->child, completed, parsed, strvec); + return ec_node_complete_child(node->child, completed, strvec); } static struct ec_node_type ec_node_weakref_type = { diff --git a/lib/ecoli_parsed.c b/lib/ecoli_parsed.c index d338953..3fb9db2 100644 --- a/lib/ecoli_parsed.c +++ b/lib/ecoli_parsed.c @@ -32,6 +32,7 @@ #include #include +#include #include #include #include @@ -50,15 +51,13 @@ struct ec_parsed { struct ec_keyval *attrs; }; -int ec_node_parse_child(struct ec_node *node, struct ec_parsed *state, - const struct ec_strvec *strvec) +static int __ec_node_parse_child(struct ec_node *node, struct ec_parsed *state, + bool is_root, const struct ec_strvec *strvec) { struct ec_strvec *match_strvec; struct ec_parsed *child; int ret; - assert(state != NULL); - /* build the node if required */ if (node->type->build != NULL) { if ((node->flags & EC_NODE_F_BUILT) == 0) { @@ -72,20 +71,26 @@ int ec_node_parse_child(struct ec_node *node, struct ec_parsed *state, if (node->type->parse == NULL) return -ENOTSUP; - child = ec_parsed(); - if (child == NULL) - return -ENOMEM; + if (!is_root) { + child = ec_parsed(); + if (child == NULL) + return -ENOMEM; + ec_parsed_add_child(state, child); + } else { + child = state; + } ec_parsed_set_node(child, node); - ec_parsed_add_child(state, child); ret = node->type->parse(node, child, strvec); - if (ret < 0) + if (ret < 0) // XXX should we free state, child? return ret; if (ret == EC_PARSED_NOMATCH) { - ec_parsed_del_child(state, child); - assert(TAILQ_EMPTY(&child->children)); - ec_parsed_free(child); + if (!is_root) { + ec_parsed_del_child(state, child); + assert(TAILQ_EMPTY(&child->children)); + ec_parsed_free(child); + } return ret; } @@ -98,30 +103,28 @@ int ec_node_parse_child(struct ec_node *node, struct ec_parsed *state, return ret; } +int ec_node_parse_child(struct ec_node *node, struct ec_parsed *state, + const struct ec_strvec *strvec) +{ + assert(state != NULL); + return __ec_node_parse_child(node, state, false, strvec); +} + struct ec_parsed *ec_node_parse_strvec(struct ec_node *node, const struct ec_strvec *strvec) { struct ec_parsed *parsed = ec_parsed(); - struct ec_parsed *child_parsed; int ret; if (parsed == NULL) return NULL; - ret = ec_node_parse_child(node, parsed, strvec); + ret = __ec_node_parse_child(node, parsed, true, strvec); if (ret < 0) { ec_parsed_free(parsed); return NULL; } - if (ret != EC_PARSED_NOMATCH) { - /* remove dummy root node */ - child_parsed = ec_parsed_get_last_child(parsed); - ec_parsed_del_child(parsed, child_parsed); - ec_parsed_free(parsed); - parsed = child_parsed; - } - return parsed; } @@ -175,33 +178,39 @@ struct ec_parsed *ec_parsed(void) return NULL; } -struct ec_parsed *ec_parsed_dup(const struct ec_parsed *parsed) +static struct ec_parsed * +__ec_parsed_dup(const struct ec_parsed *root, const struct ec_parsed *ref, + struct ec_parsed **new_ref) { struct ec_parsed *dup = NULL; struct ec_parsed *child, *dup_child; struct ec_keyval *attrs = NULL; - if (parsed == NULL) + if (root == NULL) return NULL; dup = ec_parsed(); if (dup == NULL) return NULL; - attrs = ec_keyval_dup(parsed->attrs); + if (root == ref) + *new_ref = dup; + + attrs = ec_keyval_dup(root->attrs); if (attrs == NULL) goto fail; ec_keyval_free(dup->attrs); dup->attrs = attrs; + dup->node = root->node; - if (parsed->strvec != NULL) { - dup->strvec = ec_strvec_dup(parsed->strvec); + if (root->strvec != NULL) { + dup->strvec = ec_strvec_dup(root->strvec); if (dup->strvec == NULL) goto fail; } - TAILQ_FOREACH(child, &parsed->children, next) { - dup_child = ec_parsed_dup(child); + TAILQ_FOREACH(child, &root->children, next) { + dup_child = __ec_parsed_dup(child, ref, new_ref); if (dup_child == NULL) goto fail; ec_parsed_add_child(dup, dup_child); @@ -214,6 +223,19 @@ fail: return NULL; } +struct ec_parsed *ec_parsed_dup(struct ec_parsed *parsed) //XXX const +{ + struct ec_parsed *root, *dup_root, *dup = NULL; + + root = ec_parsed_get_root(parsed); + dup_root = __ec_parsed_dup(root, parsed, &dup); + if (dup_root == NULL) + return NULL; + assert(dup != NULL); + + return dup; +} + void ec_parsed_free_children(struct ec_parsed *parsed) { struct ec_parsed *child; @@ -233,6 +255,10 @@ void ec_parsed_free(struct ec_parsed *parsed) if (parsed == NULL) return; + // assert(parsed->parent == NULL); XXX + // or + // parsed = ec_parsed_get_root(parsed); + ec_parsed_free_children(parsed); ec_strvec_free(parsed->strvec); ec_keyval_free(parsed->attrs); @@ -277,7 +303,12 @@ void ec_parsed_dump(FILE *out, const struct ec_parsed *parsed) fprintf(out, "parsed is NULL, error in parse\n"); return; } - if (!ec_parsed_matches(parsed)) { + + /* only exist if it does not match (strvec == NULL) and if it + * does not have children: an incomplete parse, like those + * generated by complete() don't match but have children that + * may match. */ + if (!ec_parsed_matches(parsed) && TAILQ_EMPTY(&parsed->children)) { fprintf(out, "no match\n"); return; } @@ -292,6 +323,7 @@ void ec_parsed_add_child(struct ec_parsed *parsed, child->parent = parsed; } +// XXX we can remove the first arg ? parsed == child->parent ? void ec_parsed_del_child(struct ec_parsed *parsed, // XXX rename del in unlink? struct ec_parsed *child) { @@ -403,7 +435,7 @@ size_t ec_parsed_matches(const struct ec_parsed *parsed) if (parsed == NULL) return 0; - if (parsed->node == NULL && TAILQ_EMPTY(&parsed->children)) // XXX both needed? + if (parsed->strvec == NULL) return 0; return 1; diff --git a/lib/ecoli_parsed.h b/lib/ecoli_parsed.h index afb765e..33da8fc 100644 --- a/lib/ecoli_parsed.h +++ b/lib/ecoli_parsed.h @@ -71,7 +71,7 @@ void ec_parsed_free_children(struct ec_parsed *parsed); * * */ -struct ec_parsed *ec_parsed_dup(const struct ec_parsed *parsed); +struct ec_parsed *ec_parsed_dup(struct ec_parsed *parsed); /** * diff --git a/lib/ecoli_test.c b/lib/ecoli_test.c index 80e6a9f..b9b515b 100644 --- a/lib/ecoli_test.c +++ b/lib/ecoli_test.c @@ -147,7 +147,7 @@ int ec_test_check_complete(struct ec_node *tk, ...) count++; /* only check matching completions */ - iter = ec_completed_iter(c, EC_MATCH); + iter = ec_completed_iter(c, EC_COMP_FULL); while ((item = ec_completed_iter_next(iter)) != NULL) { const char *str = ec_completed_item_get_str(item); if (str != NULL && strcmp(str, s) == 0) @@ -163,10 +163,10 @@ int ec_test_check_complete(struct ec_node *tk, ...) } /* check if we have more completions (or less) than expected */ - if (count != ec_completed_count(c, EC_MATCH)) { + if (count != ec_completed_count(c, EC_COMP_FULL)) { EC_LOG(EC_LOG_ERR, "nb_completion (%d) does not match (%d)\n", - count, ec_completed_count(c, EC_MATCH)); + count, ec_completed_count(c, EC_COMP_FULL)); ec_completed_dump(stdout, c); ret = -1; } else diff --git a/lib/main-readline.c b/lib/main-readline.c index da447d8..141c8cd 100644 --- a/lib/main-readline.c +++ b/lib/main-readline.c @@ -83,7 +83,7 @@ static char *my_completion_entry(const char *s, int state) return NULL; ec_completed_iter_free(iter); - iter = ec_completed_iter(c, EC_MATCH | EC_PARTIAL_MATCH); + iter = ec_completed_iter(c, EC_COMP_FULL | EC_PARTIAL_MATCH); if (iter == NULL) return NULL; } @@ -98,7 +98,7 @@ static char *my_completion_entry(const char *s, int state) /* don't add the trailing space for partial completions */ if (state == 0) { item_type = ec_completed_item_get_type(item); - if (item_type == EC_MATCH) + if (item_type == EC_COMP_FULL) rl_completion_suppress_append = 0; else rl_completion_suppress_append = 1; @@ -128,6 +128,8 @@ static char **my_attempted_completion(const char *text, int start, int end) /* this function builds the help string */ static char *get_node_help(const struct ec_completed_item *item) { + const struct ec_completed_group *grp; + struct ec_parsed *state; // XXX keep const with macro const struct ec_node *node; char *help = NULL; const char *node_help = NULL; @@ -135,10 +137,12 @@ static char *get_node_help(const struct ec_completed_item *item) // size_t i; (void)item; -#if 0 //XXX - /* Retrieve the most precise help for this node. */ - for (i = 0; i < item->pathlen; i++) { - node = item->path[i]; +#if 1 + grp = ec_completed_item_get_grp(item); + state = grp->state; + for (state = grp->state; state != NULL; + state = ec_parsed_get_parent(state)) { + node = ec_parsed_get_node(state); if (node_help == NULL) node_help = ec_keyval_get(ec_node_attrs(node), "help"); if (node_desc == NULL) @@ -164,8 +168,8 @@ static char *get_node_help(const struct ec_completed_item *item) static int show_help(int ignore, int invoking_key) { struct ec_completed_iter *iter; + const struct ec_completed_group *grp, *prev_grp = NULL; const struct ec_completed_item *item; - const struct ec_node *prev_node = NULL; struct ec_completed *c; struct ec_parsed *p; char *line = NULL; @@ -199,7 +203,8 @@ static int show_help(int ignore, int invoking_key) /* let's display one contextual help per node */ count = 0; - iter = ec_completed_iter(c, EC_NO_MATCH | EC_MATCH | EC_PARTIAL_MATCH); + iter = ec_completed_iter(c, + EC_COMP_UNKNOWN | EC_COMP_FULL | EC_PARTIAL_MATCH); if (iter == NULL) goto fail; @@ -211,14 +216,15 @@ static int show_help(int ignore, int invoking_key) helps[1] = ""; while ((item = ec_completed_iter_next(iter)) != NULL) { - const struct ec_node *node; char **tmp; - /* keep one help per node, skip other items */ - node = ec_completed_item_get_node(item); - if (node == prev_node) + /* keep one help per group, skip other items */ + grp = ec_completed_item_get_grp(item); + if (grp == prev_grp) continue; + prev_grp = grp; + tmp = realloc(helps, (count + match + 2) * sizeof(char *)); if (tmp == NULL) goto fail; diff --git a/lib/todo.txt b/lib/todo.txt index 58b7996..734de6b 100644 --- a/lib/todo.txt +++ b/lib/todo.txt @@ -82,6 +82,8 @@ examples - example with libedit - mini script language - configuration file +- mini shell: cd, ls, cat, stat +- mini network console based on ip doc === -- 2.20.1