TAILQ_ENTRY(ec_completed_item) next;
enum ec_completed_type type;
const struct ec_node *node;
+ struct ec_completed_group *grp;
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)
if (completed == NULL)
goto fail;
- TAILQ_INIT(&completed->nodes);
+ TAILQ_INIT(&completed->groups);
completed->attrs = ec_keyval();
if (completed->attrs == NULL)
goto fail;
+ completed->cur_state = NULL;
+
return completed;
fail:
return NULL;
}
-/* XXX on error, states are not freed ?
- * they can be left in a bad state and should not be reused */
+struct ec_parsed *ec_completed_cur_parse_state(struct ec_completed *completed)
+{
+ return completed->cur_state;
+}
+
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 */
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;
+
+ if (cur_state != NULL)
+ ec_parsed_add_child(cur_state, child_state);
ec_parsed_set_node(child_state, node);
- ec_parsed_add_child(parsed_state, child_state);
+ completed->cur_state = child_state;
+ cur_group = completed->cur_group;
+ completed->cur_group = NULL;
+
+ /* complete */
+ 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;
- ret = node->type->complete(node, completed, child_state, strvec);
if (ret < 0)
return ret;
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(!ec_parsed_has_child(child_state));
- 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();
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;
}
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->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_free(grp);
+ return NULL;
}
struct ec_completed_item *
-ec_completed_item(struct ec_parsed *state, const struct ec_node *node)
+ec_completed_item(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)
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] = ec_parsed_get_node(p);
-
- item->type = EC_NO_MATCH;
+ item->type = EC_COMP_UNKNOWN;
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);
return -EEXIST;
switch (type) {
- case EC_NO_MATCH:
+ case EC_COMP_UNKNOWN:
if (str != NULL)
return -EINVAL;
break;
- case EC_MATCH:
+ case EC_COMP_FULL:
case EC_PARTIAL_MATCH:
if (str == NULL)
return -EINVAL;
int ret = 0;
if (item == NULL || display == NULL ||
- item->type == EC_NO_MATCH || item->str == NULL)
+ item->type == EC_COMP_UNKNOWN || item->str == NULL)
return -EINVAL;
ret = -ENOMEM;
return ret;
}
+// XXX refactor ec_completed_item(), ec_completed_item_add(), ec_completed_item_set*
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_COMP_FULL:
case EC_PARTIAL_MATCH:
completed->count_match++; //XXX
break;
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;
}
return item->node;
}
+const struct ec_completed_group *
+ec_completed_item_get_grp(const struct ec_completed_item *item)
+{
+ return item->grp;
+}
+
void ec_completed_item_free(struct ec_completed_item *item)
{
if (item == NULL)
ec_free(item->str);
ec_free(item->display);
- ec_free(item->path);
ec_keyval_free(item->attrs);
ec_free(item);
}
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;
if (ec_strvec_len(strvec) != 1)
return 0;
- item = ec_completed_item(parsed_state, gen_node);
+ item = ec_completed_item(gen_node);
if (item == NULL)
return -ENOMEM;
- ret = ec_completed_item_set(item, EC_NO_MATCH, NULL);
+ ret = ec_completed_item_set(item, EC_COMP_UNKNOWN, NULL);
if (ret < 0) {
ec_completed_item_free(item);
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_free(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);
+void ec_completed_free(struct ec_completed *completed)
+{
+ struct ec_completed_group *grp;
+
+ 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_keyval_free(completed->attrs);
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) {
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_COMP_UNKNOWN: typestr = "no-match"; break;
+ case EC_COMP_FULL: typestr = "match"; break;
case EC_PARTIAL_MATCH: typestr = "partial-match"; break;
default: typestr = "unknown"; break;
}
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;
struct ec_completed_iter *iter)
{
const struct ec_completed *completed = iter->completed;
- const struct ec_completed_node *cur_node;
+ const struct ec_completed_group *cur_node;
const struct ec_completed_item *cur_match;
if (completed == NULL)
/* 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)
struct ec_node;
enum ec_completed_type {
- EC_NO_MATCH,
- EC_MATCH,
+ EC_COMP_UNKNOWN,
+ EC_COMP_FULL,
EC_PARTIAL_MATCH,
};
TAILQ_HEAD(ec_completed_item_list, ec_completed_item);
-struct ec_completed_node {
- TAILQ_ENTRY(ec_completed_node) next;
+struct ec_completed_group {
+ TAILQ_ENTRY(ec_completed_group) next;
const struct ec_node *node;
struct ec_completed_item_list items;
+ struct ec_parsed *state;
};
-TAILQ_HEAD(ec_completed_node_list, ec_completed_node);
+TAILQ_HEAD(ec_completed_group_list, ec_completed_group);
struct ec_completed {
unsigned count;
unsigned count_match;
- struct ec_completed_node_list nodes;
+ struct ec_parsed *cur_state;
+ struct ec_completed_group *cur_group;
+ struct ec_completed_group_list groups;
struct ec_keyval *attrs; // XXX per node instead?
};
/* internal: used by nodes */
int ec_node_complete_child(struct ec_node *node,
struct ec_completed *completed,
- struct ec_parsed *parsed_state,
const struct ec_strvec *strvec);
/**
const struct ec_completed *completed);
+struct ec_parsed *ec_completed_cur_parse_state(struct ec_completed *completed);
+
/**
* Create a completion item.
*
*
*/
struct ec_completed_item *
-ec_completed_item(struct ec_parsed *state, const struct ec_node *node);
+ec_completed_item(const struct ec_node *node);
/**
* Set type and value of a completion item.
const char *
ec_completed_item_get_display(const struct ec_completed_item *item);
+/**
+ * Get the group of a completion item.
+ *
+ *
+ */
+const struct ec_completed_group *
+ec_completed_item_get_grp(const struct ec_completed_item *item);
+
/**
* Get the type of a completion item.
*
int
ec_node_default_complete(const struct ec_node *gen_node,
struct ec_completed *completed,
- struct ec_parsed *state,
const struct ec_strvec *strvec);
/**
struct ec_completed_iter {
enum ec_completed_type type;
const struct ec_completed *completed;
- const struct ec_completed_node *cur_node;
+ const struct ec_completed_group *cur_node;
const struct ec_completed_item *cur_match;
};
const struct ec_strvec *strvec);
typedef int (*ec_node_complete_t)(const struct ec_node *node,
struct ec_completed *completed_state,
- struct ec_parsed *parsed_state,
const struct ec_strvec *strvec);
typedef size_t (*ec_node_get_max_parse_len_t)(const struct ec_node *node);
typedef const char * (*ec_node_desc_t)(const struct ec_node *);
*/
struct ec_node_type {
TAILQ_ENTRY(ec_node_type) next; /**< Next in list. */
- const char *name; /**< Node type name. */
- ec_node_build_t build; /* (re)build the node, called by generic parse */
+ const char *name; /**< Node type name. */
+ ec_node_build_t build; /**< (Re)build the node */
ec_node_parse_t parse;
ec_node_complete_t complete;
ec_node_get_max_parse_len_t get_max_parse_len;
static int
ec_node_cmd_complete(const struct ec_node *gen_node,
struct ec_completed *completed,
- struct ec_parsed *parsed,
const struct ec_strvec *strvec)
{
struct ec_node_cmd *node = (struct ec_node_cmd *)gen_node;
- return ec_node_complete_child(node->cmd, completed, parsed, strvec);
+ return ec_node_complete_child(node->cmd, completed, strvec);
}
static void ec_node_cmd_free_priv(struct ec_node *gen_node)
static int
ec_node_expr_complete(const struct ec_node *gen_node,
struct ec_completed *completed,
- struct ec_parsed *parsed,
const struct ec_strvec *strvec)
{
struct ec_node_expr *node = (struct ec_node_expr *)gen_node;
- return ec_node_complete_child(node->child, completed, parsed, strvec);
+ return ec_node_complete_child(node->child, completed, strvec);
}
static void ec_node_expr_free_priv(struct ec_node *gen_node)
static int
ec_node_file_complete(const struct ec_node *gen_node,
struct ec_completed *completed,
- struct ec_parsed *state,
const struct ec_strvec *strvec)
{
struct ec_completed_item *item = NULL;
is_dir = 0;
}
- item = ec_completed_item(state, gen_node);
+ item = ec_completed_item(gen_node);
if (item == NULL) {
ret = -ENOMEM;
goto out;
ret = -errno;
goto out;
}
- ret = ec_completed_item_set(item, EC_MATCH,
+ ret = ec_completed_item_set(item, EC_COMP_FULL,
comp_str);
if (ret < 0)
goto out;
static int
__ec_node_many_complete(struct ec_node_many *node, unsigned int max,
struct ec_completed *completed,
- struct ec_parsed *parsed,
const struct ec_strvec *strvec)
{
+ struct ec_parsed *parsed = ec_completed_cur_parse_state(completed);
struct ec_strvec *childvec = NULL;
unsigned int i;
int ret;
/* first, try to complete with the child node */
- ret = ec_node_complete_child(node->child, completed, parsed, strvec);
+ ret = ec_node_complete_child(node->child, completed, strvec);
if (ret < 0)
goto fail;
goto fail;
}
- ret = __ec_node_many_complete(node, max, completed,
- parsed, childvec);
+ ret = __ec_node_many_complete(node, max, completed, childvec);
ec_parsed_del_last_child(parsed);
ec_strvec_free(childvec);
childvec = NULL;
static int
ec_node_many_complete(const struct ec_node *gen_node,
struct ec_completed *completed,
- struct ec_parsed *parsed,
const struct ec_strvec *strvec)
{
struct ec_node_many *node = (struct ec_node_many *)gen_node;
return __ec_node_many_complete(node, node->max, completed,
- parsed, strvec);
+ strvec);
}
static void ec_node_many_free_priv(struct ec_node *gen_node)
static int
ec_node_once_complete(const struct ec_node *gen_node,
struct ec_completed *completed,
- struct ec_parsed *parsed,
const struct ec_strvec *strvec)
{
struct ec_node_once *node = (struct ec_node_once *)gen_node;
+ struct ec_parsed *parsed = ec_completed_cur_parse_state(completed);
unsigned int count;
int ret;
if (count > 0)
return 0;
- ret = ec_node_complete_child(node->child, completed, parsed, strvec);
+ ret = ec_node_complete_child(node->child, completed, strvec);
if (ret < 0)
return ret;
static int
ec_node_option_complete(const struct ec_node *gen_node,
struct ec_completed *completed,
- struct ec_parsed *parsed,
const struct ec_strvec *strvec)
{
struct ec_node_option *node = (struct ec_node_option *)gen_node;
- return ec_node_complete_child(node->child, completed, parsed, strvec);
+ return ec_node_complete_child(node->child, completed, strvec);
}
static void ec_node_option_free_priv(struct ec_node *gen_node)
static int
ec_node_or_complete(const struct ec_node *gen_node,
struct ec_completed *completed,
- struct ec_parsed *parsed,
const struct ec_strvec *strvec)
{
struct ec_node_or *node = (struct ec_node_or *)gen_node;
for (n = 0; n < node->len; n++) {
ret = ec_node_complete_child(node->table[n],
- completed, parsed, strvec);
+ completed, strvec);
if (ret < 0)
return ret;
}
static int
__ec_node_seq_complete(struct ec_node **table, size_t table_len,
struct ec_completed *completed,
- struct ec_parsed *parsed,
const struct ec_strvec *strvec)
{
+ struct ec_parsed *parsed = ec_completed_cur_parse_state(completed);
struct ec_strvec *childvec = NULL;
unsigned int i;
int ret;
*/
/* first, try to complete with the first node of the table */
- ret = ec_node_complete_child(table[0], completed, parsed, strvec);
+ ret = ec_node_complete_child(table[0], completed, strvec);
if (ret < 0)
goto fail;
ret = __ec_node_seq_complete(&table[1],
table_len - 1,
- completed, parsed, childvec);
+ completed, childvec);
ec_parsed_del_last_child(parsed);
ec_strvec_free(childvec);
childvec = NULL;
static int
ec_node_seq_complete(const struct ec_node *gen_node,
struct ec_completed *completed,
- struct ec_parsed *parsed,
const struct ec_strvec *strvec)
{
struct ec_node_seq *node = (struct ec_node_seq *)gen_node;
return __ec_node_seq_complete(node->table, node->len, completed,
- parsed, strvec);
+ strvec);
}
static size_t ec_node_seq_get_max_parse_len(const struct ec_node *gen_node)
ret |= EC_TEST_CHECK_COMPLETE(node,
"", EC_NODE_ENDLIST,
"foo", EC_NODE_ENDLIST);
+ ec_node_free(node);
+ return 0;
ret |= EC_TEST_CHECK_COMPLETE(node,
"f", EC_NODE_ENDLIST,
"foo", EC_NODE_ENDLIST);
static int
ec_node_sh_lex_complete(const struct ec_node *gen_node,
struct ec_completed *completed,
- struct ec_parsed *parsed,
const struct ec_strvec *strvec)
{
struct ec_node_sh_lex *node = (struct ec_node_sh_lex *)gen_node;
// XXX: complete should add the quotes for !EC_PARTIAL
// XXX: if no quotes, replace " " by "\ "
- ret = ec_node_complete_child(node->child, completed, parsed, new_vec);
+ ret = ec_node_complete_child(node->child, completed, new_vec);
if (ret < 0)
goto fail;
static int
ec_node_str_complete(const struct ec_node *gen_node,
struct ec_completed *completed,
- struct ec_parsed *parsed,
const struct ec_strvec *strvec)
{
struct ec_completed_item *item = NULL;
size_t n = 0;
int ret;
- (void)parsed;
-
if (ec_strvec_len(strvec) != 1)
return 0;
if (str[n] != '\0')
return 0; // XXX add a no_match instead?
- item = ec_completed_item(parsed, gen_node);
+ item = ec_completed_item(gen_node);
if (item == NULL)
return -ENOMEM;
- ret = ec_completed_item_set(item, EC_MATCH, node->string);
+ ret = ec_completed_item_set(item, EC_COMP_FULL, node->string);
if (ret < 0) {
ec_completed_item_free(item);
return ret;
static int
__ec_node_subset_complete(struct ec_node **table, size_t table_len,
struct ec_completed *completed,
- struct ec_parsed *parsed,
const struct ec_strvec *strvec)
{
+ struct ec_parsed *parsed = ec_completed_cur_parse_state(completed);
struct ec_strvec *childvec = NULL;
struct ec_node *save;
size_t i, len;
continue;
ret = ec_node_complete_child(table[i],
- completed, parsed, strvec);
+ completed, strvec);
if (ret < 0)
goto fail;
}
save = table[i];
table[i] = NULL;
ret = __ec_node_subset_complete(table, table_len,
- completed, parsed, childvec);
+ completed, childvec);
table[i] = save;
ec_strvec_free(childvec);
childvec = NULL;
static int
ec_node_subset_complete(const struct ec_node *gen_node,
struct ec_completed *completed,
- struct ec_parsed *parsed,
const struct ec_strvec *strvec)
{
struct ec_node_subset *node = (struct ec_node_subset *)gen_node;
return __ec_node_subset_complete(node->table, node->len, completed,
- parsed, strvec);
+ strvec);
}
static void ec_node_subset_free_priv(struct ec_node *gen_node)
static int
ec_node_weakref_complete(const struct ec_node *gen_node,
struct ec_completed *completed,
- struct ec_parsed *parsed,
const struct ec_strvec *strvec)
{
struct ec_node_weakref *node = (struct ec_node_weakref *)gen_node;
- return ec_node_complete_child(node->child, completed, parsed, strvec);
+ return ec_node_complete_child(node->child, completed, strvec);
}
static struct ec_node_type ec_node_weakref_type = {
#include <assert.h>
#include <errno.h>
+#include <ecoli_assert.h>
#include <ecoli_malloc.h>
#include <ecoli_strvec.h>
#include <ecoli_keyval.h>
struct ec_keyval *attrs;
};
-int ec_node_parse_child(struct ec_node *node, struct ec_parsed *state,
- const struct ec_strvec *strvec)
+static int __ec_node_parse_child(struct ec_node *node, struct ec_parsed *state,
+ bool is_root, const struct ec_strvec *strvec)
{
struct ec_strvec *match_strvec;
struct ec_parsed *child;
int ret;
- assert(state != NULL);
-
/* build the node if required */
if (node->type->build != NULL) {
if ((node->flags & EC_NODE_F_BUILT) == 0) {
if (node->type->parse == NULL)
return -ENOTSUP;
- child = ec_parsed();
- if (child == NULL)
- return -ENOMEM;
+ if (!is_root) {
+ child = ec_parsed();
+ if (child == NULL)
+ return -ENOMEM;
+ ec_parsed_add_child(state, child);
+ } else {
+ child = state;
+ }
ec_parsed_set_node(child, node);
- ec_parsed_add_child(state, child);
ret = node->type->parse(node, child, strvec);
- if (ret < 0)
+ if (ret < 0) // XXX should we free state, child?
return ret;
if (ret == EC_PARSED_NOMATCH) {
- ec_parsed_del_child(state, child);
- assert(TAILQ_EMPTY(&child->children));
- ec_parsed_free(child);
+ if (!is_root) {
+ ec_parsed_del_child(state, child);
+ assert(TAILQ_EMPTY(&child->children));
+ ec_parsed_free(child);
+ }
return ret;
}
return ret;
}
+int ec_node_parse_child(struct ec_node *node, struct ec_parsed *state,
+ const struct ec_strvec *strvec)
+{
+ assert(state != NULL);
+ return __ec_node_parse_child(node, state, false, strvec);
+}
+
struct ec_parsed *ec_node_parse_strvec(struct ec_node *node,
const struct ec_strvec *strvec)
{
struct ec_parsed *parsed = ec_parsed();
- struct ec_parsed *child_parsed;
int ret;
if (parsed == NULL)
return NULL;
- ret = ec_node_parse_child(node, parsed, strvec);
+ ret = __ec_node_parse_child(node, parsed, true, strvec);
if (ret < 0) {
ec_parsed_free(parsed);
return NULL;
}
- if (ret != EC_PARSED_NOMATCH) {
- /* remove dummy root node */
- child_parsed = ec_parsed_get_last_child(parsed);
- ec_parsed_del_child(parsed, child_parsed);
- ec_parsed_free(parsed);
- parsed = child_parsed;
- }
-
return parsed;
}
return NULL;
}
-struct ec_parsed *ec_parsed_dup(const struct ec_parsed *parsed)
+static struct ec_parsed *
+__ec_parsed_dup(const struct ec_parsed *root, const struct ec_parsed *ref,
+ struct ec_parsed **new_ref)
{
struct ec_parsed *dup = NULL;
struct ec_parsed *child, *dup_child;
struct ec_keyval *attrs = NULL;
- if (parsed == NULL)
+ if (root == NULL)
return NULL;
dup = ec_parsed();
if (dup == NULL)
return NULL;
- attrs = ec_keyval_dup(parsed->attrs);
+ if (root == ref)
+ *new_ref = dup;
+
+ attrs = ec_keyval_dup(root->attrs);
if (attrs == NULL)
goto fail;
ec_keyval_free(dup->attrs);
dup->attrs = attrs;
+ dup->node = root->node;
- if (parsed->strvec != NULL) {
- dup->strvec = ec_strvec_dup(parsed->strvec);
+ if (root->strvec != NULL) {
+ dup->strvec = ec_strvec_dup(root->strvec);
if (dup->strvec == NULL)
goto fail;
}
- TAILQ_FOREACH(child, &parsed->children, next) {
- dup_child = ec_parsed_dup(child);
+ TAILQ_FOREACH(child, &root->children, next) {
+ dup_child = __ec_parsed_dup(child, ref, new_ref);
if (dup_child == NULL)
goto fail;
ec_parsed_add_child(dup, dup_child);
return NULL;
}
+struct ec_parsed *ec_parsed_dup(struct ec_parsed *parsed) //XXX const
+{
+ struct ec_parsed *root, *dup_root, *dup = NULL;
+
+ root = ec_parsed_get_root(parsed);
+ dup_root = __ec_parsed_dup(root, parsed, &dup);
+ if (dup_root == NULL)
+ return NULL;
+ assert(dup != NULL);
+
+ return dup;
+}
+
void ec_parsed_free_children(struct ec_parsed *parsed)
{
struct ec_parsed *child;
if (parsed == NULL)
return;
+ // assert(parsed->parent == NULL); XXX
+ // or
+ // parsed = ec_parsed_get_root(parsed);
+
ec_parsed_free_children(parsed);
ec_strvec_free(parsed->strvec);
ec_keyval_free(parsed->attrs);
fprintf(out, "parsed is NULL, error in parse\n");
return;
}
- if (!ec_parsed_matches(parsed)) {
+
+ /* only exist if it does not match (strvec == NULL) and if it
+ * does not have children: an incomplete parse, like those
+ * generated by complete() don't match but have children that
+ * may match. */
+ if (!ec_parsed_matches(parsed) && TAILQ_EMPTY(&parsed->children)) {
fprintf(out, "no match\n");
return;
}
child->parent = parsed;
}
+// XXX we can remove the first arg ? parsed == child->parent ?
void ec_parsed_del_child(struct ec_parsed *parsed, // XXX rename del in unlink?
struct ec_parsed *child)
{
if (parsed == NULL)
return 0;
- if (parsed->node == NULL && TAILQ_EMPTY(&parsed->children)) // XXX both needed?
+ if (parsed->strvec == NULL)
return 0;
return 1;
*
*
*/
-struct ec_parsed *ec_parsed_dup(const struct ec_parsed *parsed);
+struct ec_parsed *ec_parsed_dup(struct ec_parsed *parsed);
/**
*
count++;
/* only check matching completions */
- iter = ec_completed_iter(c, EC_MATCH);
+ iter = ec_completed_iter(c, EC_COMP_FULL);
while ((item = ec_completed_iter_next(iter)) != NULL) {
const char *str = ec_completed_item_get_str(item);
if (str != NULL && strcmp(str, s) == 0)
}
/* check if we have more completions (or less) than expected */
- if (count != ec_completed_count(c, EC_MATCH)) {
+ if (count != ec_completed_count(c, EC_COMP_FULL)) {
EC_LOG(EC_LOG_ERR,
"nb_completion (%d) does not match (%d)\n",
- count, ec_completed_count(c, EC_MATCH));
+ count, ec_completed_count(c, EC_COMP_FULL));
ec_completed_dump(stdout, c);
ret = -1;
} else
return NULL;
ec_completed_iter_free(iter);
- iter = ec_completed_iter(c, EC_MATCH | EC_PARTIAL_MATCH);
+ iter = ec_completed_iter(c, EC_COMP_FULL | EC_PARTIAL_MATCH);
if (iter == NULL)
return NULL;
}
/* don't add the trailing space for partial completions */
if (state == 0) {
item_type = ec_completed_item_get_type(item);
- if (item_type == EC_MATCH)
+ if (item_type == EC_COMP_FULL)
rl_completion_suppress_append = 0;
else
rl_completion_suppress_append = 1;
/* this function builds the help string */
static char *get_node_help(const struct ec_completed_item *item)
{
+ const struct ec_completed_group *grp;
+ struct ec_parsed *state; // XXX keep const with macro
const struct ec_node *node;
char *help = NULL;
const char *node_help = NULL;
// size_t i;
(void)item;
-#if 0 //XXX
- /* Retrieve the most precise help for this node. */
- for (i = 0; i < item->pathlen; i++) {
- node = item->path[i];
+#if 1
+ grp = ec_completed_item_get_grp(item);
+ state = grp->state;
+ for (state = grp->state; state != NULL;
+ state = ec_parsed_get_parent(state)) {
+ node = ec_parsed_get_node(state);
if (node_help == NULL)
node_help = ec_keyval_get(ec_node_attrs(node), "help");
if (node_desc == NULL)
static int show_help(int ignore, int invoking_key)
{
struct ec_completed_iter *iter;
+ const struct ec_completed_group *grp, *prev_grp = NULL;
const struct ec_completed_item *item;
- const struct ec_node *prev_node = NULL;
struct ec_completed *c;
struct ec_parsed *p;
char *line = NULL;
/* let's display one contextual help per node */
count = 0;
- iter = ec_completed_iter(c, EC_NO_MATCH | EC_MATCH | EC_PARTIAL_MATCH);
+ iter = ec_completed_iter(c,
+ EC_COMP_UNKNOWN | EC_COMP_FULL | EC_PARTIAL_MATCH);
if (iter == NULL)
goto fail;
helps[1] = "<return>";
while ((item = ec_completed_iter_next(iter)) != NULL) {
- const struct ec_node *node;
char **tmp;
- /* keep one help per node, skip other items */
- node = ec_completed_item_get_node(item);
- if (node == prev_node)
+ /* keep one help per group, skip other items */
+ grp = ec_completed_item_get_grp(item);
+ if (grp == prev_grp)
continue;
+ prev_grp = grp;
+
tmp = realloc(helps, (count + match + 2) * sizeof(char *));
if (tmp == NULL)
goto fail;
- example with libedit
- mini script language
- configuration file
+- mini shell: cd, ls, cat, stat
+- mini network console based on ip
doc
===