summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2012-08-06 17:45:17 +0200
committerwm4 <wm4@nowhere>2012-08-06 17:45:17 +0200
commit7aae399239d02e48de9060dded1d0232310d2141 (patch)
treec4ede71396dccdc0a661d28fb4089af4c279aa05
parent0c1dd8a8f54a152755faef3d323ce6fdc7d63f73 (diff)
downloadmpv-7aae399239d02e48de9060dded1d0232310d2141.tar.bz2
mpv-7aae399239d02e48de9060dded1d0232310d2141.tar.xz
m_config: support auto-allocated sub-structs
Given your option struct has a field that is a pointer to another struct, this commit allows you to declare options that write into that other struct. The code in m_config will dereference the pointer field on its own if such an option is accessed. If the field is NULL on initialization of the containing m_config, the struct is automatically allocated. OPT_SUBSTRUCT() can be used to declare such a field. struct m_sub_options is used to describe the pointed-to struct, and includes size and defaults if the struct has to be allocated by m_config.
-rw-r--r--m_config.c83
-rw-r--r--m_config.h6
-rw-r--r--m_option.c6
-rw-r--r--m_option.h17
4 files changed, 75 insertions, 37 deletions
diff --git a/m_config.c b/m_config.c
index ab410646e1..56886e08eb 100644
--- a/m_config.c
+++ b/m_config.c
@@ -139,26 +139,18 @@ static int list_options(struct m_option *opt, char *name, char *param)
return M_OPT_EXIT;
}
-static void *optstruct_ptr(const struct m_config *config,
- const struct m_option *opt)
+// The memcpys are supposed to work around the struct aliasing violation,
+// that would result if we just dereferenced a void** (where the void** is
+// actually casted from struct some_type* ).
+static void *substruct_read_ptr(void *ptr)
{
- return m_option_get_ptr(opt, config->optstruct);
+ void *res;
+ memcpy(&res, ptr, sizeof(void*));
+ return res;
}
-
-static void optstruct_get(const struct m_config *config,
- const struct m_option *opt,
- void *dst)
-{
- if (opt->type->copy)
- opt->type->copy(opt, dst, optstruct_ptr(config, opt));
-}
-
-static void optstruct_set(const struct m_config *config,
- const struct m_option *opt,
- const void *src)
+static void substruct_write_ptr(void *ptr, void *val)
{
- if (opt->type->copy)
- opt->type->copy(opt, optstruct_ptr(config, opt), src);
+ memcpy(ptr, &val, sizeof(void*));
}
static void m_config_add_option(struct m_config *config,
@@ -172,9 +164,7 @@ static int config_destroy(void *p)
if (copt->flags & M_CFG_OPT_ALIAS)
continue;
if (copt->opt->type->flags & M_OPT_TYPE_DYNAMIC) {
- void *ptr = m_option_get_ptr(copt->opt, config->optstruct);
- if (ptr)
- m_option_free(copt->opt, ptr);
+ m_option_free(copt->opt, copt->data);
}
if (copt->global_backup)
m_option_free(copt->opt, copt->global_backup);
@@ -240,7 +230,7 @@ static void ensure_backup(struct m_config *config, struct m_config_option *co)
if (co->global_backup)
return;
co->global_backup = talloc_zero_size(co, co->opt->type->size);
- optstruct_get(config, co->opt, co->global_backup);
+ m_option_copy(co->opt, co->global_backup, co->data);
}
void m_config_enter_file_local(struct m_config *config)
@@ -255,7 +245,7 @@ void m_config_leave_file_local(struct m_config *config)
config->file_local_mode = false;
for (struct m_config_option *co = config->opts; co; co = co->next) {
if (co->global_backup) {
- optstruct_set(config, co->opt, co->global_backup);
+ m_option_copy(co->opt, co->data, co->global_backup);
m_option_free(co->opt, co->global_backup);
talloc_free(co->global_backup);
co->global_backup = NULL;
@@ -284,6 +274,11 @@ static void m_config_add_option(struct m_config *config,
co = talloc_zero(config, struct m_config_option);
co->opt = arg;
+ void *optstruct = config->optstruct;
+ if (parent && (parent->opt->type->flags & M_OPT_TYPE_USE_SUBSTRUCT))
+ optstruct = substruct_read_ptr(parent->data);
+ co->data = arg->new ? (char *)optstruct + arg->offset : arg->p;
+
if (parent) {
// Merge case: pretend it has no parent (note that we still must follow
// the "real" parent for accessing struct fields)
@@ -303,15 +298,22 @@ static void m_config_add_option(struct m_config *config,
// Option with children -> add them
if (arg->type->flags & M_OPT_TYPE_HAS_CHILD) {
- const struct m_option *sub = arg->p;
- add_options(config, co, sub);
+ if (arg->type->flags & M_OPT_TYPE_USE_SUBSTRUCT) {
+ const struct m_sub_options *subopts = arg->priv;
+ if (!substruct_read_ptr(co->data)) {
+ void *subdata = m_config_alloc_struct(config, subopts);
+ substruct_write_ptr(co->data, subdata);
+ }
+ add_options(config, co, subopts->opts);
+ } else {
+ const struct m_option *sub = arg->p;
+ add_options(config, co, sub);
+ }
} else {
- struct m_config_option *i;
// Check if there is already an option pointing to this address
- if (arg->p || arg->new && arg->offset >= 0) {
- for (i = config->opts; i; i = i->next) {
- if (arg->new ? (i->opt->new && i->opt->offset == arg->offset)
- : (!i->opt->new && i->opt->p == arg->p)) {
+ if (co->data) {
+ for (struct m_config_option *i = config->opts; i; i = i->next) {
+ if (co->data == i->data) {
// So we don't save the same vars more than 1 time
co->flags |= M_CFG_OPT_ALIAS;
break;
@@ -324,18 +326,17 @@ static void m_config_add_option(struct m_config *config,
if (arg->defval) {
// Target data in optstruct is supposed to be cleared (consider
// m_option freeing previously set dynamic data).
- optstruct_set(config, arg, arg->defval);
+ m_option_copy(arg, co->data, arg->defval);
} else if (arg->type->flags & M_OPT_TYPE_DYNAMIC) {
// Initialize dynamically managed fields from static data (like
// string options): copy the option into temporary memory,
// clear the original option (to void m_option freeing the
// static data), copy it back.
- void *init_data = optstruct_ptr(config, arg);
- if (init_data) {
+ if (co->data) {
void *temp = talloc_zero_size(NULL, arg->type->size);
- m_option_copy(arg, temp, init_data);
- memset(init_data, 0, arg->type->size);
- optstruct_set(config, arg, temp);
+ m_option_copy(arg, temp, co->data);
+ memset(co->data, 0, arg->type->size);
+ m_option_copy(arg, co->data, temp);
m_option_free(arg, temp);
talloc_free(temp);
}
@@ -431,8 +432,7 @@ static int m_config_parse_option(struct m_config *config, void *optstruct,
if (set)
ensure_backup(config, co);
- void *dst = set ? m_option_get_ptr(co->opt, optstruct) : NULL;
- return m_option_parse(co->opt, name, param, dst);
+ return m_option_parse(co->opt, name, param, set ? co->data : NULL);
}
static int parse_subopts(struct m_config *config, void *optstruct, char *name,
@@ -630,3 +630,12 @@ void m_config_set_profile(struct m_config *config, struct m_profile *p)
config->profile_depth--;
config->mode = prev_mode;
}
+
+void *m_config_alloc_struct(void *talloc_parent,
+ const struct m_sub_options *subopts)
+{
+ void *substruct = talloc_zero_size(talloc_parent, subopts->size);
+ if (subopts->defaults)
+ memcpy(substruct, subopts->defaults, subopts->size);
+ return substruct;
+}
diff --git a/m_config.h b/m_config.h
index beeab80a53..80897ce0e4 100644
--- a/m_config.h
+++ b/m_config.h
@@ -30,6 +30,7 @@
typedef struct m_profile m_profile_t;
struct m_option;
struct m_option_type;
+struct m_sub_options;
// Config option
struct m_config_option {
@@ -38,6 +39,8 @@ struct m_config_option {
char *name;
// Option description.
const struct m_option *opt;
+ // Raw value of the option.
+ void *data;
// Raw value of the backup of the global value (or NULL).
void *global_backup;
// See \ref ConfigOptionFlags.
@@ -198,4 +201,7 @@ 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);
+void *m_config_alloc_struct(void *talloc_parent,
+ const struct m_sub_options *subopts);
+
#endif /* MPLAYER_M_CONFIG_H */
diff --git a/m_option.c b/m_option.c
index 35b5efc98d..22abee1496 100644
--- a/m_option.c
+++ b/m_option.c
@@ -907,6 +907,12 @@ const m_option_type_t m_option_type_subconfig = {
.parse = parse_subconf,
};
+const m_option_type_t m_option_type_subconfig_struct = {
+ .name = "Subconfig",
+ .flags = M_OPT_TYPE_HAS_CHILD | M_OPT_TYPE_USE_SUBSTRUCT,
+ .parse = parse_subconf,
+};
+
#include "libmpcodecs/img_format.h"
/* FIXME: snyc with img_format.h */
diff --git a/m_option.h b/m_option.h
index e0321d1de1..ab83027a85 100644
--- a/m_option.h
+++ b/m_option.h
@@ -52,6 +52,7 @@ extern const m_option_type_t m_option_type_print;
extern const m_option_type_t m_option_type_print_func;
extern const m_option_type_t m_option_type_print_func_param;
extern const m_option_type_t m_option_type_subconfig;
+extern const m_option_type_t m_option_type_subconfig_struct;
extern const m_option_type_t m_option_type_imgfmt;
extern const m_option_type_t m_option_type_afmt;
@@ -148,6 +149,12 @@ struct m_opt_choice_alternatives {
int value;
};
+// m_option.priv points to this if M_OPT_TYPE_USE_SUBSTRUCT is used
+struct m_sub_options {
+ const struct m_option *opts;
+ size_t size;
+ const void *defaults;
+};
// FIXME: backward compatibility
#define CONF_TYPE_FLAG (&m_option_type_flag)
@@ -338,6 +345,10 @@ struct m_option {
// takes no parameter.
#define M_OPT_TYPE_OLD_SYNTAX_NO_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.
+#define M_OPT_TYPE_USE_SUBSTRUCT (1 << 4)
+
///////////////////////////// Parser flags /////////////////////////////////
// On success parsers return the number of arguments consumed: 0 or 1.
@@ -461,6 +472,12 @@ static inline void m_option_free(const m_option_t *opt, void *dst)
#define OPT_CHOICE_(optname, varname, flags, choices, ...) OPT_GENERAL(optname, varname, flags, .priv = (void *)&(const struct m_opt_choice_alternatives[]){OPT_HELPER_REMOVEPAREN choices, {NULL}}, __VA_ARGS__)
#define OPT_TIME(...) OPT_GENERAL(__VA_ARGS__, .type = &m_option_type_time)
+// subconf must have the type struct m_sub_options.
+// flagv should be M_OPT_MERGE or M_OPT_FLATTEN.
+// varname refers to the field, that must be a pointer to a field described by
+// the subconf struct.
+#define OPT_SUBSTRUCT(varname, subconf, flagv) OPT_GENERAL("-", varname, flagv, .type = &m_option_type_subconfig_struct, .priv = (void*)&subconf)
+
#define OPT_BASE_STRUCT struct MPOpts
#endif /* MPLAYER_M_OPTION_H */