77#include < FEXCore/fextl/fmt.h>
88#include < FEXCore/fextl/map.h>
99#include < FEXCore/fextl/string.h>
10+ #include < FEXCore/fextl/vector.h>
1011#include < FEXCore/Utils/Allocator.h>
1112#include < FEXCore/Utils/FileLoading.h>
13+ #include < FEXCore/Utils/WildcardMatcher.h>
1214#include < FEXHeaderUtils/Filesystem.h>
1315#include < FEXHeaderUtils/SymlinkChecks.h>
14-
1516#include < cstring>
1617#include < fmt/format.h>
1718#include < functional>
2829
2930namespace FEX ::Config {
3031namespace JSON {
31- static void LoadJSonConfig (const fextl::string& Config, std::function<void (const char * Name, const char * ConfigSring)> Func) {
32+ static void LoadJSonConfig (const fextl::string& Config, std::optional<fextl::string> AppName,
33+ std::function<void (const char * Name, const char * ConfigString)> Func) {
3234 fextl::vector<char > Data;
3335 if (!FEXCore::FileLoading::LoadFile (Data, Config)) {
3436 return ;
@@ -48,21 +50,35 @@ namespace JSON {
4850 return ;
4951 }
5052
51- for (const json_t * ConfigItem = json_getChild (ConfigList); ConfigItem != nullptr ; ConfigItem = json_getSibling (ConfigItem)) {
52- const char * ConfigName = json_getName (ConfigItem);
53- const char * ConfigString = json_getValue (ConfigItem);
53+ fextl::vector<const json_t *> ConfigBlocks;
54+ ConfigBlocks.push_back (ConfigList);
5455
55- if (!ConfigName) {
56- LogMan::Msg::EFmt (" JSON file '{}': Couldn't get config name for an item" , Config);
57- return ;
58- }
56+ if (AppName) {
57+ const json_t * OverrideList = json_getProperty (json, " AppOverrides" );
58+ if (OverrideList) {
59+ for (const json_t * Item = json_getChild (OverrideList); Item != nullptr ; Item = json_getSibling (Item)) {
60+ const char * AppPattern = json_getName (Item);
5961
60- if (!ConfigString) {
61- LogMan::Msg::EFmt (" JSON file '{}': Couldn't get value for config item '{}'" , Config, ConfigName);
62- return ;
62+ // Find the first match, then break
63+ if (FEXCore::Utils::Wildcard::Matches (AppPattern, *AppName)) {
64+ ConfigBlocks.push_back (Item);
65+ break ;
66+ }
67+ }
6368 }
69+ }
6470
65- Func (ConfigName, ConfigString);
71+ for (auto ConfigBlock : ConfigBlocks) {
72+ for (const json_t * ConfigItem = json_getChild (ConfigBlock); ConfigItem != nullptr ; ConfigItem = json_getSibling (ConfigItem)) {
73+ const char * ConfigName = json_getName (ConfigItem);
74+ const char * ConfigString = json_getValue (ConfigItem);
75+
76+ if (!ConfigString) {
77+ LogMan::Msg::EFmt (" JSON file '{}': Couldn't get value for config item '{}'" , Config, ConfigName);
78+ return ;
79+ }
80+ Func (ConfigName, ConfigString);
81+ }
6682 }
6783 }
6884} // namespace JSON
@@ -167,22 +183,24 @@ class OptionMapper : public FEXCore::Config::Layer {
167183
168184class MainLoader final : public OptionMapper {
169185public:
170- explicit MainLoader (FEXCore::Config::LayerType Type);
171- explicit MainLoader (fextl::string ConfigFile);
186+ explicit MainLoader (FEXCore::Config::LayerType Type, std::optional<fextl::string> AppName = std:: nullopt );
187+ explicit MainLoader (fextl::string ConfigFile, std::optional<fextl::string> AppName = std:: nullopt );
172188 explicit MainLoader (FEXCore::Config::LayerType Type, std::string_view ConfigFile);
173189
174190 void Load () override ;
175191
176192private:
193+ std::optional<fextl::string> AppName;
177194 fextl::string Config;
178195};
179196
180197class AppLoader final : public OptionMapper {
181198public:
182- explicit AppLoader (const fextl::string& Filename , FEXCore::Config::LayerType Type);
199+ explicit AppLoader (const fextl::string& AppName , FEXCore::Config::LayerType Type);
183200 void Load ();
184201
185202private:
203+ const fextl::string AppName;
186204 fextl::string Config;
187205};
188206
@@ -221,12 +239,14 @@ void OptionMapper::MapNameToOption(const char* ConfigName, const char* ConfigStr
221239#include < FEXCore/Config/ConfigOptions.inl>
222240}
223241
224- MainLoader::MainLoader (FEXCore::Config::LayerType Type)
242+ MainLoader::MainLoader (FEXCore::Config::LayerType Type, std::optional<fextl::string> AppName )
225243 : OptionMapper(Type)
244+ , AppName {AppName}
226245 , Config {FEXCore::Config::GetConfigFileLocation (Type == FEXCore::Config::LayerType::LAYER_GLOBAL_MAIN)} {}
227246
228- MainLoader::MainLoader (fextl::string ConfigFile)
247+ MainLoader::MainLoader (fextl::string ConfigFile, std::optional<fextl::string> AppName )
229248 : OptionMapper(FEXCore::Config::LayerType::LAYER_MAIN)
249+ , AppName {AppName}
230250 , Config {std::move (ConfigFile)} {}
231251
232252
@@ -236,21 +256,22 @@ MainLoader::MainLoader(FEXCore::Config::LayerType Type, std::string_view ConfigF
236256
237257void MainLoader::Load () {
238258 SetCurrentConfigFile (Config);
239- JSON::LoadJSonConfig (Config, [this ](const char * Name, const char * ConfigString) { MapNameToOption (Name, ConfigString); });
259+ JSON::LoadJSonConfig (Config, AppName, [this ](const char * Name, const char * ConfigString) { MapNameToOption (Name, ConfigString); });
240260}
241261
242- AppLoader::AppLoader (const fextl::string& Filename, FEXCore::Config::LayerType Type)
243- : OptionMapper(Type) {
262+ AppLoader::AppLoader (const fextl::string& AppName, FEXCore::Config::LayerType Type)
263+ : OptionMapper(Type)
264+ , AppName {AppName} {
244265 const bool Global = Type == FEXCore::Config::LayerType::LAYER_GLOBAL_STEAM_APP || Type == FEXCore::Config::LayerType::LAYER_GLOBAL_APP;
245- Config = FEXCore::Config::GetApplicationConfig (Filename , Global);
266+ Config = FEXCore::Config::GetApplicationConfig (AppName , Global);
246267
247268 // Immediately load so we can reload the meta layer
248269 Load ();
249270}
250271
251272void AppLoader::Load () {
252273 SetCurrentConfigFile (Config);
253- JSON::LoadJSonConfig (Config, [this ](const char * Name, const char * ConfigString) { MapNameToOption (Name, ConfigString); });
274+ JSON::LoadJSonConfig (Config, AppName, [this ](const char * Name, const char * ConfigString) { MapNameToOption (Name, ConfigString); });
254275}
255276
256277EnvLoader::EnvLoader (char * const _envp[])
@@ -320,11 +341,11 @@ fextl::unique_ptr<FEXCore::Config::Layer> CreateGlobalMainLayer() {
320341 return fextl::make_unique<MainLoader>(FEXCore::Config::LayerType::LAYER_GLOBAL_MAIN);
321342}
322343
323- fextl::unique_ptr<FEXCore::Config::Layer> CreateMainLayer (const fextl::string* File) {
344+ fextl::unique_ptr<FEXCore::Config::Layer> CreateMainLayer (const fextl::string* File, std::optional<fextl::string> AppName ) {
324345 if (File) {
325- return fextl::make_unique<MainLoader>(*File);
346+ return fextl::make_unique<MainLoader>(*File, std::move (AppName) );
326347 } else {
327- return fextl::make_unique<MainLoader>(FEXCore::Config::LayerType::LAYER_MAIN);
348+ return fextl::make_unique<MainLoader>(FEXCore::Config::LayerType::LAYER_MAIN, std::move (AppName) );
328349 }
329350}
330351
@@ -461,7 +482,7 @@ void LoadConfig(fextl::string ProgramName, char** const envp, const PortableInfo
461482 if (!IsPortable) {
462483 FEXCore::Config::AddLayer (CreateGlobalMainLayer ());
463484 }
464- FEXCore::Config::AddLayer (CreateMainLayer ());
485+ FEXCore::Config::AddLayer (CreateMainLayer (nullptr , ProgramName. empty () ? std:: nullopt : std::optional {ProgramName} ));
465486
466487 if (!ProgramName.empty ()) {
467488 if (!IsPortable) {
0 commit comments