mirror of
https://github.com/FEX-Emu/FEX.git
synced 2026-10-06 17:00:19 +02:00
Merge pull request #5388 from Sonicadvance1/123
Config: Finish wiring up Regex app overrides
This commit is contained in:
7 files changed
+133
-31
No files matched your search
@@ -6,7 +6,8 @@ set(FEXCORE_BASE_SRCS
|
||||
Utils/FileLoading.cpp
|
||||
Utils/ForcedAssert.cpp
|
||||
Utils/LogManager.cpp
|
||||
Utils/SpinWaitLock.cpp)
|
||||
Utils/SpinWaitLock.cpp
|
||||
Utils/WildcardMatcher.cpp)
|
||||
|
||||
if (NOT MINGW)
|
||||
list(APPEND FEXCORE_BASE_SRCS
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#include <FEXCore/Utils/WildcardMatcher.h>
|
||||
|
||||
namespace FEXCore::Utils::Wildcard {
|
||||
static bool matchHelper(std::string_view pattern, std::string_view text, size_t p_idx, size_t t_idx) {
|
||||
if (p_idx == pattern.size()) {
|
||||
// Pattern exhausted
|
||||
return (t_idx == text.size());
|
||||
} else if (pattern[p_idx] == '*') {
|
||||
// Wildcard: Try matching zero characters, or one or more characters
|
||||
return matchHelper(pattern, text, p_idx + 1, t_idx) || (t_idx < text.size() && matchHelper(pattern, text, p_idx, t_idx + 1));
|
||||
} else {
|
||||
// Match normally
|
||||
return (t_idx < text.size() && pattern[p_idx] == text[t_idx] && matchHelper(pattern, text, p_idx + 1, t_idx + 1));
|
||||
}
|
||||
}
|
||||
|
||||
bool Matches(std::string_view pattern, std::string_view text) {
|
||||
return matchHelper(pattern, text, 0, 0);
|
||||
}
|
||||
|
||||
} // namespace FEXCore::Utils::Wildcard
|
||||
@@ -0,0 +1,8 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
#include <string_view>
|
||||
|
||||
namespace FEXCore::Utils::Wildcard {
|
||||
bool Matches(std::string_view pattern, std::string_view text);
|
||||
} // namespace FEXCore::Utils::Wildcard
|
||||
+48
-27
@@ -7,11 +7,12 @@
|
||||
#include <FEXCore/fextl/fmt.h>
|
||||
#include <FEXCore/fextl/map.h>
|
||||
#include <FEXCore/fextl/string.h>
|
||||
#include <FEXCore/fextl/vector.h>
|
||||
#include <FEXCore/Utils/Allocator.h>
|
||||
#include <FEXCore/Utils/FileLoading.h>
|
||||
#include <FEXCore/Utils/WildcardMatcher.h>
|
||||
#include <FEXHeaderUtils/Filesystem.h>
|
||||
#include <FEXHeaderUtils/SymlinkChecks.h>
|
||||
|
||||
#include <cstring>
|
||||
#include <fmt/format.h>
|
||||
#include <functional>
|
||||
@@ -28,7 +29,8 @@
|
||||
|
||||
namespace FEX::Config {
|
||||
namespace JSON {
|
||||
static void LoadJSonConfig(const fextl::string& Config, std::function<void(const char* Name, const char* ConfigSring)> Func) {
|
||||
static void LoadJSonConfig(const fextl::string& Config, std::optional<fextl::string> AppName,
|
||||
std::function<void(const char* Name, const char* ConfigString)> Func) {
|
||||
fextl::vector<char> Data;
|
||||
if (!FEXCore::FileLoading::LoadFile(Data, Config)) {
|
||||
return;
|
||||
@@ -48,21 +50,35 @@ namespace JSON {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const json_t* ConfigItem = json_getChild(ConfigList); ConfigItem != nullptr; ConfigItem = json_getSibling(ConfigItem)) {
|
||||
const char* ConfigName = json_getName(ConfigItem);
|
||||
const char* ConfigString = json_getValue(ConfigItem);
|
||||
fextl::vector<const json_t*> ConfigBlocks;
|
||||
ConfigBlocks.push_back(ConfigList);
|
||||
|
||||
if (!ConfigName) {
|
||||
LogMan::Msg::EFmt("JSON file '{}': Couldn't get config name for an item", Config);
|
||||
return;
|
||||
if (AppName) {
|
||||
const json_t* OverrideList = json_getProperty(json, "AppOverrides");
|
||||
if (OverrideList) {
|
||||
for (const json_t* Item = json_getChild(OverrideList); Item != nullptr; Item = json_getSibling(Item)) {
|
||||
const char* AppPattern = json_getName(Item);
|
||||
|
||||
// Find the first match, then break
|
||||
if (FEXCore::Utils::Wildcard::Matches(AppPattern, *AppName)) {
|
||||
ConfigBlocks.push_back(Item);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!ConfigString) {
|
||||
LogMan::Msg::EFmt("JSON file '{}': Couldn't get value for config item '{}'", Config, ConfigName);
|
||||
return;
|
||||
for (auto ConfigBlock : ConfigBlocks) {
|
||||
for (const json_t* ConfigItem = json_getChild(ConfigBlock); ConfigItem != nullptr; ConfigItem = json_getSibling(ConfigItem)) {
|
||||
const char* ConfigName = json_getName(ConfigItem);
|
||||
const char* ConfigString = json_getValue(ConfigItem);
|
||||
|
||||
if (!ConfigString) {
|
||||
LogMan::Msg::EFmt("JSON file '{}': Couldn't get value for config item '{}'", Config, ConfigName);
|
||||
return;
|
||||
}
|
||||
Func(ConfigName, ConfigString);
|
||||
}
|
||||
|
||||
Func(ConfigName, ConfigString);
|
||||
}
|
||||
}
|
||||
} // namespace JSON
|
||||
@@ -167,22 +183,24 @@ protected:
|
||||
|
||||
class MainLoader final : public OptionMapper {
|
||||
public:
|
||||
explicit MainLoader(FEXCore::Config::LayerType Type);
|
||||
explicit MainLoader(fextl::string ConfigFile);
|
||||
explicit MainLoader(FEXCore::Config::LayerType Type, std::optional<fextl::string> AppName = std::nullopt);
|
||||
explicit MainLoader(fextl::string ConfigFile, std::optional<fextl::string> AppName = std::nullopt);
|
||||
explicit MainLoader(FEXCore::Config::LayerType Type, std::string_view ConfigFile);
|
||||
|
||||
void Load() override;
|
||||
|
||||
private:
|
||||
std::optional<fextl::string> AppName;
|
||||
fextl::string Config;
|
||||
};
|
||||
|
||||
class AppLoader final : public OptionMapper {
|
||||
public:
|
||||
explicit AppLoader(const fextl::string& Filename, FEXCore::Config::LayerType Type);
|
||||
explicit AppLoader(const fextl::string& AppName, FEXCore::Config::LayerType Type);
|
||||
void Load();
|
||||
|
||||
private:
|
||||
const fextl::string AppName;
|
||||
fextl::string Config;
|
||||
};
|
||||
|
||||
@@ -221,12 +239,14 @@ void OptionMapper::MapNameToOption(const char* ConfigName, const char* ConfigStr
|
||||
#include <FEXCore/Config/ConfigOptions.inl>
|
||||
}
|
||||
|
||||
MainLoader::MainLoader(FEXCore::Config::LayerType Type)
|
||||
MainLoader::MainLoader(FEXCore::Config::LayerType Type, std::optional<fextl::string> AppName)
|
||||
: OptionMapper(Type)
|
||||
, AppName {AppName}
|
||||
, Config {FEXCore::Config::GetConfigFileLocation(Type == FEXCore::Config::LayerType::LAYER_GLOBAL_MAIN)} {}
|
||||
|
||||
MainLoader::MainLoader(fextl::string ConfigFile)
|
||||
MainLoader::MainLoader(fextl::string ConfigFile, std::optional<fextl::string> AppName)
|
||||
: OptionMapper(FEXCore::Config::LayerType::LAYER_MAIN)
|
||||
, AppName {AppName}
|
||||
, Config {std::move(ConfigFile)} {}
|
||||
|
||||
|
||||
@@ -236,13 +256,14 @@ MainLoader::MainLoader(FEXCore::Config::LayerType Type, std::string_view ConfigF
|
||||
|
||||
void MainLoader::Load() {
|
||||
SetCurrentConfigFile(Config);
|
||||
JSON::LoadJSonConfig(Config, [this](const char* Name, const char* ConfigString) { MapNameToOption(Name, ConfigString); });
|
||||
JSON::LoadJSonConfig(Config, AppName, [this](const char* Name, const char* ConfigString) { MapNameToOption(Name, ConfigString); });
|
||||
}
|
||||
|
||||
AppLoader::AppLoader(const fextl::string& Filename, FEXCore::Config::LayerType Type)
|
||||
: OptionMapper(Type) {
|
||||
AppLoader::AppLoader(const fextl::string& AppName, FEXCore::Config::LayerType Type)
|
||||
: OptionMapper(Type)
|
||||
, AppName {AppName} {
|
||||
const bool Global = Type == FEXCore::Config::LayerType::LAYER_GLOBAL_STEAM_APP || Type == FEXCore::Config::LayerType::LAYER_GLOBAL_APP;
|
||||
Config = FEXCore::Config::GetApplicationConfig(Filename, Global);
|
||||
Config = FEXCore::Config::GetApplicationConfig(AppName, Global);
|
||||
|
||||
// Immediately load so we can reload the meta layer
|
||||
Load();
|
||||
@@ -250,7 +271,7 @@ AppLoader::AppLoader(const fextl::string& Filename, FEXCore::Config::LayerType T
|
||||
|
||||
void AppLoader::Load() {
|
||||
SetCurrentConfigFile(Config);
|
||||
JSON::LoadJSonConfig(Config, [this](const char* Name, const char* ConfigString) { MapNameToOption(Name, ConfigString); });
|
||||
JSON::LoadJSonConfig(Config, AppName, [this](const char* Name, const char* ConfigString) { MapNameToOption(Name, ConfigString); });
|
||||
}
|
||||
|
||||
EnvLoader::EnvLoader(char* const _envp[])
|
||||
@@ -320,11 +341,11 @@ fextl::unique_ptr<FEXCore::Config::Layer> CreateGlobalMainLayer() {
|
||||
return fextl::make_unique<MainLoader>(FEXCore::Config::LayerType::LAYER_GLOBAL_MAIN);
|
||||
}
|
||||
|
||||
fextl::unique_ptr<FEXCore::Config::Layer> CreateMainLayer(const fextl::string* File) {
|
||||
fextl::unique_ptr<FEXCore::Config::Layer> CreateMainLayer(const fextl::string* File, std::optional<fextl::string> AppName) {
|
||||
if (File) {
|
||||
return fextl::make_unique<MainLoader>(*File);
|
||||
return fextl::make_unique<MainLoader>(*File, std::move(AppName));
|
||||
} else {
|
||||
return fextl::make_unique<MainLoader>(FEXCore::Config::LayerType::LAYER_MAIN);
|
||||
return fextl::make_unique<MainLoader>(FEXCore::Config::LayerType::LAYER_MAIN, std::move(AppName));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -461,7 +482,7 @@ void LoadConfig(fextl::string ProgramName, char** const envp, const PortableInfo
|
||||
if (!IsPortable) {
|
||||
FEXCore::Config::AddLayer(CreateGlobalMainLayer());
|
||||
}
|
||||
FEXCore::Config::AddLayer(CreateMainLayer());
|
||||
FEXCore::Config::AddLayer(CreateMainLayer(nullptr, ProgramName.empty() ? std::nullopt : std::optional {ProgramName}));
|
||||
|
||||
if (!ProgramName.empty()) {
|
||||
if (!IsPortable) {
|
||||
|
||||
@@ -81,7 +81,7 @@ fextl::unique_ptr<FEXCore::Config::Layer> CreateGlobalMainLayer();
|
||||
*
|
||||
* @return unique_ptr for that layer
|
||||
*/
|
||||
fextl::unique_ptr<FEXCore::Config::Layer> CreateMainLayer(const fextl::string* File = nullptr);
|
||||
fextl::unique_ptr<FEXCore::Config::Layer> CreateMainLayer(const fextl::string* File = nullptr, std::optional<fextl::string> AppName = std::nullopt);
|
||||
fextl::unique_ptr<FEXCore::Config::Layer> CreateUserOverrideLayer(std::string_view AppConfig);
|
||||
|
||||
/**
|
||||
|
||||
@@ -6,9 +6,10 @@ set(TESTS
|
||||
FileMappingBaseAddress
|
||||
Filesystem
|
||||
InterruptableConditionVariable
|
||||
StringUtils)
|
||||
StringUtils
|
||||
WildcardMatcher)
|
||||
|
||||
list(APPEND LIBS Common FEXCore JemallocLibs)
|
||||
list(APPEND LIBS Common FEXCore FEXCore_Base JemallocLibs)
|
||||
|
||||
foreach(API_TEST ${TESTS})
|
||||
add_executable(${API_TEST} ${API_TEST}.cpp)
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
#include <FEXCore/fextl/string.h>
|
||||
#include <FEXCore/Utils/Allocator.h>
|
||||
#include <FEXCore/Utils/WildcardMatcher.h>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
using namespace FEXCore::Utils::Wildcard;
|
||||
|
||||
TEST_CASE("Singular regex") {
|
||||
CHECK(Matches("a", "a"));
|
||||
CHECK(Matches("a*", "a*"));
|
||||
CHECK(Matches("a*", "aaaaaaa"));
|
||||
}
|
||||
|
||||
TEST_CASE("Concat regex") {
|
||||
CHECK(Matches("aaa", "aaa"));
|
||||
CHECK(Matches("ab", "ab"));
|
||||
CHECK(!Matches("a", "ab"));
|
||||
CHECK(!Matches("ab", "a"));
|
||||
}
|
||||
TEST_CASE("Wildcard beginning end") {
|
||||
CHECK(Matches("a*", "a"));
|
||||
CHECK(Matches("*a", "a"));
|
||||
CHECK(Matches("*a*", "a"));
|
||||
}
|
||||
TEST_CASE("Wildcard middle") {
|
||||
CHECK(Matches("test*pattern", "test__pattern"));
|
||||
}
|
||||
|
||||
TEST_CASE("Wildcard mult") {
|
||||
CHECK(Matches("test*pattern*more", "test__pattern__more"));
|
||||
CHECK(Matches("test**pattern", "test_pattern"));
|
||||
}
|
||||
|
||||
TEST_CASE("Wildcard regex simple") {
|
||||
CHECK(Matches("*", ""));
|
||||
CHECK(Matches("*", "setup.json"));
|
||||
CHECK(Matches("test*pattern", "test__pattern"));
|
||||
CHECK(!Matches("setup.*", "setupjson"));
|
||||
CHECK(Matches("setup*", "setup.json"));
|
||||
CHECK(Matches("setup*", "setup/setup.json"));
|
||||
CHECK(Matches("*setup*", "setup/setup.json"));
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE("FEX regex") {
|
||||
CHECK(Matches("*Config*", "/home/ubuntu/.fex-emu/Config.json"));
|
||||
CHECK(Matches("*Config.json", "/home/ubuntu/.fex-emu/Config.json"));
|
||||
}
|
||||
Reference in new issue
Block a user