Implement argument collecting

This commit is contained in:
Nils O. Selåsdal
2015-12-10 18:51:51 +01:00
parent 5d54702501
commit 9b70b64729
+82 -46
View File
@@ -1,9 +1,11 @@
#include <stdint.h> #include <stdint.h>
#include <ctype.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <assert.h> #include <assert.h>
#include <stdlib.h> #include <stdlib.h>
#include "ucore/string.h" #include "ucore/string.h"
#include "ucore/strvec.h"
#include "ucore/utils.h" #include "ucore/utils.h"
//max words in a single command //max words in a single command
@@ -22,12 +24,13 @@ enum UCCmdRc {
UC_CMDRC_ERROR, UC_CMDRC_ERROR,
}; };
typedef enum UCCmdRc (*uc_cmd_handler)(int narg, char *args[]); typedef enum UCCmdRc (*uc_cmd_handler)(const struct UCStrv *args);
enum UCCmdType { enum UCCmdType {
UC_CMD_ROOT = 1, UC_CMD_ROOT = 1,
UC_CMD_KEYWORD, UC_CMD_KEYWORD,
UC_CMD_LIST, UC_CMD_LIST,
UC_CMD_STRING,
UC_CMD_END, UC_CMD_END,
}; };
@@ -100,18 +103,6 @@ void uc_cmd_runner_init(struct UCCmdRunner *r)
r->_root.type = UC_CMD_KEYWORD; r->_root.type = UC_CMD_KEYWORD;
} }
static void uc_cmd_list_free(struct UCCmdList *l)
{
struct UCCmdList *next;
while (l) {
next = l->next;
free(l->word);
free(l);
l = next;
}
}
void uc_cmd_node_dealloc(struct UCCmdNode *n) void uc_cmd_node_dealloc(struct UCCmdNode *n)
{ {
struct UCCmdNode *next; struct UCCmdNode *next;
@@ -121,7 +112,10 @@ void uc_cmd_node_dealloc(struct UCCmdNode *n)
if (n->type == UC_CMD_KEYWORD) { if (n->type == UC_CMD_KEYWORD) {
free(n->data); free(n->data);
} else if (n->type == UC_CMD_LIST) { } else if (n->type == UC_CMD_LIST) {
uc_cmd_list_free(n->data); uc_strv_destroy(n->data);
free(n->data);
} else if (n->type == UC_CMD_STRING) {
free(n->data);
} }
free(n); free(n);
n = next; n = next;
@@ -161,19 +155,19 @@ struct UCCmdNode *uc_cmd_node_create(const char *word)
uc_cmd_tokenize(&t, word, "() |\t\v"); uc_cmd_tokenize(&t, word, "() |\t\v");
if (t.num_words > 0) { if (t.num_words > 0) {
struct UCCmdList *list = NULL; struct UCStrv *v = malloc(sizeof *v);
for (int i = t.num_words - 1; i >= 0; i--) { uc_strv_init(v);
struct UCCmdList *l = calloc(1, sizeof *l);
l->word = strdup(t.cmd_words[i]); for (int i = 0 ; i < t.num_words; i++) {
l->next = list; uc_strv_append(v, t.cmd_words[i]);
list = l;
} }
node = uc_cmd_node_alloc(UC_CMD_LIST, list, 0); node = uc_cmd_node_alloc(UC_CMD_LIST, v, 0);
} }
uc_cmd_tokenize_destroy(&t); uc_cmd_tokenize_destroy(&t);
} else if (isupper(word[0])) {
node = uc_cmd_node_alloc(UC_CMD_STRING, strdup(word), 0);
} else { } else {
node = uc_cmd_node_alloc(UC_CMD_KEYWORD, strdup(word), 0); node = uc_cmd_node_alloc(UC_CMD_KEYWORD, strdup(word), 0);
} }
@@ -183,7 +177,7 @@ struct UCCmdNode *uc_cmd_node_create(const char *word)
} }
static int uc_cmd_node_match(const struct UCCmdNode *n, const char *word) static int uc_cmd_node_match(const struct UCCmdNode *n, const char *word, struct UCStrv *args)
{ {
size_t word_len; size_t word_len;
@@ -194,21 +188,29 @@ static int uc_cmd_node_match(const struct UCCmdNode *n, const char *word)
word_len = strlen(word); word_len = strlen(word);
if (n->type == UC_CMD_KEYWORD) { if (n->type == UC_CMD_KEYWORD) {
return strncmp(word, n->data, word_len) == 0;
}
if (n->type == UC_CMD_LIST) { if (strncmp(word, n->data, word_len) == 0) {
struct UCCmdList *l = n->data;
assert(l);
assert(l->word);
while (l) {
if (strncmp(word, l->word, word_len) == 0) {
return 1; return 1;
} }
l = l->next; } else if (n->type == UC_CMD_LIST) {
struct UCStrv *v = n->data;
assert(v);
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]);
} }
return 1;
}
}
} else if (n->type == UC_CMD_STRING) {
if (args != NULL) {
uc_strv_append(args, word);
}
return 1;
} }
return 0; return 0;
@@ -218,7 +220,7 @@ static int uc_cmd_node_match(const struct UCCmdNode *n, const char *word)
static struct UCCmdNode *uc_cmd_add(struct UCCmdNode *parent, const char *word) static struct UCCmdNode *uc_cmd_add(struct UCCmdNode *parent, const char *word)
{ {
struct UCCmdNode *new_node; struct UCCmdNode *new_node;
struct UCCmdNode **location = &parent->child; struct UCCmdNode **iter = &parent->child;
assert(parent); assert(parent);
@@ -228,8 +230,8 @@ static struct UCCmdNode *uc_cmd_add(struct UCCmdNode *parent, const char *word)
} }
while (*location) { while (*iter) {
struct UCCmdNode *n = *location; struct UCCmdNode *n = *iter;
if (new_node->type != UC_CMD_KEYWORD && n->type != UC_CMD_END) { if (new_node->type != UC_CMD_KEYWORD && n->type != UC_CMD_END) {
//we don't support combinations of keywords and variables //we don't support combinations of keywords and variables
@@ -238,13 +240,14 @@ static struct UCCmdNode *uc_cmd_add(struct UCCmdNode *parent, const char *word)
return NULL; return NULL;
} }
//TODO check for ambiguous word (e.g. add "short" when "shorter" already exists) //TODO check for ambiguous word (e.g. add "short" when "shorter" already exists)
if (uc_cmd_node_match(n, word)) { if (new_node->type == UC_CMD_KEYWORD && uc_cmd_node_match(n, word, NULL)) {
return *location; uc_cmd_node_dealloc(new_node);
return *iter;
} }
location = &n->next; iter = &n->next;
} }
*location = new_node; *iter = new_node;
return new_node; return new_node;
} }
@@ -290,6 +293,9 @@ enum UCCmdRc uc_cmd_run(struct UCCmdRunner *r, const char *cmd_line)
struct UCCmdNode *node = r->root_node->child; struct UCCmdNode *node = r->root_node->child;
struct UCCmdTokenizer t; struct UCCmdTokenizer t;
enum UCCmdRc rc = UC_CMDRC_ERROR; enum UCCmdRc rc = UC_CMDRC_ERROR;
struct UCStrv args = UC_STRV_INITIALIZER; //arguments to the callback function
//make a copy since getfields destroys the original string //make a copy since getfields destroys the original string
uc_cmd_tokenize(&t, cmd_line, NULL); uc_cmd_tokenize(&t, cmd_line, NULL);
@@ -305,7 +311,7 @@ enum UCCmdRc uc_cmd_run(struct UCCmdRunner *r, const char *cmd_line)
struct UCCmdNode *found = NULL; struct UCCmdNode *found = NULL;
while (node) { while (node) {
if (uc_cmd_node_match(node, t.cmd_words[i])) { if (uc_cmd_node_match(node, t.cmd_words[i], &args)) {
found = node; found = node;
n_found++; n_found++;
} }
@@ -315,6 +321,8 @@ enum UCCmdRc uc_cmd_run(struct UCCmdRunner *r, const char *cmd_line)
if (n_found == 1) { if (n_found == 1) {
node = found->child; node = found->child;
} else if (n_found > 1) { } else if (n_found > 1) {
uc_strv_destroy(&args);
uc_cmd_tokenize_destroy(&t);
return UC_CMDRC_AMBIGUOUS; return UC_CMDRC_AMBIGUOUS;
} }
} }
@@ -330,38 +338,57 @@ enum UCCmdRc uc_cmd_run(struct UCCmdRunner *r, const char *cmd_line)
if (node != NULL) { if (node != NULL) {
struct UCCmdDef *cmd = node->data; struct UCCmdDef *cmd = node->data;
rc = cmd->callback(0, NULL); rc = cmd->callback(&args);
} else { } else {
rc = UC_CMDRC_INCOMPLETE; rc = UC_CMDRC_INCOMPLETE;
} }
uc_strv_destroy(&args);
uc_cmd_tokenize_destroy(&t); uc_cmd_tokenize_destroy(&t);
return rc; return rc;
} }
enum UCCmdRc cmd1_cb(int narg, char *args[]) void print_args(const struct UCStrv *args)
{
for (size_t i = 0; i < args->cnt; i++) {
printf("arg %zu:%s\n", i, args->strings[i]);
}
}
enum UCCmdRc cmd1_cb(const struct UCStrv *args)
{ {
puts(__func__); puts(__func__);
print_args(args);
return UC_CMDRC_OK; return UC_CMDRC_OK;
} }
enum UCCmdRc cmd2_cb(int narg, char *args[]) enum UCCmdRc cmd2_cb(const struct UCStrv *args)
{ {
puts(__func__); puts(__func__);
print_args(args);
return UC_CMDRC_OK; return UC_CMDRC_OK;
} }
enum UCCmdRc cmd3_cb(int narg, char *args[]) enum UCCmdRc cmd3_cb(const struct UCStrv *args)
{ {
puts(__func__); puts(__func__);
print_args(args);
return UC_CMDRC_OK; return UC_CMDRC_OK;
} }
enum UCCmdRc cmd4_cb(const struct UCStrv *args)
{
puts(__func__);
print_args(args);
return UC_CMDRC_OK;
}
@@ -390,14 +417,23 @@ int main(int argc, char *argv[])
NULL NULL
}; };
struct UCCmdDef cmd4 = {
"delete file NAME",
cmd4_cb,
0,
NULL
};
uc_cmd_runner_init(&r); uc_cmd_runner_init(&r);
uc_cmd_install(&r, &cmd1); uc_cmd_install(&r, &cmd1);
uc_cmd_install(&r, &cmd2); uc_cmd_install(&r, &cmd2);
uc_cmd_install(&r, &cmd3); uc_cmd_install(&r, &cmd3);
uc_cmd_install(&r, &cmd4);
uc_cmd_run(&r, "delete file /tmp/a");
uc_cmd_run(&r, "show all"); uc_cmd_run(&r, "show all");
uc_cmd_run(&r, "show empty"); uc_cmd_run(&r, "show empty");
uc_cmd_run(&r, "show empty bottle"); uc_cmd_run(&r, "sh emp g");
/* /*
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);