mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-02-15 08:51:26 +02:00
Fix things mentioned during code review
Ref: https://github.com/dolphin-emu/dolphin/pull/4917
This commit is contained in:
parent
abe6f8766a
commit
88a21dd2b9
@ -1,6 +1,9 @@
|
|||||||
set(SRCS Analytics.cpp
|
set(SRCS Analytics.cpp
|
||||||
CDUtils.cpp
|
CDUtils.cpp
|
||||||
ColorUtil.cpp
|
ColorUtil.cpp
|
||||||
|
Config/Config.cpp
|
||||||
|
Config/Layer.cpp
|
||||||
|
Config/Section.cpp
|
||||||
ENetUtil.cpp
|
ENetUtil.cpp
|
||||||
FileSearch.cpp
|
FileSearch.cpp
|
||||||
FileUtil.cpp
|
FileUtil.cpp
|
||||||
@ -15,7 +18,6 @@ set(SRCS Analytics.cpp
|
|||||||
MsgHandler.cpp
|
MsgHandler.cpp
|
||||||
NandPaths.cpp
|
NandPaths.cpp
|
||||||
Network.cpp
|
Network.cpp
|
||||||
Config.cpp
|
|
||||||
PcapFile.cpp
|
PcapFile.cpp
|
||||||
PerformanceCounter.cpp
|
PerformanceCounter.cpp
|
||||||
Profiler.cpp
|
Profiler.cpp
|
||||||
|
@ -53,6 +53,10 @@
|
|||||||
<ClInclude Include="CommonFuncs.h" />
|
<ClInclude Include="CommonFuncs.h" />
|
||||||
<ClInclude Include="CommonPaths.h" />
|
<ClInclude Include="CommonPaths.h" />
|
||||||
<ClInclude Include="CommonTypes.h" />
|
<ClInclude Include="CommonTypes.h" />
|
||||||
|
<ClInclude Include="Config\Config.h" />
|
||||||
|
<ClInclude Include="Config\Enums.h" />
|
||||||
|
<ClInclude Include="Config\Layer.h" />
|
||||||
|
<ClInclude Include="Config\Section.h" />
|
||||||
<ClInclude Include="CPUDetect.h" />
|
<ClInclude Include="CPUDetect.h" />
|
||||||
<ClInclude Include="DebugInterface.h" />
|
<ClInclude Include="DebugInterface.h" />
|
||||||
<ClInclude Include="ENetUtil.h" />
|
<ClInclude Include="ENetUtil.h" />
|
||||||
@ -123,7 +127,6 @@
|
|||||||
<ClInclude Include="NandPaths.h" />
|
<ClInclude Include="NandPaths.h" />
|
||||||
<ClInclude Include="Network.h" />
|
<ClInclude Include="Network.h" />
|
||||||
<ClInclude Include="NonCopyable.h" />
|
<ClInclude Include="NonCopyable.h" />
|
||||||
<ClInclude Include="Config.h" />
|
|
||||||
<ClInclude Include="PcapFile.h" />
|
<ClInclude Include="PcapFile.h" />
|
||||||
<ClInclude Include="Profiler.h" />
|
<ClInclude Include="Profiler.h" />
|
||||||
<ClInclude Include="ScopeGuard.h" />
|
<ClInclude Include="ScopeGuard.h" />
|
||||||
@ -150,6 +153,9 @@
|
|||||||
<ClCompile Include="Analytics.cpp" />
|
<ClCompile Include="Analytics.cpp" />
|
||||||
<ClCompile Include="CDUtils.cpp" />
|
<ClCompile Include="CDUtils.cpp" />
|
||||||
<ClCompile Include="ColorUtil.cpp" />
|
<ClCompile Include="ColorUtil.cpp" />
|
||||||
|
<ClCompile Include="Config\Config.cpp" />
|
||||||
|
<ClCompile Include="Config\Layer.cpp" />
|
||||||
|
<ClCompile Include="Config\Section.cpp" />
|
||||||
<ClCompile Include="ENetUtil.cpp" />
|
<ClCompile Include="ENetUtil.cpp" />
|
||||||
<ClCompile Include="FileSearch.cpp" />
|
<ClCompile Include="FileSearch.cpp" />
|
||||||
<ClCompile Include="FileUtil.cpp" />
|
<ClCompile Include="FileUtil.cpp" />
|
||||||
@ -173,7 +179,6 @@
|
|||||||
<ClCompile Include="MsgHandler.cpp" />
|
<ClCompile Include="MsgHandler.cpp" />
|
||||||
<ClCompile Include="NandPaths.cpp" />
|
<ClCompile Include="NandPaths.cpp" />
|
||||||
<ClCompile Include="Network.cpp" />
|
<ClCompile Include="Network.cpp" />
|
||||||
<ClCompile Include="Config.cpp" />
|
|
||||||
<ClCompile Include="PcapFile.cpp" />
|
<ClCompile Include="PcapFile.cpp" />
|
||||||
<ClCompile Include="Profiler.cpp" />
|
<ClCompile Include="Profiler.cpp" />
|
||||||
<ClCompile Include="SDCardUtil.cpp" />
|
<ClCompile Include="SDCardUtil.cpp" />
|
||||||
|
@ -34,6 +34,10 @@
|
|||||||
<ClInclude Include="CommonFuncs.h" />
|
<ClInclude Include="CommonFuncs.h" />
|
||||||
<ClInclude Include="CommonPaths.h" />
|
<ClInclude Include="CommonPaths.h" />
|
||||||
<ClInclude Include="CommonTypes.h" />
|
<ClInclude Include="CommonTypes.h" />
|
||||||
|
<ClInclude Include="Config\Config.h" />
|
||||||
|
<ClInclude Include="Config\Enums.h" />
|
||||||
|
<ClInclude Include="Config\Layer.h" />
|
||||||
|
<ClInclude Include="Config\Section.h" />
|
||||||
<ClInclude Include="CPUDetect.h" />
|
<ClInclude Include="CPUDetect.h" />
|
||||||
<ClInclude Include="DebugInterface.h" />
|
<ClInclude Include="DebugInterface.h" />
|
||||||
<ClInclude Include="ENetUtil.h" />
|
<ClInclude Include="ENetUtil.h" />
|
||||||
@ -53,7 +57,6 @@
|
|||||||
<ClInclude Include="MsgHandler.h" />
|
<ClInclude Include="MsgHandler.h" />
|
||||||
<ClInclude Include="NandPaths.h" />
|
<ClInclude Include="NandPaths.h" />
|
||||||
<ClInclude Include="Network.h" />
|
<ClInclude Include="Network.h" />
|
||||||
<ClInclude Include="Config.h" />
|
|
||||||
<ClInclude Include="PcapFile.h" />
|
<ClInclude Include="PcapFile.h" />
|
||||||
<ClInclude Include="Profiler.h" />
|
<ClInclude Include="Profiler.h" />
|
||||||
<ClInclude Include="ScopeGuard.h" />
|
<ClInclude Include="ScopeGuard.h" />
|
||||||
@ -233,6 +236,9 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="CDUtils.cpp" />
|
<ClCompile Include="CDUtils.cpp" />
|
||||||
<ClCompile Include="ColorUtil.cpp" />
|
<ClCompile Include="ColorUtil.cpp" />
|
||||||
|
<ClCompile Include="Config\Config.cpp" />
|
||||||
|
<ClCompile Include="Config\Layer.cpp" />
|
||||||
|
<ClCompile Include="Config\Section.cpp" />
|
||||||
<ClCompile Include="ENetUtil.cpp" />
|
<ClCompile Include="ENetUtil.cpp" />
|
||||||
<ClCompile Include="FileSearch.cpp" />
|
<ClCompile Include="FileSearch.cpp" />
|
||||||
<ClCompile Include="FileUtil.cpp" />
|
<ClCompile Include="FileUtil.cpp" />
|
||||||
@ -246,7 +252,6 @@
|
|||||||
<ClCompile Include="MsgHandler.cpp" />
|
<ClCompile Include="MsgHandler.cpp" />
|
||||||
<ClCompile Include="NandPaths.cpp" />
|
<ClCompile Include="NandPaths.cpp" />
|
||||||
<ClCompile Include="Network.cpp" />
|
<ClCompile Include="Network.cpp" />
|
||||||
<ClCompile Include="Config.cpp" />
|
|
||||||
<ClCompile Include="PcapFile.cpp" />
|
<ClCompile Include="PcapFile.cpp" />
|
||||||
<ClCompile Include="Profiler.cpp" />
|
<ClCompile Include="Profiler.cpp" />
|
||||||
<ClCompile Include="SDCardUtil.cpp" />
|
<ClCompile Include="SDCardUtil.cpp" />
|
||||||
|
@ -1,496 +0,0 @@
|
|||||||
// Copyright 2016 Dolphin Emulator Project
|
|
||||||
// Licensed under GPLv2+
|
|
||||||
// Refer to the license.txt file included.
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <array>
|
|
||||||
#include <map>
|
|
||||||
|
|
||||||
#include "Common/Assert.h"
|
|
||||||
#include "Common/Config.h"
|
|
||||||
#include "Common/StringUtil.h"
|
|
||||||
|
|
||||||
namespace Config
|
|
||||||
{
|
|
||||||
const std::string& Section::NULL_STRING = "";
|
|
||||||
static Layers s_layers;
|
|
||||||
static std::list<ConfigChangedCallback> s_callbacks;
|
|
||||||
|
|
||||||
void CallbackSystems();
|
|
||||||
|
|
||||||
// Only to be used with the meta-layer
|
|
||||||
class RecursiveSection final : public Section
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
RecursiveSection(LayerType layer, System system, const std::string& name)
|
|
||||||
: Section(layer, system, name)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Exists(const std::string& key) const override;
|
|
||||||
|
|
||||||
bool Get(const std::string& key, std::string* value,
|
|
||||||
const std::string& default_value = NULL_STRING) const override;
|
|
||||||
|
|
||||||
void Set(const std::string& key, const std::string& value) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
bool RecursiveSection::Exists(const std::string& key) const
|
|
||||||
{
|
|
||||||
auto layers_it = s_layers.find(LayerType::Meta);
|
|
||||||
do
|
|
||||||
{
|
|
||||||
Section* layer_section = layers_it->second->GetSection(m_system, m_name);
|
|
||||||
if (layer_section && layer_section->Exists(key))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} while (--layers_it != s_layers.end());
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool RecursiveSection::Get(const std::string& key, std::string* value,
|
|
||||||
const std::string& default_value) const
|
|
||||||
{
|
|
||||||
static const std::array<LayerType, 7> search_order = {{
|
|
||||||
// Skip the meta layer
|
|
||||||
LayerType::CurrentRun, LayerType::CommandLine, LayerType::Movie, LayerType::Netplay,
|
|
||||||
LayerType::LocalGame, LayerType::GlobalGame, LayerType::Base,
|
|
||||||
}};
|
|
||||||
|
|
||||||
for (auto layer_id : search_order)
|
|
||||||
{
|
|
||||||
auto layers_it = s_layers.find(layer_id);
|
|
||||||
if (layers_it == s_layers.end())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
Section* layer_section = layers_it->second->GetSection(m_system, m_name);
|
|
||||||
if (layer_section && layer_section->Exists(key))
|
|
||||||
{
|
|
||||||
return layer_section->Get(key, value, default_value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Section::Get(key, value, default_value);
|
|
||||||
}
|
|
||||||
|
|
||||||
void RecursiveSection::Set(const std::string& key, const std::string& value)
|
|
||||||
{
|
|
||||||
// The RecursiveSection can't set since it is used to recursively get values from the layer
|
|
||||||
// map.
|
|
||||||
// It is only a part of the meta layer, and the meta layer isn't allowed to set any values.
|
|
||||||
_assert_msg_(COMMON, false, "Don't try to set values here!");
|
|
||||||
}
|
|
||||||
|
|
||||||
class RecursiveLayer final : public Layer
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
RecursiveLayer() : Layer(LayerType::Meta) {}
|
|
||||||
Section* GetSection(System system, const std::string& section_name) override;
|
|
||||||
Section* GetOrCreateSection(System system, const std::string& section_name) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
Section* RecursiveLayer::GetSection(System system, const std::string& section_name)
|
|
||||||
{
|
|
||||||
// Always queries backwards recursively, so it doesn't matter if it exists or not on this layer
|
|
||||||
return GetOrCreateSection(system, section_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
Section* RecursiveLayer::GetOrCreateSection(System system, const std::string& section_name)
|
|
||||||
{
|
|
||||||
Section* section = Layer::GetSection(system, section_name);
|
|
||||||
if (!section)
|
|
||||||
{
|
|
||||||
m_sections[system].emplace_back(new RecursiveSection(m_layer, system, section_name));
|
|
||||||
section = m_sections[system].back();
|
|
||||||
}
|
|
||||||
return section;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Section::Exists(const std::string& key) const
|
|
||||||
{
|
|
||||||
return m_values.find(key) != m_values.end();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Section::Delete(const std::string& key)
|
|
||||||
{
|
|
||||||
auto it = m_values.find(key);
|
|
||||||
if (it == m_values.end())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
m_values.erase(it);
|
|
||||||
|
|
||||||
m_deleted_keys.push_back(key);
|
|
||||||
m_dirty = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Section::Set(const std::string& key, const std::string& value)
|
|
||||||
{
|
|
||||||
auto it = m_values.find(key);
|
|
||||||
if (it != m_values.end() && it->second != value)
|
|
||||||
{
|
|
||||||
it->second = value;
|
|
||||||
m_dirty = true;
|
|
||||||
}
|
|
||||||
else if (it == m_values.end())
|
|
||||||
{
|
|
||||||
m_values[key] = value;
|
|
||||||
m_dirty = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Section::Set(const std::string& key, u32 newValue)
|
|
||||||
{
|
|
||||||
Section::Set(key, StringFromFormat("0x%08x", newValue));
|
|
||||||
}
|
|
||||||
|
|
||||||
void Section::Set(const std::string& key, float newValue)
|
|
||||||
{
|
|
||||||
Section::Set(key, StringFromFormat("%#.9g", newValue));
|
|
||||||
}
|
|
||||||
|
|
||||||
void Section::Set(const std::string& key, double newValue)
|
|
||||||
{
|
|
||||||
Section::Set(key, StringFromFormat("%#.17g", newValue));
|
|
||||||
}
|
|
||||||
|
|
||||||
void Section::Set(const std::string& key, int newValue)
|
|
||||||
{
|
|
||||||
Section::Set(key, StringFromInt(newValue));
|
|
||||||
}
|
|
||||||
|
|
||||||
void Section::Set(const std::string& key, bool newValue)
|
|
||||||
{
|
|
||||||
Section::Set(key, StringFromBool(newValue));
|
|
||||||
}
|
|
||||||
|
|
||||||
void Section::Set(const std::string& key, const std::string& newValue,
|
|
||||||
const std::string& defaultValue)
|
|
||||||
{
|
|
||||||
if (newValue != defaultValue)
|
|
||||||
Set(key, newValue);
|
|
||||||
else
|
|
||||||
Delete(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Section::SetLines(const std::vector<std::string>& lines)
|
|
||||||
{
|
|
||||||
m_lines = lines;
|
|
||||||
m_dirty = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Section::Get(const std::string& key, std::string* value,
|
|
||||||
const std::string& default_value) const
|
|
||||||
{
|
|
||||||
const auto& it = m_values.find(key);
|
|
||||||
if (it != m_values.end())
|
|
||||||
{
|
|
||||||
*value = it->second;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else if (&default_value != &NULL_STRING)
|
|
||||||
{
|
|
||||||
*value = default_value;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Section::Get(const std::string& key, int* value, int defaultValue) const
|
|
||||||
{
|
|
||||||
std::string temp;
|
|
||||||
bool retval = Get(key, &temp);
|
|
||||||
|
|
||||||
if (retval && TryParse(temp, value))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
*value = defaultValue;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Section::Get(const std::string& key, u32* value, u32 defaultValue) const
|
|
||||||
{
|
|
||||||
std::string temp;
|
|
||||||
bool retval = Get(key, &temp);
|
|
||||||
|
|
||||||
if (retval && TryParse(temp, value))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
*value = defaultValue;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Section::Get(const std::string& key, bool* value, bool defaultValue) const
|
|
||||||
{
|
|
||||||
std::string temp;
|
|
||||||
bool retval = Get(key, &temp);
|
|
||||||
|
|
||||||
if (retval && TryParse(temp, value))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
*value = defaultValue;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Section::Get(const std::string& key, float* value, float defaultValue) const
|
|
||||||
{
|
|
||||||
std::string temp;
|
|
||||||
bool retval = Get(key, &temp);
|
|
||||||
|
|
||||||
if (retval && TryParse(temp, value))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
*value = defaultValue;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Section::Get(const std::string& key, double* value, double defaultValue) const
|
|
||||||
{
|
|
||||||
std::string temp;
|
|
||||||
bool retval = Get(key, &temp);
|
|
||||||
|
|
||||||
if (retval && TryParse(temp, value))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
*value = defaultValue;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return a list of all lines in a section
|
|
||||||
bool Section::GetLines(std::vector<std::string>* lines, const bool remove_comments) const
|
|
||||||
{
|
|
||||||
lines->clear();
|
|
||||||
|
|
||||||
for (std::string line : m_lines)
|
|
||||||
{
|
|
||||||
line = StripSpaces(line);
|
|
||||||
|
|
||||||
if (remove_comments)
|
|
||||||
{
|
|
||||||
size_t commentPos = line.find('#');
|
|
||||||
if (commentPos == 0)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (commentPos != std::string::npos)
|
|
||||||
{
|
|
||||||
line = StripSpaces(line.substr(0, commentPos));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
lines->push_back(line);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Onion layers
|
|
||||||
Layer::Layer(std::unique_ptr<ConfigLayerLoader> loader)
|
|
||||||
: m_layer(loader->GetLayer()), m_loader(std::move(loader))
|
|
||||||
{
|
|
||||||
Load();
|
|
||||||
}
|
|
||||||
|
|
||||||
Layer::~Layer()
|
|
||||||
{
|
|
||||||
Save();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Layer::Exists(System system, const std::string& section_name, const std::string& key)
|
|
||||||
{
|
|
||||||
Section* section = GetSection(system, section_name);
|
|
||||||
if (!section)
|
|
||||||
return false;
|
|
||||||
return section->Exists(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Layer::DeleteKey(System system, const std::string& section_name, const std::string& key)
|
|
||||||
{
|
|
||||||
Section* section = GetSection(system, section_name);
|
|
||||||
if (!section)
|
|
||||||
return false;
|
|
||||||
return section->Delete(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
Section* Layer::GetSection(System system, const std::string& section_name)
|
|
||||||
{
|
|
||||||
for (Section* section : m_sections[system])
|
|
||||||
if (!strcasecmp(section->m_name.c_str(), section_name.c_str()))
|
|
||||||
return section;
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
Section* Layer::GetOrCreateSection(System system, const std::string& section_name)
|
|
||||||
{
|
|
||||||
Section* section = GetSection(system, section_name);
|
|
||||||
if (!section)
|
|
||||||
{
|
|
||||||
if (m_layer == LayerType::Meta)
|
|
||||||
m_sections[system].emplace_back(new RecursiveSection(m_layer, system, section_name));
|
|
||||||
else
|
|
||||||
m_sections[system].emplace_back(new Section(m_layer, system, section_name));
|
|
||||||
section = m_sections[system].back();
|
|
||||||
}
|
|
||||||
return section;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Layer::Load()
|
|
||||||
{
|
|
||||||
if (m_loader)
|
|
||||||
m_loader->Load(this);
|
|
||||||
ClearDirty();
|
|
||||||
CallbackSystems();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Layer::Save()
|
|
||||||
{
|
|
||||||
if (!m_loader || !IsDirty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
m_loader->Save(this);
|
|
||||||
ClearDirty();
|
|
||||||
CallbackSystems();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Layer::IsDirty() const
|
|
||||||
{
|
|
||||||
return std::any_of(m_sections.begin(), m_sections.end(), [](const auto& system) {
|
|
||||||
return std::any_of(system.second.begin(), system.second.end(),
|
|
||||||
[](const auto& section) { return section->IsDirty(); });
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void Layer::ClearDirty()
|
|
||||||
{
|
|
||||||
std::for_each(m_sections.begin(), m_sections.end(), [](const auto& system) {
|
|
||||||
std::for_each(system.second.begin(), system.second.end(),
|
|
||||||
[](const auto& section) { section->ClearDirty(); });
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
Section* GetOrCreateSection(System system, const std::string& section_name)
|
|
||||||
{
|
|
||||||
return s_layers[LayerType::Meta]->GetOrCreateSection(system, section_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
Layers* GetLayers()
|
|
||||||
{
|
|
||||||
return &s_layers;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AddLayer(std::unique_ptr<Layer> layer)
|
|
||||||
{
|
|
||||||
s_layers[layer->GetLayer()] = std::move(layer);
|
|
||||||
CallbackSystems();
|
|
||||||
}
|
|
||||||
|
|
||||||
void AddLayer(std::unique_ptr<ConfigLayerLoader> loader)
|
|
||||||
{
|
|
||||||
AddLayer(std::make_unique<Layer>(std::move(loader)));
|
|
||||||
}
|
|
||||||
|
|
||||||
void AddLoadLayer(std::unique_ptr<Layer> layer)
|
|
||||||
{
|
|
||||||
layer->Load();
|
|
||||||
AddLayer(std::move(layer));
|
|
||||||
}
|
|
||||||
|
|
||||||
void AddLoadLayer(std::unique_ptr<ConfigLayerLoader> loader)
|
|
||||||
{
|
|
||||||
AddLoadLayer(std::make_unique<Layer>(std::move(loader)));
|
|
||||||
}
|
|
||||||
|
|
||||||
Layer* GetLayer(LayerType layer)
|
|
||||||
{
|
|
||||||
if (!LayerExists(layer))
|
|
||||||
return nullptr;
|
|
||||||
return s_layers[layer].get();
|
|
||||||
}
|
|
||||||
|
|
||||||
void RemoveLayer(LayerType layer)
|
|
||||||
{
|
|
||||||
s_layers.erase(layer);
|
|
||||||
CallbackSystems();
|
|
||||||
}
|
|
||||||
bool LayerExists(LayerType layer)
|
|
||||||
{
|
|
||||||
return s_layers.find(layer) != s_layers.end();
|
|
||||||
}
|
|
||||||
|
|
||||||
void AddConfigChangedCallback(ConfigChangedCallback func)
|
|
||||||
{
|
|
||||||
s_callbacks.emplace_back(func);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CallbackSystems()
|
|
||||||
{
|
|
||||||
for (const auto& callback : s_callbacks)
|
|
||||||
callback();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Explicit load and save of layers
|
|
||||||
void Load()
|
|
||||||
{
|
|
||||||
for (auto& layer : s_layers)
|
|
||||||
layer.second->Load();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Save()
|
|
||||||
{
|
|
||||||
for (auto& layer : s_layers)
|
|
||||||
layer.second->Save();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Init()
|
|
||||||
{
|
|
||||||
// This layer always has to exist
|
|
||||||
s_layers[LayerType::Meta] = std::make_unique<RecursiveLayer>();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Shutdown()
|
|
||||||
{
|
|
||||||
s_layers.clear();
|
|
||||||
s_callbacks.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
static std::map<System, std::string> system_to_name = {
|
|
||||||
{System::Main, "Dolphin"}, {System::GCPad, "GCPad"}, {System::WiiPad, "Wiimote"},
|
|
||||||
{System::GCKeyboard, "GCKeyboard"}, {System::GFX, "Graphics"}, {System::Logger, "Logger"},
|
|
||||||
{System::Debugger, "Debugger"}, {System::UI, "UI"},
|
|
||||||
};
|
|
||||||
|
|
||||||
const std::string& GetSystemName(System system)
|
|
||||||
{
|
|
||||||
return system_to_name[system];
|
|
||||||
}
|
|
||||||
|
|
||||||
System GetSystemFromName(const std::string& system)
|
|
||||||
{
|
|
||||||
for (auto& val : system_to_name)
|
|
||||||
if (val.second == system)
|
|
||||||
return val.first;
|
|
||||||
|
|
||||||
_assert_msg_(COMMON, false, "Programming error! Couldn't convert '%s' to system!",
|
|
||||||
system.c_str());
|
|
||||||
return System::Main;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::string& GetLayerName(LayerType layer)
|
|
||||||
{
|
|
||||||
static std::map<LayerType, std::string> layer_to_name = {
|
|
||||||
{LayerType::Base, "Base"},
|
|
||||||
{LayerType::GlobalGame, "Global GameINI"},
|
|
||||||
{LayerType::LocalGame, "Local GameINI"},
|
|
||||||
{LayerType::Netplay, "Netplay"},
|
|
||||||
{LayerType::Movie, "Movie"},
|
|
||||||
{LayerType::CommandLine, "Command Line"},
|
|
||||||
{LayerType::CurrentRun, "Current Run"},
|
|
||||||
{LayerType::Meta, "Top"},
|
|
||||||
};
|
|
||||||
return layer_to_name[layer];
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,220 +0,0 @@
|
|||||||
// Copyright 2016 Dolphin Emulator Project
|
|
||||||
// Licensed under GPLv2+
|
|
||||||
// Refer to the license.txt file included.
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <list>
|
|
||||||
#include <map>
|
|
||||||
#include <memory>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
// XXX: Purely for case insensitive compare
|
|
||||||
#include "Common/IniFile.h"
|
|
||||||
|
|
||||||
namespace Config
|
|
||||||
{
|
|
||||||
enum class LayerType
|
|
||||||
{
|
|
||||||
Base,
|
|
||||||
GlobalGame,
|
|
||||||
LocalGame,
|
|
||||||
Movie,
|
|
||||||
Netplay,
|
|
||||||
CommandLine,
|
|
||||||
CurrentRun,
|
|
||||||
Meta,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class System
|
|
||||||
{
|
|
||||||
Main,
|
|
||||||
GCPad,
|
|
||||||
WiiPad,
|
|
||||||
GCKeyboard,
|
|
||||||
GFX,
|
|
||||||
Logger,
|
|
||||||
Debugger,
|
|
||||||
UI,
|
|
||||||
};
|
|
||||||
|
|
||||||
class Section;
|
|
||||||
class Layer;
|
|
||||||
class ConfigLayerLoader;
|
|
||||||
|
|
||||||
using SectionValueMap = std::map<std::string, std::string, CaseInsensitiveStringCompare>;
|
|
||||||
using LayerMap = std::map<System, std::list<Section*>>;
|
|
||||||
using Layers = std::map<LayerType, std::unique_ptr<Layer>>;
|
|
||||||
using ConfigChangedCallback = std::function<void()>;
|
|
||||||
|
|
||||||
class Section
|
|
||||||
{
|
|
||||||
friend Layer;
|
|
||||||
friend ConfigLayerLoader;
|
|
||||||
|
|
||||||
public:
|
|
||||||
Section(LayerType layer, System system, const std::string& name)
|
|
||||||
: m_layer(layer), m_system(system), m_name(name)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual bool Exists(const std::string& key) const;
|
|
||||||
bool Delete(const std::string& key);
|
|
||||||
|
|
||||||
// Setters
|
|
||||||
virtual void Set(const std::string& key, const std::string& value);
|
|
||||||
|
|
||||||
void Set(const std::string& key, u32 newValue);
|
|
||||||
void Set(const std::string& key, float newValue);
|
|
||||||
void Set(const std::string& key, double newValue);
|
|
||||||
void Set(const std::string& key, int newValue);
|
|
||||||
void Set(const std::string& key, bool newValue);
|
|
||||||
|
|
||||||
// Setters with default values
|
|
||||||
void Set(const std::string& key, const std::string& newValue, const std::string& defaultValue);
|
|
||||||
template <typename T>
|
|
||||||
void Set(const std::string& key, T newValue, const T defaultValue)
|
|
||||||
{
|
|
||||||
if (newValue != defaultValue)
|
|
||||||
Set(key, newValue);
|
|
||||||
else
|
|
||||||
Delete(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Getters
|
|
||||||
virtual bool Get(const std::string& key, std::string* value,
|
|
||||||
const std::string& default_value = NULL_STRING) const;
|
|
||||||
|
|
||||||
bool Get(const std::string& key, int* value, int defaultValue = 0) const;
|
|
||||||
bool Get(const std::string& key, u32* value, u32 defaultValue = 0) const;
|
|
||||||
bool Get(const std::string& key, bool* value, bool defaultValue = false) const;
|
|
||||||
bool Get(const std::string& key, float* value, float defaultValue = 0.0f) const;
|
|
||||||
bool Get(const std::string& key, double* value, double defaultValue = 0.0) const;
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
T Get(const std::string& key, const T& default_value) const
|
|
||||||
{
|
|
||||||
T value;
|
|
||||||
Get(key, value, default_value);
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Section chunk
|
|
||||||
void SetLines(const std::vector<std::string>& lines);
|
|
||||||
// XXX: Add to recursive layer
|
|
||||||
virtual bool GetLines(std::vector<std::string>* lines, const bool remove_comments = true) const;
|
|
||||||
virtual bool HasLines() const { return m_lines.size() > 0; }
|
|
||||||
const std::string& GetName() const { return m_name; }
|
|
||||||
const SectionValueMap& GetValues() const { return m_values; }
|
|
||||||
const std::vector<std::string>& GetDeletedKeys() const { return m_deleted_keys; }
|
|
||||||
bool IsDirty() const { return m_dirty; }
|
|
||||||
void ClearDirty() { m_dirty = false; }
|
|
||||||
protected:
|
|
||||||
bool m_dirty = false;
|
|
||||||
|
|
||||||
LayerType m_layer;
|
|
||||||
System m_system;
|
|
||||||
const std::string m_name;
|
|
||||||
static const std::string& NULL_STRING;
|
|
||||||
|
|
||||||
SectionValueMap m_values;
|
|
||||||
std::vector<std::string> m_deleted_keys;
|
|
||||||
|
|
||||||
std::vector<std::string> m_lines;
|
|
||||||
};
|
|
||||||
|
|
||||||
// XXX: Allow easy migration!
|
|
||||||
class ConfigLayerLoader
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
ConfigLayerLoader(LayerType layer) : m_layer(layer) {}
|
|
||||||
~ConfigLayerLoader() {}
|
|
||||||
virtual void Load(Layer* config_layer) = 0;
|
|
||||||
virtual void Save(Layer* config_layer) = 0;
|
|
||||||
|
|
||||||
LayerType GetLayer() const { return m_layer; }
|
|
||||||
private:
|
|
||||||
const LayerType m_layer;
|
|
||||||
};
|
|
||||||
|
|
||||||
class Layer
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
explicit Layer(LayerType layer) : m_layer(layer) {}
|
|
||||||
Layer(std::unique_ptr<ConfigLayerLoader> loader);
|
|
||||||
virtual ~Layer();
|
|
||||||
|
|
||||||
// Convenience functions
|
|
||||||
bool Exists(System system, const std::string& section_name, const std::string& key);
|
|
||||||
bool DeleteKey(System system, const std::string& section_name, const std::string& key);
|
|
||||||
template <typename T>
|
|
||||||
bool GetIfExists(System system, const std::string& section_name, const std::string& key, T* value)
|
|
||||||
{
|
|
||||||
if (Exists(system, section_name, key))
|
|
||||||
return GetOrCreateSection(system, section_name)->Get(key, value);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual Section* GetSection(System system, const std::string& section_name);
|
|
||||||
virtual Section* GetOrCreateSection(System system, const std::string& section_name);
|
|
||||||
|
|
||||||
// Explicit load and save of layers
|
|
||||||
void Load();
|
|
||||||
void Save();
|
|
||||||
|
|
||||||
LayerType GetLayer() const { return m_layer; }
|
|
||||||
const LayerMap& GetLayerMap() { return m_sections; }
|
|
||||||
// Stay away from this routine as much as possible
|
|
||||||
ConfigLayerLoader* GetLoader() { return m_loader.get(); }
|
|
||||||
protected:
|
|
||||||
bool IsDirty() const;
|
|
||||||
void ClearDirty();
|
|
||||||
|
|
||||||
LayerMap m_sections;
|
|
||||||
const LayerType m_layer;
|
|
||||||
std::unique_ptr<ConfigLayerLoader> m_loader;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Common function used for getting configuration
|
|
||||||
Section* GetOrCreateSection(System system, const std::string& section_name);
|
|
||||||
|
|
||||||
// Layer management
|
|
||||||
Layers* GetLayers();
|
|
||||||
void AddLayer(std::unique_ptr<Layer> layer);
|
|
||||||
void AddLayer(std::unique_ptr<ConfigLayerLoader> loader);
|
|
||||||
void AddLoadLayer(std::unique_ptr<Layer> layer);
|
|
||||||
void AddLoadLayer(std::unique_ptr<ConfigLayerLoader> loader);
|
|
||||||
Layer* GetLayer(LayerType layer);
|
|
||||||
void RemoveLayer(LayerType layer);
|
|
||||||
bool LayerExists(LayerType layer);
|
|
||||||
|
|
||||||
void AddConfigChangedCallback(ConfigChangedCallback func);
|
|
||||||
|
|
||||||
// Explicit load and save of layers
|
|
||||||
void Load();
|
|
||||||
void Save();
|
|
||||||
|
|
||||||
// Often used functions for getting or setting configuration on the base layer for the main system
|
|
||||||
template <typename T>
|
|
||||||
T Get(const std::string& section_name, const std::string& key, const T& default_value)
|
|
||||||
{
|
|
||||||
auto base_layer = GetLayer(Config::LayerType::Base);
|
|
||||||
return base_layer->GetOrCreateSection(Config::System::Main, section_name)
|
|
||||||
->Get(key, default_value);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
void Set(const std::string& section_name, const std::string& key, const T& value)
|
|
||||||
{
|
|
||||||
auto base_layer = GetLayer(Config::LayerType::Base);
|
|
||||||
base_layer->GetOrCreateSection(Config::System::Main, section_name)->Set(key, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Init();
|
|
||||||
void Shutdown();
|
|
||||||
|
|
||||||
const std::string& GetSystemName(System system);
|
|
||||||
System GetSystemFromName(const std::string& system);
|
|
||||||
const std::string& GetLayerName(LayerType layer);
|
|
||||||
}
|
|
140
Source/Core/Common/Config/Config.cpp
Normal file
140
Source/Core/Common/Config/Config.cpp
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
// Copyright 2016 Dolphin Emulator Project
|
||||||
|
// Licensed under GPLv2+
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <list>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
#include "Common/Assert.h"
|
||||||
|
#include "Common/Config/Config.h"
|
||||||
|
|
||||||
|
namespace Config
|
||||||
|
{
|
||||||
|
static Layers s_layers;
|
||||||
|
static std::list<ConfigChangedCallback> s_callbacks;
|
||||||
|
|
||||||
|
void InvokeConfigChangedCallbacks();
|
||||||
|
|
||||||
|
Section* GetOrCreateSection(System system, const std::string& section_name)
|
||||||
|
{
|
||||||
|
return s_layers[LayerType::Meta]->GetOrCreateSection(system, section_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
Layers* GetLayers()
|
||||||
|
{
|
||||||
|
return &s_layers;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddLayer(std::unique_ptr<Layer> layer)
|
||||||
|
{
|
||||||
|
s_layers[layer->GetLayer()] = std::move(layer);
|
||||||
|
InvokeConfigChangedCallbacks();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddLayer(std::unique_ptr<ConfigLayerLoader> loader)
|
||||||
|
{
|
||||||
|
AddLayer(std::make_unique<Layer>(std::move(loader)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddLoadLayer(std::unique_ptr<Layer> layer)
|
||||||
|
{
|
||||||
|
layer->Load();
|
||||||
|
AddLayer(std::move(layer));
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddLoadLayer(std::unique_ptr<ConfigLayerLoader> loader)
|
||||||
|
{
|
||||||
|
AddLoadLayer(std::make_unique<Layer>(std::move(loader)));
|
||||||
|
}
|
||||||
|
|
||||||
|
Layer* GetLayer(LayerType layer)
|
||||||
|
{
|
||||||
|
if (!LayerExists(layer))
|
||||||
|
return nullptr;
|
||||||
|
return s_layers[layer].get();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RemoveLayer(LayerType layer)
|
||||||
|
{
|
||||||
|
s_layers.erase(layer);
|
||||||
|
InvokeConfigChangedCallbacks();
|
||||||
|
}
|
||||||
|
bool LayerExists(LayerType layer)
|
||||||
|
{
|
||||||
|
return s_layers.find(layer) != s_layers.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddConfigChangedCallback(ConfigChangedCallback func)
|
||||||
|
{
|
||||||
|
s_callbacks.emplace_back(func);
|
||||||
|
}
|
||||||
|
|
||||||
|
void InvokeConfigChangedCallbacks()
|
||||||
|
{
|
||||||
|
for (const auto& callback : s_callbacks)
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Explicit load and save of layers
|
||||||
|
void Load()
|
||||||
|
{
|
||||||
|
for (auto& layer : s_layers)
|
||||||
|
layer.second->Load();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Save()
|
||||||
|
{
|
||||||
|
for (auto& layer : s_layers)
|
||||||
|
layer.second->Save();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Init()
|
||||||
|
{
|
||||||
|
// This layer always has to exist
|
||||||
|
s_layers[LayerType::Meta] = std::make_unique<RecursiveLayer>();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Shutdown()
|
||||||
|
{
|
||||||
|
s_layers.clear();
|
||||||
|
s_callbacks.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
static const std::map<System, std::string> system_to_name = {
|
||||||
|
{System::Main, "Dolphin"}, {System::GCPad, "GCPad"}, {System::WiiPad, "Wiimote"},
|
||||||
|
{System::GCKeyboard, "GCKeyboard"}, {System::GFX, "Graphics"}, {System::Logger, "Logger"},
|
||||||
|
{System::Debugger, "Debugger"}, {System::UI, "UI"},
|
||||||
|
};
|
||||||
|
|
||||||
|
const std::string& GetSystemName(System system)
|
||||||
|
{
|
||||||
|
return system_to_name.at(system);
|
||||||
|
}
|
||||||
|
|
||||||
|
System GetSystemFromName(const std::string& name)
|
||||||
|
{
|
||||||
|
const auto system = std::find_if(system_to_name.begin(), system_to_name.end(),
|
||||||
|
[&name](const auto& entry) { return entry.second == name; });
|
||||||
|
if (system != system_to_name.end())
|
||||||
|
return system->first;
|
||||||
|
|
||||||
|
_assert_msg_(COMMON, false, "Programming error! Couldn't convert '%s' to system!", name.c_str());
|
||||||
|
return System::Main;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string& GetLayerName(LayerType layer)
|
||||||
|
{
|
||||||
|
static const std::map<LayerType, std::string> layer_to_name = {
|
||||||
|
{LayerType::Base, "Base"},
|
||||||
|
{LayerType::GlobalGame, "Global GameINI"},
|
||||||
|
{LayerType::LocalGame, "Local GameINI"},
|
||||||
|
{LayerType::Netplay, "Netplay"},
|
||||||
|
{LayerType::Movie, "Movie"},
|
||||||
|
{LayerType::CommandLine, "Command Line"},
|
||||||
|
{LayerType::CurrentRun, "Current Run"},
|
||||||
|
{LayerType::Meta, "Top"},
|
||||||
|
};
|
||||||
|
return layer_to_name.at(layer);
|
||||||
|
}
|
||||||
|
}
|
63
Source/Core/Common/Config/Config.h
Normal file
63
Source/Core/Common/Config/Config.h
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
// Copyright 2016 Dolphin Emulator Project
|
||||||
|
// Licensed under GPLv2+
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <map>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "Common/Config/Enums.h"
|
||||||
|
#include "Common/Config/Layer.h"
|
||||||
|
#include "Common/Config/Section.h"
|
||||||
|
|
||||||
|
namespace Config
|
||||||
|
{
|
||||||
|
using Layers = std::map<LayerType, std::unique_ptr<Layer>>;
|
||||||
|
using ConfigChangedCallback = std::function<void()>;
|
||||||
|
|
||||||
|
// Common function used for getting configuration
|
||||||
|
Section* GetOrCreateSection(System system, const std::string& section_name);
|
||||||
|
|
||||||
|
// Layer management
|
||||||
|
Layers* GetLayers();
|
||||||
|
void AddLayer(std::unique_ptr<Layer> layer);
|
||||||
|
void AddLayer(std::unique_ptr<ConfigLayerLoader> loader);
|
||||||
|
void AddLoadLayer(std::unique_ptr<Layer> layer);
|
||||||
|
void AddLoadLayer(std::unique_ptr<ConfigLayerLoader> loader);
|
||||||
|
Layer* GetLayer(LayerType layer);
|
||||||
|
void RemoveLayer(LayerType layer);
|
||||||
|
bool LayerExists(LayerType layer);
|
||||||
|
|
||||||
|
void AddConfigChangedCallback(ConfigChangedCallback func);
|
||||||
|
void InvokeConfigChangedCallbacks();
|
||||||
|
|
||||||
|
// Explicit load and save of layers
|
||||||
|
void Load();
|
||||||
|
void Save();
|
||||||
|
|
||||||
|
// Often used functions for getting or setting configuration on the base layer for the main system
|
||||||
|
template <typename T>
|
||||||
|
T Get(const std::string& section_name, const std::string& key, const T& default_value)
|
||||||
|
{
|
||||||
|
auto base_layer = GetLayer(Config::LayerType::Base);
|
||||||
|
return base_layer->GetOrCreateSection(Config::System::Main, section_name)
|
||||||
|
->Get(key, default_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void Set(const std::string& section_name, const std::string& key, const T& value)
|
||||||
|
{
|
||||||
|
auto base_layer = GetLayer(Config::LayerType::Base);
|
||||||
|
base_layer->GetOrCreateSection(Config::System::Main, section_name)->Set(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Init();
|
||||||
|
void Shutdown();
|
||||||
|
|
||||||
|
const std::string& GetSystemName(System system);
|
||||||
|
System GetSystemFromName(const std::string& system);
|
||||||
|
const std::string& GetLayerName(LayerType layer);
|
||||||
|
}
|
32
Source/Core/Common/Config/Enums.h
Normal file
32
Source/Core/Common/Config/Enums.h
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
// Copyright 2017 Dolphin Emulator Project
|
||||||
|
// Licensed under GPLv2+
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace Config
|
||||||
|
{
|
||||||
|
enum class LayerType
|
||||||
|
{
|
||||||
|
Base,
|
||||||
|
GlobalGame,
|
||||||
|
LocalGame,
|
||||||
|
Movie,
|
||||||
|
Netplay,
|
||||||
|
CommandLine,
|
||||||
|
CurrentRun,
|
||||||
|
Meta,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class System
|
||||||
|
{
|
||||||
|
Main,
|
||||||
|
GCPad,
|
||||||
|
WiiPad,
|
||||||
|
GCKeyboard,
|
||||||
|
GFX,
|
||||||
|
Logger,
|
||||||
|
Debugger,
|
||||||
|
UI,
|
||||||
|
};
|
||||||
|
}
|
148
Source/Core/Common/Config/Layer.cpp
Normal file
148
Source/Core/Common/Config/Layer.cpp
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
// Copyright 2016 Dolphin Emulator Project
|
||||||
|
// Licensed under GPLv2+
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cstring>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
#include "Common/Config/Config.h"
|
||||||
|
#include "Common/Config/Layer.h"
|
||||||
|
#include "Common/Config/Section.h"
|
||||||
|
|
||||||
|
namespace Config
|
||||||
|
{
|
||||||
|
ConfigLayerLoader::ConfigLayerLoader(LayerType layer) : m_layer(layer)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ConfigLayerLoader::~ConfigLayerLoader() = default;
|
||||||
|
|
||||||
|
LayerType ConfigLayerLoader::GetLayer() const
|
||||||
|
{
|
||||||
|
return m_layer;
|
||||||
|
}
|
||||||
|
|
||||||
|
Layer::Layer(LayerType type) : m_layer(type)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Layer::Layer(std::unique_ptr<ConfigLayerLoader> loader)
|
||||||
|
: m_layer(loader->GetLayer()), m_loader(std::move(loader))
|
||||||
|
{
|
||||||
|
Load();
|
||||||
|
}
|
||||||
|
|
||||||
|
Layer::~Layer()
|
||||||
|
{
|
||||||
|
Save();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Layer::Exists(System system, const std::string& section_name, const std::string& key)
|
||||||
|
{
|
||||||
|
Section* section = GetSection(system, section_name);
|
||||||
|
if (!section)
|
||||||
|
return false;
|
||||||
|
return section->Exists(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Layer::DeleteKey(System system, const std::string& section_name, const std::string& key)
|
||||||
|
{
|
||||||
|
Section* section = GetSection(system, section_name);
|
||||||
|
if (!section)
|
||||||
|
return false;
|
||||||
|
return section->Delete(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
Section* Layer::GetSection(System system, const std::string& section_name)
|
||||||
|
{
|
||||||
|
for (auto& section : m_sections[system])
|
||||||
|
if (!strcasecmp(section.m_name.c_str(), section_name.c_str()))
|
||||||
|
return §ion;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Section* Layer::GetOrCreateSection(System system, const std::string& section_name)
|
||||||
|
{
|
||||||
|
Section* section = GetSection(system, section_name);
|
||||||
|
if (!section)
|
||||||
|
{
|
||||||
|
if (m_layer == LayerType::Meta)
|
||||||
|
m_sections[system].emplace_back(RecursiveSection(m_layer, system, section_name));
|
||||||
|
else
|
||||||
|
m_sections[system].emplace_back(Section(m_layer, system, section_name));
|
||||||
|
section = &m_sections[system].back();
|
||||||
|
}
|
||||||
|
return section;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Layer::Load()
|
||||||
|
{
|
||||||
|
if (m_loader)
|
||||||
|
m_loader->Load(this);
|
||||||
|
ClearDirty();
|
||||||
|
InvokeConfigChangedCallbacks();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Layer::Save()
|
||||||
|
{
|
||||||
|
if (!m_loader || !IsDirty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_loader->Save(this);
|
||||||
|
ClearDirty();
|
||||||
|
InvokeConfigChangedCallbacks();
|
||||||
|
}
|
||||||
|
|
||||||
|
LayerType Layer::GetLayer() const
|
||||||
|
{
|
||||||
|
return m_layer;
|
||||||
|
}
|
||||||
|
|
||||||
|
const LayerMap& Layer::GetLayerMap() const
|
||||||
|
{
|
||||||
|
return m_sections;
|
||||||
|
}
|
||||||
|
|
||||||
|
ConfigLayerLoader* Layer::GetLoader() const
|
||||||
|
{
|
||||||
|
return m_loader.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Layer::IsDirty() const
|
||||||
|
{
|
||||||
|
return std::any_of(m_sections.begin(), m_sections.end(), [](const auto& system) {
|
||||||
|
return std::any_of(system.second.begin(), system.second.end(),
|
||||||
|
[](const auto& section) { return section.IsDirty(); });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void Layer::ClearDirty()
|
||||||
|
{
|
||||||
|
std::for_each(m_sections.begin(), m_sections.end(), [](auto& system) {
|
||||||
|
std::for_each(system.second.begin(), system.second.end(),
|
||||||
|
[](auto& section) { section.ClearDirty(); });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
RecursiveLayer::RecursiveLayer() : Layer(LayerType::Meta)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Section* RecursiveLayer::GetSection(System system, const std::string& section_name)
|
||||||
|
{
|
||||||
|
// Always queries backwards recursively, so it doesn't matter if it exists or not on this layer
|
||||||
|
return GetOrCreateSection(system, section_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
Section* RecursiveLayer::GetOrCreateSection(System system, const std::string& section_name)
|
||||||
|
{
|
||||||
|
Section* section = Layer::GetSection(system, section_name);
|
||||||
|
if (!section)
|
||||||
|
{
|
||||||
|
m_sections[system].emplace_back(RecursiveSection(m_layer, system, section_name));
|
||||||
|
section = &m_sections[system].back();
|
||||||
|
}
|
||||||
|
return section;
|
||||||
|
}
|
||||||
|
}
|
80
Source/Core/Common/Config/Layer.h
Normal file
80
Source/Core/Common/Config/Layer.h
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
// Copyright 2016 Dolphin Emulator Project
|
||||||
|
// Licensed under GPLv2+
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "Common/Config/Enums.h"
|
||||||
|
#include "Common/Config/Section.h"
|
||||||
|
|
||||||
|
namespace Config
|
||||||
|
{
|
||||||
|
using LayerMap = std::map<System, std::vector<Section>>;
|
||||||
|
|
||||||
|
class ConfigLayerLoader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit ConfigLayerLoader(LayerType layer);
|
||||||
|
virtual ~ConfigLayerLoader();
|
||||||
|
virtual void Load(Layer* config_layer) = 0;
|
||||||
|
virtual void Save(Layer* config_layer) = 0;
|
||||||
|
|
||||||
|
LayerType GetLayer() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
const LayerType m_layer;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Layer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit Layer(LayerType layer);
|
||||||
|
explicit Layer(std::unique_ptr<ConfigLayerLoader> loader);
|
||||||
|
virtual ~Layer();
|
||||||
|
|
||||||
|
// Convenience functions
|
||||||
|
bool Exists(System system, const std::string& section_name, const std::string& key);
|
||||||
|
bool DeleteKey(System system, const std::string& section_name, const std::string& key);
|
||||||
|
template <typename T>
|
||||||
|
bool GetIfExists(System system, const std::string& section_name, const std::string& key, T* value)
|
||||||
|
{
|
||||||
|
if (Exists(system, section_name, key))
|
||||||
|
return GetOrCreateSection(system, section_name)->Get(key, value);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Section* GetSection(System system, const std::string& section_name);
|
||||||
|
virtual Section* GetOrCreateSection(System system, const std::string& section_name);
|
||||||
|
|
||||||
|
// Explicit load and save of layers
|
||||||
|
void Load();
|
||||||
|
void Save();
|
||||||
|
|
||||||
|
LayerType GetLayer() const;
|
||||||
|
const LayerMap& GetLayerMap() const;
|
||||||
|
// Stay away from this routine as much as possible
|
||||||
|
ConfigLayerLoader* GetLoader() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool IsDirty() const;
|
||||||
|
void ClearDirty();
|
||||||
|
|
||||||
|
LayerMap m_sections;
|
||||||
|
const LayerType m_layer;
|
||||||
|
std::unique_ptr<ConfigLayerLoader> m_loader;
|
||||||
|
};
|
||||||
|
|
||||||
|
class RecursiveLayer final : public Layer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
RecursiveLayer();
|
||||||
|
Section* GetSection(System system, const std::string& section_name) override;
|
||||||
|
Section* GetOrCreateSection(System system, const std::string& section_name) override;
|
||||||
|
};
|
||||||
|
}
|
286
Source/Core/Common/Config/Section.cpp
Normal file
286
Source/Core/Common/Config/Section.cpp
Normal file
@ -0,0 +1,286 @@
|
|||||||
|
// Copyright 2017 Dolphin Emulator Project
|
||||||
|
// Licensed under GPLv2+
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <cstddef>
|
||||||
|
#include <map>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include "Common/Assert.h"
|
||||||
|
#include "Common/Config/Config.h"
|
||||||
|
#include "Common/Config/Layer.h"
|
||||||
|
#include "Common/Config/Section.h"
|
||||||
|
#include "Common/StringUtil.h"
|
||||||
|
|
||||||
|
namespace Config
|
||||||
|
{
|
||||||
|
const std::string& Section::NULL_STRING = "";
|
||||||
|
|
||||||
|
Section::Section(LayerType layer, System system, const std::string& name)
|
||||||
|
: m_layer(layer), m_system(system), m_name(name)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Section::Exists(const std::string& key) const
|
||||||
|
{
|
||||||
|
return m_values.find(key) != m_values.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Section::Delete(const std::string& key)
|
||||||
|
{
|
||||||
|
auto it = m_values.find(key);
|
||||||
|
if (it == m_values.end())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
m_values.erase(it);
|
||||||
|
|
||||||
|
m_deleted_keys.push_back(key);
|
||||||
|
m_dirty = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Section::Set(const std::string& key, const std::string& value)
|
||||||
|
{
|
||||||
|
auto it = m_values.find(key);
|
||||||
|
if (it != m_values.end() && it->second != value)
|
||||||
|
{
|
||||||
|
it->second = value;
|
||||||
|
m_dirty = true;
|
||||||
|
}
|
||||||
|
else if (it == m_values.end())
|
||||||
|
{
|
||||||
|
m_values[key] = value;
|
||||||
|
m_dirty = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Section::Set(const std::string& key, u32 newValue)
|
||||||
|
{
|
||||||
|
Section::Set(key, StringFromFormat("0x%08x", newValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Section::Set(const std::string& key, float newValue)
|
||||||
|
{
|
||||||
|
Section::Set(key, StringFromFormat("%#.9g", newValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Section::Set(const std::string& key, double newValue)
|
||||||
|
{
|
||||||
|
Section::Set(key, StringFromFormat("%#.17g", newValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Section::Set(const std::string& key, int newValue)
|
||||||
|
{
|
||||||
|
Section::Set(key, StringFromInt(newValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Section::Set(const std::string& key, bool newValue)
|
||||||
|
{
|
||||||
|
Section::Set(key, StringFromBool(newValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Section::Set(const std::string& key, const std::string& newValue,
|
||||||
|
const std::string& defaultValue)
|
||||||
|
{
|
||||||
|
if (newValue != defaultValue)
|
||||||
|
Set(key, newValue);
|
||||||
|
else
|
||||||
|
Delete(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Section::SetLines(const std::vector<std::string>& lines)
|
||||||
|
{
|
||||||
|
m_lines = lines;
|
||||||
|
m_dirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Section::Get(const std::string& key, std::string* value,
|
||||||
|
const std::string& default_value) const
|
||||||
|
{
|
||||||
|
const auto& it = m_values.find(key);
|
||||||
|
if (it != m_values.end())
|
||||||
|
{
|
||||||
|
*value = it->second;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (&default_value != &NULL_STRING)
|
||||||
|
{
|
||||||
|
*value = default_value;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Section::Get(const std::string& key, int* value, int defaultValue) const
|
||||||
|
{
|
||||||
|
std::string temp;
|
||||||
|
bool retval = Get(key, &temp);
|
||||||
|
|
||||||
|
if (retval && TryParse(temp, value))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
*value = defaultValue;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Section::Get(const std::string& key, u32* value, u32 defaultValue) const
|
||||||
|
{
|
||||||
|
std::string temp;
|
||||||
|
bool retval = Get(key, &temp);
|
||||||
|
|
||||||
|
if (retval && TryParse(temp, value))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
*value = defaultValue;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Section::Get(const std::string& key, bool* value, bool defaultValue) const
|
||||||
|
{
|
||||||
|
std::string temp;
|
||||||
|
bool retval = Get(key, &temp);
|
||||||
|
|
||||||
|
if (retval && TryParse(temp, value))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
*value = defaultValue;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Section::Get(const std::string& key, float* value, float defaultValue) const
|
||||||
|
{
|
||||||
|
std::string temp;
|
||||||
|
bool retval = Get(key, &temp);
|
||||||
|
|
||||||
|
if (retval && TryParse(temp, value))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
*value = defaultValue;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Section::Get(const std::string& key, double* value, double defaultValue) const
|
||||||
|
{
|
||||||
|
std::string temp;
|
||||||
|
bool retval = Get(key, &temp);
|
||||||
|
|
||||||
|
if (retval && TryParse(temp, value))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
*value = defaultValue;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return a list of all lines in a section
|
||||||
|
bool Section::GetLines(std::vector<std::string>* lines, const bool remove_comments) const
|
||||||
|
{
|
||||||
|
lines->clear();
|
||||||
|
|
||||||
|
for (std::string line : m_lines)
|
||||||
|
{
|
||||||
|
line = StripSpaces(line);
|
||||||
|
|
||||||
|
if (remove_comments)
|
||||||
|
{
|
||||||
|
size_t commentPos = line.find('#');
|
||||||
|
if (commentPos == 0)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (commentPos != std::string::npos)
|
||||||
|
{
|
||||||
|
line = StripSpaces(line.substr(0, commentPos));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lines->push_back(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Section::HasLines() const
|
||||||
|
{
|
||||||
|
return !m_lines.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string& Section::GetName() const
|
||||||
|
{
|
||||||
|
return m_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
const SectionValueMap& Section::GetValues() const
|
||||||
|
{
|
||||||
|
return m_values;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<std::string>& Section::GetDeletedKeys() const
|
||||||
|
{
|
||||||
|
return m_deleted_keys;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Section::IsDirty() const
|
||||||
|
{
|
||||||
|
return m_dirty;
|
||||||
|
}
|
||||||
|
void Section::ClearDirty()
|
||||||
|
{
|
||||||
|
m_dirty = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
RecursiveSection::RecursiveSection(LayerType layer, System system, const std::string& name)
|
||||||
|
: Section(layer, system, name)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RecursiveSection::Exists(const std::string& key) const
|
||||||
|
{
|
||||||
|
auto layers_it = Config::GetLayers()->find(LayerType::Meta);
|
||||||
|
do
|
||||||
|
{
|
||||||
|
const Section* layer_section = layers_it->second->GetSection(m_system, m_name);
|
||||||
|
if (layer_section && layer_section->Exists(key))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} while (--layers_it != Config::GetLayers()->end());
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RecursiveSection::Get(const std::string& key, std::string* value,
|
||||||
|
const std::string& default_value) const
|
||||||
|
{
|
||||||
|
static constexpr std::array<LayerType, 7> search_order = {{
|
||||||
|
// Skip the meta layer
|
||||||
|
LayerType::CurrentRun, LayerType::CommandLine, LayerType::Movie, LayerType::Netplay,
|
||||||
|
LayerType::LocalGame, LayerType::GlobalGame, LayerType::Base,
|
||||||
|
}};
|
||||||
|
|
||||||
|
for (auto layer_id : search_order)
|
||||||
|
{
|
||||||
|
auto layers_it = Config::GetLayers()->find(layer_id);
|
||||||
|
if (layers_it == Config::GetLayers()->end())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const Section* layer_section = layers_it->second->GetSection(m_system, m_name);
|
||||||
|
if (layer_section && layer_section->Exists(key))
|
||||||
|
{
|
||||||
|
return layer_section->Get(key, value, default_value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Section::Get(key, value, default_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RecursiveSection::Set(const std::string& key, const std::string& value)
|
||||||
|
{
|
||||||
|
// The RecursiveSection can't set since it is used to recursively get values from the layer
|
||||||
|
// map.
|
||||||
|
// It is only a part of the meta layer, and the meta layer isn't allowed to set any values.
|
||||||
|
_assert_msg_(COMMON, false, "Don't try to set values here!");
|
||||||
|
}
|
||||||
|
}
|
110
Source/Core/Common/Config/Section.h
Normal file
110
Source/Core/Common/Config/Section.h
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
// Copyright 2017 Dolphin Emulator Project
|
||||||
|
// Licensed under GPLv2+
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
// XXX: Purely for case insensitive compare
|
||||||
|
#include "Common/CommonTypes.h"
|
||||||
|
#include "Common/Config/Enums.h"
|
||||||
|
#include "Common/IniFile.h"
|
||||||
|
|
||||||
|
namespace Config
|
||||||
|
{
|
||||||
|
class Layer;
|
||||||
|
class ConfigLayerLoader;
|
||||||
|
|
||||||
|
using SectionValueMap = std::map<std::string, std::string, CaseInsensitiveStringCompare>;
|
||||||
|
|
||||||
|
class Section
|
||||||
|
{
|
||||||
|
friend Layer;
|
||||||
|
friend ConfigLayerLoader;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Section(LayerType layer, System system, const std::string& name);
|
||||||
|
|
||||||
|
virtual bool Exists(const std::string& key) const;
|
||||||
|
bool Delete(const std::string& key);
|
||||||
|
|
||||||
|
// Setters
|
||||||
|
virtual void Set(const std::string& key, const std::string& value);
|
||||||
|
|
||||||
|
void Set(const std::string& key, u32 newValue);
|
||||||
|
void Set(const std::string& key, float newValue);
|
||||||
|
void Set(const std::string& key, double newValue);
|
||||||
|
void Set(const std::string& key, int newValue);
|
||||||
|
void Set(const std::string& key, bool newValue);
|
||||||
|
|
||||||
|
// Setters with default values
|
||||||
|
void Set(const std::string& key, const std::string& newValue, const std::string& defaultValue);
|
||||||
|
template <typename T>
|
||||||
|
void Set(const std::string& key, T newValue, const T defaultValue)
|
||||||
|
{
|
||||||
|
if (newValue != defaultValue)
|
||||||
|
Set(key, newValue);
|
||||||
|
else
|
||||||
|
Delete(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Getters
|
||||||
|
virtual bool Get(const std::string& key, std::string* value,
|
||||||
|
const std::string& default_value = NULL_STRING) const;
|
||||||
|
|
||||||
|
bool Get(const std::string& key, int* value, int defaultValue = 0) const;
|
||||||
|
bool Get(const std::string& key, u32* value, u32 defaultValue = 0) const;
|
||||||
|
bool Get(const std::string& key, bool* value, bool defaultValue = false) const;
|
||||||
|
bool Get(const std::string& key, float* value, float defaultValue = 0.0f) const;
|
||||||
|
bool Get(const std::string& key, double* value, double defaultValue = 0.0) const;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
T Get(const std::string& key, const T& default_value) const
|
||||||
|
{
|
||||||
|
T value;
|
||||||
|
Get(key, value, default_value);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Section chunk
|
||||||
|
void SetLines(const std::vector<std::string>& lines);
|
||||||
|
// XXX: Add to recursive layer
|
||||||
|
virtual bool GetLines(std::vector<std::string>* lines, const bool remove_comments = true) const;
|
||||||
|
virtual bool HasLines() const;
|
||||||
|
const std::string& GetName() const;
|
||||||
|
const SectionValueMap& GetValues() const;
|
||||||
|
const std::vector<std::string>& GetDeletedKeys() const;
|
||||||
|
bool IsDirty() const;
|
||||||
|
void ClearDirty();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool m_dirty = false;
|
||||||
|
|
||||||
|
LayerType m_layer;
|
||||||
|
System m_system;
|
||||||
|
const std::string m_name;
|
||||||
|
static const std::string& NULL_STRING;
|
||||||
|
|
||||||
|
SectionValueMap m_values;
|
||||||
|
std::vector<std::string> m_deleted_keys;
|
||||||
|
|
||||||
|
std::vector<std::string> m_lines;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Only to be used with the meta-layer
|
||||||
|
class RecursiveSection final : public Section
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
RecursiveSection(LayerType layer, System system, const std::string& name);
|
||||||
|
|
||||||
|
bool Exists(const std::string& key) const override;
|
||||||
|
|
||||||
|
bool Get(const std::string& key, std::string* value,
|
||||||
|
const std::string& default_value = NULL_STRING) const override;
|
||||||
|
|
||||||
|
void Set(const std::string& key, const std::string& value) override;
|
||||||
|
};
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user