#include <ecoli_malloc.h>
#include <ecoli_log.h>
+#include <ecoli_strvec.h>
#include <ecoli_tk.h>
#include <ecoli_tk_or.h>
#include <ecoli_tk_str.h>
#include <ecoli_test.h>
+struct ec_tk_or {
+ struct ec_tk gen;
+ struct ec_tk **table;
+ unsigned int len;
+};
+
static struct ec_parsed_tk *ec_tk_or_parse(const struct ec_tk *gen_tk,
- const char *str)
+ const struct ec_strvec *strvec)
{
struct ec_tk_or *tk = (struct ec_tk_or *)gen_tk;
- struct ec_parsed_tk *parsed_tk, *child_parsed_tk;
+ struct ec_parsed_tk *parsed_tk, *child_parsed_tk = NULL;
+ struct ec_strvec *match_strvec;
unsigned int i;
- parsed_tk = ec_parsed_tk_new(gen_tk);
+ parsed_tk = ec_parsed_tk_new();
if (parsed_tk == NULL)
- return NULL;
+ goto fail;
for (i = 0; i < tk->len; i++) {
- child_parsed_tk = ec_tk_parse(tk->table[i], str);
- if (child_parsed_tk != NULL)
+ child_parsed_tk = ec_tk_parse_tokens(tk->table[i], strvec);
+ if (child_parsed_tk == NULL)
+ goto fail;
+ if (ec_parsed_tk_matches(child_parsed_tk))
break;
+ ec_parsed_tk_free(child_parsed_tk);
+ child_parsed_tk = NULL;
}
- if (child_parsed_tk == NULL)
+ /* no match */
+ if (i == tk->len)
+ return parsed_tk;
+
+ match_strvec = ec_strvec_dup(child_parsed_tk->strvec);
+ if (match_strvec == NULL)
goto fail;
+ ec_parsed_tk_set_match(parsed_tk, gen_tk, match_strvec);
ec_parsed_tk_add_child(parsed_tk, child_parsed_tk);
- parsed_tk->str = ec_strndup(child_parsed_tk->str,
- strlen(child_parsed_tk->str));
-
return parsed_tk;
fail:
+ ec_parsed_tk_free(child_parsed_tk);
ec_parsed_tk_free(parsed_tk);
return NULL;
}
static struct ec_completed_tk *ec_tk_or_complete(const struct ec_tk *gen_tk,
- const char *str)
+ const struct ec_strvec *strvec)
{
struct ec_tk_or *tk = (struct ec_tk_or *)gen_tk;
- struct ec_completed_tk *completed_tk = NULL, *child_completed_tk;
+ struct ec_completed_tk *completed_tk, *child_completed_tk;
size_t n;
+ completed_tk = ec_completed_tk_new();
+ if (completed_tk == NULL)
+ return NULL;
+
for (n = 0; n < tk->len; n++) {
- child_completed_tk = ec_tk_complete(tk->table[n], str);
+ child_completed_tk = ec_tk_complete_tokens(tk->table[n],
+ strvec);
- if (child_completed_tk == NULL)
+ if (child_completed_tk == NULL) // XXX fail instead?
continue;
- completed_tk = ec_completed_tk_merge(completed_tk,
- child_completed_tk);
+ ec_completed_tk_merge(completed_tk, child_completed_tk);
}
return completed_tk;
}
static struct ec_tk_ops ec_tk_or_ops = {
+ .typename = "or",
.parse = ec_tk_or_parse,
.complete = ec_tk_or_complete,
.free_priv = ec_tk_or_free_priv,
struct ec_tk_or *tk = NULL;
struct ec_tk *child;
va_list ap;
+ int fail = 0;
va_start(ap, id);
for (child = va_arg(ap, struct ec_tk *);
child != EC_TK_ENDLIST;
child = va_arg(ap, struct ec_tk *)) {
- if (child == NULL)
- goto fail;
- ec_tk_or_add(&tk->gen, child);
+ /* on error, don't quit the loop to avoid leaks */
+ if (fail == 1 || child == NULL ||
+ ec_tk_or_add(&tk->gen, child) < 0) {
+ fail = 1;
+ ec_tk_free(child);
+ }
}
+ if (fail == 1)
+ goto fail;
+
va_end(ap);
return &tk->gen;
table[tk->len] = child;
tk->len ++;
+ child->parent = gen_tk;
+ TAILQ_INSERT_TAIL(&gen_tk->children, child, next);
+
return 0;
}
struct ec_tk *tk;
int ret = 0;
- /* all inputs starting with foo should match */
tk = ec_tk_or_new_list(NULL,
ec_tk_str_new(NULL, "foo"),
ec_tk_str_new(NULL, "bar"),
ec_log(EC_LOG_ERR, "cannot create tk\n");
return -1;
}
- ret |= EC_TEST_CHECK_TK_PARSE(tk, "foo", "foo");
- ret |= EC_TEST_CHECK_TK_PARSE(tk, "fooxxx", "foo");
- ret |= EC_TEST_CHECK_TK_PARSE(tk, "bar", "bar");
- ret |= EC_TEST_CHECK_TK_PARSE(tk, "oo", NULL);
+ ret |= EC_TEST_CHECK_TK_PARSE(tk, 1, "foo", EC_TK_ENDLIST);
+ ret |= EC_TEST_CHECK_TK_PARSE(tk, 1, "bar", EC_TK_ENDLIST);
+ ret |= EC_TEST_CHECK_TK_PARSE(tk, 1, "foo", "bar", EC_TK_ENDLIST);
+ ret |= EC_TEST_CHECK_TK_PARSE(tk, -1, " ", EC_TK_ENDLIST);
+ ret |= EC_TEST_CHECK_TK_PARSE(tk, -1, "foox", EC_TK_ENDLIST);
+ ret |= EC_TEST_CHECK_TK_PARSE(tk, -1, "toto", EC_TK_ENDLIST);
+ ret |= EC_TEST_CHECK_TK_PARSE(tk, -1, "", EC_TK_ENDLIST);
ec_tk_free(tk);
/* test completion */
ec_log(EC_LOG_ERR, "cannot create tk\n");
return -1;
}
- ret |= EC_TEST_CHECK_TK_COMPLETE(tk, "", "");
- ret |= EC_TEST_CHECK_TK_COMPLETE(tk, "f", "oo");
- ret |= EC_TEST_CHECK_TK_COMPLETE(tk, "b", "ar");
- ret |= EC_TEST_CHECK_TK_COMPLETE(tk, "t", "");
- ret |= EC_TEST_CHECK_TK_COMPLETE(tk, "to", "to");
- ret |= EC_TEST_CHECK_TK_COMPLETE(tk, "x", NULL);
- ret |= EC_TEST_CHECK_TK_COMPLETE_LIST(tk, "",
- "foo", "bar", "bar2", "toto", "titi", EC_TK_ENDLIST);
- ret |= EC_TEST_CHECK_TK_COMPLETE_LIST(tk, "f",
- "oo", EC_TK_ENDLIST);
- ret |= EC_TEST_CHECK_TK_COMPLETE_LIST(tk, "b",
- "ar", "ar2", EC_TK_ENDLIST);
- ret |= EC_TEST_CHECK_TK_COMPLETE_LIST(tk, "t",
- "oto", "iti", EC_TK_ENDLIST);
+ ret |= EC_TEST_CHECK_TK_COMPLETE(tk,
+ "", EC_TK_ENDLIST,
+ "foo", "bar", "bar2", "toto", "titi", EC_TK_ENDLIST,
+ "");
+ ret |= EC_TEST_CHECK_TK_COMPLETE(tk,
+ "f", EC_TK_ENDLIST,
+ "oo", EC_TK_ENDLIST,
+ "oo");
+ ret |= EC_TEST_CHECK_TK_COMPLETE(tk,
+ "b", EC_TK_ENDLIST,
+ "ar", "ar2", EC_TK_ENDLIST,
+ "ar");
+ ret |= EC_TEST_CHECK_TK_COMPLETE(tk,
+ "bar", EC_TK_ENDLIST,
+ "", "2", EC_TK_ENDLIST,
+ "");
+ ret |= EC_TEST_CHECK_TK_COMPLETE(tk,
+ "t", EC_TK_ENDLIST,
+ "oto", "iti", EC_TK_ENDLIST,
+ "");
+ ret |= EC_TEST_CHECK_TK_COMPLETE(tk,
+ "to", EC_TK_ENDLIST,
+ "to", EC_TK_ENDLIST,
+ "to");
+ ret |= EC_TEST_CHECK_TK_COMPLETE(tk,
+ "x", EC_TK_ENDLIST,
+ EC_TK_ENDLIST,
+ "");
ec_tk_free(tk);
return ret;