summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenjamin Franzke <benjaminfranzke@googlemail.com>2013-11-05 11:48:34 +0100
committerBenjamin Franzke <benjaminfranzke@googlemail.com>2013-11-05 13:55:08 +0100
commitdcbb1f9f99b6720638ed1d5be46fbf0b712791b6 (patch)
tree047ec923520aac92d15289779544c03dad832f68
parent9eb80c522892e425424da90d7c1417b6594f319e (diff)
downloadpjctl-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.
-rw-r--r--src/pjctl.c303
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 = &params[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;
}
}