aboutsummaryrefslogtreecommitdiffstats
path: root/src/config
diff options
context:
space:
mode:
Diffstat (limited to 'src/config')
-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.hxx2
-rw-r--r--src/config/ConfigError.cxx2
-rw-r--r--src/config/ConfigError.hxx2
-rw-r--r--src/config/ConfigFile.cxx262
-rw-r--r--src/config/ConfigFile.hxx2
-rw-r--r--src/config/ConfigGlobal.cxx46
-rw-r--r--src/config/ConfigGlobal.hxx23
-rw-r--r--src/config/ConfigOption.hxx142
-rw-r--r--src/config/ConfigParser.cxx6
-rw-r--r--src/config/ConfigParser.hxx2
-rw-r--r--src/config/ConfigPath.cxx4
-rw-r--r--src/config/ConfigPath.hxx2
-rw-r--r--src/config/ConfigTemplates.cxx162
-rw-r--r--src/config/ConfigTemplates.hxx15
-rw-r--r--src/config/Data.cxx37
-rw-r--r--src/config/Data.hxx37
-rw-r--r--src/config/Param.cxx29
-rw-r--r--src/config/Param.hxx67
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