From 0a3d3f5392630e6e3b16a4bcd5e96fca337db422 Mon Sep 17 00:00:00 2001 From: sippeangelo Date: Wed, 30 Dec 2015 22:54:29 +0100 Subject: [PATCH] Rewrote ConfigFile to use "boost-extras" ini_file parser instead for property_tree, since property_tree is a pain to work with. --- include/Engine/Core/ConfigFile.h | 56 +++++++++------- src/Engine/CMakeLists.txt | 1 + src/Engine/Core/ConfigFile.cpp | 112 +++++++++++++++++++++++++------ src/Engine/Input/InputProxy.cpp | 11 ++- 4 files changed, 133 insertions(+), 47 deletions(-) diff --git a/include/Engine/Core/ConfigFile.h b/include/Engine/Core/ConfigFile.h index 54bbbad4..6aa43930 100644 --- a/include/Engine/Core/ConfigFile.h +++ b/include/Engine/Core/ConfigFile.h @@ -3,10 +3,10 @@ #include #include -#include -#include #include - +#include +#include +#include #include "../Common.h" #include "ResourceManager.h" @@ -20,46 +20,52 @@ private: public: template T Get(std::string key, T defaultValue); - template - std::vector> GetAll(std::string key); template 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(); private: boost::filesystem::path m_Path; - boost::property_tree::ptree m_PTreeDefaults; - boost::property_tree::ptree m_PTreeOverrides; - boost::property_tree::ptree m_PTreeMerged; + ini_file::section_map m_Defaults; + ini_file::section_map m_Overrides; + 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> tokenizeKey(std::string key); }; template T ConfigFile::Get(std::string key, T defaultValue) { - return m_PTreeMerged.get(key, defaultValue); -} + auto param = GetParam(key); + if (param == nullptr) { + return defaultValue; + } -template -std::vector> ConfigFile::GetAll(std::string key) -{ - std::vector> 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(child.second.data()); - out.push_back(std::make_pair(child.first, value)); - } - return out; + return boost::lexical_cast(param->get_value()); } template void ConfigFile::Set(std::string key, T value) { - m_PTreeOverrides.put(key, value); - m_PTreeMerged.put(key, value); + 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; + } + + m_Overrides[section][param] = boost::lexical_cast(value); + m_Merged[section][param] = boost::lexical_cast(value); } #endif diff --git a/src/Engine/CMakeLists.txt b/src/Engine/CMakeLists.txt index 5d74d7d7..61604f90 100644 --- a/src/Engine/CMakeLists.txt +++ b/src/Engine/CMakeLists.txt @@ -94,6 +94,7 @@ set(SOURCE_FILES ${CMAKE_SOURCE_DIR}/deps/include/imgui/imgui.cpp ${CMAKE_SOURCE_DIR}/deps/include/imgui/imgui_draw.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 ) diff --git a/src/Engine/Core/ConfigFile.cpp b/src/Engine/Core/ConfigFile.cpp index 00ab4993..a11b4f2b 100644 --- a/src/Engine/Core/ConfigFile.cpp +++ b/src/Engine/Core/ConfigFile.cpp @@ -7,36 +7,110 @@ ConfigFile::ConfigFile(std::string path) boost::filesystem::path defaultFile; defaultFile = m_Path.parent_path() / ("Default" + m_Path.filename().string()); + std::fstream file; // Read defaults - if (boost::filesystem::exists(defaultFile)) { + file.open(defaultFile.string()); + if (file) { try { - boost::property_tree::ini_parser::read_ini(defaultFile.string(), m_PTreeDefaults); - } catch (boost::property_tree::ptree_error& e) { - LOG_ERROR("Failed to parse \"%s\":\n%s", defaultFile.string().c_str(), e.what()); + file >> m_Defaults; + } 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 { + 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 { 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 - if (boost::filesystem::exists(m_Path)) { - try { - boost::property_tree::ini_parser::read_ini(m_Path.string(), m_PTreeOverrides); - for (auto& topLevelNode : m_PTreeOverrides) { - auto& mergedTopLevelNode = m_PTreeMerged.find(topLevelNode.first); - 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()); - } +const ini_file::section* ConfigFile::GetSection(std::string section) +{ + 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; } + + 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() { - 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> 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); +} \ No newline at end of file diff --git a/src/Engine/Input/InputProxy.cpp b/src/Engine/Input/InputProxy.cpp index c3e4d669..a49f25fb 100644 --- a/src/Engine/Input/InputProxy.cpp +++ b/src/Engine/Input/InputProxy.cpp @@ -17,10 +17,15 @@ InputProxy::~InputProxy() void InputProxy::LoadBindings(std::string file) { auto config = ResourceManager::Load(file); - for (auto& origin : config->GetAll("Bindings")) { + auto section = config->GetSection("Bindings"); + if (section == nullptr) { + return; + } + + for (auto& param : *section) { Events::BindOrigin e; - e.Origin = origin.first; - e.Command = origin.second; + e.Origin = param.first; + e.Command = param.second->get_value(); e.Value = 1.f; if (!e.Command.empty()) { char prefix = e.Command.at(0);