diff --git a/src/cmd/cmd.c b/src/cmd/cmd.c index a556e4f..960ddd6 100644 --- a/src/cmd/cmd.c +++ b/src/cmd/cmd.c @@ -23,8 +23,6 @@ enum UCCmdRc { UC_CMDRC_ERROR, }; -struct UCCmdArgs; -typedef enum UCCmdRc (*UCCmdHandler)(const struct UCCmdArgs *args); enum UCCmdType { UC_CMD_ROOT = 1, @@ -44,6 +42,29 @@ struct UCCmdList { struct UCStrv descrs; }; +struct UCCmdArgs; +typedef enum UCCmdRc (*UCCmdHandler)(const struct UCCmdArgs *args); + +struct UCCmdDef { + const char *cmd; + const char *help; + UCCmdHandler callback; + uint32_t flags; +}; + +struct UCCmdArgs { + struct UCStrv argv; + const struct UCCmdDef *cmd; + void *ctx; +}; + +struct UCCmdRunner; +typedef int (*UCCmdRootExit)(struct UCCmdRunner *r, int current_id, void *ctx); +struct UCCmdRoot { + int node_id; + UCCmdRootExit exit_callback; +}; + /** * Command are broken into words and inserted into a tree. * the 3 commands: @@ -63,12 +84,14 @@ struct UCCmdList { * * END nodes are complete commands. Other child/next pointers will be nULL */ + struct UCCmdNode { enum UCCmdType type; union { struct UCCmdWord word; struct UCCmdList list; const struct UCCmdDef *cmd; + const struct UCCmdRootExit *root; } data; uint32_t flags; struct UCCmdNode *next; //next at same level @@ -77,18 +100,9 @@ struct UCCmdNode { }; struct UCCmdRunner { - struct UCCmdNode *root_node; + struct UCCmdNode *current_root; struct UCCmdNode _root; }; - -struct UCCmdDef { - const char *cmd; - const char *help; - UCCmdHandler callback; - uint32_t flags; -}; - - //max words in a single command #define UC_CMD_MAX_WORDS 32 @@ -98,14 +112,20 @@ struct UCCmdTokenizer { int num_words; }; -struct UCCmdArgs { - struct UCStrv argv; - const struct UCCmdDef *cmd; -}; void print_args(const struct UCStrv *args); +static int uc_str_empty(const char *str) +{ + while (*str) { + if (!isspace(*str++)) { + return 0; + } + } + return 0; +} + static int uc_cmd_type_is_variable(enum UCCmdType type) { @@ -148,7 +168,7 @@ void uc_cmd_runner_init(struct UCCmdRunner *r) { memset(r, 0, sizeof *r); - r->root_node = &r->_root; + r->current_root = &r->_root; r->_root.type = UC_CMD_ROOT; } @@ -178,8 +198,8 @@ uc_cmd_node_dealloc(struct UCCmdNode *n) void uc_cmd_runner_destroy(struct UCCmdRunner *r) { - uc_cmd_node_dealloc(r->root_node->child); - r->root_node->child = NULL; + uc_cmd_node_dealloc(r->_root.child); + r->current_root->child = NULL; } static struct UCCmdNode * @@ -198,40 +218,62 @@ uc_cmd_node_alloc(enum UCCmdType type, uint32_t flags) return n; } -static struct UCCmdNode * -uc_cmd_node_create(const char *word) +static struct +UCCmdNode *uc_cmd_node_create_list(const char *word) { struct UCCmdNode *node = NULL; - if (word[0] == '(') { //list (foo|bar|baz) - struct UCCmdTokenizer t; + struct UCCmdTokenizer t; - uc_cmd_tokenize(&t, word, "() |\t\v"); - if (t.num_words > 0) { - node = uc_cmd_node_alloc(UC_CMD_LIST, 0); + uc_cmd_tokenize(&t, word, "() |\t\v"); + if (t.num_words > 0) { + node = uc_cmd_node_alloc(UC_CMD_LIST, 0); + if (node != NULL) { uc_strv_init(&node->data.list.words); uc_strv_init(&node->data.list.descrs); - for (int i = 0 ; i < t.num_words; i++) { + for (int i = 0; i < t.num_words; i++) { uc_strv_append(&node->data.list.words, t.cmd_words[i]); } } + } - uc_cmd_tokenize_destroy(&t); - } else if (isupper(word[0])) { - node = uc_cmd_node_alloc(UC_CMD_STRING, 0); - node->data.word.word = strdup(word); - } else { - node = uc_cmd_node_alloc(UC_CMD_KEYWORD, 0); + uc_cmd_tokenize_destroy(&t); + return node; +} + +static struct UCCmdNode * +uc_cmd_node_create_word(enum UCCmdType type, const char *word) +{ + struct UCCmdNode *node; + + node = uc_cmd_node_alloc(type, 0); + if (node != NULL) { node->data.word.word = strdup(word); } return node; } +static struct UCCmdNode * +uc_cmd_node_create(const char *word) +{ + struct UCCmdNode *node; + + if (word[0] == '(') { //list (foo|bar|baz) + node = uc_cmd_node_create_list(word); + } else if (isupper(word[0])) { + node = uc_cmd_node_create_word(UC_CMD_STRING, word); + } else { + node = uc_cmd_node_create_word(UC_CMD_KEYWORD, word); + } + + return node; +} + static int -uc_cmd_node_match(const struct UCCmdNode *n, const char *word, struct UCStrv *args) +uc_cmd_node_match(const struct UCCmdNode *n, const char *word, struct UCStrv *matches) { size_t word_len; int found = 0; @@ -245,8 +287,8 @@ uc_cmd_node_match(const struct UCCmdNode *n, const char *word, struct UCStrv *ar if (n->type == UC_CMD_KEYWORD) { if (strncmp(word, n->data.word.word, word_len) == 0) { - if (args != NULL) { - uc_strv_append(args, n->data.word.word); + if (matches != NULL) { + uc_strv_append(matches, n->data.word.word); } found = 1; } @@ -258,15 +300,15 @@ uc_cmd_node_match(const struct UCCmdNode *n, const char *word, struct UCStrv *ar for(size_t i = 0; i < v->cnt; i++) { if (strncmp(word, v->strings[i], word_len) == 0) { - if (args != NULL) { - uc_strv_append(args, v->strings[i]); + if (matches != NULL) { + uc_strv_append(matches, v->strings[i]); } found = 1; } } } else if (n->type == UC_CMD_STRING) { - if (args != NULL) { - uc_strv_append(args, word); + if (matches != NULL) { + uc_strv_append(matches, word); } found = 1; } @@ -311,7 +353,8 @@ uc_cmd_add(struct UCCmdNode *parent, const char *word) return new_node; } -static int uc_cmd_node_add_help(struct UCCmdNode *node) +static int +uc_cmd_node_add_help(struct UCCmdNode *node) { struct UCCmdTokenizer t; int i; @@ -341,13 +384,15 @@ static int uc_cmd_node_add_help(struct UCCmdNode *node) if (node->type == UC_CMD_ROOT) { break; } + if (i < 0) { break; } if (node->type == UC_CMD_KEYWORD || node->type == UC_CMD_STRING) { - if (node->data.word.descr == NULL) { + if (node->data.word.descr == NULL && + !uc_str_empty(t.cmd_words[i])) { node->data.word.descr = strdup(t.cmd_words[i]); } i--; @@ -381,7 +426,7 @@ static int uc_cmd_node_add_help(struct UCCmdNode *node) int uc_cmd_install_noassert(struct UCCmdRunner *r, struct UCCmdDef *cmd) { - struct UCCmdNode *node = r->root_node; + struct UCCmdNode *node = r->current_root; struct UCCmdNode *new_node; struct UCCmdTokenizer t; int rc; @@ -419,21 +464,19 @@ uc_cmd_install_noassert(struct UCCmdRunner *r, struct UCCmdDef *cmd) return rc; } -int +void uc_cmd_install(struct UCCmdRunner *r, struct UCCmdDef *cmd) { int rc; rc = uc_cmd_install_noassert(r, cmd); UC_ASSERT(rc == 0); - - return rc; } enum UCCmdRc uc_cmd_find(struct UCCmdNode *first, const struct UCCmdTokenizer *t, - struct UCStrv *args, + struct UCStrv *matches, struct UCCmdNode **result) { struct UCCmdNode *node = first; @@ -444,7 +487,7 @@ uc_cmd_find(struct UCCmdNode *first, int n_found = 0; while (node) { - if (uc_cmd_node_match(node, t->cmd_words[i], args)) { + if (uc_cmd_node_match(node, t->cmd_words[i], matches)) { if (n_found == 0) { //keep the 1. matched found = node; @@ -476,11 +519,11 @@ uc_cmd_find(struct UCCmdNode *first, enum UCCmdRc uc_cmd_parse_and_find(struct UCCmdRunner *r, const char *cmd_line, - struct UCStrv *args, + struct UCStrv *matches, struct UCCmdNode **result) { - struct UCCmdNode *node = r->root_node->child; + struct UCCmdNode *node = r->current_root->child; struct UCCmdTokenizer t; enum UCCmdRc rc = UC_CMDRC_ERROR; @@ -491,7 +534,7 @@ uc_cmd_parse_and_find(struct UCCmdRunner *r, const char *cmd_line, //match the commands towards the command tree // - rc = uc_cmd_find(node, &t, args, result); + rc = uc_cmd_find(node, &t, matches, result); } uc_cmd_tokenize_destroy(&t); @@ -543,7 +586,6 @@ uc_cmd_complete(struct UCCmdRunner *r, const char *cmd_line, struct UCStrv *comp } node = node->next; } - } return rc; @@ -552,11 +594,11 @@ uc_cmd_complete(struct UCCmdRunner *r, const char *cmd_line, struct UCStrv *comp enum UCCmdRc -uc_cmd_run(struct UCCmdRunner *r, const char *cmd_line) +uc_cmd_run_ctx(struct UCCmdRunner *r, const char *cmd_line, void *ctx) { struct UCCmdArgs args = { .argv = UC_STRV_INITIALIZER, - .cmd = NULL, + .ctx = ctx, }; struct UCCmdNode *found = NULL; @@ -588,6 +630,12 @@ uc_cmd_run(struct UCCmdRunner *r, const char *cmd_line) return rc; } +enum UCCmdRc +uc_cmd_run(struct UCCmdRunner *r, const char *cmd_line) +{ + return uc_cmd_run_ctx(r, cmd_line, NULL); +} + void print_args(const struct UCStrv *args) { @@ -670,7 +718,7 @@ int main(int argc, char *argv[]) struct UCCmdRunner r; struct UCCmdDef cmd1 = { "show all", - " \nEverything\n", + "show stuff\nEverything\n", cmd1_cb, 0, NULL @@ -678,8 +726,8 @@ int main(int argc, char *argv[]) struct UCCmdDef cmd2 = { "show empty", - "Show parameter\nAll empty\n", - cmd2_cb, + " \n everyhing that's empty\n", + cmd2_cb, 0, NULL };