Skip to content

Commit 81d4e8f

Browse files
badumbatishSonicadvance1
authored andcommitted
Initial implementation for regex engine
Add support for question mark and plus mark in regex, supply testing for star Added more characters to the regex alphabets, add more test case Added support for regex matching of configs, awaiting reviews Rename variable to CamelCase Addresses PR reviews Remove unnecessary features and test cases Rewrite to naive regex with dp Addresses PR reviews Build fixes Code Review
1 parent 5b4a596 commit 81d4e8f

6 files changed

Lines changed: 140 additions & 16 deletions

File tree

FEXCore/Source/CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ set(FEXCORE_BASE_SRCS
66
Utils/FileLoading.cpp
77
Utils/ForcedAssert.cpp
88
Utils/LogManager.cpp
9-
Utils/SpinWaitLock.cpp)
9+
Utils/SpinWaitLock.cpp
10+
Utils/WildcardMatcher.cpp)
1011

1112
if (NOT MINGW)
1213
list(APPEND FEXCORE_BASE_SRCS
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// SPDX-License-Identifier: MIT
2+
3+
#include <FEXCore/Utils/WildcardMatcher.h>
4+
5+
namespace FEXCore::Utils::Wildcard {
6+
class WildcardMatcher {
7+
private:
8+
std::string_view pattern;
9+
std::string_view text;
10+
11+
public:
12+
WildcardMatcher(std::string_view pattern, std::string_view text)
13+
: pattern(pattern)
14+
, text(text) {}
15+
16+
bool matchHelper(size_t p_idx, size_t t_idx);
17+
};
18+
19+
bool WildcardMatcher::matchHelper(size_t p_idx, size_t t_idx) {
20+
if (p_idx == pattern.size()) {
21+
// Pattern exhausted
22+
return (t_idx == text.size());
23+
} else if (pattern[p_idx] == '*') {
24+
// Wildcard: Try matching zero characters, or one or more characters
25+
return matchHelper(p_idx + 1, t_idx) || (t_idx < text.size() && matchHelper(p_idx, t_idx + 1));
26+
} else {
27+
// Match normally
28+
return (t_idx < text.size() && pattern[p_idx] == text[t_idx] && matchHelper(p_idx + 1, t_idx + 1));
29+
}
30+
}
31+
32+
bool Matches(std::string_view pattern, std::string_view text) {
33+
WildcardMatcher matcher(pattern, text);
34+
return matcher.matchHelper(0, 0);
35+
}
36+
37+
} // namespace FEXCore::Utils::Wildcard
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// SPDX-License-Identifier: MIT
2+
3+
#pragma once
4+
#include <string_view>
5+
6+
namespace FEXCore::Utils::Wildcard {
7+
bool Matches(std::string_view pattern, std::string_view text);
8+
} // namespace FEXCore::Utils::Wildcard

Source/Common/Config.cpp

Lines changed: 42 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,12 @@
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>
@@ -28,7 +29,7 @@
2829

2930
namespace FEX::Config {
3031
namespace 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::function<void(const char* Name, const char* ConfigString)> Func) {
3233
fextl::vector<char> Data;
3334
if (!FEXCore::FileLoading::LoadFile(Data, Config)) {
3435
return;
@@ -48,21 +49,49 @@ namespace JSON {
4849
return;
4950
}
5051

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);
52+
fextl::vector<const json_t*> ConfigBlocks;
53+
ConfigBlocks.push_back(ConfigList);
5454

55-
if (!ConfigName) {
56-
LogMan::Msg::EFmt("JSON file '{}': Couldn't get config name for an item", Config);
57-
return;
58-
}
55+
const json_t* OverrideList = json_getProperty(json, "AppOverrides");
56+
if (OverrideList) {
57+
for (const json_t* Item = json_getChild(OverrideList); Item != nullptr; Item = json_getSibling(Item)) {
58+
const char* ItemName = json_getName(Item);
59+
const json_t* OverrideNamedList = json_getProperty(OverrideList, ItemName);
60+
61+
if (!ItemName) {
62+
LogMan::Msg::EFmt("JSON file '{}': Couldn't get config name for an item", Config);
63+
break;
64+
}
5965

60-
if (!ConfigString) {
61-
LogMan::Msg::EFmt("JSON file '{}': Couldn't get value for config item '{}'", Config, ConfigName);
62-
return;
66+
if (!OverrideNamedList) {
67+
LogMan::Msg::EFmt("JSON file '{}': Couldn't get value for config item '{}'", Config, ItemName);
68+
break;
69+
}
70+
71+
// Find the first match, then break
72+
if (FEXCore::Utils::Wildcard::Matches(ItemName, Config)) {
73+
ConfigBlocks.push_back(OverrideNamedList);
74+
break;
75+
}
6376
}
77+
}
78+
79+
for (auto ConfigBlock : ConfigBlocks) {
80+
for (const json_t* ConfigItem = json_getChild(ConfigBlock); ConfigItem != nullptr; ConfigItem = json_getSibling(ConfigItem)) {
81+
const char* ConfigName = json_getName(ConfigItem);
82+
const char* ConfigString = json_getValue(ConfigItem);
83+
84+
if (!ConfigName) {
85+
LogMan::Msg::EFmt("JSON file '{}': Couldn't get config name for an item", Config);
86+
return;
87+
}
6488

65-
Func(ConfigName, ConfigString);
89+
if (!ConfigString) {
90+
LogMan::Msg::EFmt("JSON file '{}': Couldn't get value for config item '{}'", Config, ConfigName);
91+
return;
92+
}
93+
Func(ConfigName, ConfigString);
94+
}
6695
}
6796
}
6897
} // namespace JSON

unittests/APITests/CMakeLists.txt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,10 @@ set(TESTS
66
FileMappingBaseAddress
77
Filesystem
88
InterruptableConditionVariable
9-
StringUtils)
9+
StringUtils
10+
WildcardMatcher)
1011

11-
list(APPEND LIBS Common FEXCore JemallocLibs)
12+
list(APPEND LIBS Common FEXCore FEXCore_Base JemallocLibs)
1213

1314
foreach(API_TEST ${TESTS})
1415
add_executable(${API_TEST} ${API_TEST}.cpp)
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
#include <FEXCore/fextl/string.h>
2+
#include <FEXCore/Utils/Allocator.h>
3+
#include <FEXCore/Utils/WildcardMatcher.h>
4+
#include <catch2/catch_test_macros.hpp>
5+
6+
using namespace FEXCore::Utils::Wildcard;
7+
8+
TEST_CASE("Singular regex") {
9+
CHECK(Matches("a", "a"));
10+
CHECK(Matches("a*", "a*"));
11+
CHECK(Matches("a*", "aaaaaaa"));
12+
}
13+
14+
TEST_CASE("Concat regex") {
15+
CHECK(Matches("aaa", "aaa"));
16+
CHECK(Matches("ab", "ab"));
17+
CHECK(!Matches("a", "ab"));
18+
CHECK(!Matches("ab", "a"));
19+
}
20+
TEST_CASE("Wildcard beginning end") {
21+
CHECK(Matches("a*", "a"));
22+
CHECK(Matches("*a", "a"));
23+
CHECK(Matches("*a*", "a"));
24+
}
25+
TEST_CASE("Wildcard middle") {
26+
CHECK(Matches("test*pattern", "test__pattern"));
27+
}
28+
29+
TEST_CASE("Wildcard mult") {
30+
CHECK(Matches("test*pattern*more", "test__pattern__more"));
31+
CHECK(Matches("test**pattern", "test_pattern"));
32+
}
33+
34+
TEST_CASE("Wildcard regex simple") {
35+
CHECK(Matches("*", ""));
36+
CHECK(Matches("*", "setup.json"));
37+
CHECK(Matches("test*pattern", "test__pattern"));
38+
CHECK(!Matches("setup.*", "setupjson"));
39+
CHECK(Matches("setup*", "setup.json"));
40+
CHECK(Matches("setup*", "setup/setup.json"));
41+
CHECK(Matches("*setup*", "setup/setup.json"));
42+
}
43+
44+
45+
TEST_CASE("FEX regex") {
46+
CHECK(Matches("*Config*", "/home/ubuntu/.fex-emu/Config.json"));
47+
CHECK(Matches("*Config.json", "/home/ubuntu/.fex-emu/Config.json"));
48+
}

0 commit comments

Comments
 (0)