From d4619418f0b1ba8acbc7f8edab908c0b10f07a41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Tue, 8 Dec 2015 23:59:39 +0100 Subject: [PATCH] Add support for lists --- src/cmd/cmd.c | 72 +++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 61 insertions(+), 11 deletions(-) diff --git a/src/cmd/cmd.c b/src/cmd/cmd.c index 59aa421..cf83793 100644 --- a/src/cmd/cmd.c +++ b/src/cmd/cmd.c @@ -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; } @@ -187,16 +221,29 @@ static struct UCCmdNode *uc_cmd_add(struct UCCmdNode *parent, const char *word) struct UCCmdNode **location = &parent->child; 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);