#include "config.hpp" #include "utils.hpp" #include #include namespace common { bool Configuration::parse_bool(const std::string &value) { if (value == "true") return true; if (value == "false") return false; throw Exception("Error: Failed to parse configuration file: Unknown bool (true/false): "+value); } std::string Configuration::parse_string(const std::string &value) { std::string fres; fres.reserve(value.size()); bool escaped = false; for (const char c : value) { if (!escaped) { if (c == '\\') { escaped = true; continue; } else fres.push_back(c); } else { char nc; switch (c) { case 'n': nc = '\n'; break; case 'r': nc = '\r'; break; case 't': nc = '\t'; break; case 'b': nc = '\b'; break; case '\\': nc = '\\'; break; default: throw Exception("Unknown escape sequence: \\"+std::string(1, c)); } fres.push_back(nc); escaped = false; } } return fres; } bool Configuration::file_exists(std::string_view path) { // Make sure we don't respond to some file that is actually called "none"... if (path.empty() || path == "none") return false; return std::filesystem::exists(path); } Configuration::KeyValueMap Configuration::file_parser(const std::string& path) { std::unordered_map fres; // Open file std::ifstream cfgf(path); if (!cfgf) { throw Exception("Failed to open configuration file: "+path); } // Read each entry for (std::string key; cfgf >> key;) { // Read value std::string value; std::getline(cfgf, value); // Ignore comment and empty lines if (key.empty() || key[0] == '#') continue; // Erase all leading spaces in value while (!value.empty() && (value[0] == ' ' || value[0] == '\t')) value.erase(0, 1); // Add to function result fres.emplace(std::move(key), std::move(value)); } // Return final result return fres; } extern "C" char **environ; Configuration::KeyValueMap Configuration::environment_parser() { std::unordered_map fres; for (char **s = environ; *s; s++) { const auto pair = utils::str_split(*s, '=', 1); fres.emplace(pair[0], pair[1]); } return fres; } void Configuration::parse(const std::string &file) { const auto file_location = file.empty()? std::filesystem::current_path(): std::filesystem::path(file).parent_path(); if (!ignore_environment) fill(environment_parser()); if (!file.empty()) fill(file_parser(file), true); } }