config/Param: split block-specific attributes to new struct ConfigBlock
The old struct config_param remains only for top-level string options.
This commit is contained in:
@@ -20,8 +20,12 @@
|
||||
#include "config.h"
|
||||
#include "Block.hxx"
|
||||
#include "ConfigParser.hxx"
|
||||
#include "ConfigPath.hxx"
|
||||
#include "system/FatalError.hxx"
|
||||
#include "fs/AllocatedPath.hxx"
|
||||
#include "util/Error.hxx"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
int
|
||||
@@ -57,3 +61,96 @@ BlockParam::GetBoolValue() const
|
||||
|
||||
return value2;
|
||||
}
|
||||
|
||||
ConfigBlock::~ConfigBlock()
|
||||
{
|
||||
delete next;
|
||||
}
|
||||
|
||||
const BlockParam *
|
||||
ConfigBlock::GetBlockParam(const char *name) const
|
||||
{
|
||||
for (const auto &i : block_params) {
|
||||
if (i.name == name) {
|
||||
i.used = true;
|
||||
return &i;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const char *
|
||||
ConfigBlock::GetBlockValue(const char *name, const char *default_value) const
|
||||
{
|
||||
const BlockParam *bp = GetBlockParam(name);
|
||||
if (bp == nullptr)
|
||||
return default_value;
|
||||
|
||||
return bp->value.c_str();
|
||||
}
|
||||
|
||||
AllocatedPath
|
||||
ConfigBlock::GetBlockPath(const char *name, const char *default_value,
|
||||
Error &error) const
|
||||
{
|
||||
assert(!error.IsDefined());
|
||||
|
||||
int line2 = line;
|
||||
const char *s;
|
||||
|
||||
const BlockParam *bp = GetBlockParam(name);
|
||||
if (bp != nullptr) {
|
||||
line2 = bp->line;
|
||||
s = bp->value.c_str();
|
||||
} else {
|
||||
if (default_value == nullptr)
|
||||
return AllocatedPath::Null();
|
||||
|
||||
s = default_value;
|
||||
}
|
||||
|
||||
AllocatedPath path = ParsePath(s, error);
|
||||
if (gcc_unlikely(path.IsNull()))
|
||||
error.FormatPrefix("Invalid path in \"%s\" at line %i: ",
|
||||
name, line2);
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
AllocatedPath
|
||||
ConfigBlock::GetBlockPath(const char *name, Error &error) const
|
||||
{
|
||||
return GetBlockPath(name, nullptr, error);
|
||||
}
|
||||
|
||||
int
|
||||
ConfigBlock::GetBlockValue(const char *name, int default_value) const
|
||||
{
|
||||
const BlockParam *bp = GetBlockParam(name);
|
||||
if (bp == nullptr)
|
||||
return default_value;
|
||||
|
||||
return bp->GetIntValue();
|
||||
}
|
||||
|
||||
unsigned
|
||||
ConfigBlock::GetBlockValue(const char *name, unsigned default_value) const
|
||||
{
|
||||
const BlockParam *bp = GetBlockParam(name);
|
||||
if (bp == nullptr)
|
||||
return default_value;
|
||||
|
||||
return bp->GetUnsignedValue();
|
||||
}
|
||||
|
||||
gcc_pure
|
||||
bool
|
||||
ConfigBlock::GetBlockValue(const char *name, bool default_value) const
|
||||
{
|
||||
const BlockParam *bp = GetBlockParam(name);
|
||||
if (bp == nullptr)
|
||||
return default_value;
|
||||
|
||||
return bp->GetBoolValue();
|
||||
}
|
||||
|
@@ -21,9 +21,14 @@
|
||||
#define MPD_CONFIG_BLOCK_HXX
|
||||
|
||||
#include "check.h"
|
||||
#include "Param.hxx"
|
||||
#include "Compiler.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class Error;
|
||||
class AllocatedPath;
|
||||
|
||||
struct BlockParam {
|
||||
std::string name;
|
||||
@@ -50,4 +55,71 @@ struct BlockParam {
|
||||
bool GetBoolValue() const;
|
||||
};
|
||||
|
||||
struct ConfigBlock {
|
||||
/**
|
||||
* The next #ConfigBlock with the same name. The destructor
|
||||
* deletes the whole chain.
|
||||
*/
|
||||
ConfigBlock *next;
|
||||
|
||||
int line;
|
||||
|
||||
std::vector<BlockParam> block_params;
|
||||
|
||||
/**
|
||||
* This flag is false when nobody has queried the value of
|
||||
* this option yet.
|
||||
*/
|
||||
bool used;
|
||||
|
||||
explicit ConfigBlock(int _line=-1)
|
||||
:next(nullptr), line(_line), used(false) {}
|
||||
|
||||
ConfigBlock(const ConfigBlock &) = delete;
|
||||
|
||||
~ConfigBlock();
|
||||
|
||||
ConfigBlock &operator=(const ConfigBlock &) = delete;
|
||||
|
||||
/**
|
||||
* Determine if this is a "null" instance, i.e. an empty
|
||||
* object that was synthesized and not loaded from a
|
||||
* configuration file.
|
||||
*/
|
||||
bool IsNull() const {
|
||||
return line < 0;
|
||||
}
|
||||
|
||||
gcc_nonnull_all
|
||||
void AddBlockParam(const char *_name, const char *_value,
|
||||
int _line=-1) {
|
||||
block_params.emplace_back(_name, _value, _line);
|
||||
}
|
||||
|
||||
gcc_nonnull_all gcc_pure
|
||||
const BlockParam *GetBlockParam(const char *_name) const;
|
||||
|
||||
gcc_pure
|
||||
const char *GetBlockValue(const char *name,
|
||||
const char *default_value=nullptr) const;
|
||||
|
||||
/**
|
||||
* Same as config_get_path(), but looks up the setting in the
|
||||
* specified block.
|
||||
*/
|
||||
AllocatedPath GetBlockPath(const char *name, const char *default_value,
|
||||
Error &error) const;
|
||||
|
||||
AllocatedPath GetBlockPath(const char *name, Error &error) const;
|
||||
|
||||
gcc_pure
|
||||
int GetBlockValue(const char *name, int default_value) const;
|
||||
|
||||
gcc_pure
|
||||
unsigned GetBlockValue(const char *name, unsigned default_value) const;
|
||||
|
||||
gcc_pure
|
||||
bool GetBlockValue(const char *name, bool default_value) const;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@@ -21,6 +21,7 @@
|
||||
#include "ConfigFile.hxx"
|
||||
#include "Data.hxx"
|
||||
#include "Param.hxx"
|
||||
#include "Block.hxx"
|
||||
#include "ConfigTemplates.hxx"
|
||||
#include "util/Tokenizer.hxx"
|
||||
#include "util/StringUtil.hxx"
|
||||
@@ -38,7 +39,7 @@ static constexpr char CONF_COMMENT = '#';
|
||||
static constexpr Domain config_file_domain("config_file");
|
||||
|
||||
static bool
|
||||
config_read_name_value(struct config_param *param, char *input, unsigned line,
|
||||
config_read_name_value(ConfigBlock &block, char *input, unsigned line,
|
||||
Error &error)
|
||||
{
|
||||
Tokenizer tokenizer(input);
|
||||
@@ -65,7 +66,7 @@ config_read_name_value(struct config_param *param, char *input, unsigned line,
|
||||
return false;
|
||||
}
|
||||
|
||||
const BlockParam *bp = param->GetBlockParam(name);
|
||||
const BlockParam *bp = block.GetBlockParam(name);
|
||||
if (bp != nullptr) {
|
||||
error.Format(config_file_domain,
|
||||
"\"%s\" is duplicate, first defined on line %i",
|
||||
@@ -73,14 +74,14 @@ config_read_name_value(struct config_param *param, char *input, unsigned line,
|
||||
return false;
|
||||
}
|
||||
|
||||
param->AddBlockParam(name, value, line);
|
||||
block.AddBlockParam(name, value, line);
|
||||
return true;
|
||||
}
|
||||
|
||||
static struct config_param *
|
||||
static ConfigBlock *
|
||||
config_read_block(BufferedReader &reader, Error &error)
|
||||
{
|
||||
struct config_param *ret = new config_param(reader.GetLineNumber());
|
||||
auto *ret = new ConfigBlock(reader.GetLineNumber());
|
||||
|
||||
while (true) {
|
||||
char *line = reader.ReadLine();
|
||||
@@ -115,7 +116,7 @@ config_read_block(BufferedReader &reader, Error &error)
|
||||
|
||||
/* parse name and value */
|
||||
|
||||
if (!config_read_name_value(ret, line, reader.GetLineNumber(),
|
||||
if (!config_read_name_value(*ret, line, reader.GetLineNumber(),
|
||||
error)) {
|
||||
assert(*line != 0);
|
||||
delete ret;
|
||||
@@ -125,6 +126,64 @@ config_read_block(BufferedReader &reader, Error &error)
|
||||
}
|
||||
}
|
||||
|
||||
gcc_nonnull_all
|
||||
static void
|
||||
Append(ConfigBlock *&head, ConfigBlock *p)
|
||||
{
|
||||
assert(p->next == nullptr);
|
||||
|
||||
auto **i = &head;
|
||||
while (*i != nullptr)
|
||||
i = &(*i)->next;
|
||||
|
||||
*i = p;
|
||||
}
|
||||
|
||||
static bool
|
||||
ReadConfigBlock(ConfigData &config_data, BufferedReader &reader,
|
||||
const char *name, ConfigOption o,
|
||||
Tokenizer &tokenizer,
|
||||
Error &error)
|
||||
{
|
||||
const unsigned i = unsigned(o);
|
||||
const ConfigTemplate &option = config_block_templates[i];
|
||||
ConfigBlock *&head = config_data.blocks[i];
|
||||
|
||||
if (head != nullptr && !option.repeatable) {
|
||||
ConfigBlock *block = head;
|
||||
error.Format(config_file_domain,
|
||||
"config parameter \"%s\" is first defined "
|
||||
"on line %d and redefined on line %u\n",
|
||||
name, block->line,
|
||||
reader.GetLineNumber());
|
||||
return false;
|
||||
}
|
||||
|
||||
/* now parse the block or the value */
|
||||
|
||||
if (tokenizer.CurrentChar() != '{') {
|
||||
error.Format(config_file_domain,
|
||||
"line %u: '{' expected",
|
||||
reader.GetLineNumber());
|
||||
return false;
|
||||
}
|
||||
|
||||
char *line = StripLeft(tokenizer.Rest() + 1);
|
||||
if (*line != 0 && *line != CONF_COMMENT) {
|
||||
error.Format(config_file_domain,
|
||||
"line %u: Unknown tokens after '{'",
|
||||
reader.GetLineNumber());
|
||||
return false;
|
||||
}
|
||||
|
||||
auto *param = config_read_block(reader, error);
|
||||
if (param == nullptr)
|
||||
return false;
|
||||
|
||||
Append(head, param);
|
||||
return true;
|
||||
}
|
||||
|
||||
gcc_nonnull_all
|
||||
static void
|
||||
Append(config_param *&head, config_param *p)
|
||||
@@ -145,7 +204,7 @@ ReadConfigParam(ConfigData &config_data, BufferedReader &reader,
|
||||
Error &error)
|
||||
{
|
||||
const unsigned i = unsigned(o);
|
||||
const ConfigTemplate &option = config_templates[i];
|
||||
const ConfigTemplate &option = config_param_templates[i];
|
||||
config_param *&head = config_data.params[i];
|
||||
|
||||
if (head != nullptr && !option.repeatable) {
|
||||
@@ -160,57 +219,28 @@ ReadConfigParam(ConfigData &config_data, BufferedReader &reader,
|
||||
|
||||
/* now parse the block or the value */
|
||||
|
||||
struct config_param *param;
|
||||
if (option.block) {
|
||||
/* it's a block, call config_read_block() */
|
||||
|
||||
if (tokenizer.CurrentChar() != '{') {
|
||||
const char *value = tokenizer.NextString(error);
|
||||
if (value == nullptr) {
|
||||
if (tokenizer.IsEnd())
|
||||
error.Format(config_file_domain,
|
||||
"line %u: '{' expected",
|
||||
"line %u: Value missing",
|
||||
reader.GetLineNumber());
|
||||
return false;
|
||||
}
|
||||
else
|
||||
error.FormatPrefix("line %u: ",
|
||||
reader.GetLineNumber());
|
||||
|
||||
char *line = StripLeft(tokenizer.Rest() + 1);
|
||||
if (*line != 0 && *line != CONF_COMMENT) {
|
||||
error.Format(config_file_domain,
|
||||
"line %u: Unknown tokens after '{'",
|
||||
reader.GetLineNumber());
|
||||
return false;
|
||||
}
|
||||
|
||||
param = config_read_block(reader, error);
|
||||
if (param == nullptr) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
/* a string value */
|
||||
|
||||
const char *value = tokenizer.NextString(error);
|
||||
if (value == nullptr) {
|
||||
if (tokenizer.IsEnd())
|
||||
error.Format(config_file_domain,
|
||||
"line %u: Value missing",
|
||||
reader.GetLineNumber());
|
||||
else
|
||||
error.FormatPrefix("line %u: ",
|
||||
reader.GetLineNumber());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!tokenizer.IsEnd() &&
|
||||
tokenizer.CurrentChar() != CONF_COMMENT) {
|
||||
error.Format(config_file_domain,
|
||||
"line %u: Unknown tokens after value",
|
||||
reader.GetLineNumber());
|
||||
return false;
|
||||
}
|
||||
|
||||
param = new config_param(value,
|
||||
reader.GetLineNumber());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!tokenizer.IsEnd() &&
|
||||
tokenizer.CurrentChar() != CONF_COMMENT) {
|
||||
error.Format(config_file_domain,
|
||||
"line %u: Unknown tokens after value",
|
||||
reader.GetLineNumber());
|
||||
return false;
|
||||
}
|
||||
|
||||
auto *param = new config_param(value, reader.GetLineNumber());
|
||||
Append(head, param);
|
||||
return true;
|
||||
}
|
||||
@@ -242,10 +272,15 @@ ReadConfigFile(ConfigData &config_data, BufferedReader &reader, Error &error)
|
||||
"repeatable" flag */
|
||||
|
||||
const ConfigOption o = ParseConfigOptionName(name);
|
||||
ConfigBlockOption bo;
|
||||
if (o != ConfigOption::MAX) {
|
||||
if (!ReadConfigParam(config_data, reader, name, o,
|
||||
tokenizer, error))
|
||||
return false;
|
||||
} else if ((bo = ParseConfigBlockOptionName(name)) != ConfigBlockOption::MAX) {
|
||||
if (!ReadConfigBlock(config_data, reader, name, o,
|
||||
tokenizer, error))
|
||||
return false;
|
||||
} else {
|
||||
error.Format(config_file_domain,
|
||||
"unrecognized parameter in config file at "
|
||||
|
@@ -22,6 +22,7 @@
|
||||
#include "ConfigParser.hxx"
|
||||
#include "Data.hxx"
|
||||
#include "Param.hxx"
|
||||
#include "Block.hxx"
|
||||
#include "ConfigFile.hxx"
|
||||
#include "ConfigPath.hxx"
|
||||
#include "ConfigError.hxx"
|
||||
@@ -51,15 +52,15 @@ ReadConfigFile(Path path, Error &error)
|
||||
}
|
||||
|
||||
static void
|
||||
Check(const config_param *param)
|
||||
Check(const ConfigBlock &block)
|
||||
{
|
||||
if (!param->used)
|
||||
/* this whole config_param was not queried at all -
|
||||
if (!block.used)
|
||||
/* this whole block was not queried at all -
|
||||
the feature might be disabled at compile time?
|
||||
Silently ignore it here. */
|
||||
return;
|
||||
|
||||
for (const auto &i : param->block_params) {
|
||||
for (const auto &i : block.block_params) {
|
||||
if (!i.used)
|
||||
FormatWarning(config_domain,
|
||||
"option '%s' on line %i was not recognized",
|
||||
@@ -69,9 +70,9 @@ Check(const config_param *param)
|
||||
|
||||
void config_global_check(void)
|
||||
{
|
||||
for (auto i : config_data.params)
|
||||
for (const config_param *p = i; p != nullptr; p = p->next)
|
||||
Check(p);
|
||||
for (auto i : config_data.blocks)
|
||||
for (const auto *p = i; p != nullptr; p = p->next)
|
||||
Check(*p);
|
||||
}
|
||||
|
||||
const config_param *
|
||||
@@ -83,18 +84,27 @@ config_get_param(ConfigOption option)
|
||||
return param;
|
||||
}
|
||||
|
||||
const config_param *
|
||||
config_find_block(ConfigOption option, const char *key, const char *value)
|
||||
const ConfigBlock *
|
||||
config_get_block(ConfigBlockOption option)
|
||||
{
|
||||
for (const config_param *param = config_get_param(option);
|
||||
param != nullptr; param = param->next) {
|
||||
const char *value2 = param->GetBlockValue(key);
|
||||
ConfigBlock *block = config_data.blocks[unsigned(option)];
|
||||
if (block != nullptr)
|
||||
block->used = true;
|
||||
return block;
|
||||
}
|
||||
|
||||
const ConfigBlock *
|
||||
config_find_block(ConfigBlockOption option, const char *key, const char *value)
|
||||
{
|
||||
for (const auto *block = config_get_block(option);
|
||||
block != nullptr; block = block->next) {
|
||||
const char *value2 = block->GetBlockValue(key);
|
||||
if (value2 == nullptr)
|
||||
FormatFatalError("block without '%s' name in line %d",
|
||||
key, param->line);
|
||||
key, block->line);
|
||||
|
||||
if (strcmp(value2, value) == 0)
|
||||
return param;
|
||||
return block;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
|
@@ -27,6 +27,7 @@ class Error;
|
||||
class Path;
|
||||
class AllocatedPath;
|
||||
struct config_param;
|
||||
struct ConfigBlock;
|
||||
|
||||
void config_global_init(void);
|
||||
void config_global_finish(void);
|
||||
@@ -44,6 +45,10 @@ gcc_pure
|
||||
const config_param *
|
||||
config_get_param(enum ConfigOption option);
|
||||
|
||||
gcc_pure
|
||||
const ConfigBlock *
|
||||
config_get_block(enum ConfigBlockOption option);
|
||||
|
||||
/**
|
||||
* Find a block with a matching attribute.
|
||||
*
|
||||
@@ -52,8 +57,8 @@ config_get_param(enum ConfigOption option);
|
||||
* @param value the expected attribute value
|
||||
*/
|
||||
gcc_pure
|
||||
const config_param *
|
||||
config_find_block(ConfigOption option, const char *key, const char *value);
|
||||
const ConfigBlock *
|
||||
config_find_block(ConfigBlockOption option, const char *key, const char *value);
|
||||
|
||||
/* Note on gcc_pure: Some of the functions declared pure are not
|
||||
really pure in strict sense. They have side effect such that they
|
||||
|
@@ -49,7 +49,6 @@ enum class ConfigOption {
|
||||
ZEROCONF_ENABLED,
|
||||
PASSWORD,
|
||||
DEFAULT_PERMS,
|
||||
AUDIO_OUTPUT,
|
||||
AUDIO_OUTPUT_FORMAT,
|
||||
MIXER_TYPE,
|
||||
REPLAYGAIN,
|
||||
@@ -73,15 +72,20 @@ enum class ConfigOption {
|
||||
ID3V1_ENCODING,
|
||||
METADATA_TO_USE,
|
||||
SAVE_ABSOLUTE_PATHS,
|
||||
DECODER,
|
||||
INPUT,
|
||||
GAPLESS_MP3_PLAYBACK,
|
||||
PLAYLIST_PLUGIN,
|
||||
AUTO_UPDATE,
|
||||
AUTO_UPDATE_DEPTH,
|
||||
DESPOTIFY_USER,
|
||||
DESPOTIFY_PASSWORD,
|
||||
DESPOTIFY_HIGH_BITRATE,
|
||||
MAX
|
||||
};
|
||||
|
||||
enum class ConfigBlockOption {
|
||||
AUDIO_OUTPUT,
|
||||
DECODER,
|
||||
INPUT,
|
||||
PLAYLIST_PLUGIN,
|
||||
AUDIO_FILTER,
|
||||
DATABASE,
|
||||
NEIGHBORS,
|
||||
@@ -99,4 +103,11 @@ gcc_pure
|
||||
enum ConfigOption
|
||||
ParseConfigOptionName(const char *name);
|
||||
|
||||
/**
|
||||
* @return #ConfigOption::MAX if not found
|
||||
*/
|
||||
gcc_pure
|
||||
enum ConfigBlockOption
|
||||
ParseConfigBlockOptionName(const char *name);
|
||||
|
||||
#endif
|
||||
|
@@ -23,76 +23,105 @@
|
||||
|
||||
#include <string.h>
|
||||
|
||||
const ConfigTemplate config_templates[] = {
|
||||
{ "music_directory", false, false },
|
||||
{ "playlist_directory", false, false },
|
||||
{ "follow_inside_symlinks", false, false },
|
||||
{ "follow_outside_symlinks", false, false },
|
||||
{ "db_file", false, false },
|
||||
{ "sticker_file", false, false },
|
||||
{ "log_file", false, false },
|
||||
{ "pid_file", false, false },
|
||||
{ "state_file", false, false },
|
||||
{ "state_file_interval", false, false },
|
||||
{ "restore_paused", false, false },
|
||||
{ "user", false, false },
|
||||
{ "group", false, false },
|
||||
{ "bind_to_address", true, false },
|
||||
{ "port", false, false },
|
||||
{ "log_level", false, false },
|
||||
{ "zeroconf_name", false, false },
|
||||
{ "zeroconf_enabled", false, false },
|
||||
{ "password", true, false },
|
||||
{ "default_permissions", false, false },
|
||||
{ "audio_output", true, true },
|
||||
{ "audio_output_format", false, false },
|
||||
{ "mixer_type", false, false },
|
||||
{ "replaygain", false, false },
|
||||
{ "replaygain_preamp", false, false },
|
||||
{ "replaygain_missing_preamp", false, false },
|
||||
{ "replaygain_limit", false, false },
|
||||
{ "volume_normalization", false, false },
|
||||
{ "samplerate_converter", false, false },
|
||||
{ "audio_buffer_size", false, false },
|
||||
{ "buffer_before_play", false, false },
|
||||
{ "http_proxy_host", false, false },
|
||||
{ "http_proxy_port", false, false },
|
||||
{ "http_proxy_user", false, false },
|
||||
{ "http_proxy_password", false, false },
|
||||
{ "connection_timeout", false, false },
|
||||
{ "max_connections", false, false },
|
||||
{ "max_playlist_length", false, false },
|
||||
{ "max_command_list_size", false, false },
|
||||
{ "max_output_buffer_size", false, false },
|
||||
{ "filesystem_charset", false, false },
|
||||
{ "id3v1_encoding", false, false },
|
||||
{ "metadata_to_use", false, false },
|
||||
{ "save_absolute_paths_in_playlists", false, false },
|
||||
{ "decoder", true, true },
|
||||
{ "input", true, true },
|
||||
{ "gapless_mp3_playback", false, false },
|
||||
{ "playlist_plugin", true, true },
|
||||
{ "auto_update", false, false },
|
||||
{ "auto_update_depth", false, false },
|
||||
{ "despotify_user", false, false },
|
||||
{ "despotify_password", false, false},
|
||||
{ "despotify_high_bitrate", false, false },
|
||||
{ "filter", true, true },
|
||||
{ "database", false, true },
|
||||
{ "neighbors", true, true },
|
||||
const ConfigTemplate config_param_templates[] = {
|
||||
{ "music_directory", false },
|
||||
{ "playlist_directory", false },
|
||||
{ "follow_inside_symlinks", false },
|
||||
{ "follow_outside_symlinks", false },
|
||||
{ "db_file", false },
|
||||
{ "sticker_file", false },
|
||||
{ "log_file", false },
|
||||
{ "pid_file", false },
|
||||
{ "state_file", false },
|
||||
{ "state_file_interval", false },
|
||||
{ "restore_paused", false },
|
||||
{ "user", false },
|
||||
{ "group", false },
|
||||
{ "bind_to_address", true },
|
||||
{ "port", false },
|
||||
{ "log_level", false },
|
||||
{ "zeroconf_name", false },
|
||||
{ "zeroconf_enabled", false },
|
||||
{ "password", true },
|
||||
{ "default_permissions", false },
|
||||
{ "audio_output_format", false },
|
||||
{ "mixer_type", false },
|
||||
{ "replaygain", false },
|
||||
{ "replaygain_preamp", false },
|
||||
{ "replaygain_missing_preamp", false },
|
||||
{ "replaygain_limit", false },
|
||||
{ "volume_normalization", false },
|
||||
{ "samplerate_converter", false },
|
||||
{ "audio_buffer_size", false },
|
||||
{ "buffer_before_play", false },
|
||||
{ "http_proxy_host", false },
|
||||
{ "http_proxy_port", false },
|
||||
{ "http_proxy_user", false },
|
||||
{ "http_proxy_password", false },
|
||||
{ "connection_timeout", false },
|
||||
{ "max_connections", false },
|
||||
{ "max_playlist_length", false },
|
||||
{ "max_command_list_size", false },
|
||||
{ "max_output_buffer_size", false },
|
||||
{ "filesystem_charset", false },
|
||||
{ "id3v1_encoding", false },
|
||||
{ "metadata_to_use", false },
|
||||
{ "save_absolute_paths_in_playlists", false },
|
||||
{ "gapless_mp3_playback", false },
|
||||
{ "auto_update", false },
|
||||
{ "auto_update_depth", false },
|
||||
{ "despotify_user", false },
|
||||
{ "despotify_password", false },
|
||||
{ "despotify_high_bitrate", false },
|
||||
};
|
||||
|
||||
static constexpr unsigned n_config_templates = ARRAY_SIZE(config_templates);
|
||||
static constexpr unsigned n_config_param_templates =
|
||||
ARRAY_SIZE(config_param_templates);
|
||||
|
||||
static_assert(n_config_templates == unsigned(ConfigOption::MAX),
|
||||
"Wrong number of config_templates");
|
||||
static_assert(n_config_param_templates == unsigned(ConfigOption::MAX),
|
||||
"Wrong number of config_param_templates");
|
||||
|
||||
const ConfigTemplate config_block_templates[] = {
|
||||
{ "audio_output", true },
|
||||
{ "decoder", true },
|
||||
{ "input", true },
|
||||
{ "playlist_plugin", true },
|
||||
{ "filter", true },
|
||||
{ "database", false },
|
||||
{ "neighbors", true },
|
||||
};
|
||||
|
||||
static constexpr unsigned n_config_block_templates =
|
||||
ARRAY_SIZE(config_block_templates);
|
||||
|
||||
static_assert(n_config_block_templates == unsigned(ConfigBlockOption::MAX),
|
||||
"Wrong number of config_block_templates");
|
||||
|
||||
gcc_pure
|
||||
static inline unsigned
|
||||
ParseConfigTemplateName(const ConfigTemplate templates[], unsigned count,
|
||||
const char *name)
|
||||
{
|
||||
unsigned i = 0;
|
||||
for (; i < count; ++i)
|
||||
if (strcmp(templates[i].name, name) == 0)
|
||||
break;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
ConfigOption
|
||||
ParseConfigOptionName(const char *name)
|
||||
{
|
||||
for (unsigned i = 0; i < n_config_templates; ++i)
|
||||
if (strcmp(config_templates[i].name, name) == 0)
|
||||
return ConfigOption(i);
|
||||
|
||||
return ConfigOption::MAX;
|
||||
return ConfigOption(ParseConfigTemplateName(config_param_templates,
|
||||
n_config_param_templates,
|
||||
name));
|
||||
}
|
||||
|
||||
ConfigBlockOption
|
||||
ParseConfigBlockOptionName(const char *name)
|
||||
{
|
||||
return ConfigBlockOption(ParseConfigTemplateName(config_block_templates,
|
||||
n_config_block_templates,
|
||||
name));
|
||||
}
|
||||
|
@@ -23,9 +23,9 @@
|
||||
struct ConfigTemplate {
|
||||
const char *const name;
|
||||
const bool repeatable;
|
||||
const bool block;
|
||||
};
|
||||
|
||||
extern const ConfigTemplate config_templates[];
|
||||
extern const ConfigTemplate config_param_templates[];
|
||||
extern const ConfigTemplate config_block_templates[];
|
||||
|
||||
#endif
|
||||
|
@@ -20,6 +20,7 @@
|
||||
#include "config.h"
|
||||
#include "Data.hxx"
|
||||
#include "Param.hxx"
|
||||
#include "Block.hxx"
|
||||
|
||||
void
|
||||
ConfigData::Clear()
|
||||
@@ -28,4 +29,9 @@ ConfigData::Clear()
|
||||
delete i;
|
||||
i = nullptr;
|
||||
}
|
||||
|
||||
for (auto &i : blocks) {
|
||||
delete i;
|
||||
i = nullptr;
|
||||
}
|
||||
}
|
||||
|
@@ -25,9 +25,11 @@
|
||||
#include <array>
|
||||
|
||||
struct config_param;
|
||||
struct ConfigBlock;
|
||||
|
||||
struct ConfigData {
|
||||
std::array<config_param *, std::size_t(ConfigOption::MAX)> params;
|
||||
std::array<ConfigBlock *, std::size_t(ConfigBlockOption::MAX)> blocks;
|
||||
|
||||
void Clear();
|
||||
};
|
||||
|
@@ -19,12 +19,6 @@
|
||||
|
||||
#include "config.h"
|
||||
#include "Param.hxx"
|
||||
#include "ConfigPath.hxx"
|
||||
#include "util/Error.hxx"
|
||||
#include "fs/AllocatedPath.hxx"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
config_param::config_param(const char *_value, int _line)
|
||||
:next(nullptr), value(_value), line(_line), used(false) {}
|
||||
@@ -33,91 +27,3 @@ config_param::~config_param()
|
||||
{
|
||||
delete next;
|
||||
}
|
||||
|
||||
const BlockParam *
|
||||
config_param::GetBlockParam(const char *name) const
|
||||
{
|
||||
for (const auto &i : block_params) {
|
||||
if (i.name == name) {
|
||||
i.used = true;
|
||||
return &i;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const char *
|
||||
config_param::GetBlockValue(const char *name, const char *default_value) const
|
||||
{
|
||||
const BlockParam *bp = GetBlockParam(name);
|
||||
if (bp == nullptr)
|
||||
return default_value;
|
||||
|
||||
return bp->value.c_str();
|
||||
}
|
||||
|
||||
AllocatedPath
|
||||
config_param::GetBlockPath(const char *name, const char *default_value,
|
||||
Error &error) const
|
||||
{
|
||||
assert(!error.IsDefined());
|
||||
|
||||
int line2 = line;
|
||||
const char *s;
|
||||
|
||||
const BlockParam *bp = GetBlockParam(name);
|
||||
if (bp != nullptr) {
|
||||
line2 = bp->line;
|
||||
s = bp->value.c_str();
|
||||
} else {
|
||||
if (default_value == nullptr)
|
||||
return AllocatedPath::Null();
|
||||
|
||||
s = default_value;
|
||||
}
|
||||
|
||||
AllocatedPath path = ParsePath(s, error);
|
||||
if (gcc_unlikely(path.IsNull()))
|
||||
error.FormatPrefix("Invalid path in \"%s\" at line %i: ",
|
||||
name, line2);
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
AllocatedPath
|
||||
config_param::GetBlockPath(const char *name, Error &error) const
|
||||
{
|
||||
return GetBlockPath(name, nullptr, error);
|
||||
}
|
||||
|
||||
int
|
||||
config_param::GetBlockValue(const char *name, int default_value) const
|
||||
{
|
||||
const BlockParam *bp = GetBlockParam(name);
|
||||
if (bp == nullptr)
|
||||
return default_value;
|
||||
|
||||
return bp->GetIntValue();
|
||||
}
|
||||
|
||||
unsigned
|
||||
config_param::GetBlockValue(const char *name, unsigned default_value) const
|
||||
{
|
||||
const BlockParam *bp = GetBlockParam(name);
|
||||
if (bp == nullptr)
|
||||
return default_value;
|
||||
|
||||
return bp->GetUnsignedValue();
|
||||
}
|
||||
|
||||
gcc_pure
|
||||
bool
|
||||
config_param::GetBlockValue(const char *name, bool default_value) const
|
||||
{
|
||||
const BlockParam *bp = GetBlockParam(name);
|
||||
if (bp == nullptr)
|
||||
return default_value;
|
||||
|
||||
return bp->GetBoolValue();
|
||||
}
|
||||
|
@@ -20,14 +20,10 @@
|
||||
#ifndef MPD_CONFIG_PARAM_HXX
|
||||
#define MPD_CONFIG_PARAM_HXX
|
||||
|
||||
#include "Block.hxx"
|
||||
#include "check.h"
|
||||
#include "Compiler.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class AllocatedPath;
|
||||
class Error;
|
||||
|
||||
struct config_param {
|
||||
/**
|
||||
@@ -40,8 +36,6 @@ struct config_param {
|
||||
|
||||
int line;
|
||||
|
||||
std::vector<BlockParam> block_params;
|
||||
|
||||
/**
|
||||
* This flag is false when nobody has queried the value of
|
||||
* this option yet.
|
||||
@@ -68,37 +62,6 @@ struct config_param {
|
||||
bool IsNull() const {
|
||||
return line < 0;
|
||||
}
|
||||
|
||||
gcc_nonnull_all
|
||||
void AddBlockParam(const char *_name, const char *_value,
|
||||
int _line=-1) {
|
||||
block_params.emplace_back(_name, _value, _line);
|
||||
}
|
||||
|
||||
gcc_nonnull_all gcc_pure
|
||||
const BlockParam *GetBlockParam(const char *_name) const;
|
||||
|
||||
gcc_pure
|
||||
const char *GetBlockValue(const char *name,
|
||||
const char *default_value=nullptr) const;
|
||||
|
||||
/**
|
||||
* Same as config_get_path(), but looks up the setting in the
|
||||
* specified block.
|
||||
*/
|
||||
AllocatedPath GetBlockPath(const char *name, const char *default_value,
|
||||
Error &error) const;
|
||||
|
||||
AllocatedPath GetBlockPath(const char *name, Error &error) const;
|
||||
|
||||
gcc_pure
|
||||
int GetBlockValue(const char *name, int default_value) const;
|
||||
|
||||
gcc_pure
|
||||
unsigned GetBlockValue(const char *name, unsigned default_value) const;
|
||||
|
||||
gcc_pure
|
||||
bool GetBlockValue(const char *name, bool default_value) const;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
Reference in New Issue
Block a user