/*
* This file is part of mpv.
*
* mpv is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* mpv is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with mpv. If not, see <http://www.gnu.org/licenses/>.
*/
/// \file
/// \ingroup Config
#include "config.h"
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <strings.h>
#include <assert.h>
#include <stdbool.h>
#include <pthread.h>
#include "libmpv/client.h"
#include "mpv_talloc.h"
#include "m_config.h"
#include "options/m_option.h"
#include "common/common.h"
#include "common/global.h"
#include "common/msg.h"
#include "common/msg_control.h"
#include "misc/dispatch.h"
#include "misc/node.h"
#include "osdep/atomic.h"
extern const char mp_help_text[];
static const union m_option_value default_value;
// Profiles allow to predefine some sets of options that can then
// be applied later on with the internal -profile option.
#define MAX_PROFILE_DEPTH 20
// Maximal include depth.
#define MAX_RECURSION_DEPTH 8
// For use with m_config_cache.
struct m_config_shadow {
struct m_config *root;
pthread_mutex_t lock;
// Incremented on every option change.
mp_atomic_uint64 ts;
// -- immutable after init
// List of m_sub_options instances.
// Index 0 is the top-level and is always present.
// Immutable after init.
// Invariant: a parent is always at a lower index than any of its children.
struct m_config_group *groups;
int num_groups;
// -- protected by lock
struct m_config_data *data; // protected shadow copy of the option data
struct config_cache **listeners;
int num_listeners;
};
// Represents a sub-struct (OPT_SUBSTRUCT()).
struct m_config_group {
const struct m_sub_options *group;
int group_count; // 1 + number of all sub groups owned by this (so
// m_config_shadow.groups[idx..idx+group_count] is used
// by the entire tree of sub groups included by this
// group)
int parent_group; // index of parent group into m_config_shadow.groups[],
// or -1 for group 0
int parent_ptr; // ptr offset in the parent group's data, or -1 if
// none
};
// A copy of option data. Used for the main option struct, the shadow data,
// and copies for m_config_cache.
struct m_config_data {
struct m_config_shadow *shadow; // option definitions etc., main data copy
int group_index; // start index into m_config.groups[]
struct m_group_data *gdata; // user struct allocation (our copy of data)
int num_gdata; // (group_index+num_gdata = end index)
};
struct config_cache {
struct m_config_cache *public;
struct m_config_data *data; // public data
struct m_config_data *src; // global data (currently ==shadow->data)
struct m_config_shadow *shadow; // global metadata
uint64_t ts; // timestamp of this data copy
bool in_list; // part of m_config_shadow->listeners[]
int upd_group; // for "incremental" change notification
int upd_opt;
// --- Implicitly synchronized by setting/unsetting wakeup_cb.
struct mp_dispatch_queue *wakeup_dispatch_queue;
void (*wakeup_dispatch_cb)(void *ctx);
void *wakeup_dispatch_cb_ctx;
// --- Protected by shadow->lock
void (*wakeup_cb)(void *ctx);
void *wakeup_cb_ctx;
};
// Per m_config_data state for each m_config_group.
struct m_group_data {
char *udata; // pointer to group user option struct
uint64_t ts; // timestamp of the data copy
};
struct m_profile {
struct m_profile *next;
char *name;
char *desc;
int num_opts;
// Option/value pair array.
char **opts;
};
// In the file local case, this contains the old global value.
struct m_opt_backup {
struct m_opt_backup *next;
struct m_config_option *co;
void *backup;
};
static void add_sub_group(struct m_config *config, const char *name_prefix,
int parent_group_index, int parent_ptr,
const struct m_sub_options *subopts);
static struct m_group_data *m_config_gdata(struct m_config_data *data,
int group_index)
{
if (group_index < data->group_index ||
group_index >= data->group_index + data->num_gdata)
return NULL;
return &data->gdata[group_index - data->group_index];
}
static void list_profiles(struct m_config *config)
{
MP_INFO(config, "Available profiles:\n");
for (struct m_profile *p = config->profiles; p; p = p->next)
MP_INFO(config, "\t%s\t%s\n", p->name, p->desc ? p->desc : "");
MP_INFO(config, "\n");
}
static int show_profile(struct m_config *config, bstr param)
{
struct m_profile *p;
if (!param.len) {
list_profiles(config);
return M_OPT_EXIT;
}
if (!(p = m_config_get_profile(config, param))) {
MP_ERR(config, "Unknow
|