Small cmd progress
This commit is contained in:
+104
-56
@@ -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,40 +218,62 @@ 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);
|
||||||
|
|
||||||
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_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
|
||||||
|
|||||||
Reference in New Issue
Block a user