return completed;
}
-struct ec_completed_elt *ec_completed_elt(const struct ec_node *node,
- const char *add)
+struct ec_completed *
+ec_node_complete_child(struct ec_node *node,
+ struct ec_parsed *state,
+ const struct ec_strvec *strvec)
{
- struct ec_completed_elt *elt = NULL;
-
- elt = ec_calloc(1, sizeof(*elt));
- if (elt == NULL)
- return NULL;
+ struct ec_completed *completed;
+ struct ec_parsed *child;
+ int ret;
- elt->node = node;
- if (add != NULL) {
- elt->add = ec_strdup(add);
- if (elt->add == NULL) {
- ec_completed_elt_free(elt);
- return NULL;
+ /* 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;
+ }
}
}
+ node->flags |= EC_NODE_F_BUILT;
- return elt;
+ if (node->type->complete == NULL) {
+ errno = ENOTSUP;
+ return NULL;
+ }
+
+ child = ec_parsed();
+ if (child == NULL)
+ return NULL;
+
+ child->node = node;
+ ec_parsed_add_child(state, child);
+ completed = node->type->complete(node, child, strvec);
+
+#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);
+#endif
+
+ ec_parsed_del_child(state, child);
+ assert(TAILQ_EMPTY(&child->children));
+ ec_parsed_free(child);
+
+ return completed;
+}
+
+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;
+
+ if (state == NULL)
+ return NULL;
+
+ completed = ec_node_complete_child(node, state, strvec);
+ ec_parsed_free(state);
+
+ return completed;
}
-/* XXX define when to use ec_node_complete() or node->complete()
- * (same for parse)
- * suggestion: node->op() is internal, user calls the function
- * other idea: have 2 functions
- */
struct ec_completed *ec_node_complete(struct ec_node *node,
const char *str)
{
return NULL;
}
-/* default completion function: return a no-match element */
-struct ec_completed *ec_node_default_complete(const struct ec_node *gen_node,
- const struct ec_strvec *strvec)
+/* count the number of identical chars at the beginning of 2 strings */
+static size_t strcmp_count(const char *s1, const char *s2)
{
- struct ec_completed *completed;
- struct ec_completed_elt *completed_elt;
+ size_t i = 0;
- (void)strvec;
+ while (s1[i] && s2[i] && s1[i] == s2[i])
+ i++;
- completed = ec_completed();
- if (completed == NULL)
- return NULL;
+ return i;
+}
- if (ec_strvec_len(strvec) != 1)
- return completed;
+static struct ec_completed_elt *
+ec_completed_elt(enum ec_completed_type type, struct ec_parsed *state,
+ const struct ec_node *node, const char *add)
+{
+ struct ec_completed_elt *elt = NULL;
- completed_elt = ec_completed_elt(gen_node, NULL);
- if (completed_elt == NULL) {
- ec_completed_free(completed);
+ elt = ec_calloc(1, sizeof(*elt));
+ if (elt == NULL)
return NULL;
- }
- ec_completed_add_elt(completed, completed_elt);
+ /* XXX can state be NULL? */
+ if (state != NULL) {
+ struct ec_parsed *p;
+ size_t len;
- return completed;
-}
+ /* get path len */
+ for (p = state, len = 0; p != NULL;
+ p = ec_parsed_get_parent(p), len++)
+ ;
-struct ec_completed *ec_node_complete_strvec(struct ec_node *node,
- const struct ec_strvec *strvec)
-{
- int ret;
+ elt->path = ec_calloc(len, sizeof(*elt->path));
+ if (elt->path == NULL)
+ goto fail;
- /* 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;
- }
- }
- }
- node->flags |= EC_NODE_F_BUILT;
+ elt->pathlen = len;
- if (node->type->complete == NULL) {
- errno = ENOTSUP;
- return NULL;
+ /* write path in array */
+ for (p = state, len = 0; p != NULL;
+ p = ec_parsed_get_parent(p), len++)
+ elt->path[len] = p->node;
}
- return node->type->complete(node, strvec);
-}
+ elt->type = type;
+ elt->node = node;
+ if (add != NULL) {
+ elt->add = ec_strdup(add);
+ if (elt->add == NULL)
+ goto fail;
+ }
-/* count the number of identical chars at the beginning of 2 strings */
-static size_t strcmp_count(const char *s1, const char *s2)
-{
- size_t i = 0;
+ return elt;
- while (s1[i] && s2[i] && s1[i] == s2[i])
- i++;
+fail:
+ if (elt != NULL) {
+ ec_free(elt->path);
+ ec_free(elt->add);
+ }
+ ec_completed_elt_free(elt);
- return i;
+ return NULL;
}
-void ec_completed_add_elt(
- struct ec_completed *completed, struct ec_completed_elt *elt)
+static int ec_completed_add_elt(struct ec_completed *completed,
+ struct ec_completed_elt *elt)
{
size_t n;
- 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);
+ if (completed->smallest_start == NULL)
+ return -ENOMEM;
} else {
n = strcmp_count(elt->add,
completed->smallest_start);
completed->smallest_start[n] = '\0';
}
+ completed->count_match++;
}
+ TAILQ_INSERT_TAIL(&completed->elts, elt, next);
+ completed->count++;
+
+ return 0;
+}
+
+int ec_completed_add_match(struct ec_completed *completed,
+ struct ec_parsed *state,
+ const struct ec_node *node, const char *add)
+{
+ struct ec_completed_elt *elt;
+ int ret;
+
+ elt = ec_completed_elt(EC_MATCH, state, node, add);
+ if (elt == NULL)
+ return -ENOMEM;
+
+ ret = ec_completed_add_elt(completed, elt);
+ if (ret < 0) {
+ ec_completed_elt_free(elt);
+ return ret;
+ }
+
+ return 0;
+}
+
+int ec_completed_add_no_match(struct ec_completed *completed,
+ struct ec_parsed *state, const struct ec_node *node)
+{
+ struct ec_completed_elt *elt;
+ int ret;
+
+ elt = ec_completed_elt(EC_NO_MATCH, state, node, NULL);
+ if (elt == NULL)
+ return -ENOMEM;
+
+ ret = ec_completed_add_elt(completed, elt);
+ if (ret < 0) {
+ ec_completed_elt_free(elt);
+ return ret;
+ }
+
+ return 0;
}
void ec_completed_elt_free(struct ec_completed_elt *elt)
{
ec_free(elt->add);
+ ec_free(elt->path);
ec_free(elt);
}
+/* 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)
+{
+ struct ec_completed *completed;
+
+ (void)strvec;
+ (void)state;
+
+ completed = ec_completed();
+ if (completed == NULL)
+ return NULL;
+
+ if (ec_strvec_len(strvec) != 1)
+ return completed;
+
+ if (ec_completed_add_no_match(completed, state, gen_node) < 0) {
+ ec_completed_free(completed);
+ return NULL;
+ }
+
+ return completed;
+}
+
void ec_completed_merge(struct ec_completed *completed1,
struct ec_completed *completed2)
{
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;
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;
return NULL;
iter->completed = completed;
- iter->flags = flags;
+ iter->type = type;
iter->cur = NULL;
return iter;
return NULL;
do {
- if (iter->cur == NULL) {
+ if (iter->cur == NULL)
iter->cur = TAILQ_FIRST(&iter->completed->elts);
- } else {
+ else
iter->cur = TAILQ_NEXT(iter->cur, next);
- }
if (iter->cur == NULL)
break;
if (iter->cur->add == NULL &&
- (iter->flags & EC_NO_MATCH))
+ (iter->type & EC_NO_MATCH))
break;
if (iter->cur->add != NULL &&
- (iter->flags & EC_MATCH))
+ (iter->type & EC_MATCH))
break;
} while (iter->cur != NULL);