diff --git a/NEWS b/NEWS
index e586519e3..97499a0b3 100644
--- a/NEWS
+++ b/NEWS
@@ -1,4 +1,6 @@
ver 0.21 (not yet released)
+* configuration
+ - add "include" directive, allows including config files
* protocol
- "tagtypes" can be used to hide tags
- "find" and "search" can sort
diff --git a/doc/user.xml b/doc/user.xml
index dad61f286..a2d7a3d04 100644
--- a/doc/user.xml
+++ b/doc/user.xml
@@ -410,6 +410,14 @@ systemctl start mpd.socket
device "iec958:CARD=Intel,DEV=0"
mixer_control "PCM"
}
+
+
+ The include directive can be used to
+ include settings from another file; the given file name is
+ relative to the current file:
+
+
+ include "other.conf"
diff --git a/src/config/File.cxx b/src/config/File.cxx
index 29c073f3b..7b6838bf2 100644
--- a/src/config/File.cxx
+++ b/src/config/File.cxx
@@ -25,6 +25,7 @@
#include "Templates.hxx"
#include "util/Tokenizer.hxx"
#include "util/StringStrip.hxx"
+#include "util/StringAPI.hxx"
#include "util/Domain.hxx"
#include "util/RuntimeError.hxx"
#include "fs/Path.hxx"
@@ -152,8 +153,11 @@ ReadConfigParam(ConfigData &config_data, BufferedReader &reader,
reader.GetLineNumber()));
}
+/**
+ * @param directory the directory used to resolve relative paths
+ */
static void
-ReadConfigFile(ConfigData &config_data, BufferedReader &reader)
+ReadConfigFile(ConfigData &config_data, BufferedReader &reader, Path directory)
{
while (true) {
char *line = reader.ReadLine();
@@ -171,6 +175,16 @@ ReadConfigFile(ConfigData &config_data, BufferedReader &reader)
const char *name = tokenizer.NextWord();
assert(name != nullptr);
+ if (StringIsEqual(name, "include")) {
+ // TODO: allow absolute path specifications
+ // TODO: detect recusion
+ // TODO: Config{Block,Param} have only line number but no file name
+ // TODO: support wildcards (include "conf.d/*.conf")
+ // TODO: add "include_optional"
+ ReadConfigFile(config_data, directory / AllocatedPath::FromUTF8Throw(ExpectValueAndEnd(tokenizer)));
+ continue;
+ }
+
/* get the definition of that option, and check the
"repeatable" flag */
@@ -202,7 +216,7 @@ ReadConfigFile(ConfigData &config_data, Path path)
BufferedReader reader(file);
try {
- ReadConfigFile(config_data, reader);
+ ReadConfigFile(config_data, reader, path.GetDirectoryName());
} catch (...) {
std::throw_with_nested(FormatRuntimeError("Error in %s line %u",
path_utf8.c_str(),