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,
};
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,17 +218,17 @@ 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;
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);
@@ -217,21 +237,43 @@ uc_cmd_node_create(const char *word)
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);
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,7 +726,7 @@ int main(int argc, char *argv[])
struct UCCmdDef cmd2 = {
"show empty",
"Show parameter\nAll empty\n",
" \n everyhing that's empty\n",
cmd2_cb,
0,
NULL