mirror of
https://github.com/mpv-player/mpv
synced 2024-12-20 22:02:59 +00:00
options: change handling of "no-" options
Normally, all flag options can be negated by prepending a "no-", for example "--no-opt" becomes "--opt=no". Some flag options can't actually be negated, so add a CONF_TYPE_STORE option type to disallow the "no-" fallback. Do the same for choice options. Remove the explicit "no-" prefixed options, add "no" as choice. Move the handling of automatic "no-" options from parser-mpcmd.c to m_config.c, and use it in m_config_set_option/m_config_parse_option. This makes these options available in the config file. It also simplifies sub-option parsing, because it doesn't need to handle "no-" anymore.
This commit is contained in:
parent
ae070a6f1e
commit
830560979c
@ -71,7 +71,7 @@ const m_option_t radioopts_conf[]={
|
||||
#ifdef CONFIG_TV
|
||||
const m_option_t tvopts_conf[]={
|
||||
{"immediatemode", &stream_tv_defaults.immediate, CONF_TYPE_INT, CONF_RANGE, 0, 1, NULL},
|
||||
{"no-audio", &stream_tv_defaults.noaudio, CONF_TYPE_FLAG, 0, 0, 1, NULL},
|
||||
{"audio", &stream_tv_defaults.noaudio, CONF_TYPE_FLAG, 0, 1, 0, NULL},
|
||||
{"audiorate", &stream_tv_defaults.audiorate, CONF_TYPE_INT, 0, 0, 0, NULL},
|
||||
{"driver", &stream_tv_defaults.driver, CONF_TYPE_STRING, 0, 0, 0, NULL},
|
||||
{"device", &stream_tv_defaults.device, CONF_TYPE_STRING, 0, 0, 0, NULL},
|
||||
@ -288,9 +288,9 @@ extern const m_option_t lavc_decode_opts_conf[];
|
||||
const m_option_t common_opts[] = {
|
||||
// ------------------------- common options --------------------
|
||||
OPT_MAKE_FLAGS("quiet", quiet, CONF_GLOBAL),
|
||||
{"really-quiet", &verbose, CONF_TYPE_FLAG, CONF_GLOBAL|CONF_PRE_PARSE, 0, -10, NULL},
|
||||
{"really-quiet", &verbose, CONF_TYPE_STORE, CONF_GLOBAL|CONF_PRE_PARSE, 0, -10, NULL},
|
||||
// -v is handled in command line preparser
|
||||
{"v", NULL, CONF_TYPE_FLAG, CONF_GLOBAL | CONF_NOCFG, 0, 0, NULL},
|
||||
{"v", NULL, CONF_TYPE_STORE, CONF_GLOBAL | CONF_NOCFG, 0, 0, NULL},
|
||||
{"msglevel", (void *) msgl_config, CONF_TYPE_SUBCONFIG, CONF_GLOBAL, 0, 0, NULL},
|
||||
{"msgcolor", &mp_msg_color, CONF_TYPE_FLAG, CONF_GLOBAL | CONF_PRE_PARSE, 0, 1, NULL},
|
||||
{"msgmodule", &mp_msg_module, CONF_TYPE_FLAG, CONF_GLOBAL, 0, 1, NULL},
|
||||
@ -303,9 +303,9 @@ const m_option_t common_opts[] = {
|
||||
// ------------------------- stream options --------------------
|
||||
|
||||
#ifdef CONFIG_STREAM_CACHE
|
||||
OPT_INTRANGE("cache", stream_cache_size, 0, 32, 0x7fffffff, OPTDEF_INT(-1)),
|
||||
OPT_FLAG_CONSTANTS("no-cache", stream_cache_size, 0, -1, 0),
|
||||
|
||||
OPT_CHOICE_OR_INT("cache", stream_cache_size, 0, 32, 0x7fffffff,
|
||||
({"no", -1}),
|
||||
OPTDEF_INT(-1)),
|
||||
OPT_FLOATRANGE("cache-min", stream_cache_min_percent, 0, 0, 99),
|
||||
OPT_FLOATRANGE("cache-seek-min", stream_cache_seek_min_percent, 0, 0, 99),
|
||||
OPT_CHOICE_OR_INT("cache-pause", stream_cache_pause, 0,
|
||||
@ -367,9 +367,9 @@ const m_option_t common_opts[] = {
|
||||
OPT_TRACKCHOICE("aid", audio_id),
|
||||
OPT_TRACKCHOICE("vid", video_id),
|
||||
OPT_TRACKCHOICE("sid", sub_id),
|
||||
OPT_FLAG_CONSTANTS("no-sub", sub_id, 0, -1, -2),
|
||||
OPT_FLAG_CONSTANTS("no-video", video_id, 0, -1, -2),
|
||||
OPT_FLAG_CONSTANTS("no-audio", audio_id, 0, -1, -2),
|
||||
OPT_FLAG_STORE("no-sub", sub_id, 0, -2),
|
||||
OPT_FLAG_STORE("no-video", video_id, 0, -2),
|
||||
OPT_FLAG_STORE("no-audio", audio_id, 0, -2),
|
||||
OPT_STRINGLIST("alang", audio_lang, 0),
|
||||
OPT_STRINGLIST("slang", sub_lang, 0),
|
||||
|
||||
@ -462,7 +462,8 @@ const m_option_t common_opts[] = {
|
||||
{"sws", &sws_flags, CONF_TYPE_INT, 0, 0, 2, NULL},
|
||||
{"ssf", (void *) scaler_filter_conf, CONF_TYPE_SUBCONFIG, 0, 0, 0, NULL},
|
||||
OPT_FLOATRANGE("aspect", movie_aspect, 0, 0.1, 10.0),
|
||||
OPT_FLAG_CONSTANTS("no-aspect", movie_aspect, 0, 0, 0),
|
||||
// xxx: this aliases int with float, which is very evil (but works in this case)
|
||||
OPT_FLAG_STORE("no-aspect", movie_aspect, 0, 0),
|
||||
|
||||
OPT_FLAG_CONSTANTS("flip", flip, 0, 0, 1),
|
||||
|
||||
@ -579,7 +580,7 @@ const m_option_t mplayer_opts[]={
|
||||
// set bpp (x11+vm)
|
||||
OPT_INTRANGE("bpp", vo_dbpp, 0, 0, 32),
|
||||
{"colorkey", &vo_colorkey, CONF_TYPE_INT, 0, 0, 0, NULL},
|
||||
{"no-colorkey", &vo_colorkey, CONF_TYPE_FLAG, 0, 0, 0x1000000, NULL},
|
||||
{"no-colorkey", &vo_colorkey, CONF_TYPE_STORE, 0, 0, 0x1000000, NULL},
|
||||
// wait for v-sync (gl)
|
||||
{"vsync", &vo_vsync, CONF_TYPE_FLAG, 0, 0, 1, NULL},
|
||||
{"panscan", &vo_panscan, CONF_TYPE_FLOAT, CONF_RANGE, 0, 1.0, NULL},
|
||||
@ -645,8 +646,7 @@ const m_option_t mplayer_opts[]={
|
||||
|
||||
{"leak-report", "", CONF_TYPE_PRINT, 0, 0, 0, (void*)1},
|
||||
|
||||
OPT_FLAG_CONSTANTS("no-loop", loop_times, 0, 0, -1),
|
||||
OPT_CHOICE_OR_INT("loop", loop_times, CONF_GLOBAL, 1, 10000,
|
||||
OPT_CHOICE_OR_INT("loop", loop_times, M_OPT_GLOBAL, 1, 10000,
|
||||
({"no", -1}, {"0", -1},
|
||||
{"inf", 0})),
|
||||
|
||||
@ -666,8 +666,8 @@ const m_option_t mplayer_opts[]={
|
||||
OPT_CHOICE("hr-seek", hr_seek, 0,
|
||||
({"no", -1}, {"absolute", 0}, {"always", 1}, {"yes", 1})),
|
||||
OPT_FLOATRANGE("hr-seek-demuxer-offset", hr_seek_demuxer_offset, 0, -9, 99),
|
||||
OPT_FLAG_CONSTANTS("no-autosync", autosync, 0, 0, -1),
|
||||
OPT_INTRANGE("autosync", autosync, 0, 0, 10000),
|
||||
OPT_CHOICE_OR_INT("autosync", autosync, 0, 0, 10000,
|
||||
({"no", -1})),
|
||||
|
||||
OPT_FLAG_ON("softsleep", softsleep, 0),
|
||||
|
||||
|
@ -392,6 +392,13 @@ static int m_config_parse_option(struct m_config *config, void *optstruct,
|
||||
assert(config != NULL);
|
||||
assert(name.len != 0);
|
||||
|
||||
if (m_config_map_option(config, &name, ¶m) == M_OPT_INVALID) {
|
||||
mp_tmsg(MSGT_CFGPARSER, MSGL_ERR,
|
||||
"A no-* option can't take parameters: --%.*s=%.*s\n",
|
||||
BSTR_P(name), BSTR_P(param));
|
||||
return M_OPT_INVALID;
|
||||
}
|
||||
|
||||
struct m_config_option *co = m_config_get_co(config, name);
|
||||
if (!co)
|
||||
return M_OPT_UNKNOWN;
|
||||
@ -446,32 +453,15 @@ static int parse_subopts(struct m_config *config, void *optstruct, char *name,
|
||||
char n[110];
|
||||
if (snprintf(n, 110, "%s%s", prefix, lst[2 * i]) > 100)
|
||||
abort();
|
||||
if (!m_config_get_option(config, bstr0(n))) {
|
||||
if (strncmp(lst[2 * i], "no-", 3))
|
||||
goto nosubopt;
|
||||
snprintf(n, 110, "%s%s", prefix, lst[2 * i] + 3);
|
||||
const struct m_option *o = m_config_get_option(config, bstr0(n));
|
||||
if (!o || o->type != &m_option_type_flag) {
|
||||
nosubopt:
|
||||
int sr = m_config_parse_option(config, optstruct, bstr0(n),
|
||||
bstr0(lst[2 * i + 1]), set);
|
||||
if (sr < 0) {
|
||||
if (sr == M_OPT_UNKNOWN) {
|
||||
mp_tmsg(MSGT_CFGPARSER, MSGL_ERR,
|
||||
"Error: option '%s' has no suboption '%s'.\n",
|
||||
name, lst[2 * i]);
|
||||
r = M_OPT_INVALID;
|
||||
break;
|
||||
}
|
||||
if (lst[2 * i + 1]) {
|
||||
mp_tmsg(MSGT_CFGPARSER, MSGL_ERR,
|
||||
"A --no-* option can't take parameters: "
|
||||
"%s=%s\n", lst[2 * i], lst[2 * i + 1]);
|
||||
r = M_OPT_INVALID;
|
||||
break;
|
||||
}
|
||||
lst[2 * i + 1] = "no";
|
||||
}
|
||||
int sr = m_config_parse_option(config, optstruct, bstr0(n),
|
||||
bstr0(lst[2 * i + 1]), set);
|
||||
if (sr < 0) {
|
||||
if (sr == M_OPT_MISSING_PARAM) {
|
||||
} else if (sr == M_OPT_MISSING_PARAM) {
|
||||
mp_tmsg(MSGT_CFGPARSER, MSGL_ERR,
|
||||
"Error: suboption '%s' of '%s' must have "
|
||||
"a parameter!\n", lst[2 * i], name);
|
||||
@ -532,6 +522,29 @@ const struct m_option *m_config_get_option(const struct m_config *config,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int m_config_map_option(struct m_config *config, bstr *name, bstr *param)
|
||||
{
|
||||
bstr s = *name;
|
||||
if (m_config_get_option(config, s))
|
||||
return 0;
|
||||
|
||||
if (!bstr_eatstart0(&s, "no-"))
|
||||
return M_OPT_UNKNOWN;
|
||||
|
||||
const struct m_option *opt = m_config_get_option(config, s);
|
||||
if (!opt || (opt->type != &m_option_type_flag
|
||||
&& opt->type != &m_option_type_choice))
|
||||
return M_OPT_UNKNOWN;
|
||||
// Avoid allowing "--no-no-opt".
|
||||
if (bstr_startswith(bstr0(opt->name), bstr0("no-")))
|
||||
return M_OPT_UNKNOWN;
|
||||
if (param->len)
|
||||
return M_OPT_INVALID;
|
||||
*name = s;
|
||||
*param = bstr0("no");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void m_config_print_option_list(const struct m_config *config)
|
||||
{
|
||||
char min[50], max[50];
|
||||
|
@ -155,6 +155,17 @@ const struct m_option *m_config_get_option(const struct m_config *config,
|
||||
struct m_config_option *m_config_get_co(const struct m_config *config,
|
||||
struct bstr name);
|
||||
|
||||
/* Map options like "no-opt=" to "opt=no".
|
||||
* config The config object.
|
||||
* \param name The option's name. May be set to a new name.
|
||||
* \param param The option value. May be set to a new value.
|
||||
* \return The following error codes:
|
||||
* M_OPT_UNKNOWN: option not found
|
||||
* M_OPT_INVALID: parameter non-empty in map case, prevents the mapping
|
||||
* 0: success, *name and *param have been changed (or not)
|
||||
*/
|
||||
int m_config_map_option(struct m_config *config, bstr *name, bstr *param);
|
||||
|
||||
/* Print a list of all registered options.
|
||||
* \param config The config object.
|
||||
*/
|
||||
|
@ -152,6 +152,31 @@ const m_option_type_t m_option_type_flag = {
|
||||
.clamp = clamp_flag,
|
||||
};
|
||||
|
||||
// Single-value, write-only flag
|
||||
|
||||
static int parse_store(const m_option_t *opt, struct bstr name,
|
||||
struct bstr param, void *dst)
|
||||
{
|
||||
if (param.len == 0 || bstrcasecmp0(param, "yes") == 0) {
|
||||
if (dst)
|
||||
VAL(dst) = opt->max;
|
||||
return 0;
|
||||
} else {
|
||||
mp_msg(MSGT_CFGPARSER, MSGL_ERR,
|
||||
"Invalid parameter for %.*s flag: %.*s\n",
|
||||
BSTR_P(name), BSTR_P(param));
|
||||
return M_OPT_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
const m_option_type_t m_option_type_store = {
|
||||
// can only be activated
|
||||
.name = "Flag",
|
||||
.size = sizeof(int),
|
||||
.flags = M_OPT_TYPE_OLD_SYNTAX_NO_PARAM,
|
||||
.parse = parse_store,
|
||||
};
|
||||
|
||||
// Integer
|
||||
|
||||
#undef VAL
|
||||
|
@ -36,6 +36,7 @@ struct m_struct_st;
|
||||
|
||||
// Simple types
|
||||
extern const m_option_type_t m_option_type_flag;
|
||||
extern const m_option_type_t m_option_type_store;
|
||||
extern const m_option_type_t m_option_type_int;
|
||||
extern const m_option_type_t m_option_type_int64;
|
||||
extern const m_option_type_t m_option_type_intpair;
|
||||
@ -180,6 +181,7 @@ struct m_sub_options {
|
||||
|
||||
// FIXME: backward compatibility
|
||||
#define CONF_TYPE_FLAG (&m_option_type_flag)
|
||||
#define CONF_TYPE_STORE (&m_option_type_store)
|
||||
#define CONF_TYPE_INT (&m_option_type_int)
|
||||
#define CONF_TYPE_INT64 (&m_option_type_int64)
|
||||
#define CONF_TYPE_FLOAT (&m_option_type_float)
|
||||
@ -205,6 +207,7 @@ struct m_sub_options {
|
||||
// size/alignment requirements for option values in general.
|
||||
union m_option_value {
|
||||
int flag; // not the C type "bool"!
|
||||
int store;
|
||||
int int_;
|
||||
int64_t int64;
|
||||
float float_;
|
||||
@ -513,6 +516,7 @@ static inline void m_option_free(const m_option_t *opt, void *dst)
|
||||
#define OPT_MAKE_FLAGS OPT_FLAG_ON
|
||||
#define OPT_FLAG_CONSTANTS(...) OPT_FLAG_CONSTANTS_(__VA_ARGS__, .type = &m_option_type_flag)
|
||||
#define OPT_FLAG_CONSTANTS_(optname, varname, flags, offvalue, value, ...) OPT_GENERAL(optname, varname, flags, .min = offvalue, .max = value, __VA_ARGS__)
|
||||
#define OPT_FLAG_STORE(optname, varname, flags, value) OPT_GENERAL(optname, varname, flags, .max = value, .type = &m_option_type_store)
|
||||
#define OPT_STRINGLIST(...) OPT_GENERAL(__VA_ARGS__, .type = &m_option_type_string_list)
|
||||
#define OPT_PATHLIST(...) OPT_GENERAL(__VA_ARGS__, .type = &m_option_type_string_list, .priv = (void *)&(const char){OPTION_PATH_SEPARATOR})
|
||||
#define OPT_INT(...) OPT_GENERAL(__VA_ARGS__, .type = &m_option_type_int)
|
||||
|
@ -87,32 +87,21 @@ static int split_opt_silent(struct parse_state *p)
|
||||
}
|
||||
}
|
||||
|
||||
p->mp_opt = m_config_get_option(p->config, p->arg);
|
||||
if (!p->mp_opt) {
|
||||
// Automagic "no-" arguments: "--no-bla" turns into "--bla=no".
|
||||
if (!bstr_startswith0(p->arg, "no-"))
|
||||
return -1;
|
||||
if (m_config_map_option(p->config, &p->arg, &p->param) == M_OPT_INVALID)
|
||||
return -2;
|
||||
|
||||
struct bstr s = bstr_cut(p->arg, 3);
|
||||
p->mp_opt = m_config_get_option(p->config, s);
|
||||
if (!p->mp_opt || p->mp_opt->type != &m_option_type_flag)
|
||||
return -1;
|
||||
// Avoid allowing "--no-no-bla".
|
||||
if (bstr_startswith(bstr0(p->mp_opt->name), bstr0("no-")))
|
||||
return -1;
|
||||
// Flag options never have parameters.
|
||||
p->mp_opt = m_config_get_option(p->config, p->arg);
|
||||
if (!p->mp_opt)
|
||||
return -1;
|
||||
|
||||
if ((p->mp_opt->type->flags & M_OPT_TYPE_OLD_SYNTAX_NO_PARAM)
|
||||
|| p->param.len
|
||||
|| bstr_endswith0(p->arg, "-clr"))
|
||||
{
|
||||
old_syntax = false;
|
||||
if (p->param.len)
|
||||
return -2;
|
||||
p->arg = s;
|
||||
p->param = bstr0("no");
|
||||
}
|
||||
|
||||
if (bstr_endswith0(p->arg, "-clr"))
|
||||
old_syntax = false;
|
||||
|
||||
if (old_syntax && !(p->mp_opt->type->flags & M_OPT_TYPE_OLD_SYNTAX_NO_PARAM))
|
||||
{
|
||||
if (old_syntax) {
|
||||
if (p->argc < 1)
|
||||
return -3;
|
||||
p->param = bstr0(p->argv[0]);
|
||||
|
@ -1643,7 +1643,6 @@ const struct vo_driver video_out_vdpau = {
|
||||
.options = (const struct m_option []){
|
||||
OPT_INTRANGE("deint", deint, 0, -4, 4),
|
||||
OPT_FLAG_ON("chroma-deint", chroma_deint, 0, OPTDEF_INT(1)),
|
||||
OPT_FLAG_OFF("nochroma-deint", chroma_deint, 0),
|
||||
OPT_MAKE_FLAGS("pullup", pullup, 0),
|
||||
OPT_FLOATRANGE("denoise", denoise, 0, 0, 1),
|
||||
OPT_FLOATRANGE("sharpen", sharpen, 0, -1, 1),
|
||||
|
Loading…
Reference in New Issue
Block a user