#include "command.h" #include #include #include #include #include #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 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