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
+167 -33
View File
@@ -68,11 +68,12 @@ struct UCCmdNode {
union {
struct UCCmdWord word;
struct UCCmdList list;
struct UCCmdDef *cmd;
const struct UCCmdDef *cmd;
} data;
uint32_t flags;
struct UCCmdNode *next; //next at same level
struct UCCmdNode *child;
struct UCCmdNode *parent;
};
struct UCCmdRunner {
@@ -99,17 +100,21 @@ struct UCCmdTokenizer {
struct UCCmdArgs {
struct UCStrv argv;
struct UCCmdDef *cmd;
const struct UCCmdDef *cmd;
};
void print_args(const struct UCStrv *args);
static int uc_cmd_type_is_variable(enum UCCmdType type)
void
print_args(const struct UCStrv *args);
static int
uc_cmd_type_is_variable(enum UCCmdType type)
{
return type == UC_CMD_LIST ||
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;
@@ -144,13 +149,14 @@ uc_cmd_runner_init(struct UCCmdRunner *r)
{
memset(r, 0, sizeof *r);
r->root_node = &r->_root;
r->_root.type = UC_CMD_KEYWORD;
r->_root.type = UC_CMD_ROOT;
}
void
uc_cmd_node_dealloc(struct UCCmdNode *n)
{
struct UCCmdNode *next;
while (n) {
uc_cmd_node_dealloc(n->child);
next = n->next;
@@ -281,6 +287,7 @@ uc_cmd_add(struct UCCmdNode *parent, const char *word)
if (new_node == NULL) {
return NULL;
}
new_node->parent = parent;
while (*iter) {
struct UCCmdNode *n = *iter;
@@ -304,12 +311,80 @@ uc_cmd_add(struct UCCmdNode *parent, const char *word)
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
uc_cmd_install_noassert(struct UCCmdRunner *r, struct UCCmdDef *cmd)
{
struct UCCmdNode *node = r->root_node;
struct UCCmdNode *new_node;
struct UCCmdTokenizer t;
int rc;
uc_cmd_tokenize(&t, cmd->cmd, NULL);
if (t.num_words <= 0) {
@@ -333,13 +408,15 @@ uc_cmd_install_noassert(struct UCCmdRunner *r, struct UCCmdDef *cmd)
return -1;
}
new_node->data.cmd = cmd;
new_node->next = node->child;
node->child = new_node;
new_node->next = node->child;
node->child = new_node;
new_node->parent = node;
rc = uc_cmd_node_add_help(new_node);
uc_cmd_tokenize_destroy(&t);
return 0;
return rc;
}
int
@@ -360,11 +437,11 @@ uc_cmd_find(struct UCCmdNode *first,
struct UCCmdNode **result)
{
struct UCCmdNode *node = first;
struct UCCmdNode *found = NULL;
enum UCCmdRc rc = UC_CMDRC_NOT_FOUND;
for (int i = 0; i < t->num_words && node; i++) {
int n_found = 0;
struct UCCmdNode *found = NULL;
while (node) {
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;
}
@@ -423,42 +500,57 @@ uc_cmd_parse_and_find(struct UCCmdRunner *r, const char *cmd_line,
}
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;
enum UCCmdRc rc;
rc = uc_cmd_parse_and_find(r, cmd_line, NULL, &found);
if (rc != UC_CMDRC_NOT_FOUND && found != NULL) {
struct UCCmdNode *node = found;
struct UCCmdNode *node = found->child;
while (node) {
if (node->type == UC_CMD_END) {
uc_strv_append(&completions, "<CR>");
uc_strv_append(completions, "<CR>");
} 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 ||
node->type == UC_CMD_KEYWORD) {
uc_strv_append(&completions, node->data.word.word);
uc_strv_append(completions, node->data.word.word);
}
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;
}
enum UCCmdRc
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);
if (rc == UC_CMDRC_OK) {
found = found->child;
// Now check the current level for any UC_CMD_END
// which indicates a complete command
while (found) {
@@ -482,7 +575,7 @@ uc_cmd_run(struct UCCmdRunner *r, const char *cmd_line)
}
if (found != NULL) {
struct UCCmdDef *cmd = found->data.cmd;
const struct UCCmdDef *cmd = found->data.cmd;
args.cmd = cmd;
rc = cmd->callback(&args);
} else {
@@ -536,8 +629,39 @@ enum UCCmdRc cmd4_cb(const struct UCCmdArgs *args)
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[])
@@ -546,7 +670,7 @@ int main(int argc, char *argv[])
struct UCCmdRunner r;
struct UCCmdDef cmd1 = {
"show all",
"\n\n",
" \nEverything\n",
cmd1_cb,
0,
NULL
@@ -554,7 +678,7 @@ int main(int argc, char *argv[])
struct UCCmdDef cmd2 = {
"show empty",
"\n\n",
"Show parameter\nAll empty\n",
cmd2_cb,
0,
NULL
@@ -562,7 +686,7 @@ int main(int argc, char *argv[])
struct UCCmdDef cmd3 = {
"show empty bottle",
"\n\n\n",
NULL,
cmd3_cb,
0,
NULL
@@ -570,7 +694,7 @@ int main(int argc, char *argv[])
struct UCCmdDef cmd4 = {
"delete file NAME",
"\n\nName of the file\n",
"delete\nfile\nName of the file\n",
cmd4_cb,
0,
NULL
@@ -587,6 +711,12 @@ int main(int argc, char *argv[])
uc_cmd_run(&r, "show empty");
uc_cmd_run(&r, "sh emp b");
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)) {
enum UCCmdRc rc = uc_cmd_run(&r, line);
@@ -596,9 +726,13 @@ int main(int argc, char *argv[])
}
*/
uc_cmd_complete(&r, "sho em");
uc_cmd_complete(&r, "show ");
uc_cmd_complete(&r, "");
do_complete(&r, "sho em");
do_complete(&r, "show ");
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);