From dcbb1f9f99b6720638ed1d5be46fbf0b712791b6 Mon Sep 17 00:00:00 2001 From: Benjamin Franzke Date: Tue, 5 Nov 2013 11:48:34 +0100 Subject: [WIP] New commandline parsing This commit tries to centralize the user input parsing, so that the functions really only do what they are for, e.g. requesting for given valid input. --- src/pjctl.c | 303 +++++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 199 insertions(+), 104 deletions(-) diff --git a/src/pjctl.c b/src/pjctl.c index 1b0d295..5eb7520 100644 --- a/src/pjctl.c +++ b/src/pjctl.c @@ -55,12 +55,19 @@ enum pjctl_state { struct pjctl; +union pjctl_param_parse { + uint8_t p[8]; + struct { uint8_t val; } power; + struct { uint8_t type; uint8_t num; } source; + struct { uint8_t type; uint8_t val; } mute; +}; + struct queue_command { char *command; void (*response_func)(struct pjctl *pjctl, struct queue_command *cmd, char *op, char *param); char *prefix; - int (*toggle)(struct pjctl *pjctl, char **argv, int argc); + int (*toggle)(struct pjctl *pjctl, union pjctl_param_parse *parse); struct queue_command *prev, *next; }; @@ -324,7 +331,7 @@ power_response(struct pjctl *pjctl, struct queue_command *cmd, char *op, char *param) { int ret; - char *p[2] = { "power", NULL }; + union pjctl_param_parse p; fputs(cmd->prefix, stdout); free(cmd->prefix); @@ -337,42 +344,29 @@ power_response(struct pjctl *pjctl, struct queue_command *cmd, printf("%s\n", param[0] == '1' ? "on" : "off" ); if (cmd->toggle) { - p[1] = param[0] == '1' ? "off" : "on"; - cmd->toggle(pjctl, p, ARRAY_SIZE(p)); + p.power.val = param[0] == '1' ? '0' : '1'; + cmd->toggle(pjctl, &p); } } } static int -power(struct pjctl *pjctl, char **argv, int argc) +power(struct pjctl *pjctl, union pjctl_param_parse *parse) { struct queue_command *cmd; - char code; cmd = calloc(1, sizeof *cmd); if (!cmd) return -1; - if (argc < 2) { - return -1; - } - if (strcmp(argv[1], "on") == 0) - code = '1'; - else if (strcmp(argv[1], "off") == 0) - code = '0'; - else if (strcmp(argv[1], "toggle") == 0) { - code = '?'; + if (parse->power.val == '?') cmd->toggle = power; - } else { - fprintf(stderr, "invalid power parameter\n"); - return -1; - } - if (asprintf(&cmd->command, "%%1POWR %c\r", code) < 0) + if (asprintf(&cmd->command, "%%1POWR %c\r", parse->power.val) < 0) return -1; cmd->response_func = power_response; if (asprintf(&cmd->prefix, "power %s: ", - cmd->toggle ? "status" : argv[1]) < 0) + cmd->toggle ? "status" : "TODO on/off") < 0) return -1; insert_at_head(&pjctl->queue, cmd); @@ -389,50 +383,23 @@ source_response(struct pjctl *pjctl, struct queue_command *cmd, } static int -source(struct pjctl *pjctl, char **argv, int argc) +source(struct pjctl *pjctl, union pjctl_param_parse *p) { struct queue_command *cmd; - int type = 0, offset; - int num; - int i; + uint8_t type = p->source.type, num = p->source.num; const char *switches[] = { "rgb", "video", "digital", "storage", "net" }; cmd = calloc(1, sizeof *cmd); if (!cmd) return -1; - if (argc < 2) { - fprintf(stderr, "missing parameter to source commands\n"); - return -1; - } - - for (i = 0; i < ARRAY_SIZE(switches); ++i) { - offset = strlen(switches[i]); - if (strncmp(argv[1], switches[i], offset) == 0) { - type = i+1; - break; - } - } - - if (type == 0) { - fprintf(stderr, "incorrect source type given\n"); - return -1; - } - - num = argv[1][offset]; - if (num < '1' || num > '9') { - fprintf(stderr, - "warning: missing source number, defaulting to 1\n"); - num = '1'; - } - - if (asprintf(&cmd->command, "%%1INPT %d%c\r", type, num) < 0) + if (asprintf(&cmd->command, "%%1INPT %d%d\r", type, num) < 0) return -1; cmd->response_func = source_response; insert_at_head(&pjctl->queue, cmd); - printf("source select %s%c: ", switches[type-1], num); + printf("source select %s%d: ", switches[type-1], num); return 0; } @@ -442,7 +409,7 @@ avmute_response(struct pjctl *pjctl, struct queue_command *cmd, char *op, char *param) { int ret; - char *params[3] = { "mute", NULL, NULL }; + union pjctl_param_parse p; fputs(cmd->prefix, stdout); free(cmd->prefix); @@ -456,15 +423,12 @@ avmute_response(struct pjctl *pjctl, struct queue_command *cmd, return; switch (param[0]) { case '1': - params[1] = "video"; printf("video"); break; case '2': - params[1] = "audio"; printf("audio"); break; case '3': - params[1] = "av"; printf("video & audio"); break; default: @@ -473,61 +437,36 @@ avmute_response(struct pjctl *pjctl, struct queue_command *cmd, } printf(" mute "); - params[2] = param[1] == '1' ? "on" : "off"; - printf("%s\n", params[2]); + printf("%s\n", param[1] == '1' ? "on" : "off"); - if (cmd->toggle) - cmd->toggle(pjctl, params, 3); + if (cmd->toggle) { + p.mute.type = param[0]; + p.mute.val = param[1] == '1' ? '0' : '1'; + cmd->toggle(pjctl, &p); + } } } static int -avmute(struct pjctl *pjctl, char **argv, int argc) +avmute(struct pjctl *pjctl, union pjctl_param_parse *p) { struct queue_command *cmd; - int type = 0; - int i; - char code; + uint8_t type = p->mute.type; + char code = p->mute.val; const char *targets[] = { "video", "audio", "av" }; cmd = calloc(1, sizeof *cmd); if (!cmd) return -1; - if (argc < 3) { - fprintf(stderr, "missing parameter to source commands\n"); - return -1; - } - - for (i = 0; i < ARRAY_SIZE(targets); ++i) { - if (strcmp(argv[1], targets[i]) == 0) { - type = i+1; - break; - } - } - - if (type == 0) { - fprintf(stderr, "incorrect source type given\n"); - return -1; - } - - if (strcmp(argv[2], "on") == 0) - code = '1'; - else if (strcmp(argv[2], "off") == 0) - code = '0'; - else if (strcmp(argv[2], "toggle") == 0) { - code = '?'; - cmd->toggle = avmute; - } else { - fprintf(stderr, "invalid mute parameter\n"); - return -1; - } + if (code == '?') + cmd->toggle = power; if (asprintf(&cmd->command, "%%1AVMT %d%c\r", type, code) < 0) return -1; cmd->response_func = avmute_response; if (asprintf(&cmd->prefix, "%s mute %s: ", - targets[type-1], cmd->toggle ? "status" : argv[2]) < 0) + targets[type-1], cmd->toggle ? "status" : "TODO on/off") < 0) return -1; insert_at_head(&pjctl->queue, cmd); @@ -729,7 +668,7 @@ class_response(struct pjctl *pjctl, struct queue_command *cmd, } static int -status(struct pjctl *pjctl, char **argv, int argc) +status(struct pjctl *pjctl, union pjctl_param_parse *parse) { /* Note: incomplete commands stored here */ static const struct queue_command cmds[] = { @@ -763,17 +702,87 @@ status(struct pjctl *pjctl, char **argv, int argc) return 0; } +enum pjctl_param_type { + PJCTL_PARAM_ATOM, + PJCTL_PARAM_RANGE, + PJCTL_PARAM_SWITCH, + PJCTL_PARAM_END +}; + +struct pjctl_param { + enum pjctl_param_type type; + union { + const char **atoms; + struct { int start, end, fallback; } range; + } p; +}; + +#define P (struct pjctl_param[]) +#define P_ATOM(...) { \ + .type = PJCTL_PARAM_ATOM, \ + .p.atoms = (const char *[]) { __VA_ARGS__, NULL } \ +} +#define P_RANGE(a,b,c) { .type = PJCTL_PARAM_RANGE, .p.range = { (a),(b),(c) } } +#define P_SWITCH { .type = PJCTL_PARAM_SWITCH } +#define P_END { .type = PJCTL_PARAM_END } + static struct pjctl_command { char *name; - int (*func)(struct pjctl *pjctl, char **argv, int argc); - char *help; + int (*func)(struct pjctl *pjctl, union pjctl_param_parse *p); + struct pjctl_param *params; } commands[] = { - { "power", power, "" }, - { "source", source, "[1-9]" }, - { "mute", avmute, " " }, - { "status", status, ""}, + { "power", power, P{ P_SWITCH, P_END } }, + { "source", source, + P{ P_ATOM("rgb", "video", "digital", "storage", "net"), + P_RANGE(1,9,1), P_END } + }, + { "mute", avmute, P{ P_ATOM("video", "audio", "av"), P_SWITCH, P_END }}, + { "status", status, NULL }, }; +enum pjctl_command_type { + PJCTL_COMMAND_POWER, + PJCTL_COMMAND_SOURCE, + PJCTL_COMMAND_MUTE, + PJCTL_COMMAND_STATUS +}; + + +static void +cmd_help(struct pjctl_param *params) +{ + int i, j; + struct pjctl_param *p; + char prefix; + + if (params == NULL) + return; + + for (i = 0; params[i].type != PJCTL_PARAM_END; ++i) { + p = ¶ms[i]; + switch (p->type) { + case PJCTL_PARAM_SWITCH: + printf(" "); + break; + case PJCTL_PARAM_RANGE: + printf(" [%d-%d]", p->p.range.start, p->p.range.end); + break; + case PJCTL_PARAM_ATOM: + printf(" "); + prefix = '<'; + for (j = 0; p->p.atoms[j]; ++j) { + printf("%c%s", prefix, p->p.atoms[j]); + prefix = '|'; + } + printf(">"); + break; + default: + abort(); + break; + } + } +} + static void usage(struct pjctl *pjctl) { @@ -781,14 +790,94 @@ usage(struct pjctl *pjctl) printf("usage: pjctl [-p password] command [args..]\n\n"); printf("commands:\n"); - for (i = 0; i < ARRAY_SIZE(commands); ++i) - printf(" %s %s\n", commands[i].name, commands[i].help); + for (i = 0; i < ARRAY_SIZE(commands); ++i) { + printf(" %s", commands[i].name); + cmd_help(commands[i].params); + printf("\n"); + } +} + +static int +parse_params(struct pjctl_command *cmd, char **argv, int argc, + union pjctl_param_parse *parse) +{ + struct pjctl_param *param; + uint8_t *p = parse->p; + int idx = 1; + int i; + int type = 0; + long int num; + + if (cmd->params == NULL) + return 0; + + for (param = &cmd->params[0], idx = 0; + param->type != PJCTL_PARAM_END; + param++, idx++) { + switch (param->type) { + case PJCTL_PARAM_SWITCH: + if (argc <= idx) + return -1; + + if (strcmp(argv[idx], "on") == 0) + p[idx] = '1'; + else if (strcmp(argv[idx], "off") == 0) + p[idx] = '0'; + else if (strcmp(argv[idx], "toggle") == 0) { + p[idx] = '?'; + } else { + fprintf(stderr, "invalid %s parameter\n", + cmd->name); + return -1; + } + break; + case PJCTL_PARAM_ATOM: + if (argc <= idx) + return -1; + + for (i = 0; param->p.atoms[i]; ++i) { + if (strcmp(argv[idx], param->p.atoms[i]) == 0) { + type = i+1; + break; + } + } + if (type == 0) { + fprintf(stderr, "incorrect %s type given\n", + cmd->name); + return -1; + } + + p[idx] = type; + break; + case PJCTL_PARAM_RANGE: + if (argc <= idx) { + p[idx] = param->p.range.fallback; + break; + } + + num = strtol(argv[idx], NULL, 10); + if (num < param->p.range.start || + num > param->p.range.end) { + fprintf(stderr, "invalid %s range parameter\n", + cmd->name); + return -1; + } + + p[idx] = num; + break; + default: + abort(); + } + } + + return 0; } int main(int argc, char **argv) { struct pjctl pjctl; + union pjctl_param_parse parse; char *host; char *sport = "4352"; struct addrinfo hints, *result, *rp; @@ -814,8 +903,14 @@ main(int argc, char **argv) for (i = 0; i < ARRAY_SIZE(commands); ++i) { if (strcmp(argv[optind+1], commands[i].name) == 0) { - if (commands[i].func(&pjctl, &argv[optind+1], - argc-optind-1) < 0) + if (parse_params(&commands[i], + &argv[optind+2], argc-optind-2, + &parse) < 0) { + usage(&pjctl); + return 1; + } + + if (commands[i].func(&pjctl, &parse) < 0) return 1; } } -- cgit