X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=lib%2Fecoli_completed.c;h=4836803c7ea20e8c158769fa0c31bfe656272efb;hb=ff1f48e335ca77cc97e49ea86b292233731ecb78;hp=18e92edefffe80e075c418e357df2831d0662aaa;hpb=bf091fc25fc602ceb9ec389f341c52bd0bf7d2af;p=protos%2Flibecoli.git diff --git a/lib/ecoli_completed.c b/lib/ecoli_completed.c index 18e92ed..4836803 100644 --- a/lib/ecoli_completed.c +++ b/lib/ecoli_completed.c @@ -39,103 +39,120 @@ #include #include +struct ec_completed_item { + TAILQ_ENTRY(ec_completed_item) next; + enum ec_completed_type type; + const struct ec_node *node; + 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) { struct ec_completed *completed = NULL; completed = ec_calloc(1, sizeof(*completed)); if (completed == NULL) - return NULL; + goto fail; - TAILQ_INIT(&completed->elts); - completed->count_match = 0; + TAILQ_INIT(&completed->nodes); - return completed; -} - -static struct ec_completed_elt * -ec_completed_elt(const struct ec_node *node, const char *add) -{ - struct ec_completed_elt *elt = NULL; + completed->attrs = ec_keyval(); + if (completed->attrs == NULL) + goto fail; - elt = ec_calloc(1, sizeof(*elt)); - if (elt == NULL) - return NULL; + return completed; - elt->node = node; - if (add != NULL) { - elt->add = ec_strdup(add); - if (elt->add == NULL) { - ec_completed_elt_free(elt); - return NULL; - } - } + fail: + if (completed != NULL) + ec_keyval_free(completed->attrs); + ec_free(completed); - return elt; + return NULL; } -struct ec_completed * +/* 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_parsed *state, + struct ec_completed *completed, + struct ec_parsed *parsed_state, const struct ec_strvec *strvec) { - struct ec_completed *completed; - struct ec_parsed *child; + struct ec_parsed *child_state = NULL; int ret; /* build the node if required */ if (node->type->build != NULL) { if ((node->flags & EC_NODE_F_BUILT) == 0) { ret = node->type->build(node); - if (ret < 0) { - errno = -ret; - return NULL; - } + if (ret < 0) + return ret; } } node->flags |= EC_NODE_F_BUILT; - if (node->type->complete == NULL) { - errno = ENOTSUP; - return NULL; - } + if (node->type->complete == NULL) + return -ENOTSUP; - child = ec_parsed(); - if (child == NULL) - return NULL; + child_state = ec_parsed(); + if (child_state == NULL) + return -ENOMEM; + child_state->node = node; + ec_parsed_add_child(parsed_state, child_state); - child->node = node; - ec_parsed_add_child(state, child); - completed = node->type->complete(node, child, strvec); + ret = node->type->complete(node, completed, child_state, strvec); + if (ret < 0) + return ret; #if 0 // XXX dump printf("----------------------------------------------------------\n"); ec_node_dump(stdout, node); ec_strvec_dump(stdout, strvec); ec_completed_dump(stdout, completed); - ec_parsed_dump(stdout, state); + ec_parsed_dump(stdout, parsed_state); #endif - ec_parsed_del_child(state, child); - assert(TAILQ_EMPTY(&child->children)); - ec_parsed_free(child); + ec_parsed_del_child(parsed_state, child_state); + assert(TAILQ_EMPTY(&child_state->children)); + ec_parsed_free(child_state); - return completed; + return 0; } struct ec_completed *ec_node_complete_strvec(struct ec_node *node, const struct ec_strvec *strvec) { - struct ec_parsed *state = ec_parsed(); - struct ec_completed *completed; + struct ec_parsed *parsed_state = NULL; + struct ec_completed *completed = NULL; + int ret; - if (state == NULL) - return NULL; + parsed_state = ec_parsed(); + if (parsed_state == NULL) + goto fail; - completed = ec_node_complete_child(node, state, strvec); - ec_parsed_free(state); + completed = ec_completed(); + if (completed == NULL) + goto fail; + + ret = ec_node_complete_child(node, completed, + parsed_state, 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; } struct ec_completed *ec_node_complete(struct ec_node *node, @@ -164,154 +181,305 @@ struct ec_completed *ec_node_complete(struct ec_node *node, return NULL; } -/* default completion function: return a no-match element */ -struct ec_completed *ec_node_default_complete(const struct ec_node *gen_node, - struct ec_parsed *state, - const struct ec_strvec *strvec) +static struct ec_completed_node * +ec_completed_node(const struct ec_node *node) { - struct ec_completed *completed; - - (void)strvec; - (void)state; + struct ec_completed_node *compnode = NULL; - completed = ec_completed(); - if (completed == NULL) + compnode = ec_calloc(1, sizeof(*compnode)); + if (compnode == NULL) return NULL; - if (ec_strvec_len(strvec) != 1) - return completed; + compnode->node = node; + TAILQ_INIT(&compnode->items); - if (ec_completed_add_elt(completed, gen_node, NULL) < 0) { - ec_completed_free(completed); - return NULL; + return compnode; +} + +struct ec_completed_item * +ec_completed_item(struct ec_parsed *state, 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) + goto fail; + + item->attrs = ec_keyval(); + 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] = p->node; + + item->type = EC_NO_MATCH; + 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); } + ec_free(item); - return completed; + return NULL; +} + +int +ec_completed_item_set(struct ec_completed_item *item, + enum ec_completed_type type, const char *str) +{ + 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: + 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; + } + + item->type = type; + item->str = str_copy; + item->display = display_copy; + return 0; + +fail: + ec_free(str_copy); + ec_free(display_copy); + return ret; } -/* count the number of identical chars at the beginning of 2 strings */ -static size_t strcmp_count(const char *s1, const char *s2) +int ec_completed_item_set_display(struct ec_completed_item *item, + const char *display) { - size_t i = 0; + char *display_copy = NULL; + int ret = 0; + + if (item == NULL || display == NULL || + item->type == EC_NO_MATCH || item->str == NULL) + return -EINVAL; + + ret = -ENOMEM; + display_copy = ec_strdup(display); + if (display_copy == NULL) + goto fail; - while (s1[i] && s2[i] && s1[i] == s2[i]) - i++; + ec_free(item->display); + item->display = display_copy; - return i; + return 0; + +fail: + ec_free(display_copy); + return ret; } -static int __ec_completed_add_elt(struct ec_completed *completed, - struct ec_completed_elt *elt) +int +ec_completed_item_add(struct ec_completed *completed, + struct ec_completed_item *item) { - size_t n; + struct ec_completed_node *compnode = NULL; + + if (completed == NULL || item == NULL || item->node == NULL) + return -EINVAL; + + switch (item->type) { + case EC_NO_MATCH: + break; + case EC_MATCH: + case EC_PARTIAL_MATCH: + completed->count_match++; //XXX + break; + default: + return -EINVAL; + } - TAILQ_INSERT_TAIL(&completed->elts, elt, next); - completed->count++; - if (elt->add != NULL) { - completed->count_match++; - if (completed->smallest_start == NULL) { - completed->smallest_start = ec_strdup(elt->add); - } else { - n = strcmp_count(elt->add, - completed->smallest_start); - completed->smallest_start[n] = '\0'; - } + /* 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) + return -ENOMEM; + TAILQ_INSERT_TAIL(&completed->nodes, compnode, next); } + completed->count++; + TAILQ_INSERT_TAIL(&compnode->items, item, next); + return 0; } -int ec_completed_add_elt(struct ec_completed *completed, - const struct ec_node *node, const char *add) +const char * +ec_completed_item_get_str(const struct ec_completed_item *item) { - struct ec_completed_elt *elt; + return item->str; +} - elt = ec_completed_elt(node, add); - if (elt == NULL) - return -ENOMEM; +const char * +ec_completed_item_get_display(const struct ec_completed_item *item) +{ + return item->display; +} - return __ec_completed_add_elt(completed, elt); +enum ec_completed_type +ec_completed_item_get_type(const struct ec_completed_item *item) +{ + return item->type; } -void ec_completed_elt_free(struct ec_completed_elt *elt) +void ec_completed_item_free(struct ec_completed_item *item) { - ec_free(elt->add); - ec_free(elt); + if (item == NULL) + return; + + ec_free(item->str); + ec_free(item->display); + ec_free(item->path); + ec_keyval_free(item->attrs); + ec_free(item); } -void ec_completed_merge(struct ec_completed *completed1, - struct ec_completed *completed2) +/* 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_elt *elt; + struct ec_completed_item *item = NULL; + int ret; - assert(completed1 != NULL); - assert(completed2 != NULL); + if (ec_strvec_len(strvec) != 1) + return 0; - while (!TAILQ_EMPTY(&completed2->elts)) { - elt = TAILQ_FIRST(&completed2->elts); - TAILQ_REMOVE(&completed2->elts, elt, next); - __ec_completed_add_elt(completed1, elt); + 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); + return ret; } - ec_completed_free(completed2); + return 0; } void ec_completed_free(struct ec_completed *completed) { - struct ec_completed_elt *elt; + struct ec_completed_node *compnode; + struct ec_completed_item *item; if (completed == NULL) return; - while (!TAILQ_EMPTY(&completed->elts)) { - elt = TAILQ_FIRST(&completed->elts); - TAILQ_REMOVE(&completed->elts, elt, next); - ec_completed_elt_free(elt); + while (!TAILQ_EMPTY(&completed->nodes)) { + compnode = TAILQ_FIRST(&completed->nodes); + TAILQ_REMOVE(&completed->nodes, compnode, next); + + while (!TAILQ_EMPTY(&compnode->items)) { + item = TAILQ_FIRST(&compnode->items); + TAILQ_REMOVE(&compnode->items, item, next); + ec_completed_item_free(item); + } + ec_free(compnode); } - ec_free(completed->smallest_start); + ec_keyval_free(completed->attrs); ec_free(completed); } void ec_completed_dump(FILE *out, const struct ec_completed *completed) { - struct ec_completed_elt *elt; + struct ec_completed_node *compnode; + struct ec_completed_item *item; if (completed == NULL || completed->count == 0) { fprintf(out, "no completion\n"); return; } - fprintf(out, "completion: count=%u match=%u smallest_start=<%s>\n", - completed->count, completed->count_match, - completed->smallest_start); + fprintf(out, "completion: count=%u match=%u\n", + completed->count, completed->count_match); - TAILQ_FOREACH(elt, &completed->elts, next) { - fprintf(out, "add=<%s>, node=%p, node_type=%s\n", - elt->add, elt->node, elt->node->type->name); - } -} + TAILQ_FOREACH(compnode, &completed->nodes, next) { + fprintf(out, "node=%p, node_type=%s\n", + compnode->node, compnode->node->type->name); + TAILQ_FOREACH(item, &compnode->items, next) { + const char *typestr; -const char *ec_completed_smallest_start( - const struct ec_completed *completed) -{ - if (completed == NULL || completed->smallest_start == NULL) - return ""; + 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; + default: typestr = "unknown"; break; + } - return completed->smallest_start; + fprintf(out, " type=%s str=<%s> disp=<%s>\n", + typestr, item->str, item->display); + } + } } unsigned int ec_completed_count( const struct ec_completed *completed, - enum ec_completed_filter_flags flags) + enum ec_completed_type type) { unsigned int count = 0; if (completed == NULL) return count; - if (flags & EC_MATCH) + if (type & EC_MATCH) count += completed->count_match; - if (flags & EC_NO_MATCH) + if (type & EC_NO_MATCH) count += (completed->count - completed->count_match); //XXX return count; @@ -319,7 +487,7 @@ unsigned int ec_completed_count( struct ec_completed_iter * ec_completed_iter(struct ec_completed *completed, - enum ec_completed_filter_flags flags) + enum ec_completed_type type) { struct ec_completed_iter *iter; @@ -328,39 +496,57 @@ ec_completed_iter(struct ec_completed *completed, return NULL; iter->completed = completed; - iter->flags = flags; - iter->cur = NULL; + iter->type = type; + iter->cur_node = NULL; + iter->cur_match = NULL; return iter; } -const struct ec_completed_elt *ec_completed_iter_next( +const struct ec_completed_item *ec_completed_iter_next( struct ec_completed_iter *iter) { - if (iter->completed == NULL) - return NULL; + const struct ec_completed *completed = iter->completed; + const struct ec_completed_node *cur_node; + const struct ec_completed_item *cur_match; - do { - if (iter->cur == NULL) { - iter->cur = TAILQ_FIRST(&iter->completed->elts); - } else { - iter->cur = TAILQ_NEXT(iter->cur, next); - } - - if (iter->cur == NULL) - break; + if (completed == NULL) + return NULL; - if (iter->cur->add == NULL && - (iter->flags & EC_NO_MATCH)) - break; + cur_node = iter->cur_node; + cur_match = iter->cur_match; - if (iter->cur->add != NULL && - (iter->flags & EC_MATCH)) - break; + /* first call */ + if (cur_node == NULL) { + TAILQ_FOREACH(cur_node, &completed->nodes, next) { + TAILQ_FOREACH(cur_match, &cur_node->items, next) { + if (cur_match != NULL && + cur_match->type & iter->type) + goto found; + } + } + return NULL; + } else { + cur_match = TAILQ_NEXT(cur_match, next); + if (cur_match != NULL && + cur_match->type & iter->type) + goto found; + cur_node = TAILQ_NEXT(cur_node, next); + while (cur_node != NULL) { + cur_match = TAILQ_FIRST(&cur_node->items); + if (cur_match != NULL && + cur_match->type & iter->type) + goto found; + cur_node = TAILQ_NEXT(cur_node, next); + } + return NULL; + } - } while (iter->cur != NULL); +found: + iter->cur_node = cur_node; + iter->cur_match = cur_match; - return iter->cur; + return iter->cur_match; } void ec_completed_iter_free(struct ec_completed_iter *iter)