{
struct ec_comp *comp = NULL;
struct ec_strvec *strvec = NULL;
- struct ec_comp_iter *iter = NULL;
struct ec_comp_item *item = NULL;
size_t count;
count = ec_comp_count(comp, EC_COMP_UNKNOWN | EC_COMP_FULL |
EC_COMP_PARTIAL);
- iter = ec_comp_iter(comp,
- EC_COMP_UNKNOWN | EC_COMP_FULL | EC_COMP_PARTIAL);
- if (iter == NULL)
- goto fail;
-
- while ((item = ec_comp_iter_next(iter)) != NULL) {
-
+ EC_COMP_FOREACH(item, comp, EC_COMP_UNKNOWN | EC_COMP_FULL |
+ EC_COMP_PARTIAL) {
/* only one match, display it fully */
if (count == 1) {
printf("%s\n", ec_comp_item_get_str(item));
printf("%s\n", ec_comp_item_get_display(item));
}
- ec_comp_iter_free(iter);
ec_comp_free(comp);
ec_strvec_free(strvec);
return 0;
*
*
*/
-struct ec_comp_iter {
- enum ec_comp_type type;
- const struct ec_comp *comp;
- struct ec_comp_group *cur_node;
- struct ec_comp_item *cur_match;
-};
/**
+ * Get the first completion item matching the type.
*
+ * Also see EC_COMP_FOREACH().
*
- *
+ * @param comp
+ * The completion list.
+ * @param type
+ * A logical OR of flags among EC_COMP_UNKNOWN, EC_COMP_PARTIAL and
+ * EC_COMP_FULL, to select the type to iterate.
+ * @return
+ * A completion item.
*/
-struct ec_comp_iter *
-ec_comp_iter(const struct ec_comp *comp,
- enum ec_comp_type type);
+struct ec_comp_item *
+ec_comp_iter_first(const struct ec_comp *comp, enum ec_comp_type type);
/**
+ * Get the first completion item matching the type.
*
+ * Also see EC_COMP_FOREACH().
*
- *
+ * @param comp
+ * The completion list.
+ * @param type
+ * A logical OR of flags among EC_COMP_UNKNOWN, EC_COMP_PARTIAL and
+ * EC_COMP_FULL, to select the type to iterate.
+ * @return
+ * A completion item.
*/
-struct ec_comp_item *ec_comp_iter_next(
- struct ec_comp_iter *iter);
+struct ec_comp_item *
+ec_comp_iter_next(struct ec_comp_item *item, enum ec_comp_type type);
/**
- *
- *
- *
+ * Iterate items matching a given type.
+ *
+ * @param item
+ * The item that will be set at each iteration.
+ * @param comp
+ * The completion list.
+ * @param type
+ * A logical OR of flags among EC_COMP_UNKNOWN, EC_COMP_PARTIAL and
+ * EC_COMP_FULL, to select the type to iterate.
*/
-void ec_comp_iter_free(struct ec_comp_iter *iter);
-
+#define EC_COMP_FOREACH(item, comp, type) \
+ for (item = ec_comp_iter_first(comp, type); \
+ item != NULL; \
+ item = ec_comp_iter_next(item, type))
#endif
return count;
}
-struct ec_comp_iter *
-ec_comp_iter(const struct ec_comp *comp,
- enum ec_comp_type type)
-{
- struct ec_comp_iter *iter;
-
- iter = ec_calloc(1, sizeof(*iter));
- if (iter == NULL)
- return NULL;
-
- iter->comp = comp;
- iter->type = type;
- iter->cur_node = NULL;
- iter->cur_match = NULL;
-
- return iter;
-}
-
-struct ec_comp_item *ec_comp_iter_next(
- struct ec_comp_iter *iter)
+static struct ec_comp_item *
+__ec_comp_iter_next(const struct ec_comp *comp, struct ec_comp_item *item,
+ enum ec_comp_type type)
{
- const struct ec_comp *comp;
- struct ec_comp_group *cur_node;
+ struct ec_comp_group *cur_grp;
struct ec_comp_item *cur_match;
- if (iter == NULL)
- return NULL;
- comp = iter->comp;
- if (comp == NULL)
- return NULL;
-
- cur_node = iter->cur_node;
- cur_match = iter->cur_match;
-
/* first call */
- if (cur_node == NULL) {
- TAILQ_FOREACH(cur_node, &comp->groups, next) {
- TAILQ_FOREACH(cur_match, &cur_node->items, next) {
- if (cur_match != NULL &&
- cur_match->type & iter->type)
- goto found;
+ if (item == NULL) {
+ TAILQ_FOREACH(cur_grp, &comp->groups, next) {
+ TAILQ_FOREACH(cur_match, &cur_grp->items, next) {
+ if (cur_match->type & type)
+ return cur_match;
}
}
return NULL;
- } else {
+ }
+
+ cur_grp = item->grp;
+ cur_match = TAILQ_NEXT(item, next);
+ while (cur_match != NULL) {
+ if (cur_match->type & type)
+ return cur_match;
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);
+ }
+ cur_grp = TAILQ_NEXT(cur_grp, next);
+ while (cur_grp != NULL) {
+ TAILQ_FOREACH(cur_match, &cur_grp->items, next) {
+ if (cur_match->type & type)
+ return cur_match;
}
- return NULL;
}
-found:
- iter->cur_node = cur_node;
- iter->cur_match = cur_match;
+ return NULL;
+}
- return iter->cur_match;
+struct ec_comp_item *
+ec_comp_iter_next(struct ec_comp_item *item, enum ec_comp_type type)
+{
+ if (item == NULL)
+ return NULL;
+ return __ec_comp_iter_next(item->grp->comp, item, type);
}
-void ec_comp_iter_free(struct ec_comp_iter *iter)
+
+struct ec_comp_item *
+ec_comp_iter_first(const struct ec_comp *comp, enum ec_comp_type type)
{
- ec_free(iter);
+ return __ec_comp_iter_next(comp, NULL, type);
}
/* LCOV_EXCL_START */
{
struct ec_node *node = NULL;
struct ec_comp *c = NULL;
- struct ec_comp_iter *iter = NULL;
struct ec_comp_item *item;
FILE *f = NULL;
char *buf = NULL;
free(buf);
buf = NULL;
- iter = ec_comp_iter(c, EC_COMP_ALL);
- item = ec_comp_iter_next(iter);
+ item = ec_comp_iter_first(c, EC_COMP_ALL);
if (item == NULL)
goto fail;
!strcmp(ec_node_id(ec_comp_item_get_node(item)), "id_x"),
"bad item node\n");
- item = ec_comp_iter_next(iter);
+ item = ec_comp_iter_next(item, EC_COMP_ALL);
if (item == NULL)
goto fail;
!strcmp(ec_node_id(ec_comp_item_get_node(item)), "id_y"),
"bad item node\n");
- item = ec_comp_iter_next(iter);
+ item = ec_comp_iter_next(item, EC_COMP_ALL);
testres |= EC_TEST_CHECK(item == NULL, "should be the last item\n");
- ec_comp_iter_free(iter);
ec_comp_free(c);
ec_node_free(node);
return testres;
fail:
- ec_comp_iter_free(iter);
ec_comp_free(c);
ec_node_free(node);
if (f != NULL)
ssize_t
ec_editline_get_completions(const struct ec_comp *cmpl, char ***matches_out)
{
- const struct ec_comp_item *item;
- struct ec_comp_iter *iter = NULL;
+ struct ec_comp_item *item;
char **matches = NULL;
size_t count = 0;
- iter = ec_comp_iter(cmpl, EC_COMP_FULL | EC_COMP_PARTIAL);
- if (iter == NULL)
- goto fail;
-
- while ((item = ec_comp_iter_next(iter)) != NULL) {
+ EC_COMP_FOREACH(item, cmpl, EC_COMP_FULL | EC_COMP_PARTIAL) {
char **tmp;
tmp = realloc(matches, (count + 1) * sizeof(char *));
fail:
ec_editline_free_completions(matches, count);
*matches_out = NULL;
- ec_comp_iter_free(iter);
return -1;
}
char *
ec_editline_append_chars(const struct ec_comp *cmpl)
{
- const struct ec_comp_item *item;
- struct ec_comp_iter *iter = NULL;
+ struct ec_comp_item *item;
const char *append;
char *ret = NULL;
size_t n;
- iter = ec_comp_iter(cmpl, EC_COMP_FULL | EC_COMP_PARTIAL);
- if (iter == NULL)
- goto fail;
-
- while ((item = ec_comp_iter_next(iter)) != NULL) {
+ EC_COMP_FOREACH(item, cmpl, EC_COMP_FULL | EC_COMP_PARTIAL) {
append = ec_comp_item_get_completion(item);
if (ret == NULL) {
ret = ec_strdup(append);
ret[n] = '\0';
}
}
- ec_comp_iter_free(iter);
return ret;
fail:
- ec_comp_iter_free(iter);
ec_free(ret);
return NULL;
ec_editline_get_helps(const struct ec_editline *editline, const char *line,
const char *full_line, struct ec_editline_help **helps_out)
{
- struct ec_comp_iter *iter = NULL;
const struct ec_comp_group *grp, *prev_grp = NULL;
- const struct ec_comp_item *item;
+ struct ec_comp_item *item;
struct ec_comp *cmpl = NULL;
struct ec_pnode *parse = NULL;
unsigned int count = 0;
if (cmpl == NULL) //XXX log error
goto fail;
- /* let's display one contextual help per node */
- iter = ec_comp_iter(cmpl,
- EC_COMP_UNKNOWN | EC_COMP_FULL | EC_COMP_PARTIAL);
- if (iter == NULL)
- goto fail;
-
helps = ec_calloc(1, sizeof(*helps));
if (helps == NULL)
goto fail;
goto fail;
}
- while ((item = ec_comp_iter_next(iter)) != NULL) {
+ /* let's display one contextual help per node */
+ EC_COMP_FOREACH(item, cmpl,
+ EC_COMP_UNKNOWN | EC_COMP_FULL | EC_COMP_PARTIAL) {
struct ec_editline_help *tmp = NULL;
/* keep one help per group, skip other items */
count++;
}
- ec_comp_iter_free(iter);
ec_comp_free(cmpl);
*helps_out = helps;
return count;
fail:
- ec_comp_iter_free(iter);
ec_pnode_free(parse);
ec_comp_free(cmpl);
if (helps != NULL) {
#include <ecoli_string.h>
#include <ecoli_test.h>
#include <ecoli_strvec.h>
+#include <ecoli_htable.h>
#include <ecoli_node.h>
#include <ecoli_parse.h>
#include <ecoli_complete.h>
const struct ec_strvec *strvec)
{
struct ec_node_sh_lex *priv = ec_node_priv(node);
- struct ec_comp *tmp_comp = NULL;
struct ec_strvec *new_vec = NULL;
- struct ec_comp_iter *iter = NULL;
struct ec_comp_item *item = NULL;
+ struct ec_htable *htable = NULL;
char *new_str = NULL;
const char *str;
char missing_quote = '\0';
if (new_vec == NULL)
goto fail;
- /* we will store the completions in a temporary struct, because
- * we want to update them (ex: add missing quotes) */
- tmp_comp = ec_comp(ec_comp_get_state(comp));
- if (tmp_comp == NULL)
+ /* let's store the existing full completions in a htable */
+ htable = ec_htable();
+ if (htable == NULL)
goto fail;
- ret = ec_complete_child(priv->child, tmp_comp, new_vec);
+ EC_COMP_FOREACH(item, comp, EC_COMP_FULL) {
+ if (ec_htable_set(htable, &item, sizeof(item), NULL, NULL) < 0)
+ goto fail;
+ }
+
+ /* do the completion */
+ ret = ec_complete_child(priv->child, comp, new_vec);
if (ret < 0)
goto fail;
- /* add missing quote for full completions */
+ /* add missing quote for any new full completions */
if (missing_quote != '\0') {
- iter = ec_comp_iter(tmp_comp, EC_COMP_FULL);
- if (iter == NULL)
- goto fail;
- while ((item = ec_comp_iter_next(iter)) != NULL) {
+ EC_COMP_FOREACH(item, comp, EC_COMP_FULL) {
+ if (ec_htable_has_key(htable, &item, sizeof(item)))
+ continue;
+
str = ec_comp_item_get_str(item);
if (ec_asprintf(&new_str, "%c%s%c", missing_quote, str,
missing_quote) < 0) {
}
}
- ec_comp_iter_free(iter);
ec_strvec_free(new_vec);
-
- ec_comp_merge(comp, tmp_comp);
+ ec_htable_free(htable);
return 0;
fail:
- ec_comp_free(tmp_comp);
- ec_comp_iter_free(iter);
ec_strvec_free(new_vec);
ec_free(new_str);
+ ec_htable_free(htable);
return -1;
}
for (s = va_arg(ap, const char *);
s != EC_VA_END;
s = va_arg(ap, const char *)) {
- struct ec_comp_iter *iter;
const struct ec_comp_item *item;
if (s == NULL) {
count++;
/* only check matching completions */
- iter = ec_comp_iter(c, type);
- while ((item = ec_comp_iter_next(iter)) != NULL) {
+ EC_COMP_FOREACH(item, c, type) {
const char *str = ec_comp_item_get_str(item);
if (str != NULL && strcmp(str, s) == 0)
break;
"completion <%s> not in list\n", s);
ret = -1;
}
- ec_comp_iter_free(iter);
}
/* check if we have more completions (or less) than expected */