Small cmd progress

This commit is contained in:
Nils O. Selåsdal
2016-03-07 22:18:15 +01:00
parent 28d56d64f6
commit fae2a60203
+98 -50
View File
@@ -23,8 +23,6 @@ enum UCCmdRc {
UC_CMDRC_ERROR, UC_CMDRC_ERROR,
}; };
struct UCCmdArgs;
typedef enum UCCmdRc (*UCCmdHandler)(const struct UCCmdArgs *args);
enum UCCmdType { enum UCCmdType {
UC_CMD_ROOT = 1, UC_CMD_ROOT = 1,
@@ -44,6 +42,29 @@ struct UCCmdList {
struct UCStrv descrs; 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. * Command are broken into words and inserted into a tree.
* the 3 commands: * the 3 commands:
@@ -63,12 +84,14 @@ struct UCCmdList {
* *
* END nodes are complete commands. Other child/next pointers will be nULL * END nodes are complete commands. Other child/next pointers will be nULL
*/ */
struct UCCmdNode { struct UCCmdNode {
enum UCCmdType type; enum UCCmdType type;
union { union {
struct UCCmdWord word; struct UCCmdWord word;
struct UCCmdList list; struct UCCmdList list;
const struct UCCmdDef *cmd; const struct UCCmdDef *cmd;
const struct UCCmdRootExit *root;
} data; } data;
uint32_t flags; uint32_t flags;
struct UCCmdNode *next; //next at same level struct UCCmdNode *next; //next at same level
@@ -77,18 +100,9 @@ struct UCCmdNode {
}; };
struct UCCmdRunner { struct UCCmdRunner {
struct UCCmdNode *root_node; struct UCCmdNode *current_root;
struct UCCmdNode _root; struct UCCmdNode _root;
}; };
struct UCCmdDef {
const char *cmd;
const char *help;
UCCmdHandler callback;
uint32_t flags;
};
//max words in a single command //max words in a single command
#define UC_CMD_MAX_WORDS 32 #define UC_CMD_MAX_WORDS 32
@@ -98,14 +112,20 @@ struct UCCmdTokenizer {
int num_words; int num_words;
}; };
struct UCCmdArgs {
struct UCStrv argv;
const struct UCCmdDef *cmd;
};
void void
print_args(const struct UCStrv *args); 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 static int
uc_cmd_type_is_variable(enum UCCmdType type) uc_cmd_type_is_variable(enum UCCmdType type)
{ {
@@ -148,7 +168,7 @@ void
uc_cmd_runner_init(struct UCCmdRunner *r) uc_cmd_runner_init(struct UCCmdRunner *r)
{ {
memset(r, 0, sizeof *r); memset(r, 0, sizeof *r);
r->root_node = &r->_root; r->current_root = &r->_root;
r->_root.type = UC_CMD_ROOT; r->_root.type = UC_CMD_ROOT;
} }
@@ -178,8 +198,8 @@ uc_cmd_node_dealloc(struct UCCmdNode *n)
void void
uc_cmd_runner_destroy(struct UCCmdRunner *r) uc_cmd_runner_destroy(struct UCCmdRunner *r)
{ {
uc_cmd_node_dealloc(r->root_node->child); uc_cmd_node_dealloc(r->_root.child);
r->root_node->child = NULL; r->current_root->child = NULL;
} }
static struct UCCmdNode * static struct UCCmdNode *
@@ -198,17 +218,17 @@ uc_cmd_node_alloc(enum UCCmdType type, uint32_t flags)
return n; return n;
} }
static struct UCCmdNode * static struct
uc_cmd_node_create(const char *word) UCCmdNode *uc_cmd_node_create_list(const char *word)
{ {
struct UCCmdNode *node = NULL; struct UCCmdNode *node = NULL;
if (word[0] == '(') { //list (foo|bar|baz)
struct UCCmdTokenizer t; struct UCCmdTokenizer t;
uc_cmd_tokenize(&t, word, "() |\t\v"); uc_cmd_tokenize(&t, word, "() |\t\v");
if (t.num_words > 0) { if (t.num_words > 0) {
node = uc_cmd_node_alloc(UC_CMD_LIST, 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.words);
uc_strv_init(&node->data.list.descrs); uc_strv_init(&node->data.list.descrs);
@@ -217,21 +237,43 @@ uc_cmd_node_create(const char *word)
uc_strv_append(&node->data.list.words, t.cmd_words[i]); uc_strv_append(&node->data.list.words, t.cmd_words[i]);
} }
} }
}
uc_cmd_tokenize_destroy(&t); uc_cmd_tokenize_destroy(&t);
} else if (isupper(word[0])) { return node;
node = uc_cmd_node_alloc(UC_CMD_STRING, 0); }
node->data.word.word = strdup(word);
} else { static struct UCCmdNode *
node = uc_cmd_node_alloc(UC_CMD_KEYWORD, 0); 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); node->data.word.word = strdup(word);
} }
return node; 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 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; size_t word_len;
int found = 0; 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 (n->type == UC_CMD_KEYWORD) {
if (strncmp(word, n->data.word.word, word_len) == 0) { if (strncmp(word, n->data.word.word, word_len) == 0) {
if (args != NULL) { if (matches != NULL) {
uc_strv_append(args, n->data.word.word); uc_strv_append(matches, n->data.word.word);
} }
found = 1; 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++) { for(size_t i = 0; i < v->cnt; i++) {
if (strncmp(word, v->strings[i], word_len) == 0) { if (strncmp(word, v->strings[i], word_len) == 0) {
if (args != NULL) { if (matches != NULL) {
uc_strv_append(args, v->strings[i]); uc_strv_append(matches, v->strings[i]);
} }
found = 1; found = 1;
} }
} }
} else if (n->type == UC_CMD_STRING) { } else if (n->type == UC_CMD_STRING) {
if (args != NULL) { if (matches != NULL) {
uc_strv_append(args, word); uc_strv_append(matches, word);
} }
found = 1; found = 1;
} }
@@ -311,7 +353,8 @@ uc_cmd_add(struct UCCmdNode *parent, const char *word)
return new_node; 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; struct UCCmdTokenizer t;
int i; int i;
@@ -341,13 +384,15 @@ static int uc_cmd_node_add_help(struct UCCmdNode *node)
if (node->type == UC_CMD_ROOT) { if (node->type == UC_CMD_ROOT) {
break; break;
} }
if (i < 0) { if (i < 0) {
break; break;
} }
if (node->type == UC_CMD_KEYWORD || if (node->type == UC_CMD_KEYWORD ||
node->type == UC_CMD_STRING) { 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]); node->data.word.descr = strdup(t.cmd_words[i]);
} }
i--; i--;
@@ -381,7 +426,7 @@ static int uc_cmd_node_add_help(struct UCCmdNode *node)
int int
uc_cmd_install_noassert(struct UCCmdRunner *r, struct UCCmdDef *cmd) 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 UCCmdNode *new_node;
struct UCCmdTokenizer t; struct UCCmdTokenizer t;
int rc; int rc;
@@ -419,21 +464,19 @@ uc_cmd_install_noassert(struct UCCmdRunner *r, struct UCCmdDef *cmd)
return rc; return rc;
} }
int void
uc_cmd_install(struct UCCmdRunner *r, struct UCCmdDef *cmd) uc_cmd_install(struct UCCmdRunner *r, struct UCCmdDef *cmd)
{ {
int rc; int rc;
rc = uc_cmd_install_noassert(r, cmd); rc = uc_cmd_install_noassert(r, cmd);
UC_ASSERT(rc == 0); UC_ASSERT(rc == 0);
return rc;
} }
enum UCCmdRc enum UCCmdRc
uc_cmd_find(struct UCCmdNode *first, uc_cmd_find(struct UCCmdNode *first,
const struct UCCmdTokenizer *t, const struct UCCmdTokenizer *t,
struct UCStrv *args, struct UCStrv *matches,
struct UCCmdNode **result) struct UCCmdNode **result)
{ {
struct UCCmdNode *node = first; struct UCCmdNode *node = first;
@@ -444,7 +487,7 @@ uc_cmd_find(struct UCCmdNode *first,
int n_found = 0; int n_found = 0;
while (node) { 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) { if (n_found == 0) {
//keep the 1. matched //keep the 1. matched
found = node; found = node;
@@ -476,11 +519,11 @@ uc_cmd_find(struct UCCmdNode *first,
enum UCCmdRc enum UCCmdRc
uc_cmd_parse_and_find(struct UCCmdRunner *r, const char *cmd_line, uc_cmd_parse_and_find(struct UCCmdRunner *r, const char *cmd_line,
struct UCStrv *args, struct UCStrv *matches,
struct UCCmdNode **result) struct UCCmdNode **result)
{ {
struct UCCmdNode *node = r->root_node->child; struct UCCmdNode *node = r->current_root->child;
struct UCCmdTokenizer t; struct UCCmdTokenizer t;
enum UCCmdRc rc = UC_CMDRC_ERROR; 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 //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); 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; node = node->next;
} }
} }
return rc; return rc;
@@ -552,11 +594,11 @@ uc_cmd_complete(struct UCCmdRunner *r, const char *cmd_line, struct UCStrv *comp
enum UCCmdRc 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 = { struct UCCmdArgs args = {
.argv = UC_STRV_INITIALIZER, .argv = UC_STRV_INITIALIZER,
.cmd = NULL, .ctx = ctx,
}; };
struct UCCmdNode *found = NULL; struct UCCmdNode *found = NULL;
@@ -588,6 +630,12 @@ uc_cmd_run(struct UCCmdRunner *r, const char *cmd_line)
return rc; 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) void print_args(const struct UCStrv *args)
{ {
@@ -670,7 +718,7 @@ int main(int argc, char *argv[])
struct UCCmdRunner r; struct UCCmdRunner r;
struct UCCmdDef cmd1 = { struct UCCmdDef cmd1 = {
"show all", "show all",
" \nEverything\n", "show stuff\nEverything\n",
cmd1_cb, cmd1_cb,
0, 0,
NULL NULL
@@ -678,7 +726,7 @@ int main(int argc, char *argv[])
struct UCCmdDef cmd2 = { struct UCCmdDef cmd2 = {
"show empty", "show empty",
"Show parameter\nAll empty\n", " \n everyhing that's empty\n",
cmd2_cb, cmd2_cb,
0, 0,
NULL NULL