From 19479c32167c1b9dd4c7c73b5b2bb507e204b328 Mon Sep 17 00:00:00 2001 From: vaxerski Date: Thu, 28 Dec 2023 23:25:43 +0100 Subject: [PATCH] core: add support for handlers --- src/config.cpp | 29 ++++++++++++++++++++++---- src/config.hpp | 7 +++++++ src/public.hpp | 45 +++++++++++++++++++++++++--------------- tests/config/config.conf | 3 ++- tests/main.cpp | 27 ++++++++++++++++++++++++ 5 files changed, 89 insertions(+), 22 deletions(-) diff --git a/src/config.cpp b/src/config.cpp index a6158a2..1e32882 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -243,11 +243,28 @@ CParseResult CConfig::parseLine(std::string line) { } if (equalsPos != std::string::npos) { - // set value - CParseResult ret = configSetValueSafe(removeBeginEndSpacesTabs(line.substr(0, equalsPos)), removeBeginEndSpacesTabs(line.substr(equalsPos + 1))); - if (ret.error) { - return ret; + // set value or call handler + CParseResult ret; + const auto LHS = removeBeginEndSpacesTabs(line.substr(0, equalsPos)); + const auto RHS = removeBeginEndSpacesTabs(line.substr(equalsPos + 1)); + + bool found = false; + for (auto& h : impl->handlers) { + if (!h.options.allowFlags && h.name != LHS) + continue; + + if (h.options.allowFlags && !LHS.starts_with(h.name)) + continue; + + ret = h.func(LHS.c_str(), RHS.c_str()); + found = true; } + + if (!found) + ret = configSetValueSafe(LHS, RHS); + + if (ret.error) + return ret; } else if (!line.empty()) { // has to be a set if (line.contains("}")) { @@ -319,3 +336,7 @@ CConfigValue* CConfig::getConfigValuePtr(const char* name) { const auto IT = impl->values.find(std::string{name}); return IT == impl->values.end() ? nullptr : &IT->second; } + +void CConfig::registerHandler(PCONFIGHANDLERFUNC func, const char* name, SHandlerOptions options) { + impl->handlers.push_back(SHandler{name, options, func}); +} \ No newline at end of file diff --git a/src/config.hpp b/src/config.hpp index e117386..24a376c 100644 --- a/src/config.hpp +++ b/src/config.hpp @@ -4,12 +4,19 @@ #include #include +struct SHandler { + std::string name = ""; + Hyprlang::SHandlerOptions options; + Hyprlang::PCONFIGHANDLERFUNC func = nullptr; +}; + class CConfigImpl { public: std::string path = ""; std::unordered_map values; std::unordered_map defaultValues; + std::vector handlers; std::vector categories; diff --git a/src/public.hpp b/src/public.hpp index 57993ce..2c144f9 100644 --- a/src/public.hpp +++ b/src/public.hpp @@ -22,6 +22,30 @@ namespace Hyprlang { } }; + class CParseResult { + public: + bool error = false; + const char* getError() const { + return errorString; + } + void setError(const char* err); + + private: + void setError(const std::string& err); + + std::string errorStdString = ""; + const char* errorString = nullptr; + + friend class CConfig; + }; + + struct SHandlerOptions { + bool allowFlags = false; + }; + + /* typedefs */ + typedef CParseResult (*PCONFIGHANDLERFUNC)(const char* COMMAND, const char* VALUE); + struct SConfigValueImpl; /* Container for a config value */ class CConfigValue { @@ -63,23 +87,6 @@ namespace Hyprlang { friend class CConfig; }; - class CParseResult { - public: - bool error = false; - const char* getError() const { - return errorString; - } - void setError(const char* err); - - private: - void setError(const std::string& err); - - std::string errorStdString = ""; - const char* errorString = nullptr; - - friend class CConfig; - }; - /* Base class for a config file */ class CConfig { public: @@ -91,6 +98,10 @@ namespace Hyprlang { Value provided becomes default */ void addConfigValue(const char* name, const CConfigValue value); + /* Register a handler. Can be called anytime, though not recommended + to do this dynamically */ + void registerHandler(PCONFIGHANDLERFUNC func, const char* name, SHandlerOptions options); + /* Commence the config state. Config becomes immutable, as in no new values may be added or removed. Required for parsing. */ void commence(); diff --git a/tests/config/config.conf b/tests/config/config.conf index b6a0ab9..75a2b0d 100644 --- a/tests/config/config.conf +++ b/tests/config/config.conf @@ -24,7 +24,8 @@ testCategory { testStringQuotes = "Hello World!" #testDefault = 123 -#doABarrelRoll = woohoo, some, params # Funny! +doABarrelRoll = woohoo, some, params # Funny! +flagsabc = test #doSomethingFunny = 1, 2, 3, 4 # Funnier! #testSpaces = abc , def # many spaces, should be trimmed diff --git a/tests/main.cpp b/tests/main.cpp index 6f38f80..52ea912 100644 --- a/tests/main.cpp +++ b/tests/main.cpp @@ -10,6 +10,26 @@ std::cout << "Passed " << #expr << ". Got " << val << "\n"; \ } +// globals for testing +bool barrelRoll = false; +std::string flagsFound = ""; + +static Hyprlang::CParseResult handleDoABarrelRoll(const char* COMMAND, const char* VALUE) { + if (std::string(VALUE) == "woohoo, some, params") + barrelRoll = true; + + Hyprlang::CParseResult result; + return result; +} + +static Hyprlang::CParseResult handleFlagsTest(const char* COMMAND, const char* VALUE) { + std::string cmd = COMMAND; + flagsFound = cmd.substr(5); + + Hyprlang::CParseResult result; + return result; +} + int main(int argc, char** argv, char** envp) { int ret = 0; @@ -33,6 +53,9 @@ int main(int argc, char** argv, char** envp) { config.addConfigValue("testCategory:testColor2", 0L); config.addConfigValue("testCategory:testColor3", 0L); + config.registerHandler(&handleDoABarrelRoll, "doABarrelRoll", {false}); + config.registerHandler(&handleFlagsTest, "flags", {true}); + config.commence(); const auto PARSERESULT = config.parse(); @@ -58,6 +81,10 @@ int main(int argc, char** argv, char** envp) { EXPECT(std::any_cast(config.getConfigValue("testCategory:testColor1")), 0xFFFFFFFFL); EXPECT(std::any_cast(config.getConfigValue("testCategory:testColor2")), 0xFF000000L); EXPECT(std::any_cast(config.getConfigValue("testCategory:testColor3")), 0x22ffeeffL); + + // test handlers + EXPECT(barrelRoll, true); + EXPECT(flagsFound, std::string{"abc"}); } catch (const char* e) { std::cout << "Error: " << e << "\n"; return 1;