return NULL;
}
+#if 0 // XXX dump
+ {
+ struct ec_completed *c;
+ c = node->type->complete(node, strvec);
+
+ printf("--------------------------------------------------------------\n");
+ ec_node_dump(stdout, node);
+ ec_strvec_dump(stdout, strvec);
+ ec_completed_dump(stdout, c);
+ return c;
+ }
+#else
return node->type->complete(node, strvec);
+#endif
}
/* count the number of identical chars at the beginning of 2 strings */
struct ec_strvec;
struct ec_keyval;
-/* return 0 on success, else -errno. */
-typedef int (*ec_node_build_t)(struct ec_node *node);
-
-typedef struct ec_parsed *(*ec_node_parse_t)(const struct ec_node *node,
- const struct ec_strvec *strvec);
-typedef struct ec_completed *(*ec_node_complete_t)(const struct ec_node *node,
- const struct ec_strvec *strvec);
-typedef const char * (*ec_node_desc_t)(const struct ec_node *);
-typedef void (*ec_node_init_priv_t)(struct ec_node *);
-typedef void (*ec_node_free_priv_t)(struct ec_node *);
-
#define EC_NODE_TYPE_REGISTER(t) \
static void ec_node_init_##t(void); \
static void __attribute__((constructor, used)) \
TAILQ_HEAD(ec_node_type_list, ec_node_type);
+/* return 0 on success, else -errno. */
+typedef int (*ec_node_build_t)(struct ec_node *node);
+
+typedef int (*ec_node_parse_t)(const struct ec_node *node,
+ struct ec_parsed *state,
+ const struct ec_strvec *strvec);
+typedef struct ec_completed *(*ec_node_complete_t)(const struct ec_node *node,
+ const struct ec_strvec *strvec);
+typedef const char * (*ec_node_desc_t)(const struct ec_node *);
+typedef void (*ec_node_init_priv_t)(struct ec_node *);
+typedef void (*ec_node_free_priv_t)(struct ec_node *);
+
/**
* A structure describing a node type.
*/
.eval_free = ec_node_cmd_eval_free,
};
-static struct ec_parsed *ec_node_cmd_parse(const struct ec_node *gen_node,
- const struct ec_strvec *strvec)
+static int ec_node_cmd_parse(const struct ec_node *gen_node,
+ struct ec_parsed *state,
+ const struct ec_strvec *strvec)
{
struct ec_node_cmd *node = (struct ec_node_cmd *)gen_node;
- return ec_node_parse_strvec(node->cmd, strvec);
+ return ec_node_parse_child(node->cmd, state, strvec);
}
static struct ec_completed *ec_node_cmd_complete(const struct ec_node *gen_node,
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <errno.h>
#include <ecoli_malloc.h>
#include <ecoli_log.h>
struct ec_node gen;
};
-static struct ec_parsed *ec_node_empty_parse(const struct ec_node *gen_node,
- const struct ec_strvec *strvec)
+static int ec_node_empty_parse(const struct ec_node *gen_node,
+ struct ec_parsed *state,
+ const struct ec_strvec *strvec)
{
- struct ec_parsed *parsed;
- struct ec_strvec *match_strvec;
-
+ (void)gen_node;
+ (void)state;
(void)strvec;
-
- parsed = ec_parsed();
- if (parsed == NULL)
- goto fail;
-
- match_strvec = ec_strvec();
- if (match_strvec == NULL)
- goto fail;
-
- ec_parsed_set_match(parsed, gen_node, match_strvec);
-
- return parsed;
-
- fail:
- ec_parsed_free(parsed);
- return NULL;
+ return 0;
}
static struct ec_node_type ec_node_empty_type = {
unsigned int paren_len;
};
-static struct ec_parsed *ec_node_expr_parse(const struct ec_node *gen_node,
- const struct ec_strvec *strvec)
+static int ec_node_expr_parse(const struct ec_node *gen_node,
+ struct ec_parsed *state,
+ const struct ec_strvec *strvec)
{
struct ec_node_expr *node = (struct ec_node_expr *)gen_node;
- return ec_node_parse_strvec(node->child, strvec);
+ return ec_node_parse_child(node->child, state, strvec);
}
static struct ec_completed *ec_node_expr_complete(const struct ec_node *gen_node,
return 0;
}
-static struct ec_parsed *ec_node_int_parse(const struct ec_node *gen_node,
- const struct ec_strvec *strvec)
+static int ec_node_int_parse(const struct ec_node *gen_node,
+ struct ec_parsed *state,
+ const struct ec_strvec *strvec)
{
struct ec_node_int *node = (struct ec_node_int *)gen_node;
- struct ec_parsed *parsed;
- struct ec_strvec *match_strvec;
const char *str;
long long val;
- parsed = ec_parsed();
- if (parsed == NULL)
- goto fail;
+ (void)state;
if (ec_strvec_len(strvec) == 0)
- return parsed;
+ return EC_PARSED_NOMATCH;
str = ec_strvec_val(strvec, 0);
if (parse_llint(node, str, &val) < 0)
- return parsed;
+ return EC_PARSED_NOMATCH;
- match_strvec = ec_strvec_ndup(strvec, 0, 1);
- if (match_strvec == NULL)
- goto fail;
-
- ec_parsed_set_match(parsed, gen_node, match_strvec);
-
- return parsed;
-
- fail:
- ec_parsed_free(parsed);
- return NULL;
+ return 1;
}
static struct ec_node_type ec_node_int_type = {
#include <string.h>
#include <assert.h>
#include <stdarg.h>
+#include <errno.h>
#include <ecoli_malloc.h>
#include <ecoli_log.h>
struct ec_node *child;
};
-static struct ec_parsed *ec_node_many_parse(const struct ec_node *gen_node,
- const struct ec_strvec *strvec)
+static int ec_node_many_parse(const struct ec_node *gen_node,
+ struct ec_parsed *state,
+ const struct ec_strvec *strvec)
{
struct ec_node_many *node = (struct ec_node_many *)gen_node;
- struct ec_parsed *parsed, *child_parsed;
- struct ec_strvec *match_strvec;
+ struct ec_parsed *child_parsed;
struct ec_strvec *childvec = NULL;
- size_t off = 0, len, count;
-
- parsed = ec_parsed();
- if (parsed == NULL)
- goto fail;
+ size_t off = 0, count;
+ int ret;
for (count = 0; node->max == 0 || count < node->max; count++) {
childvec = ec_strvec_ndup(strvec, off,
ec_strvec_len(strvec) - off);
- if (childvec == NULL)
- goto fail;
-
- child_parsed = ec_node_parse_strvec(node->child, childvec);
- if (child_parsed == NULL)
+ if (childvec == NULL) {
+ ret = -ENOMEM;
goto fail;
+ }
+ ret = ec_node_parse_child(node->child, state, childvec);
ec_strvec_free(childvec);
childvec = NULL;
- if (!ec_parsed_matches(child_parsed)) {
- ec_parsed_free(child_parsed);
+ if (ret == EC_PARSED_NOMATCH)
break;
- }
-
- ec_parsed_add_child(parsed, child_parsed);
+ else if (ret < 0)
+ goto fail;
/* it matches an empty strvec, no need to continue */
- len = ec_parsed_len(child_parsed);
- if (len == 0) {
+ if (ret == 0) {
+ child_parsed = ec_parsed_get_last_child(state);
+ ec_parsed_del_child(state, child_parsed);
ec_parsed_free(child_parsed);
break;
}
- off += len;
+ off += ret;
}
if (count < node->min) {
- ec_parsed_free_children(parsed);
- return parsed;
+ ec_parsed_free_children(state);
+ return EC_PARSED_NOMATCH;
}
- match_strvec = ec_strvec_ndup(strvec, 0, off);
- if (match_strvec == NULL)
- goto fail;
-
- ec_parsed_set_match(parsed, gen_node, match_strvec);
-
- return parsed;
+ return off;
fail:
ec_strvec_free(childvec);
- ec_parsed_free(parsed);
- return NULL;
+ return ret;
}
#if 0 //XXX missing node_many_complete
struct ec_node *child;
};
-static struct ec_parsed *ec_node_option_parse(const struct ec_node *gen_node,
- const struct ec_strvec *strvec)
+static int
+ec_node_option_parse(const struct ec_node *gen_node,
+ struct ec_parsed *state,
+ const struct ec_strvec *strvec)
{
struct ec_node_option *node = (struct ec_node_option *)gen_node;
- struct ec_parsed *parsed = NULL, *child_parsed;
- struct ec_strvec *match_strvec;
-
- parsed = ec_parsed();
- if (parsed == NULL)
- goto fail;
-
- child_parsed = ec_node_parse_strvec(node->child, strvec);
- if (child_parsed == NULL)
- goto fail;
-
- if (ec_parsed_matches(child_parsed)) {
- ec_parsed_add_child(parsed, child_parsed);
- match_strvec = ec_strvec_dup(child_parsed->strvec);
- } else {
- ec_parsed_free(child_parsed);
- match_strvec = ec_strvec();
- }
-
- if (match_strvec == NULL)
- goto fail;
+ int ret;
- ec_parsed_set_match(parsed, gen_node, match_strvec);
+ ret = ec_node_parse_child(node->child, state, strvec);
+ if (ret == EC_PARSED_NOMATCH)
+ return 0;
+ else if (ret < 0)
+ return ret;
- return parsed;
-
- fail:
- ec_parsed_free(parsed);
- return NULL;
+ return ret;
}
-static struct ec_completed *ec_node_option_complete(const struct ec_node *gen_node,
- const struct ec_strvec *strvec)
+static struct ec_completed *
+ec_node_option_complete(const struct ec_node *gen_node,
+ const struct ec_strvec *strvec)
{
struct ec_node_option *node = (struct ec_node_option *)gen_node;
unsigned int len;
};
-static struct ec_parsed *ec_node_or_parse(const struct ec_node *gen_node,
- const struct ec_strvec *strvec)
+static int
+ec_node_or_parse(const struct ec_node *gen_node,
+ struct ec_parsed *state,
+ const struct ec_strvec *strvec)
{
struct ec_node_or *node = (struct ec_node_or *)gen_node;
- struct ec_parsed *parsed, *child_parsed = NULL;
- struct ec_strvec *match_strvec;
unsigned int i;
-
- parsed = ec_parsed();
- if (parsed == NULL)
- goto fail;
+ int ret;
for (i = 0; i < node->len; i++) {
- child_parsed = ec_node_parse_strvec(node->table[i], strvec);
- if (child_parsed == NULL)
- goto fail;
- if (ec_parsed_matches(child_parsed))
- break;
- ec_parsed_free(child_parsed);
- child_parsed = NULL;
+ ret = ec_node_parse_child(node->table[i], state, strvec);
+ if (ret == EC_PARSED_NOMATCH)
+ continue;
+ return ret;
}
- /* no match */
- if (i == node->len)
- return parsed;
-
- match_strvec = ec_strvec_dup(child_parsed->strvec);
- if (match_strvec == NULL)
- goto fail;
-
- ec_parsed_set_match(parsed, gen_node, match_strvec);
- ec_parsed_add_child(parsed, child_parsed);
-
- return parsed;
-
- fail:
- ec_parsed_free(child_parsed);
- ec_parsed_free(parsed);
- return NULL;
+ return EC_PARSED_NOMATCH;
}
static struct ec_completed *ec_node_or_complete(const struct ec_node *gen_node,
regex_t re;
};
-static struct ec_parsed *ec_node_re_parse(const struct ec_node *gen_node,
- const struct ec_strvec *strvec)
+static int
+ec_node_re_parse(const struct ec_node *gen_node,
+ struct ec_parsed *state,
+ const struct ec_strvec *strvec)
{
struct ec_node_re *node = (struct ec_node_re *)gen_node;
- struct ec_strvec *match_strvec;
- struct ec_parsed *parsed = NULL;
const char *str;
regmatch_t pos;
- parsed = ec_parsed();
- if (parsed == NULL)
- goto fail;
+ (void)state;
if (ec_strvec_len(strvec) == 0)
- return parsed;
+ return EC_PARSED_NOMATCH;
str = ec_strvec_val(strvec, 0);
if (regexec(&node->re, str, 1, &pos, 0) != 0)
- return parsed;
+ return EC_PARSED_NOMATCH;
if (pos.rm_so != 0 || pos.rm_eo != (int)strlen(str))
- return parsed;
-
- match_strvec = ec_strvec_ndup(strvec, 0, 1);
- if (match_strvec == NULL)
- goto fail;
+ return EC_PARSED_NOMATCH;
- ec_parsed_set_match(parsed, gen_node, match_strvec);
-
- return parsed;
-
- fail:
- ec_parsed_free(parsed);
- return NULL;
+ return 1;
}
static void ec_node_re_free_priv(struct ec_node *gen_node)
return NULL;
}
-static struct ec_parsed *ec_node_re_lex_parse(const struct ec_node *gen_node,
- const struct ec_strvec *strvec)
+static int
+ec_node_re_lex_parse(const struct ec_node *gen_node,
+ struct ec_parsed *state,
+ const struct ec_strvec *strvec)
{
struct ec_node_re_lex *node = (struct ec_node_re_lex *)gen_node;
- struct ec_strvec *new_vec = NULL, *match_strvec;
- struct ec_parsed *parsed = NULL, *child_parsed;
+ struct ec_strvec *new_vec = NULL;
+ struct ec_parsed *child_parsed;
const char *str;
+ int ret;
- parsed = ec_parsed();
- if (parsed == NULL)
- return NULL;
-
- if (ec_strvec_len(strvec) == 0)
- return parsed;
-
- str = ec_strvec_val(strvec, 0);
- new_vec = tokenize(node->table, node->len, str);
- if (new_vec == NULL)
- goto fail;
-
- printf("--------\n");
- ec_strvec_dump(stdout, new_vec);
- child_parsed = ec_node_parse_strvec(node->child, new_vec);
- if (child_parsed == NULL)
+ if (ec_strvec_len(strvec) == 0) {
+ new_vec = ec_strvec();
+ } else {
+ str = ec_strvec_val(strvec, 0);
+ new_vec = tokenize(node->table, node->len, str);
+ }
+ if (new_vec == NULL) {
+ ret = -ENOMEM;
goto fail;
+ }
- if (!ec_parsed_matches(child_parsed) ||
- ec_parsed_len(child_parsed) !=
- ec_strvec_len(new_vec)) {
- ec_strvec_free(new_vec);
- ec_parsed_free(child_parsed);
- return parsed;
+ ret = ec_node_parse_child(node->child, state, new_vec);
+ if (ret >= 0) {
+ if ((unsigned)ret == ec_strvec_len(new_vec)) {
+ ret = 1;
+ } else {
+ child_parsed = ec_parsed_get_last_child(state);
+ ec_parsed_del_child(state, child_parsed);
+ ec_parsed_free(child_parsed);
+ ret = EC_PARSED_NOMATCH;
+ }
}
+
ec_strvec_free(new_vec);
new_vec = NULL;
- ec_parsed_add_child(parsed, child_parsed);
- match_strvec = ec_strvec_ndup(strvec, 0, 1);
- if (match_strvec == NULL)
- goto fail;
- ec_parsed_set_match(parsed, gen_node, match_strvec);
-
- return parsed;
+ return ret;
fail:
ec_strvec_free(new_vec);
- ec_parsed_free(parsed);
-
- return NULL;
+ return ret;
}
static void ec_node_re_lex_free_priv(struct ec_node *gen_node)
unsigned int len;
};
-static struct ec_parsed *ec_node_seq_parse(const struct ec_node *gen_node,
- const struct ec_strvec *strvec)
+static int
+ec_node_seq_parse(const struct ec_node *gen_node,
+ struct ec_parsed *state,
+ const struct ec_strvec *strvec)
{
struct ec_node_seq *node = (struct ec_node_seq *)gen_node;
- struct ec_parsed *parsed, *child_parsed;
- struct ec_strvec *match_strvec;
struct ec_strvec *childvec = NULL;
size_t len = 0;
unsigned int i;
-
- parsed = ec_parsed();
- if (parsed == NULL)
- goto fail;
+ int ret;
for (i = 0; i < node->len; i++) {
childvec = ec_strvec_ndup(strvec, len,
ec_strvec_len(strvec) - len);
- if (childvec == NULL)
- goto fail;
-
- child_parsed = ec_node_parse_strvec(node->table[i], childvec);
- if (child_parsed == NULL)
+ if (childvec == NULL) {
+ ret = -ENOMEM;
goto fail;
+ }
+ ret = ec_node_parse_child(node->table[i], state, childvec);
ec_strvec_free(childvec);
childvec = NULL;
-
- if (!ec_parsed_matches(child_parsed)) {
- ec_parsed_free(child_parsed);
- // XXX ec_parsed_free_children needed? see subset.c
- ec_parsed_free_children(parsed);
- return parsed;
+ if (ret == EC_PARSED_NOMATCH) {
+ ec_parsed_free_children(state);
+ return EC_PARSED_NOMATCH;
+ } else if (ret < 0) {
+ goto fail;
}
- ec_parsed_add_child(parsed, child_parsed);
- len += ec_parsed_len(child_parsed);
+ len += ret;
}
- match_strvec = ec_strvec_ndup(strvec, 0, len);
- if (match_strvec == NULL)
- goto fail;
-
- ec_parsed_set_match(parsed, gen_node, match_strvec);
-
- return parsed;
+ return len;
fail:
ec_strvec_free(childvec);
- ec_parsed_free(parsed);
- return NULL;
+ return ret;
}
static struct ec_completed *
return NULL;
}
-static struct ec_parsed *ec_node_sh_lex_parse(const struct ec_node *gen_node,
- const struct ec_strvec *strvec)
+static int
+ec_node_sh_lex_parse(const struct ec_node *gen_node,
+ struct ec_parsed *state,
+ const struct ec_strvec *strvec)
{
struct ec_node_sh_lex *node = (struct ec_node_sh_lex *)gen_node;
- struct ec_strvec *new_vec = NULL, *match_strvec;
- struct ec_parsed *parsed = NULL, *child_parsed;
+ struct ec_strvec *new_vec = NULL;
+ struct ec_parsed *child_parsed;
const char *str;
+ int ret;
- parsed = ec_parsed();
- if (parsed == NULL)
- return NULL;
-
- if (ec_strvec_len(strvec) == 0)
- return parsed;
-
- str = ec_strvec_val(strvec, 0);
- new_vec = tokenize(str, 0, 0, NULL);
- if (new_vec == NULL)
- goto fail;
-
- child_parsed = ec_node_parse_strvec(node->child, new_vec);
- if (child_parsed == NULL)
+ if (ec_strvec_len(strvec) == 0) {
+ new_vec = ec_strvec();
+ } else {
+ str = ec_strvec_val(strvec, 0);
+ new_vec = tokenize(str, 0, 0, NULL);
+ }
+ if (new_vec == NULL) {
+ ret = -ENOMEM;
goto fail;
+ }
- if (!ec_parsed_matches(child_parsed) ||
- ec_parsed_len(child_parsed) !=
- ec_strvec_len(new_vec)) {
- ec_strvec_free(new_vec);
- ec_parsed_free(child_parsed);
- return parsed;
+ ret = ec_node_parse_child(node->child, state, new_vec);
+ if (ret >= 0) {
+ if ((unsigned)ret == ec_strvec_len(new_vec)) {
+ ret = 1;
+ } else {
+ child_parsed = ec_parsed_get_last_child(state);
+ ec_parsed_del_child(state, child_parsed);
+ ec_parsed_free(child_parsed);
+ ret = EC_PARSED_NOMATCH;
+ }
}
+
ec_strvec_free(new_vec);
new_vec = NULL;
- ec_parsed_add_child(parsed, child_parsed);
- match_strvec = ec_strvec_ndup(strvec, 0, 1);
- if (match_strvec == NULL)
- goto fail;
- ec_parsed_set_match(parsed, gen_node, match_strvec);
-
- return parsed;
+ return ret;
fail:
ec_strvec_free(new_vec);
- ec_parsed_free(parsed);
-
- return NULL;
+ return ret;
}
static struct ec_completed *ec_node_sh_lex_complete(const struct ec_node *gen_node,
struct ec_node gen;
};
-static struct ec_parsed *ec_node_space_parse(const struct ec_node *gen_node,
- const struct ec_strvec *strvec)
+static int
+ec_node_space_parse(const struct ec_node *gen_node,
+ struct ec_parsed *state,
+ const struct ec_strvec *strvec)
{
- struct ec_parsed *parsed = NULL;
- struct ec_strvec *match_strvec;
const char *str;
size_t len = 0;
- parsed = ec_parsed();
- if (parsed == NULL)
- goto fail;
+ (void)state;
+ (void)gen_node;
if (ec_strvec_len(strvec) == 0)
- return parsed;
+ return EC_PARSED_NOMATCH;
str = ec_strvec_val(strvec, 0);
while (isspace(str[len]))
len++;
if (len == 0 || len != strlen(str))
- return parsed;
+ return EC_PARSED_NOMATCH;
- match_strvec = ec_strvec_ndup(strvec, 0, 1);
- if (match_strvec == NULL)
- goto fail;
-
- ec_parsed_set_match(parsed, gen_node, match_strvec);
-
- return parsed;
-
- fail:
- ec_parsed_free(parsed);
- return NULL;
+ return 1;
}
static struct ec_node_type ec_node_space_type = {
unsigned len;
};
-static struct ec_parsed *ec_node_str_parse(const struct ec_node *gen_node,
- const struct ec_strvec *strvec)
+static int
+ec_node_str_parse(const struct ec_node *gen_node,
+ struct ec_parsed *state,
+ const struct ec_strvec *strvec)
{
struct ec_node_str *node = (struct ec_node_str *)gen_node;
- struct ec_strvec *match_strvec;
- struct ec_parsed *parsed = NULL;
const char *str;
- parsed = ec_parsed();
- if (parsed == NULL)
- goto fail;
+ (void)state;
if (ec_strvec_len(strvec) == 0)
- return parsed;
+ return EC_PARSED_NOMATCH;
str = ec_strvec_val(strvec, 0);
if (strcmp(str, node->string) != 0)
- return parsed;
-
- match_strvec = ec_strvec_ndup(strvec, 0, 1);
- if (match_strvec == NULL)
- goto fail;
+ return EC_PARSED_NOMATCH;
- ec_parsed_set_match(parsed, gen_node, match_strvec);
-
- return parsed;
-
- fail:
- ec_parsed_free(parsed);
- return NULL;
+ return 1;
}
static struct ec_completed *ec_node_str_complete(const struct ec_node *gen_node,
};
struct parse_result {
- struct ec_parsed **parsed_table; /* list of parsed node */
- size_t parsed_table_len; /* number of parsed node */
- size_t len; /* consumed strings */
+ size_t parsed_len; /* number of parsed node */
+ size_t len; /* consumed strings */
};
-static int __ec_node_subset_parse(struct ec_node **table, size_t table_len,
- const struct ec_strvec *strvec,
- struct parse_result *out)
+/* recursively find the longest list of nodes that matches: the state is
+ * updated accordingly. */
+static int
+__ec_node_subset_parse(struct parse_result *out, struct ec_node **table,
+ size_t table_len, struct ec_parsed *state,
+ const struct ec_strvec *strvec)
{
struct ec_node **child_table;
- struct ec_parsed *child_parsed = NULL;
struct ec_strvec *childvec = NULL;
size_t i, j, len = 0;
struct parse_result best_result, result;
+ struct ec_parsed *best_parsed = NULL;
int ret;
if (table_len == 0)
return 0;
memset(&best_result, 0, sizeof(best_result));
- best_result.parsed_table =
- ec_calloc(table_len, sizeof(*best_result.parsed_table[0]));
- if (best_result.parsed_table == NULL)
- goto fail;
child_table = ec_calloc(table_len - 1, sizeof(*child_table));
- if (child_table == NULL)
+ if (child_table == NULL) {
+ ret = -ENOMEM;
goto fail;
+ }
for (i = 0; i < table_len; i++) {
/* try to parse elt i */
- child_parsed = ec_node_parse_strvec(table[i], strvec);
- if (child_parsed == NULL)
- goto fail;
-
- if (!ec_parsed_matches(child_parsed)) {
- ec_parsed_free(child_parsed);
- child_parsed = NULL;
+ ret = ec_node_parse_child(table[i], state, strvec);
+ if (ret == EC_PARSED_NOMATCH)
continue;
- }
+ else if (ret < 0)
+ goto fail;
/* build a new table without elt i */
for (j = 0; j < table_len; j++) {
child_table[j - 1] = table[j];
}
- /* build a new strvec */
- len = ec_parsed_len(child_parsed);
+ /* build a new strvec (ret is the len of matched strvec) */
+ len = ret;
childvec = ec_strvec_ndup(strvec, len,
ec_strvec_len(strvec) - len);
- if (childvec == NULL)
+ if (childvec == NULL) {
+ ret = -ENOMEM;
goto fail;
+ }
memset(&result, 0, sizeof(result));
-
- ret = __ec_node_subset_parse(child_table, table_len - 1,
- childvec, &result);
+ ret = __ec_node_subset_parse(&result, child_table,
+ table_len - 1, state, childvec);
ec_strvec_free(childvec);
childvec = NULL;
if (ret < 0)
goto fail;
/* if result is not the best, ignore */
- if (result.parsed_table_len + 1 <=
- best_result.parsed_table_len) {
- ec_parsed_free(child_parsed);
- child_parsed = NULL;
- for (j = 0; j < result.parsed_table_len; j++)
- ec_parsed_free(result.parsed_table[j]);
- ec_free(result.parsed_table);
+ if (result.parsed_len < best_result.parsed_len) {
+ struct ec_parsed *child_parsed;
+
memset(&result, 0, sizeof(result));
+ child_parsed = ec_parsed_get_last_child(state);
+ ec_parsed_del_child(state, child_parsed);
+ ec_parsed_free(child_parsed);
continue;
}
/* replace the previous best result */
- for (j = 0; j < best_result.parsed_table_len; j++)
- ec_parsed_free(best_result.parsed_table[j]);
- best_result.parsed_table[0] = child_parsed;
- child_parsed = NULL;
- for (j = 0; j < result.parsed_table_len; j++)
- best_result.parsed_table[j+1] = result.parsed_table[j];
- best_result.parsed_table_len = result.parsed_table_len + 1;
+ ec_parsed_free(best_parsed);
+ best_parsed = ec_parsed_get_last_child(state);
+ ec_parsed_del_child(state, best_parsed);
+
+ best_result.parsed_len = result.parsed_len + 1;
best_result.len = len + result.len;
- ec_free(result.parsed_table);
+
+ memset(&result, 0, sizeof(result));
}
*out = best_result;
ec_free(child_table);
+ if (best_parsed != NULL)
+ ec_parsed_add_child(state, best_parsed);
return 0;
fail:
- ec_parsed_free(child_parsed);
+ ec_parsed_free(best_parsed);
ec_strvec_free(childvec);
- for (j = 0; j < best_result.parsed_table_len; j++)
- ec_parsed_free(best_result.parsed_table[j]);
- ec_free(best_result.parsed_table);
ec_free(child_table);
- return -1;
+ return ret;
}
-static struct ec_parsed *ec_node_subset_parse(const struct ec_node *gen_node,
- const struct ec_strvec *strvec)
+static int
+ec_node_subset_parse(const struct ec_node *gen_node,
+ struct ec_parsed *state,
+ const struct ec_strvec *strvec)
{
struct ec_node_subset *node = (struct ec_node_subset *)gen_node;
struct ec_parsed *parsed = NULL;
struct parse_result result;
- struct ec_strvec *match_strvec;
- size_t i;
int ret;
memset(&result, 0, sizeof(result));
- parsed = ec_parsed();
- if (parsed == NULL)
- goto fail;
-
- ret = __ec_node_subset_parse(node->table, node->len, strvec, &result);
+ ret = __ec_node_subset_parse(&result, node->table,
+ node->len, state, strvec);
if (ret < 0)
goto fail;
/* if no child node matches, return a matching empty strvec */
- if (result.parsed_table_len == 0) {
- ec_free(result.parsed_table);
- match_strvec = ec_strvec();
- if (match_strvec == NULL)
- goto fail;
- ec_parsed_set_match(parsed, gen_node, match_strvec);
- return parsed;
- }
-
- for (i = 0; i < result.parsed_table_len; i++) {
- ec_parsed_add_child(parsed, result.parsed_table[i]);
- result.parsed_table[i] = NULL;
- }
- ec_free(result.parsed_table);
- result.parsed_table = NULL;
-
- match_strvec = ec_strvec_ndup(strvec, 0, result.len);
- if (match_strvec == NULL)
- goto fail;
-
- ec_parsed_set_match(parsed, gen_node, match_strvec);
+ if (result.parsed_len == 0)
+ return 0;
- return parsed;
+ return result.len;
fail:
- for (i = 0; i < result.parsed_table_len; i++)
- ec_parsed_free(result.parsed_table[i]);
- ec_free(result.parsed_table);
ec_parsed_free(parsed);
-
- return NULL;
+ return ret;
}
static struct ec_completed *
struct ec_node *child;
};
-static struct ec_parsed *ec_node_weakref_parse(const struct ec_node *gen_node,
- const struct ec_strvec *strvec)
+static int
+ec_node_weakref_parse(const struct ec_node *gen_node,
+ struct ec_parsed *state,
+ const struct ec_strvec *strvec)
{
struct ec_node_weakref *node = (struct ec_node_weakref *)gen_node;
- return ec_node_parse_strvec(node->child, strvec);
+ return ec_node_parse_child(node->child, state, strvec);
}
-static struct ec_completed *ec_node_weakref_complete(const struct ec_node *gen_node,
- const struct ec_strvec *strvec)
+static struct ec_completed *
+ec_node_weakref_complete(const struct ec_node *gen_node,
+ const struct ec_strvec *strvec)
{
struct ec_node_weakref *node = (struct ec_node_weakref *)gen_node;
#include <ecoli_node.h>
#include <ecoli_parsed.h>
+int ec_node_parse_child(struct ec_node *node, struct ec_parsed *state,
+ 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) {
+ ret = node->type->build(node);
+ if (ret < 0)
+ return ret;
+ }
+ }
+ node->flags |= EC_NODE_F_BUILT;
+
+ if (node->type->parse == NULL)
+ return -ENOTSUP;
+
+ child = ec_parsed();
+ if (child == NULL)
+ return -ENOMEM;
+
+ ec_parsed_add_child(state, child);
+ ret = node->type->parse(node, child, strvec);
+ if (ret == EC_PARSED_NOMATCH) {
+ ec_parsed_del_child(state, child);
+ assert(TAILQ_EMPTY(&child->children));
+ ec_parsed_free(child);
+ return ret;
+ } else if (ret < 0) {
+ return ret;
+ }
+
+ match_strvec = ec_strvec_ndup(strvec, 0, ret);
+ if (match_strvec == NULL)
+ return -ENOMEM;
+
+ child->node = node;
+ child->strvec = match_strvec;
+
+ return ret;
+}
+
+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);
+ if (ret < 0 && ret != EC_PARSED_NOMATCH) {
+ ec_parsed_free(parsed);
+ parsed = NULL;
+ } else 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;
+}
+
struct ec_parsed *ec_node_parse(struct ec_node *node, const char *str)
{
struct ec_strvec *strvec = NULL;
- struct ec_parsed *parsed;
+ struct ec_parsed *parsed = NULL;
errno = ENOMEM;
strvec = ec_strvec();
fail:
ec_strvec_free(strvec);
+ ec_parsed_free(parsed);
return NULL;
}
-struct ec_parsed *ec_node_parse_strvec(struct ec_node *node,
- const struct ec_strvec *strvec)
-{
- struct ec_parsed *parsed;
- 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;
- }
- }
- }
- node->flags |= EC_NODE_F_BUILT;
-
- if (node->type->parse == NULL) {
- errno = ENOTSUP;
- return NULL;
- }
-
- parsed = node->type->parse(node, strvec);
-
- return parsed;
-}
-
-
struct ec_parsed *ec_parsed(void)
{
struct ec_parsed *parsed = NULL;
return NULL;
}
-void ec_parsed_set_match(struct ec_parsed *parsed,
- const struct ec_node *node, struct ec_strvec *strvec)
-{
- parsed->node = node;
- parsed->strvec = strvec;
-}
-
void ec_parsed_free_children(struct ec_parsed *parsed)
{
struct ec_parsed *child;
struct ec_parsed *child;
const struct ec_strvec *vec;
size_t i;
- const char *id = "None", *typename = "None";
+ const char *id = "none", *typename = "none";
if (parsed->node != NULL) {
if (parsed->node->id != NULL)
fprintf(out, "%s<%s>",
i == 0 ? "" : ",",
ec_strvec_val(vec, i));
- fprintf(out, "]\n");
+ // XXX
+ if (!strcmp(typename, "int") || !strcmp(typename, "str"))
+ fprintf(out, "] <<<<<\n");
+ else
+ fprintf(out, "]\n");
TAILQ_FOREACH(child, &parsed->children, next)
__ec_parsed_dump(out, child, indent + 2);
struct ec_parsed *child)
{
TAILQ_INSERT_TAIL(&parsed->children, child, next);
+ child->parent = parsed;
}
void ec_parsed_del_child(struct ec_parsed *parsed,
struct ec_parsed *child)
{
TAILQ_REMOVE(&parsed->children, child, next);
+ child->parent = NULL;
+}
+
+struct ec_parsed *
+ec_parsed_get_last_child(struct ec_parsed *parsed)
+{
+ return TAILQ_LAST(&parsed->children, ec_parsed_list);
+}
+
+struct ec_parsed *ec_parsed_get_root(struct ec_parsed *parsed)
+{
+ if (parsed == NULL)
+ return NULL;
+
+ while (parsed->parent != NULL)
+ parsed = parsed->parent;
+
+ return parsed;
}
struct ec_parsed *ec_parsed_find_first(struct ec_parsed *parsed,
if (parsed == NULL)
return 0;
- if (parsed->node == NULL && TAILQ_EMPTY(&parsed->children))
+ if (parsed->node == NULL && TAILQ_EMPTY(&parsed->children)) // XXX both needed?
return 0;
return 1;
#include <sys/queue.h>
#include <sys/types.h>
+#include <limits.h>
#include <stdio.h>
struct ec_node;
struct ec_parsed {
TAILQ_ENTRY(ec_parsed) next;
struct ec_parsed_list children;
+ struct ec_parsed *parent;
const struct ec_node *node;
struct ec_strvec *strvec;
};
void ec_parsed_free(struct ec_parsed *parsed);
void ec_parsed_free_children(struct ec_parsed *parsed);
-const struct ec_strvec *ec_parsed_strvec(
- const struct ec_parsed *parsed);
-
-void ec_parsed_set_match(struct ec_parsed *parsed,
- const struct ec_node *node, struct ec_strvec *strvec);
+const struct ec_strvec *ec_parsed_strvec(const struct ec_parsed *parsed);
/* XXX we could use a cache to store possible completions or match: the
* cache would be per-node, and would be reset for each call to parse()
*/
struct ec_parsed *ec_node_parse(struct ec_node *node, const char *str);
-/* mostly internal to nodes */
-/* XXX it should not reset cache
- * ... not sure... it is used by tests */
struct ec_parsed *ec_node_parse_strvec(struct ec_node *node,
- const struct ec_strvec *strvec);
+ const struct ec_strvec *strvec);
+
+#define EC_PARSED_NOMATCH INT_MIN
+/* internal: used by nodes */
+/* return:
+ * EC_PARSED_NOMATCH (negative) if it does not match
+ * any other negative value (-errno) for other errors
+ * the number of matched strings in strvec
+ */
+int ec_node_parse_child(struct ec_node *node,
+ struct ec_parsed *state,
+ const struct ec_strvec *strvec);
void ec_parsed_add_child(struct ec_parsed *parsed,
- struct ec_parsed *child);
+ struct ec_parsed *child);
void ec_parsed_del_child(struct ec_parsed *parsed,
- struct ec_parsed *child);
+ struct ec_parsed *child);
+struct ec_parsed *ec_parsed_get_root(struct ec_parsed *parsed);
+struct ec_parsed *ec_parsed_get_last_child(struct ec_parsed *parsed);
void ec_parsed_dump(FILE *out, const struct ec_parsed *parsed);
struct ec_parsed *ec_parsed_find_first(struct ec_parsed *parsed,
}
p = ec_node_parse_strvec(tk, vec);
- /* XXX only for debug */
- ec_parsed_dump(stdout, p);
+ ec_parsed_dump(stdout, p); /* XXX only for debug */
if (p == NULL) {
ec_log(EC_LOG_ERR, "parsed is NULL\n");
}
/* complete at current cursor position */
line[rl_point] = '\0';
c = ec_node_complete(commands, line);
- ec_completed_dump(stdout, c);
+ //ec_completed_dump(stdout, c);
free(line);
if (c == NULL)
return 1;
if (cmdlist == NULL)
goto fail;
+
cmd = EC_NODE_SEQ(NULL,
ec_node_str(NULL, "hello"),
EC_NODE_OR("name",
if (ec_node_or_add(cmdlist, cmd) < 0)
goto fail;
+
cmd = EC_NODE_CMD(NULL, "good morning bob|bobby|michael [count]",
ec_node_int("count", 0, 10, 10));
if (cmd == NULL)
if (ec_node_or_add(cmdlist, cmd) < 0)
goto fail;
+
+ cmd = EC_NODE_CMD(NULL,
+ "buy potatoes,carrots,pumpkins");
+ if (cmd == NULL)
+ goto fail;
+ ec_keyval_set(ec_node_attrs(cmd), "help",
+ "buy some vegetables", NULL);
+ if (ec_node_or_add(cmdlist, cmd) < 0)
+ goto fail;
+
+
cmd = EC_NODE_SEQ(NULL,
ec_node_str(NULL, "bye")
);
if (ec_node_or_add(cmdlist, cmd) < 0)
goto fail;
+
commands = ec_node_sh_lex(NULL, cmdlist);
if (commands == NULL)
goto fail;
- ec_completed_tk -> ec_completed
- tk, gen_tk, token, ... -> node
- tokens -> input_str / input_strvec ?
+- use is_err() for errno in ptrs
dependencies
============