Rewrote ConfigFile to use "boost-extras" ini_file parser instead for property_tree, since property_tree is a pain to work with.

This commit is contained in:
2015-12-30 22:54:29 +01:00
parent c0b31dc92c
commit 0a3d3f5392
4 changed files with 133 additions and 47 deletions
+31 -25
View File
@@ -3,10 +3,10 @@
#include <string> #include <string>
#include <boost/filesystem.hpp> #include <boost/filesystem.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/ini_parser.hpp>
#include <boost/lexical_cast.hpp> #include <boost/lexical_cast.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/range/adaptors.hpp>
#include <ini_file/ini_file.hpp>
#include "../Common.h" #include "../Common.h"
#include "ResourceManager.h" #include "ResourceManager.h"
@@ -20,46 +20,52 @@ private:
public: public:
template <typename T> template <typename T>
T Get(std::string key, T defaultValue); T Get(std::string key, T defaultValue);
template <typename T>
std::vector<std::pair<std::string, T>> GetAll(std::string key);
template <typename T> template <typename T>
void Set(std::string key, T value); void Set(std::string key, T value);
const ini_file::section* GetSection(std::string section);
const ini_file::section_map& GetSections() { return m_Merged; }
const ini_file::param* GetParam(std::string key);
void SaveToDisk(); void SaveToDisk();
private: private:
boost::filesystem::path m_Path; boost::filesystem::path m_Path;
boost::property_tree::ptree m_PTreeDefaults; ini_file::section_map m_Defaults;
boost::property_tree::ptree m_PTreeOverrides; ini_file::section_map m_Overrides;
boost::property_tree::ptree m_PTreeMerged; ini_file::section_map m_Merged;
// Merge ini file section map b into a
void mergeINI(ini_file::section_map& a, const ini_file::section_map& b);
// Convert an ini key delimited by periods to a section and a param
boost::optional<std::pair<std::string, std::string>> tokenizeKey(std::string key);
}; };
template <typename T> template <typename T>
T ConfigFile::Get(std::string key, T defaultValue) T ConfigFile::Get(std::string key, T defaultValue)
{ {
return m_PTreeMerged.get<T>(key, defaultValue); auto param = GetParam(key);
} if (param == nullptr) {
return defaultValue;
}
template <typename T> return boost::lexical_cast<T>(param->get_value());
std::vector<std::pair<std::string, T>> ConfigFile::GetAll(std::string key)
{
std::vector<std::pair<std::string, T>> out;
auto parent = m_PTreeMerged.find(key);
if (parent == m_PTreeMerged.not_found()) {
return out;
}
for (auto& child : parent->second) {
T value = boost::lexical_cast<T>(child.second.data());
out.push_back(std::make_pair(child.first, value));
}
return out;
} }
template <typename T> template <typename T>
void ConfigFile::Set(std::string key, T value) void ConfigFile::Set(std::string key, T value)
{ {
m_PTreeOverrides.put<T>(key, value); std::string section;
m_PTreeMerged.put<T>(key, value); std::string param;
if (auto tokens = tokenizeKey(key)) {
std::tie(section, param) = *tokens;
} else {
LOG_WARNING("%s: Malformed config key \"%s\"", m_Path.string().c_str(), key.c_str());
return;
}
m_Overrides[section][param] = boost::lexical_cast<std::string>(value);
m_Merged[section][param] = boost::lexical_cast<std::string>(value);
} }
#endif #endif
+1
View File
@@ -94,6 +94,7 @@ set(SOURCE_FILES
${CMAKE_SOURCE_DIR}/deps/include/imgui/imgui.cpp ${CMAKE_SOURCE_DIR}/deps/include/imgui/imgui.cpp
${CMAKE_SOURCE_DIR}/deps/include/imgui/imgui_draw.cpp ${CMAKE_SOURCE_DIR}/deps/include/imgui/imgui_draw.cpp
${CMAKE_SOURCE_DIR}/deps/include/imgui/imgui_demo.cpp ${CMAKE_SOURCE_DIR}/deps/include/imgui/imgui_demo.cpp
${CMAKE_SOURCE_DIR}/deps/include/ini_file/ini_file.cpp
${CMAKE_SOURCE_DIR}/deps/include/nativefiledialog/nfd_common.c ${CMAKE_SOURCE_DIR}/deps/include/nativefiledialog/nfd_common.c
) )
+93 -19
View File
@@ -7,36 +7,110 @@ ConfigFile::ConfigFile(std::string path)
boost::filesystem::path defaultFile; boost::filesystem::path defaultFile;
defaultFile = m_Path.parent_path() / ("Default" + m_Path.filename().string()); defaultFile = m_Path.parent_path() / ("Default" + m_Path.filename().string());
std::fstream file;
// Read defaults // Read defaults
if (boost::filesystem::exists(defaultFile)) { file.open(defaultFile.string());
if (file) {
try { try {
boost::property_tree::ini_parser::read_ini(defaultFile.string(), m_PTreeDefaults); file >> m_Defaults;
} catch (boost::property_tree::ptree_error& e) { } catch (ini_file::ini_exceptions::ini_file_exception& e) {
LOG_ERROR("Failed to parse \"%s\":\n%s", defaultFile.string().c_str(), e.what()); LOG_ERROR("Failed to parse \"%s\":\n%s", defaultFile.string().c_str(), "ini_file_exception");
}
} else {
LOG_WARNING("Failed to find \"%s\"! Relying on hardcoded default values!", defaultFile.string().c_str());
}
file.close();
// Read overrides
file.open(m_Path.string());
if (file) {
try {
file >> m_Overrides;
} catch (ini_file::ini_exceptions::ini_file_exception& e) {
LOG_ERROR("Failed to parse \"%s\":\n%s", defaultFile.string().c_str(), "ini_file_exception");
} }
} else { } else {
LOG_ERROR("Failed to find \"%s\"! Relying on hardcoded default values!", defaultFile.string().c_str()); LOG_ERROR("Failed to find \"%s\"! Relying on hardcoded default values!", defaultFile.string().c_str());
} }
file.close();
m_PTreeMerged = m_PTreeDefaults; // Merge
mergeINI(m_Merged, m_Defaults);
mergeINI(m_Merged, m_Overrides);
}
// Read overrides const ini_file::section* ConfigFile::GetSection(std::string section)
if (boost::filesystem::exists(m_Path)) { {
try { auto sectionIt = m_Merged.find(section);
boost::property_tree::ini_parser::read_ini(m_Path.string(), m_PTreeOverrides); if (sectionIt == m_Merged.end()) {
for (auto& topLevelNode : m_PTreeOverrides) { LOG_WARNING("%s: Unknown section \"%s\"", m_Path.string().c_str(), section.c_str());
auto& mergedTopLevelNode = m_PTreeMerged.find(topLevelNode.first); return nullptr;
for (auto& childOverrideNode : topLevelNode.second) {
mergedTopLevelNode->second.put_child(childOverrideNode.first, childOverrideNode.second);
}
}
} catch (boost::property_tree::ptree_error& e) {
LOG_ERROR("Failed to parse \"%s\":\n%s", m_Path.filename().string().c_str(), e.what());
}
} }
return sectionIt->second.get();
}
const ini_file::param* ConfigFile::GetParam(std::string key)
{
std::string section;
std::string param;
if (auto tokens = tokenizeKey(key)) {
std::tie(section, param) = *tokens;
} else {
LOG_WARNING("%s: Malformed config key \"%s\"", m_Path.string().c_str(), key.c_str());
return nullptr;
}
auto sectionIt = m_Merged.find(section);
if (sectionIt == m_Merged.end()) {
LOG_WARNING("%s: Unknown section \"%s\"", m_Path.string().c_str(), section.c_str());
return nullptr;
}
auto paramIt = sectionIt->second->find(param);
if (paramIt == sectionIt->second->end()) {
LOG_WARNING("%s: Unknown section param \"%s\"", m_Path.string().c_str(), key.c_str());
return nullptr;
}
return paramIt->second.get();
} }
void ConfigFile::SaveToDisk() void ConfigFile::SaveToDisk()
{ {
boost::property_tree::ini_parser::write_ini(m_Path.string(), m_PTreeOverrides); std::ofstream file(m_Path.string());
file << m_Overrides;
file.close();
}
void ConfigFile::mergeINI(ini_file::section_map& to, const ini_file::section_map& from)
{
for (auto& section : from) {
for (auto& param : *section.second) {
auto& p = to[section.first][param.first];
if (!param.second->get_comment().empty()) {
p.set_comment(param.second->get_comment());
}
p.set_value(param.second->get_value());
}
}
}
boost::optional<std::pair<std::string, std::string>> ConfigFile::tokenizeKey(std::string key)
{
std::size_t delimiter = key.find_last_of('.');
if (delimiter == std::string::npos) {
return boost::none;
}
std::string section = key.substr(0, delimiter);
if (section.empty()) {
return boost::none;
}
std::string param = key.substr(delimiter + 1);
if (param.empty()) {
return boost::none;
}
return std::make_pair(section, param);
} }
+8 -3
View File
@@ -17,10 +17,15 @@ InputProxy::~InputProxy()
void InputProxy::LoadBindings(std::string file) void InputProxy::LoadBindings(std::string file)
{ {
auto config = ResourceManager::Load<ConfigFile>(file); auto config = ResourceManager::Load<ConfigFile>(file);
for (auto& origin : config->GetAll<std::string>("Bindings")) { auto section = config->GetSection("Bindings");
if (section == nullptr) {
return;
}
for (auto& param : *section) {
Events::BindOrigin e; Events::BindOrigin e;
e.Origin = origin.first; e.Origin = param.first;
e.Command = origin.second; e.Command = param.second->get_value();
e.Value = 1.f; e.Value = 1.f;
if (!e.Command.empty()) { if (!e.Command.empty()) {
char prefix = e.Command.at(0); char prefix = e.Command.at(0);