From 80bc73d81349c7f74b2425b2cb5403443a4a5c5c Mon Sep 17 00:00:00 2001 From: Dudemanguy Date: Sat, 2 Mar 2024 09:17:52 -0600 Subject: [PATCH] player/command: implement skippable arguments in commands Optional arguments already exist, but they're not exactly skippable. If you exclude one of these arguments, everything else afterwards also needs to be excluded. In c678033c1d60b48ae02fbbe4815869b9504a17f6, the arguments of loadfile were changed so a new index argument (optional) must always exist before you can pass the options argument. This naturally breaks the old syntax and to be fair, it is a bit weird to do something like "loadfile file.mkv append -1 options=value". So let's make the old commands compatibile again by making the index argument skippable and adding functionality to support this. The actual command itself (cmd_loadfile) is responsible for handling this sanely. --- input/cmd.c | 13 +++++++++++++ input/cmd.h | 1 + options/m_option.h | 3 +++ player/command.c | 15 +++++++++++---- 4 files changed, 28 insertions(+), 4 deletions(-) diff --git a/input/cmd.c b/input/cmd.c index 64232143f7644..3a26e2f792cbd 100644 --- a/input/cmd.c +++ b/input/cmd.c @@ -416,6 +416,19 @@ static struct mp_cmd *parse_cmd_str(struct mp_log *log, void *tmp, struct mp_cmd_arg arg = {.type = opt}; r = m_option_parse(ctx->log, opt, bstr0(cmd->name), cur_token, &arg.v); + + // Try to read the next cmd arg instead. + while (r < 0 && opt->skippable) { + assert(i + 1 < MP_CMD_MAX_ARGS); + ++i; + arg.skipped = true; + opt = get_arg_type(cmd->def, i); + if (!opt) + break; + 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)); diff --git a/input/cmd.h b/input/cmd.h index 3d4b15fcc3ee4..0efbf0558ab96 100644 --- a/input/cmd.h +++ b/input/cmd.h @@ -94,6 +94,7 @@ struct mp_cmd_arg { char **str_list; void *p; } v; + bool skipped; }; typedef struct mp_cmd { diff --git a/options/m_option.h b/options/m_option.h index 891b51794e1e1..4c339b41bfda8 100644 --- a/options/m_option.h +++ b/options/m_option.h @@ -384,6 +384,9 @@ struct m_option { // See \ref OptionFlags. unsigned int flags; + // Only for use with commands + bool skippable; + int offset; // Most numeric types restrict the range to [min, max] if minmpctx; char *filename = cmd->args[0].v.s; int action_flag = cmd->args[1].v.i; - int insert_at_idx = cmd->args[2].v.i; + int insert_at_idx = -1; + char **pairs; + + if (cmd->args[2].skipped) { + pairs = cmd->args[2].v.str_list; + } else { + insert_at_idx = cmd->args[2].v.i; + pairs = cmd->args[3].v.str_list; + } struct load_action action = get_load_action(mpctx, action_flag); @@ -5591,8 +5599,7 @@ static void cmd_loadfile(void *p) playlist_clear(mpctx->playlist); struct playlist_entry *entry = playlist_entry_new(filename); - if (cmd->args[3].v.str_list) { - char **pairs = cmd->args[3].v.str_list; + if (pairs) { for (int i = 0; pairs[i] && pairs[i + 1]; i += 2) playlist_entry_add_param(entry, bstr0(pairs[i]), bstr0(pairs[i + 1])); } @@ -6769,7 +6776,7 @@ const struct mp_cmd_def mp_cmds[] = { {"insert-at", 5}, {"insert-at-play", 6}), .flags = MP_CMD_OPT_ARG}, - {"index", OPT_INT(v.i), OPTDEF_INT(-1)}, + {"index", OPT_INT(v.i), .flags = MP_CMD_OPT_ARG, .skippable = true}, {"options", OPT_KEYVALUELIST(v.str_list), .flags = MP_CMD_OPT_ARG}, }, },