1
0
mirror of https://github.com/VCMP-SqMod/SqMod.git synced 2025-10-21 10:27:18 +02:00

Major plugin refactor and cleanup.

Switched to POCO library for unified platform/library interface.
Deprecated the external module API. It was creating more problems than solving.
Removed most built-in libraries in favor of system libraries for easier maintenance.
Cleaned and secured code with help from static analyzers.
This commit is contained in:
Sandu Liviu Catalin
2021-01-30 08:51:39 +02:00
parent e0e34b4030
commit 4a6bfc086c
6219 changed files with 1209835 additions and 454916 deletions

View File

@@ -0,0 +1,62 @@
//
// ApacheCodeWriter.cpp
//
// Copyright (c) 2008, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "ApacheCodeWriter.h"
#include "Page.h"
ApacheCodeWriter::ApacheCodeWriter(const Page& page, const std::string& clazz):
CodeWriter(page, clazz)
{
}
ApacheCodeWriter::~ApacheCodeWriter()
{
}
void ApacheCodeWriter::writeHeaderIncludes(std::ostream& ostr)
{
CodeWriter::writeHeaderIncludes(ostr);
ostr << "#include \"Poco/Net/HTTPRequestHandlerFactory.h\"\n";
}
void ApacheCodeWriter::writeFactoryClass(std::ostream& ostr)
{
ostr << "\n\n";
factoryClass(ostr, "Poco::Net::HTTPRequestHandlerFactory");
}
void ApacheCodeWriter::writeImplIncludes(std::ostream& ostr)
{
CodeWriter::writeImplIncludes(ostr);
ostr << "#include \"Poco/ClassLibrary.h\"\n";
}
void ApacheCodeWriter::writeFactory(std::ostream& ostr)
{
ostr << "\n\n";
factoryImpl(ostr, "");
}
void ApacheCodeWriter::writeManifest(std::ostream& ostr)
{
std::string ns = page().get("page.namespace", "");
if (!ns.empty()) ns += "::";
ostr << "\n\n";
ostr << "POCO_BEGIN_MANIFEST(Poco::Net::HTTPRequestHandlerFactory)\n";
ostr << "\tPOCO_EXPORT_CLASS(" << ns << clazz() << "Factory)\n";
ostr << "POCO_END_MANIFEST\n";
}

View File

@@ -0,0 +1,37 @@
//
// ApacheCodeWriter.h
//
// Copyright (c) 2008, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#ifndef ApacheCodeWriter_INCLUDED
#define ApacheCodeWriter_INCLUDED
#include "CodeWriter.h"
class ApacheCodeWriter: public CodeWriter
/// Code generator for ApacheConnector request handlers.
{
public:
ApacheCodeWriter(const Page& page, const std::string& clazz);
/// Creates the CodeWriter, using the given Page.
~ApacheCodeWriter();
/// Destroys the PageReader.
protected:
virtual void writeHeaderIncludes(std::ostream& ostr);
virtual void writeFactoryClass(std::ostream& ostr);
virtual void writeImplIncludes(std::ostream& ostr);
virtual void writeFactory(std::ostream& ostr);
virtual void writeManifest(std::ostream& ostr);
};
#endif // CodeWriter_INCLUDED

View File

@@ -0,0 +1,419 @@
//
// CodeWriter.cpp
//
// Copyright (c) 2008, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "CodeWriter.h"
#include "Page.h"
#include "Poco/Path.h"
#include "Poco/StringTokenizer.h"
#include "Poco/String.h"
using Poco::Path;
using Poco::StringTokenizer;
CodeWriter::CodeWriter(const Page& page, const std::string& clazz):
_page(page),
_class(clazz)
{
}
CodeWriter::~CodeWriter()
{
}
void CodeWriter::writeHeader(std::ostream& ostr, const std::string& headerFileName)
{
beginGuard(ostr, headerFileName);
writeHeaderIncludes(ostr);
ostr << "\n\n";
std::string decls(_page.headerDecls().str());
if (!decls.empty())
{
ostr << decls << "\n\n";
}
beginNamespace(ostr);
writeHandlerClass(ostr);
writeFactoryClass(ostr);
endNamespace(ostr);
endGuard(ostr, headerFileName);
}
void CodeWriter::writeImpl(std::ostream& ostr, const std::string& headerFileName)
{
ostr << "#include \"" << headerFileName << "\"\n";
writeImplIncludes(ostr);
if (_page.getBool("page.escape", false))
{
ostr << "#include \"Poco/Net/EscapeHTMLStream.h\"\n";
}
if (_page.getBool("page.compressed", false))
{
ostr << "#include \"Poco/DeflatingStream.h\"\n";
}
if (_page.getBool("page.buffered", false))
{
ostr << "#include \"Poco/StreamCopier.h\"\n";
ostr << "#include <sstream>\n";
}
std::string decls(_page.implDecls().str());
if (!decls.empty())
{
ostr << decls << "\n\n";
}
ostr << "using namespace std::string_literals;\n\n\n";
beginNamespace(ostr);
std::string path = _page.get("page.path", "");
if (!path.empty())
{
ostr << "\tconst std::string " << _class << "::PATH(\"" << path << "\");\n\n\n";
}
writeConstructor(ostr);
writeHandler(ostr);
writeFactory(ostr);
endNamespace(ostr);
writeManifest(ostr);
}
void CodeWriter::beginNamespace(std::ostream& ostr)
{
std::string ns = _page.get("page.namespace", "");
if (!ns.empty())
{
StringTokenizer tok(ns, ":", StringTokenizer::TOK_IGNORE_EMPTY | StringTokenizer::TOK_TRIM);
for (StringTokenizer::Iterator it = tok.begin(); it != tok.end(); ++it)
{
ostr << "namespace " << *it << " {\n";
}
ostr << "\n\n";
}
}
void CodeWriter::endNamespace(std::ostream& ostr)
{
std::string ns = _page.get("page.namespace", "");
if (!ns.empty())
{
ostr << "\n\n";
StringTokenizer tok(ns, ":", StringTokenizer::TOK_IGNORE_EMPTY | StringTokenizer::TOK_TRIM);
for (StringTokenizer::Iterator it = tok.begin(); it != tok.end(); ++it)
{
ostr << "} ";
}
ostr << "// namespace " << ns << "\n";
}
}
void CodeWriter::beginGuard(std::ostream& ostr, const std::string& headerFileName)
{
Path p(headerFileName);
std::string guard(p.getBaseName());
Poco::translateInPlace(guard, ".-", "__");
guard += "_INCLUDED";
ostr << "#ifndef " << guard << "\n";
ostr << "#define " << guard << "\n";
ostr << "\n\n";
}
void CodeWriter::endGuard(std::ostream& ostr, const std::string& headerFileName)
{
Path p(headerFileName);
std::string guard(p.getBaseName());
Poco::translateInPlace(guard, ".-", "__");
guard += "_INCLUDED";
ostr << "\n\n";
ostr << "#endif // " << guard << "\n";
}
void CodeWriter::handlerClass(std::ostream& ostr, const std::string& base, const std::string& ctorArg)
{
std::string exprt(_page.get("page.export", ""));
if (!exprt.empty()) exprt += ' ';
ostr << "class " << exprt << _class << ": public " << base << "\n";
ostr << "{\n";
ostr << "public:\n";
if (!ctorArg.empty())
{
ostr << "\t" << _class << "(" << ctorArg << ");\n";
ostr << "\n";
}
ostr << "\tvoid handleRequest(Poco::Net::HTTPServerRequest& request, Poco::Net::HTTPServerResponse& response);\n";
writeHandlerMembers(ostr);
std::string path = _page.get("page.path", "");
if (!path.empty())
{
ostr << "\n\tstatic const std::string PATH;\n";
}
ostr << "};\n";
}
void CodeWriter::factoryClass(std::ostream& ostr, const std::string& base)
{
ostr << "class " << _class << "Factory: public " << base << "\n";
ostr << "{\n";
ostr << "public:\n";
ostr << "\tPoco::Net::HTTPRequestHandler* createRequestHandler(const Poco::Net::HTTPServerRequest& request);\n";
ostr << "};\n";
}
void CodeWriter::factoryImpl(std::ostream& ostr, const std::string& arg)
{
ostr << "Poco::Net::HTTPRequestHandler* " << _class << "Factory::createRequestHandler(const Poco::Net::HTTPServerRequest& request)\n";
ostr << "{\n";
ostr << "\treturn new " << _class << "(" << arg << ");\n";
ostr << "}\n";
}
void CodeWriter::writeHeaderIncludes(std::ostream& ostr)
{
ostr << "#include \"Poco/Net/HTTPRequestHandler.h\"\n";
}
void CodeWriter::writeHandlerClass(std::ostream& ostr)
{
std::string base(_page.get("page.baseClass", "Poco::Net::HTTPRequestHandler"));
std::string ctorArg;
ctorArg = _page.get("page.context", _page.get("page.ctorArg", ""));
handlerClass(ostr, base, ctorArg);
}
void CodeWriter::writeHandlerMembers(std::ostream& ostr)
{
std::string context(_page.get("page.context", ""));
if (!context.empty())
{
ostr << "\n";
ostr << "protected:\n";
ostr << "\t" << context << " context() const\n";
ostr << "\t{\n";
ostr << "\t\treturn _context;\n";
ostr << "\t}\n";
ostr << "\n";
ostr << "private:\n";
ostr << "\t" << context << " _context;\n";
}
}
void CodeWriter::writeFactoryClass(std::ostream& ostr)
{
}
void CodeWriter::writeImplIncludes(std::ostream& ostr)
{
ostr << "#include \"Poco/Net/HTTPServerRequest.h\"\n";
ostr << "#include \"Poco/Net/HTTPServerResponse.h\"\n";
ostr << "#include \"Poco/Net/HTMLForm.h\"\n";
}
void CodeWriter::writeConstructor(std::ostream& ostr)
{
std::string base(_page.get("page.baseClass", "Poco::Net::HTTPRequestHandler"));
std::string context(_page.get("page.context", ""));
std::string ctorArg(_page.get("page.ctorArg", ""));
if (!context.empty())
{
ostr << _class << "::" << _class << "(" << context << " context):\n";
ostr << "\t_context(context)\n";
ostr << "{\n}\n";
ostr << "\n\n";
}
else if (!ctorArg.empty())
{
ostr << _class << "::" << _class << "(" << ctorArg << " arg):\n";
ostr << "\t" << base << "(arg)\n";
ostr << "{\n}\n";
ostr << "\n\n";
}
}
void CodeWriter::writeHandler(std::ostream& ostr)
{
ostr << "void " << _class << "::handleRequest(Poco::Net::HTTPServerRequest& request, Poco::Net::HTTPServerResponse& response)\n";
ostr << "{\n";
writeResponse(ostr);
writeSession(ostr);
if (_page.has("page.precondition"))
{
ostr << "\tif (!(" << _page.get("page.precondition") << ")) return;\n\n";
}
writeForm(ostr);
ostr << _page.preHandler().str();
writeContent(ostr);
ostr << "}\n";
}
void CodeWriter::writeFactory(std::ostream& ostr)
{
}
void CodeWriter::writeManifest(std::ostream& ostr)
{
}
void CodeWriter::writeSession(std::ostream& ostr)
{
}
void CodeWriter::writeForm(std::ostream& ostr)
{
if (_page.getBool("page.form", true))
{
std::string partHandler(_page.get("page.formPartHandler", ""));
if (!partHandler.empty())
{
ostr << "\t" << partHandler << " cpspPartHandler(*this);\n";
}
ostr << "\tPoco::Net::HTMLForm form(request, request.stream()";
if (!partHandler.empty())
{
ostr << ", cpspPartHandler";
}
ostr << ");\n";
}
}
void CodeWriter::writeResponse(std::ostream& ostr)
{
std::string contentType(_page.get("page.contentType", "text/html"));
std::string contentLang(_page.get("page.contentLanguage", ""));
std::string contentSecurityPolicy(_page.get("page.contentSecurityPolicy", ""));
std::string cacheControl(_page.get("page.cacheControl", ""));
bool buffered(_page.getBool("page.buffered", false));
bool chunked(_page.getBool("page.chunked", !buffered));
bool compressed(_page.getBool("page.compressed", false));
if (buffered) compressed = false;
if (compressed) chunked = true;
if (chunked)
{
ostr << "\tresponse.setChunkedTransferEncoding(true);\n";
}
ostr << "\tresponse.setContentType(\"" << contentType << "\"s);\n";
if (!contentLang.empty())
{
ostr << "\tif (request.has(\"Accept-Language\"s))\n"
<< "\t\tresponse.set(\"Content-Language\"s, \"" << contentLang << "\"s);\n";
}
if (!contentSecurityPolicy.empty())
{
ostr << "\tresponse.set(\"Content-Secure-Policy\"s, \"" << contentSecurityPolicy << "\"s);\n";
}
if (compressed)
{
ostr << "\tbool _compressResponse(request.hasToken(\"Accept-Encoding\"s, \"gzip\"s));\n"
<< "\tif (_compressResponse) response.set(\"Content-Encoding\"s, \"gzip\"s);\n";
}
if (!cacheControl.empty())
{
ostr << "\tresponse.set(\"Cache-Control\"s, \"" << cacheControl << "\"s);\n";
}
ostr << "\n";
}
void CodeWriter::writeContent(std::ostream& ostr)
{
bool escape(_page.getBool("page.escape", false));
bool buffered(_page.getBool("page.buffered", false));
bool chunked(_page.getBool("page.chunked", !buffered));
bool compressed(_page.getBool("page.compressed", false));
int compressionLevel(_page.getInt("page.compressionLevel", 1));
if (buffered) compressed = false;
if (compressed) chunked = true;
if (buffered)
{
ostr << "\tstd::stringstream responseStream;\n";
if (escape)
{
ostr << "\tPoco::Net::EscapeHTMLOutputStream _escapeStream(responseStream);\n";
}
ostr << cleanupHandler(_page.handler().str());
if (!chunked)
{
ostr << "\tresponse.setContentLength(static_cast<int>(responseStream.tellp()));\n";
}
ostr << "\tPoco::StreamCopier::copyStream(responseStream, response.send());\n";
}
else if (compressed)
{
ostr << "\tstd::ostream& _responseStream = response.send();\n"
<< "\tPoco::DeflatingOutputStream _gzipStream(_responseStream, Poco::DeflatingStreamBuf::STREAM_GZIP, " << compressionLevel << ");\n"
<< "\tstd::ostream& responseStream = _compressResponse ? _gzipStream : _responseStream;\n";
if (escape)
{
ostr << "\tPoco::Net::EscapeHTMLOutputStream _escapeStream(responseStream);\n";
}
ostr << cleanupHandler(_page.handler().str());
ostr << "\tif (_compressResponse) _gzipStream.close();\n";
}
else
{
ostr << "\tstd::ostream& responseStream = response.send();\n";
if (escape)
{
ostr << "\tPoco::Net::EscapeHTMLOutputStream _escapeStream(responseStream);\n";
}
ostr << cleanupHandler(_page.handler().str());
}
}
std::string CodeWriter::cleanupHandler(std::string handler)
{
static const std::string EMPTY_WRITE("\tresponseStream << \"\";\n");
static const std::string NEWLINE_WRITE("\tresponseStream << \"\\n\";\n");
static const std::string DOUBLE_NEWLINE_WRITE("\tresponseStream << \"\\n\";\n\tresponseStream << \"\\n\";\n");
static const std::string EMPTY;
// remove empty writes
Poco::replaceInPlace(handler, EMPTY_WRITE, EMPTY);
// remove consecutive newlines
while (handler.find(DOUBLE_NEWLINE_WRITE) != std::string::npos)
{
Poco::replaceInPlace(handler, DOUBLE_NEWLINE_WRITE, NEWLINE_WRITE);
}
return handler;
}

View File

@@ -0,0 +1,95 @@
//
// CodeWriter.h
//
// Copyright (c) 2008, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#ifndef CodeWriter_INCLUDED
#define CodeWriter_INCLUDED
#include "Poco/Poco.h"
#include <ostream>
class Page;
class CodeWriter
/// This class implements the code generator for
/// generating C++ header and implementation files
/// from C++ Server Pages.
{
public:
CodeWriter(const Page& page, const std::string& clazz);
/// Creates the CodeWriter, using the given Page.
virtual ~CodeWriter();
/// Destroys the PageReader.
virtual void writeHeader(std::ostream& ostr, const std::string& headerFileName);
/// Writes the header file contents to the given stream.
virtual void writeImpl(std::ostream& ostr, const std::string& headerFileName);
/// Writes the implementation file contents to the given stream.
const Page& page() const;
/// Returns a const reference to the Page.
const std::string& clazz() const;
/// Returns the name of the handler class.
protected:
virtual void writeHeaderIncludes(std::ostream& ostr);
virtual void writeHandlerClass(std::ostream& ostr);
virtual void writeHandlerMembers(std::ostream& ostr);
virtual void writeFactoryClass(std::ostream& ostr);
virtual void writeImplIncludes(std::ostream& ostr);
virtual void writeConstructor(std::ostream& ostr);
virtual void writeHandler(std::ostream& ostr);
virtual void writeFactory(std::ostream& ostr);
virtual void writeSession(std::ostream& ostr);
virtual void writeForm(std::ostream& ostr);
virtual void writeResponse(std::ostream& ostr);
virtual void writeContent(std::ostream& ostr);
virtual void writeManifest(std::ostream& ostr);
void beginGuard(std::ostream& ostr, const std::string& headerFileName);
void endGuard(std::ostream& ostr, const std::string& headerFileName);
void beginNamespace(std::ostream& ostr);
void endNamespace(std::ostream& ostr);
void handlerClass(std::ostream& ostr, const std::string& base, const std::string& ctorArg);
void factoryClass(std::ostream& ostr, const std::string& base);
void factoryImpl(std::ostream& ostr, const std::string& arg);
std::string cleanupHandler(std::string handler);
private:
CodeWriter();
CodeWriter(const CodeWriter&);
CodeWriter& operator = (const CodeWriter&);
const Page& _page;
std::string _class;
};
//
// inlines
//
inline const Page& CodeWriter::page() const
{
return _page;
}
inline const std::string& CodeWriter::clazz() const
{
return _class;
}
#endif // CodeWriter_INCLUDED

View File

@@ -0,0 +1,143 @@
//
// OSPCodeWriter.cpp
//
// Copyright (c) 2008, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "OSPCodeWriter.h"
#include "Page.h"
#include "Poco/NumberParser.h"
OSPCodeWriter::OSPCodeWriter(const Page& page, const std::string& clazz):
CodeWriter(page, clazz)
{
}
OSPCodeWriter::~OSPCodeWriter()
{
}
void OSPCodeWriter::writeHeaderIncludes(std::ostream& ostr)
{
CodeWriter::writeHeaderIncludes(ostr);
ostr << "#include \"Poco/OSP/Web/WebRequestHandlerFactory.h\"\n";
ostr << "#include \"Poco/OSP/BundleContext.h\"\n";
}
void OSPCodeWriter::writeHandlerClass(std::ostream& ostr)
{
std::string base(page().get("page.baseClass", "Poco::Net::HTTPRequestHandler"));
handlerClass(ostr, base, "Poco::OSP::BundleContext::Ptr");
}
void OSPCodeWriter::writeHandlerMembers(std::ostream& ostr)
{
std::string base(page().get("page.baseClass", ""));
if (base.empty())
{
ostr << "\n";
ostr << "protected:\n";
ostr << "\tPoco::OSP::BundleContext::Ptr context() const\n";
ostr << "\t{\n";
ostr << "\t\treturn _pContext;\n";
ostr << "\t}\n";
ostr << "\n";
ostr << "\tPoco::OSP::BundleContext::Ptr c() const\n";
ostr << "\t{\n";
ostr << "\t\treturn _pContext;\n";
ostr << "\t}\n";
ostr << "\n";
ostr << "private:\n";
ostr << "\tPoco::OSP::BundleContext::Ptr _pContext;\n";
}
}
void OSPCodeWriter::writeFactoryClass(std::ostream& ostr)
{
ostr << "\n\n";
factoryClass(ostr, "Poco::OSP::Web::WebRequestHandlerFactory");
}
void OSPCodeWriter::writeImplIncludes(std::ostream& ostr)
{
CodeWriter::writeImplIncludes(ostr);
if (page().has("page.session"))
{
ostr << "#include \"Poco/OSP/Web/WebSession.h\"\n";
ostr << "#include \"Poco/OSP/Web/WebSessionManager.h\"\n";
ostr << "#include \"Poco/OSP/ServiceRegistry.h\"\n";
}
}
void OSPCodeWriter::writeConstructor(std::ostream& ostr)
{
std::string base(page().get("page.baseClass", ""));
ostr << clazz() << "::" << clazz() << "(Poco::OSP::BundleContext::Ptr pContext):\n";
if (base.empty())
{
ostr << "\t_pContext(pContext)\n";
}
else
{
ostr << "\t" << base << "(pContext)\n";
}
ostr << "{\n}\n";
ostr << "\n\n";
}
void OSPCodeWriter::writeSession(std::ostream& ostr)
{
if (page().has("page.session"))
{
std::string session = page().get("page.session");
std::string sessionCode;
if (session.empty()) return;
if (session[0] == '@')
sessionCode = "context()->thisBundle()->properties().getString(\"" + session.substr(1) + "\"s)";
else
sessionCode = "\"" + session + "\"s";
std::string sessionTimeoutCode = page().get("page.sessionTimeout", "30");
int sessionTimeout;
if (!Poco::NumberParser::tryParse(sessionTimeoutCode, sessionTimeout))
{
sessionTimeoutCode = "context()->thisBundle()->properties().getInt(\"" + sessionTimeoutCode + "\"s)";
}
ostr << "\tPoco::OSP::Web::WebSession::Ptr session;\n";
ostr << "\t{\n";
ostr << "\t\tPoco::OSP::ServiceRef::Ptr pWebSessionManagerRef = context()->registry().findByName(Poco::OSP::Web::WebSessionManager::SERVICE_NAME);\n";
ostr << "\t\tif (pWebSessionManagerRef)\n";
ostr << "\t\t{\n";
ostr << "\t\t\tPoco::OSP::Web::WebSessionManager::Ptr pWebSessionManager = pWebSessionManagerRef->castedInstance<Poco::OSP::Web::WebSessionManager>();\n";
if (page().get("page.createSession", "true") != "false")
{
ostr << "\t\t\tsession = pWebSessionManager->get(" << sessionCode << ", request, " << sessionTimeoutCode << ", context());\n";
}
else
{
ostr << "\t\t\tsession = pWebSessionManager->find(" << sessionCode << ", request);\n";
}
ostr << "\t\t}\n";
ostr << "\t}\n";
}
}
void OSPCodeWriter::writeFactory(std::ostream& ostr)
{
ostr << "\n\n";
factoryImpl(ostr, "context()");
}

View File

@@ -0,0 +1,40 @@
//
// OSPCodeWriter.h
//
// Copyright (c) 2008, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#ifndef OSPCodeWriter_INCLUDED
#define OSPCodeWriter_INCLUDED
#include "CodeWriter.h"
class OSPCodeWriter: public CodeWriter
/// Code generator for OSP Web request handlers.
{
public:
OSPCodeWriter(const Page& page, const std::string& clazz);
/// Creates the CodeWriter, using the given Page.
~OSPCodeWriter();
/// Destroys the PageReader.
protected:
virtual void writeHeaderIncludes(std::ostream& ostr);
virtual void writeHandlerClass(std::ostream& ostr);
virtual void writeHandlerMembers(std::ostream& ostr);
virtual void writeFactoryClass(std::ostream& ostr);
virtual void writeImplIncludes(std::ostream& ostr);
virtual void writeConstructor(std::ostream& ostr);
virtual void writeFactory(std::ostream& ostr);
virtual void writeSession(std::ostream& ostr);
};
#endif // CodeWriter_INCLUDED

46
vendor/POCO/PageCompiler/src/Page.cpp vendored Normal file
View File

@@ -0,0 +1,46 @@
//
// Page.cpp
//
// Copyright (c) 2008, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Page.h"
#include "Poco/String.h"
#include "Poco/NumberParser.h"
Page::Page()
{
}
Page::~Page()
{
}
bool Page::getBool(const std::string& property, bool deflt) const
{
if (has(property))
{
const std::string& value = get(property);
return Poco::icompare(value, "true") == 0
|| Poco::icompare(value, "yes") == 0
|| Poco::icompare(value, "on") == 0;
}
else return deflt;
}
int Page::getInt(const std::string& property, int deflt) const
{
if (has(property))
{
return Poco::NumberParser::parse(get(property));
}
else return deflt;
}

130
vendor/POCO/PageCompiler/src/Page.h vendored Normal file
View File

@@ -0,0 +1,130 @@
//
// Page.h
//
// Copyright (c) 2008, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#ifndef Page_INCLUDED
#define Page_INCLUDED
#include "Poco/Net/NameValueCollection.h"
#include <sstream>
class Page: public Poco::Net::NameValueCollection
/// This class represents a server page consisting of
/// handler code and declarations, as well as page attributes.
{
public:
Page();
/// Creates a Page.
~Page();
/// Destroys the Page.
std::stringstream& headerDecls();
/// Returns the user-specified declarations for the header file.
const std::stringstream& headerDecls() const;
/// Returns the user-specified declarations for the header file.
std::stringstream& implDecls();
/// Returns the user-specified declarations for the source file.
const std::stringstream& implDecls() const;
/// Returns the user-specified declarations for the source file.
std::stringstream& handler();
/// Returns the request handler code.
const std::stringstream& handler() const;
/// Returns the request prehandler code.
std::stringstream& preHandler();
/// Returns the request handler code.
const std::stringstream& preHandler() const;
/// Returns the request prehandler code.
bool getBool(const std::string& property, bool deflt = false) const;
/// Returns the boolean value of the given property.
///
/// The return value will be true if the property
/// has one of the following values:
/// - true
/// - yes
/// - on
///
/// Otherwise, the return value will be false.
int getInt(const std::string& property, int deflt = 0) const;
/// Returns the integer value of the given property.
private:
Page(const Page&);
Page& operator = (const Page&);
std::stringstream _headerDecls;
std::stringstream _implDecls;
std::stringstream _handler;
std::stringstream _preHandler;
};
//
// inlines
//
inline std::stringstream& Page::headerDecls()
{
return _headerDecls;
}
inline const std::stringstream& Page::headerDecls() const
{
return _headerDecls;
}
inline std::stringstream& Page::implDecls()
{
return _implDecls;
}
inline const std::stringstream& Page::implDecls() const
{
return _implDecls;
}
inline std::stringstream& Page::handler()
{
return _handler;
}
inline const std::stringstream& Page::handler() const
{
return _handler;
}
inline std::stringstream& Page::preHandler()
{
return _preHandler;
}
inline const std::stringstream& Page::preHandler() const
{
return _preHandler;
}
#endif // Page_INCLUDED

View File

@@ -0,0 +1,390 @@
//
// PageCompiler.cpp
//
// A compiler that compiler HTML pages containing JSP directives into C++ classes.
//
// Copyright (c) 2008, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Util/Application.h"
#include "Poco/Util/Option.h"
#include "Poco/Util/OptionSet.h"
#include "Poco/Util/HelpFormatter.h"
#include "Poco/Util/AbstractConfiguration.h"
#include "Poco/AutoPtr.h"
#include "Poco/FileStream.h"
#include "Poco/Path.h"
#include "Poco/DateTime.h"
#include "Poco/DateTimeFormatter.h"
#include "Poco/DateTimeFormat.h"
#include "Poco/StringTokenizer.h"
#include "Poco/LineEndingConverter.h"
#include "Poco/Ascii.h"
#include "Page.h"
#include "PageReader.h"
#include "CodeWriter.h"
#include "ApacheCodeWriter.h"
#include "OSPCodeWriter.h"
#include <sstream>
#include <iostream>
#include <memory>
using Poco::Util::Application;
using Poco::Util::Option;
using Poco::Util::OptionSet;
using Poco::Util::HelpFormatter;
using Poco::Util::AbstractConfiguration;
using Poco::Util::OptionCallback;
using Poco::AutoPtr;
using Poco::FileInputStream;
using Poco::FileOutputStream;
using Poco::Path;
using Poco::DateTime;
using Poco::DateTimeFormatter;
using Poco::DateTimeFormat;
using Poco::StringTokenizer;
using Poco::OutputLineEndingConverter;
class CompilerApp: public Application
{
public:
CompilerApp():
_helpRequested(false),
_generateOSPCode(false),
_generateApacheCode(false),
_emitLineDirectives(true),
_escape(false)
{
}
protected:
void initialize(Application& self)
{
loadConfiguration(); // load default configuration files, if present
Application::initialize(self);
}
void defineOptions(OptionSet& options)
{
Application::defineOptions(options);
options.addOption(
Option("help", "h", "Display help information on command line arguments.")
.required(false)
.repeatable(false)
.callback(OptionCallback<CompilerApp>(this, &CompilerApp::handleHelp)));
options.addOption(
Option("define", "D",
"Define a configuration property. A configuration property "
"defined with this option can be referenced in the input "
"page file, using the following syntax: ${<name>}.")
.required(false)
.repeatable(true)
.argument("<name>=<value>")
.callback(OptionCallback<CompilerApp>(this, &CompilerApp::handleDefine)));
options.addOption(
Option("config-file", "f", "Load configuration data from the given file.")
.required(false)
.repeatable(true)
.argument("<file>")
.callback(OptionCallback<CompilerApp>(this, &CompilerApp::handleConfig)));
options.addOption(
Option("output-dir", "o", "Write output files to directory <dir>.")
.required(false)
.repeatable(false)
.argument("<dir>")
.callback(OptionCallback<CompilerApp>(this, &CompilerApp::handleOutputDir)));
options.addOption(
Option("header-output-dir", "H", "Write header file to directory <dir>.")
.required(false)
.repeatable(false)
.argument("<dir>")
.callback(OptionCallback<CompilerApp>(this, &CompilerApp::handleHeaderOutputDir)));
options.addOption(
Option("header-prefix", "P", "Prepend the given <prefix> to the header file name in the generated #include directive.")
.required(false)
.repeatable(false)
.argument("<prefix>")
.callback(OptionCallback<CompilerApp>(this, &CompilerApp::handleHeaderPrefix)));
options.addOption(
Option("base-file-name", "b", "Use <name> instead of the class name for the output file name.")
.required(false)
.repeatable(false)
.argument("<name>")
.callback(OptionCallback<CompilerApp>(this, &CompilerApp::handleBase)));
options.addOption(
Option("osp", "O", "Add factory class definition and implementation for use with the Open Service Platform.")
.required(false)
.repeatable(false)
.callback(OptionCallback<CompilerApp>(this, &CompilerApp::handleOSP)));
options.addOption(
Option("apache", "A", "Add factory class definition and implementation, and shared library manifest for use with ApacheConnector.")
.required(false)
.repeatable(false)
.callback(OptionCallback<CompilerApp>(this, &CompilerApp::handleApache)));
options.addOption(
Option("noline", "N", "Do not include #line directives in generated code.")
.required(false)
.repeatable(false)
.callback(OptionCallback<CompilerApp>(this, &CompilerApp::handleNoLine)));
options.addOption(
Option("escape", "e", "Escape special HTML characters (<, >, \", &) in <%= %> expressions.")
.required(false)
.repeatable(false)
.callback(OptionCallback<CompilerApp>(this, &CompilerApp::handleEscape)));
}
void handleHelp(const std::string& name, const std::string& value)
{
_helpRequested = true;
stopOptionsProcessing();
}
void handleDefine(const std::string& name, const std::string& value)
{
defineProperty(value);
}
void handleConfig(const std::string& name, const std::string& value)
{
loadConfiguration(value);
}
void handleOutputDir(const std::string& name, const std::string& value)
{
_outputDir = value;
}
void handleHeaderOutputDir(const std::string& name, const std::string& value)
{
_headerOutputDir = value;
}
void handleHeaderPrefix(const std::string& name, const std::string& value)
{
_headerPrefix = value;
if (!_headerPrefix.empty() && _headerPrefix[_headerPrefix.size() - 1] != '/')
_headerPrefix += '/';
}
void handleBase(const std::string& name, const std::string& value)
{
_base = value;
}
void handleOSP(const std::string& name, const std::string& value)
{
_generateOSPCode = true;
}
void handleApache(const std::string& name, const std::string& value)
{
_generateApacheCode = true;
}
void handleNoLine(const std::string& name, const std::string& value)
{
_emitLineDirectives = false;
}
void handleEscape(const std::string& name, const std::string& value)
{
_escape = true;
}
void displayHelp()
{
HelpFormatter helpFormatter(options());
helpFormatter.setCommand(commandName());
helpFormatter.setUsage("[<option> ...] <file> ...");
helpFormatter.setHeader(
"\n"
"The POCO C++ Server Page Compiler.\n"
"Copyright (c) 2008-2020 by Applied Informatics Software Engineering GmbH.\n"
"All rights reserved.\n\n"
"This program compiles web pages containing embedded C++ code "
"into a C++ class that can be used with the HTTP server "
"from the POCO Net library. \n\n"
"The following command line options are supported:"
);
helpFormatter.setFooter(
"For more information, please see the POCO C++ Libraries "
"documentation at <http://pocoproject.org/docs/>."
);
helpFormatter.setIndent(8);
helpFormatter.format(std::cout);
}
void defineProperty(const std::string& def)
{
std::string name;
std::string value;
std::string::size_type pos = def.find('=');
if (pos != std::string::npos)
{
name.assign(def, 0, pos);
value.assign(def, pos + 1, def.length() - pos);
}
else name = def;
config().setString(name, value);
}
int main(const std::vector<std::string>& args)
{
if (_helpRequested || args.empty())
{
displayHelp();
return Application::EXIT_OK;
}
for (std::vector<std::string>::const_iterator it = args.begin(); it != args.end(); ++it)
{
compile(*it);
}
return Application::EXIT_OK;
}
void parse(const std::string& path, Page& page, std::string& clazz)
{
FileInputStream srcStream(path);
PageReader pageReader(page, path);
pageReader.emitLineDirectives(_emitLineDirectives);
pageReader.parse(srcStream);
Path p(path);
if (page.has("page.class"))
{
clazz = page.get("page.class");
}
else
{
clazz = p.getBaseName() + "Handler";
clazz[0] = Poco::Ascii::toUpper(clazz[0]);
}
}
void write(const std::string& path, const Page& page, const std::string& clazz)
{
Path p(path);
config().setString("inputFileName", p.getFileName());
config().setString("inputFilePath", p.toString());
DateTime now;
config().setString("dateTime", DateTimeFormatter::format(now, DateTimeFormat::SORTABLE_FORMAT));
if (page.has("page.class"))
{
p.setBaseName(clazz);
}
std::unique_ptr<CodeWriter> pCodeWriter(createCodeWriter(page, clazz));
if (!_outputDir.empty())
{
p = Path(_outputDir, p.getBaseName());
}
if (!_base.empty())
{
p.setBaseName(_base);
}
p.setExtension("cpp");
std::string implPath = p.toString();
std::string implFileName = p.getFileName();
if (!_headerOutputDir.empty())
{
p = Path(_headerOutputDir, p.getBaseName());
}
p.setExtension("h");
std::string headerPath = p.toString();
std::string headerFileName = p.getFileName();
config().setString("outputFileName", implFileName);
config().setString("outputFilePath", implPath);
FileOutputStream implStream(implPath);
OutputLineEndingConverter implLEC(implStream);
writeFileHeader(implLEC);
pCodeWriter->writeImpl(implLEC, _headerPrefix + headerFileName);
config().setString("outputFileName", headerFileName);
config().setString("outputFilePath", headerPath);
FileOutputStream headerStream(headerPath);
OutputLineEndingConverter headerLEC(headerStream);
writeFileHeader(headerLEC);
pCodeWriter->writeHeader(headerLEC, headerFileName);
}
void compile(const std::string& path)
{
Page page;
if (_escape)
{
page.set("page.escape", "true");
}
std::string clazz;
parse(path, page, clazz);
write(path, page, clazz);
FileInputStream srcStream(path);
PageReader pageReader(page, path);
pageReader.emitLineDirectives(_emitLineDirectives);
pageReader.parse(srcStream);
}
void writeFileHeader(std::ostream& ostr)
{
std::string fileHeader = config().getString("PageCompiler.fileHeader", "");
if (!fileHeader.empty())
{
ostr << fileHeader << std::endl;
ostr << "\n\n";
}
}
CodeWriter* createCodeWriter(const Page& page, const std::string& clazz)
{
if (_generateOSPCode)
return new OSPCodeWriter(page, clazz);
else if (_generateApacheCode)
return new ApacheCodeWriter(page, clazz);
else
return new CodeWriter(page, clazz);
}
private:
bool _helpRequested;
bool _generateOSPCode;
bool _generateApacheCode;
bool _emitLineDirectives;
bool _escape;
std::string _outputDir;
std::string _headerOutputDir;
std::string _headerPrefix;
std::string _base;
};
POCO_APP_MAIN(CompilerApp)

View File

@@ -0,0 +1,423 @@
//
// PageReader.cpp
//
// Copyright (c) 2008, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "PageReader.h"
#include "Page.h"
#include "Poco/FileStream.h"
#include "Poco/CountingStream.h"
#include "Poco/Path.h"
#include "Poco/Exception.h"
#include "Poco/Ascii.h"
const std::string PageReader::MARKUP_BEGIN("\tresponseStream << \"");
const std::string PageReader::MARKUP_END("\";\n");
const std::string PageReader::EXPR_BEGIN("\tresponseStream << (");
const std::string PageReader::EXPR_END(");\n");
const std::string PageReader::ESC_EXPR_BEGIN("\t_escapeStream << (");
const std::string PageReader::ESC_EXPR_END(");\n");
PageReader::PageReader(Page& page, const std::string& path):
_page(page),
_pParent(0),
_path(path),
_line(0),
_emitLineDirectives(false)
{
_attrs.reserve(4096);
}
PageReader::PageReader(const PageReader& parent, const std::string& path):
_page(parent._page),
_pParent(&parent),
_path(path),
_line(0),
_emitLineDirectives(false)
{
_attrs.reserve(4096);
}
PageReader::~PageReader()
{
}
void PageReader::emitLineDirectives(bool flag)
{
_emitLineDirectives = flag;
}
void PageReader::parse(std::istream& pageStream)
{
ParsingState state = STATE_MARKUP;
_page.handler() << MARKUP_BEGIN;
Poco::CountingInputStream countingPageStream(pageStream);
std::string token;
nextToken(countingPageStream, token);
while (!token.empty())
{
_line = countingPageStream.getCurrentLineNumber();
if (token == "<%")
{
if (state == STATE_MARKUP)
{
_page.handler() << MARKUP_END;
generateLineDirective(_page.handler());
state = STATE_BLOCK;
}
else _page.handler() << token;
}
else if (token == "<%%")
{
if (state == STATE_MARKUP)
{
_page.handler() << MARKUP_END;
generateLineDirective(_page.preHandler());
state = STATE_PREHANDLER;
}
else _page.handler() << token;
}
else if (token == "<%!")
{
if (state == STATE_MARKUP)
{
_page.handler() << MARKUP_END;
generateLineDirective(_page.implDecls());
state = STATE_IMPLDECL;
}
else _page.handler() << token;
}
else if (token == "<%!!")
{
if (state == STATE_MARKUP)
{
_page.handler() << MARKUP_END;
generateLineDirective(_page.headerDecls());
state = STATE_HDRDECL;
}
else _page.handler() << token;
}
else if (token == "<%--")
{
if (state == STATE_MARKUP)
{
_page.handler() << MARKUP_END;
state = STATE_COMMENT;
}
else _page.handler() << token;
}
else if (token == "<%@")
{
if (state == STATE_MARKUP)
{
_page.handler() << MARKUP_END;
state = STATE_ATTR;
_attrs.clear();
}
else _page.handler() << token;
}
else if (token == "<%=")
{
if (state == STATE_MARKUP)
{
_page.handler() << MARKUP_END;
generateLineDirective(_page.handler());
if (escape())
{
_page.handler() << ESC_EXPR_BEGIN;
state = STATE_ESC_EXPR;
}
else
{
_page.handler() << EXPR_BEGIN;
state = STATE_EXPR;
}
}
else _page.handler() << token;
}
else if (token == "<%-")
{
if (state == STATE_MARKUP)
{
_page.handler() << MARKUP_END;
generateLineDirective(_page.handler());
_page.handler() << EXPR_BEGIN;
state = STATE_EXPR;
}
else _page.handler() << token;
}
else if (token == "%>")
{
if (state == STATE_EXPR)
{
_page.handler() << EXPR_END;
_page.handler() << MARKUP_BEGIN;
state = STATE_MARKUP;
}
else if (state == STATE_ESC_EXPR)
{
_page.handler() << ESC_EXPR_END;
_page.handler() << MARKUP_BEGIN;
state = STATE_MARKUP;
}
else if (state == STATE_ATTR)
{
parseAttributes();
_attrs.clear();
_page.handler() << MARKUP_BEGIN;
state = STATE_MARKUP;
}
else if (state != STATE_MARKUP)
{
_page.handler() << MARKUP_BEGIN;
state = STATE_MARKUP;
}
else _page.handler() << token;
}
else
{
switch (state)
{
case STATE_MARKUP:
if (token == "\n")
{
_page.handler() << "\\n";
_page.handler() << MARKUP_END;
_page.handler() << MARKUP_BEGIN;
}
else if (token == "\t")
{
_page.handler() << "\\t";
}
else if (token == "\"")
{
_page.handler() << "\\\"";
}
else if (token == "\\")
{
_page.handler() << "\\\\";
}
else if (token != "\r")
{
_page.handler() << token;
}
break;
case STATE_IMPLDECL:
_page.implDecls() << token;
break;
case STATE_HDRDECL:
_page.headerDecls() << token;
break;
case STATE_PREHANDLER:
_page.preHandler() << token;
break;
case STATE_BLOCK:
_page.handler() << token;
break;
case STATE_EXPR:
case STATE_ESC_EXPR:
_page.handler() << token;
break;
case STATE_COMMENT:
break;
case STATE_ATTR:
_attrs += token;
break;
}
}
nextToken(countingPageStream, token);
}
if (state == STATE_MARKUP)
{
_page.handler() << MARKUP_END;
}
else throw Poco::SyntaxException("unclosed meta or code block", where());
}
void PageReader::parseAttributes()
{
static const int eof = std::char_traits<char>::eof();
std::string basename;
std::istringstream istr(_attrs);
int ch = istr.get();
while (ch != eof && Poco::Ascii::isSpace(ch)) ch = istr.get();
while (ch != eof && Poco::Ascii::isAlphaNumeric(ch)) { basename += (char) ch; ch = istr.get(); }
while (ch != eof && Poco::Ascii::isSpace(ch)) ch = istr.get();
while (ch != eof)
{
std::string name(basename + ".");
std::string value;
while (ch != eof && Poco::Ascii::isAlphaNumeric(ch)) { name += (char) ch; ch = istr.get(); }
while (ch != eof && Poco::Ascii::isSpace(ch)) ch = istr.get();
if (ch != '=') throw Poco::SyntaxException("bad attribute syntax: '=' expected", where());
ch = istr.get();
while (ch != eof && Poco::Ascii::isSpace(ch)) ch = istr.get();
if (ch == '"')
{
ch = istr.get();
while (ch != eof && ch != '"') { value += (char) ch; ch = istr.get(); }
if (ch != '"') throw Poco::SyntaxException("bad attribute syntax: '\"' expected", where());
}
else if (ch == '\'')
{
ch = istr.get();
while (ch != eof && ch != '\'') { value += (char) ch; ch = istr.get(); }
if (ch != '\'') throw Poco::SyntaxException("bad attribute syntax: ''' expected", where());
}
else throw Poco::SyntaxException("bad attribute syntax: '\"' or ''' expected", where());
ch = istr.get();
handleAttribute(name, value);
while (ch != eof && Poco::Ascii::isSpace(ch)) ch = istr.get();
}
}
void PageReader::nextToken(std::istream& istr, std::string& token)
{
token.clear();
int ch = istr.get();
if (ch != -1)
{
if (ch == '<' && istr.peek() == '%')
{
token += "<%";
istr.get();
ch = istr.peek();
switch (ch)
{
case '%':
case '@':
case '=':
ch = istr.get();
token += (char) ch;
break;
case '!':
ch = istr.get();
token += (char) ch;
if (istr.peek() == '!')
{
ch = istr.get();
token += (char) ch;
}
break;
case '-':
ch = istr.get();
token += (char) ch;
if (istr.peek() == '-')
{
ch = istr.get();
token += (char) ch;
}
break;
}
}
else if (ch == '%' && istr.peek() == '>')
{
token += "%>";
istr.get();
}
else token += (char) ch;
}
}
void PageReader::handleAttribute(const std::string& name, const std::string& value)
{
if (name == "include.page" || name == "include.file")
{
include(value);
}
else if (name == "header.include")
{
_page.headerDecls() << "#include \"" << value << "\"\n";
}
else if (name == "header.sinclude")
{
_page.headerDecls() << "#include <" << value << ">\n";
}
else if (name == "impl.include")
{
_page.implDecls() << "#include \"" << value << "\"\n";
}
else if (name == "impl.sinclude")
{
_page.implDecls() << "#include <" << value << ">\n";
}
else
{
_page.set(name, value);
}
}
void PageReader::include(const std::string& path)
{
Poco::Path currentPath(_path);
Poco::Path includePath(path);
currentPath.resolve(includePath);
_page.handler() << "\t// begin include " << currentPath.toString() << "\n";
Poco::FileInputStream includeStream(currentPath.toString());
PageReader includeReader(*this, currentPath.toString());
includeReader.emitLineDirectives(_emitLineDirectives);
includeReader.parse(includeStream);
_page.handler() << "\t// end include " << currentPath.toString() << "\n";
}
std::string PageReader::where() const
{
std::stringstream result;
result << "in file '" << _path << "', line " << _line;
const PageReader* pParent = _pParent;
while (pParent)
{
result << "\n\tincluded from file '"<< pParent->_path << "', line " << pParent->_line;
pParent = pParent->_pParent;
}
return result.str();
}
void PageReader::generateLineDirective(std::ostream& ostr)
{
if (_emitLineDirectives)
{
Poco::Path p(_path);
p.makeAbsolute();
std::string absPath = p.toString();
ostr << "#line " << _line << " \"";
for (std::string::const_iterator it = absPath.begin(); it != absPath.end(); ++it)
{
if (*it == '\\')
ostr << "\\\\";
else
ostr << *it;
}
ostr << "\"\n";
}
}
bool PageReader::escape() const
{
return _page.getBool("page.escape", false);
}

View File

@@ -0,0 +1,92 @@
//
// PageReader.h
//
// Copyright (c) 2008, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#ifndef PageReader_INCLUDED
#define PageReader_INCLUDED
#include "Poco/Poco.h"
#include <istream>
#include <ostream>
#include <sstream>
class Page;
class PageReader
/// This class implements the parser for reading page files
/// containing JSP-style tags.
{
public:
PageReader(Page& page, const std::string& path);
/// Creates the PageReader, using the given Page.
PageReader(const PageReader& parent, const std::string& path);
/// Creates the PageReader, using the given PageReader as parent.
~PageReader();
/// Destroys the PageReader.
void parse(std::istream& pageStream);
/// Parses a HTML file containing server page directives,
/// converts the file into C++ code and adds the code
/// to the reader's Page object. Also parses page
/// attributes and include directives.
void emitLineDirectives(bool flag = true);
/// Enables writing of #line directives to generated code.
protected:
enum ParsingState
{
STATE_MARKUP,
STATE_IMPLDECL,
STATE_HDRDECL,
STATE_PREHANDLER,
STATE_BLOCK,
STATE_EXPR,
STATE_ESC_EXPR,
STATE_COMMENT,
STATE_ATTR
};
static const std::string MARKUP_BEGIN;
static const std::string MARKUP_END;
static const std::string EXPR_BEGIN;
static const std::string EXPR_END;
static const std::string ESC_EXPR_BEGIN;
static const std::string ESC_EXPR_END;
void include(const std::string& path);
void parseAttributes();
void nextToken(std::istream& istr, std::string& token);
void handleAttribute(const std::string& name, const std::string& value);
std::string where() const;
bool escape() const;
protected:
void generateLineDirective(std::ostream& ostr);
private:
PageReader();
PageReader(const PageReader&);
PageReader& operator = (const PageReader&);
Page& _page;
const PageReader* _pParent;
std::string _path;
std::string _attrs;
std::streamsize _line;
bool _emitLineDirectives;
};
#endif // PageReader_INCLUDED