diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index a68e453ec..a0ff3d5f4 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -30,6 +30,8 @@ add_library(common
gl/texture.h
hash_combine.h
heap_array.h
+ layered_settings_interface.cpp
+ layered_settings_interface.h
log.cpp
log.h
make_array.h
@@ -43,6 +45,7 @@ add_library(common
progress_callback.h
rectangle.h
scope_guard.h
+ settings_interface.h
string.cpp
string.h
string_util.cpp
diff --git a/src/common/common.vcxproj b/src/common/common.vcxproj
index f26b94d5e..8623a9b67 100644
--- a/src/common/common.vcxproj
+++ b/src/common/common.vcxproj
@@ -45,6 +45,7 @@
true
+
@@ -55,6 +56,7 @@
+
@@ -116,6 +118,7 @@
true
+
diff --git a/src/common/common.vcxproj.filters b/src/common/common.vcxproj.filters
index 08727e67b..85eb5dc60 100644
--- a/src/common/common.vcxproj.filters
+++ b/src/common/common.vcxproj.filters
@@ -133,6 +133,8 @@
gl
+
+
@@ -244,6 +246,7 @@
vulkan
+
diff --git a/src/common/layered_settings_interface.cpp b/src/common/layered_settings_interface.cpp
new file mode 100644
index 000000000..922db3f82
--- /dev/null
+++ b/src/common/layered_settings_interface.cpp
@@ -0,0 +1,189 @@
+#include "layered_settings_interface.h"
+#include "common/assert.h"
+
+LayeredSettingsInterface::LayeredSettingsInterface() = default;
+
+LayeredSettingsInterface::~LayeredSettingsInterface() = default;
+
+bool LayeredSettingsInterface::Save()
+{
+ Panic("Attempting to save layered settings interface");
+ return false;
+}
+
+void LayeredSettingsInterface::Clear()
+{
+ Panic("Attempting to clear layered settings interface");
+}
+
+bool LayeredSettingsInterface::GetIntValue(const char* section, const char* key, s32* value) const
+{
+ for (u32 layer = FIRST_LAYER; layer <= LAST_LAYER; layer++)
+ {
+ if (SettingsInterface* sif = m_layers[layer]; sif != nullptr)
+ {
+ if (sif->GetIntValue(section, key, value))
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool LayeredSettingsInterface::GetUIntValue(const char* section, const char* key, u32* value) const
+{
+ for (u32 layer = FIRST_LAYER; layer <= LAST_LAYER; layer++)
+ {
+ if (SettingsInterface* sif = m_layers[layer]; sif != nullptr)
+ {
+ if (sif->GetUIntValue(section, key, value))
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool LayeredSettingsInterface::GetFloatValue(const char* section, const char* key, float* value) const
+{
+ for (u32 layer = FIRST_LAYER; layer <= LAST_LAYER; layer++)
+ {
+ if (SettingsInterface* sif = m_layers[layer]; sif != nullptr)
+ {
+ if (sif->GetFloatValue(section, key, value))
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool LayeredSettingsInterface::GetDoubleValue(const char* section, const char* key, double* value) const
+{
+ for (u32 layer = FIRST_LAYER; layer <= LAST_LAYER; layer++)
+ {
+ if (SettingsInterface* sif = m_layers[layer]; sif != nullptr)
+ {
+ if (sif->GetDoubleValue(section, key, value))
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool LayeredSettingsInterface::GetBoolValue(const char* section, const char* key, bool* value) const
+{
+ for (u32 layer = FIRST_LAYER; layer <= LAST_LAYER; layer++)
+ {
+ if (SettingsInterface* sif = m_layers[layer]; sif != nullptr)
+ {
+ if (sif->GetBoolValue(section, key, value))
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool LayeredSettingsInterface::GetStringValue(const char* section, const char* key, std::string* value) const
+{
+ for (u32 layer = FIRST_LAYER; layer <= LAST_LAYER; layer++)
+ {
+ if (SettingsInterface* sif = m_layers[layer]; sif != nullptr)
+ {
+ if (sif->GetStringValue(section, key, value))
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void LayeredSettingsInterface::SetIntValue(const char* section, const char* key, int value)
+{
+ Panic("Attempt to call SetIntValue() on layered settings interface");
+}
+
+void LayeredSettingsInterface::SetUIntValue(const char* section, const char* key, u32 value)
+{
+ Panic("Attempt to call SetUIntValue() on layered settings interface");
+}
+
+void LayeredSettingsInterface::SetFloatValue(const char* section, const char* key, float value)
+{
+ Panic("Attempt to call SetFloatValue() on layered settings interface");
+}
+
+void LayeredSettingsInterface::SetDoubleValue(const char* section, const char* key, double value)
+{
+ Panic("Attempt to call SetDoubleValue() on layered settings interface");
+}
+
+void LayeredSettingsInterface::SetBoolValue(const char* section, const char* key, bool value)
+{
+ Panic("Attempt to call SetBoolValue() on layered settings interface");
+}
+
+void LayeredSettingsInterface::SetStringValue(const char* section, const char* key, const char* value)
+{
+ Panic("Attempt to call SetStringValue() on layered settings interface");
+}
+
+bool LayeredSettingsInterface::ContainsValue(const char* section, const char* key) const
+{
+ for (u32 layer = FIRST_LAYER; layer <= LAST_LAYER; layer++)
+ {
+ if (SettingsInterface* sif = m_layers[layer]; sif != nullptr)
+ {
+ if (sif->ContainsValue(key, section))
+ return true;
+ }
+ }
+ return false;
+}
+
+void LayeredSettingsInterface::DeleteValue(const char* section, const char* key)
+{
+ Panic("Attempt to call DeleteValue() on layered settings interface");
+}
+
+void LayeredSettingsInterface::ClearSection(const char* section)
+{
+ Panic("Attempt to call ClearSection() on layered settings interface");
+}
+
+std::vector LayeredSettingsInterface::GetStringList(const char* section, const char* key) const
+{
+ std::vector ret;
+
+ for (u32 layer = FIRST_LAYER; layer <= LAST_LAYER; layer++)
+ {
+ if (SettingsInterface* sif = m_layers[layer]; sif != nullptr)
+ {
+ ret = sif->GetStringList(section, key);
+ if (!ret.empty())
+ break;
+ }
+ }
+
+ return ret;
+}
+
+void LayeredSettingsInterface::SetStringList(const char* section, const char* key,
+ const std::vector& items)
+{
+ Panic("Attempt to call SetStringList() on layered settings interface");
+}
+
+bool LayeredSettingsInterface::RemoveFromStringList(const char* section, const char* key, const char* item)
+{
+ Panic("Attempt to call RemoveFromStringList() on layered settings interface");
+ return false;
+}
+
+bool LayeredSettingsInterface::AddToStringList(const char* section, const char* key, const char* item)
+{
+ Panic("Attempt to call AddToStringList() on layered settings interface");
+ return true;
+}
diff --git a/src/common/layered_settings_interface.h b/src/common/layered_settings_interface.h
new file mode 100644
index 000000000..982871048
--- /dev/null
+++ b/src/common/layered_settings_interface.h
@@ -0,0 +1,62 @@
+#pragma once
+#include "settings_interface.h"
+#include
+
+class LayeredSettingsInterface final : public SettingsInterface
+{
+public:
+ enum Layer : u32
+ {
+ LAYER_CMDLINE,
+ LAYER_GAME,
+ LAYER_INPUT,
+ LAYER_BASE,
+ NUM_LAYERS
+ };
+
+ LayeredSettingsInterface();
+ ~LayeredSettingsInterface() override;
+
+ SettingsInterface* GetLayer(Layer layer) const { return m_layers[layer]; }
+ void SetLayer(Layer layer, SettingsInterface* sif) { m_layers[layer] = sif; }
+
+ bool Save() override;
+
+ void Clear() override;
+
+ bool GetIntValue(const char* section, const char* key, s32* value) const override;
+ bool GetUIntValue(const char* section, const char* key, u32* value) const override;
+ bool GetFloatValue(const char* section, const char* key, float* value) const override;
+ bool GetDoubleValue(const char* section, const char* key, double* value) const override;
+ bool GetBoolValue(const char* section, const char* key, bool* value) const override;
+ bool GetStringValue(const char* section, const char* key, std::string* value) const override;
+
+ void SetIntValue(const char* section, const char* key, s32 value) override;
+ void SetUIntValue(const char* section, const char* key, u32 value) override;
+ void SetFloatValue(const char* section, const char* key, float value) override;
+ void SetDoubleValue(const char* section, const char* key, double value) override;
+ void SetBoolValue(const char* section, const char* key, bool value) override;
+ void SetStringValue(const char* section, const char* key, const char* value) override;
+ bool ContainsValue(const char* section, const char* key) const override;
+ void DeleteValue(const char* section, const char* key) override;
+ void ClearSection(const char* section) override;
+
+ std::vector GetStringList(const char* section, const char* key) const override;
+ void SetStringList(const char* section, const char* key, const std::vector& items) override;
+ bool RemoveFromStringList(const char* section, const char* key, const char* item) override;
+ bool AddToStringList(const char* section, const char* key, const char* item) override;
+
+ // default parameter overloads
+ using SettingsInterface::GetBoolValue;
+ using SettingsInterface::GetDoubleValue;
+ using SettingsInterface::GetFloatValue;
+ using SettingsInterface::GetIntValue;
+ using SettingsInterface::GetStringValue;
+ using SettingsInterface::GetUIntValue;
+
+private:
+ static constexpr Layer FIRST_LAYER = LAYER_CMDLINE;
+ static constexpr Layer LAST_LAYER = LAYER_BASE;
+
+ std::array m_layers{};
+};
diff --git a/src/common/settings_interface.h b/src/common/settings_interface.h
new file mode 100644
index 000000000..80fab415a
--- /dev/null
+++ b/src/common/settings_interface.h
@@ -0,0 +1,213 @@
+#pragma once
+
+#include "types.h"
+#include
+#include
+#include
+
+class SettingsInterface
+{
+public:
+ virtual ~SettingsInterface() = default;
+
+ virtual bool Save() = 0;
+ virtual void Clear() = 0;
+
+ virtual bool GetIntValue(const char* section, const char* key, s32* value) const = 0;
+ virtual bool GetUIntValue(const char* section, const char* key, u32* value) const = 0;
+ virtual bool GetFloatValue(const char* section, const char* key, float* value) const = 0;
+ virtual bool GetDoubleValue(const char* section, const char* key, double* value) const = 0;
+ virtual bool GetBoolValue(const char* section, const char* key, bool* value) const = 0;
+ virtual bool GetStringValue(const char* section, const char* key, std::string* value) const = 0;
+
+ virtual void SetIntValue(const char* section, const char* key, s32 value) = 0;
+ virtual void SetUIntValue(const char* section, const char* key, u32 value) = 0;
+ virtual void SetFloatValue(const char* section, const char* key, float value) = 0;
+ virtual void SetDoubleValue(const char* section, const char* key, double value) = 0;
+ virtual void SetBoolValue(const char* section, const char* key, bool value) = 0;
+ virtual void SetStringValue(const char* section, const char* key, const char* value) = 0;
+
+ virtual std::vector GetStringList(const char* section, const char* key) const = 0;
+ virtual void SetStringList(const char* section, const char* key, const std::vector& items) = 0;
+ virtual bool RemoveFromStringList(const char* section, const char* key, const char* item) = 0;
+ virtual bool AddToStringList(const char* section, const char* key, const char* item) = 0;
+
+ virtual bool ContainsValue(const char* section, const char* key) const = 0;
+ virtual void DeleteValue(const char* section, const char* key) = 0;
+ virtual void ClearSection(const char* section) = 0;
+
+ ALWAYS_INLINE s32 GetIntValue(const char* section, const char* key, s32 default_value = 0) const
+ {
+ s32 value;
+ return GetIntValue(section, key, &value) ? value : default_value;
+ }
+
+ ALWAYS_INLINE u32 GetUIntValue(const char* section, const char* key, u32 default_value = 0) const
+ {
+ u32 value;
+ return GetUIntValue(section, key, &value) ? value : default_value;
+ }
+
+ ALWAYS_INLINE float GetFloatValue(const char* section, const char* key, float default_value = 0.0f) const
+ {
+ float value;
+ return GetFloatValue(section, key, &value) ? value : default_value;
+ }
+
+ ALWAYS_INLINE double GetDoubleValue(const char* section, const char* key, double default_value = 0.0) const
+ {
+ double value;
+ return GetDoubleValue(section, key, &value) ? value : default_value;
+ }
+
+ ALWAYS_INLINE bool GetBoolValue(const char* section, const char* key, bool default_value = false) const
+ {
+ bool value;
+ return GetBoolValue(section, key, &value) ? value : default_value;
+ }
+
+ ALWAYS_INLINE std::string GetStringValue(const char* section, const char* key, const char* default_value = "") const
+ {
+ std::string value;
+ if (!GetStringValue(section, key, &value))
+ value.assign(default_value);
+ return value;
+ }
+
+ ALWAYS_INLINE std::optional GetOptionalIntValue(const char* section, const char* key,
+ std::optional default_value = std::nullopt)
+ {
+ s32 ret;
+ return GetIntValue(section, key, &ret) ? std::optional(ret) : default_value;
+ }
+
+ ALWAYS_INLINE std::optional GetOptionalUIntValue(const char* section, const char* key,
+ std::optional default_value = std::nullopt)
+ {
+ u32 ret;
+ return GetUIntValue(section, key, &ret) ? std::optional(ret) : default_value;
+ }
+
+ ALWAYS_INLINE std::optional GetOptionalFloatValue(const char* section, const char* key,
+ std::optional default_value = std::nullopt)
+ {
+ float ret;
+ return GetFloatValue(section, key, &ret) ? std::optional(ret) : default_value;
+ }
+
+ ALWAYS_INLINE std::optional GetOptionalDoubleValue(const char* section, const char* key,
+ std::optional default_value = std::nullopt)
+ {
+ double ret;
+ return GetDoubleValue(section, key, &ret) ? std::optional(ret) : default_value;
+ }
+
+ ALWAYS_INLINE std::optional GetOptionalBoolValue(const char* section, const char* key,
+ std::optional default_value = std::nullopt)
+ {
+ bool ret;
+ return GetBoolValue(section, key, &ret) ? std::optional(ret) : default_value;
+ }
+
+ ALWAYS_INLINE std::optional
+ GetOptionalStringValue(const char* section, const char* key,
+ std::optional default_value = std::nullopt) const
+ {
+ std::string ret;
+ return GetStringValue(section, key, &ret) ? std::optional(ret) : default_value;
+ }
+
+ ALWAYS_INLINE void SetOptionalIntValue(const char* section, const char* key, const std::optional& value)
+ {
+ value.has_value() ? SetIntValue(section, key, value.value()) : DeleteValue(section, key);
+ }
+
+ ALWAYS_INLINE void SetOptionalUIntValue(const char* section, const char* key, const std::optional& value)
+ {
+ value.has_value() ? SetUIntValue(section, key, value.value()) : DeleteValue(section, key);
+ }
+
+ ALWAYS_INLINE void SetOptionalFloatValue(const char* section, const char* key, const std::optional& value)
+ {
+ value.has_value() ? SetFloatValue(section, key, value.value()) : DeleteValue(section, key);
+ }
+
+ ALWAYS_INLINE void SetOptionalDoubleValue(const char* section, const char* key, const std::optional& value)
+ {
+ value.has_value() ? SetDoubleValue(section, key, value.value()) : DeleteValue(section, key);
+ }
+
+ ALWAYS_INLINE void SetOptionalBoolValue(const char* section, const char* key, const std::optional& value)
+ {
+ value.has_value() ? SetBoolValue(section, key, value.value()) : DeleteValue(section, key);
+ }
+
+ ALWAYS_INLINE void SetOptionalStringValue(const char* section, const char* key,
+ const std::optional& value)
+ {
+ value.has_value() ? SetStringValue(section, key, value.value()) : DeleteValue(section, key);
+ }
+
+ ALWAYS_INLINE void CopyBoolValue(const SettingsInterface& si, const char* section, const char* key)
+ {
+ bool value;
+ if (si.GetBoolValue(section, key, &value))
+ SetBoolValue(section, key, value);
+ else
+ DeleteValue(section, key);
+ }
+
+ ALWAYS_INLINE void CopyIntValue(const SettingsInterface& si, const char* section, const char* key)
+ {
+ s32 value;
+ if (si.GetIntValue(section, key, &value))
+ SetIntValue(section, key, value);
+ else
+ DeleteValue(section, key);
+ }
+
+ ALWAYS_INLINE void CopyUIntValue(const SettingsInterface& si, const char* section, const char* key)
+ {
+ u32 value;
+ if (si.GetUIntValue(section, key, &value))
+ SetUIntValue(section, key, value);
+ else
+ DeleteValue(section, key);
+ }
+
+ ALWAYS_INLINE void CopyFloatValue(const SettingsInterface& si, const char* section, const char* key)
+ {
+ float value;
+ if (si.GetFloatValue(section, key, &value))
+ SetFloatValue(section, key, value);
+ else
+ DeleteValue(section, key);
+ }
+
+ ALWAYS_INLINE void CopyDoubleValue(const SettingsInterface& si, const char* section, const char* key)
+ {
+ double value;
+ if (si.GetDoubleValue(section, key, &value))
+ SetDoubleValue(section, key, value);
+ else
+ DeleteValue(section, key);
+ }
+
+ ALWAYS_INLINE void CopyStringValue(const SettingsInterface& si, const char* section, const char* key)
+ {
+ std::string value;
+ if (si.GetStringValue(section, key, &value))
+ SetStringValue(section, key, value.c_str());
+ else
+ DeleteValue(section, key);
+ }
+
+ ALWAYS_INLINE void CopyStringListValue(const SettingsInterface& si, const char* section, const char* key)
+ {
+ std::vector value(si.GetStringList(section, key));
+ if (!value.empty())
+ SetStringList(section, key, value);
+ else
+ DeleteValue(section, key);
+ }
+};
diff --git a/src/core/settings.cpp b/src/core/settings.cpp
index 833b6b9f6..93227ca3f 100644
--- a/src/core/settings.cpp
+++ b/src/core/settings.cpp
@@ -12,8 +12,6 @@
Settings g_settings;
-SettingsInterface::~SettingsInterface() = default;
-
const char* SettingInfo::StringDefaultValue() const
{
return default_value ? default_value : "";
diff --git a/src/core/settings.h b/src/core/settings.h
index e837f8b26..bcba2c08f 100644
--- a/src/core/settings.h
+++ b/src/core/settings.h
@@ -1,5 +1,6 @@
#pragma once
#include "common/log.h"
+#include "common/settings_interface.h"
#include "common/string.h"
#include "types.h"
#include
@@ -7,33 +8,6 @@
#include
#include
-class SettingsInterface
-{
-public:
- virtual ~SettingsInterface();
-
- virtual bool Save() = 0;
- virtual void Clear() = 0;
-
- virtual int GetIntValue(const char* section, const char* key, int default_value = 0) = 0;
- virtual float GetFloatValue(const char* section, const char* key, float default_value = 0.0f) = 0;
- virtual bool GetBoolValue(const char* section, const char* key, bool default_value = false) = 0;
- virtual std::string GetStringValue(const char* section, const char* key, const char* default_value = "") = 0;
-
- virtual void SetIntValue(const char* section, const char* key, int value) = 0;
- virtual void SetFloatValue(const char* section, const char* key, float value) = 0;
- virtual void SetBoolValue(const char* section, const char* key, bool value) = 0;
- virtual void SetStringValue(const char* section, const char* key, const char* value) = 0;
-
- virtual std::vector GetStringList(const char* section, const char* key) = 0;
- virtual void SetStringList(const char* section, const char* key, const std::vector& items) = 0;
- virtual bool RemoveFromStringList(const char* section, const char* key, const char* item) = 0;
- virtual bool AddToStringList(const char* section, const char* key, const char* item) = 0;
-
- virtual void DeleteValue(const char* section, const char* key) = 0;
- virtual void ClearSection(const char* section) = 0;
-};
-
struct SettingInfo
{
enum class Type
diff --git a/src/duckstation-regtest/regtest_settings_interface.cpp b/src/duckstation-regtest/regtest_settings_interface.cpp
index e41fa45dd..c7d210d85 100644
--- a/src/duckstation-regtest/regtest_settings_interface.cpp
+++ b/src/duckstation-regtest/regtest_settings_interface.cpp
@@ -23,90 +23,129 @@ static std::string GetFullKey(const char* section, const char* key)
return StringUtil::StdStringFromFormat("%s/%s", section, key);
}
-int RegTestSettingsInterface::GetIntValue(const char* section, const char* key, int default_value /*= 0*/)
+bool RegTestSettingsInterface::GetIntValue(const char* section, const char* key, s32* value) const
{
- int retval = default_value;
-
const std::string fullkey(GetFullKey(section, key));
auto iter = m_keys.find(fullkey);
- if (iter != m_keys.end())
- retval = StringUtil::FromChars(iter->second, 10).value_or(default_value);
+ if (iter == m_keys.end())
+ return false;
- Log_DevPrintf("GetIntValue(%s) -> %d", fullkey.c_str(), retval);
- return retval;
+ std::optional parsed = StringUtil::FromChars(iter->second, 10);
+ if (!parsed.has_value())
+ return false;
+
+ *value = parsed.value();
+ return true;
}
-float RegTestSettingsInterface::GetFloatValue(const char* section, const char* key, float default_value /*= 0.0f*/)
+bool RegTestSettingsInterface::GetUIntValue(const char* section, const char* key, u32* value) const
{
- float retval = default_value;
-
const std::string fullkey(GetFullKey(section, key));
auto iter = m_keys.find(fullkey);
- if (iter != m_keys.end())
- retval = StringUtil::FromChars(iter->second).value_or(default_value);
+ if (iter == m_keys.end())
+ return false;
- Log_DevPrintf("GetFloatValue(%s) -> %f", fullkey.c_str(), retval);
- return retval;
+ std::optional parsed = StringUtil::FromChars(iter->second, 10);
+ if (!parsed.has_value())
+ return false;
+
+ *value = parsed.value();
+ return true;
}
-bool RegTestSettingsInterface::GetBoolValue(const char* section, const char* key, bool default_value /*= false*/)
+bool RegTestSettingsInterface::GetFloatValue(const char* section, const char* key, float* value) const
{
- bool retval = default_value;
-
const std::string fullkey(GetFullKey(section, key));
auto iter = m_keys.find(fullkey);
- if (iter != m_keys.end())
- retval = StringUtil::FromChars(iter->second).value_or(default_value);
+ if (iter == m_keys.end())
+ return false;
- Log_DevPrintf("GetBoolValue(%s) -> %s", fullkey.c_str(), retval ? "true" : "false");
- return retval;
+ std::optional parsed = StringUtil::FromChars(iter->second);
+ if (!parsed.has_value())
+ return false;
+
+ *value = parsed.value();
+ return true;
}
-std::string RegTestSettingsInterface::GetStringValue(const char* section, const char* key,
- const char* default_value /*= ""*/)
+bool RegTestSettingsInterface::GetDoubleValue(const char* section, const char* key, double* value) const
{
- std::string retval;
-
const std::string fullkey(GetFullKey(section, key));
auto iter = m_keys.find(fullkey);
- if (iter != m_keys.end())
- retval = iter->second;
- else
- retval = default_value;
+ if (iter == m_keys.end())
+ return false;
- Log_DevPrintf("GetStringValue(%s) -> %s", fullkey.c_str(), retval.c_str());
- return retval;
+ std::optional parsed = StringUtil::FromChars(iter->second);
+ if (!parsed.has_value())
+ return false;
+
+ *value = parsed.value();
+ return true;
}
-void RegTestSettingsInterface::SetIntValue(const char* section, const char* key, int value)
+bool RegTestSettingsInterface::GetBoolValue(const char* section, const char* key, bool* value) const
+{
+ const std::string fullkey(GetFullKey(section, key));
+ auto iter = m_keys.find(fullkey);
+ if (iter == m_keys.end())
+ return false;
+
+ std::optional parsed = StringUtil::FromChars(iter->second);
+ if (!parsed.has_value())
+ return false;
+
+ *value = parsed.value();
+ return true;
+}
+
+bool RegTestSettingsInterface::GetStringValue(const char* section, const char* key, std::string* value) const
+{
+ const std::string fullkey(GetFullKey(section, key));
+ auto iter = m_keys.find(fullkey);
+ if (iter == m_keys.end())
+ return false;
+
+ *value = iter->second;
+ return true;
+}
+
+void RegTestSettingsInterface::SetIntValue(const char* section, const char* key, s32 value)
+{
+ const std::string fullkey(GetFullKey(section, key));
+ m_keys[std::move(fullkey)] = std::to_string(value);
+}
+
+void RegTestSettingsInterface::SetUIntValue(const char* section, const char* key, u32 value)
{
const std::string fullkey(GetFullKey(section, key));
- Log_DevPrintf("SetIntValue(%s, %d)", fullkey.c_str(), value);
m_keys[std::move(fullkey)] = std::to_string(value);
}
void RegTestSettingsInterface::SetFloatValue(const char* section, const char* key, float value)
{
const std::string fullkey(GetFullKey(section, key));
- Log_DevPrintf("SetFloatValue(%s, %f)", fullkey.c_str(), value);
+ m_keys[std::move(fullkey)] = std::to_string(value);
+}
+
+void RegTestSettingsInterface::SetDoubleValue(const char* section, const char* key, double value)
+{
+ const std::string fullkey(GetFullKey(section, key));
m_keys[std::move(fullkey)] = std::to_string(value);
}
void RegTestSettingsInterface::SetBoolValue(const char* section, const char* key, bool value)
{
const std::string fullkey(GetFullKey(section, key));
- Log_DevPrintf("SetBoolValue(%s, %s)", fullkey.c_str(), value ? "true" : "false");
m_keys[std::move(fullkey)] = std::string(value ? "true" : "false");
}
void RegTestSettingsInterface::SetStringValue(const char* section, const char* key, const char* value)
{
const std::string fullkey(GetFullKey(section, key));
- Log_DevPrintf("SetStringValue(%s, %s)", fullkey.c_str(), value);
m_keys[std::move(fullkey)] = value;
}
-std::vector RegTestSettingsInterface::GetStringList(const char* section, const char* key)
+std::vector RegTestSettingsInterface::GetStringList(const char* section, const char* key) const
{
std::vector ret;
Panic("Not implemented");
@@ -131,10 +170,15 @@ bool RegTestSettingsInterface::AddToStringList(const char* section, const char*
return false;
}
+bool RegTestSettingsInterface::ContainsValue(const char* section, const char* key) const
+{
+ const std::string fullkey(GetFullKey(section, key));
+ return (m_keys.find(fullkey) != m_keys.end());
+}
+
void RegTestSettingsInterface::DeleteValue(const char* section, const char* key)
{
const std::string fullkey(GetFullKey(section, key));
- Log_DevPrintf("DeleteValue(%s)", fullkey.c_str());
auto iter = m_keys.find(fullkey);
if (iter != m_keys.end())
@@ -143,8 +187,6 @@ void RegTestSettingsInterface::DeleteValue(const char* section, const char* key)
void RegTestSettingsInterface::ClearSection(const char* section)
{
- Log_DevPrintf("ClearSection(%s)", section);
-
const std::string start(StringUtil::StdStringFromFormat("%s/", section));
for (auto iter = m_keys.begin(); iter != m_keys.end();)
{
diff --git a/src/duckstation-regtest/regtest_settings_interface.h b/src/duckstation-regtest/regtest_settings_interface.h
index 7f5d312f0..ccbf6930b 100644
--- a/src/duckstation-regtest/regtest_settings_interface.h
+++ b/src/duckstation-regtest/regtest_settings_interface.h
@@ -10,25 +10,38 @@ public:
~RegTestSettingsInterface();
bool Save() override;
+
void Clear() override;
- int GetIntValue(const char* section, const char* key, int default_value = 0) override;
- float GetFloatValue(const char* section, const char* key, float default_value = 0.0f) override;
- bool GetBoolValue(const char* section, const char* key, bool default_value = false) override;
+ bool GetIntValue(const char* section, const char* key, s32* value) const override;
+ bool GetUIntValue(const char* section, const char* key, u32* value) const override;
+ bool GetFloatValue(const char* section, const char* key, float* value) const override;
+ bool GetDoubleValue(const char* section, const char* key, double* value) const override;
+ bool GetBoolValue(const char* section, const char* key, bool* value) const override;
+ bool GetStringValue(const char* section, const char* key, std::string* value) const override;
- std::string GetStringValue(const char* section, const char* key, const char* default_value = "") override;
- void SetIntValue(const char* section, const char* key, int value) override;
+ void SetIntValue(const char* section, const char* key, s32 value) override;
+ void SetUIntValue(const char* section, const char* key, u32 value) override;
void SetFloatValue(const char* section, const char* key, float value) override;
+ void SetDoubleValue(const char* section, const char* key, double value) override;
void SetBoolValue(const char* section, const char* key, bool value) override;
void SetStringValue(const char* section, const char* key, const char* value) override;
+ bool ContainsValue(const char* section, const char* key) const override;
+ void DeleteValue(const char* section, const char* key) override;
+ void ClearSection(const char* section) override;
- std::vector GetStringList(const char* section, const char* key) override;
+ std::vector GetStringList(const char* section, const char* key) const override;
void SetStringList(const char* section, const char* key, const std::vector& items) override;
bool RemoveFromStringList(const char* section, const char* key, const char* item) override;
bool AddToStringList(const char* section, const char* key, const char* item) override;
- void DeleteValue(const char* section, const char* key) override;
- void ClearSection(const char* section) override;
+ // default parameter overloads
+ using SettingsInterface::GetBoolValue;
+ using SettingsInterface::GetDoubleValue;
+ using SettingsInterface::GetFloatValue;
+ using SettingsInterface::GetIntValue;
+ using SettingsInterface::GetStringValue;
+ using SettingsInterface::GetUIntValue;
private:
using KeyMap = std::unordered_map;
diff --git a/src/frontend-common/common_host_interface.cpp b/src/frontend-common/common_host_interface.cpp
index 81408490f..f6c2e8603 100644
--- a/src/frontend-common/common_host_interface.cpp
+++ b/src/frontend-common/common_host_interface.cpp
@@ -2866,10 +2866,9 @@ void CommonHostInterface::ClearAllControllerBindings()
bool CommonHostInterface::ApplyInputProfile(const char* profile_path)
{
- if (!FileSystem::FileExists(profile_path))
- return false;
-
INISettingsInterface profile(profile_path);
+ if (!profile.Load())
+ return false;
std::lock_guard guard(m_settings_mutex);
@@ -2966,7 +2965,6 @@ bool CommonHostInterface::SaveInputProfile(const char* profile_path)
Log_WarningPrintf("Input profile at '%s' does not exist, new input profile will be created", profile_path);
INISettingsInterface profile(profile_path);
- profile.Clear();
for (u32 controller_index = 1; controller_index <= NUM_CONTROLLER_AND_CARD_PORTS; controller_index++)
{
@@ -3309,6 +3307,10 @@ void CommonHostInterface::LoadSettings()
#ifndef __ANDROID__
// we don't check the settings version on android, because it's not using the ini yet..
// we can re-enable this once we move it over.. eventually.
+ const bool loaded = static_cast(m_settings_interface.get())->Load();
+ if (!loaded)
+ SetDefaultSettings(*m_settings_interface);
+
const int settings_version = m_settings_interface->GetIntValue("Main", "SettingsVersion", -1);
if (settings_version != SETTINGS_VERSION)
{
@@ -3876,6 +3878,13 @@ bool CommonHostInterface::UpdateControllerInputMapFromGameSettings()
}
INISettingsInterface si(std::move(path));
+ if (!si.Load())
+ {
+ AddFormattedOSDMessage(10.0f, TranslateString("OSDMessage", "Input profile '%s' cannot be loaded."),
+ gs->input_profile_name.c_str());
+ return false;
+ }
+
UpdateControllerInputMap(si);
return true;
}
diff --git a/src/frontend-common/ini_settings_interface.cpp b/src/frontend-common/ini_settings_interface.cpp
index 35146f828..1bf92cdd5 100644
--- a/src/frontend-common/ini_settings_interface.cpp
+++ b/src/frontend-common/ini_settings_interface.cpp
@@ -1,24 +1,28 @@
+/* PCSX2 - PS2 Emulator for PCs
+ * Copyright (C) 2002-2021 PCSX2 Dev Team
+ *
+ * PCSX2 is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU Lesser General Public License as published by the Free Software Found-
+ * ation, either version 3 of the License, or (at your option) any later version.
+ *
+ * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with PCSX2.
+ * If not, see .
+ */
+
#include "ini_settings_interface.h"
#include "common/file_system.h"
#include "common/log.h"
+#include "common/string_util.h"
#include
#include
Log_SetChannel(INISettingsInterface);
-INISettingsInterface::INISettingsInterface(std::string filename) : m_filename(std::move(filename)), m_ini(true, true)
-{
- SI_Error err = SI_FAIL;
- std::FILE* fp = FileSystem::OpenCFile(m_filename.c_str(), "rb");
- if (fp)
- {
- err = m_ini.LoadFile(fp);
- std::fclose(fp);
- }
-
- if (err != SI_OK)
- Log_WarningPrintf("Settings could not be loaded from '%s', defaults will be used.", m_filename.c_str());
-}
+INISettingsInterface::INISettingsInterface(std::string filename) : m_filename(std::move(filename)), m_ini(true, true) {}
INISettingsInterface::~INISettingsInterface()
{
@@ -26,8 +30,24 @@ INISettingsInterface::~INISettingsInterface()
Save();
}
+bool INISettingsInterface::Load()
+{
+ if (m_filename.empty())
+ return false;
+
+ SI_Error err = SI_FAIL;
+ auto fp = FileSystem::OpenManagedCFile(m_filename.c_str(), "rb");
+ if (fp)
+ err = m_ini.LoadFile(fp.get());
+
+ return (err == SI_OK);
+}
+
bool INISettingsInterface::Save()
{
+ if (m_filename.empty())
+ return false;
+
SI_Error err = SI_FAIL;
std::FILE* fp = FileSystem::OpenCFile(m_filename.c_str(), "wb");
if (fp)
@@ -51,25 +71,84 @@ void INISettingsInterface::Clear()
m_ini.Reset();
}
-int INISettingsInterface::GetIntValue(const char* section, const char* key, int default_value /*= 0*/)
+bool INISettingsInterface::GetIntValue(const char* section, const char* key, s32* value) const
{
- return static_cast(m_ini.GetLongValue(section, key, default_value));
+ const char* str_value = m_ini.GetValue(section, key);
+ if (!str_value)
+ return false;
+
+ std::optional parsed_value = StringUtil::FromChars(str_value, 10);
+ if (!parsed_value.has_value())
+ return false;
+
+ *value = parsed_value.value();
+ return true;
}
-float INISettingsInterface::GetFloatValue(const char* section, const char* key, float default_value /*= 0.0f*/)
+bool INISettingsInterface::GetUIntValue(const char* section, const char* key, u32* value) const
{
- return static_cast(m_ini.GetDoubleValue(section, key, default_value));
+ const char* str_value = m_ini.GetValue(section, key);
+ if (!str_value)
+ return false;
+
+ std::optional parsed_value = StringUtil::FromChars(str_value, 10);
+ if (!parsed_value.has_value())
+ return false;
+
+ *value = parsed_value.value();
+ return true;
}
-bool INISettingsInterface::GetBoolValue(const char* section, const char* key, bool default_value /*= false*/)
+bool INISettingsInterface::GetFloatValue(const char* section, const char* key, float* value) const
{
- return m_ini.GetBoolValue(section, key, default_value);
+ const char* str_value = m_ini.GetValue(section, key);
+ if (!str_value)
+ return false;
+
+ std::optional parsed_value = StringUtil::FromChars(str_value);
+ if (!parsed_value.has_value())
+ return false;
+
+ *value = parsed_value.value();
+ return true;
}
-std::string INISettingsInterface::GetStringValue(const char* section, const char* key,
- const char* default_value /*= ""*/)
+bool INISettingsInterface::GetDoubleValue(const char* section, const char* key, double* value) const
{
- return m_ini.GetValue(section, key, default_value);
+ const char* str_value = m_ini.GetValue(section, key);
+ if (!str_value)
+ return false;
+
+ std::optional parsed_value = StringUtil::FromChars(str_value);
+ if (!parsed_value.has_value())
+ return false;
+
+ *value = parsed_value.value();
+ return true;
+}
+
+bool INISettingsInterface::GetBoolValue(const char* section, const char* key, bool* value) const
+{
+ const char* str_value = m_ini.GetValue(section, key);
+ if (!str_value)
+ return false;
+
+ std::optional parsed_value = StringUtil::FromChars(str_value);
+ if (!parsed_value.has_value())
+ return false;
+
+ *value = parsed_value.value();
+ return true;
+}
+
+bool INISettingsInterface::GetStringValue(const char* section, const char* key, std::string* value) const
+{
+ const char* str_value = m_ini.GetValue(section, key);
+ if (!str_value)
+ return false;
+
+ value->assign(str_value);
+ return true;
}
void INISettingsInterface::SetIntValue(const char* section, const char* key, int value)
@@ -78,12 +157,24 @@ void INISettingsInterface::SetIntValue(const char* section, const char* key, int
m_ini.SetLongValue(section, key, static_cast(value), nullptr, false, true);
}
+void INISettingsInterface::SetUIntValue(const char* section, const char* key, u32 value)
+{
+ m_dirty = true;
+ m_ini.SetLongValue(section, key, static_cast(value), nullptr, false, true);
+}
+
void INISettingsInterface::SetFloatValue(const char* section, const char* key, float value)
{
m_dirty = true;
m_ini.SetDoubleValue(section, key, static_cast(value), nullptr, true);
}
+void INISettingsInterface::SetDoubleValue(const char* section, const char* key, double value)
+{
+ m_dirty = true;
+ m_ini.SetDoubleValue(section, key, value, nullptr, true);
+}
+
void INISettingsInterface::SetBoolValue(const char* section, const char* key, bool value)
{
m_dirty = true;
@@ -96,6 +187,11 @@ void INISettingsInterface::SetStringValue(const char* section, const char* key,
m_ini.SetValue(section, key, value, nullptr, true);
}
+bool INISettingsInterface::ContainsValue(const char* section, const char* key) const
+{
+ return (m_ini.GetValue(section, key, nullptr) != nullptr);
+}
+
void INISettingsInterface::DeleteValue(const char* section, const char* key)
{
m_dirty = true;
@@ -109,7 +205,7 @@ void INISettingsInterface::ClearSection(const char* section)
m_ini.SetValue(section, nullptr, nullptr);
}
-std::vector INISettingsInterface::GetStringList(const char* section, const char* key)
+std::vector INISettingsInterface::GetStringList(const char* section, const char* key) const
{
std::list entries;
if (!m_ini.GetAllValues(section, key, entries))
@@ -117,8 +213,8 @@ std::vector INISettingsInterface::GetStringList(const char* section
std::vector ret;
ret.reserve(entries.size());
- std::transform(entries.begin(), entries.end(), std::back_inserter(ret),
- [](const CSimpleIniA::Entry& it) { return std::string(it.pItem); });
+ for (const CSimpleIniA::Entry& entry : entries)
+ ret.emplace_back(entry.pItem);
return ret;
}
diff --git a/src/frontend-common/ini_settings_interface.h b/src/frontend-common/ini_settings_interface.h
index 2faa3ed6e..09bf62e76 100644
--- a/src/frontend-common/ini_settings_interface.h
+++ b/src/frontend-common/ini_settings_interface.h
@@ -1,5 +1,20 @@
+/* PCSX2 - PS2 Emulator for PCs
+ * Copyright (C) 2002-2021 PCSX2 Dev Team
+ *
+ * PCSX2 is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU Lesser General Public License as published by the Free Software Found-
+ * ation, either version 3 of the License, or (at your option) any later version.
+ *
+ * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with PCSX2.
+ * If not, see .
+ */
+
#pragma once
-#include "core/settings.h"
+#include "common/settings_interface.h"
// being a pain here...
#ifdef _WIN32
@@ -13,27 +28,43 @@ public:
INISettingsInterface(std::string filename);
~INISettingsInterface() override;
+ const std::string& GetFileName() const { return m_filename; }
+
+ bool Load();
bool Save() override;
void Clear() override;
- int GetIntValue(const char* section, const char* key, int default_value = 0) override;
- float GetFloatValue(const char* section, const char* key, float default_value = 0.0f) override;
- bool GetBoolValue(const char* section, const char* key, bool default_value = false) override;
- std::string GetStringValue(const char* section, const char* key, const char* default_value = "") override;
+ bool GetIntValue(const char* section, const char* key, s32* value) const override;
+ bool GetUIntValue(const char* section, const char* key, u32* value) const override;
+ bool GetFloatValue(const char* section, const char* key, float* value) const override;
+ bool GetDoubleValue(const char* section, const char* key, double* value) const override;
+ bool GetBoolValue(const char* section, const char* key, bool* value) const override;
+ bool GetStringValue(const char* section, const char* key, std::string* value) const override;
- void SetIntValue(const char* section, const char* key, int value) override;
+ void SetIntValue(const char* section, const char* key, s32 value) override;
+ void SetUIntValue(const char* section, const char* key, u32 value) override;
void SetFloatValue(const char* section, const char* key, float value) override;
+ void SetDoubleValue(const char* section, const char* key, double value) override;
void SetBoolValue(const char* section, const char* key, bool value) override;
void SetStringValue(const char* section, const char* key, const char* value) override;
+ bool ContainsValue(const char* section, const char* key) const override;
void DeleteValue(const char* section, const char* key) override;
void ClearSection(const char* section) override;
- std::vector GetStringList(const char* section, const char* key) override;
+ std::vector GetStringList(const char* section, const char* key) const override;
void SetStringList(const char* section, const char* key, const std::vector& items) override;
bool RemoveFromStringList(const char* section, const char* key, const char* item) override;
bool AddToStringList(const char* section, const char* key, const char* item) override;
+ // default parameter overloads
+ using SettingsInterface::GetBoolValue;
+ using SettingsInterface::GetDoubleValue;
+ using SettingsInterface::GetFloatValue;
+ using SettingsInterface::GetIntValue;
+ using SettingsInterface::GetStringValue;
+ using SettingsInterface::GetUIntValue;
+
private:
std::string m_filename;
CSimpleIniA m_ini;