summaryrefslogtreecommitdiffstats
path: root/input
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2018-01-10 01:20:58 +0100
committerKevin Mitchell <kevmitch@gmail.com>2018-01-10 20:36:27 -0800
commit2d345c59d637ec12fbc39d97e1999c335dffcdd2 (patch)
treeec8281b2e0ccec14739827e28153f73b22fd26ed /input
parente3bee23fe4e0dc15ea2564b684572572f2393a15 (diff)
downloadmpv-2d345c59d637ec12fbc39d97e1999c335dffcdd2.tar.bz2
mpv-2d345c59d637ec12fbc39d97e1999c335dffcdd2.tar.xz
input: make command argument list a dynamic array
Replace the static array with dynamic memory allocation. This also requires some code to honor mp_cmd.nargs more strictly. Generally allocates more stuff. Fixes #5375 (although we could also just raise the static limit).
Diffstat (limited to 'input')
-rw-r--r--input/cmd_list.c5
-rw-r--r--input/cmd_list.h4
-rw-r--r--input/cmd_parse.c93
-rw-r--r--input/input.h5
4 files changed, 55 insertions, 52 deletions
diff --git a/input/cmd_list.c b/input/cmd_list.c
index 333f2cb223..dc3dd68a61 100644
--- a/input/cmd_list.c
+++ b/input/cmd_list.c
@@ -39,7 +39,8 @@
* (ARG_INT, ARG_FLOAT, ARG_STRING) if any, then optional arguments
* (OARG_INT(default), etc) if any. The command will be given the default
* argument value if the user didn't give enough arguments to specify it.
- * A command can take a maximum of MP_CMD_MAX_ARGS arguments.
+ * A command can take a maximum of MP_CMD_DEF_MAX_ARGS arguments, or more
+ * if the command uses varargs.
*/
#define ARG_INT OPT_INT(ARG(i), 0)
@@ -363,7 +364,7 @@ void mp_print_cmd_list(struct mp_log *out)
for (int i = 0; mp_cmds[i].name; i++) {
const struct mp_cmd_def *def = &mp_cmds[i];
mp_info(out, "%-20.20s", def->name);
- for (int j = 0; j < MP_CMD_MAX_ARGS && def->args[j].type; j++) {
+ for (int j = 0; j < MP_CMD_DEF_MAX_ARGS && def->args[j].type; j++) {
const char *type = def->args[j].type->name;
if (def->args[j].defval)
mp_info(out, " [%s]", type);
diff --git a/input/cmd_list.h b/input/cmd_list.h
index 6590158c31..4d03626bee 100644
--- a/input/cmd_list.h
+++ b/input/cmd_list.h
@@ -21,14 +21,14 @@
#include <stdbool.h>
#include "options/m_option.h"
-#define MP_CMD_MAX_ARGS 10
+#define MP_CMD_DEF_MAX_ARGS 9
#define MP_CMD_OPT_ARG 0x1000
struct mp_cmd_def {
int id; // one of MP_CMD_...
const char *name; // user-visible name (as used in input.conf)
- const struct m_option args[MP_CMD_MAX_ARGS];
+ const struct m_option args[MP_CMD_DEF_MAX_ARGS];
bool allow_auto_repeat; // react to repeated key events
bool on_updown; // always emit it on both up and down key events
bool vararg; // last argument can be given 0 to multiple times
diff --git a/input/cmd_parse.c b/input/cmd_parse.c
index 66a7cfe4b0..c4ac9dd6b7 100644
--- a/input/cmd_parse.c
+++ b/input/cmd_parse.c
@@ -92,46 +92,42 @@ static bool find_cmd(struct mp_log *log, struct mp_cmd *cmd, bstr name)
static bool is_vararg(const struct mp_cmd_def *m, int i)
{
- return m->vararg && (i + 1 >= MP_CMD_MAX_ARGS || !m->args[i + 1].type);
+ return m->vararg && (i + 1 >= MP_CMD_DEF_MAX_ARGS || !m->args[i + 1].type);
}
static const struct m_option *get_arg_type(const struct mp_cmd_def *cmd, int i)
{
- if (i >= MP_CMD_MAX_ARGS)
- return NULL;
- const struct m_option *opt = &cmd->args[i];
- if (!opt->type && is_vararg(cmd, i)) {
+ const struct m_option *opt = NULL;
+ if (is_vararg(cmd, i)) {
// The last arg in a vararg command sets all vararg types.
- for (int n = i; n >= 0; n--) {
+ for (int n = MPMIN(i, MP_CMD_DEF_MAX_ARGS - 1); n >= 0; n--) {
if (cmd->args[n].type) {
opt = &cmd->args[n];
break;
}
}
+ } else if (i < MP_CMD_DEF_MAX_ARGS) {
+ opt = &cmd->args[i];
}
- return opt->type ? opt : NULL;
+ return opt && opt->type ? opt : NULL;
}
-// Set correct arg count, and fill in missing optional args.
+// Verify that there are missing args, fill in missing optional args.
static bool finish_cmd(struct mp_log *log, struct mp_cmd *cmd)
{
- cmd->nargs = 0;
- for (int i = 0; i < MP_CMD_MAX_ARGS; i++) {
- if (!cmd->args[i].type) {
- const struct m_option *opt = get_arg_type(cmd->def, i);
- if (!opt || is_vararg(cmd->def, i))
- break;
- if (!opt->defval && !(opt->flags & MP_CMD_OPT_ARG)) {
- mp_err(log, "Command %s: more than %d arguments required.\n",
- cmd->name, cmd->nargs);
- return false;
- }
- cmd->args[i].type = opt;
- if (opt->defval)
- m_option_copy(opt, &cmd->args[i].v, opt->defval);
+ for (int i = cmd->nargs; i < MP_CMD_DEF_MAX_ARGS; i++) {
+ const struct m_option *opt = get_arg_type(cmd->def, i);
+ if (!opt || is_vararg(cmd->def, i))
+ break;
+ if (!opt->defval && !(opt->flags & MP_CMD_OPT_ARG)) {
+ mp_err(log, "Command %s: more than %d arguments required.\n",
+ cmd->name, cmd->nargs);
+ return false;
}
- if (cmd->args[i].type)
- cmd->nargs = i + 1;
+ struct mp_cmd_arg arg = {.type = opt};
+ if (opt->defval)
+ m_option_copy(opt, &arg.v, opt->defval);
+ MP_TARRAY_APPEND(cmd, cmd->args, cmd->nargs, arg);
}
return true;
}
@@ -169,8 +165,8 @@ struct mp_cmd *mp_input_parse_cmd_node(struct mp_log *log, mpv_node *node)
goto error;
}
mpv_node *val = &args->values[cur++];
- cmd->args[i].type = opt;
- void *dst = &cmd->args[i].v;
+ struct mp_cmd_arg arg = {.type = opt};
+ void *dst = &arg.v;
if (val->format == MPV_FORMAT_STRING) {
int r = m_option_parse(log, opt, bstr0(cmd->name),
bstr0(val->u.string), dst);
@@ -187,6 +183,7 @@ struct mp_cmd *mp_input_parse_cmd_node(struct mp_log *log, mpv_node *node)
goto error;
}
}
+ MP_TARRAY_APPEND(cmd, cmd->args, cmd->nargs, arg);
}
if (!finish_cmd(log, cmd))
@@ -194,10 +191,6 @@ struct mp_cmd *mp_input_parse_cmd_node(struct mp_log *log, mpv_node *node)
return cmd;
error:
- for (int n = 0; n < MP_CMD_MAX_ARGS; n++) {
- if (cmd->args[n].type)
- m_option_free(cmd->args[n].type, &cmd->args[n].v);
- }
talloc_free(cmd);
return NULL;
}
@@ -293,14 +286,15 @@ static struct mp_cmd *parse_cmd_str(struct mp_log *log, void *tmp,
if (r < 1)
break;
- struct mp_cmd_arg *cmdarg = &cmd->args[i];
- cmdarg->type = opt;
- r = m_option_parse(ctx->log, opt, bstr0(cmd->name), cur_token, &cmdarg->v);
+ struct mp_cmd_arg arg = {.type = opt};
+ r = m_option_parse(ctx->log, opt, bstr0(cmd->name), cur_token, &arg.v);
if (r < 0) {
MP_ERR(ctx, "Command %s: argument %d can't be parsed: %s.\n",
cmd->name, i + 1, m_option_strerror(r));
goto error;
}
+
+ MP_TARRAY_APPEND(cmd, cmd->args, cmd->nargs, arg);
}
if (!finish_cmd(ctx->log, cmd))
@@ -360,7 +354,9 @@ mp_cmd_t *mp_input_parse_cmd_(struct mp_log *log, bstr str, const char *loc)
.original = bstrdup(list, original),
};
talloc_steal(list, cmd);
- list->args[0].v.p = cmd;
+ struct mp_cmd_arg arg = {0};
+ arg.v.p = cmd;
+ list->args = talloc_memdup(list, &arg, sizeof(arg));
p_prev = &cmd->queue_next;
cmd = list;
}
@@ -382,19 +378,19 @@ done:
struct mp_cmd *mp_input_parse_cmd_strv(struct mp_log *log, const char **argv)
{
- mpv_node items[MP_CMD_MAX_ARGS];
- mpv_node_list list = {.values = items};
+ int count = 0;
+ while (argv[count])
+ count++;
+ mpv_node *items = talloc_zero_array(NULL, mpv_node, count);
+ mpv_node_list list = {.values = items, .num = count};
mpv_node node = {.format = MPV_FORMAT_NODE_ARRAY, .u = {.list = &list}};
- while (argv[list.num]) {
- if (list.num >= MP_CMD_MAX_ARGS) {
- mp_err(log, "Too many arguments to command.\n");
- return NULL;
- }
- char *s = (char *)argv[list.num];
- items[list.num++] = (mpv_node){.format = MPV_FORMAT_STRING,
- .u = {.string = s}};
+ for (int n = 0; n < count; n++) {
+ items[n] = (mpv_node){.format = MPV_FORMAT_STRING,
+ .u = {.string = (char *)argv[n]}};
}
- return mp_input_parse_cmd_node(log, &node);
+ struct mp_cmd *res = mp_input_parse_cmd_node(log, &node);
+ talloc_free(items);
+ return res;
}
void mp_cmd_free(mp_cmd_t *cmd)
@@ -413,8 +409,9 @@ mp_cmd_t *mp_cmd_clone(mp_cmd_t *cmd)
ret = talloc_memdup(NULL, cmd, sizeof(mp_cmd_t));
talloc_set_destructor(ret, destroy_cmd);
ret->name = talloc_strdup(ret, cmd->name);
+ ret->args = talloc_zero_array(ret, struct mp_cmd_arg, ret->nargs);
for (i = 0; i < ret->nargs; i++) {
- memset(&ret->args[i].v, 0, ret->args[i].type->type->size);
+ ret->args[i].type = cmd->args[i].type;
m_option_copy(ret->args[i].type, &ret->args[i].v, &cmd->args[i].v);
}
ret->original = bstrdup(ret, cmd->original);
@@ -428,7 +425,9 @@ mp_cmd_t *mp_cmd_clone(mp_cmd_t *cmd)
if (prev) {
prev->queue_next = sub;
} else {
- ret->args[0].v.p = sub;
+ struct mp_cmd_arg arg = {0};
+ arg.v.p = sub;
+ ret->args = talloc_memdup(ret, &arg, sizeof(arg));
}
prev = sub;
}
diff --git a/input/input.h b/input/input.h
index f00eb9b0e2..16b203a5e7 100644
--- a/input/input.h
+++ b/input/input.h
@@ -56,6 +56,9 @@ enum mp_input_section_flags {
struct input_ctx;
struct mp_log;
+// Arbitrary upper bound for sanity.
+#define MP_CMD_MAX_ARGS 100
+
struct mp_cmd_arg {
const struct m_option *type;
union {
@@ -71,7 +74,7 @@ struct mp_cmd_arg {
typedef struct mp_cmd {
int id;
char *name;
- struct mp_cmd_arg args[MP_CMD_MAX_ARGS];
+ struct mp_cmd_arg *args;
int nargs;
int flags; // mp_cmd_flags bitfield
bstr original;