From efe9f5b614d5c567431682c520a70260994a629f Mon Sep 17 00:00:00 2001 From: Tixx <83774803+WiserTixx@users.noreply.github.com> Date: Sun, 27 Apr 2025 23:35:11 +0200 Subject: [PATCH] Add INI parser and function to expand env vars --- include/Utils.h | 89 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/include/Utils.h b/include/Utils.h index 77638ec..33c01d6 100644 --- a/include/Utils.h +++ b/include/Utils.h @@ -5,10 +5,13 @@ */ #pragma once +#include +#include #include #include namespace Utils { + inline std::vector Split(const std::string& String, const std::string& delimiter) { std::vector Val; size_t pos; @@ -23,4 +26,90 @@ namespace Utils { Val.push_back(s); return Val; }; + inline std::string ExpandEnvVars(const std::string& input) { + std::string result; + std::regex envPattern(R"(%([^%]+)%|\$([A-Za-z_][A-Za-z0-9_]*)|\$\{([^}]+)\})"); + + std::sregex_iterator begin(input.begin(), input.end(), envPattern); + std::sregex_iterator end; + + size_t lastPos = 0; + + for (auto it = begin; it != end; ++it) { + const auto& match = *it; + + result.append(input, lastPos, match.position() - lastPos); + + std::string varName; + if (match[1].matched) varName = match[1].str(); // %VAR% + else if (match[2].matched) varName = match[2].str(); // $VAR + else if (match[3].matched) varName = match[3].str(); // ${VAR} + + if (const char* envValue = std::getenv(varName.c_str())) { + result.append(envValue); + } + + lastPos = match.position() + match.length(); + } + + result.append(input, lastPos, input.length() - lastPos); + + return result; + } + inline std::map> ParseINI(const std::string& contents) { + std::map> ini; + + std::string currentSection; + auto sections = Split(contents, "\n"); + + for (size_t i = 0; i < sections.size(); i++) { + std::string line = sections[i]; + if (line.empty() || line[0] == ';' || line[0] == '#') + continue; + + for (auto& c : line) { + if (c == '#' || c == ';') { + line = line.substr(0, &c - &line[0]); + break; + } + } + + auto invalidLineLog = [&]{ + warn("Invalid INI line: " + line); + warn("Surrounding lines: \n" + + (i > 0 ? sections[i - 1] : "") + "\n" + + (i < sections.size() - 1 ? sections[i + 1] : "")); + }; + + if (line[0] == '[') { + currentSection = line.substr(1, line.find(']') - 1); + } else { + + if (currentSection.empty()) { + invalidLineLog(); + continue; + } + + std::string key, value; + size_t pos = line.find('='); + if (pos != std::string::npos) { + key = line.substr(0, pos); + value = line.substr(pos + 1); + ini[currentSection][key] = value; + } else { + invalidLineLog(); + continue; + } + + key.erase(key.find_last_not_of(" \t") + 1); + value.erase(0, value.find_first_not_of(" \t")); + value.erase(value.find_last_not_of(" \t") + 1); + + ini[currentSection][key] = value; + } + } + + return ini; + } + }; \ No newline at end of file