From 6a6ab6529a253b1fd56b30ee2ed6cab9ad95fd70 Mon Sep 17 00:00:00 2001 From: Connor McLaughlin Date: Sat, 9 Jul 2022 00:14:48 +1000 Subject: [PATCH] Backport SettingsInterface --- src/common/CMakeLists.txt | 3 + src/common/common.vcxproj | 3 + src/common/common.vcxproj.filters | 3 + src/common/layered_settings_interface.cpp | 189 ++++++++++++++++ src/common/layered_settings_interface.h | 62 +++++ src/common/settings_interface.h | 213 ++++++++++++++++++ src/core/settings.cpp | 2 - src/core/settings.h | 28 +-- .../regtest_settings_interface.cpp | 122 ++++++---- .../regtest_settings_interface.h | 29 ++- src/frontend-common/common_host_interface.cpp | 17 +- .../ini_settings_interface.cpp | 146 ++++++++++-- src/frontend-common/ini_settings_interface.h | 45 +++- 13 files changed, 749 insertions(+), 113 deletions(-) create mode 100644 src/common/layered_settings_interface.cpp create mode 100644 src/common/layered_settings_interface.h create mode 100644 src/common/settings_interface.h 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;