summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--mpvcore/input/input.c120
-rw-r--r--mpvcore/input/input.h5
-rw-r--r--mpvcore/m_option.h6
-rw-r--r--mpvcore/player/command.c2
4 files changed, 79 insertions, 54 deletions
diff --git a/mpvcore/input/input.c b/mpvcore/input/input.c
index 180c2ad158..c000835d58 100644
--- a/mpvcore/input/input.c
+++ b/mpvcore/input/input.c
@@ -92,6 +92,11 @@ struct key_name {
char *name;
};
+// This does not specify the real destination of the command parameter values,
+// it just provides a dummy for the OPT_ macros.
+#define OPT_BASE_STRUCT struct mp_cmd_arg
+#define ARG(t) "", v. t
+
/* This array defines all known commands.
* The first field is an id used to recognize the command.
* The second is the command name used in slave mode and input.conf.
@@ -99,33 +104,40 @@ struct key_name {
* (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 (10).
+ * A command can take a maximum of MP_CMD_MAX_ARGS arguments.
*/
-#define ARG_INT { .type = {"", NULL, &m_option_type_int} }
-#define ARG_FLOAT { .type = {"", NULL, &m_option_type_float} }
-#define ARG_DOUBLE { .type = {"", NULL, &m_option_type_double} }
-#define ARG_STRING { .type = {"", NULL, &m_option_type_string} }
-#define ARG_CHOICE(c) { .type = {"", NULL, &m_option_type_choice, \
- M_CHOICES(c)} }
-#define ARG_TIME { .type = {"", NULL, &m_option_type_time} }
-
-#define OARG_DOUBLE(def) { .type = {"", NULL, &m_option_type_double}, \
- .optional = true, .v.d = def }
-#define OARG_INT(def) { .type = {"", NULL, &m_option_type_int}, \
- .optional = true, .v.i = def }
-#define OARG_CHOICE(def, c) { .type = {"", NULL, &m_option_type_choice, \
- M_CHOICES(c)}, \
- .optional = true, .v.i = def }
+#define ARG_INT OPT_INT(ARG(i), 0)
+#define ARG_FLOAT OPT_FLOAT(ARG(f), 0)
+#define ARG_DOUBLE OPT_DOUBLE(ARG(d), 0)
+#define ARG_STRING OPT_STRING(ARG(s), 0)
+#define ARG_CHOICE(c) OPT_CHOICE(ARG(i), 0, c)
+#define ARG_TIME OPT_TIME(ARG(d), 0)
+#define OARG_DOUBLE(def) OPT_DOUBLE(ARG(d), 0, OPTDEF_DOUBLE(def))
+#define OARG_INT(def) OPT_INT(ARG(i), 0, OPTDEF_INT(def))
+#define OARG_CHOICE(def, c) OPT_CHOICE(ARG(i), 0, c, OPTDEF_INT(def))
static int parse_cycle_dir(const struct m_option *opt, struct bstr name,
struct bstr param, void *dst);
static const struct m_option_type m_option_type_cycle_dir = {
.name = "up|down",
.parse = parse_cycle_dir,
+ .size = sizeof(double),
+};
+
+#define OPT_CYCLEDIR(...) \
+ OPT_GENERAL(double, __VA_ARGS__, .type = &m_option_type_cycle_dir)
+
+#define OARG_CYCLEDIR(def) OPT_CYCLEDIR(ARG(d), 0, OPTDEF_DOUBLE(def))
+
+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];
+ bool allow_auto_repeat; // react to repeated key events
};
-static const mp_cmd_t mp_cmds[] = {
+static const struct mp_cmd_def mp_cmds[] = {
{ MP_CMD_IGNORE, "ignore", },
{ MP_CMD_RADIO_STEP_CHANNEL, "radio_step_channel", { ARG_INT } },
@@ -214,9 +226,7 @@ static const mp_cmd_t mp_cmds[] = {
.allow_auto_repeat = true},
{ MP_CMD_CYCLE, "cycle", {
ARG_STRING,
- { .type = {"", NULL, &m_option_type_cycle_dir},
- .optional = true,
- .v.d = 1 },
+ OARG_CYCLEDIR(1),
},
.allow_auto_repeat = true
},
@@ -246,6 +256,9 @@ static const mp_cmd_t mp_cmds[] = {
{0}
};
+#undef OPT_BASE_STRUCT
+#undef ARG
+
// Map legacy commands to proper commands
struct legacy_cmd {
const char *old, *new;
@@ -969,16 +982,35 @@ static int parse_cmd(struct input_ctx *ictx, struct mp_cmd **dest, bstr str,
goto error;
}
+ const struct mp_cmd_def *cmd_def = &mp_cmds[cmd_idx];
cmd = talloc_ptrtype(NULL, cmd);
- *cmd = mp_cmds[cmd_idx];
- cmd->scale = 1;
- cmd->pausing = pausing;
- cmd->on_osd = on_osd;
- cmd->raw_args = raw_args;
+ *cmd = (struct mp_cmd) {
+ .name = (char *)cmd_def->name,
+ .id = cmd_def->id,
+ .pausing = pausing,
+ .on_osd = on_osd,
+ .raw_args = raw_args,
+ .scale = 1,
+ .def = cmd_def,
+ };
+ int min_args = 0;
for (int i = 0; i < MP_CMD_MAX_ARGS; i++) {
struct mp_cmd_arg *cmdarg = &cmd->args[i];
- if (!cmdarg->type.type)
+ const struct m_option *opt = &cmd_def->args[i];
+ if (opt->type) {
+ cmdarg->type = opt;
+ if (opt->defval) {
+ memcpy(&cmdarg->v, opt->defval, opt->type->size);
+ } else {
+ min_args++;
+ }
+ }
+ }
+
+ for (int i = 0; i < MP_CMD_MAX_ARGS; i++) {
+ struct mp_cmd_arg *cmdarg = &cmd->args[i];
+ if (!cmdarg->type)
break;
str = bstr_lstrip(str);
if (eat_token(&str, ";")) {
@@ -1002,19 +1034,19 @@ static int parse_cmd(struct input_ctx *ictx, struct mp_cmd **dest, bstr str,
} else {
if (!read_token(str, &str, &arg))
break;
- if (cmdarg->optional && bstrcmp0(arg, "-") == 0)
+ if (i >= min_args && bstrcmp0(arg, "-") == 0)
continue;
}
// Prevent option API from trying to deallocate static strings
- cmdarg->v = ((struct mp_cmd_arg) {{0}}).v;
- int r = m_option_parse(&cmdarg->type, bstr0(cmd->name), arg, &cmdarg->v);
+ cmdarg->v = ((struct mp_cmd_arg) {0}).v;
+ int r = m_option_parse(cmdarg->type, bstr0(cmd->name), arg, &cmdarg->v);
if (r < 0) {
MP_ERR(ictx, "Command %s: argument %d can't be parsed: %s.\n",
cmd->name, i + 1, m_option_strerror(r));
goto error;
}
- if (cmdarg->type.type == &m_option_type_string)
- cmdarg->v.s = talloc_steal(cmd, cmdarg->v.s);
+ if (cmdarg->type->type == &m_option_type_string)
+ talloc_steal(cmd, cmdarg->v.s);
}
if (eat_token(&str, ";")) {
@@ -1030,12 +1062,6 @@ static int parse_cmd(struct input_ctx *ictx, struct mp_cmd **dest, bstr str,
goto error;
}
- int min_args = 0;
- while (min_args < MP_CMD_MAX_ARGS && cmd->args[min_args].type.type
- && !cmd->args[min_args].optional)
- {
- min_args++;
- }
if (cmd->nargs < min_args) {
MP_ERR(ictx, "Command %s requires at least %d arguments, we found "
"only %d so far.\n", cmd->name, min_args, cmd->nargs);
@@ -1888,7 +1914,7 @@ mp_cmd_t *mp_input_get_cmd(struct input_ctx *ictx, int time, int peek_only)
struct mp_cmd *repeated = check_autorepeat(ictx);
if (repeated) {
repeated->repeated = true;
- if (repeated->allow_auto_repeat) {
+ if (repeated->def && repeated->def->allow_auto_repeat) {
queue_add_tail(queue, repeated);
} else {
talloc_free(repeated);
@@ -1930,8 +1956,8 @@ mp_cmd_t *mp_cmd_clone(mp_cmd_t *cmd)
ret = talloc_memdup(NULL, cmd, sizeof(mp_cmd_t));
ret->name = talloc_strdup(ret, cmd->name);
- for (i = 0; i < MP_CMD_MAX_ARGS; i++) {
- if (cmd->args[i].type.type == &m_option_type_string)
+ for (i = 0; i < ret->nargs; i++) {
+ if (cmd->args[i].type->type == &m_option_type_string)
ret->args[i].v.s = talloc_strdup(ret, cmd->args[i].v.s);
}
@@ -2433,14 +2459,12 @@ static int print_key_list(m_option_t *cfg, char *optname, char *optparam)
static int print_cmd_list(m_option_t *cfg, char *optname, char *optparam)
{
- const mp_cmd_t *cmd;
- int i, j;
-
- for (i = 0; (cmd = &mp_cmds[i])->name != NULL; i++) {
- printf("%-20.20s", cmd->name);
- for (j = 0; j < MP_CMD_MAX_ARGS && cmd->args[j].type.type; j++) {
- const char *type = cmd->args[j].type.type->name;
- if (cmd->args[j].optional)
+ for (int i = 0; mp_cmds[i].name; i++) {
+ const struct mp_cmd_def *def = &mp_cmds[i];
+ printf("%-20.20s", def->name);
+ for (int j = 0; j < MP_CMD_MAX_ARGS && def->args[j].type; j++) {
+ const char *type = def->args[j].type->name;
+ if (def->args[j].defval)
printf(" [%s]", type);
else
printf(" %s", type);
diff --git a/mpvcore/input/input.h b/mpvcore/input/input.h
index f55e151b7d..a7ddaa7db1 100644
--- a/mpvcore/input/input.h
+++ b/mpvcore/input/input.h
@@ -131,8 +131,7 @@ enum mp_input_section_flags {
struct input_ctx;
struct mp_cmd_arg {
- struct m_option type;
- bool optional;
+ const struct m_option *type;
union {
int i;
float f;
@@ -158,7 +157,7 @@ typedef struct mp_cmd {
int mouse_x, mouse_y;
struct mp_cmd *queue_next;
double scale; // for scaling numeric arguments
- bool allow_auto_repeat; // used in command specification
+ const struct mp_cmd_def *def;
} mp_cmd_t;
diff --git a/mpvcore/m_option.h b/mpvcore/m_option.h
index 5e3184a964..684fc2c715 100644
--- a/mpvcore/m_option.h
+++ b/mpvcore/m_option.h
@@ -503,8 +503,10 @@ int m_option_required_params(const m_option_t *opt);
#define OPTION_PATH_SEPARATOR ':'
#endif
-#define OPTDEF_STR(s) .defval = (void *)&(char * const){s}
-#define OPTDEF_INT(i) .defval = (void *)&(const int){i}
+#define OPTDEF_STR(s) .defval = (void *)&(char * const){s}
+#define OPTDEF_INT(i) .defval = (void *)&(const int){i}
+#define OPTDEF_FLOAT(f) .defval = (void *)&(const float){f}
+#define OPTDEF_DOUBLE(d) .defval = (void *)&(const double){d}
#define OPT_GENERAL(ctype, optname, varname, flagv, ...) \
{.name = optname, .flags = flagv, .is_new_option = 1, \
diff --git a/mpvcore/player/command.c b/mpvcore/player/command.c
index bb72ec4d9a..c2db56444e 100644
--- a/mpvcore/player/command.c
+++ b/mpvcore/player/command.c
@@ -2437,7 +2437,7 @@ void run_command(MPContext *mpctx, mp_cmd_t *cmd)
if (!cmd->raw_args) {
for (int n = 0; n < cmd->nargs; n++) {
- if (cmd->args[n].type.type == CONF_TYPE_STRING) {
+ if (cmd->args[n].type->type == CONF_TYPE_STRING) {
cmd->args[n].v.s =
mp_property_expand_string(mpctx, cmd->args[n].v.s);
if (!cmd->args[n].v.s)