diff options
author | Dan Goodliffe <dan@randomdan.homeip.net> | 2025-08-21 20:39:52 +0100 |
---|---|---|
committer | Dan Goodliffe <dan@randomdan.homeip.net> | 2025-08-25 16:00:59 +0100 |
commit | b2416925f8845b70ed25fb4ec7cde8ef11e8c239 (patch) | |
tree | 9ed898937ddceca6bcf0e2a6d6dfda3754dceefe /src/logTypes.cpp | |
download | webstat-b2416925f8845b70ed25fb4ec7cde8ef11e8c239.tar.bz2 webstat-b2416925f8845b70ed25fb4ec7cde8ef11e8c239.tar.xz webstat-b2416925f8845b70ed25fb4ec7cde8ef11e8c239.zip |
Initial commit; basic Apache log parsing
Diffstat (limited to 'src/logTypes.cpp')
-rw-r--r-- | src/logTypes.cpp | 96 |
1 files changed, 96 insertions, 0 deletions
diff --git a/src/logTypes.cpp b/src/logTypes.cpp new file mode 100644 index 0000000..42f0979 --- /dev/null +++ b/src/logTypes.cpp @@ -0,0 +1,96 @@ +#include "logTypes.hpp" + +namespace scn { + scan_expected<typename ContextType::iterator> + scanner<WebStat::QuotedString>::scan(WebStat::QuotedString & value, ContextType & ctx) + { + if (auto empty = scn::scan<>(ctx.range(), R"("")")) { + return empty->begin(); + } + + auto result = scn::scan<std::string>(ctx.range(), R"("{:[^"]}")"); + if (!result) { + return unexpected(result.error()); + } + value = result->value(); + return result->begin(); + } + + scan_expected<typename ContextType::iterator> + scanner<WebStat::QueryString>::scan(WebStat::QueryString & value, ContextType & ctx) + { + if (auto null = scn::scan<>(ctx.range(), R"("")")) { + return null->begin(); + } + + if (auto empty = scn::scan<>(ctx.range(), R"("?")")) { + value.emplace(); + return empty->begin(); + } + + auto result = scn::scan<std::string>(ctx.range(), R"("?{:[^"]}")"); + if (!result) { + return unexpected(result.error()); + } + value = result->value(); + return result->begin(); + } + + scan_expected<typename ContextType::iterator> + scanner<WebStat::CLFString>::scan(WebStat::CLFString & value, ContextType & ctx) + { + if (auto empty = scn::scan<>(ctx.range(), R"("")")) { + value.emplace(); + return empty->begin(); + } + + if (auto null = scn::scan<>(ctx.range(), R"("-")")) { + return null->begin(); + } + + auto result = scn::scan<std::string>(ctx.range(), R"("{:[^"]}")"); + if (!result) { + return unexpected(result.error()); + } + value = result->value(); + decode(*value); + return result->begin(); + } + + void + scanner<WebStat::CLFString>::decode(std::string & value) + { + static constexpr auto BS_MAP = []() { + std::array<char, 128> map {}; + map['f'] = '\f'; + map['n'] = '\n'; + map['r'] = '\r'; + map['t'] = '\t'; + map['v'] = '\v'; + map['"'] = '"'; + map['\\'] = '\\'; + return map; + }(); + + if (auto src = std::ranges::find(value, '\\'); src != value.end()) { + auto dest = src; + while (src != value.cend()) { + if (*src == '\\') { + const std::string_view escaped {++src, value.end()}; + if (auto chr = BS_MAP[static_cast<unsigned char>(*src)]) { + *dest++ = chr; + src++; + } + else if (auto hex = scn::scan<unsigned char>(escaped, R"(x{:.2x})")) { + *dest++ = static_cast<char>(hex->value()); + src += 3; + } + } + else { + *dest++ = *src++; + } + } + value.erase(dest, value.end()); + } + } +} |