diff options
Diffstat (limited to 'm_config.c')
-rw-r--r-- | m_config.c | 225 |
1 files changed, 93 insertions, 132 deletions
diff --git a/m_config.c b/m_config.c index 0c5677a7cc..5b8dc77ba7 100644 --- a/m_config.c +++ b/m_config.c @@ -140,22 +140,26 @@ static int list_options(struct m_option *opt, char *name, char *param) return M_OPT_EXIT; } -static void m_option_save(const struct m_config *config, - const struct m_option *opt, void *dst) +static void *optstruct_ptr(const struct m_config *config, + const struct m_option *opt) { - if (opt->type->copy) { - const void *src = m_option_get_ptr(opt, config->optstruct); - opt->type->copy(opt, dst, src, NULL); - } + return m_option_get_ptr(opt, config->optstruct); } -static void m_option_set(void *optstruct, - const struct m_option *opt, const void *src) +static void optstruct_get(const struct m_config *config, + const struct m_option *opt, + void *dst) { - if (opt->type->copy) { - void *dst = m_option_get_ptr(opt, optstruct); - opt->type->copy(opt, dst, src, optstruct); - } + if (opt->type->copy) + opt->type->copy(opt, dst, optstruct_ptr(config, opt), NULL); +} + +static void optstruct_set(const struct m_config *config, + const struct m_option *opt, + const void *src) +{ + if (opt->type->copy) + opt->type->copy(opt, optstruct_ptr(config, opt), src, config->optstruct); } @@ -164,6 +168,23 @@ static void m_config_add_option(struct m_config *config, const struct m_option *arg, const char *prefix, char *disabled_feature); +static int config_destroy(void *p) +{ + struct m_config *config = p; + for (struct m_config_option *copt = config->opts; copt; copt = copt->next) { + 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); + } + if (copt->global_backup) + m_option_free(copt->opt, copt->global_backup); + } + return 0; +} + struct m_config *m_config_new(void *optstruct, int includefunc(struct m_config *conf, char *filename)) @@ -177,8 +198,7 @@ struct m_config *m_config_new(void *optstruct, }; config = talloc_zero(NULL, struct m_config); - config->full = true; - config->lvl = 1; // 0 Is the defaults + talloc_set_destructor(config, config_destroy); struct m_option *self_opts = talloc_memdup(config, ref_opts, sizeof(ref_opts)); for (int i = 1; self_opts[i].name; i++) @@ -197,113 +217,56 @@ struct m_config *m_config_new(void *optstruct, return config; } -struct m_config *m_config_simple(const struct m_option *options) +struct m_config *m_config_simple(const struct m_option *options, + void *optstruct) { - struct m_config *config = talloc_zero(NULL, struct m_config); + struct m_config *config = talloc_struct(NULL, struct m_config, { + .optstruct = optstruct, + }); + talloc_set_destructor(config, config_destroy); m_config_register_options(config, options); return config; } void m_config_free(struct m_config *config) { - assert(config->full); // use talloc_free() for simple - struct m_config_option *copt; - for (copt = config->opts; copt; copt = copt->next) { - 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); - } - struct m_config_save_slot *sl; - for (sl = copt->slots; sl; sl = sl->prev) - m_option_free(copt->opt, sl->data); - } talloc_free(config); } -void m_config_initialize(struct m_config *config, void *optstruct) +static void ensure_backup(struct m_config *config, struct m_config_option *co) { - struct m_config_option *copt; - for (copt = config->opts; copt; copt = copt->next) { - const struct m_option *opt = copt->opt; - if (!opt->defval) - continue; - m_option_set(optstruct, opt, opt->defval); - } + if (!config->file_local_mode) + return; + if (co->opt->type->flags & M_OPT_TYPE_HAS_CHILD) + return; + if (co->opt->flags & (M_OPT_GLOBAL | M_OPT_NOSAVE)) + return; + if (co->flags & M_CFG_OPT_ALIAS) + return; + if (co->global_backup) + return; + co->global_backup = talloc_zero_size(co, co->opt->type->size); + optstruct_get(config, co->opt, co->global_backup); } -void m_config_push(struct m_config *config) +void m_config_enter_file_local(struct m_config *config) { - struct m_config_option *co; - struct m_config_save_slot *slot; - - assert(config != NULL); - assert(config->lvl > 0); - - config->lvl++; - - for (co = config->opts; co; co = co->next) { - if (co->opt->type->flags & M_OPT_TYPE_HAS_CHILD) - continue; - if (co->opt->flags & (M_OPT_GLOBAL | M_OPT_NOSAVE)) - continue; - if (co->flags & M_CFG_OPT_ALIAS) - continue; - - // Update the current status - m_option_save(config, co->opt, co->slots->data); - - // Allocate a new slot - slot = talloc_zero_size(co, sizeof(struct m_config_save_slot) + - co->opt->type->size); - slot->lvl = config->lvl; - slot->prev = co->slots; - co->slots = slot; - m_option_copy(co->opt, co->slots->data, co->slots->prev->data); - // Reset our set flag - co->flags &= ~M_CFG_OPT_SET; - } - - mp_msg(MSGT_CFGPARSER, MSGL_DBG2, - "Config pushed level is now %d\n", config->lvl); + assert(!config->file_local_mode); + config->file_local_mode = true; } -void m_config_pop(struct m_config *config) +void m_config_leave_file_local(struct m_config *config) { - struct m_config_option *co; - struct m_config_save_slot *slot; - - assert(config != NULL); - assert(config->lvl > 1); - - for (co = config->opts; co; co = co->next) { - int pop = 0; - if (co->opt->type->flags & M_OPT_TYPE_HAS_CHILD) - continue; - if (co->opt->flags & (M_OPT_GLOBAL | M_OPT_NOSAVE)) - continue; - if (co->flags & M_CFG_OPT_ALIAS) - continue; - if (co->slots->lvl > config->lvl) - mp_msg(MSGT_CFGPARSER, MSGL_WARN, - "Save slot found from lvl %d is too old: %d !!!\n", - config->lvl, co->slots->lvl); - - while (co->slots->lvl >= config->lvl) { - m_option_free(co->opt, co->slots->data); - slot = co->slots; - co->slots = slot->prev; - talloc_free(slot); - pop++; + assert(config->file_local_mode); + 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_free(co->opt, co->global_backup); + talloc_free(co->global_backup); + co->global_backup = NULL; } - if (pop) // We removed some ctx -> set the previous value - m_option_set(config->optstruct, co->opt, co->slots->data); } - - config->lvl--; - mp_msg(MSGT_CFGPARSER, MSGL_DBG2, "Config poped level=%d\n", config->lvl); } static void add_options(struct m_config *config, const struct m_option *defs, @@ -332,15 +295,12 @@ static void m_config_add_option(struct m_config *config, char *disabled_feature) { struct m_config_option *co; - struct m_config_save_slot *sl; assert(config != NULL); - assert(config->lvl > 0 || !config->full); assert(arg != NULL); // Allocate a new entry for this option - co = talloc_zero_size(config, - sizeof(struct m_config_option) + arg->type->size); + co = talloc_zero(config, struct m_config_option); co->opt = arg; co->disabled_feature = disabled_feature; @@ -361,33 +321,33 @@ static void m_config_add_option(struct m_config *config, if (arg->new ? (i->opt->new && i->opt->offset == arg->offset) : (!i->opt->new && i->opt->p == arg->p)) { // So we don't save the same vars more than 1 time - co->slots = i->slots; co->flags |= M_CFG_OPT_ALIAS; break; } } } - if (config->full && !(co->flags & M_CFG_OPT_ALIAS)) { - // Allocate a slot for the defaults - sl = talloc_zero_size(co, sizeof(struct m_config_save_slot) + - arg->type->size); - m_option_save(config, arg, sl->data); - // Hack to avoid too much trouble with dynamically allocated data: - // We replace original default and always use a dynamic version - if (!arg->new && (arg->type->flags & M_OPT_TYPE_DYNAMIC)) { - char **hackptr = m_option_get_ptr(arg, config->optstruct); - if (hackptr && *hackptr) { - *hackptr = NULL; - m_option_set(config->optstruct, arg, sl->data); + if (co->flags & M_CFG_OPT_ALIAS) { + assert(!arg->defval); + } else { + 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); + } else if (!arg->new && (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) { + 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_free(arg, temp); + talloc_free(temp); } } - sl->lvl = 0; - sl->prev = NULL; - co->slots = talloc_zero_size(co, sizeof(struct m_config_save_slot) + - arg->type->size); - co->slots->prev = sl; - co->slots->lvl = config->lvl; - m_option_copy(co->opt, co->slots->data, sl->data); } } co->next = config->opts; @@ -398,7 +358,6 @@ int m_config_register_options(struct m_config *config, const struct m_option *args) { assert(config != NULL); - assert(config->lvl > 0 || !config->full); assert(args != NULL); add_options(config, args, NULL, NULL); @@ -432,7 +391,6 @@ static int m_config_parse_option(struct m_config *config, void *optstruct, bool ambiguous_param, bool set) { assert(config != NULL); - assert(config->lvl > 0 || !config->full); assert(name.len != 0); struct m_config_option *co = m_config_get_co(config, name); @@ -483,6 +441,9 @@ static int m_config_parse_option(struct m_config *config, void *optstruct, return parse_subopts(config, optstruct, co->name, prefix, param, set); } + if (set) + ensure_backup(config, co); + void *dst = set ? m_option_get_ptr(co->opt, optstruct) : NULL; int r = co->opt->type->parse(co->opt, name, param, ambiguous_param, dst, optstruct); @@ -573,12 +534,13 @@ int m_config_check_option(struct m_config *config, struct bstr name, return r; } -int m_config_parse_suboptions(struct m_config *config, void *optstruct, - char *name, char *subopts) +int m_config_parse_suboptions(struct m_config *config, char *name, + char *subopts) { if (!subopts || !*subopts) return 0; - return parse_subopts(config, optstruct, name, "", bstr0(subopts), true); + return parse_subopts(config, config->optstruct, name, "", bstr0(subopts), + true); } @@ -588,7 +550,6 @@ const struct m_option *m_config_get_option(const struct m_config *config, struct m_config_option *co; assert(config != NULL); - assert(config->lvl > 0 || !config->full); co = m_config_get_co(config, name); if (co) |