Small cmd progress
This commit is contained in:
+105
-57
@@ -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
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user