X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=lib%2Fecoli_completed.c;h=728b284f97da7bb98062ecb2b7ebde262b71cd9e;hb=e746f568b6a3ab77d0100976d8fa5a68f611bcd3;hp=0b0e641c759d58203cd0ebc9ebbf6c730b68bbab;hpb=43ded238abb9481d41b28b59ea4c09d98374117a;p=protos%2Flibecoli.git diff --git a/lib/ecoli_completed.c b/lib/ecoli_completed.c index 0b0e641..728b284 100644 --- a/lib/ecoli_completed.c +++ b/lib/ecoli_completed.c @@ -48,73 +48,92 @@ struct ec_completed *ec_completed(void) return NULL; TAILQ_INIT(&completed->nodes); - TAILQ_INIT(&completed->matches); return completed; } -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); + + ret = ec_completed_add_node(completed, node); + if (ret < 0) + return ret; - 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, @@ -154,188 +173,225 @@ static size_t strcmp_count(const char *s1, const char *s2) return i; } -static struct ec_completed_item * -ec_completed_item(enum ec_completed_type type, struct ec_parsed *state, - const struct ec_node *node, const char *add) +static struct ec_completed_node * +ec_completed_node(const struct ec_node *node) { - struct ec_completed_item *item = NULL; + struct ec_completed_node *compnode = NULL; - item = ec_calloc(1, sizeof(*item)); - if (item == NULL) + compnode = ec_calloc(1, sizeof(*compnode)); + if (compnode == NULL) return NULL; - /* XXX can state be NULL? */ - if (state != NULL) { - struct ec_parsed *p; - size_t len; + compnode->node = node; + TAILQ_INIT(&compnode->items); - /* get path len */ - for (p = state, len = 0; p != NULL; - p = ec_parsed_get_parent(p), len++) - ; + return compnode; +} - item->path = ec_calloc(len, sizeof(*item->path)); - if (item->path == NULL) - goto fail; +static 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->pathlen = len; + item = ec_calloc(1, sizeof(*item)); + if (item == NULL) + return NULL; - /* write path in array */ - for (p = state, len = 0; p != NULL; - p = ec_parsed_get_parent(p), len++) - item->path[len] = p->node; - } + /* 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 = type; + item->type = EC_NO_MATCH; item->node = node; - if (add != NULL) { - item->add = ec_strdup(add); - if (item->add == NULL) - goto fail; - } return item; fail: if (item != NULL) { ec_free(item->path); - ec_free(item->add); + ec_free(item->str); } ec_completed_item_free(item); return NULL; } -static int ec_completed_add_item(struct ec_completed *completed, - struct ec_completed_item *item) +static int +__ec_completed_add_match(enum ec_completed_type type, + struct ec_completed *completed, + struct ec_parsed *parsed_state, + const struct ec_node *node, const char *str) { - size_t n; + struct ec_completed_node *compnode = NULL; + struct ec_completed_item *item = NULL; + int ret = -ENOMEM; - if (item->add != NULL) { - if (completed->smallest_start == NULL) { - completed->smallest_start = ec_strdup(item->add); - if (completed->smallest_start == NULL) - return -ENOMEM; - } else { - n = strcmp_count(item->add, - completed->smallest_start); - completed->smallest_start[n] = '\0'; - } - completed->count_match++; + /* find the compnode entry corresponding to this node */ + TAILQ_FOREACH(compnode, &completed->nodes, next) { + if (compnode->node == node) + break; + } + if (compnode == NULL) + return -ENOENT; + + item = ec_completed_item(parsed_state, node); + if (item == NULL) + goto fail; + item->type = type; + if (str != NULL) { + item->str = ec_strdup(str); + if (item->str == NULL) + goto fail; } - TAILQ_INSERT_TAIL(&completed->matches, item, next); + if (item->str != NULL) + completed->count_match++; + + TAILQ_INSERT_TAIL(&compnode->items, item, next); completed->count++; return 0; + +fail: + ec_completed_item_free(item); + return ret; } -int ec_completed_add_match(struct ec_completed *completed, - struct ec_parsed *state, - const struct ec_node *node, const char *add) +int +ec_completed_add_match(struct ec_completed *completed, + struct ec_parsed *parsed_state, + const struct ec_node *node, const char *str) { - struct ec_completed_item *item; - int ret; - - item = ec_completed_item(EC_MATCH, state, node, add); - if (item == NULL) - return -ENOMEM; + struct ec_completed_node *compnode = NULL; + struct ec_completed_item *item = NULL; + int ret = -ENOMEM; - ret = ec_completed_add_item(completed, item); - if (ret < 0) { - ec_completed_item_free(item); - return ret; + /* find the compnode entry corresponding to this node */ + TAILQ_FOREACH(compnode, &completed->nodes, next) { + if (compnode->node == node) + break; } + if (compnode == NULL) + return -ENOENT; - return 0; -} - -int ec_completed_add_no_match(struct ec_completed *completed, - struct ec_parsed *state, const struct ec_node *node) -{ - struct ec_completed_item *item; - int ret; - - item = ec_completed_item(EC_NO_MATCH, state, node, NULL); + item = ec_completed_item(parsed_state, node); if (item == NULL) - return -ENOMEM; - - ret = ec_completed_add_item(completed, item); - if (ret < 0) { - ec_completed_item_free(item); - return ret; + goto fail; + item->type = EC_MATCH; + if (str != NULL) { + item->str = ec_strdup(str); + if (item->str == NULL) + goto fail; } + if (item->str != NULL) + completed->count_match++; + + TAILQ_INSERT_TAIL(&compnode->items, item, next); + completed->count++; + return 0; + +fail: + ec_completed_item_free(item); + return ret; } -void ec_completed_item_free(struct ec_completed_item *item) +int +ec_completed_add_no_match(struct ec_completed *completed, + struct ec_parsed *parsed_state, + const struct ec_node *node) { - ec_free(item->add); - ec_free(item->path); - ec_free(item); + return __ec_completed_add_match(EC_NO_MATCH, completed, parsed_state, + node, 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) +int +ec_completed_add_partial_match(struct ec_completed *completed, + struct ec_parsed *parsed_state, + const struct ec_node *node, const char *str) { - struct ec_completed *completed; - - (void)strvec; - (void)state; + return __ec_completed_add_match(EC_PARTIAL_MATCH, completed, parsed_state, + node, str); +} - completed = ec_completed(); - if (completed == NULL) - return NULL; +int +ec_completed_add_node(struct ec_completed *completed, + const struct ec_node *node) +{ + struct ec_completed_node *compnode = NULL; - if (ec_strvec_len(strvec) != 1) - return completed; + compnode = ec_completed_node(node); + if (compnode == NULL) + return -ENOMEM; - if (ec_completed_add_no_match(completed, state, gen_node) < 0) { - ec_completed_free(completed); - return NULL; - } + TAILQ_INSERT_TAIL(&completed->nodes, compnode, next); + return 0; +} - return completed; +void ec_completed_item_free(struct ec_completed_item *match) +{ + ec_free(match->str); + ec_free(match->path); + ec_free(match); } -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, + struct ec_completed *completed, + struct ec_parsed *parsed_state, + const struct ec_strvec *strvec) { - struct ec_completed_item *item; + int ret; - assert(completed1 != NULL); - assert(completed2 != NULL); + if (ec_strvec_len(strvec) != 1) + return 0; - while (!TAILQ_EMPTY(&completed2->matches)) { - item = TAILQ_FIRST(&completed2->matches); - TAILQ_REMOVE(&completed2->matches, item, next); - ec_completed_add_item(completed1, item); - } + ret = ec_completed_add_no_match(completed, parsed_state, gen_node); + if (ret < 0) + return ret; - ec_completed_free(completed2); + return 0; } void ec_completed_free(struct ec_completed *completed) { + struct ec_completed_node *compnode; struct ec_completed_item *item; if (completed == NULL) return; - while (!TAILQ_EMPTY(&completed->matches)) { - item = TAILQ_FIRST(&completed->matches); - TAILQ_REMOVE(&completed->matches, item, next); - ec_completed_item_free(item); + 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_free(completed); } void ec_completed_dump(FILE *out, const struct ec_completed *completed) { + struct ec_completed_node *compnode; struct ec_completed_item *item; if (completed == NULL || completed->count == 0) { @@ -343,23 +399,57 @@ void ec_completed_dump(FILE *out, const struct ec_completed *completed) 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(item, &completed->matches, next) { - fprintf(out, "add=<%s>, node=%p, node_type=%s\n", - item->add, item->node, item->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; + + 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; + } + + fprintf(out, " type=%s str=<%s>\n", typestr, item->str); + } } } -const char *ec_completed_smallest_start( - const struct ec_completed *completed) +char *ec_completed_smallest_start(const struct ec_completed *completed) { - if (completed == NULL || completed->smallest_start == NULL) - return ""; + struct ec_completed_node *compnode; + struct ec_completed_item *item; + char *smallest_start = NULL; + size_t n; + + if (completed == NULL) + goto fail; + + TAILQ_FOREACH(compnode, &completed->nodes, next) { + TAILQ_FOREACH(item, &compnode->items, next) { + if (item->str == NULL) + continue; + if (smallest_start == NULL) { + smallest_start = ec_strdup(item->str); + if (smallest_start == NULL) + goto fail; + } else { + n = strcmp_count(item->str, smallest_start); + smallest_start[n] = '\0'; + } + } + } - return completed->smallest_start; + return smallest_start; + +fail: + ec_free(smallest_start); + return NULL; } unsigned int ec_completed_count( @@ -391,7 +481,8 @@ ec_completed_iter(struct ec_completed *completed, iter->completed = completed; iter->type = type; - iter->cur_item = NULL; + iter->cur_node = NULL; + iter->cur_match = NULL; return iter; } @@ -400,30 +491,46 @@ 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_item *cur_match; if (completed == NULL) return NULL; - do { - if (iter->cur_item == NULL) - iter->cur_item = TAILQ_FIRST(&completed->matches); - else - iter->cur_item = TAILQ_NEXT(iter->cur_item, next); - - if (iter->cur_item == NULL) - break; + cur_node = iter->cur_node; + cur_match = iter->cur_match; - if (iter->cur_item->add == NULL && - (iter->type & EC_NO_MATCH)) - break; - - if (iter->cur_item->add != NULL && - (iter->type & 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_item != NULL); +found: + iter->cur_node = cur_node; + iter->cur_match = cur_match; - return iter->cur_item; + return iter->cur_match; } void ec_completed_iter_free(struct ec_completed_iter *iter)