summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBenjamin Franzke <benjaminfranzke@googlemail.com>2013-11-05 11:48:34 +0100
committerBenjamin Franzke <benjaminfranzke@googlemail.com>2014-01-04 15:47:49 +0100
commit1f0238fb70f8f4e034e69c43872e62bb1917459e (patch)
tree9c5e9bd79bfe2f140243332063666fe9ab97391f /src
parentf35cc11d24f9955ffaffb80edc90db6279bdc43e (diff)
downloadpjctl-1f0238fb70f8f4e034e69c43872e62bb1917459e.tar.gz
pjctl-1f0238fb70f8f4e034e69c43872e62bb1917459e.tar.bz2
pjctl-1f0238fb70f8f4e034e69c43872e62bb1917459e.zip
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/Makefile.am2
-rw-r--r--src/param.h47
-rw-r--r--src/pjctl.c272
3 files changed, 216 insertions, 105 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 42f568a..af28cf2 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,6 +1,6 @@
bin_PROGRAMS = pjctl
-pjctl_SOURCES = pjctl.c
+pjctl_SOURCES = pjctl.c param.h
pjctl_LDADD = $(crypto_LIBS)
AM_CPPFLAGS = $(crypto_CFLAGS)
diff --git a/src/param.h b/src/param.h
new file mode 100644
index 0000000..553366c
--- /dev/null
+++ b/src/param.h
@@ -0,0 +1,47 @@
+/*
+ * pjctl - network projector control utility
+ *
+ * Copyright (C) 2011 Benjamin Franzke <benjaminfranzke@googlemail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef PARAM_H
+#define PARAM_H
+
+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 }
+
+#endif /* PARAM_H */
diff --git a/src/pjctl.c b/src/pjctl.c
index 1b0d295..01e9f4e 100644
--- a/src/pjctl.c
+++ b/src/pjctl.c
@@ -36,6 +36,7 @@
#ifndef NO_CRYPTO
#include <openssl/md5.h>
#endif
+#include "param.h"
enum pjlink_packet_offsets {
PJLINK_HEADER = 0,
@@ -60,7 +61,7 @@ struct queue_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;
};
@@ -76,6 +77,13 @@ struct pjctl {
#endif
};
+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;
+};
+
#define ARRAY_SIZE(a) (sizeof(a)/sizeof((a)[0]))
#define MIN(a,b) ((a)<(b) ? (a) : (b))
@@ -324,7 +332,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 +345,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 +384,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 +410,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 +424,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 +438,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 +669,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[] = {
@@ -765,30 +705,148 @@ status(struct pjctl *pjctl, char **argv, int argc)
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 },
};
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)
{
int i;
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 +872,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;
}
}