Implement argument collecting
This commit is contained in:
+82
-46
@@ -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);
|
||||||
|
|||||||
Reference in New Issue
Block a user