ferencd@0: /* ferencd@0: * This project is licensed under the MIT license. For more information see the ferencd@0: * LICENSE file. ferencd@0: */ ferencd@0: #pragma once ferencd@0: ferencd@0: // ----------------------------------------------------------------------------- ferencd@0: ferencd@0: #include ferencd@0: #include ferencd@0: #include ferencd@0: // windows compatibility includes ferencd@0: #include ferencd@0: #include ferencd@0: ferencd@0: // ----------------------------------------------------------------------------- ferencd@0: ferencd@0: namespace maddy { ferencd@0: ferencd@0: // ----------------------------------------------------------------------------- ferencd@0: ferencd@0: /** ferencd@0: * BlockParser ferencd@0: * ferencd@0: * The code expects every child to have the following static function to be ferencd@0: * implemented: ferencd@0: * `static bool IsStartingLine(const std::string& line)` ferencd@0: * ferencd@0: * @class ferencd@0: */ ferencd@0: class BlockParser ferencd@0: { ferencd@0: public: ferencd@0: /** ferencd@0: * ctor ferencd@0: * ferencd@0: * @method ferencd@0: * @param {std::function} parseLineCallback ferencd@0: * @param {std::function(const std::string& line)>} getBlockParserForLineCallback ferencd@0: */ ferencd@0: BlockParser( ferencd@0: std::function parseLineCallback, ferencd@0: std::function(const std::string& line)> getBlockParserForLineCallback ferencd@0: ) ferencd@0: : result("", std::ios_base::ate | std::ios_base::in | std::ios_base::out) ferencd@0: , childParser(nullptr) ferencd@0: , parseLineCallback(parseLineCallback) ferencd@0: , getBlockParserForLineCallback(getBlockParserForLineCallback) ferencd@0: {} ferencd@0: ferencd@0: /** ferencd@0: * dtor ferencd@0: * ferencd@0: * @method ferencd@0: */ ferencd@0: virtual ~BlockParser() {} ferencd@0: ferencd@0: /** ferencd@0: * AddLine ferencd@0: * ferencd@0: * Adding a line which has to be parsed. ferencd@0: * ferencd@0: * @method ferencd@0: * @param {std::string&} line ferencd@0: * @return {void} ferencd@0: */ ferencd@0: virtual void ferencd@0: AddLine(std::string& line) ferencd@0: { ferencd@0: this->parseBlock(line); ferencd@0: ferencd@0: if (this->isInlineBlockAllowed() && !this->childParser) ferencd@0: { ferencd@0: this->childParser = this->getBlockParserForLine(line); ferencd@0: } ferencd@0: ferencd@0: if (this->childParser) ferencd@0: { ferencd@0: this->childParser->AddLine(line); ferencd@0: ferencd@0: if (this->childParser->IsFinished()) ferencd@0: { ferencd@0: this->result << this->childParser->GetResult().str(); ferencd@0: this->childParser = nullptr; ferencd@0: } ferencd@0: ferencd@0: return; ferencd@0: } ferencd@0: ferencd@0: if (this->isLineParserAllowed()) ferencd@0: { ferencd@0: this->parseLine(line); ferencd@0: } ferencd@0: ferencd@0: this->result << line; ferencd@0: } ferencd@0: ferencd@0: /** ferencd@0: * IsFinished ferencd@0: * ferencd@0: * Check if the BlockParser is done ferencd@0: * ferencd@0: * @method ferencd@0: * @return {bool} ferencd@0: */ ferencd@0: virtual bool IsFinished() const = 0; ferencd@0: ferencd@0: /** ferencd@0: * GetResult ferencd@0: * ferencd@0: * Get the parsed HTML output. ferencd@0: * ferencd@0: * @method ferencd@0: * @return {std::stringstream} ferencd@0: */ ferencd@0: std::stringstream& ferencd@0: GetResult() ferencd@0: { ferencd@0: return this->result; ferencd@0: } ferencd@0: ferencd@0: /** ferencd@0: * Clear ferencd@0: * ferencd@0: * Clear the result to reuse the parser object. ferencd@0: * ferencd@0: * It is only used by one test for now. ferencd@0: * ferencd@0: * @method ferencd@0: * @return {void} ferencd@0: */ ferencd@0: void ferencd@0: Clear() ferencd@0: { ferencd@0: this->result.str(""); ferencd@0: } ferencd@0: ferencd@0: protected: ferencd@0: std::stringstream result; ferencd@0: std::shared_ptr childParser; ferencd@0: ferencd@0: virtual bool isInlineBlockAllowed() const = 0; ferencd@0: virtual bool isLineParserAllowed() const = 0; ferencd@0: virtual void parseBlock(std::string& line) = 0; ferencd@0: ferencd@0: void ferencd@0: parseLine(std::string& line) ferencd@0: { ferencd@0: if (parseLineCallback) ferencd@0: { ferencd@0: parseLineCallback(line); ferencd@0: } ferencd@0: } ferencd@0: ferencd@0: uint32_t ferencd@0: getIndentationWidth(const std::string& line) const ferencd@0: { ferencd@0: bool hasMetNonSpace = false; ferencd@0: ferencd@0: uint32_t indentation = static_cast( ferencd@0: std::count_if( ferencd@0: line.begin(), ferencd@0: line.end(), ferencd@0: [&hasMetNonSpace](unsigned char c) ferencd@0: { ferencd@0: if (hasMetNonSpace) ferencd@0: { ferencd@0: return false; ferencd@0: } ferencd@0: ferencd@0: if (std::isspace(c)) ferencd@0: { ferencd@0: return true; ferencd@0: } ferencd@0: ferencd@0: hasMetNonSpace = true; ferencd@0: return false; ferencd@0: } ferencd@0: ) ferencd@0: ); ferencd@0: ferencd@0: return indentation; ferencd@0: } ferencd@0: ferencd@0: std::shared_ptr ferencd@0: getBlockParserForLine(const std::string& line) ferencd@0: { ferencd@0: if (getBlockParserForLineCallback) ferencd@0: { ferencd@0: return getBlockParserForLineCallback(line); ferencd@0: } ferencd@0: ferencd@0: return nullptr; ferencd@0: } ferencd@0: ferencd@0: private: ferencd@0: std::function parseLineCallback; ferencd@0: std::function(const std::string& line)> getBlockParserForLineCallback; ferencd@0: }; // class BlockParser ferencd@0: ferencd@0: // ----------------------------------------------------------------------------- ferencd@0: ferencd@0: } // namespace maddy