diff options
-rw-r--r-- | DOCS/man/en/mpv.rst | 23 | ||||
-rw-r--r-- | core/cfg-mplayer.h | 8 | ||||
-rw-r--r-- | core/m_config.c | 126 | ||||
-rw-r--r-- | core/m_config.h | 56 | ||||
-rw-r--r-- | core/m_option.c | 23 | ||||
-rw-r--r-- | core/m_option.h | 23 | ||||
-rw-r--r-- | core/parser-cfg.c | 38 | ||||
-rw-r--r-- | core/parser-mpcmd.c | 85 |
8 files changed, 175 insertions, 207 deletions
diff --git a/DOCS/man/en/mpv.rst b/DOCS/man/en/mpv.rst index 60f8d0cabc..5f6a659e69 100644 --- a/DOCS/man/en/mpv.rst +++ b/DOCS/man/en/mpv.rst @@ -285,29 +285,6 @@ the *XXX* option or if *XXX* is compiled in. | Or in a script: | `mpv --ao=pcm:file=%\`expr length "$NAME"\`%"$NAME" test.avi` -Single dash versus double dash options --------------------------------------- - -There are actually two option syntaxes: one which uses a single dash (``-opt``), -and one with double dashes (``--opt``). The double dash syntax always requires -a ``=`` to separate option name and value, while single dash options use a -space. - - -| Both of these examples pass the value `pcm:file=test.wav` to the `ao` option: -| `mpv -ao pcm:file=test.wav` -| `mpv --ao=pcm:file=test.wav` - -| This passes the empty string to `ao`, while `pcm:file=test.wav` is interpreted - as filename (common mistake): -| `mpv --ao pcm:file=test.wav` - -It's best to stick to one syntax to avoid usage errors. The double dash syntax -is preferred, and used throughout the manpage. - -*NOTE*: the differences between these syntaxes might be removed in the future. -However, this has not happened yet. - Per-file options ---------------- diff --git a/core/cfg-mplayer.h b/core/cfg-mplayer.h index c581fe59fe..edab5f37e4 100644 --- a/core/cfg-mplayer.h +++ b/core/cfg-mplayer.h @@ -549,10 +549,10 @@ const m_option_t mplayer_opts[]={ OPT_FLOATRANGE("softvol-max", softvol_max, 0, 10, 10000), {"volstep", &volstep, CONF_TYPE_INT, CONF_RANGE, 0, 100, NULL}, OPT_FLOATRANGE("volume", mixer_init_volume, 0, -1, 10000), - OPT_CHOICE("mute", mixer_init_mute, 0, + OPT_CHOICE("mute", mixer_init_mute, M_OPT_OPTIONAL_PARAM, ({"auto", -1}, {"no", 0}, - {"yes", 1})), + {"yes", 1}, {"", 1})), OPT_MAKE_FLAGS("gapless-audio", gapless_audio, 0), // override audio buffer size (used only by -ao oss/win32, obsolete) OPT_INT("abs", ao_buffersize, 0), @@ -635,7 +635,7 @@ const m_option_t mplayer_opts[]={ OPT_CHOICE("framedrop", frame_dropping, 0, ({"no", 0}, - {"yes", 1}, {"", 1}, + {"yes", 1}, {"hard", 2})), OPT_FLAG_ON("untimed", untimed, 0), @@ -673,7 +673,7 @@ const m_option_t mplayer_opts[]={ OPT_CHOICE("term-osd", term_osd, 0, ({"force", 1}, - {"auto", 2}, {"", 2}, + {"auto", 2}, {"no", 0})), OPT_STRING("term-osd-esc", term_osd_esc, 0, OPTDEF_STR("\x1b[A\r\x1b[K")), diff --git a/core/m_config.c b/core/m_config.c index f95af2baea..2d994bb802 100644 --- a/core/m_config.c +++ b/core/m_config.c @@ -384,20 +384,18 @@ struct m_config_option *m_config_get_co(const struct m_config *config, } static int parse_subopts(struct m_config *config, void *optstruct, char *name, - char *prefix, struct bstr param, bool set); + char *prefix, struct bstr param, int flags); static int m_config_parse_option(struct m_config *config, void *optstruct, - struct bstr name, struct bstr param, bool set) + struct bstr name, struct bstr param, int flags) { assert(config != NULL); assert(name.len != 0); + bool set = !(flags & M_SETOPT_CHECK_ONLY); - 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; - } + int r = m_config_map_option(config, &name, ¶m, false); + if (r < 0) + return r; struct m_config_option *co = m_config_get_co(config, name); if (!co) @@ -406,8 +404,11 @@ static int m_config_parse_option(struct m_config *config, void *optstruct, // This is the only mandatory function assert(co->opt->type->parse); + if ((flags & M_SETOPT_PRE_PARSE_ONLY) && !(co->opt->flags & M_OPT_PRE_PARSE)) + return 0; + // Check if this option isn't forbidden in the current mode - if ((config->mode == M_CONFIG_FILE) && (co->opt->flags & M_OPT_NOCFG)) { + if ((flags & M_SETOPT_FROM_CONFIG_FILE) && (co->opt->flags & M_OPT_NOCFG)) { mp_tmsg(MSGT_CFGPARSER, MSGL_ERR, "The %.*s option can't be used in a config file.\n", BSTR_P(name)); @@ -430,7 +431,7 @@ static int m_config_parse_option(struct m_config *config, void *optstruct, char prefix[110]; assert(strlen(co->name) < 100); sprintf(prefix, "%s:", co->name); - return parse_subopts(config, optstruct, co->name, prefix, param, set); + return parse_subopts(config, optstruct, co->name, prefix, param, flags); } if (set) @@ -440,7 +441,7 @@ static int m_config_parse_option(struct m_config *config, void *optstruct, } static int parse_subopts(struct m_config *config, void *optstruct, char *name, - char *prefix, struct bstr param, bool set) + char *prefix, struct bstr param, int flags) { char **lst = NULL; // Split the argument into child options @@ -453,21 +454,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(); - 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; - } else if (sr == M_OPT_MISSING_PARAM) { + r = m_config_parse_option(config, optstruct, bstr0(n), + bstr0(lst[2 * i + 1]), flags); + if (r < 0) { + if (r > M_OPT_EXIT) { mp_tmsg(MSGT_CFGPARSER, MSGL_ERR, - "Error: suboption '%s' of '%s' must have " - "a parameter!\n", lst[2 * i], name); + "Error parsing suboption %s/%s (%s)\n", + name, lst[2 * i], m_option_strerror(r)); r = M_OPT_INVALID; - } else - r = sr; + } break; } } @@ -475,39 +470,38 @@ static int parse_subopts(struct m_config *config, void *optstruct, char *name, return r; } -int m_config_set_option(struct m_config *config, struct bstr name, - struct bstr param) +int m_config_parse_suboptions(struct m_config *config, char *name, + char *subopts) { - mp_msg(MSGT_CFGPARSER, MSGL_DBG2, "Setting %.*s=%.*s\n", BSTR_P(name), - BSTR_P(param)); - return m_config_parse_option(config, config->optstruct, name, param, true); + if (!subopts || !*subopts) + return 0; + int r = parse_subopts(config, config->optstruct, name, "", bstr0(subopts), 0); + if (r < 0 && r > M_OPT_EXIT) { + mp_tmsg(MSGT_CFGPARSER, MSGL_ERR, "Error parsing suboption %s (%s)\n", + name, m_option_strerror(r)); + r = M_OPT_INVALID; + } + return r; } -int m_config_check_option(struct m_config *config, struct bstr name, - struct bstr param) +int m_config_set_option_ext(struct m_config *config, struct bstr name, + struct bstr param, int flags) { - int r; - mp_msg(MSGT_CFGPARSER, MSGL_DBG2, "Checking %.*s=%.*s\n", BSTR_P(name), - BSTR_P(param)); - r = m_config_parse_option(config, NULL, name, param, 0); - if (r == M_OPT_MISSING_PARAM) { - mp_tmsg(MSGT_CFGPARSER, MSGL_ERR, - "Error: option '%.*s' must have a parameter!\n", BSTR_P(name)); - return M_OPT_INVALID; + int r = m_config_parse_option(config, config->optstruct, name, param, flags); + if (r < 0 && r > M_OPT_EXIT) { + mp_tmsg(MSGT_CFGPARSER, MSGL_ERR, "Error parsing option %.*s (%s)\n", + BSTR_P(name), m_option_strerror(r)); + r = M_OPT_INVALID; } return r; } -int m_config_parse_suboptions(struct m_config *config, char *name, - char *subopts) +int m_config_set_option(struct m_config *config, struct bstr name, + struct bstr param) { - if (!subopts || !*subopts) - return 0; - return parse_subopts(config, config->optstruct, name, "", bstr0(subopts), - true); + return m_config_set_option_ext(config, name, param, 0); } - const struct m_option *m_config_get_option(const struct m_config *config, struct bstr name) { @@ -522,16 +516,24 @@ 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) +int m_config_map_option(struct m_config *config, bstr *name, bstr *param, + bool ambiguous) { bstr s = *name; - if (m_config_get_option(config, s)) - return 0; + const struct m_option *opt = m_config_get_option(config, s); + if (opt) { + if (bstr_endswith0(s, "-clr")) + return (ambiguous || !param->len) ? 0 : M_OPT_DISALLOW_PARAM; + if (ambiguous && ((opt->flags & M_OPT_OPTIONAL_PARAM) || + (opt->type->flags & M_OPT_TYPE_OPTIONAL_PARAM))) + return 0; + return 1; + } if (!bstr_eatstart0(&s, "no-")) return M_OPT_UNKNOWN; - const struct m_option *opt = m_config_get_option(config, s); + 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; @@ -539,7 +541,7 @@ int m_config_map_option(struct m_config *config, bstr *name, bstr *param) if (bstr_startswith(bstr0(opt->name), bstr0("no-"))) return M_OPT_UNKNOWN; if (param->len) - return M_OPT_INVALID; + return M_OPT_DISALLOW_PARAM; *name = s; *param = bstr0("no"); return 0; @@ -610,14 +612,16 @@ void m_profile_set_desc(struct m_profile *p, char *desc) } int m_config_set_profile_option(struct m_config *config, struct m_profile *p, - char *name, char *val) + bstr name, bstr val) { - int i = m_config_check_option0(config, name, val); + int i = m_config_set_option_ext(config, name, val, + M_SETOPT_CHECK_ONLY | + M_SETOPT_FROM_CONFIG_FILE); if (i < 0) return i; p->opts = talloc_realloc(p, p->opts, char *, 2 * (p->num_opts + 2)); - p->opts[p->num_opts * 2] = talloc_strdup(p, name); - p->opts[p->num_opts * 2 + 1] = talloc_strdup(p, val); + p->opts[p->num_opts * 2] = bstrdup0(p, name); + p->opts[p->num_opts * 2 + 1] = bstrdup0(p, val); p->num_opts++; p->opts[p->num_opts * 2] = p->opts[p->num_opts * 2 + 1] = NULL; return 1; @@ -625,19 +629,19 @@ int m_config_set_profile_option(struct m_config *config, struct m_profile *p, void m_config_set_profile(struct m_config *config, struct m_profile *p) { - int i; if (config->profile_depth > MAX_PROFILE_DEPTH) { mp_tmsg(MSGT_CFGPARSER, MSGL_WARN, "WARNING: Profile inclusion too deep.\n"); return; } - int prev_mode = config->mode; - config->mode = M_CONFIG_FILE; config->profile_depth++; - for (i = 0; i < p->num_opts; i++) - m_config_set_option0(config, p->opts[2 * i], p->opts[2 * i + 1]); + for (int i = 0; i < p->num_opts; i++) { + m_config_set_option_ext(config, + bstr0(p->opts[2 * i]), + bstr0(p->opts[2 * i + 1]), + M_SETOPT_FROM_CONFIG_FILE); + } config->profile_depth--; - config->mode = prev_mode; } void *m_config_alloc_struct(void *talloc_parent, diff --git a/core/m_config.h b/core/m_config.h index 8b9b0dc7f7..57170cf48a 100644 --- a/core/m_config.h +++ b/core/m_config.h @@ -64,13 +64,6 @@ struct m_profile { char **opts; }; -enum option_source { - // Set when parsing command line arguments. - M_COMMAND_LINE, - // Set when parsing from a config file. - M_CONFIG_FILE, -}; - // Config object /** \ingroup Config */ typedef struct m_config { @@ -78,7 +71,6 @@ typedef struct m_config { /** This contains all options and suboptions. */ struct m_config_option *opts; - enum option_source mode; // When options are set (via m_config_set_option or m_config_set_profile), // back up the old value (unless it's already backed up). Used for restoring // global options when per-file options are set. @@ -114,7 +106,19 @@ void m_config_leave_file_local(struct m_config *config); int m_config_register_options(struct m_config *config, const struct m_option *args); -/* Set an option. +enum { + M_SETOPT_PRE_PARSE_ONLY = 1, // Silently ignore non-M_OPT_PRE_PARSE opt. + M_SETOPT_CHECK_ONLY = 2, // Don't set, just check name/value + M_SETOPT_FROM_CONFIG_FILE = 4, // Reject M_OPT_NOCFG opt. (print error) +}; + +// Set the named option to the given string. +// flags: combination of M_SETOPT_* flags (0 for normal operation) +// Returns >= 0 on success, otherwise see OptionParserReturn. +int m_config_set_option_ext(struct m_config *config, struct bstr name, + struct bstr param, int flags); + +/* Set an option. (Like: m_config_set_option_ext(config, name, param, 0)) * \param config The config object. * \param name The option's name. * \param param The value of the option, can be NULL. @@ -129,18 +133,6 @@ static inline int m_config_set_option0(struct m_config *config, return m_config_set_option(config, bstr0(name), bstr0(param)); } -/* Check if an option setting is valid. - * Same as above m_config_set_option() but doesn't actually set anything. - */ -int m_config_check_option(struct m_config *config, struct bstr name, - struct bstr param); - -static inline int m_config_check_option0(struct m_config *config, - const char *name, const char *param) -{ - return m_config_check_option(config, bstr0(name), bstr0(param)); -} - int m_config_parse_suboptions(struct m_config *config, char *name, char *subopts); @@ -156,15 +148,19 @@ 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) + * config: config object. + * name: option's name. May be set to a new name. + * value: option value. May be set to a new value. + * ambiguous: if true, "value" may be either an option value, or a separate, + * unrelated option following the current option. + * returns the following error codes: + * < 0: one of the M_OPT_ error codes + * 0: the option is valid, *value is set implicitly + * ("--foo bar" maps to "--foo=yes" + "bar", *value == "yes") + * 1: the option is valid, *value is a proper parameter */ -int m_config_map_option(struct m_config *config, bstr *name, bstr *param); +int m_config_map_option(struct m_config *config, bstr *name, bstr *value, + bool ambiguous); /* Print a list of all registered options. * \param config The config object. @@ -204,7 +200,7 @@ void m_profile_set_desc(struct m_profile *p, char *desc); * \param val The option's value. */ int m_config_set_profile_option(struct m_config *config, struct m_profile *p, - char *name, char *val); + bstr name, bstr val); /* Enables profile usage * Used by the config file parser when loading a profile. diff --git a/core/m_option.c b/core/m_option.c index 078f9f327b..595675cebb 100644 --- a/core/m_option.c +++ b/core/m_option.c @@ -43,17 +43,18 @@ char *m_option_strerror(int code) { switch (code) { case M_OPT_UNKNOWN: - return mp_gtext("Unrecognized option name"); + return mp_gtext("option not found"); case M_OPT_MISSING_PARAM: - return mp_gtext("Required parameter for option missing"); + return mp_gtext("option requires parameter"); case M_OPT_INVALID: - return mp_gtext("Option parameter could not be parsed"); + return mp_gtext("option parameter could not be parsed"); case M_OPT_OUT_OF_RANGE: - return mp_gtext("Parameter is outside values allowed for option"); + return mp_gtext("parameter is outside values allowed for option"); + case M_OPT_DISALLOW_PARAM: + return mp_gtext("option doesn't take a parameter"); case M_OPT_PARSER_ERR: - return mp_gtext("Parser error"); default: - return NULL; + return mp_gtext("parser error"); } } @@ -144,7 +145,7 @@ const m_option_type_t m_option_type_flag = { // need yes or no in config files .name = "Flag", .size = sizeof(int), - .flags = M_OPT_TYPE_OLD_SYNTAX_NO_PARAM, + .flags = M_OPT_TYPE_OPTIONAL_PARAM, .parse = parse_flag, .print = print_flag, .copy = copy_opt, @@ -165,7 +166,7 @@ static int parse_store(const m_option_t *opt, struct bstr name, mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Invalid parameter for %.*s flag: %.*s\n", BSTR_P(name), BSTR_P(param)); - return M_OPT_INVALID; + return M_OPT_DISALLOW_PARAM; } } @@ -173,7 +174,7 @@ 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, + .flags = M_OPT_TYPE_OPTIONAL_PARAM, .parse = parse_store, }; @@ -1039,7 +1040,7 @@ static int parse_print(const m_option_t *opt, struct bstr name, const m_option_type_t m_option_type_print = { .name = "Print", - .flags = M_OPT_TYPE_OLD_SYNTAX_NO_PARAM, + .flags = M_OPT_TYPE_OPTIONAL_PARAM, .parse = parse_print, }; @@ -1051,7 +1052,7 @@ const m_option_type_t m_option_type_print_func_param = { const m_option_type_t m_option_type_print_func = { .name = "Print", - .flags = M_OPT_TYPE_ALLOW_WILDCARD | M_OPT_TYPE_OLD_SYNTAX_NO_PARAM, + .flags = M_OPT_TYPE_ALLOW_WILDCARD | M_OPT_TYPE_OPTIONAL_PARAM, .parse = parse_print, }; diff --git a/core/m_option.h b/core/m_option.h index a3da08ea7a..e63bf3610f 100644 --- a/core/m_option.h +++ b/core/m_option.h @@ -363,6 +363,9 @@ struct m_option { // (e.g. "--parent=child=value" becomes "--child=value") #define M_OPT_MERGE (1 << 9) +// See M_OPT_TYPE_OPTIONAL_PARAM. +#define M_OPT_OPTIONAL_PARAM (1 << 10) + // These are kept for compatibility with older code. #define CONF_MIN M_OPT_MIN #define CONF_MAX M_OPT_MAX @@ -397,10 +400,11 @@ struct m_option { */ #define M_OPT_TYPE_DYNAMIC (1 << 2) -// The parameter is optional and by default no parameter is preferred. If the -// "old syntax" is used, the command line parser will assume that the argument -// takes no parameter. -#define M_OPT_TYPE_OLD_SYNTAX_NO_PARAM (1 << 3) +// The parameter is optional and by default no parameter is preferred. If +// ambiguous syntax is used ("--opt value"), the command line parser will +// assume that the argument takes no parameter. In config files, these +// options can be used without "=" and value. +#define M_OPT_TYPE_OPTIONAL_PARAM (1 << 3) // modify M_OPT_TYPE_HAS_CHILD so that m_option::p points to // struct m_sub_options, instead of a direct m_option array. @@ -408,7 +412,9 @@ struct m_option { ///////////////////////////// Parser flags ///////////////////////////////// -// On success parsers return the number of arguments consumed: 0 or 1. +// OptionParserReturn +// +// On success parsers return a number >= 0. // // To indicate that MPlayer should exit without playing anything, // parsers return M_OPT_EXIT minus the number of parameters they @@ -429,13 +435,16 @@ struct m_option { // vary from type to type. #define M_OPT_OUT_OF_RANGE -4 +// The option doesn't take a parameter. +#define M_OPT_DISALLOW_PARAM -5 + // Returned if the parser failed for any other reason than a bad parameter. -#define M_OPT_PARSER_ERR -5 +#define M_OPT_PARSER_ERR -6 // Returned when MPlayer should exit. Used by various help stuff. /** M_OPT_EXIT must be the lowest number on this list. */ -#define M_OPT_EXIT -6 +#define M_OPT_EXIT -7 char *m_option_strerror(int code); diff --git a/core/parser-cfg.c b/core/parser-cfg.c index 1a67389854..e5bf6eb3b5 100644 --- a/core/parser-cfg.c +++ b/core/parser-cfg.c @@ -61,7 +61,6 @@ int m_config_parse_config_file(m_config_t *config, const char *conffile) int param_pos; /* param pos */ int ret = 1; int errors = 0; - int prev_mode = config->mode; m_profile_t *profile = NULL; mp_msg(MSGT_CFGPARSER, MSGL_V, "Reading config file %s", conffile); @@ -71,9 +70,7 @@ int m_config_parse_config_file(m_config_t *config, const char *conffile) ": too deep 'include'. check your configfiles\n"); ret = -1; goto out; - } else - - config->mode = M_CONFIG_FILE; + } if ((line = malloc(MAX_LINE_LEN + 1)) == NULL) { mp_msg(MSGT_CFGPARSER, MSGL_FATAL, @@ -145,10 +142,13 @@ int m_config_parse_config_file(m_config_t *config, const char *conffile) ++line_pos; param_pos = 0; + bool param_set = false; /* check '=' */ if (line[line_pos] == '=') { line_pos++; + param_set = true; + /* whitespaces... */ while (isspace(line[line_pos])) ++line_pos; @@ -197,23 +197,34 @@ int m_config_parse_config_file(m_config_t *config, const char *conffile) ret = -1; } + bstr bopt = bstr0(opt); + bstr bparam = bstr0(param); + + tmp = m_config_map_option(config, &bopt, &bparam, false); + if (tmp > 0 && !param_set) + tmp = M_OPT_MISSING_PARAM; + if (tmp < 0) { + PRINT_LINENUM; + mp_msg(MSGT_CFGPARSER, MSGL_ERR, + "error parsing option %s=%s: %s\n", + opt, param, m_option_strerror(tmp)); + continue; + } + if (profile) { if (!strcmp(opt, "profile-desc")) m_profile_set_desc(profile, param), tmp = 1; else tmp = m_config_set_profile_option(config, profile, - opt, param); - } else - tmp = m_config_set_option0(config, opt, param); + bopt, bparam); + } else { + tmp = m_config_set_option_ext(config, bopt, bparam, + M_SETOPT_FROM_CONFIG_FILE); + } if (tmp < 0) { PRINT_LINENUM; - if (tmp == M_OPT_UNKNOWN) { - mp_msg(MSGT_CFGPARSER, MSGL_ERR, - "unknown option '%s'\n", opt); - continue; - } mp_msg(MSGT_CFGPARSER, MSGL_ERR, - "setting option %s='%s' failed\n", opt, param); + "setting option %s='%s' failed.\n", opt, param); continue; /* break */ } @@ -225,7 +236,6 @@ out: free(line); if (fp) fclose(fp); - config->mode = prev_mode; --recursion_depth; if (ret < 0) { mp_msg(MSGT_CFGPARSER, MSGL_FATAL, "Error loading config file %s.\n", diff --git a/core/parser-mpcmd.c b/core/parser-mpcmd.c index 025c7faf97..9914e7a614 100644 --- a/core/parser-mpcmd.c +++ b/core/parser-mpcmd.c @@ -47,7 +47,7 @@ struct parse_state { bool no_more_opts; bool error; - const struct m_option *mp_opt; // NULL <=> it's a file arg + bool is_opt; struct bstr arg; struct bstr param; }; @@ -60,7 +60,7 @@ static int split_opt_silent(struct parse_state *p) if (p->argc < 1) return 1; - p->mp_opt = NULL; + p->is_opt = false; p->arg = bstr0(p->argv[0]); p->param = bstr0(NULL); @@ -75,35 +75,20 @@ static int split_opt_silent(struct parse_state *p) return split_opt_silent(p); } - bool old_syntax = !bstr_startswith0(p->arg, "--"); - if (old_syntax) { - p->arg = bstr_cut(p->arg, 1); - } else { - p->arg = bstr_cut(p->arg, 2); - int idx = bstrchr(p->arg, '='); - if (idx > 0) { - p->param = bstr_cut(p->arg, idx + 1); - p->arg = bstr_splice(p->arg, 0, idx); - } - } + p->is_opt = true; - if (m_config_map_option(p->config, &p->arg, &p->param) == M_OPT_INVALID) - return -2; + if (!bstr_eatstart0(&p->arg, "--")) + bstr_eatstart0(&p->arg, "-"); - p->mp_opt = m_config_get_option(p->config, p->arg); - if (!p->mp_opt) - return -1; + bool ambiguous = !bstr_split_tok(p->arg, "=", &p->arg, &p->param); - if ((p->mp_opt->type->flags & M_OPT_TYPE_OLD_SYNTAX_NO_PARAM) - || p->param.len - || bstr_endswith0(p->arg, "-clr")) - { - old_syntax = false; - } + int r = m_config_map_option(p->config, &p->arg, &p->param, ambiguous); + if (r < 0) + return r; - if (old_syntax) { + if (ambiguous && r > 0) { if (p->argc < 1) - return -3; + return M_OPT_MISSING_PARAM; p->param = bstr0(p->argv[0]); p->argc--; p->argv++; @@ -119,17 +104,10 @@ static bool split_opt(struct parse_state *p) if (r >= 0) return r == 0; p->error = true; - if (r == -2) - mp_tmsg(MSGT_CFGPARSER, MSGL_ERR, - "A no-* option can't take parameters: --%.*s=%.*s\n", - BSTR_P(p->arg), BSTR_P(p->param)); - else if (r == -3) - mp_tmsg(MSGT_CFGPARSER, MSGL_ERR, - "Option %.*s needs a parameter.\n", BSTR_P(p->arg)); - else - mp_tmsg(MSGT_CFGPARSER, MSGL_ERR, - "Unknown option on the command line: %.*s\n", - BSTR_P(p->arg)); + + mp_tmsg(MSGT_CFGPARSER, MSGL_FATAL, + "Error parsing commandline option %.*s: %s\n", + BSTR_P(p->arg), m_option_strerror(r)); return false; } @@ -154,7 +132,6 @@ bool m_config_parse_mp_command_line(m_config_t *config, struct playlist *files, assert(config != NULL); assert(!config->file_local_mode); - config->mode = M_COMMAND_LINE; mode = GLOBAL; #ifdef CONFIG_MACOSX_FINDER if (macosx_finder_args(config, files, argc, argv)) @@ -163,22 +140,16 @@ bool m_config_parse_mp_command_line(m_config_t *config, struct playlist *files, struct parse_state p = {config, argc, argv}; while (split_opt(&p)) { - if (p.mp_opt) { + if (p.is_opt) { int r; - if (mode == GLOBAL && !(p.mp_opt->flags & M_OPT_PRE_PARSE)) { - r = m_config_set_option(config, p.arg, p.param); - } else { - r = m_config_check_option(config, p.arg, p.param); - } + r = m_config_set_option_ext(config, p.arg, p.param, + mode == LOCAL ? M_SETOPT_CHECK_ONLY : 0); if (r <= M_OPT_EXIT) goto err_out; if (r < 0) { - char *msg = m_option_strerror(r); - if (!msg) - goto print_err; mp_tmsg(MSGT_CFGPARSER, MSGL_FATAL, - "Error parsing commandline option %.*s: %s\n", - BSTR_P(p.arg), msg); + "Setting commandline option --%.*s=%.*s failed.\n", + BSTR_P(p.arg), BSTR_P(p.param)); goto err_out; } @@ -237,8 +208,11 @@ bool m_config_parse_mp_command_line(m_config_t *config, struct playlist *files, char *param0 = bstrdup0(NULL, p.param); struct playlist *pl = playlist_parse_file(param0); talloc_free(param0); - if (!pl) - goto print_err; + if (!pl) { + mp_tmsg(MSGT_CFGPARSER, MSGL_FATAL, + "Error reading playlist '%.*s'", BSTR_P(p.param)); + goto err_out; + } playlist_transfer_entries(files, pl); talloc_free(pl); continue; @@ -305,9 +279,6 @@ bool m_config_parse_mp_command_line(m_config_t *config, struct playlist *files, assert(!config->file_local_mode); return true; -print_err: - mp_tmsg(MSGT_CFGPARSER, MSGL_FATAL, - "Error parsing option on the command line: %.*s\n", BSTR_P(p.arg)); err_out: talloc_free(local_params); if (config->file_local_mode) @@ -330,11 +301,11 @@ void m_config_preparse_command_line(m_config_t *config, int argc, char **argv) struct parse_state p = {config, argc, argv}; while (split_opt_silent(&p) == 0) { - if (p.mp_opt) { + if (p.is_opt) { // Ignore non-pre-parse options. They will be set later. // Option parsing errors will be handled later as well. - if (p.mp_opt->flags & M_OPT_PRE_PARSE) - m_config_set_option(config, p.arg, p.param); + m_config_set_option_ext(config, p.arg, p.param, + M_SETOPT_PRE_PARSE_ONLY); if (bstrcmp0(p.arg, "v") == 0) verbose++; } |