summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2014-05-18 18:57:02 +0200
committerwm4 <wm4@nowhere>2014-05-18 19:21:39 +0200
commitcaa939aa91157937759a8be54f9c794d05fd0120 (patch)
treec607c46bd72131a28ddb808f03ebd56412b566a5
parentf47a4fc3d900e14653bc059717e2805ad4964a67 (diff)
downloadmpv-caa939aa91157937759a8be54f9c794d05fd0120.tar.bz2
mpv-caa939aa91157937759a8be54f9c794d05fd0120.tar.xz
options: unify code for setting string and "raw" options
The code paths for setting options by string and by direct "raw" value were too different, which resulted in some weird code. Make the code paths closer to each other. Also, use this to remove the weirdness in the mpv_set_option() implementation.
-rw-r--r--options/m_config.c125
-rw-r--r--options/m_config.h12
-rw-r--r--player/client.c80
-rw-r--r--player/command.c11
4 files changed, 138 insertions, 90 deletions
diff --git a/options/m_config.c b/options/m_config.c
index 632f27b64f..271b2bde8b 100644
--- a/options/m_config.c
+++ b/options/m_config.c
@@ -471,6 +471,80 @@ const char *m_config_get_positional_option(const struct m_config *config, int p)
return NULL;
}
+// return: <0: M_OPT_ error, 0: skip, 1: check, 2: set
+static int handle_set_opt_flags(struct m_config *config,
+ struct m_config_option *co, int flags)
+{
+ int optflags = co->opt->flags;
+ bool set = !(flags & M_SETOPT_CHECK_ONLY);
+
+ if ((flags & M_SETOPT_PRE_PARSE_ONLY) && !(optflags & M_OPT_PRE_PARSE))
+ return 0;
+
+ if ((flags & M_SETOPT_PRESERVE_CMDLINE) && co->is_set_from_cmdline)
+ set = false;
+
+ if ((flags & M_SETOPT_NO_FIXED) && (optflags & M_OPT_FIXED))
+ return M_OPT_INVALID;
+
+ if ((flags & M_SETOPT_NO_PRE_PARSE) && (optflags & M_OPT_PRE_PARSE))
+ return M_OPT_INVALID;
+
+ // Check if this option isn't forbidden in the current mode
+ if ((flags & M_SETOPT_FROM_CONFIG_FILE) && (optflags & M_OPT_NOCFG)) {
+ MP_ERR(config, "The %s option can't be used in a config file.\n",
+ co->name);
+ return M_OPT_INVALID;
+ }
+ if (flags & M_SETOPT_BACKUP) {
+ if (optflags & M_OPT_GLOBAL) {
+ MP_ERR(config, "The %s option is global and can't be set per-file.\n",
+ co->name);
+ return M_OPT_INVALID;
+ }
+ if (set)
+ ensure_backup(config, co);
+ }
+
+ return set ? 2 : 1;
+}
+
+static void handle_set_from_cmdline(struct m_config *config,
+ struct m_config_option *co)
+{
+ co->is_set_from_cmdline = true;
+ // Mark aliases too
+ if (co->data) {
+ for (int n = 0; n < config->num_opts; n++) {
+ struct m_config_option *co2 = &config->opts[n];
+ if (co2->data == co->data)
+ co2->is_set_from_cmdline = true;
+ }
+ }
+}
+
+// The type data points to is as in: m_config_get_co(config, name)->opt
+int m_config_set_option_raw(struct m_config *config, struct m_config_option *co,
+ void *data, int flags)
+{
+ if (!co)
+ return M_OPT_UNKNOWN;
+
+ // This affects some special options like "include", "profile". Maybe these
+ // should work, or maybe not. For now they would require special code.
+ if (!co->data)
+ return M_OPT_UNKNOWN;
+
+ int r = handle_set_opt_flags(config, co, flags);
+ if (r <= 1)
+ return r;
+
+ m_option_copy(co->opt, co->data, data);
+ if (flags & M_SETOPT_FROM_CMDLINE)
+ handle_set_from_cmdline(config, co);
+ return 0;
+}
+
static int parse_subopts(struct m_config *config, char *name, char *prefix,
struct bstr param, int flags);
@@ -479,7 +553,6 @@ static int m_config_parse_option(struct m_config *config, struct bstr name,
{
assert(config != NULL);
assert(name.len != 0);
- bool set = !(flags & M_SETOPT_CHECK_ONLY);
struct m_config_option *co = m_config_get_co(config, name);
if (!co) {
@@ -498,33 +571,16 @@ static int m_config_parse_option(struct m_config *config, struct bstr name,
// 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;
-
- if ((flags & M_SETOPT_PRESERVE_CMDLINE) && co->is_set_from_cmdline)
- set = false;
+ int r = handle_set_opt_flags(config, co, flags);
+ if (r <= 0)
+ return r;
+ bool set = r == 2;
if (set) {
MP_VERBOSE(config, "Setting option '%.*s' = '%.*s' (flags = %d)\n",
BSTR_P(name), BSTR_P(param), flags);
}
- // Check if this option isn't forbidden in the current mode
- if ((flags & M_SETOPT_FROM_CONFIG_FILE) && (co->opt->flags & M_OPT_NOCFG)) {
- MP_ERR(config, "The %.*s option can't be used in a config file.\n",
- BSTR_P(name));
- return M_OPT_INVALID;
- }
- if (flags & M_SETOPT_BACKUP) {
- if (co->opt->flags & M_OPT_GLOBAL) {
- MP_ERR(config, "The %.*s option is global and can't be set per-file.\n",
- BSTR_P(name));
- return M_OPT_INVALID;
- }
- if (set)
- ensure_backup(config, co);
- }
-
if (config->includefunc && bstr_equals0(name, "include"))
return parse_include(config, param, set, flags);
if (config->use_profiles && bstr_equals0(name, "profile"))
@@ -542,20 +598,10 @@ static int m_config_parse_option(struct m_config *config, struct bstr name,
return parse_subopts(config, (char *)co->name, prefix, param, flags);
}
- int r = m_option_parse(config->log, co->opt, name, param,
- set ? co->data : NULL);
+ r = m_option_parse(config->log, co->opt, name, param, set ? co->data : NULL);
- if (r >= 0 && set && (flags & M_SETOPT_FROM_CMDLINE)) {
- co->is_set_from_cmdline = true;
- // Mark aliases too
- if (co->data) {
- for (int n = 0; n < config->num_opts; n++) {
- struct m_config_option *co2 = &config->opts[n];
- if (co2->data == co->data)
- co2->is_set_from_cmdline = true;
- }
- }
- }
+ if (r >= 0 && set && (flags & M_SETOPT_FROM_CMDLINE))
+ handle_set_from_cmdline(config, co);
return r;
}
@@ -621,17 +667,12 @@ int m_config_set_option(struct m_config *config, struct bstr name,
}
int m_config_set_option_node(struct m_config *config, bstr name,
- struct mpv_node *data)
+ struct mpv_node *data, int flags)
{
struct m_config_option *co = m_config_get_co(config, name);
if (!co)
return M_OPT_UNKNOWN;
- // This affects some special options like "include", "profile". Maybe these
- // should work, or maybe not. For now they would require special code.
- if (!co->data)
- return M_OPT_UNKNOWN;
-
int r;
// Do this on an "empty" type to make setting the option strictly overwrite
@@ -646,7 +687,7 @@ int m_config_set_option_node(struct m_config *config, bstr name,
}
if (r >= 0)
- m_option_copy(co->opt, co->data, &val);
+ r = m_config_set_option_raw(config, co, &val, flags);
m_option_free(co->opt, &val);
return r;
diff --git a/options/m_config.h b/options/m_config.h
index 57a271f1c4..5a6274b945 100644
--- a/options/m_config.h
+++ b/options/m_config.h
@@ -116,8 +116,13 @@ enum {
M_SETOPT_FROM_CMDLINE = 8, // Mark as set by command line
M_SETOPT_BACKUP = 16, // Call m_config_backup_opt() before
M_SETOPT_PRESERVE_CMDLINE = 32, // Don't set if already marked as FROM_CMDLINE
+ M_SETOPT_NO_FIXED = 64, // Reject M_OPT_FIXED options
+ M_SETOPT_NO_PRE_PARSE = 128, // Reject M_OPT_PREPARSE options
};
+// Flags for safe option setting during runtime.
+#define M_SETOPT_RUNTIME (M_SETOPT_NO_FIXED | M_SETOPT_NO_PRE_PARSE)
+
// 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.
@@ -139,10 +144,15 @@ static inline int m_config_set_option0(struct m_config *config,
return m_config_set_option(config, bstr0(name), bstr0(param));
}
+// Similar to m_config_set_option_ext(), but set as data in its native format.
+// The type data points to is as in co->opt
+int m_config_set_option_raw(struct m_config *config, struct m_config_option *co,
+ void *data, int flags);
+
// Similar to m_config_set_option_ext(), but set as data using mpv_node.
struct mpv_node;
int m_config_set_option_node(struct m_config *config, bstr name,
- struct mpv_node *data);
+ struct mpv_node *data, int flags);
int m_config_parse_suboptions(struct m_config *config, char *name,
diff --git a/player/client.c b/player/client.c
index 88ebabafaa..580eebaddb 100644
--- a/player/client.c
+++ b/player/client.c
@@ -237,6 +237,18 @@ void mpv_resume(mpv_handle *ctx)
mp_dispatch_resume(ctx->mpctx->dispatch);
}
+static void lock_core(mpv_handle *ctx)
+{
+ if (ctx->mpctx->initialized)
+ mp_dispatch_lock(ctx->mpctx->dispatch);
+}
+
+static void unlock_core(mpv_handle *ctx)
+{
+ if (ctx->mpctx->initialized)
+ mp_dispatch_unlock(ctx->mpctx->dispatch);
+}
+
void mpv_destroy(mpv_handle *ctx)
{
if (!ctx)
@@ -631,47 +643,33 @@ void mpv_free_node_contents(mpv_node *node)
int mpv_set_option(mpv_handle *ctx, const char *name, mpv_format format,
void *data)
{
- if (ctx->mpctx->initialized) {
- char prop[100];
- snprintf(prop, sizeof(prop), "options/%s", name);
- int err = mpv_set_property(ctx, prop, format, data);
- switch (err) {
- case MPV_ERROR_PROPERTY_UNAVAILABLE:
- case MPV_ERROR_PROPERTY_ERROR:
- return MPV_ERROR_OPTION_ERROR;
- case MPV_ERROR_PROPERTY_FORMAT:
- return MPV_ERROR_OPTION_FORMAT;
- case MPV_ERROR_PROPERTY_NOT_FOUND:
- return MPV_ERROR_OPTION_NOT_FOUND;
- default:
- return err;
- }
- } else {
- const struct m_option *type = get_mp_type(format);
- if (!type)
- return MPV_ERROR_OPTION_FORMAT;
- struct mpv_node tmp;
- if (format != MPV_FORMAT_NODE) {
- tmp.format = format;
- memcpy(&tmp.u, data, type->type->size);
- format = MPV_FORMAT_NODE;
- data = &tmp;
- }
- int err = m_config_set_option_node(ctx->mpctx->mconfig, bstr0(name),
- data);
- switch (err) {
- case M_OPT_MISSING_PARAM:
- case M_OPT_INVALID:
- return MPV_ERROR_OPTION_ERROR;
- case M_OPT_OUT_OF_RANGE:
- return MPV_ERROR_OPTION_FORMAT;
- case M_OPT_UNKNOWN:
- return MPV_ERROR_OPTION_NOT_FOUND;
- default:
- if (err >= 0)
- return 0;
- return MPV_ERROR_OPTION_ERROR;
- }
+ int flags = ctx->mpctx->initialized ? M_SETOPT_RUNTIME : 0;
+ const struct m_option *type = get_mp_type(format);
+ if (!type)
+ return MPV_ERROR_OPTION_FORMAT;
+ struct mpv_node tmp;
+ if (format != MPV_FORMAT_NODE) {
+ tmp.format = format;
+ memcpy(&tmp.u, data, type->type->size);
+ format = MPV_FORMAT_NODE;
+ data = &tmp;
+ }
+ lock_core(ctx);
+ int err = m_config_set_option_node(ctx->mpctx->mconfig, bstr0(name),
+ data, flags);
+ unlock_core(ctx);
+ switch (err) {
+ case M_OPT_MISSING_PARAM:
+ case M_OPT_INVALID:
+ return MPV_ERROR_OPTION_ERROR;
+ case M_OPT_OUT_OF_RANGE:
+ return MPV_ERROR_OPTION_FORMAT;
+ case M_OPT_UNKNOWN:
+ return MPV_ERROR_OPTION_NOT_FOUND;
+ default:
+ if (err >= 0)
+ return 0;
+ return MPV_ERROR_OPTION_ERROR;
}
}
diff --git a/player/command.c b/player/command.c
index fd0f589053..5e09079866 100644
--- a/player/command.c
+++ b/player/command.c
@@ -2273,12 +2273,11 @@ static int access_options(struct m_property_action_arg *ka, MPContext *mpctx)
case M_PROPERTY_GET:
m_option_copy(opt->opt, ka->arg, opt->data);
return M_PROPERTY_OK;
- case M_PROPERTY_SET:
- if (!(opt->opt->flags & (M_OPT_PRE_PARSE | M_OPT_FIXED))) {
- m_option_copy(opt->opt, opt->data, ka->arg);
- return M_PROPERTY_OK;
- }
- return M_PROPERTY_ERROR;
+ case M_PROPERTY_SET: {
+ int r = m_config_set_option_raw(mpctx->mconfig, opt, ka->arg,
+ M_SETOPT_RUNTIME);
+ return r < 0 ? M_PROPERTY_ERROR : M_PROPERTY_OK;
+ }
case M_PROPERTY_GET_TYPE:
*(struct m_option *)ka->arg = *opt->opt;
return M_PROPERTY_OK;