Add support for lists
This commit is contained in:
+60
-10
@@ -65,8 +65,9 @@ struct UCCmdTokenizer {
|
||||
int num_words;
|
||||
};
|
||||
|
||||
static void uc_cmd_tokenize(struct UCCmdTokenizer *t, const char *cmd)
|
||||
static void uc_cmd_tokenize(struct UCCmdTokenizer *t, const char *cmd, const char *delim)
|
||||
{
|
||||
|
||||
t->num_words = 0;
|
||||
t->cmd_copy = strdup(cmd);
|
||||
if (t->cmd_copy == NULL) {
|
||||
@@ -74,11 +75,15 @@ static void uc_cmd_tokenize(struct UCCmdTokenizer *t, const char *cmd)
|
||||
return;
|
||||
}
|
||||
|
||||
if (delim == NULL) {
|
||||
delim = "\r\n\t\v ";
|
||||
}
|
||||
|
||||
t->num_words = getfields(t->cmd_copy,
|
||||
t->cmd_words,
|
||||
ARRAY_SIZE(t->cmd_words),
|
||||
1,
|
||||
"\r\n\t\v ");
|
||||
delim);
|
||||
}
|
||||
|
||||
static void uc_cmd_tokenize_destroy(struct UCCmdTokenizer *t)
|
||||
@@ -147,6 +152,37 @@ struct UCCmdNode *uc_cmd_node_alloc(enum UCCmdType type, void *data, uint32_t fl
|
||||
return n;
|
||||
}
|
||||
|
||||
struct UCCmdNode *uc_cmd_node_create(const char *word)
|
||||
{
|
||||
struct UCCmdNode *node = NULL;
|
||||
|
||||
if (word[0] == '(') { //list (foo|bar|baz)
|
||||
struct UCCmdTokenizer t;
|
||||
|
||||
uc_cmd_tokenize(&t, word, "() |\t\v");
|
||||
if (t.num_words > 0) {
|
||||
struct UCCmdList *list = NULL;
|
||||
|
||||
for (int i = t.num_words - 1; i >= 0; i--) {
|
||||
struct UCCmdList *l = calloc(1, sizeof *l);
|
||||
|
||||
l->word = strdup(t.cmd_words[i]);
|
||||
l->next = list;
|
||||
list = l;
|
||||
}
|
||||
node = uc_cmd_node_alloc(UC_CMD_LIST, list, 0);
|
||||
}
|
||||
|
||||
uc_cmd_tokenize_destroy(&t);
|
||||
} else {
|
||||
node = uc_cmd_node_alloc(UC_CMD_KEYWORD, strdup(word), 0);
|
||||
}
|
||||
|
||||
|
||||
return node;
|
||||
|
||||
}
|
||||
|
||||
static int uc_cmd_node_match(const struct UCCmdNode *n, const char *word)
|
||||
{
|
||||
size_t word_len;
|
||||
@@ -168,15 +204,13 @@ static int uc_cmd_node_match(const struct UCCmdNode *n, const char *word)
|
||||
assert(l->word);
|
||||
|
||||
while (l) {
|
||||
if (strncmp(word, n->data, word_len) == 0) {
|
||||
if (strncmp(word, l->word, word_len) == 0) {
|
||||
return 1;
|
||||
}
|
||||
l = l->next;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
@@ -188,15 +222,28 @@ static struct UCCmdNode *uc_cmd_add(struct UCCmdNode *parent, const char *word)
|
||||
|
||||
assert(parent);
|
||||
|
||||
new_node = uc_cmd_node_create(word);
|
||||
if (new_node == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
while (*location) {
|
||||
struct UCCmdNode *n = *location;
|
||||
|
||||
if (new_node->type != UC_CMD_KEYWORD && n->type != UC_CMD_END) {
|
||||
//we don't support combinations of keywords and variables
|
||||
//at the same level.
|
||||
uc_cmd_node_dealloc(new_node);
|
||||
return NULL;
|
||||
}
|
||||
//TODO check for ambiguous word (e.g. add "short" when "shorter" already exists)
|
||||
if (uc_cmd_node_match(n, word)) {
|
||||
return *location;
|
||||
}
|
||||
location = &n->next;
|
||||
}
|
||||
|
||||
new_node = uc_cmd_node_alloc(UC_CMD_KEYWORD, strdup(word), 0);
|
||||
*location = new_node;
|
||||
|
||||
return new_node;
|
||||
@@ -208,7 +255,7 @@ int uc_cmd_install(struct UCCmdRunner *r, struct UCCmdDef *cmd)
|
||||
struct UCCmdNode *new_node;
|
||||
struct UCCmdTokenizer t;
|
||||
|
||||
uc_cmd_tokenize(&t, cmd->cmd);
|
||||
uc_cmd_tokenize(&t, cmd->cmd, NULL);
|
||||
if (t.num_words <= 0) {
|
||||
uc_cmd_tokenize_destroy(&t);
|
||||
return -1;
|
||||
@@ -216,6 +263,9 @@ int uc_cmd_install(struct UCCmdRunner *r, struct UCCmdDef *cmd)
|
||||
|
||||
for (int i = 0; i < t.num_words; i++) {
|
||||
node = uc_cmd_add(node, t.cmd_words[i]);
|
||||
if (node == NULL) {
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
|
||||
//TODO, check for duplicate command here.
|
||||
@@ -242,7 +292,7 @@ enum UCCmdRc uc_cmd_run(struct UCCmdRunner *r, const char *cmd_line)
|
||||
enum UCCmdRc rc = UC_CMDRC_ERROR;
|
||||
|
||||
//make a copy since getfields destroys the original string
|
||||
uc_cmd_tokenize(&t, cmd_line);
|
||||
uc_cmd_tokenize(&t, cmd_line, NULL);
|
||||
if (t.num_words <= 0) {
|
||||
uc_cmd_tokenize_destroy(&t);
|
||||
return rc;
|
||||
@@ -334,7 +384,7 @@ int main(int argc, char *argv[])
|
||||
};
|
||||
|
||||
struct UCCmdDef cmd3 = {
|
||||
"show empty bottles",
|
||||
"show empty (bottle|glass)",
|
||||
cmd3_cb,
|
||||
0,
|
||||
NULL
|
||||
@@ -347,7 +397,7 @@ int main(int argc, char *argv[])
|
||||
|
||||
uc_cmd_run(&r, "show all");
|
||||
uc_cmd_run(&r, "show empty");
|
||||
uc_cmd_run(&r, "show empty bottles");
|
||||
uc_cmd_run(&r, "show empty bottle");
|
||||
/*
|
||||
while (fgets(line,sizeof line, stdin)) {
|
||||
enum UCCmdRc rc = uc_cmd_run(&r, line);
|
||||
|
||||
Reference in New Issue
Block a user