summaryrefslogtreecommitdiff
path: root/usr.bin/tmux/arguments.c
diff options
context:
space:
mode:
authorNicholas Marriott <nicm@cvs.openbsd.org>2021-08-25 08:51:56 +0000
committerNicholas Marriott <nicm@cvs.openbsd.org>2021-08-25 08:51:56 +0000
commit98ffd29fab2ef14be2c2b4748c62d5e8fd1631f7 (patch)
tree92e990c5d80de0e52a3f2ac636a43a10b48d3556 /usr.bin/tmux/arguments.c
parenta50c0d7da75e4226abcd1c52f16afcdebd6b7e28 (diff)
Validate command argument types (string or command list) and give more
useful error messages.
Diffstat (limited to 'usr.bin/tmux/arguments.c')
-rw-r--r--usr.bin/tmux/arguments.c89
1 files changed, 79 insertions, 10 deletions
diff --git a/usr.bin/tmux/arguments.c b/usr.bin/tmux/arguments.c
index d072f20004f..0702420bafe 100644
--- a/usr.bin/tmux/arguments.c
+++ b/usr.bin/tmux/arguments.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: arguments.c,v 1.46 2021/08/23 17:05:43 nicm Exp $ */
+/* $OpenBSD: arguments.c,v 1.47 2021/08/25 08:51:55 nicm Exp $ */
/*
* Copyright (c) 2010 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -124,10 +124,11 @@ args_create(void)
/* Parse arguments into a new argument set. */
struct args *
args_parse(const struct args_parse *parse, struct args_value *values,
- u_int count)
+ u_int count, char **cause)
{
struct args *args;
u_int i;
+ enum args_parse_type type;
struct args_value *value, *new;
u_char flag, argument;
const char *found, *string, *s;
@@ -153,11 +154,13 @@ args_parse(const struct args_parse *parse, struct args_value *values,
if (flag == '\0')
break;
if (!isalnum(flag)) {
+ xasprintf(cause, "invalid flag -%c", flag);
args_free(args);
return (NULL);
}
found = strchr(parse->template, flag);
if (found == NULL) {
+ xasprintf(cause, "unknown flag -%c", flag);
args_free(args);
return (NULL);
}
@@ -167,12 +170,22 @@ args_parse(const struct args_parse *parse, struct args_value *values,
args_set(args, flag, NULL);
continue;
}
- new = xcalloc(1, sizeof *value);
+ new = xcalloc(1, sizeof *new);
if (*string != '\0') {
new->type = ARGS_STRING;
new->string = xstrdup(string);
} else {
if (i == count) {
+ xasprintf(cause,
+ "-%c expects an argument",
+ flag);
+ args_free(args);
+ return (NULL);
+ }
+ if (values[i].type != ARGS_STRING) {
+ xasprintf(cause,
+ "-%c argument must be a string",
+ flag);
args_free(args);
return (NULL);
}
@@ -192,14 +205,60 @@ args_parse(const struct args_parse *parse, struct args_value *values,
s = args_value_as_string(value);
log_debug("%s: %u = %s", __func__, i, s);
+ if (parse->cb != NULL) {
+ type = parse->cb(args, args->count, cause);
+ if (type == ARGS_PARSE_INVALID) {
+ args_free(args);
+ return (NULL);
+ }
+ } else
+ type = ARGS_PARSE_STRING;
+
args->values = xrecallocarray(args->values,
args->count, args->count + 1, sizeof *args->values);
- args_copy_value(&args->values[args->count++], value);
+ new = &args->values[args->count++];
+
+ switch (type) {
+ case ARGS_PARSE_INVALID:
+ fatalx("unexpected argument type");
+ case ARGS_PARSE_STRING:
+ if (value->type != ARGS_STRING) {
+ xasprintf(cause,
+ "argument %u must be \"string\"",
+ args->count);
+ args_free(args);
+ return (NULL);
+ }
+ args_copy_value(new, value);
+ break;
+ case ARGS_PARSE_COMMANDS_OR_STRING:
+ args_copy_value(new, value);
+ break;
+ case ARGS_PARSE_COMMANDS:
+ if (value->type != ARGS_COMMANDS) {
+ xasprintf(cause,
+ "argument %u must be { commands }",
+ args->count);
+ args_free(args);
+ return (NULL);
+ }
+ args_copy_value(new, value);
+ break;
+ }
}
}
- if ((parse->lower != -1 && args->count < (u_int)parse->lower) ||
- (parse->upper != -1 && args->count > (u_int)parse->upper)) {
+ if (parse->lower != -1 && args->count < (u_int)parse->lower) {
+ xasprintf(cause,
+ "too few arguments (need at least %u)",
+ parse->lower);
+ args_free(args);
+ return (NULL);
+ }
+ if (parse->upper != -1 && args->count > (u_int)parse->upper) {
+ xasprintf(cause,
+ "too many arguments (need at most %u)",
+ parse->upper);
args_free(args);
return (NULL);
}
@@ -254,15 +313,25 @@ args_free(struct args *args)
void
args_vector(struct args *args, int *argc, char ***argv)
{
- struct args_value *value;
- u_int i;
+ char *s;
+ u_int i;
*argc = 0;
*argv = NULL;
for (i = 0; i < args->count; i++) {
- value = &args->values[i];
- cmd_append_argv(argc, argv, args_value_as_string(value));
+ switch (args->values[i].type) {
+ case ARGS_NONE:
+ break;
+ case ARGS_STRING:
+ cmd_append_argv(argc, argv, args->values[i].string);
+ break;
+ case ARGS_COMMANDS:
+ s = cmd_list_print(args->values[i].cmdlist, 0);
+ cmd_append_argv(argc, argv, s);
+ free(s);
+ break;
+ }
}
}