diff options
| author | 2023-12-24 04:26:00 -0600 | |
|---|---|---|
| committer | 2023-12-24 04:26:00 -0600 | |
| commit | 20d9fc5b5356a1054cb104ba6651b77184abf0db (patch) | |
| tree | 5f115d8051dad73069d3a632a6f2c260cf7efdac /src/command.c | |
initial commit
Diffstat (limited to 'src/command.c')
| -rw-r--r-- | src/command.c | 239 |
1 files changed, 239 insertions, 0 deletions
diff --git a/src/command.c b/src/command.c new file mode 100644 index 0000000..6be2fb5 --- /dev/null +++ b/src/command.c @@ -0,0 +1,239 @@ +#include "command.h" + +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> +#include <stdbool.h> +#include <stdio.h> + +#include "commands.h" + +#define CMD_ALIASES(...) (const char *[]){ __VA_ARGS__, NULL } + +struct l2_command_node l2_cmd_root = { + .type = CMD_NODE_TYPE_NULL, + .name = "", + + .cmd_proc = NULL, + + .children = (struct l2_command_node []) { + { + .type = CMD_NODE_TYPE_LITERAL, + .name = "instance", + + .children = (struct l2_command_node []) { + { + .type = CMD_NODE_TYPE_LITERAL, + .name = "add", + + .children = (struct l2_command_node []) { + { + .type = CMD_NODE_TYPE_ARGUMENT, + .name = "name", + + .cmd_proc = &cmd_instance_add, + + .children = (struct l2_command_node []) { + { + .type = CMD_NODE_TYPE_LITERAL, + .name = "at", + + .children = (struct l2_command_node []) { + { + .type = CMD_NODE_TYPE_ARGUMENT, + .name = "location", + + .cmd_proc = &cmd_instance_add + }, + { 0 } + } + }, + { 0 } + } + }, + { 0 } + } + }, + { + .type = CMD_NODE_TYPE_LITERAL, + .name = "remove", + + .children = (struct l2_command_node []) { + { + .type = CMD_NODE_TYPE_ARGUMENT, + .name = "name", + + .cmd_proc = &cmd_instance_remove + }, + { 0 } + } + }, + { + .type = CMD_NODE_TYPE_LITERAL, + .name = "list", + + .cmd_proc = &cmd_instance_list + }, + { + .type = CMD_NODE_TYPE_LITERAL, + .name = "rename", + + .children = (struct l2_command_node []) { + { + .type = CMD_NODE_TYPE_ARGUMENT, + .name = "oldname", + + .children = (struct l2_command_node []) { + { + .type = CMD_NODE_TYPE_ARGUMENT, + .name = "newname", + + .cmd_proc = &cmd_instance_rename + }, + { 0 } + } + }, + { 0 } + } + }, + { 0 } + } + }, + { 0 } + } +}; + +bool l2_cmd__parse_command_int(char **argvcur, struct l2_command_node *start, struct l2_context_node **ctx, struct l2_parseinfo *parseinfo); + +unsigned l2_cmd_parse_command(char **argv, struct l2_parseinfo *parseinfo) +{ + if (!argv || !parseinfo) { + return CMD_PARSE_EUSAGE; + } + + l2_cmd__parse_command_int(argv, &l2_cmd_root, &parseinfo->ctx, parseinfo); + + return parseinfo->ctx ? CMD_PARSE_SUCCESS : CMD_PARSE_ESYNTAX; +} + +bool l2_cmd__parse_command_int(char **argvcur, struct l2_command_node *start, struct l2_context_node **ctx, struct l2_parseinfo *parseinfo) +{ + struct l2_command_node *curchild; + struct l2_context_node *childctx = NULL; + unsigned argresult; + + *ctx = NULL; + + if (!*argvcur) { + return true; + } + + switch (start->type) { + case CMD_NODE_TYPE_NULL: + curchild = start->children; + + while (curchild && curchild->name && !*ctx) { + l2_cmd__parse_command_int(argvcur, curchild, ctx, parseinfo); + ++curchild; + } + + return true; + case CMD_NODE_TYPE_LITERAL: + if (strcmp(*argvcur, start->name)) { + if (!start->extra.aliases) return true; /* no aliases */ + + bool found = false; + for (const char **alias = start->extra.aliases; *alias; ++alias) { + if (!strcmp(*argvcur, *alias)) { + found = true; + break; + } + } + + if (!found) return true; + } + + break; + case CMD_NODE_TYPE_ARGUMENT: + argresult = start->extra.validate_proc ? (start->extra.validate_proc)(*argvcur) : CMD_VALIDATE_PASS; + if (argresult != CMD_VALIDATE_PASS) + return argresult == CMD_VALIDATE_FAIL_SKIP; + break; + default: + abort(); + } + + curchild = start->children; + while (curchild && curchild->name && !childctx) { + if (!l2_cmd__parse_command_int(argvcur + 1, curchild, &childctx, parseinfo)) break; + ++curchild; + } + + if (childctx || start->cmd_proc) { /* we've found a promising child node (or we're executable) */ + size_t arglen = strlen(*argvcur); + struct l2_context_node *mynode = calloc(1, sizeof(struct l2_context_node) + arglen); + mynode->node = start; + mynode->next = childctx; + mynode->value = *argvcur; + + *ctx = mynode; + + if (!childctx) { /* we're the executable node */ + parseinfo->argv = argvcur + 1; + parseinfo->proc = start->cmd_proc; + } + } + + return true; +} + +void l2_cmd_free_ctx(struct l2_context_node *ctx) +{ + if (!ctx) return; + + struct l2_context_node *next; + do { + next = ctx->next; + free(ctx); + ctx = next; + } while (ctx); +} + +#if 0 +#include "uuid/uuid.h" +#include <inttypes.h> + +int main(int argc, char **argv) +{ + char **argvcur = argv + 1; + + if (!*argvcur) { + printf("done\n"); + return 1; + } + + ((void)argc); + + struct l2_context_node *cur; + struct l2_parseinfo parseinfo; + memset(&parseinfo, 0, sizeof(struct l2_parseinfo)); + + unsigned res = l2_cmd_parse_command(argv + 1, &parseinfo); + + printf("%p %s\n", (void *)parseinfo.ctx, parseinfo.argv ? *parseinfo.argv : "(null)"); + + if (res == CMD_PARSE_SUCCESS) { + cur = parseinfo.ctx; + while (cur) { + printf("%s\n", cur->value); + cur = cur->next; + } + + printf("command returned: %u\n", (parseinfo.proc)(parseinfo.ctx, parseinfo.argv)); + + l2_cmd_free_ctx(parseinfo.ctx); + } + + return 0; +} +#endif |
