summaryrefslogtreecommitdiff
path: root/Source
diff options
context:
space:
mode:
authorRyan Houdek <Sonicadvance1@gmail.com>2016-01-14 16:36:11 -0600
committerLéo Lam <leo@innovatetechnologi.es>2017-02-23 18:15:11 +0100
commit8360e358ee56ef5cef9aba78a57b7d0ae358ed01 (patch)
tree47757df676c545f2dfecfb307c35d9a6790978df /Source
parentf7a09c41a1aeb7026ff979589197ab03a27f2357 (diff)
New configuration namespace
Diffstat (limited to 'Source')
-rw-r--r--Source/Core/Common/CMakeLists.txt1
-rw-r--r--Source/Core/Common/Common.vcxproj2
-rw-r--r--Source/Core/Common/Common.vcxproj.filters2
-rw-r--r--Source/Core/Common/Config.cpp461
-rw-r--r--Source/Core/Common/Config.h187
5 files changed, 653 insertions, 0 deletions
diff --git a/Source/Core/Common/CMakeLists.txt b/Source/Core/Common/CMakeLists.txt
index 5f910a1670..7ed79d07d1 100644
--- a/Source/Core/Common/CMakeLists.txt
+++ b/Source/Core/Common/CMakeLists.txt
@@ -15,6 +15,7 @@ set(SRCS Analytics.cpp
MsgHandler.cpp
NandPaths.cpp
Network.cpp
+ Config.cpp
PcapFile.cpp
PerformanceCounter.cpp
Profiler.cpp
diff --git a/Source/Core/Common/Common.vcxproj b/Source/Core/Common/Common.vcxproj
index 831dcad4a7..047b863443 100644
--- a/Source/Core/Common/Common.vcxproj
+++ b/Source/Core/Common/Common.vcxproj
@@ -123,6 +123,7 @@
<ClInclude Include="NandPaths.h" />
<ClInclude Include="Network.h" />
<ClInclude Include="NonCopyable.h" />
+ <ClInclude Include="Config.h" />
<ClInclude Include="PcapFile.h" />
<ClInclude Include="Profiler.h" />
<ClInclude Include="ScopeGuard.h" />
@@ -172,6 +173,7 @@
<ClCompile Include="MsgHandler.cpp" />
<ClCompile Include="NandPaths.cpp" />
<ClCompile Include="Network.cpp" />
+ <ClCompile Include="Config.cpp" />
<ClCompile Include="PcapFile.cpp" />
<ClCompile Include="Profiler.cpp" />
<ClCompile Include="SDCardUtil.cpp" />
diff --git a/Source/Core/Common/Common.vcxproj.filters b/Source/Core/Common/Common.vcxproj.filters
index 3c9b952742..52625071a4 100644
--- a/Source/Core/Common/Common.vcxproj.filters
+++ b/Source/Core/Common/Common.vcxproj.filters
@@ -53,6 +53,7 @@
<ClInclude Include="MsgHandler.h" />
<ClInclude Include="NandPaths.h" />
<ClInclude Include="Network.h" />
+ <ClInclude Include="Config.h" />
<ClInclude Include="PcapFile.h" />
<ClInclude Include="Profiler.h" />
<ClInclude Include="ScopeGuard.h" />
@@ -245,6 +246,7 @@
<ClCompile Include="MsgHandler.cpp" />
<ClCompile Include="NandPaths.cpp" />
<ClCompile Include="Network.cpp" />
+ <ClCompile Include="Config.cpp" />
<ClCompile Include="PcapFile.cpp" />
<ClCompile Include="Profiler.cpp" />
<ClCompile Include="SDCardUtil.cpp" />
diff --git a/Source/Core/Common/Config.cpp b/Source/Core/Common/Config.cpp
new file mode 100644
index 0000000000..e41f123243
--- /dev/null
+++ b/Source/Core/Common/Config.cpp
@@ -0,0 +1,461 @@
+// Copyright 2016 Dolphin Emulator Project
+// Licensed under GPLv2+
+// Refer to the license.txt file included.
+
+#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);
+ 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;
+ else
+ m_values[key] = value;
+}
+
+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);
+}
+
+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);
+ CallbackSystems();
+}
+
+void Layer::Save()
+{
+ if (m_loader)
+ m_loader->Save(this);
+}
+
+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();
+
+ CallbackSystems();
+}
+
+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];
+}
+}
diff --git a/Source/Core/Common/Config.h b/Source/Core/Common/Config.h
new file mode 100644
index 0000000000..ac7fb5d6ad
--- /dev/null
+++ b/Source/Core/Common/Config.h
@@ -0,0 +1,187 @@
+// 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;
+
+ // Section chunk
+ void SetLines(const std::vector<std::string>& lines) { m_lines = 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; }
+protected:
+ 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_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:
+ 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();
+
+void Init();
+void Shutdown();
+
+const std::string& GetSystemName(System system);
+System GetSystemFromName(const std::string& system);
+const std::string& GetLayerName(LayerType layer);
+}