aboutsummaryrefslogtreecommitdiffstats
path: root/src/command.c
diff options
context:
space:
mode:
authorLibravatar bigfoot547 <[email protected]>2023-12-24 04:26:00 -0600
committerLibravatar bigfoot547 <[email protected]>2023-12-24 04:26:00 -0600
commit20d9fc5b5356a1054cb104ba6651b77184abf0db (patch)
tree5f115d8051dad73069d3a632a6f2c260cf7efdac /src/command.c
initial commit
Diffstat (limited to 'src/command.c')
-rw-r--r--src/command.c239
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