X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=lib%2Fecoli_completed.c;h=25ae6cb96870e48fb2147f1790d7b5782ca816a4;hb=ef05ddd2034f31839d5f0be21e372f8313e5d9eb;hp=64bb70d593942e75213ddde124e7528444e11809;hpb=e0aa24099c9c73831684689da1aa3c05e340e775;p=protos%2Flibecoli.git diff --git a/lib/ecoli_completed.c b/lib/ecoli_completed.c index 64bb70d..25ae6cb 100644 --- a/lib/ecoli_completed.c +++ b/lib/ecoli_completed.c @@ -32,6 +32,7 @@ #include #include +#include #include #include #include @@ -39,28 +40,49 @@ #include #include -struct ec_completed *ec_completed(void) +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 *start; /* the initial token */ + char *full; /* the full token after completion */ + char *completion; /* chars that are added, NULL if not applicable */ + char *display; /* what should be displayed by help/completers */ + struct ec_keyval *attrs; +}; + +struct ec_completed *ec_completed(struct ec_parsed *state) { struct ec_completed *completed = NULL; completed = ec_calloc(1, sizeof(*completed)); if (completed == NULL) - return NULL; + goto fail; + + TAILQ_INIT(&completed->groups); - TAILQ_INIT(&completed->nodes); + completed->cur_state = state; return completed; + + fail: + ec_free(completed); + + return NULL; +} + +struct ec_parsed *ec_completed_get_state(struct ec_completed *completed) +{ + return completed->cur_state; } -/* XXX on error, states are not freed ? - * they can be left in a bad state and should not be reused */ 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 */ @@ -76,13 +98,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; - child_state->node = node; - ec_parsed_add_child(parsed_state, child_state); - ret = node->type->complete(node, completed, child_state, strvec); + if (cur_state != NULL) + ec_parsed_add_child(cur_state, child_state); + ec_parsed_set_node(child_state, node); + completed->cur_state = child_state; + cur_group = completed->cur_group; + completed->cur_group = NULL; + + /* fill the completed struct with items */ + 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; + if (ret < 0) return ret; @@ -91,42 +131,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(TAILQ_EMPTY(&child_state->children)); - 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(); + completed = ec_completed(NULL); 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; } @@ -157,240 +183,347 @@ 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->attrs = ec_keyval(); + if (grp->attrs == NULL) + goto fail; + + 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_keyval_free(grp->attrs); + } + ec_free(grp); + return NULL; } -struct ec_completed_item * -ec_completed_item(struct ec_parsed *state, const struct ec_node *node) +static struct ec_completed_item * +ec_completed_item(const struct ec_node *node, enum ec_completed_type type, + const char *start, const char *full) { struct ec_completed_item *item = NULL; - struct ec_parsed *p; - size_t len; + struct ec_keyval *attrs = NULL; + char *comp_cp = NULL, *start_cp = NULL; + char *full_cp = NULL, *display_cp = NULL; + + if (type == EC_COMP_UNKNOWN && full != NULL) { + errno = EINVAL; + return NULL; + } + if (type != EC_COMP_UNKNOWN && full == NULL) { + errno = EINVAL; + return NULL; + } item = ec_calloc(1, sizeof(*item)); if (item == NULL) - return 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) + attrs = ec_keyval(); + if (attrs == 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] = p->node; - item->type = EC_NO_MATCH; + if (start != NULL) { + start_cp = ec_strdup(start); + if (start_cp == NULL) + goto fail; + + if (ec_str_startswith(full, start)) { + comp_cp = ec_strdup(&full[strlen(start)]); + if (comp_cp == NULL) + goto fail; + } + } + if (full != NULL) { + full_cp = ec_strdup(full); + if (full_cp == NULL) + goto fail; + display_cp = ec_strdup(full); + if (display_cp == NULL) + goto fail; + } + item->node = node; + item->type = type; + item->start = start_cp; + item->full = full_cp; + item->completion = comp_cp; + item->display = display_cp; + item->attrs = attrs; return item; fail: - if (item != NULL) { - ec_free(item->path); - ec_free(item->str); - ec_free(item->display); - } - ec_completed_item_free(item); + ec_keyval_free(item->attrs); + ec_free(comp_cp); + ec_free(start_cp); + ec_free(full_cp); + ec_free(display_cp); + ec_free(item); return NULL; } -int -ec_completed_item_set(struct ec_completed_item *item, - enum ec_completed_type type, const char *str) +int ec_completed_item_set_display(struct ec_completed_item *item, + const char *display) { - char *str_copy = NULL; char *display_copy = NULL; int ret = 0; - if (item == NULL) - return -EINVAL; - if (item->str != NULL) - return -EEXIST; - - switch (type) { - case EC_NO_MATCH: - if (str != NULL) - return -EINVAL; - break; - case EC_MATCH: - case EC_PARTIAL_MATCH: - if (str == NULL) - return -EINVAL; - break; - default: + if (item == NULL || display == NULL || + item->type == EC_COMP_UNKNOWN) return -EINVAL; - } - if (str != NULL) { - ret = -ENOMEM; - str_copy = ec_strdup(str); - if (str_copy == NULL) - goto fail; - display_copy = ec_strdup(str); - if (display_copy == NULL) - goto fail; - } + display_copy = ec_strdup(display); + if (display_copy == NULL) + goto fail; - item->type = type; - item->str = str_copy; + ec_free(item->display); item->display = display_copy; + return 0; fail: - ec_free(str_copy); ec_free(display_copy); return ret; } -int ec_completed_item_set_display(struct ec_completed_item *item, - const char *display) +int +ec_completed_item_set_completion(struct ec_completed_item *item, + const char *completion) { - char *display_copy = NULL; + char *completion_copy = NULL; int ret = 0; - if (item == NULL || display == NULL || - item->type == EC_NO_MATCH || item->str == NULL) + if (item == NULL || completion == NULL || + item->type == EC_COMP_UNKNOWN) return -EINVAL; ret = -ENOMEM; - display_copy = ec_strdup(display); - if (display_copy == NULL) + completion_copy = ec_strdup(completion); + if (completion_copy == NULL) goto fail; - ec_free(item->display); - item->display = display_copy; + ec_free(item->completion); + item->completion = completion_copy; return 0; fail: - ec_free(display_copy); + ec_free(completion_copy); return ret; - } int +ec_completed_item_set_str(struct ec_completed_item *item, + const char *str) +{ + char *str_copy = NULL; + int ret = 0; + + if (item == NULL || str == NULL || + item->type == EC_COMP_UNKNOWN) + return -EINVAL; + + ret = -ENOMEM; + str_copy = ec_strdup(str); + if (str_copy == NULL) + goto fail; + + ec_free(item->full); + item->full = str_copy; + + return 0; + +fail: + ec_free(str_copy); + return ret; +} + +static 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_PARTIAL_MATCH: + case EC_COMP_FULL: + case EC_COMP_PARTIAL: completed->count_match++; //XXX break; default: 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; } -void ec_completed_item_free(struct ec_completed_item *item) +const char * +ec_completed_item_get_str(const struct ec_completed_item *item) +{ + return item->full; +} + +const char * +ec_completed_item_get_display(const struct ec_completed_item *item) +{ + return item->display; +} + +const char * +ec_completed_item_get_completion(const struct ec_completed_item *item) +{ + return item->completion; +} + +enum ec_completed_type +ec_completed_item_get_type(const struct ec_completed_item *item) +{ + return item->type; +} + +const struct ec_node * +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; +} + +static void +ec_completed_item_free(struct ec_completed_item *item) { if (item == NULL) return; - ec_free(item->str); + ec_free(item->full); + ec_free(item->start); + ec_free(item->completion); ec_free(item->display); - ec_free(item->path); + ec_keyval_free(item->attrs); ec_free(item); } +int ec_completed_add_item(struct ec_completed *completed, + const struct ec_node *node, + struct ec_completed_item **p_item, + enum ec_completed_type type, + const char *start, const char *full) +{ + struct ec_completed_item *item = NULL; + int ret; + + item = ec_completed_item(node, type, start, full); + if (item == NULL) + return -1; + + ret = ec_completed_item_add(completed, item); + if (ret < 0) + goto fail; + + if (p_item != NULL) + *p_item = item; + + return 0; + +fail: + ec_completed_item_free(item); + + return -1; +} + /* default completion function: return a no-match element */ 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; int ret; if (ec_strvec_len(strvec) != 1) return 0; - item = ec_completed_item(parsed_state, gen_node); - if (item == NULL) - return -ENOMEM; - ret = ec_completed_item_set(item, EC_NO_MATCH, NULL); - if (ret < 0) { - ec_completed_item_free(item); - return ret; - } - ret = ec_completed_item_add(completed, item); - if (ret < 0) { - ec_completed_item_free(item); + ret = ec_completed_add_item(completed, gen_node, NULL, + EC_COMP_UNKNOWN, NULL, NULL); + if (ret < 0) return ret; - } 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_keyval_free(grp->attrs); + ec_free(grp); +} + +void ec_completed_free(struct ec_completed *completed) +{ + struct ec_completed_group *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); + 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_free(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) { @@ -401,25 +534,43 @@ 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_PARTIAL_MATCH: typestr = "partial-match"; break; + case EC_COMP_UNKNOWN: typestr = "unknown"; break; + case EC_COMP_FULL: typestr = "full"; break; + case EC_COMP_PARTIAL: typestr = "partial"; break; default: typestr = "unknown"; break; } - fprintf(out, " type=%s str=<%s> disp=<%s>\n", - typestr, item->str, item->display); + fprintf(out, " type=%s str=<%s> comp=<%s> disp=<%s>\n", + typestr, item->full, item->completion, + item->display); } } } +int ec_completed_merge(struct ec_completed *to, + struct ec_completed *from) +{ + struct ec_completed_group *grp; + + while (!TAILQ_EMPTY(&from->groups)) { + grp = TAILQ_FIRST(&from->groups); + TAILQ_REMOVE(&from->groups, grp, next); + TAILQ_INSERT_TAIL(&to->groups, grp, next); + } + to->count += from->count; + to->count_match += from->count_match; + + ec_completed_free(from); + return 0; +} + unsigned int ec_completed_count( const struct ec_completed *completed, enum ec_completed_type type) @@ -429,9 +580,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; @@ -455,12 +606,12 @@ ec_completed_iter(struct ec_completed *completed, return iter; } -const struct ec_completed_item *ec_completed_iter_next( +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_item *cur_match; + struct ec_completed *completed = iter->completed; + struct ec_completed_group *cur_node; + struct ec_completed_item *cur_match; if (completed == NULL) return NULL; @@ -470,7 +621,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)