diff options
Diffstat (limited to '')
-rw-r--r-- | src/config/Block.cxx (renamed from src/config/ConfigData.cxx) | 49 | ||||
-rw-r--r-- | src/config/Block.hxx (renamed from src/config/ConfigData.hxx) | 54 | ||||
-rw-r--r-- | src/config/ConfigDefaults.hxx | 2 | ||||
-rw-r--r-- | src/config/ConfigError.cxx | 2 | ||||
-rw-r--r-- | src/config/ConfigError.hxx | 2 | ||||
-rw-r--r-- | src/config/ConfigFile.cxx | 262 | ||||
-rw-r--r-- | src/config/ConfigFile.hxx | 2 | ||||
-rw-r--r-- | src/config/ConfigGlobal.cxx | 46 | ||||
-rw-r--r-- | src/config/ConfigGlobal.hxx | 23 | ||||
-rw-r--r-- | src/config/ConfigOption.hxx | 142 | ||||
-rw-r--r-- | src/config/ConfigParser.cxx | 6 | ||||
-rw-r--r-- | src/config/ConfigParser.hxx | 2 | ||||
-rw-r--r-- | src/config/ConfigPath.cxx | 4 | ||||
-rw-r--r-- | src/config/ConfigPath.hxx | 2 | ||||
-rw-r--r-- | src/config/ConfigTemplates.cxx | 162 | ||||
-rw-r--r-- | src/config/ConfigTemplates.hxx | 15 | ||||
-rw-r--r-- | src/config/Data.cxx | 37 | ||||
-rw-r--r-- | src/config/Data.hxx | 37 | ||||
-rw-r--r-- | src/config/Param.cxx | 29 | ||||
-rw-r--r-- | src/config/Param.hxx | 67 |
20 files changed, 614 insertions, 331 deletions
diff --git a/src/config/ConfigData.cxx b/src/config/Block.cxx index 70e1e55ed..a74903b10 100644 --- a/src/config/ConfigData.cxx +++ b/src/config/Block.cxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2014 The Music Player Daemon Project + * Copyright (C) 2003-2015 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -18,18 +18,18 @@ */ #include "config.h" -#include "ConfigData.hxx" +#include "Block.hxx" #include "ConfigParser.hxx" #include "ConfigPath.hxx" -#include "util/Error.hxx" -#include "fs/AllocatedPath.hxx" #include "system/FatalError.hxx" +#include "fs/AllocatedPath.hxx" +#include "util/Error.hxx" #include <assert.h> #include <stdlib.h> int -block_param::GetIntValue() const +BlockParam::GetIntValue() const { char *endptr; long value2 = strtol(value.c_str(), &endptr, 0); @@ -40,7 +40,7 @@ block_param::GetIntValue() const } unsigned -block_param::GetUnsignedValue() const +BlockParam::GetUnsignedValue() const { char *endptr; unsigned long value2 = strtoul(value.c_str(), &endptr, 0); @@ -51,7 +51,7 @@ block_param::GetUnsignedValue() const } bool -block_param::GetBoolValue() const +BlockParam::GetBoolValue() const { bool value2; if (!get_bool(value.c_str(), &value2)) @@ -62,16 +62,13 @@ block_param::GetBoolValue() const return value2; } -config_param::config_param(const char *_value, int _line) - :next(nullptr), value(_value), line(_line), used(false) {} - -config_param::~config_param() +ConfigBlock::~ConfigBlock() { delete next; } -const block_param * -config_param::GetBlockParam(const char *name) const +const BlockParam * +ConfigBlock::GetBlockParam(const char *name) const { for (const auto &i : block_params) { if (i.name == name) { @@ -80,13 +77,13 @@ config_param::GetBlockParam(const char *name) const } } - return NULL; + return nullptr; } const char * -config_param::GetBlockValue(const char *name, const char *default_value) const +ConfigBlock::GetBlockValue(const char *name, const char *default_value) const { - const block_param *bp = GetBlockParam(name); + const BlockParam *bp = GetBlockParam(name); if (bp == nullptr) return default_value; @@ -94,7 +91,7 @@ config_param::GetBlockValue(const char *name, const char *default_value) const } AllocatedPath -config_param::GetBlockPath(const char *name, const char *default_value, +ConfigBlock::GetBlockPath(const char *name, const char *default_value, Error &error) const { assert(!error.IsDefined()); @@ -102,7 +99,7 @@ config_param::GetBlockPath(const char *name, const char *default_value, int line2 = line; const char *s; - const block_param *bp = GetBlockParam(name); + const BlockParam *bp = GetBlockParam(name); if (bp != nullptr) { line2 = bp->line; s = bp->value.c_str(); @@ -122,15 +119,15 @@ config_param::GetBlockPath(const char *name, const char *default_value, } AllocatedPath -config_param::GetBlockPath(const char *name, Error &error) const +ConfigBlock::GetBlockPath(const char *name, Error &error) const { return GetBlockPath(name, nullptr, error); } int -config_param::GetBlockValue(const char *name, int default_value) const +ConfigBlock::GetBlockValue(const char *name, int default_value) const { - const block_param *bp = GetBlockParam(name); + const BlockParam *bp = GetBlockParam(name); if (bp == nullptr) return default_value; @@ -138,9 +135,9 @@ config_param::GetBlockValue(const char *name, int default_value) const } unsigned -config_param::GetBlockValue(const char *name, unsigned default_value) const +ConfigBlock::GetBlockValue(const char *name, unsigned default_value) const { - const block_param *bp = GetBlockParam(name); + const BlockParam *bp = GetBlockParam(name); if (bp == nullptr) return default_value; @@ -149,10 +146,10 @@ config_param::GetBlockValue(const char *name, unsigned default_value) const gcc_pure bool -config_param::GetBlockValue(const char *name, bool default_value) const +ConfigBlock::GetBlockValue(const char *name, bool default_value) const { - const block_param *bp = GetBlockParam(name); - if (bp == NULL) + const BlockParam *bp = GetBlockParam(name); + if (bp == nullptr) return default_value; return bp->GetBoolValue(); diff --git a/src/config/ConfigData.hxx b/src/config/Block.hxx index e42d674ba..9e72018ca 100644 --- a/src/config/ConfigData.hxx +++ b/src/config/Block.hxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2014 The Music Player Daemon Project + * Copyright (C) 2003-2015 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -17,20 +17,20 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#ifndef MPD_CONFIG_DATA_HXX -#define MPD_CONFIG_DATA_HXX +#ifndef MPD_CONFIG_BLOCK_HXX +#define MPD_CONFIG_BLOCK_HXX -#include "ConfigOption.hxx" +#include "check.h" +#include "Param.hxx" #include "Compiler.h" #include <string> -#include <array> #include <vector> -class AllocatedPath; class Error; +class AllocatedPath; -struct block_param { +struct BlockParam { std::string name; std::string value; int line; @@ -42,7 +42,7 @@ struct block_param { mutable bool used; gcc_nonnull_all - block_param(const char *_name, const char *_value, int _line=-1) + BlockParam(const char *_name, const char *_value, int _line=-1) :name(_name), value(_value), line(_line), used(false) {} gcc_pure @@ -55,18 +55,16 @@ struct block_param { bool GetBoolValue() const; }; -struct config_param { +struct ConfigBlock { /** - * The next config_param with the same name. The destructor + * The next #ConfigBlock with the same name. The destructor * deletes the whole chain. */ - struct config_param *next; - - std::string value; + ConfigBlock *next; - unsigned int line; + int line; - std::vector<block_param> block_params; + std::vector<BlockParam> block_params; /** * This flag is false when nobody has queried the value of @@ -74,17 +72,14 @@ struct config_param { */ bool used; - config_param(int _line=-1) + explicit ConfigBlock(int _line=-1) :next(nullptr), line(_line), used(false) {} - gcc_nonnull_all - config_param(const char *_value, int _line=-1); - - config_param(const config_param &) = delete; + ConfigBlock(const ConfigBlock &) = delete; - ~config_param(); + ~ConfigBlock(); - config_param &operator=(const config_param &) = delete; + ConfigBlock &operator=(const ConfigBlock &) = delete; /** * Determine if this is a "null" instance, i.e. an empty @@ -92,7 +87,12 @@ struct config_param { * configuration file. */ bool IsNull() const { - return line == unsigned(-1); + return line < 0; + } + + gcc_pure + bool IsEmpty() const { + return block_params.empty(); } gcc_nonnull_all @@ -102,14 +102,14 @@ struct config_param { } gcc_nonnull_all gcc_pure - const block_param *GetBlockParam(const char *_name) const; + const BlockParam *GetBlockParam(const char *_name) const; gcc_pure const char *GetBlockValue(const char *name, const char *default_value=nullptr) const; /** - * Same as config_dup_path(), but looks up the setting in the + * Same as config_get_path(), but looks up the setting in the * specified block. */ AllocatedPath GetBlockPath(const char *name, const char *default_value, @@ -127,8 +127,4 @@ struct config_param { bool GetBlockValue(const char *name, bool default_value) const; }; -struct ConfigData { - std::array<config_param *, std::size_t(CONF_MAX)> params; -}; - #endif diff --git a/src/config/ConfigDefaults.hxx b/src/config/ConfigDefaults.hxx index c50f28c91..2dca5d469 100644 --- a/src/config/ConfigDefaults.hxx +++ b/src/config/ConfigDefaults.hxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2014 The Music Player Daemon Project + * Copyright (C) 2003-2015 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify diff --git a/src/config/ConfigError.cxx b/src/config/ConfigError.cxx index 70aff7175..b2a773b15 100644 --- a/src/config/ConfigError.cxx +++ b/src/config/ConfigError.cxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2014 The Music Player Daemon Project + * Copyright (C) 2003-2015 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify diff --git a/src/config/ConfigError.hxx b/src/config/ConfigError.hxx index cbfa79df3..89543599d 100644 --- a/src/config/ConfigError.hxx +++ b/src/config/ConfigError.hxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2014 The Music Player Daemon Project + * Copyright (C) 2003-2015 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify diff --git a/src/config/ConfigFile.cxx b/src/config/ConfigFile.cxx index 1329c4cd4..b6164b8bc 100644 --- a/src/config/ConfigFile.cxx +++ b/src/config/ConfigFile.cxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2014 The Music Player Daemon Project + * Copyright (C) 2003-2015 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -19,28 +19,27 @@ #include "config.h" #include "ConfigFile.hxx" -#include "ConfigData.hxx" +#include "Data.hxx" +#include "Param.hxx" +#include "Block.hxx" #include "ConfigTemplates.hxx" #include "util/Tokenizer.hxx" #include "util/StringUtil.hxx" #include "util/Error.hxx" #include "util/Domain.hxx" -#include "fs/Limits.hxx" #include "fs/Path.hxx" -#include "fs/FileSystem.hxx" +#include "fs/io/FileReader.hxx" +#include "fs/io/BufferedReader.hxx" #include "Log.hxx" #include <assert.h> -#include <stdio.h> -#define MAX_STRING_SIZE MPD_PATH_MAX+80 - -#define CONF_COMMENT '#' +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); @@ -67,7 +66,7 @@ config_read_name_value(struct config_param *param, char *input, unsigned line, return false; } - const struct block_param *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", @@ -75,27 +74,26 @@ 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 * -config_read_block(FILE *fp, int *count, char *string, Error &error) +static ConfigBlock * +config_read_block(BufferedReader &reader, Error &error) { - struct config_param *ret = new config_param(*count); + auto *ret = new ConfigBlock(reader.GetLineNumber()); while (true) { - char *line; - - line = fgets(string, MAX_STRING_SIZE, fp); + char *line = reader.ReadLine(); if (line == nullptr) { delete ret; - error.Set(config_file_domain, - "Expected '}' before end-of-file"); + + if (reader.Check(error)) + error.Set(config_file_domain, + "Expected '}' before end-of-file"); return nullptr; } - (*count)++; line = StripLeft(line); if (*line == 0 || *line == CONF_COMMENT) continue; @@ -108,8 +106,8 @@ config_read_block(FILE *fp, int *count, char *string, Error &error) if (*line != 0 && *line != CONF_COMMENT) { delete ret; error.Format(config_file_domain, - "line %i: Unknown tokens after '}'", - *count); + "line %y: Unknown tokens after '}'", + reader.GetLineNumber()); return nullptr; } @@ -118,10 +116,11 @@ config_read_block(FILE *fp, int *count, char *string, Error &error) /* parse name and value */ - if (!config_read_name_value(ret, line, *count, error)) { + if (!config_read_name_value(*ret, line, reader.GetLineNumber(), + error)) { assert(*line != 0); delete ret; - error.FormatPrefix("line %i: ", *count); + error.FormatPrefix("line %u: ", reader.GetLineNumber()); return nullptr; } } @@ -129,6 +128,64 @@ config_read_block(FILE *fp, int *count, char *string, 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, ConfigBlockOption 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) { assert(p->next == nullptr); @@ -141,21 +198,62 @@ Append(config_param *&head, config_param *p) } static bool -ReadConfigFile(ConfigData &config_data, FILE *fp, Error &error) +ReadConfigParam(ConfigData &config_data, BufferedReader &reader, + const char *name, ConfigOption o, + Tokenizer &tokenizer, + Error &error) { - assert(fp != nullptr); + const unsigned i = unsigned(o); + const ConfigTemplate &option = config_param_templates[i]; + config_param *&head = config_data.params[i]; - char string[MAX_STRING_SIZE + 1]; - int count = 0; - struct config_param *param; + if (head != nullptr && !option.repeatable) { + struct config_param *param = head; + error.Format(config_file_domain, + "config parameter \"%s\" is first defined " + "on line %d and redefined on line %u\n", + name, param->line, + reader.GetLineNumber()); + return false; + } - while (fgets(string, MAX_STRING_SIZE, fp)) { - char *line; - const char *name, *value; + /* now parse the block or the value */ - count++; + 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()); - line = StripLeft(string); + 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; +} + +static bool +ReadConfigFile(ConfigData &config_data, BufferedReader &reader, Error &error) +{ + while (true) { + char *line = reader.ReadLine(); + if (line == nullptr) + return true; + + line = StripLeft(line); if (*line == 0 || *line == CONF_COMMENT) continue; @@ -163,10 +261,10 @@ ReadConfigFile(ConfigData &config_data, FILE *fp, Error &error) by either the value or '{' */ Tokenizer tokenizer(line); - name = tokenizer.NextWord(error); + const char *name = tokenizer.NextWord(error); if (name == nullptr) { assert(!tokenizer.IsEnd()); - error.FormatPrefix("line %i: ", count); + error.FormatPrefix("line %u: ", reader.GetLineNumber()); return false; } @@ -174,79 +272,23 @@ ReadConfigFile(ConfigData &config_data, FILE *fp, Error &error) "repeatable" flag */ const ConfigOption o = ParseConfigOptionName(name); - if (o == CONF_MAX) { - error.Format(config_file_domain, - "unrecognized parameter in config file at " - "line %i: %s\n", count, name); - return false; - } - - const unsigned i = unsigned(o); - const ConfigTemplate &option = config_templates[i]; - config_param *&head = config_data.params[i]; - - if (head != nullptr && !option.repeatable) { - param = head; - error.Format(config_file_domain, - "config parameter \"%s\" is first defined " - "on line %i and redefined on line %i\n", - name, param->line, count); - return false; - } - - /* now parse the block or the value */ - - if (option.block) { - /* it's a block, call config_read_block() */ - - if (tokenizer.CurrentChar() != '{') { - error.Format(config_file_domain, - "line %i: '{' expected", count); - return false; - } - - line = StripLeft(tokenizer.Rest() + 1); - if (*line != 0 && *line != CONF_COMMENT) { - error.Format(config_file_domain, - "line %i: Unknown tokens after '{'", - count); + ConfigBlockOption bo; + if (o != ConfigOption::MAX) { + if (!ReadConfigParam(config_data, reader, name, o, + tokenizer, error)) return false; - } - - param = config_read_block(fp, &count, string, error); - if (param == nullptr) { + } else if ((bo = ParseConfigBlockOptionName(name)) != ConfigBlockOption::MAX) { + if (!ReadConfigBlock(config_data, reader, name, bo, + tokenizer, error)) return false; - } } else { - /* a string value */ - - value = tokenizer.NextString(error); - if (value == nullptr) { - if (tokenizer.IsEnd()) - error.Format(config_file_domain, - "line %i: Value missing", - count); - else - error.FormatPrefix("line %i: ", count); - - return false; - } - - if (!tokenizer.IsEnd() && - tokenizer.CurrentChar() != CONF_COMMENT) { - error.Format(config_file_domain, - "line %i: Unknown tokens after value", - count); - return false; - } - - param = new config_param(value, count); + error.Format(config_file_domain, + "unrecognized parameter in config file at " + "line %u: %s\n", + reader.GetLineNumber(), name); + return false; } - - Append(head, param); } - - return true; } bool @@ -257,13 +299,11 @@ ReadConfigFile(ConfigData &config_data, Path path, Error &error) FormatDebug(config_file_domain, "loading file %s", path_utf8.c_str()); - FILE *fp = FOpen(path, FOpenMode::ReadText); - if (fp == nullptr) { - error.FormatErrno("Failed to open %s", path_utf8.c_str()); + FileReader file(path, error); + if (!file.IsDefined()) return false; - } - bool result = ReadConfigFile(config_data, fp, error); - fclose(fp); - return result; + BufferedReader reader(file); + return ReadConfigFile(config_data, reader, error) && + reader.Check(error); } diff --git a/src/config/ConfigFile.hxx b/src/config/ConfigFile.hxx index b87182c6a..30bee0614 100644 --- a/src/config/ConfigFile.hxx +++ b/src/config/ConfigFile.hxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2014 The Music Player Daemon Project + * Copyright (C) 2003-2015 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify diff --git a/src/config/ConfigGlobal.cxx b/src/config/ConfigGlobal.cxx index 9bc83398c..192baffec 100644 --- a/src/config/ConfigGlobal.cxx +++ b/src/config/ConfigGlobal.cxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2014 The Music Player Daemon Project + * Copyright (C) 2003-2015 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -20,7 +20,9 @@ #include "config.h" #include "ConfigGlobal.hxx" #include "ConfigParser.hxx" -#include "ConfigData.hxx" +#include "Data.hxx" +#include "Param.hxx" +#include "Block.hxx" #include "ConfigFile.hxx" #include "ConfigPath.hxx" #include "ConfigError.hxx" @@ -36,8 +38,7 @@ static ConfigData config_data; void config_global_finish(void) { - for (auto i : config_data.params) - delete i; + config_data.Clear(); } void config_global_init(void) @@ -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) +{ + 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 config_param *param = config_get_param(option); - param != nullptr; param = param->next) { - const char *value2 = param->GetBlockValue(key); + 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; diff --git a/src/config/ConfigGlobal.hxx b/src/config/ConfigGlobal.hxx index 831418d03..b24b9aada 100644 --- a/src/config/ConfigGlobal.hxx +++ b/src/config/ConfigGlobal.hxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2014 The Music Player Daemon Project + * Copyright (C) 2003-2015 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -27,15 +27,20 @@ class Error; class Path; class AllocatedPath; struct config_param; +struct ConfigBlock; -void config_global_init(void); -void config_global_finish(void); +void +config_global_init(); + +void +config_global_finish(); /** * Call this function after all configuration has been evaluated. It * checks for unused parameters, and logs warnings. */ -void config_global_check(void); +void +config_global_check(); bool ReadConfigFile(Path path, Error &error); @@ -44,6 +49,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 +61,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 @@ -64,7 +73,7 @@ config_find_block(ConfigOption option, const char *key, const char *value); gcc_pure const char * -config_get_string(enum ConfigOption option, const char *default_value); +config_get_string(enum ConfigOption option, const char *default_value=nullptr); /** * Returns an optional configuration variable which contains an diff --git a/src/config/ConfigOption.hxx b/src/config/ConfigOption.hxx index 8eb4c7eaf..5acd6fd49 100644 --- a/src/config/ConfigOption.hxx +++ b/src/config/ConfigOption.hxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2014 The Music Player Daemon Project + * Copyright (C) 2003-2015 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -22,71 +22,93 @@ #include "Compiler.h" -enum ConfigOption { - CONF_MUSIC_DIR, - CONF_PLAYLIST_DIR, - CONF_FOLLOW_INSIDE_SYMLINKS, - CONF_FOLLOW_OUTSIDE_SYMLINKS, - CONF_DB_FILE, - CONF_STICKER_FILE, - CONF_LOG_FILE, - CONF_PID_FILE, - CONF_STATE_FILE, - CONF_STATE_FILE_INTERVAL, - CONF_RESTORE_PAUSED, - CONF_USER, - CONF_GROUP, - CONF_BIND_TO_ADDRESS, - CONF_PORT, - CONF_LOG_LEVEL, - CONF_ZEROCONF_NAME, - CONF_ZEROCONF_ENABLED, - CONF_PASSWORD, - CONF_DEFAULT_PERMS, - CONF_AUDIO_OUTPUT, - CONF_AUDIO_OUTPUT_FORMAT, - CONF_MIXER_TYPE, - CONF_REPLAYGAIN, - CONF_REPLAYGAIN_PREAMP, - CONF_REPLAYGAIN_MISSING_PREAMP, - CONF_REPLAYGAIN_LIMIT, - CONF_VOLUME_NORMALIZATION, - CONF_SAMPLERATE_CONVERTER, - CONF_AUDIO_BUFFER_SIZE, - CONF_BUFFER_BEFORE_PLAY, - CONF_HTTP_PROXY_HOST, - CONF_HTTP_PROXY_PORT, - CONF_HTTP_PROXY_USER, - CONF_HTTP_PROXY_PASSWORD, - CONF_CONN_TIMEOUT, - CONF_MAX_CONN, - CONF_MAX_PLAYLIST_LENGTH, - CONF_MAX_COMMAND_LIST_SIZE, - CONF_MAX_OUTPUT_BUFFER_SIZE, - CONF_FS_CHARSET, - CONF_ID3V1_ENCODING, - CONF_METADATA_TO_USE, - CONF_SAVE_ABSOLUTE_PATHS, - CONF_DECODER, - CONF_INPUT, - CONF_GAPLESS_MP3_PLAYBACK, - CONF_PLAYLIST_PLUGIN, - CONF_AUTO_UPDATE, - CONF_AUTO_UPDATE_DEPTH, - CONF_DESPOTIFY_USER, - CONF_DESPOTIFY_PASSWORD, - CONF_DESPOTIFY_HIGH_BITRATE, - CONF_AUDIO_FILTER, - CONF_DATABASE, - CONF_NEIGHBORS, - CONF_MAX +#if defined(WIN32) && CLANG_OR_GCC_VERSION(4,7) +/* "INPUT" is declared by winuser.h */ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wshadow" +#endif + +enum class ConfigOption { + MUSIC_DIR, + PLAYLIST_DIR, + FOLLOW_INSIDE_SYMLINKS, + FOLLOW_OUTSIDE_SYMLINKS, + DB_FILE, + STICKER_FILE, + LOG_FILE, + PID_FILE, + STATE_FILE, + STATE_FILE_INTERVAL, + RESTORE_PAUSED, + USER, + GROUP, + BIND_TO_ADDRESS, + PORT, + LOG_LEVEL, + ZEROCONF_NAME, + ZEROCONF_ENABLED, + PASSWORD, + DEFAULT_PERMS, + AUDIO_OUTPUT_FORMAT, + MIXER_TYPE, + REPLAYGAIN, + REPLAYGAIN_PREAMP, + REPLAYGAIN_MISSING_PREAMP, + REPLAYGAIN_LIMIT, + VOLUME_NORMALIZATION, + SAMPLERATE_CONVERTER, + AUDIO_BUFFER_SIZE, + BUFFER_BEFORE_PLAY, + HTTP_PROXY_HOST, + HTTP_PROXY_PORT, + HTTP_PROXY_USER, + HTTP_PROXY_PASSWORD, + CONN_TIMEOUT, + MAX_CONN, + MAX_PLAYLIST_LENGTH, + MAX_COMMAND_LIST_SIZE, + MAX_OUTPUT_BUFFER_SIZE, + FS_CHARSET, + ID3V1_ENCODING, + METADATA_TO_USE, + SAVE_ABSOLUTE_PATHS, + GAPLESS_MP3_PLAYBACK, + AUTO_UPDATE, + AUTO_UPDATE_DEPTH, + DESPOTIFY_USER, + DESPOTIFY_PASSWORD, + DESPOTIFY_HIGH_BITRATE, + MAX }; +enum class ConfigBlockOption { + AUDIO_OUTPUT, + DECODER, + INPUT, + PLAYLIST_PLUGIN, + RESAMPLER, + AUDIO_FILTER, + DATABASE, + NEIGHBORS, + MAX +}; + +#if defined(WIN32) && CLANG_OR_GCC_VERSION(4,7) +#pragma GCC diagnostic pop +#endif + /** - * @return #CONF_MAX if not found + * @return #ConfigOption::MAX if not found */ gcc_pure enum ConfigOption ParseConfigOptionName(const char *name); +/** + * @return #ConfigOption::MAX if not found + */ +gcc_pure +enum ConfigBlockOption +ParseConfigBlockOptionName(const char *name); + #endif diff --git a/src/config/ConfigParser.cxx b/src/config/ConfigParser.cxx index 3535c9a13..40afe1edd 100644 --- a/src/config/ConfigParser.cxx +++ b/src/config/ConfigParser.cxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2014 The Music Player Daemon Project + * Copyright (C) 2003-2015 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -23,8 +23,8 @@ bool get_bool(const char *value, bool *value_r) { - static const char *t[] = { "yes", "true", "1", nullptr }; - static const char *f[] = { "no", "false", "0", nullptr }; + static const char *const t[] = { "yes", "true", "1", nullptr }; + static const char *const f[] = { "no", "false", "0", nullptr }; if (string_array_contains(t, value)) { *value_r = true; diff --git a/src/config/ConfigParser.hxx b/src/config/ConfigParser.hxx index 06151b0bd..c696801f5 100644 --- a/src/config/ConfigParser.hxx +++ b/src/config/ConfigParser.hxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2014 The Music Player Daemon Project + * Copyright (C) 2003-2015 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify diff --git a/src/config/ConfigPath.cxx b/src/config/ConfigPath.cxx index a3b3f83a5..c1e57b3ba 100644 --- a/src/config/ConfigPath.cxx +++ b/src/config/ConfigPath.cxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2014 The Music Player Daemon Project + * Copyright (C) 2003-2015 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -70,7 +70,7 @@ GetHome(Error &error) static AllocatedPath GetConfiguredHome(Error &error) { - const char *user = config_get_string(CONF_USER, nullptr); + const char *user = config_get_string(ConfigOption::USER); return user != nullptr ? GetHome(user, error) : GetHome(error); diff --git a/src/config/ConfigPath.hxx b/src/config/ConfigPath.hxx index a5518a497..afd3e0435 100644 --- a/src/config/ConfigPath.hxx +++ b/src/config/ConfigPath.hxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2014 The Music Player Daemon Project + * Copyright (C) 2003-2015 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify diff --git a/src/config/ConfigTemplates.cxx b/src/config/ConfigTemplates.cxx index 58ee56425..cd353dc19 100644 --- a/src/config/ConfigTemplates.cxx +++ b/src/config/ConfigTemplates.cxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2014 The Music Player Daemon Project + * Copyright (C) 2003-2015 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -19,80 +19,110 @@ #include "ConfigTemplates.hxx" #include "ConfigOption.hxx" +#include "util/Macros.hxx" #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" }, + { "playlist_directory" }, + { "follow_inside_symlinks" }, + { "follow_outside_symlinks" }, + { "db_file" }, + { "sticker_file" }, + { "log_file" }, + { "pid_file" }, + { "state_file" }, + { "state_file_interval" }, + { "restore_paused" }, + { "user" }, + { "group" }, + { "bind_to_address", true }, + { "port" }, + { "log_level" }, + { "zeroconf_name" }, + { "zeroconf_enabled" }, + { "password", true }, + { "default_permissions" }, + { "audio_output_format" }, + { "mixer_type" }, + { "replaygain" }, + { "replaygain_preamp" }, + { "replaygain_missing_preamp" }, + { "replaygain_limit" }, + { "volume_normalization" }, + { "samplerate_converter" }, + { "audio_buffer_size" }, + { "buffer_before_play" }, + { "http_proxy_host", false, true }, + { "http_proxy_port", false, true }, + { "http_proxy_user", false, true }, + { "http_proxy_password", false, true }, + { "connection_timeout" }, + { "max_connections" }, + { "max_playlist_length" }, + { "max_command_list_size" }, + { "max_output_buffer_size" }, + { "filesystem_charset" }, + { "id3v1_encoding", false, true }, + { "metadata_to_use" }, + { "save_absolute_paths_in_playlists" }, + { "gapless_mp3_playback" }, + { "auto_update" }, + { "auto_update_depth" }, + { "despotify_user", false, true }, + { "despotify_password", false, true }, + { "despotify_high_bitrate", false, true }, }; -static constexpr unsigned n_config_templates = - sizeof(config_templates) / sizeof(config_templates[0]); +static constexpr unsigned n_config_param_templates = + ARRAY_SIZE(config_param_templates); -static_assert(n_config_templates == unsigned(CONF_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 }, + { "resampler" }, + { "filter", true }, + { "database" }, + { "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(ParseConfigTemplateName(config_param_templates, + n_config_param_templates, + name)); +} - return CONF_MAX; +ConfigBlockOption +ParseConfigBlockOptionName(const char *name) +{ + return ConfigBlockOption(ParseConfigTemplateName(config_block_templates, + n_config_block_templates, + name)); } diff --git a/src/config/ConfigTemplates.hxx b/src/config/ConfigTemplates.hxx index 90d098dc0..3a18ebdc8 100644 --- a/src/config/ConfigTemplates.hxx +++ b/src/config/ConfigTemplates.hxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2014 The Music Player Daemon Project + * Copyright (C) 2003-2015 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -23,9 +23,18 @@ struct ConfigTemplate { const char *const name; const bool repeatable; - const bool block; + + // TODO: print warning when a deprecated option is used + const bool deprecated; + + constexpr ConfigTemplate(const char *_name, + bool _repeatable=false, + bool _deprecated=false) + :name(_name), repeatable(_repeatable), + deprecated(_deprecated) {} }; -extern const ConfigTemplate config_templates[]; +extern const ConfigTemplate config_param_templates[]; +extern const ConfigTemplate config_block_templates[]; #endif diff --git a/src/config/Data.cxx b/src/config/Data.cxx new file mode 100644 index 000000000..52521e31a --- /dev/null +++ b/src/config/Data.cxx @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2003-2015 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" +#include "Data.hxx" +#include "Param.hxx" +#include "Block.hxx" + +void +ConfigData::Clear() +{ + for (auto &i : params) { + delete i; + i = nullptr; + } + + for (auto &i : blocks) { + delete i; + i = nullptr; + } +} diff --git a/src/config/Data.hxx b/src/config/Data.hxx new file mode 100644 index 000000000..6036c49e6 --- /dev/null +++ b/src/config/Data.hxx @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2003-2015 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef MPD_CONFIG_DATA_HXX +#define MPD_CONFIG_DATA_HXX + +#include "ConfigOption.hxx" + +#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(); +}; + +#endif diff --git a/src/config/Param.cxx b/src/config/Param.cxx new file mode 100644 index 000000000..bfd9743d2 --- /dev/null +++ b/src/config/Param.cxx @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2003-2015 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" +#include "Param.hxx" + +config_param::config_param(const char *_value, int _line) + :next(nullptr), value(_value), line(_line), used(false) {} + +config_param::~config_param() +{ + delete next; +} diff --git a/src/config/Param.hxx b/src/config/Param.hxx new file mode 100644 index 000000000..e6a039c2a --- /dev/null +++ b/src/config/Param.hxx @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2003-2015 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef MPD_CONFIG_PARAM_HXX +#define MPD_CONFIG_PARAM_HXX + +#include "check.h" +#include "Compiler.h" + +#include <string> + +struct config_param { + /** + * The next config_param with the same name. The destructor + * deletes the whole chain. + */ + struct config_param *next; + + std::string value; + + int line; + + /** + * This flag is false when nobody has queried the value of + * this option yet. + */ + bool used; + + explicit config_param(int _line=-1) + :next(nullptr), line(_line), used(false) {} + + gcc_nonnull_all + config_param(const char *_value, int _line=-1); + + config_param(const config_param &) = delete; + + ~config_param(); + + config_param &operator=(const config_param &) = 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; + } +}; + +#endif |