From 830560979c02b4e06924a813cf9bacb1629d40c9 Mon Sep 17 00:00:00 2001 From: wm4 Date: Thu, 20 Sep 2012 03:32:01 +0200 Subject: 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. --- core/cfg-mplayer.h | 30 ++++++++++++++-------------- core/m_config.c | 57 ++++++++++++++++++++++++++++++++--------------------- core/m_config.h | 11 +++++++++++ core/m_option.c | 25 +++++++++++++++++++++++ core/m_option.h | 4 ++++ core/parser-mpcmd.c | 33 +++++++++++-------------------- 6 files changed, 101 insertions(+), 59 deletions(-) (limited to 'core') diff --git a/core/cfg-mplayer.h b/core/cfg-mplayer.h index 5770857c2d..c581fe59fe 100644 --- a/core/cfg-mplayer.h +++ b/core/cfg-mplayer.h @@ -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), diff --git a/core/m_config.c b/core/m_config.c index 9c0ddf8e20..f95af2baea 100644 --- a/core/m_config.c +++ b/core/m_config.c @@ -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]; diff --git a/core/m_config.h b/core/m_config.h index de89803cac..8b9b0dc7f7 100644 --- a/core/m_config.h +++ b/core/m_config.h @@ -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. */ diff --git a/core/m_option.c b/core/m_option.c index c1d2ee4fbe..078f9f327b 100644 --- a/core/m_option.c +++ b/core/m_option.c @@ -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 diff --git a/core/m_option.h b/core/m_option.h index 81ab73e98b..a3da08ea7a 100644 --- a/core/m_option.h +++ b/core/m_option.h @@ -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) diff --git a/core/parser-mpcmd.c b/core/parser-mpcmd.c index bc7499fd83..025c7faf97 100644 --- a/core/parser-mpcmd.c +++ b/core/parser-mpcmd.c @@ -87,32 +87,21 @@ static int split_opt_silent(struct parse_state *p) } } + if (m_config_map_option(p->config, &p->arg, &p->param) == M_OPT_INVALID) + return -2; + 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; - - 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. - old_syntax = false; - if (p->param.len) - return -2; - p->arg = s; - p->param = bstr0("no"); - } + if (!p->mp_opt) + return -1; - if (bstr_endswith0(p->arg, "-clr")) + 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 (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]); -- cgit v1.2.3