IMplement help system. Though it need refactoring.

This commit is contained in:
Nils O. Selåsdal
2015-12-15 22:26:59 +01:00
parent f107898919
commit 433fdd0a4b
+168 -34
View File
@@ -68,11 +68,12 @@ struct UCCmdNode {
union { union {
struct UCCmdWord word; struct UCCmdWord word;
struct UCCmdList list; struct UCCmdList list;
struct UCCmdDef *cmd; const struct UCCmdDef *cmd;
} data; } data;
uint32_t flags; uint32_t flags;
struct UCCmdNode *next; //next at same level struct UCCmdNode *next; //next at same level
struct UCCmdNode *child; struct UCCmdNode *child;
struct UCCmdNode *parent;
}; };
struct UCCmdRunner { struct UCCmdRunner {
@@ -99,17 +100,21 @@ struct UCCmdTokenizer {
struct UCCmdArgs { struct UCCmdArgs {
struct UCStrv argv; struct UCStrv argv;
struct UCCmdDef *cmd; const struct UCCmdDef *cmd;
}; };
void print_args(const struct UCStrv *args); void
static int uc_cmd_type_is_variable(enum UCCmdType type) print_args(const struct UCStrv *args);
static int
uc_cmd_type_is_variable(enum UCCmdType type)
{ {
return type == UC_CMD_LIST || return type == UC_CMD_LIST ||
type == UC_CMD_STRING; type == UC_CMD_STRING;
} }
static void uc_cmd_tokenize(struct UCCmdTokenizer *t, const char *cmd, const char *delim) static void
uc_cmd_tokenize(struct UCCmdTokenizer *t, const char *cmd, const char *delim)
{ {
t->num_words = 0; t->num_words = 0;
@@ -144,13 +149,14 @@ uc_cmd_runner_init(struct UCCmdRunner *r)
{ {
memset(r, 0, sizeof *r); memset(r, 0, sizeof *r);
r->root_node = &r->_root; r->root_node = &r->_root;
r->_root.type = UC_CMD_KEYWORD; r->_root.type = UC_CMD_ROOT;
} }
void void
uc_cmd_node_dealloc(struct UCCmdNode *n) uc_cmd_node_dealloc(struct UCCmdNode *n)
{ {
struct UCCmdNode *next; struct UCCmdNode *next;
while (n) { while (n) {
uc_cmd_node_dealloc(n->child); uc_cmd_node_dealloc(n->child);
next = n->next; next = n->next;
@@ -281,6 +287,7 @@ uc_cmd_add(struct UCCmdNode *parent, const char *word)
if (new_node == NULL) { if (new_node == NULL) {
return NULL; return NULL;
} }
new_node->parent = parent;
while (*iter) { while (*iter) {
struct UCCmdNode *n = *iter; struct UCCmdNode *n = *iter;
@@ -304,12 +311,80 @@ 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)
{
struct UCCmdTokenizer t;
int i;
if (node->data.cmd->help == NULL) {
//allow helpless commands
return 0;
}
if (node->type != UC_CMD_END) {
return -10;
}
uc_cmd_tokenize(&t, node->data.cmd->help, "\n");
if (t.num_words <= 0) {
uc_cmd_tokenize_destroy(&t);
return -11;
}
i = t.num_words - 1;
//we have the last node in the tree
//Walk it up towards the root(backwards) and fill
//in help texts where it's missing.
while (node->parent) {
node = node->parent;
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) {
node->data.word.descr = strdup(t.cmd_words[i]);
}
i--;
} else if (node->type == UC_CMD_LIST) {
if (node->data.list.descrs.cnt == 0) {
for (int k = (int)node->data.list.words.cnt -1; k >= 0; k++) {
if (i < 0) {
break;
}
uc_strv_append(&node->data.list.descrs, t.cmd_words[i]);
i--;
}
} else {
i -= (int)node->data.list.words.cnt;
}
}
}
uc_cmd_tokenize_destroy(&t);
if (node->type != UC_CMD_ROOT || i != -1) {
//we didn't consume all the help tokens, so the
//command definition is screwd up
return -20;
}
return 0;
}
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->root_node;
struct UCCmdNode *new_node; struct UCCmdNode *new_node;
struct UCCmdTokenizer t; struct UCCmdTokenizer t;
int rc;
uc_cmd_tokenize(&t, cmd->cmd, NULL); uc_cmd_tokenize(&t, cmd->cmd, NULL);
if (t.num_words <= 0) { if (t.num_words <= 0) {
@@ -333,13 +408,15 @@ uc_cmd_install_noassert(struct UCCmdRunner *r, struct UCCmdDef *cmd)
return -1; return -1;
} }
new_node->data.cmd = cmd; new_node->data.cmd = cmd;
new_node->next = node->child; new_node->next = node->child;
node->child = new_node; node->child = new_node;
new_node->parent = node;
rc = uc_cmd_node_add_help(new_node);
uc_cmd_tokenize_destroy(&t); uc_cmd_tokenize_destroy(&t);
return 0; return rc;
} }
int int
@@ -360,11 +437,11 @@ uc_cmd_find(struct UCCmdNode *first,
struct UCCmdNode **result) struct UCCmdNode **result)
{ {
struct UCCmdNode *node = first; struct UCCmdNode *node = first;
struct UCCmdNode *found = NULL;
enum UCCmdRc rc = UC_CMDRC_NOT_FOUND; enum UCCmdRc rc = UC_CMDRC_NOT_FOUND;
for (int i = 0; i < t->num_words && node; i++) { for (int i = 0; i < t->num_words && node; i++) {
int n_found = 0; int n_found = 0;
struct UCCmdNode *found = NULL;
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], args)) {
@@ -387,9 +464,9 @@ uc_cmd_find(struct UCCmdNode *first,
} }
} }
*result = node; *result = found;
if (node == NULL) { if (found == NULL) {
rc = UC_CMDRC_NOT_FOUND; rc = UC_CMDRC_NOT_FOUND;
} }
@@ -423,42 +500,57 @@ uc_cmd_parse_and_find(struct UCCmdRunner *r, const char *cmd_line,
} }
enum UCCmdRc enum UCCmdRc
uc_cmd_complete(struct UCCmdRunner *r, const char *cmd_line) uc_cmd_help(struct UCCmdRunner *r, const char *cmd_line, struct UCStrv *completions)
{ {
struct UCCmdNode *found = NULL;
enum UCCmdRc rc;
struct UCStrv completions = UC_STRV_INITIALIZER; rc = uc_cmd_parse_and_find(r, cmd_line, NULL, &found);
if (rc == UC_CMDRC_OK) {
struct UCCmdNode *node = found;
if (node->type == UC_CMD_LIST) {
uc_strv_append_all(completions, &node->data.list.descrs, 1);
} else if (node->type == UC_CMD_STRING ||
node->type == UC_CMD_KEYWORD) {
if (node->data.word.descr != NULL) {
uc_strv_append(completions, node->data.word.descr);
}
}
}
return rc;
}
enum UCCmdRc
uc_cmd_complete(struct UCCmdRunner *r, const char *cmd_line, struct UCStrv *completions)
{
struct UCCmdNode *found = NULL; struct UCCmdNode *found = NULL;
enum UCCmdRc rc; enum UCCmdRc rc;
rc = uc_cmd_parse_and_find(r, cmd_line, NULL, &found); rc = uc_cmd_parse_and_find(r, cmd_line, NULL, &found);
if (rc != UC_CMDRC_NOT_FOUND && found != NULL) { if (rc != UC_CMDRC_NOT_FOUND && found != NULL) {
struct UCCmdNode *node = found; struct UCCmdNode *node = found->child;
while (node) { while (node) {
if (node->type == UC_CMD_END) { if (node->type == UC_CMD_END) {
uc_strv_append(&completions, "<CR>"); uc_strv_append(completions, "<CR>");
} else if (node->type == UC_CMD_LIST) { } else if (node->type == UC_CMD_LIST) {
uc_strv_append_all(&completions, &node->data.list.words, 1); uc_strv_append_all(completions, &node->data.list.words, 1);
} else if (node->type == UC_CMD_STRING || } else if (node->type == UC_CMD_STRING ||
node->type == UC_CMD_KEYWORD) { node->type == UC_CMD_KEYWORD) {
uc_strv_append(&completions, node->data.word.word); uc_strv_append(completions, node->data.word.word);
} }
node = node->next; node = node->next;
} }
printf("Possible completions for '%s'\n", cmd_line); }
print_args(&completions);
} else {
printf("No possible completions\n");
}
uc_strv_destroy(&completions);
return rc; return rc;
} }
enum UCCmdRc enum UCCmdRc
uc_cmd_run(struct UCCmdRunner *r, const char *cmd_line) uc_cmd_run(struct UCCmdRunner *r, const char *cmd_line)
{ {
@@ -472,6 +564,7 @@ uc_cmd_run(struct UCCmdRunner *r, const char *cmd_line)
rc = uc_cmd_parse_and_find(r, cmd_line, &args.argv, &found); rc = uc_cmd_parse_and_find(r, cmd_line, &args.argv, &found);
if (rc == UC_CMDRC_OK) { if (rc == UC_CMDRC_OK) {
found = found->child;
// Now check the current level for any UC_CMD_END // Now check the current level for any UC_CMD_END
// which indicates a complete command // which indicates a complete command
while (found) { while (found) {
@@ -482,7 +575,7 @@ uc_cmd_run(struct UCCmdRunner *r, const char *cmd_line)
} }
if (found != NULL) { if (found != NULL) {
struct UCCmdDef *cmd = found->data.cmd; const struct UCCmdDef *cmd = found->data.cmd;
args.cmd = cmd; args.cmd = cmd;
rc = cmd->callback(&args); rc = cmd->callback(&args);
} else { } else {
@@ -536,8 +629,39 @@ enum UCCmdRc cmd4_cb(const struct UCCmdArgs *args)
return UC_CMDRC_OK; return UC_CMDRC_OK;
} }
void do_complete(struct UCCmdRunner *r, const char *command)
{
struct UCStrv completions = UC_STRV_INITIALIZER;
uc_cmd_complete(r, command, &completions);
if (completions.cnt > 0) {
printf("Possible completions for '%s' :\n", command);
for (size_t i = 0; i < completions.cnt; i++) {
printf("\t%s\n", completions.strings[i]);
}
} else {
printf("No completions for '%s' :\n", command);
}
uc_strv_destroy(&completions);
}
void do_help(struct UCCmdRunner *r, const char *command)
{
struct UCStrv completions = UC_STRV_INITIALIZER;
uc_cmd_help(r, command, &completions);
if (completions.cnt > 0) {
printf("help for '%s' :\n", command);
for (size_t i = 0; i < completions.cnt; i++) {
printf("\t%s\n", completions.strings[i]);
}
} else {
printf("No help for '%s' :\n", command);
}
uc_strv_destroy(&completions);
}
int main(int argc, char *argv[]) int main(int argc, char *argv[])
@@ -546,7 +670,7 @@ int main(int argc, char *argv[])
struct UCCmdRunner r; struct UCCmdRunner r;
struct UCCmdDef cmd1 = { struct UCCmdDef cmd1 = {
"show all", "show all",
"\n\n", " \nEverything\n",
cmd1_cb, cmd1_cb,
0, 0,
NULL NULL
@@ -554,7 +678,7 @@ int main(int argc, char *argv[])
struct UCCmdDef cmd2 = { struct UCCmdDef cmd2 = {
"show empty", "show empty",
"\n\n", "Show parameter\nAll empty\n",
cmd2_cb, cmd2_cb,
0, 0,
NULL NULL
@@ -562,7 +686,7 @@ int main(int argc, char *argv[])
struct UCCmdDef cmd3 = { struct UCCmdDef cmd3 = {
"show empty bottle", "show empty bottle",
"\n\n\n", NULL,
cmd3_cb, cmd3_cb,
0, 0,
NULL NULL
@@ -570,7 +694,7 @@ int main(int argc, char *argv[])
struct UCCmdDef cmd4 = { struct UCCmdDef cmd4 = {
"delete file NAME", "delete file NAME",
"\n\nName of the file\n", "delete\nfile\nName of the file\n",
cmd4_cb, cmd4_cb,
0, 0,
NULL NULL
@@ -587,6 +711,12 @@ int main(int argc, char *argv[])
uc_cmd_run(&r, "show empty"); uc_cmd_run(&r, "show empty");
uc_cmd_run(&r, "sh emp b"); uc_cmd_run(&r, "sh emp b");
uc_cmd_run(&r, ""); uc_cmd_run(&r, "");
do_help(&r, "delete file /tmp/a");
do_help(&r, "show empty");
do_help(&r, "show all");
do_help(&r, "sh");
do_help(&r, "");
/* /*
while (fgets(line,sizeof line, stdin)) { while (fgets(line,sizeof line, stdin)) {
enum UCCmdRc rc = uc_cmd_run(&r, line); enum UCCmdRc rc = uc_cmd_run(&r, line);
@@ -596,9 +726,13 @@ int main(int argc, char *argv[])
} }
*/ */
uc_cmd_complete(&r, "sho em"); do_complete(&r, "sho em");
uc_cmd_complete(&r, "show "); do_complete(&r, "show ");
uc_cmd_complete(&r, ""); do_complete(&r, "");
do_complete(&r, "delet ");
do_complete(&r, "delete ");
do_complete(&r, "delete file");
do_complete(&r, "delete fil");
uc_cmd_runner_destroy(&r); uc_cmd_runner_destroy(&r);