feat(config): Add directive for file inclusion
This commit is contained in:
parent
febe6997b6
commit
874e6b0d6c
@ -74,7 +74,7 @@ class config {
|
|||||||
T get(const string& section, const string& key) const {
|
T get(const string& section, const string& key) const {
|
||||||
auto it = m_sections.find(section);
|
auto it = m_sections.find(section);
|
||||||
if (it == m_sections.end() || it->second.find(key) == it->second.end()) {
|
if (it == m_sections.end() || it->second.find(key) == it->second.end()) {
|
||||||
throw key_error("Missing parameter [" + section + "." + key + "]");
|
throw key_error("Missing parameter \"" + section + "." + key + "\"");
|
||||||
}
|
}
|
||||||
return dereference<T>(section, key, it->second.at(key), convert<T>(string{it->second.at(key)}));
|
return dereference<T>(section, key, it->second.at(key), convert<T>(string{it->second.at(key)}));
|
||||||
}
|
}
|
||||||
@ -125,7 +125,7 @@ class config {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (results.empty()) {
|
if (results.empty()) {
|
||||||
throw key_error("Missing parameter [" + section + "." + key + "-0]");
|
throw key_error("Missing parameter \"" + section + "." + key + "-0\"");
|
||||||
}
|
}
|
||||||
|
|
||||||
return results;
|
return results;
|
||||||
@ -220,7 +220,7 @@ class config {
|
|||||||
} else if ((pos = path.find(".")) != string::npos) {
|
} else if ((pos = path.find(".")) != string::npos) {
|
||||||
return dereference_local<T>(path.substr(0, pos), path.substr(pos + 1), section);
|
return dereference_local<T>(path.substr(0, pos), path.substr(pos + 1), section);
|
||||||
} else {
|
} else {
|
||||||
throw value_error("Invalid reference defined at [" + section + "." + key + "]");
|
throw value_error("Invalid reference defined at \"" + section + "." + key + "\"");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -251,7 +251,8 @@ class config {
|
|||||||
size_t pos;
|
size_t pos;
|
||||||
if ((pos = key.find(':')) != string::npos) {
|
if ((pos = key.find(':')) != string::npos) {
|
||||||
string fallback = key.substr(pos + 1);
|
string fallback = key.substr(pos + 1);
|
||||||
m_log.info("The reference ${%s.%s} does not exist, using defined fallback value \"%s\"", section, key.substr(0, pos), fallback);
|
m_log.info("The reference ${%s.%s} does not exist, using defined fallback value \"%s\"", section,
|
||||||
|
key.substr(0, pos), fallback);
|
||||||
return convert<T>(move(fallback));
|
return convert<T>(move(fallback));
|
||||||
}
|
}
|
||||||
throw value_error("The reference ${" + section + "." + key + "} does not exist (no fallback set)");
|
throw value_error("The reference ${" + section + "." + key + "} does not exist (no fallback set)");
|
||||||
|
@ -77,9 +77,9 @@ namespace string_util {
|
|||||||
string strip(const string& haystack, char needle);
|
string strip(const string& haystack, char needle);
|
||||||
string strip_trailing_newline(const string& haystack);
|
string strip_trailing_newline(const string& haystack);
|
||||||
|
|
||||||
string ltrim(string&& value, const char& needle);
|
string ltrim(string&& value, const char& needle = ' ');
|
||||||
string rtrim(string&& value, const char& needle);
|
string rtrim(string&& value, const char& needle = ' ');
|
||||||
string trim(string&& value, const char& needle);
|
string trim(string&& value, const char& needle = ' ');
|
||||||
|
|
||||||
string join(const vector<string>& strs, const string& delim);
|
string join(const vector<string>& strs, const string& delim);
|
||||||
vector<string>& split_into(const string& s, char delim, vector<string>& container);
|
vector<string>& split_into(const string& s, char delim, vector<string>& container);
|
||||||
|
@ -77,21 +77,58 @@ void config::warn_deprecated(const string& section, const string& key, string re
|
|||||||
* Parse key/value pairs from the configuration file
|
* Parse key/value pairs from the configuration file
|
||||||
*/
|
*/
|
||||||
void config::parse_file() {
|
void config::parse_file() {
|
||||||
std::ifstream in(m_file);
|
vector<pair<int, string>> lines;
|
||||||
string line;
|
vector<string> files{m_file};
|
||||||
string section;
|
|
||||||
unsigned int lineno{0};
|
|
||||||
|
|
||||||
while (std::getline(in, line)) {
|
|
||||||
lineno++;
|
|
||||||
|
|
||||||
line = string_util::replace_all(line, "\t", "");
|
|
||||||
|
|
||||||
|
std::function<void(int, string&&)> pushline = [&](int lineno, string&& line) {
|
||||||
// Ignore empty lines and comments
|
// Ignore empty lines and comments
|
||||||
if (line.empty() || line[0] == ';' || line[0] == '#') {
|
if (line.empty() || line[0] == ';' || line[0] == '#') {
|
||||||
continue;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string key, value;
|
||||||
|
string::size_type pos;
|
||||||
|
|
||||||
|
// Filter lines by:
|
||||||
|
// - key/value pairs
|
||||||
|
// - section headers
|
||||||
|
if ((pos = line.find('=')) != string::npos) {
|
||||||
|
key = forward<string>(string_util::trim(forward<string>(line.substr(0, pos))));
|
||||||
|
value = forward<string>(string_util::trim(line.substr(pos + 1)));
|
||||||
|
} else if (line[0] != '[' || line[line.length() - 1] != ']') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key == "include-file") {
|
||||||
|
if (value.empty() || !file_util::exists(value)) {
|
||||||
|
throw value_error("Invalid include file \"" + value + "\" defined on line " + to_string(lineno));
|
||||||
|
}
|
||||||
|
if (std::find(files.begin(), files.end(), value) != files.end()) {
|
||||||
|
throw value_error("Recursive include file \"" + value + "\"");
|
||||||
|
}
|
||||||
|
files.push_back(value);
|
||||||
|
m_log.trace("config: Including file \"%s\"", value);
|
||||||
|
for (auto&& l : string_util::split(file_util::contents(value), '\n')) {
|
||||||
|
pushline(lineno, forward<string>(l));
|
||||||
|
}
|
||||||
|
files.pop_back();
|
||||||
|
} else {
|
||||||
|
lines.emplace_back(make_pair(lineno, line));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
int lineno{0};
|
||||||
|
string line;
|
||||||
|
std::ifstream in(m_file);
|
||||||
|
while (std::getline(in, line)) {
|
||||||
|
pushline(++lineno, string_util::replace_all(line, "\t", ""));
|
||||||
|
}
|
||||||
|
|
||||||
|
string section;
|
||||||
|
for (auto&& l : lines) {
|
||||||
|
auto& lineno = l.first;
|
||||||
|
auto& line = l.second;
|
||||||
|
|
||||||
// New section
|
// New section
|
||||||
if (line[0] == '[' && line[line.length() - 1] == ']') {
|
if (line[0] == '[' && line[line.length() - 1] == ']') {
|
||||||
section = line.substr(1, line.length() - 2);
|
section = line.substr(1, line.length() - 2);
|
||||||
@ -107,7 +144,7 @@ void config::parse_file() {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
string key{forward<string>(string_util::trim(forward<string>(line.substr(0, equal_pos)), ' '))};
|
string key{forward<string>(string_util::trim(forward<string>(line.substr(0, equal_pos))))};
|
||||||
string value;
|
string value;
|
||||||
|
|
||||||
auto it = m_sections[section].find(key);
|
auto it = m_sections[section].find(key);
|
||||||
@ -116,7 +153,7 @@ void config::parse_file() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (equal_pos + 1 < line.size()) {
|
if (equal_pos + 1 < line.size()) {
|
||||||
value = forward<string>(string_util::trim(line.substr(equal_pos + 1), ' '));
|
value = forward<string>(string_util::trim(line.substr(equal_pos + 1)));
|
||||||
size_t len{value.size()};
|
size_t len{value.size()};
|
||||||
if (len > 2 && value[0] == '"' && value[len - 1] == '"') {
|
if (len > 2 && value[0] == '"' && value[len - 1] == '"') {
|
||||||
value.erase(len - 1, 1).erase(0, 1);
|
value.erase(len - 1, 1).erase(0, 1);
|
||||||
@ -149,13 +186,14 @@ void config::copy_inherited() {
|
|||||||
// Get name of base section
|
// Get name of base section
|
||||||
auto inherit = param.second;
|
auto inherit = param.second;
|
||||||
if ((inherit = dereference<string>(section.first, param.first, inherit, inherit)).empty()) {
|
if ((inherit = dereference<string>(section.first, param.first, inherit, inherit)).empty()) {
|
||||||
throw value_error("[" + section.first + "." + KEY_INHERIT + "] requires a value");
|
throw value_error("Invalid section \"\" defined for \"" + section.first + "." + KEY_INHERIT + "\"");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find and validate base section
|
// Find and validate base section
|
||||||
auto base_section = m_sections.find(inherit);
|
auto base_section = m_sections.find(inherit);
|
||||||
if (base_section == m_sections.end()) {
|
if (base_section == m_sections.end()) {
|
||||||
throw value_error("[" + section.first + "." + KEY_INHERIT + "] invalid reference \"" + inherit + "\"");
|
throw value_error(
|
||||||
|
"Invalid section \"" + inherit + "\" defined for \"" + section.first + "." + KEY_INHERIT + "\"");
|
||||||
}
|
}
|
||||||
|
|
||||||
m_log.trace("config: Copying missing params (sub=\"%s\", base=\"%s\")", section.first, inherit);
|
m_log.trace("config: Copying missing params (sub=\"%s\", base=\"%s\")", section.first, inherit);
|
||||||
|
@ -190,7 +190,11 @@ namespace file_util {
|
|||||||
string contents(const string& filename) {
|
string contents(const string& filename) {
|
||||||
try {
|
try {
|
||||||
string contents;
|
string contents;
|
||||||
std::getline(std::ifstream(filename, std::ifstream::in), contents);
|
string line;
|
||||||
|
std::ifstream in(filename, std::ifstream::in);
|
||||||
|
while (std::getline(in, line)) {
|
||||||
|
contents += line + '\n';
|
||||||
|
}
|
||||||
return contents;
|
return contents;
|
||||||
} catch (const std::ifstream::failure& e) {
|
} catch (const std::ifstream::failure& e) {
|
||||||
return "";
|
return "";
|
||||||
|
@ -43,6 +43,7 @@ int main() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
"trim"_test = [] {
|
"trim"_test = [] {
|
||||||
|
expect(string_util::trim(" x x ") == "x x");
|
||||||
expect(string_util::ltrim("xxtestxx", 'x') == "testxx");
|
expect(string_util::ltrim("xxtestxx", 'x') == "testxx");
|
||||||
expect(string_util::rtrim("xxtestxx", 'x') == "xxtest");
|
expect(string_util::rtrim("xxtestxx", 'x') == "xxtest");
|
||||||
expect(string_util::trim("xxtestxx", 'x') == "test");
|
expect(string_util::trim("xxtestxx", 'x') == "test");
|
||||||
|
Loading…
Reference in New Issue
Block a user