diff options
author | Benjamin Franzke <benjaminfranzke@googlemail.com> | 2013-11-05 11:48:34 +0100 |
---|---|---|
committer | Benjamin Franzke <benjaminfranzke@googlemail.com> | 2013-11-05 13:55:08 +0100 |
commit | dcbb1f9f99b6720638ed1d5be46fbf0b712791b6 (patch) | |
tree | 047ec923520aac92d15289779544c03dad832f68 /src | |
parent | 9eb80c522892e425424da90d7c1417b6594f319e (diff) | |
download | pjctl-dcbb1f9f99b6720638ed1d5be46fbf0b712791b6.tar.gz pjctl-dcbb1f9f99b6720638ed1d5be46fbf0b712791b6.tar.bz2 pjctl-dcbb1f9f99b6720638ed1d5be46fbf0b712791b6.zip |
[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.
Diffstat (limited to 'src')
-rw-r--r-- | src/pjctl.c | 303 |
1 files 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, "<on|off|toggle>" }, - { "source", source, "<rgb|video|digital|storage|net>[1-9]" }, - { "mute", avmute, "<video|audio|av> <on|off>" }, - { "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(" <on|off|toggle>"); + 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] <hostname> 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; } } |