diff options
Diffstat (limited to 'options/m_config_frontend.c')
-rw-r--r-- | options/m_config_frontend.c | 151 |
1 files changed, 117 insertions, 34 deletions
diff --git a/options/m_config_frontend.c b/options/m_config_frontend.c index 94cc9c015a..a3356c4111 100644 --- a/options/m_config_frontend.c +++ b/options/m_config_frontend.c @@ -51,17 +51,28 @@ struct m_profile { char *name; char *desc; char *cond; + int restore_mode; int num_opts; // Option/value pair array. // name,value = opts[n*2+0],opts[n*2+1] char **opts; + // For profile restoring. + struct m_opt_backup *backups; }; // In the file local case, this contains the old global value. +// It's also used for profile restoring. struct m_opt_backup { struct m_opt_backup *next; struct m_config_option *co; - void *backup; + int flags; + void *backup, *nval; +}; + +static const struct m_option profile_restore_mode_opt = { + .name = "profile-restore", + .type = &m_option_type_choice, + M_CHOICES({"default", 0}, {"copy", 1}, {"copy-equal", 2}), }; static void list_profiles(struct m_config *config) @@ -178,44 +189,66 @@ error: return NULL; } -static void ensure_backup(struct m_config *config, struct m_config_option *co) +static void backup_dtor(void *p) +{ + struct m_opt_backup *bc = p; + m_option_free(bc->co->opt, bc->backup); + if (bc->nval) + m_option_free(bc->co->opt, bc->nval); +} + +#define BACKUP_LOCAL 1 +#define BACKUP_NVAL 2 +static void ensure_backup(struct m_opt_backup **list, int flags, + struct m_config_option *co) { if (!co->data) return; - for (struct m_opt_backup *cur = config->backup_opts; cur; cur = cur->next) { + for (struct m_opt_backup *cur = *list; cur; cur = cur->next) { if (cur->co->data == co->data) // comparing data ptr catches aliases return; } struct m_opt_backup *bc = talloc_ptrtype(NULL, bc); + talloc_set_destructor(bc, backup_dtor); *bc = (struct m_opt_backup) { .co = co, .backup = talloc_zero_size(bc, co->opt->type->size), + .nval = flags & BACKUP_NVAL + ? talloc_zero_size(bc, co->opt->type->size) : NULL, + .flags = flags, }; m_option_copy(co->opt, bc->backup, co->data); - bc->next = config->backup_opts; - config->backup_opts = bc; - co->is_set_locally = true; + bc->next = *list; + *list = bc; + if (bc->flags & BACKUP_LOCAL) + co->is_set_locally = true; } -void m_config_restore_backups(struct m_config *config) +static void restore_backups(struct m_opt_backup **list, struct m_config *config) { - while (config->backup_opts) { - struct m_opt_backup *bc = config->backup_opts; - config->backup_opts = bc->next; + while (*list) { + struct m_opt_backup *bc = *list; + *list = bc->next; - m_config_set_option_raw(config, bc->co, bc->backup, 0); + if (!bc->nval || m_option_equal(bc->co->opt, bc->co->data, bc->nval)) + m_config_set_option_raw(config, bc->co, bc->backup, 0); - m_option_free(bc->co->opt, bc->backup); - bc->co->is_set_locally = false; + if (bc->flags & BACKUP_LOCAL) + bc->co->is_set_locally = false; talloc_free(bc); } } +void m_config_restore_backups(struct m_config *config) +{ + restore_backups(&config->backup_opts, config); +} + void m_config_backup_opt(struct m_config *config, const char *opt) { struct m_config_option *co = m_config_get_co(config, bstr0(opt)); if (co) { - ensure_backup(config, co); + ensure_backup(&config->backup_opts, BACKUP_LOCAL, co); } else { MP_ERR(config, "Option %s not found.\n", opt); } @@ -224,7 +257,7 @@ void m_config_backup_opt(struct m_config *config, const char *opt) void m_config_backup_all_opts(struct m_config *config) { for (int n = 0; n < config->num_opts; n++) - ensure_backup(config, &config->opts[n]); + ensure_backup(&config->backup_opts, BACKUP_LOCAL, &config->opts[n]); } @@ -360,7 +393,7 @@ static int handle_set_opt_flags(struct m_config *config, return M_OPT_INVALID; } if ((flags & M_SETOPT_BACKUP) && set) - ensure_backup(config, co); + ensure_backup(&config->backup_opts, BACKUP_LOCAL, co); return set ? 2 : 1; } @@ -577,6 +610,9 @@ int m_config_set_option_raw(struct m_config *config, if (!co->data) return flags & M_SETOPT_FROM_CMDLINE ? 0 : M_OPT_UNKNOWN; + if (config->profile_backup_tmp) + ensure_backup(config->profile_backup_tmp, config->profile_backup_flags, co); + m_config_mark_co_flags(co, flags); m_option_copy(co->opt, co->data, data); @@ -884,23 +920,26 @@ struct m_profile *m_config_add_profile(struct m_config *config, char *name) return p; } -void m_profile_set_desc(struct m_profile *p, bstr desc) -{ - talloc_free(p->desc); - p->desc = bstrto0(p, desc); -} - -void m_profile_set_cond(struct m_profile *p, bstr cond) -{ - TA_FREEP(&p->cond); - cond = bstr_strip(cond); - if (cond.len) - p->cond = bstrto0(p, cond); -} - int m_config_set_profile_option(struct m_config *config, struct m_profile *p, bstr name, bstr val) { + if (bstr_equals0(name, "profile-desc")) { + talloc_free(p->desc); + p->desc = bstrto0(p, val); + return 0; + } + if (bstr_equals0(name, "profile-cond")) { + TA_FREEP(&p->cond); + val = bstr_strip(val); + if (val.len) + p->cond = bstrto0(p, val); + return 0; + } + if (bstr_equals0(name, profile_restore_mode_opt.name)) { + return m_option_parse(config->log, &profile_restore_mode_opt, name, val, + &p->restore_mode); + } + int i = m_config_set_option_cli(config, name, val, M_SETOPT_CHECK_ONLY | M_SETOPT_FROM_CONFIG_FILE); @@ -914,19 +953,32 @@ int m_config_set_profile_option(struct m_config *config, struct m_profile *p, return 1; } -int m_config_set_profile(struct m_config *config, char *name, int flags) +static struct m_profile *find_check_profile(struct m_config *config, char *name) { struct m_profile *p = m_config_get_profile0(config, name); if (!p) { MP_WARN(config, "Unknown profile '%s'.\n", name); - return M_OPT_INVALID; + return NULL; } - MP_VERBOSE(config, "Applying profile '%s'...\n", name); - if (config->profile_depth > MAX_PROFILE_DEPTH) { MP_WARN(config, "WARNING: Profile inclusion too deep.\n"); + return NULL; + } + return p; +} + +int m_config_set_profile(struct m_config *config, char *name, int flags) +{ + MP_VERBOSE(config, "Applying profile '%s'...\n", name); + struct m_profile *p = find_check_profile(config, name); + if (!p) return M_OPT_INVALID; + + if (!config->profile_backup_tmp && p->restore_mode) { + config->profile_backup_tmp = &p->backups; + config->profile_backup_flags = p->restore_mode == 2 ? BACKUP_NVAL : 0; } + config->profile_depth++; for (int i = 0; i < p->num_opts; i++) { m_config_set_option_cli(config, @@ -936,6 +988,31 @@ int m_config_set_profile(struct m_config *config, char *name, int flags) } config->profile_depth--; + if (config->profile_backup_tmp == &p->backups) { + config->profile_backup_tmp = NULL; + + for (struct m_opt_backup *bc = p->backups; bc; bc = bc->next) { + if (bc && bc->nval) + m_option_copy(bc->co->opt, bc->nval, bc->co->data); + talloc_steal(p, bc); + } + } + + return 0; +} + +int m_config_restore_profile(struct m_config *config, char *name) +{ + MP_VERBOSE(config, "Restoring from profile '%s'...\n", name); + struct m_profile *p = find_check_profile(config, name); + if (!p) + return M_OPT_INVALID; + + if (!p->backups) + MP_WARN(config, "Profile contains no restore data.\n"); + + restore_backups(&p->backups, config); + return 0; } @@ -960,6 +1037,12 @@ struct mpv_node m_config_get_profiles(struct m_config *config) node_map_add_string(entry, "profile-desc", profile->desc); if (profile->cond) node_map_add_string(entry, "profile-cond", profile->cond); + if (profile->restore_mode) { + char *s = + m_option_print(&profile_restore_mode_opt, &profile->restore_mode); + node_map_add_string(entry, profile_restore_mode_opt.name, s); + talloc_free(s); + } struct mpv_node *opts = node_map_add(entry, "options", MPV_FORMAT_NODE_ARRAY); |