From b23f4c3efee981f10bf100970b6db5602e955ba1 Mon Sep 17 00:00:00 2001 From: zosrothko Date: Wed, 1 Nov 2017 09:03:10 +0100 Subject: [PATCH] Backport from feature-gradle Signed-off-by: zosrothko --- Foundation/include/Poco/Environment.h | 127 ++ Foundation/src/Environment.cpp | 166 ++ PocoDoc/cfg/mkdoc-poco.xml | 135 ++ PocoDoc/cfg/mkdocumentation.xml | 117 ++ PocoDoc/src/DocWriter.cpp | 2377 +++++++++++++++++++++++++ PocoDoc/src/DocWriter.h | 227 +++ PocoDoc/src/PocoDoc.cpp | 494 +++++ 7 files changed, 3643 insertions(+) create mode 100644 Foundation/include/Poco/Environment.h create mode 100644 Foundation/src/Environment.cpp create mode 100644 PocoDoc/cfg/mkdoc-poco.xml create mode 100644 PocoDoc/cfg/mkdocumentation.xml create mode 100644 PocoDoc/src/DocWriter.cpp create mode 100644 PocoDoc/src/DocWriter.h create mode 100644 PocoDoc/src/PocoDoc.cpp diff --git a/Foundation/include/Poco/Environment.h b/Foundation/include/Poco/Environment.h new file mode 100644 index 000000000..8faf7b5f7 --- /dev/null +++ b/Foundation/include/Poco/Environment.h @@ -0,0 +1,127 @@ +// +// Environment.h +// +// Library: Foundation +// Package: Core +// Module: Environment +// +// Definition of the Environment class. +// +// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// SPDX-License-Identifier: BSL-1.0 +// + + +#ifndef Foundation_Environment_INCLUDED +#define Foundation_Environment_INCLUDED + + +#include "Poco/Foundation.h" + + +namespace Poco { + + +class Foundation_API Environment + /// This class provides access to environment variables + /// and some general system information. +{ +public: + typedef UInt8 NodeId[6]; /// Ethernet address. + + static std::string get(const std::string& name); + /// Returns the value of the environment variable + /// with the given name. Throws a NotFoundException + /// if the variable does not exist. + + static std::string get(const std::string& name, const std::string& defaultValue); + /// Returns the value of the environment variable + /// with the given name. If the environment variable + /// is undefined, returns defaultValue instead. + + static bool has(const std::string& name); + /// Returns true iff an environment variable + /// with the given name is defined. + + static void set(const std::string& name, const std::string& value); + /// Sets the environment variable with the given name + /// to the given value. + + static std::string osName(); + /// Returns the operating system name. + + static std::string osDisplayName(); + /// Returns the operating system name in a + /// "user-friendly" way. + /// + /// Currently this is only implemented for + /// Windows. There it will return names like + /// "Windows XP" or "Windows 7/Server 2008 SP2". + /// On other platforms, returns the same as + /// osName(). + + static std::string osVersion(); + /// Returns the operating system version. + + static std::string osArchitecture(); + /// Returns the operating system architecture. + + static std::string nodeName(); + /// Returns the node (or host) name. + + static void nodeId(NodeId& id); + /// Returns the Ethernet address of the first Ethernet + /// adapter found on the system. + /// + /// Throws a SystemException if no Ethernet adapter is available. + + static std::string nodeId(); + /// Returns the Ethernet address (format "xx:xx:xx:xx:xx:xx") + /// of the first Ethernet adapter found on the system. + /// + /// Throws a SystemException if no Ethernet adapter is available. + + static unsigned processorCount(); + /// Returns the number of processors installed in the system. + /// + /// If the number of processors cannot be determined, returns 1. + + static Poco::UInt32 libraryVersion(); + /// Returns the POCO C++ Libraries version as a hexadecimal + /// number in format 0xAABBCCDD, where + /// - AA is the major version number, + /// - BB is the minor version number, + /// - CC is the revision number, and + /// - DD is the patch level number. + /// + /// Some patch level ranges have special meanings: + /// - Dx mark development releases, + /// - Ax mark alpha releases, and + /// - Bx mark beta releases. + + static Poco::Int32 os(); + /// Return the operating system as defined + /// in the include Foundation/Platform.h (POCO_OS) + + static Poco::Int32 cpu(); + /// Return the underlying cpu that runs this operating system + /// as defined in Foundation/Platform (POCO_ARCH) + + static bool osFamilyUnix(); + /// Return true if the operating system belongs to the Linux family + + static bool osFamilyWindows(); + /// Return true if the operating system belongs to the Windows family + + static bool osFamilyVms(); + /// Return true if the operating system belongs to the VMS family + +}; + + +} // namespace Poco + + +#endif // Foundation_Environment_INCLUDED diff --git a/Foundation/src/Environment.cpp b/Foundation/src/Environment.cpp new file mode 100644 index 000000000..5509aa791 --- /dev/null +++ b/Foundation/src/Environment.cpp @@ -0,0 +1,166 @@ +// +// Environment.cpp +// +// Library: Foundation +// Package: Core +// Module: Environment +// +// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// SPDX-License-Identifier: BSL-1.0 +// + + +#include "Poco/Environment.h" +#include "Poco/Version.h" +#include +#include // sprintf() + + +#if defined(POCO_OS_FAMILY_VMS) +#include "Environment_VMS.cpp" +#elif defined(POCO_VXWORKS) +#include "Environment_VX.cpp" +#elif defined(POCO_OS_FAMILY_UNIX) +#include "Environment_UNIX.cpp" +#elif defined(POCO_OS_FAMILY_WINDOWS) +#if defined(_WIN32_WCE) +#include "Environment_WINCE.cpp" +#else +#include "Environment_WIN32.cpp" +#endif +#endif + + +namespace Poco { + + +std::string Environment::get(const std::string& name) +{ + return EnvironmentImpl::getImpl(name); +} + + +std::string Environment::get(const std::string& name, const std::string& defaultValue) +{ + if (has(name)) + return get(name); + else + return defaultValue; +} + + +bool Environment::has(const std::string& name) +{ + return EnvironmentImpl::hasImpl(name); +} + + +void Environment::set(const std::string& name, const std::string& value) +{ + EnvironmentImpl::setImpl(name, value); +} + + +std::string Environment::osName() +{ + return EnvironmentImpl::osNameImpl(); +} + + +std::string Environment::osDisplayName() +{ + return EnvironmentImpl::osDisplayNameImpl(); +} + + +std::string Environment::osVersion() +{ + return EnvironmentImpl::osVersionImpl(); +} + + +std::string Environment::osArchitecture() +{ + return EnvironmentImpl::osArchitectureImpl(); +} + + +std::string Environment::nodeName() +{ + return EnvironmentImpl::nodeNameImpl(); +} + + +std::string Environment::nodeId() +{ + NodeId id; + nodeId(id); + char result[18]; + std::sprintf(result, "%02x:%02x:%02x:%02x:%02x:%02x", + id[0], + id[1], + id[2], + id[3], + id[4], + id[5]); + return std::string(result); +} + + +void Environment::nodeId(NodeId& id) +{ + return EnvironmentImpl::nodeIdImpl(id); +} + + +unsigned Environment::processorCount() +{ + return EnvironmentImpl::processorCountImpl(); +} + + +Poco::UInt32 Environment::libraryVersion() +{ + return POCO_VERSION; +} + +Poco::Int32 Environment::os() +{ + return POCO_OS; +} + +Poco::Int32 Environment::cpu() +{ + return POCO_ARCH; +} + +bool Environment::osFamilyUnix() +{ +#if defined(POCO_OS_FAMILY_UNIX) + return true; +#else + return false; +#endif +} + +bool Environment::osFamilyWindows() +{ +#if defined(POCO_OS_FAMILY_WINDOWS) + return true; +#else + return false; +#endif +} + +bool Environment::osFamilyVms() +{ +#if defined(POCO_OS_FAMILY_VMS) + return true; +#else + return false; +#endif +} + +} // namespace Poco diff --git a/PocoDoc/cfg/mkdoc-poco.xml b/PocoDoc/cfg/mkdoc-poco.xml new file mode 100644 index 000000000..19e62ccb9 --- /dev/null +++ b/PocoDoc/cfg/mkdoc-poco.xml @@ -0,0 +1,135 @@ + + + + + ${PocoBuild}/*/include/Poco/*.h + ${PocoBuild}/*/include/Poco/*/*.h + ${PocoBuild}/*/include/Poco/*/*/*.h + ${PocoBuild}/*/include/Poco/*/*.h + ${PocoBuild}/*/*/include/Poco/*/*/*.h + + + *_*.h, + expat*.h, + zconf.h, + zlib.h, + Alignment.h, + QName.h, + CppUnitException.h, + Constants.h, + inffast.h, + ${PocoBuild}/PDF/include/*.h, + ${PocoBuild}/CppParser/include/*.h + + + + ${PocoBuild}/doc/*.page, + ${PocoBuild}/*/doc/*.page + ${PocoBuild}/*/*/doc/*.page + + + ${PocoBase}/PocoDoc/resources/css, + ${PocoBase}/PocoDoc/resources/js, + ${PocoBase}/PocoDoc/resources/images, + ${PocoBase}/PocoDoc/resources/index.thtml, + ${PocoBuild}/*/doc/images + + + + cl.exe + + ${Includes}, + /I${PocoBase}/openssl/include + /I${VC}/include, + /I${WDK}/shared + /I${WDK}/um + /I${WDK}/ucrt + /nologo, + /D_DEBUG, + /E, + /C, + /DPOCO_NO_GCC_API_ATTRIBUTE + /DPOCO_NO_WINDOWS_H + + ${VC}/bin + true + + + ${CXX} ${CXXFLAGS} + + ${Includes}, + -I/usr/local/mysql/include, + -I/usr/include/mysql, + -I/usr/include/postgresql, + -D_DEBUG, + -E, + -C, + -DPOCO_NO_GCC_API_ATTRIBUTE + -DPOCO_NO_WINDOWS_H + + + true + + + EN + utf-8 + POCO C++ Libraries + Applied Informatics Software Engineering GmbH and Contributors + http://pocoproject.org/ + + + + All Base Classes + All Symbols + Anonymous + Constructors + Class + Deprecated + Description + Destructor + Direct Base Classes + Enumerations + Functions +
Header
+ if and only if + Inheritance + Inherited Functions + is deprecated and should no longer be used + Known Derived Classes + Library + Member Functions + Member Summary + more... + Namespaces + Namespace + Nested Classes + Package + Packages + Package Index + See also + Struct + Symbol Index + This + Types + Variables + Contents + User Guides and Tutorials + Introduction +
+
+ + + + + c1 + warning + + + + + ConsoleChannel + %s: [%p] %t + + + +
diff --git a/PocoDoc/cfg/mkdocumentation.xml b/PocoDoc/cfg/mkdocumentation.xml new file mode 100644 index 000000000..affe2828c --- /dev/null +++ b/PocoDoc/cfg/mkdocumentation.xml @@ -0,0 +1,117 @@ + + + + + ${PocoBuild}/*/include/Poco/*.h + ${PocoBuild}/*/include/Poco/*/*.h + ${PocoBuild}/*/include/Poco/*/*/*.h + ${PocoBuild}/*/include/Poco/*/*.h + ${PocoBuild}/*/*/include/Poco/*/*/*.h + + + *_*.h, + expat*.h, + zconf.h, + zlib.h, + XMLStreamParser.h, + CppUnitException.h, + RepeatedTest.h, + + + + ${PocoBuild}/doc/*.page, + ${PocoBuild}/*/doc/*.page + ${PocoBuild}/*/*/doc/*.page + + + ${PocoBase}/PocoDoc/resources/css, + ${PocoBase}/PocoDoc/resources/js, + ${PocoBase}/PocoDoc/resources/images, + ${PocoBase}/PocoDoc/resources/index.thtml, + ${PocoBuild}/*/doc/images + + + C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin\cl.exe + + ${Includes}, + -I/usr/local/mysql/include, + -I/usr/include/mysql, + -I/usr/include/postgresql, + /I${PocoBase}/openssl/include + /IC:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\include, + /IC:\Program Files (x86)\Windows Kits\8.1\Include\shared, + /IC:\Program Files (x86)\Windows Kits\8.1\Include\um, + /IC:\Program Files (x86)\Windows Kits\10\Include\10.0.15063.0\ucrt, + /nologo, + -D_DEBUG, + -E, + -C, + -DPOCO_NO_GCC_API_ATTRIBUTE + -DPOCO_NO_WINDOWS_H + + + true + + EN + utf-8 + Applied Informatics C++ Libraries and Tools + Applied Informatics Software Engineering GmbH and Contributors + http://www.appinf.com/ + images/headerlogo.png + + + + All Base Classes + All Symbols + Anonymous + Constructors + Class + Deprecated + Description + Destructor + Direct Base Classes + Enumerations + Functions +
Header
+ if and only if + Inheritance + Inherited Functions + is deprecated and should no longer be used + Known Derived Classes + Library + Member Functions + Member Summary + more... + Namespaces + Namespace + Nested Classes + Package + Packages + Package Index + See also + Struct + Symbol Index + This + Types + Variables + Contents + User Guides and Tutorials + Introduction +
+
+ + + + + c1 + information + + + + + ConsoleChannel + %s: [%p] %t + + + +
diff --git a/PocoDoc/src/DocWriter.cpp b/PocoDoc/src/DocWriter.cpp new file mode 100644 index 000000000..a6361aef1 --- /dev/null +++ b/PocoDoc/src/DocWriter.cpp @@ -0,0 +1,2377 @@ +// +// DocWriter.cpp +// +// Copyright (c) 2005-2014, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// SPDX-License-Identifier: BSL-1.0 +// + + +#include "DocWriter.h" +#include "Poco/NumberFormatter.h" +#include "Poco/Path.h" +#include "Poco/String.h" +#include "Poco/DateTime.h" +#include "Poco/DateTimeFormat.h" +#include "Poco/DateTimeFormatter.h" +#include "Poco/RegularExpression.h" +#include "Poco/Exception.h" +#include "Poco/Format.h" +#include "Poco/Util/Application.h" +#include "Poco/CppParser/Struct.h" +#include "Poco/CppParser/Enum.h" +#include "Poco/CppParser/EnumValue.h" +#include "Poco/CppParser/Function.h" +#include "Poco/CppParser/Parameter.h" +#include "Poco/CppParser/TypeDef.h" +#include "Poco/CppParser/Variable.h" +#include +#include +#include +#include + + +using Poco::NumberFormatter; +using Poco::Path; +using Poco::DateTime; +using Poco::DateTimeFormat; +using Poco::DateTimeFormatter; +using Poco::RegularExpression; +using Poco::format; +using Poco::Util::Application; +using namespace Poco::CppParser; + + +std::string DocWriter::_language; +DocWriter::StringMap DocWriter::_strings; +Poco::Logger* DocWriter::_pLogger(0); +const std::string DocWriter::RFC_URI("http://www.ietf.org/rfc/rfc"); +const std::string DocWriter::nbsp(" "); // Invalid HTML entity for XML. Replace   with   +const std::string DocWriter::copy("©"); // Invalid HTML entity for XML. Replace © with © +const std::string DocWriter::mdash("—"); // Invalid HTML entity for XML. Replace — with — + +DocWriter::DocWriter(const NameSpace::SymbolTable& symbols, const std::string& path, bool prettifyCode, bool noFrames): + _prettifyCode(prettifyCode), + _noFrames(noFrames), + _htmlMode(false), + _literalMode(false), + _symbols(symbols), + _path(path), + _pNameSpace(0), + _pendingLine(false), + _indent(0), + _titleId(0) +{ + _pLogger = &Poco::Logger::get("DocWriter"); + + Application& app = Application::instance(); + _language = app.config().getString("PocoDoc.language", "EN"); + + logger().information(std::string("Loading translation strings [") + _language + "]"); + + loadStrings(_language); +} + + +DocWriter::~DocWriter() +{ +} + + +void DocWriter::addPage(const std::string& path) +{ + Page page; + page.path = path; + Path p(path); + p.setExtension("html"); + page.fileName = p.getFileName(); + _pages[page.fileName] = page; +} + + +void DocWriter::write() +{ + writePages(); + int nameSpaces = 0; + int classes = 0; + for (NameSpace::SymbolTable::const_iterator it = _symbols.begin(); it != _symbols.end(); ++it) + { + switch (it->second->kind()) + { + case Symbol::SYM_NAMESPACE: + ++nameSpaces; + logger().information("Generating namespace " + it->second->fullName()); + writeNameSpace(static_cast(it->second)); + break; + case Symbol::SYM_STRUCT: + ++classes; + logger().information("Generating class/struct " + it->second->fullName()); + writeClass(static_cast(it->second)); + break; + default: + break; + } + } + logger().information("Generating overview and index"); + writeNavigation(); + logger().information(NumberFormatter::format(nameSpaces) + " namespaces, " + NumberFormatter::format(classes) + " classes."); + Application& app = Application::instance(); + app.config().setInt("PocoDoc.statistics.namespaces", nameSpaces); + app.config().setInt("PocoDoc.statistics.classes", classes); + std::ostringstream pageIndexStream; + writePageIndex(pageIndexStream); + app.config().setString("PocoDoc.pageIndex", pageIndexStream.str()); + std::ostringstream nameSpaceIndexStream; + writeNameSpaceIndex(nameSpaceIndexStream); + app.config().setString("PocoDoc.nameSpaceIndex", nameSpaceIndexStream.str()); +} + + +void DocWriter::writeNavigation() +{ + Application& app = Application::instance(); + std::string software(app.config().getString("PocoDoc.software", "")); + + std::string path(pathFor("navigation.html")); + std::ofstream ostr(path.c_str()); + if (!ostr.good()) throw Poco::CreateFileException(path); + writeHeader(ostr, tr("Navigation"), "js/iframeResizer.contentWindow.min.js"); + beginBody(ostr); + ostr << "

" << htmlize(software) << "

\n"; + + if (!_pages.empty()) + { + ostr << "

" << tr("Guides") << "

\n"; + ostr << "
    \n"; + std::set categories; + for (PageMap::const_iterator it = _pages.begin(); it != _pages.end(); ++it) + { + categories.insert(it->second.category); + } + for (std::set::const_iterator it = categories.begin(); it != categories.end(); ++it) + { + std::string node = "category-"; + node += *it; + ostr << "
  • "; + ostr << tr(*it) << "\n"; + writeCategoryIndex(ostr, *it, "_top"); + ostr << "
  • \n"; + } + ostr << "
\n"; + } + + ostr << "

" << tr("Namespaces") << "

\n"; + ostr << "
    \n"; + + std::map namespaces; // sort namespaces by full name + for (NameSpace::SymbolTable::const_iterator it = _symbols.begin(); it != _symbols.end(); ++it) + { + if (it->second->kind() == Symbol::SYM_NAMESPACE) + { + namespaces[it->second->fullName()] = it->second; + } + } + for (std::map::const_iterator it = namespaces.begin(); it != namespaces.end(); ++it) + { + ostr << "
  • "; + writeTargetLink(ostr, baseNameFor(it->second) + ".html", it->second->fullName(), "_top"); + ostr << "
  • \n"; + } + ostr << "
\n"; + ostr << "

" << tr("Packages") << "

\n"; + ostr << "
    \n"; + std::set libs; + libraries(libs); + for (std::set::const_iterator itl = libs.begin(); itl != libs.end(); ++itl) + { + std::string node = "library-"; + node += *itl; + ostr << "
  • " << *itl << "\n"; + std::set pkgs; + packages(*itl, pkgs); + ostr << "
      \n"; + for (std::set::const_iterator itp = pkgs.begin(); itp != pkgs.end(); ++itp) + { + std::string uri("package-"); + uri += makeFileName(*itl); + uri += '.'; + uri += makeFileName(*itp); + uri += ".html"; + ostr << "
    • "; + writeTargetLink(ostr, uri, *itp, "_top"); + ostr << "
    • \n"; + writePackage(uri, *itl, *itp); + } + ostr << "
    \n"; + ostr << "
  • \n"; + } + ostr << "
\n"; + ostr << "
" << nbsp << "
\n"; // workaround to avoid cutting off a few pixels from last line + endBody(ostr); + ostr << "" << std::endl; + writeFooter(ostr); +} + + +void DocWriter::writePageIndex(std::ostream& ostr) +{ + std::set categories; + for (PageMap::const_iterator it = _pages.begin(); it != _pages.end(); ++it) + { + categories.insert(it->second.category); + } + + ostr << "" << std::endl; + int column = 0; + for (std::set::const_iterator it = categories.begin(); it != categories.end(); ++it) + { + if (column == 0) + { + ostr << "" << std::endl; + } + ostr << "" << std::endl; + ++column; + if (column == PAGE_INDEX_COLUMNS) + { + ostr << "" << std::endl; + column = 0; + } + } + if (column != 0) + { + while (column < PAGE_INDEX_COLUMNS) + { + ostr << "" << std::endl; + ++column; + } + ostr << "" << std::endl; + } + ostr << "
" << std::endl; + ostr << "

" << htmlize(tr(*it)) << "

"; + writeCategoryIndex(ostr, *it, ""); + ostr << "
"; +} + + +void DocWriter::writeNameSpaceIndex(std::ostream& ostr) +{ + std::map nsMap; + for (NameSpace::SymbolTable::const_iterator it = _symbols.begin(); it != _symbols.end(); ++it) + { + if (it->second->kind() == Symbol::SYM_NAMESPACE) + { + const NameSpace* pNameSpace = static_cast(it->second); + nsMap[it->second->fullName()] = pNameSpace; + } + } + + ostr << "" << std::endl; + int column = 0; + for (std::map::const_iterator it = nsMap.begin(); it != nsMap.end(); ++it) + { + const NameSpace* pNameSpace = it->second; + if (column == 0) + { + ostr << "" << std::endl; + } + ostr << "" << std::endl; + ++column; + if (column == NAMESPACE_INDEX_COLUMNS) + { + ostr << "" << std::endl; + column = 0; + } + } + if (column != 0) + { + while (column < NAMESPACE_INDEX_COLUMNS) + { + ostr << "" << std::endl; + ++column; + } + ostr << "" << std::endl; + } + ostr << "
" << std::endl; + writeLink(ostr, uriFor(pNameSpace), pNameSpace->fullName()); + ostr << "
"; +} + + +void DocWriter::writeEclipseTOC() +{ + Application& app = Application::instance(); + std::string software(app.config().getString("PocoDoc.software", "")); + + std::string path(pathFor("toc.xml")); + Poco::Path p(path); + std::string dir = p[p.depth() - 1]; + dir.append("/"); + p.popDirectory(); + std::ofstream ostr(p.toString().c_str()); + if (!ostr.good()) throw Poco::CreateFileException(path); + + ostr << "" << std::endl; + ostr << "" << std::endl; + + if (!_pages.empty()) + { + ostr << "" << std::endl; + std::set categories; + for (PageMap::const_iterator it = _pages.begin(); it != _pages.end(); ++it) + { + categories.insert(it->second.category); + } + for (std::set::const_iterator it = categories.begin(); it != categories.end(); ++it) + { + ostr << "" << std::endl; + for (PageMap::const_iterator itp = _pages.begin(); itp != _pages.end(); ++itp) + { + if (itp->second.category == *it) + { + ostr << "" << std::endl; + } + } + ostr << "" << std::endl; + } + ostr << "" << std::endl; + } + + ostr << "" << std::endl; + + std::map namespaces; // sort namespaces by full name + for (NameSpace::SymbolTable::const_iterator it = _symbols.begin(); it != _symbols.end(); ++it) + { + if (it->second->kind() == Symbol::SYM_NAMESPACE) + { + namespaces[it->second->fullName()] = it->second; + } + } + for (std::map::const_iterator it = namespaces.begin(); it != namespaces.end(); ++it) + { + ostr << "" << std::endl; + } + ostr << "" << std::endl; + + ostr << "" << std::endl; + + std::set libs; + libraries(libs); + for (std::set::const_iterator itl = libs.begin(); itl != libs.end(); ++itl) + { + ostr << "" << std::endl; + std::set pkgs; + packages(*itl, pkgs); + for (std::set::const_iterator itp = pkgs.begin(); itp != pkgs.end(); ++itp) + { + std::string uri("package-"); + uri += makeFileName(*itl); + uri += '.'; + uri += makeFileName(*itp); + uri += "-index.html"; + + ostr << "" << std::endl; + } + ostr << "" << std::endl; + } + + ostr << "" << std::endl; + + ostr << "" << std::endl; + + ostr << "" << std::endl; +} + + +void DocWriter::writeClass(const Struct* pStruct) +{ + _pNameSpace = pStruct; + std::string path(pathFor(fileNameFor(pStruct))); + std::ofstream ostr(path.c_str()); + if (!ostr.good()) throw Poco::CreateFileException(path); + std::string header; + if (pStruct->isClass()) + header += tr("Class") + " "; + else + header += tr("Struct") + " "; + header += pStruct->fullName(); + writeHeader(ostr, header, "js/iframeResizer.min.js"); + writeTitle(ostr, pStruct->nameSpace(), pStruct->declaration() + (pStruct->isFinal() ? " final" : "")); + beginBody(ostr); + writeNavigationFrame(ostr, "library", pStruct->getLibrary()); + beginContent(ostr); + writeFileInfo(ostr, pStruct); + const std::string& doc = pStruct->getDocumentation(); + if (pStruct->attrs().has("deprecated")) + { + writeDeprecated(ostr, pStruct->isClass() ? "class" : "struct"); + } + if (!doc.empty()) + { + if (doc.find("TODO") != std::string::npos) + logger().notice(std::string("TODO in class documentation for ") + pStruct->fullName()); + + writeSubTitle(ostr, tr("Description")); + writeDescription(ostr, pStruct->getDocumentation()); + } + else if (pStruct->isPublic() && !pStruct->isDerived()) + { + logger().notice(std::string("Public root class has no documentation: ") + pStruct->fullName()); + } + writeInheritance(ostr, pStruct); + writeMethodSummary(ostr, pStruct); + writeNestedClasses(ostr, pStruct); + writeTypes(ostr, pStruct); + writeEnums(ostr, pStruct); + writeConstructors(ostr, pStruct); + writeDestructor(ostr, pStruct); + writeMethods(ostr, pStruct); + writeVariables(ostr, pStruct); + writeCopyright(ostr); + endContent(ostr); + endBody(ostr); + writeFooter(ostr); +} + + +void DocWriter::writeNameSpace(const NameSpace* pNameSpace) +{ + _pNameSpace = pNameSpace; + std::string path(pathFor(fileNameFor(pNameSpace))); + std::ofstream ostr(path.c_str()); + if (!ostr.good()) throw Poco::CreateFileException(path); + writeHeader(ostr, tr("Namespace") + " " + pNameSpace->fullName(), "js/iframeResizer.min.js"); + writeTitle(ostr, pNameSpace->nameSpace(), std::string("namespace ") + pNameSpace->name()); + beginBody(ostr); + writeNavigationFrame(ostr, "", ""); + beginContent(ostr); + writeSubTitle(ostr, tr("Overview")); + writeNameSpacesSummary(ostr, pNameSpace); + writeClassesSummary(ostr, pNameSpace); + writeTypesSummary(ostr, pNameSpace); + writeFunctionsSummary(ostr, pNameSpace); + writeNameSpaces(ostr, pNameSpace); + writeClasses(ostr, pNameSpace); + writeTypes(ostr, pNameSpace); + writeEnums(ostr, pNameSpace); + writeFunctions(ostr, pNameSpace); + writeVariables(ostr, pNameSpace); + writeCopyright(ostr); + endContent(ostr); + endBody(ostr); + writeFooter(ostr); +} + + +void DocWriter::writePackage(const std::string& file, const std::string& library, const std::string& package) +{ + std::string path(pathFor(file)); + std::ofstream ostr(path.c_str()); + if (!ostr.good()) throw Poco::CreateFileException(path); + writeHeader(ostr, tr("Package_Index"), "js/iframeResizer.min.js"); + writeTitle(ostr, tr("Library") + " " + library, tr("Package") + " " + package); + beginBody(ostr); + writeNavigationFrame(ostr, "library", library); + beginContent(ostr); + writeSubTitle(ostr, tr("Overview")); + + ostr << "

" << tr("Classes") << ": " << std::endl; + bool first = true; + std::string prevName; + std::string prevNameSpace; + bool haveFunctions = false; + for (NameSpace::SymbolTable::const_iterator it = _symbols.begin(); it != _symbols.end(); ++it) + { + Symbol* pSym = it->second; + Struct* pStruct = dynamic_cast(pSym); + Function* pFunc = dynamic_cast(pSym); + if (pFunc && pFunc->isFunction() && pFunc->getLibrary() == library && pFunc->getPackage() == package) haveFunctions = true; + bool isClass = pStruct && pStruct->getAccess() == Symbol::ACC_PUBLIC; + if (isClass) + { + if (pSym->getLibrary() == library && pSym->getPackage() == package) + { + const std::string& name = pSym->name(); + const std::string& nameSpace = pSym->nameSpace()->fullName(); + if (name != prevName || nameSpace != prevNameSpace) + { + writeNameListItem(ostr, it->second->name(), it->second, pSym->nameSpace(), first); + prevName = name; + prevNameSpace = nameSpace; + } + } + } + } + ostr << "

" << std::endl; + + prevName.clear(); + prevNameSpace.clear(); + if (haveFunctions) + { + ostr << "

" << tr("Functions") << ": " << std::endl; + first = true; + for (NameSpace::SymbolTable::const_iterator it = _symbols.begin(); it != _symbols.end(); ++it) + { + Symbol* pSym = it->second; + Function* pFunc = dynamic_cast(pSym); + if (pFunc && pFunc->isFunction()) + { + if (pSym->getLibrary() == library && pSym->getPackage() == package) + { + const std::string& name = pSym->name(); + const std::string& nameSpace = pSym->nameSpace()->fullName(); + if (name != prevName || nameSpace != prevNameSpace) + { + writeNameListItem(ostr, it->second->name(), it->second, pSym->nameSpace(), first); + prevName = name; + prevNameSpace = nameSpace; + } + } + } + } + ostr << "

" << std::endl; + } + + prevName.clear(); + prevNameSpace.clear(); + writeSubTitle(ostr, tr("Classes")); + for (NameSpace::SymbolTable::const_iterator it = _symbols.begin(); it != _symbols.end(); ++it) + { + Symbol* pSym = it->second; + Struct* pStruct = dynamic_cast(pSym); + bool isClass = pStruct && pStruct->getAccess() == Symbol::ACC_PUBLIC; + if (isClass) + { + if (pSym->getLibrary() == library && pSym->getPackage() == package) + { + const std::string& name = pSym->name(); + const std::string& nameSpace = pSym->nameSpace()->fullName(); + if (name != prevName || nameSpace != prevNameSpace) + { + writeClassSummary(ostr, pStruct); + prevName = name; + prevNameSpace = nameSpace; + } + } + } + } + + writeCopyright(ostr); + endContent(ostr); + endBody(ostr); + writeFooter(ostr); +} + + +std::string DocWriter::fileNameFor(const Symbol* pNameSpace) +{ + std::string result(baseNameFor(pNameSpace)); + if (!result.empty()) result.append(".html"); + return result; +} + + +std::string DocWriter::baseNameFor(const Symbol* pNameSpace) +{ + std::string result; + std::string fullName(pNameSpace->fullName()); + std::string::const_iterator it = fullName.begin(); + std::string::const_iterator end = fullName.end(); + while (it != end) + { + if (*it == ':') + { + result += '.'; + ++it; + } + else result += *it; + if (it != end) ++it; + } + return result; +} + + +std::string DocWriter::pathFor(const std::string& file) +{ + Path p(_path); + p.makeDirectory(); + p.setFileName(file); + return p.toString(); +} + + +std::string DocWriter::uriFor(const Symbol* pSymbol) +{ + const Function* pFunc = dynamic_cast(pSymbol); + if (pFunc && pFunc->isConstructor()) + return fileNameFor(pSymbol->nameSpace()); + else if (dynamic_cast(pSymbol)) + return fileNameFor(pSymbol); + else + return fileNameFor(pSymbol->nameSpace()) + "#" + NumberFormatter::format(pSymbol->id()); +} + + +std::string DocWriter::makeFileName(const std::string& str) +{ + std::string result; + for (std::string::const_iterator it = str.begin(); it != str.end(); ++it) + { + if (std::isalnum(*it)) + result += *it; + else + result += "_"; + } + return result; +} + + +void DocWriter::writeHeader(std::ostream& ostr, const std::string& title, const std::string& extraScript) +{ + Application& app = Application::instance(); + std::string company(app.config().getString("PocoDoc.company", "Applied Informatics")); + std::string charset(app.config().getString("PocoDoc.charset", "utf-8")); + DateTime now; + ostr << "" << std::endl; + ostr << "" << std::endl; + ostr << "" << std::endl; + ostr << "" << htmlize(title) << "" << std::endl; + ostr << "" << std::endl; + ostr << "" << std::endl; + ostr << "" << std::endl; + ostr << "" << std::endl; + if (_prettifyCode) + { + ostr << "" << std::endl; + ostr << "" << std::endl; + } + if (!extraScript.empty()) + { + ostr << "" << std::endl; + } + ostr << "" << std::endl; + ostr << "" << std::endl; + ostr << "" << std::endl; +} + + +void DocWriter::writeFooter(std::ostream& ostr) +{ + Application& app = Application::instance(); + std::string googleAnalyticsCode(app.config().getString("PocoDoc.googleAnalyticsCode", "")); + ostr << googleAnalyticsCode; + ostr << "" << std::endl; + ostr << "" << std::endl; +} + + +void DocWriter::writeCopyright(std::ostream& ostr) +{ + Application& app = Application::instance(); + std::string software(app.config().getString("PocoDoc.software", "")); + std::string version(app.config().getString("PocoDoc.version", "")); + std::string company(app.config().getString("PocoDoc.company", "Applied Informatics")); + std::string companyURI(app.config().getString("PocoDoc.companyURI", "http://www.appinf.com/")); + std::string licenseURI(app.config().getString("PocoDoc.licenseURI", "")); + DateTime now; + ostr << "\n"; +} + + +void DocWriter::writeTitle(std::ostream& ostr, const std::string& category, const std::string& title) +{ + Application& app = Application::instance(); + std::string headerImage(app.config().getString("PocoDoc.headerImage", "")); + ostr << "
\n"; + if (!headerImage.empty()) + { + ostr << "\n"; + } + ostr << "

"; + if (category.empty()) + ostr << nbsp ; + else + ostr << htmlize(category); + ostr << "

\n"; + ostr << "

" << htmlize(title) << "

"; + ostr << "\n
\n"; +} + + +void DocWriter::writeTitle(std::ostream& ostr, const NameSpace* pNameSpace, const std::string& title) +{ + Application& app = Application::instance(); + std::string headerImage(app.config().getString("PocoDoc.headerImage", "")); + ostr << "
\n"; + if (!headerImage.empty()) + { + ostr << "\n"; + } + const std::string& nameSpace = pNameSpace->fullName(); + if (!nameSpace.empty()) + { + ostr << "

"; + writeLink(ostr, uriFor(pNameSpace), nameSpace, "namespace"); + ostr << "

\n"; + } + else + { + ostr << "

::

\n"; + } + + std::string::size_type posFirstOpen = title.find_first_of('<'); + bool isTemplate = (posFirstOpen != std::string::npos); + std::string::size_type posFirstClose = std::string::npos; + std::string templateParam; + std::string templateParamSpec; + if (isTemplate) + { + int tempCount = 1; + posFirstClose = posFirstOpen; + while (tempCount != 0) + { + ++posFirstClose; + if (title[posFirstClose] == '>') + --tempCount; + if (title[posFirstClose] == '<') + ++tempCount; + } + ++posFirstClose; + templateParam = title.substr(0, posFirstClose); + templateParamSpec = title.substr(posFirstClose+1); + } + + if (isTemplate) + { + ostr << "

" + << htmlize(templateParam) + << "

\n" + << "

" + << htmlize(templateParamSpec) + << "

"; + } + else + { + ostr << "

" + << htmlize(title) + << "

"; + } + ostr << "\n
\n"; +} + + +void DocWriter::writeSubTitle(std::ostream& ostr, const std::string& title) +{ + ostr << "

" + << htmlize(title) + << "

\n"; +} + + +void DocWriter::writeNavigationFrame(std::ostream& ostr, const std::string& group, const std::string& item) +{ + std::string query; + if (!group.empty() && !item.empty()) + { + query = "?expand="; + query += group; + query += "-"; + query += item; + } + ostr << "\n"; +} + + +void DocWriter::beginBody(std::ostream& ostr) +{ + ostr << "
\n"; +} + + +void DocWriter::endBody(std::ostream& ostr) +{ + ostr << "\n
\n"; +} + + +void DocWriter::beginContent(std::ostream& ostr) +{ + ostr << "
\n"; +} + + +void DocWriter::endContent(std::ostream& ostr) +{ + ostr << "\n
\n"; +} + + +void DocWriter::writeDescription(std::ostream& ostr, const std::string& text) +{ + ostr << "
\n" + << "

"; + + _titleId = 0; + _htmlMode = false; + TextState state = TEXT_PARAGRAPH; + std::string::const_iterator it = text.begin(); + std::string::const_iterator end = text.end(); + while (it != end) + { + std::string line; + while (it != end && *it != '\n') line += *it++; + writeDescriptionLine(ostr, line, state); + if (it != end) ++it; + } + switch (state) + { + case TEXT_PARAGRAPH: + ostr << "

"; + break; + case TEXT_LIST: + ostr << "\n"; + break; + case TEXT_OLIST: + ostr << "\n"; + break; + case TEXT_LITERAL: + ostr << ""; + break; + default: + break; + } + ostr << "\n
\n"; +} + + +void DocWriter::writeDescriptionLine(std::ostream& ostr, const std::string& text, TextState& state) +{ + if (_htmlMode) + { + writeText(ostr, text); + } + else + { + TextState lineState = analyzeLine(text); + if (lineState == TEXT_LITERAL && state != lineState) + { + _indent = 0; + _pendingLine = false; + } + switch (lineState) + { + case TEXT_PARAGRAPH: + switch (state) + { + case TEXT_PARAGRAPH: + writeText(ostr, text); + break; + case TEXT_LIST: + ostr << "\n\n

"; + writeText(ostr, text); + break; + case TEXT_OLIST: + ostr << "\n\n

"; + writeText(ostr, text); + break; + case TEXT_LITERAL: + ostr << "\n

"; + writeText(ostr, text); + break; + default: + break; + } + state = TEXT_PARAGRAPH; + break; + case TEXT_LIST: + switch (state) + { + case TEXT_PARAGRAPH: + ostr << "

\n
    \n
  • "; + writeListItem(ostr, text); + state = TEXT_LIST; + break; + case TEXT_LIST: + case TEXT_OLIST: + ostr << "
  • \n
  • "; + writeListItem(ostr, text); + state = TEXT_LIST; + break; + case TEXT_LITERAL: + writeLiteral(ostr, text); + break; + default: + break; + } + break; + case TEXT_OLIST: + switch (state) + { + case TEXT_PARAGRAPH: + ostr << "

    \n
      \n
    1. "; + writeOrderedListItem(ostr, text); + state = TEXT_OLIST; + break; + case TEXT_LIST: + case TEXT_OLIST: + ostr << "
    2. \n
    3. "; + writeOrderedListItem(ostr, text); + state = TEXT_OLIST; + break; + case TEXT_LITERAL: + writeLiteral(ostr, text); + break; + default: + break; + } + break; + case TEXT_LITERAL: + switch (state) + { + case TEXT_PARAGRAPH: + ostr << "

      \n"; + writeLiteral(ostr, text); + state = TEXT_LITERAL; + break; + case TEXT_LIST: + writeText(ostr, text); + state = TEXT_LIST; + break; + case TEXT_OLIST: + writeText(ostr, text); + state = TEXT_OLIST; + break; + case TEXT_LITERAL: + writeLiteral(ostr, text); + break; + default: + break; + } + break; + case TEXT_WHITESPACE: + switch (state) + { + case TEXT_PARAGRAPH: + ostr << "

      \n

      "; + break; + case TEXT_LIST: + ostr << "

    4. \n
\n

"; + state = TEXT_PARAGRAPH; + break; + case TEXT_OLIST: + ostr << "\n\n

"; + state = TEXT_PARAGRAPH; + break; + case TEXT_LITERAL: + writeLiteral(ostr, text); + break; + default: + break; + } + break; + } + } +} + + +void DocWriter::writeSummary(std::ostream& ostr, const std::string& text, const std::string& uri) +{ + ostr << "

"; + std::string::const_iterator beg = text.begin(); + std::string::const_iterator it = beg; + std::string::const_iterator end = text.end(); + while (it != end && *it != '.') ++it; + if (it != end) ++it; + writeText(ostr, beg, it); + if (!uri.empty()) + { + ostr << nbsp ; + writeImageLink(ostr, uri, "arrow.png", tr("more")); + } + ostr << "

\n"; +} + + +DocWriter::TextState DocWriter::analyzeLine(const std::string& line) +{ + int nSpaces = 0; + std::string::const_iterator it = line.begin(); + std::string::const_iterator end = line.end(); + while (it != end && std::isspace(*it)) { ++it; ++nSpaces; } + if (it == end) + return TEXT_WHITESPACE; + else if (nSpaces < 3) + return TEXT_PARAGRAPH; + else if (*it == '-' || *it == '*') + return TEXT_LIST; + else if (std::isdigit(*it)) + { + ++it; + if (it != end && *it == '.') + return TEXT_OLIST; + } + return TEXT_LITERAL; +} + + +std::string DocWriter::htmlizeName(const std::string& name) +{ + std::string result; + for (std::string::const_iterator it = name.begin(); it != name.end(); ++it) + { + if (*it == ' ') + result += nbsp ; + else + result += htmlize(*it); + } + return result; +} + + +void DocWriter::writeText(std::ostream& ostr, const std::string& text) +{ + std::string::const_iterator it(text.begin()); + std::string::const_iterator end(text.end()); + + while (it != end && std::isspace(*it)) ++it; + if (it != end) + { + if (*it == '!') + { + std::string heading("h4"); + ++it; + if (it != end && *it == '!') + { + heading = "h3"; + ++it; + } + if (it != end && *it == '!') + { + heading = "h2"; + ++it; + } + while (it != end && std::isspace(*it)) ++it; + ostr << "

<" << heading << ">" << format("", _titleId++) << htmlize(std::string(it, end)) << "

" << std::endl; + return; + } + } + writeText(ostr, it, end); + ostr << ' '; +} + + +void DocWriter::writeText(std::ostream& ostr, std::string::const_iterator begin, const std::string::const_iterator& end) +{ + std::string token; + nextToken(begin, end, token); + while (!token.empty()) + { + if (!writeSymbol(ostr, token, begin, end) && !writeSpecial(ostr, token, begin, end)) + { + if (token == "[[") + { + std::string uri; + std::string text; + std::string::const_iterator it(begin); + while (it != end && std::isspace(*it)) ++it; + while (it != end && !std::isspace(*it)) uri += *it++; + while (it != end && std::isspace(*it)) ++it; + while (it != end && *it != ']') text += *it++; + while (it != end && *it == ']') ++it; + if (uri.compare(0, 6, "image:") == 0) + { + uri.erase(0, 6); + writeImage(ostr, uri, text); + } + else + { + std::string target; + if (uri.compare(0, 7, "http://") == 0 || uri.compare(0, 8, "https://") == 0) + target = "_blank"; + writeTargetLink(ostr, uri, text, target); + } + begin = it; + nextToken(begin, end, token); + continue; + } + if (token == "RFC") + { + std::string::const_iterator it(begin); + std::string spc; + nextToken(begin, end, spc); + if (spc == " ") + { + std::string n; + nextToken(begin, end, n); + if (!n.empty() && std::isdigit(n[0])) + { + std::string uri(RFC_URI); + uri += n; + uri += ".txt"; + writeTargetLink(ostr, uri, token + " " + n, "_blank"); + nextToken(begin, end, token); + continue; + } + } + begin = it; + } + if (token == "http") + { + std::string::const_iterator it(begin); + std::string css; + nextToken(begin, end, css); + if (css == "://") + { + std::string uri(token); + uri += css; + while (begin != end && !std::isspace(*begin) && *begin != '>' && *begin != ')') uri += *begin++; + if (uri[uri.length() - 1] == '.') + { + uri.resize(uri.length() - 1); + writeTargetLink(ostr, uri, uri, "_blank"); + ostr << '.'; + } + else writeTargetLink(ostr, uri, uri, "_blank"); + nextToken(begin, end, token); + continue; + } + else + ostr << htmlize(token); + begin = it; + } + else + { + ostr << htmlize(token); + } + nextToken(begin, end, token); + } + } +} + + +void DocWriter::writeDecl(std::ostream& ostr, const std::string& decl) +{ + writeDecl(ostr, decl.begin(), decl.end()); +} + + +void DocWriter::writeDecl(std::ostream& ostr, std::string::const_iterator begin, const std::string::const_iterator& end) +{ + std::string token; + nextToken(begin, end, token); + while (!token.empty()) + { + if (!writeSymbol(ostr, token, begin, end)) + { + ostr << htmlize(token); + nextToken(begin, end, token); + } + } +} + + +bool DocWriter::writeSymbol(std::ostream& ostr, std::string& token, std::string::const_iterator& begin, const std::string::const_iterator& end) +{ + if (std::isalnum(token[0]) && _pNameSpace) + { + std::string id(token); + std::string next; + std::string::const_iterator it(begin); + nextToken(begin, end, next); + begin = it; + if (std::isupper(id[0]) || (!next.empty() && next[0] == '(')) + { + std::string::const_iterator it2(begin); + while (next == "::") + { + nextToken(begin, end, next); // :: + id += next; + nextToken(begin, end, next); // id + id += next; + it2 = begin; + nextToken(begin, end, next); + begin = it2; + } + Symbol* pSym = _pNameSpace->lookup(id); + if (pSym) + { + writeLink(ostr, pSym, id); + nextToken(begin, end, token); + return true; + } + begin = it; + } + } + return false; +} + + +bool DocWriter::writeSpecial(std::ostream& ostr, std::string& token, std::string::const_iterator& begin, const std::string::const_iterator& end) +{ + if (token == "<%") + { + _htmlMode = true; + ostr << "

"; + } + else if (token == "<{") + { + _htmlMode = true; + } + else if (token == "%>") + { + _htmlMode = false; + ostr << "

"; + } + else if (token == "}>") + { + _htmlMode = false; + } + else if (token == "") + { + prop.append(token); + nextToken(begin, end, token); + } + Poco::trimInPlace(prop); + Application& app = Application::instance(); + ostr << htmlize(app.config().getString(prop, std::string("NOT FOUND: ") + prop)); + } + else if (_htmlMode) + { + ostr << token; + } + else if (token == "<*") + { + ostr << ""; + } + else if (token == "*>") + { + ostr << ""; + } + else if (token == ""; + } + else if (token == "!>") + { + ostr << ""; + } + else if (token == "<[") + { + ostr << ""; + _literalMode = true; + } + else if (token == "]>") + { + ostr << ""; + _literalMode = false; + } + else if (token == "--" && !_literalMode) + { + ostr << mdash; + } + else if (token == "iff" && !_literalMode) + { + ostr << tr("iff"); + } + else if (token != "----") + { + return false; + } + nextToken(begin, end, token); + return true; +} + + +void DocWriter::nextToken(std::string::const_iterator& it, const std::string::const_iterator& end, std::string& token) +{ + token.clear(); + if (it != end && (std::isalnum(*it) || *it == '_')) + { + while (it != end && (std::isalnum(*it) || *it == '_')) token += *it++; + } + else if (it != end && std::isspace(*it)) + { + while (it != end && std::isspace(*it)) token += *it++; + } + else if (it != end && *it == '<') + { + token += *it++; + if (it != end && std::ispunct(*it)) token += *it++; + } + else if (it != end && *it == '[') + { + token += *it++; + if (it != end && *it == '[') token += *it++; + } + else if (it != end && (*it == ']' || *it == '*' || *it == '!' || *it == '%' || *it == '}' || *it == '?')) + { + token += *it++; + if (it != end && *it == '>') token += *it++; + } + else if (it != end && *it == '-') + { + while (it != end && *it == '-') token += *it++; + } + else if (it != end && *it == ':') + { + while (it != end && (*it == ':' || *it == '/')) token += *it++; + } + else if (it != end) + { + token += *it++; + } +} + + +void DocWriter::writeListItem(std::ostream& ostr, const std::string& text) +{ + std::string::const_iterator it = text.begin(); + std::string::const_iterator end = text.end(); + while (it != end && std::isspace(*it)) ++it; + if ((it != end && *it == '-') || *it == '*') + { + ++it; + while (it != end && std::isspace(*it)) ++it; + } + writeText(ostr, it, end); + ostr << ' '; +} + + +void DocWriter::writeOrderedListItem(std::ostream& ostr, const std::string& text) +{ + std::string::const_iterator it = text.begin(); + std::string::const_iterator end = text.end(); + while (it != end && std::isspace(*it)) ++it; + if (it != end && std::isdigit(*it)) + { + while (it != end && std::isdigit(*it)) ++it; + if (it != end && *it == '.') ++it; + while (it != end && std::isspace(*it)) ++it; + } + writeText(ostr, it, end); + ostr << ' '; +} + + +void DocWriter::writeLiteral(std::ostream& ostr, const std::string& text) +{ + if (_pendingLine) + { + ostr << "\n"; + _pendingLine = false; + } + + std::string::const_iterator it(text.begin()); + std::string::const_iterator end(text.end()); + if (_indent == 0) + { + while (it != end && std::isspace(*it)) + { + ++it; + ++_indent; + } + } + else + { + int i = 0; + while (it != end && i < _indent) + { + ++it; + ++i; + } + } + std::string line(it, end); + Poco::trimRightInPlace(line); + if (line.empty()) + _pendingLine = true; + else + ostr << htmlize(std::string(it, end)) << "\n"; +} + + +void DocWriter::writeFileInfo(std::ostream& ostr, const Symbol* pSymbol) +{ + std::string library(pSymbol->getLibrary()); + std::string package(pSymbol->getPackage()); + if (library.empty() || library == "ChangeThis") + logger().notice(std::string("No library name specified in ") + pSymbol->getFile()); + if (package.empty() || package == "ChangeThis") + logger().notice(std::string("No package name specified in ") + pSymbol->getFile()); + + ostr << "

\n"; + ostr << "" << tr("Library") << ": " << library << "
\n" + << "" << tr("Package") << ": " << package << "
\n" + << "" << tr("Header") << ": " << headerFor(pSymbol); + ostr << "

\n"; +} + + +void DocWriter::writeInheritance(std::ostream& ostr, const Struct* pStruct) +{ + std::set bases; + pStruct->bases(bases); + if (!bases.empty() || pStruct->derivedBegin() != pStruct->derivedEnd()) + { + writeSubTitle(ostr, tr("Inheritance")); + if (pStruct->baseBegin() != pStruct->baseEnd()) + { + ostr << "

" << tr("Direct_Base_Classes") << ": "; + bool first = true; + for (Struct::BaseIterator it = pStruct->baseBegin(); it != pStruct->baseEnd(); ++it) + { + std::string base; + if (it->pClass) + { + if (it->pClass->nameSpace() == pStruct->nameSpace()) + base = it->pClass->name(); + else + base = it->pClass->fullName(); + } + else base = it->name; + writeNameListItem(ostr, base, it->pClass, pStruct->nameSpace(), first); + } + ostr << "

\n"; + } + if (!bases.empty()) + { + ostr << "

" << tr("All_Base_Classes") << ": "; + bool first = true; + for (std::set::const_iterator it = bases.begin(); it != bases.end(); ++it) + { + std::string base; + Symbol* pBase = pStruct->nameSpace()->lookup(*it); + if (pBase) + { + if (pBase->nameSpace() == pStruct->nameSpace()) + base = pBase->name(); + else + base = pBase->fullName(); + } + else base = *it; + writeNameListItem(ostr, base, pBase, pStruct->nameSpace(), first); + } + ostr << "

\n"; + } + Struct::StructSet derived; + pStruct->derived(derived); + if (!derived.empty()) + { + ostr << "

" << tr("Known_Derived_Classes") << ": "; + bool first = true; + for (Struct::StructSet::const_iterator it = derived.begin(); it != derived.end(); ++it) + { + std::string derived; + if ((*it)->nameSpace() == pStruct->nameSpace()) + derived = (*it)->name(); + else + derived = (*it)->fullName(); + writeNameListItem(ostr, derived, *it, pStruct->nameSpace(), first); + } + ostr << "

\n"; + } + } +} + + +void DocWriter::writeMethodSummary(std::ostream& ostr, const Struct* pStruct) +{ + bool titleWritten = false; + MethodMap methods; + Struct::Functions functions; + pStruct->methods(Symbol::ACC_PUBLIC, functions); + for (Struct::Functions::const_iterator it = functions.begin(); it != functions.end(); ++it) + { + if (methods.find((*it)->name()) == methods.end()) + methods[(*it)->name()] = *it; + } + pStruct->methods(Symbol::ACC_PROTECTED, functions); + for (Struct::Functions::const_iterator it = functions.begin(); it != functions.end(); ++it) + { + if (methods.find((*it)->name()) == methods.end()) + methods[(*it)->name()] = *it; + } + if (!methods.empty()) + { + writeSubTitle(ostr, tr("Member_Summary")); + titleWritten = true; + ostr << "

" << tr("Member_Functions") << ": "; + bool first = true; + for (MethodMap::const_iterator it = methods.begin(); it != methods.end(); ++it) + { + writeNameListItem(ostr, it->first, it->second, pStruct, first); + } + ostr << "

\n"; + } + methods.clear(); + Struct::FunctionSet inhFunctions; + pStruct->inheritedMethods(inhFunctions); + for (Struct::FunctionSet::const_iterator it = inhFunctions.begin(); it != inhFunctions.end(); ++it) + { + if (methods.find((*it)->name()) == methods.end()) + methods[(*it)->name()] = *it; + } + if (!methods.empty()) + { + if (!titleWritten) + writeSubTitle(ostr, tr("Member_Summary")); + ostr << "

" << tr("Inherited_Functions") << ": "; + bool first = true; + for (MethodMap::const_iterator it = methods.begin(); it != methods.end(); ++it) + { + writeNameListItem(ostr, it->first, it->second, pStruct, first); + } + ostr << "

\n"; + } +} + + +void DocWriter::writeNestedClasses(std::ostream& ostr, const Struct* pStruct) +{ + NameSpace::SymbolTable classes; + pStruct->classes(classes); + bool hasNested = false; + for (NameSpace::Iterator it = classes.begin(); it != classes.end(); ++it) + { + if (it->second->getAccess() != Symbol::ACC_PRIVATE) + hasNested = true; + } + if (hasNested) + { + writeSubTitle(ostr, tr("Nested_Classes")); + for (NameSpace::Iterator it = classes.begin(); it != classes.end(); ++it) + { + if (it->second->getAccess() != Symbol::ACC_PRIVATE) + writeClassSummary(ostr, static_cast(it->second)); + } + } +} + + +void DocWriter::writeNameSpacesSummary(std::ostream& ostr, const NameSpace* pNameSpace) +{ + NameSpace::SymbolTable nameSpaces; + pNameSpace->nameSpaces(nameSpaces); + if (!nameSpaces.empty()) + { + ostr << "

" << tr("Namespaces") << ": " << std::endl; + bool first = true; + for (NameSpace::Iterator it = nameSpaces.begin(); it != nameSpaces.end(); ++it) + { + writeNameListItem(ostr, it->second->name(), it->second, pNameSpace, first); + } + ostr << "

" << std::endl; + } +} + + +void DocWriter::writeNameSpaces(std::ostream& ostr, const NameSpace* pNameSpace) +{ + NameSpace::SymbolTable nameSpaces; + pNameSpace->nameSpaces(nameSpaces); + if (!nameSpaces.empty()) + { + writeSubTitle(ostr, tr("Namespaces")); + for (NameSpace::Iterator it = nameSpaces.begin(); it != nameSpaces.end(); ++it) + { + ostr << "

"; + std::string what("namespace "); + what += it->second->name(); + writeLink(ostr, uriFor(it->second), what, "class"); + ostr << "

\n"; + } + } +} + + +void DocWriter::writeClassesSummary(std::ostream& ostr, const NameSpace* pNameSpace) +{ + NameSpace::SymbolTable classes; + pNameSpace->classes(classes); + if (!classes.empty()) + { + ostr << "

" << tr("Classes") << ": " << std::endl; + bool first = true; + for (NameSpace::Iterator it = classes.begin(); it != classes.end(); ++it) + { + writeNameListItem(ostr, it->second->name(), it->second, pNameSpace, first); + } + ostr << "

" << std::endl; + } +} + + +void DocWriter::writeClasses(std::ostream& ostr, const NameSpace* pNameSpace) +{ + NameSpace::SymbolTable classes; + pNameSpace->classes(classes); + if (!classes.empty()) + { + writeSubTitle(ostr, tr("Classes")); + for (NameSpace::Iterator it = classes.begin(); it != classes.end(); ++it) + { + writeClassSummary(ostr, static_cast(it->second)); + } + } +} + + +void DocWriter::writeClassSummary(std::ostream& ostr, const Struct* pStruct) +{ + ostr << "

"; + std::string what; + if (pStruct->isClass()) + what += "class "; + else + what += "struct "; + what += pStruct->name(); + writeLink(ostr, uriFor(pStruct), what, "class"); + if (pStruct->getAccess() != Symbol::ACC_PUBLIC) + writeIcon(ostr, "protected"); + ostr << "

\n"; + writeSummary(ostr, pStruct->getDocumentation(), uriFor(pStruct)); +} + + +void DocWriter::writeTypesSummary(std::ostream& ostr, const NameSpace* pNameSpace) +{ + NameSpace::SymbolTable types; + pNameSpace->typeDefs(types); + if (!types.empty()) + { + ostr << "

" << tr("Types") << ": " << std::endl; + bool first = true; + for (NameSpace::Iterator it = types.begin(); it != types.end(); ++it) + { + writeNameListItem(ostr, it->second->name(), it->second, pNameSpace, first); + } + ostr << "

" << std::endl; + } +} + + +void DocWriter::writeTypes(std::ostream& ostr, const NameSpace* pNameSpace) +{ + NameSpace::SymbolTable types; + pNameSpace->typeDefs(types); + bool hasTypes = false; + for (NameSpace::Iterator it = types.begin(); !hasTypes && it != types.end(); ++it) + { + if (it->second->getAccess() != Symbol::ACC_PRIVATE) + hasTypes = true; + } + if (hasTypes) + { + writeSubTitle(ostr, tr("Types")); + for (NameSpace::Iterator it = types.begin(); it != types.end(); ++it) + { + if (it->second->getAccess() != Symbol::ACC_PRIVATE) + writeType(ostr, static_cast(it->second)); + } + } +} + + +void DocWriter::writeType(std::ostream& ostr, const TypeDef* pType) +{ + ostr << "

"; + writeAnchor(ostr, pType->name(), pType); + if (pType->getAccess() != Symbol::ACC_PUBLIC) + writeIcon(ostr, "protected"); + ostr << "

\n"; + ostr << "

"; + writeDecl(ostr, pType->declaration()); + ostr << ";

\n"; + writeDescription(ostr, pType->getDocumentation()); +} + + +void DocWriter::writeEnums(std::ostream& ostr, const NameSpace* pNameSpace) +{ + NameSpace::SymbolTable enums; + pNameSpace->enums(enums); + bool hasEnums = false; + for (NameSpace::Iterator it = enums.begin(); !hasEnums && it != enums.end(); ++it) + { + if (it->second->getAccess() != Symbol::ACC_PRIVATE) + hasEnums = true; + } + if (hasEnums) + { + writeSubTitle(ostr, tr("Enumerations")); + for (NameSpace::Iterator it = enums.begin(); it != enums.end(); ++it) + { + if (it->second->getAccess() != Symbol::ACC_PRIVATE) + writeEnum(ostr, static_cast(it->second)); + } + } +} + + +void DocWriter::writeEnum(std::ostream& ostr, const Enum* pEnum) +{ + ostr << "

"; + const std::string& name = pEnum->name(); + if (name[0] == '#') + ostr << "" << tr("Anonymous") << ""; + else + writeAnchor(ostr, name, pEnum); + if (pEnum->getAccess() != Symbol::ACC_PUBLIC) + writeIcon(ostr, "protected"); + ostr << "

\n"; + writeDescription(ostr, pEnum->getDocumentation()); + for (Enum::Iterator it = pEnum->begin(); it != pEnum->end(); ++it) + { + const std::string& name = (*it)->name(); + const std::string& value = (*it)->value(); + ostr << "

"; + writeAnchor(ostr, name, *it); + if (!value.empty()) + ostr << " = " << htmlize(value); + ostr << "

\n"; + writeDescription(ostr, (*it)->getDocumentation()); + } +} + + +void DocWriter::writeConstructors(std::ostream& ostr, const Struct* pStruct) +{ + Struct::Functions ctors; + pStruct->constructors(ctors); + if (!ctors.empty()) + { + writeSubTitle(ostr, tr("Constructors")); + for (Struct::Functions::const_iterator it = ctors.begin(); it != ctors.end(); ++it) + { + if ((*it)->getAccess() == Symbol::ACC_PUBLIC) + writeFunction(ostr, *it); + } + for (Struct::Functions::const_iterator it = ctors.begin(); it != ctors.end(); ++it) + { + if ((*it)->getAccess() == Symbol::ACC_PROTECTED) + writeFunction(ostr, *it); + } + } +} + + +void DocWriter::writeDestructor(std::ostream& ostr, const Struct* pStruct) +{ + if (pStruct->destructor()) + { + writeSubTitle(ostr, tr("Destructor")); + writeFunction(ostr, pStruct->destructor()); + } +} + + +void DocWriter::writeMethods(std::ostream& ostr, const Struct* pStruct) +{ + Struct::Functions methods; + pStruct->methods(Symbol::ACC_PUBLIC, methods); + pStruct->methods(Symbol::ACC_PROTECTED, methods); + if (!methods.empty()) + { + writeSubTitle(ostr, tr("Member_Functions")); + for (Struct::Functions::const_iterator it = methods.begin(); it != methods.end(); ++it) + { + writeFunction(ostr, *it); + } + } +} + + +void DocWriter::writeFunctionsSummary(std::ostream& ostr, const NameSpace* pNameSpace) +{ + NameSpace::SymbolTable funcs; + pNameSpace->functions(funcs); + if (!funcs.empty()) + { + ostr << "

" << tr("Functions") << ": " << std::endl; + std::string lastName; + bool first = true; + for (NameSpace::Iterator it = funcs.begin(); it != funcs.end(); ++it) + { + if (it->second->name() != lastName) + { + writeNameListItem(ostr, it->second->name(), it->second, pNameSpace, first); + lastName = it->second->name(); + } + } + ostr << "

" << std::endl; + } +} + + +void DocWriter::writeFunctions(std::ostream& ostr, const NameSpace* pNameSpace) +{ + NameSpace::SymbolTable funcs; + pNameSpace->functions(funcs); + if (!funcs.empty()) + { + writeSubTitle(ostr, tr("Functions")); + for (NameSpace::Iterator it = funcs.begin(); it != funcs.end(); ++it) + { + writeFunction(ostr, static_cast(it->second)); + } + } +} + + +void DocWriter::writeFunction(std::ostream& ostr, const Function* pFunc) +{ + ostr << "

"; + writeAnchor(ostr, pFunc->name(), pFunc); + if (pFunc->getAccess() != Symbol::ACC_PUBLIC) + writeIcon(ostr, "protected"); + if (pFunc->isVirtual()) + writeIcon(ostr, "virtual"); + else if (pFunc->flags() & Function::FN_STATIC) + writeIcon(ostr, "static"); + if (pFunc->flags() & Function::FN_INLINE) + writeIcon(ostr, "inline"); + ostr << "

\n"; + ostr << "

"; + const std::string& decl = pFunc->declaration(); + writeDecl(ostr, decl); + if (!std::isalnum(decl[decl.length() - 1])) + ostr << " "; + ostr << "("; + bool hasArgs = false; + for (Function::Iterator it = pFunc->begin(); it != pFunc->end(); ++it) + { + hasArgs = true; + if (it != pFunc->begin()) + ostr << ","; + ostr << "
    "; + writeDecl(ostr, (*it)->declaration()); + if ((*it)->hasDefaultValue()) + { + ostr << " = " << (*it)->defaultDecl(); + } + } + if (hasArgs) + ostr << "
"; + ostr << ")"; + if (pFunc->flags() & Function::FN_CONST) + ostr << " const"; + if (pFunc->flags() & Function::FN_OVERRIDE) + ostr << " override"; + else if (pFunc->flags() & Function::FN_FINAL) + ostr << " final"; + if (pFunc->flags() & Function::FN_DELETE) + ostr << " = delete"; + else if (pFunc->flags() & Function::FN_DEFAULT) + ostr << " = default"; + else if (pFunc->flags() & Function::FN_PURE_VIRTUAL) + ostr << " = 0"; + ostr << ";

\n"; + + if (pFunc->attrs().has("deprecated")) + { + writeDeprecated(ostr, "function"); + } + + Function* pOverridden = pFunc->getOverridden(); + const std::string& doc(pFunc->getDocumentation()); + if (doc.empty() && pFunc->isPublic() && !pOverridden && !pFunc->isConstructor() && !pFunc->isDestructor()) + logger().notice(std::string("Undocumented public function: ") + pFunc->fullName()); + + writeDescription(ostr, doc); + if (pOverridden) + { + ostr << "

" << tr("See_also") << ": "; + writeLink(ostr, pOverridden, pOverridden->fullName() + "()"); + ostr << "

\n"; + } +} + + +void DocWriter::writeVariables(std::ostream& ostr, const NameSpace* pNameSpace) +{ + NameSpace::SymbolTable vars; + pNameSpace->variables(vars); + bool hasVars = false; + for (NameSpace::Iterator it = vars.begin(); !hasVars && it != vars.end(); ++it) + { + if (it->second->getAccess() != Symbol::ACC_PRIVATE) + hasVars = true; + } + if (hasVars) + { + + writeSubTitle(ostr, tr("Variables")); + for (NameSpace::Iterator it = vars.begin(); it != vars.end(); ++it) + { + if (it->second->getAccess() == Symbol::ACC_PUBLIC) + writeVariable(ostr, static_cast(it->second)); + } + for (NameSpace::Iterator it = vars.begin(); it != vars.end(); ++it) + { + if (it->second->getAccess() == Symbol::ACC_PROTECTED) + writeVariable(ostr, static_cast(it->second)); + } + } +} + + +void DocWriter::writeVariable(std::ostream& ostr, const Variable* pVar) +{ + ostr << "

"; + writeAnchor(ostr, pVar->name(), pVar); + if (pVar->getAccess() != Symbol::ACC_PUBLIC) + writeIcon(ostr, "protected"); + if (pVar->flags() & Function::FN_STATIC) + writeIcon(ostr, "static"); + ostr << "

\n"; + ostr << "

"; + writeDecl(ostr, pVar->declaration()); + ostr << ";

\n"; + writeDescription(ostr, pVar->getDocumentation()); +} + + +void DocWriter::writeNameListItem(std::ostream& ostr, const std::string& str, const Symbol* pSymbol, const NameSpace* pNameSpace, bool& first) +{ + if (first) + first = false; + else + ostr << ", "; + + if (pSymbol) + writeLink(ostr, pSymbol, str); + else + ostr << htmlizeName(str); +} + + +void DocWriter::writeLink(std::ostream& ostr, const std::string& uri, const std::string& text) +{ + ostr << "" << htmlize(text) << ""; +} + + +void DocWriter::writeLink(std::ostream& ostr, const Symbol* pSymbol, const std::string& name) +{ + ostr << "" << htmlizeName(name) << ""; +} + + +void DocWriter::writeLink(std::ostream& ostr, const std::string& uri, const std::string& text, const std::string& linkClass) +{ + ostr << "" << htmlize(text) << ""; +} + + +void DocWriter::writeTargetLink(std::ostream& ostr, const std::string& uri, const std::string& text, const std::string& target) +{ + if (_noFrames && target != "_blank") + ostr << "" << text << ""; + else if (!target.empty()) + ostr << "" << text << ""; + else + ostr << "" << htmlize(text) << ""; +} + + +void DocWriter::writeImageLink(std::ostream& ostr, const std::string& uri, const std::string& image, const std::string& alt) +{ + ostr << ""; + ostr << "" + alt + " "; + ostr << ""; +} + + +void DocWriter::writeImage(std::ostream& ostr, const std::string& uri, const std::string& caption) +{ + ostr << "
" << std::endl; + ostr << "" + caption + " " << std::endl; + if (!caption.empty()) + { + ostr << "
" << htmlize(caption) << "
"; + } + ostr << "
" << std::endl; +} + + +void DocWriter::writeIcon(std::ostream& ostr, const std::string& icon) +{ + ostr << " " + icon + " "; +} + + +void DocWriter::writeAnchor(std::ostream& ostr, const std::string& text, const Symbol* pSymbol) +{ + ostr << "" << htmlize(text) << ""; +} + + +void DocWriter::writeDeprecated(std::ostream& ostr, const std::string& what) +{ + ostr << "
" << std::endl; + ostr << "

" << tr("Deprecated") << ". " << tr("This") << " " << what << " " << tr("is_deprecated") << ".

" << std::endl; + ostr << "
" << std::endl; +} + + +std::string DocWriter::headerFor(const Symbol* pSymbol) +{ + Path path(pSymbol->getFile()); + std::string header; + int i = 0; + while (i < path.depth() - 1 && path[i] != "include") ++i; + for (++i; i < path.depth(); ++i) + { + header += path[i]; + header += "/"; + } + header += path.getFileName(); + return header; +} + + +std::string DocWriter::titleFor(const Symbol* pSymbol) +{ + std::string title; + switch (pSymbol->kind()) + { + case Symbol::SYM_NAMESPACE: + title += "namespace"; + break; + case Symbol::SYM_STRUCT: + title += (static_cast(pSymbol)->isClass() ? "class" : "struct"); + break; + case Symbol::SYM_ENUM: + title += "enum "; + break; + default: + break; + } + if (!title.empty()) title += " "; + const Function* pFunc = dynamic_cast(pSymbol); + if (pFunc && pFunc->isConstructor()) + { + title += "class " + pSymbol->nameSpace()->fullName(); + } + else + { + title += pSymbol->fullName(); + if (pFunc) title += "()"; + } + return title; +} + + +std::string DocWriter::htmlize(const std::string& str) +{ + std::string result; + for (std::string::const_iterator it = str.begin(); it != str.end(); ++it) + result += htmlize(*it); + return result; +} + + +std::string DocWriter::htmlize(char c) +{ + std::string result; + switch (c) + { + case '"': + result += """; + break; + case '<': + result += "<"; + break; + case '>': + result += ">"; + break; + case '&': + result += "&"; + break; + default: + result += c; + } + return result; +} + + +void DocWriter::libraries(std::set& libs) +{ + for (NameSpace::SymbolTable::const_iterator it = _symbols.begin(); it != _symbols.end(); ++it) + { + const std::string& lib = it->second->getLibrary(); + if (!lib.empty()) + libs.insert(lib); + } +} + + +void DocWriter::packages(const std::string& lib, std::set& packages) +{ + for (NameSpace::SymbolTable::const_iterator it = _symbols.begin(); it != _symbols.end(); ++it) + { + const std::string& plib = it->second->getLibrary(); + const std::string& pkg = it->second->getPackage(); + if (!pkg.empty() && lib == plib) + packages.insert(pkg); + } +} + + +void DocWriter::writePages() +{ + _pNameSpace = rootNameSpace(); + for (PageMap::iterator it = _pages.begin(); it != _pages.end(); ++it) + { + writePage(it->second); + } +} + + +void DocWriter::writePage(Page& page) +{ + std::ifstream istr(page.path.c_str()); + if (!istr.good()) throw Poco::OpenFileException(page.path); + std::string title; + std::string category; + std::string text; + int ch = istr.get(); + while (ch != -1 && ch != '\n') { title += (char) ch; ch = istr.get(); } + ch = istr.get(); + while (ch != -1 && ch != '\n') { category += (char) ch; ch = istr.get(); } + + while (std::isspace(ch)) ch = istr.get(); + while (ch != -1) + { + text += (char) ch; + if (ch == '\n') text += ' '; + ch = istr.get(); + } + + page.title = title; + page.category = category; + + TOC toc; + scanTOC(text, toc); + + std::string path(pathFor(page.fileName)); + std::ofstream ostr(path.c_str()); + if (!ostr.good()) throw Poco::CreateFileException(path); + writeHeader(ostr, title, "js/iframeResizer.min.js"); + writeTitle(ostr, tr(category), title); + beginBody(ostr); + writeNavigationFrame(ostr, "category", category); + beginContent(ostr); + if (!toc.empty()) + { + writeTOC(ostr, toc); + } + writeDescription(ostr, text); + writeCopyright(ostr); + endContent(ostr); + endBody(ostr); + ostr << "" << std::endl; + writeFooter(ostr); +} + + +void DocWriter::scanTOC(const std::string& text, TOC& toc) +{ + int titleId = 0; + std::istringstream istr(text); + while (!istr.eof()) + { + std::string line; + std::getline(istr, line); + std::string::const_iterator it(line.begin()); + std::string::const_iterator end(line.end()); + while (it != end && std::isspace(*it)) ++it; + if (it != end && *it == '!') + { + ++it; + int level = MAX_TITLE_LEVEL; + while (it != end && *it == '!') + { + level--; + ++it; + } + while (it != end && std::isspace(*it)) ++it; + TOCEntry entry; + entry.id = titleId++; + entry.level = level; + entry.title.assign(it, end); + toc.push_back(entry); + } + } +} + + +void DocWriter::writeTOC(std::ostream& ostr, const TOC& toc) +{ + ostr << "
" << std::endl; + ostr << "
  • " << tr("TOC") << std::endl; + int lastLevel = 0; + for (TOC::const_iterator it = toc.begin(); it != toc.end(); ++it) + { + int level = it->level; + if (level > lastLevel) + { + ostr << "
      " << std::endl; + } + else if (level < lastLevel) + { + for (int i = level; i < lastLevel; i++) + { + ostr << "
  • " << std::endl; + } + } + else + { + ostr << "" << std::endl; + } + ostr << "
  • " << htmlize(it->title) << "" << std::endl; + lastLevel = level; + } + while (lastLevel-- > 1) + { + ostr << "
" << std::endl; + } + ostr << "
" << std::endl; +} + + +void DocWriter::writeCategoryIndex(const std::string& category, const std::string& fileName) +{ + std::ofstream ostr(pathFor(fileName).c_str()); + if (!ostr.good()) throw Poco::CreateFileException(fileName); + writeHeader(ostr, tr(category)); + beginBody(ostr); + ostr << "

" << htmlize(tr(category)) << "

"; + writeCategoryIndex(ostr, category, "_top"); + endBody(ostr); + writeFooter(ostr); +} + + +void DocWriter::writeCategoryIndex(std::ostream& ostr, const std::string& category, const std::string& target) +{ + ostr << "
    \n"; + for (PageMap::const_iterator it = _pages.begin(); it != _pages.end(); ++it) + { + if (it->second.category == category) + { + ostr << "
  • "; + writeTargetLink(ostr, it->second.fileName, it->second.title, target); + ostr << "
  • \n"; + } + } + ostr << "
\n"; +} + + +NameSpace* DocWriter::rootNameSpace() const +{ + for (NameSpace::SymbolTable::const_iterator it = _symbols.begin(); it != _symbols.end(); ++it) + { + if (it->second->kind() == Symbol::SYM_NAMESPACE) + { + NameSpace* pNS = static_cast(it->second); + while (pNS->nameSpace()) pNS = pNS->nameSpace(); + return pNS; + } + } + return 0; +} + + +const std::string& DocWriter::tr(const std::string& id) +{ + StringMap::const_iterator it = _strings.find(id); + + if (it == _strings.end()) + { + loadString(id, id, _language); + it = _strings.find(id); + } + if (it != _strings.end()) + return it->second; + else + return id; +} + + +void DocWriter::loadString(const std::string& id, const std::string& def, const std::string& language) +{ + Application& app = Application::instance(); + std::pair p(id, app.config().getString("Translations." + language + "." + id, def)); + _strings.insert(p); +} + + +void DocWriter::loadStrings(const std::string& language) +{ + _strings.clear(); + loadString("AAAIntroduction", "Introduction", language); + loadString("All_Base_Classes", "All Base Classes", language); + loadString("All_Symbols", "All Symbols", language); + loadString("Anonymous", "Anonymous", language); + loadString("Constructors", "Constructors", language); + loadString("Class", "Class", language); + loadString("Deprecated", "Deprecated", language); + loadString("Description", "Description", language); + loadString("Destructor", "Destructor", language); + loadString("Direct_Base_Classes", "Direct Base Classes", language); + loadString("Enumerations", "Enumerations", language); + loadString("Functions", "Functions", language); + loadString("Header", "Header", language); + loadString("iff", "if and only if", language); + loadString("Inheritance", "Inheritance", language); + loadString("Inherited_Functions", "Inherited Functions", language); + loadString("is_deprecated", "is deprecated and should no longer be used", language); + loadString("Known_Derived_Classes", "Known Derived Classes", language); + loadString("Library", "Library", language); + loadString("License", "License", language); + loadString("Member_Functions", "Member Functions", language); + loadString("Member_Summary", "Member Summary", language); + loadString("more", "more...", language); + loadString("Namespaces", "Namespaces", language); + loadString("Namespace", "Namespace", language); + loadString("Nested_Classes", "Nested Classes", language); + loadString("Package", "Package", language); + loadString("Packages", "Packages", language); + loadString("Package_Index", "Package Index", language); + loadString("Reference", "Reference", language); + loadString("See_also", "See also", language); + loadString("Struct", "Struct", language); + loadString("Symbol_Index", "Symbol Index", language); + loadString("This", "This", language); + loadString("Types", "Types", language); + loadString("Variables", "Variables", language); +} diff --git a/PocoDoc/src/DocWriter.h b/PocoDoc/src/DocWriter.h new file mode 100644 index 000000000..e70763c6c --- /dev/null +++ b/PocoDoc/src/DocWriter.h @@ -0,0 +1,227 @@ +// +// DocWriter.h +// +// Definition of the DocWriter class. +// +// Copyright (c) 2005-2007, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// SPDX-License-Identifier: BSL-1.0 +// + + +#ifndef PocoDoc_DocWriter_INCLUDED +#define PocoDoc_DocWriter_INCLUDED + + +#include "Poco/CppParser/NameSpace.h" +#include "Poco/Logger.h" +#include +#include +#include + + +namespace Poco { +namespace CppParser { + + +class Symbol; +class Struct; +class Function; +class TypeDef; +class Enum; +class Variable; + + +} } // namespace Poco::CppParser + + +class DocWriter + /// Given a symbol table obtained from a CppParser, this + /// class writes reference documentation in HTML format + /// to a directory. +{ +public: + DocWriter(const Poco::CppParser::NameSpace::SymbolTable& symbols, const std::string& path, bool prettifyCode = true, bool noFrames = false); + /// Creates the DocWriter. + + ~DocWriter(); + /// Destroys the DocWriter. + + void write(); + /// Writes all documentation files. + + void writeEclipseTOC(); + /// Write Eclipse Table-Of-Contents XML files. + + void addPage(const std::string& path); + /// Adds a page. + +protected: + enum TextState + { + TEXT_PARAGRAPH, + TEXT_LIST, + TEXT_OLIST, + TEXT_LITERAL, + TEXT_WHITESPACE + }; + + struct Page + { + std::string path; + std::string fileName; + std::string title; + std::string category; + }; + + enum + { + MAX_TITLE_LEVEL = 3, + PAGE_INDEX_COLUMNS = 2, + NAMESPACE_INDEX_COLUMNS = 4 + }; + + struct TOCEntry + { + std::string title; + int level; + int id; + }; + + typedef std::vector TOC; + typedef std::map MethodMap; + typedef std::map StringMap; + typedef std::map PageMap; + + void writePages(); + void writePage(Page& page); + void scanTOC(const std::string& text, TOC& toc); + void writeTOC(std::ostream& ostr, const TOC& toc); + void writeCategoryIndex(const std::string& category, const std::string& fileName); + void writeCategoryIndex(std::ostream& ostr, const std::string& category, const std::string& target); + void writePageIndex(std::ostream& ostr); + void writeNameSpaceIndex(std::ostream& ostr); + + void writeClass(const Poco::CppParser::Struct* pStruct); + void writeNameSpace(const Poco::CppParser::NameSpace* pNameSpace); + + void writeNavigation(); + void writePackage(const std::string& file, const std::string& library, const std::string& package); + + std::string pathFor(const std::string& file); + static std::string fileNameFor(const Poco::CppParser::Symbol* pNameSpace); + static std::string baseNameFor(const Poco::CppParser::Symbol* pNameSpace); + static std::string uriFor(const Poco::CppParser::Symbol* pSymbol); + static std::string makeFileName(const std::string& str); + static std::string headerFor(const Poco::CppParser::Symbol* pSymbol); + static std::string titleFor(const Poco::CppParser::Symbol* pSymbol); + + void writeHeader(std::ostream& ostr, const std::string& title, const std::string& extraScript = ""); + void writeNavigationFrame(std::ostream& ostr, const std::string& group, const std::string& item); + static void writeFooter(std::ostream& ostr); + void writeCopyright(std::ostream& ostr); + static void writeTitle(std::ostream& ostr, const std::string& category, const std::string& title); + static void writeTitle(std::ostream& ostr, const Poco::CppParser::NameSpace* pNameSpace, const std::string& title); + static void writeSubTitle(std::ostream& ostr, const std::string& title); + static void beginBody(std::ostream& ostr); + static void endBody(std::ostream& ostr); + static void beginContent(std::ostream& ostr); + static void endContent(std::ostream& ostr); + void writeDescription(std::ostream& ostr, const std::string& text); + void writeDescriptionLine(std::ostream& ostr, const std::string& text, TextState& state); + void writeSummary(std::ostream& ostr, const std::string& text, const std::string& uri); + static std::string htmlize(const std::string& str); + static std::string htmlize(char c); + static TextState analyzeLine(const std::string& line); + static std::string htmlizeName(const std::string& name); + void writeText(std::ostream& ostr, const std::string& text); + void writeText(std::ostream& ostr, std::string::const_iterator begin, const std::string::const_iterator& end); + void writeDecl(std::ostream& ostr, const std::string& decl); + void writeDecl(std::ostream& ostr, std::string::const_iterator begin, const std::string::const_iterator& end); + bool writeSymbol(std::ostream& ostr, std::string& token, std::string::const_iterator& begin, const std::string::const_iterator& end); + bool writeSpecial(std::ostream& ostr, std::string& token, std::string::const_iterator& begin, const std::string::const_iterator& end); + void nextToken(std::string::const_iterator& it, const std::string::const_iterator& end, std::string& token); + void writeListItem(std::ostream& ostr, const std::string& text); + void writeOrderedListItem(std::ostream& ostr, const std::string& text); + void writeLiteral(std::ostream& ostr, const std::string& text); + void writeFileInfo(std::ostream& ostr, const Poco::CppParser::Symbol* pSymbol); + void writeInheritance(std::ostream& ostr, const Poco::CppParser::Struct* pStruct); + void writeMethodSummary(std::ostream& ostr, const Poco::CppParser::Struct* pStruct); + void writeNestedClasses(std::ostream& ostr, const Poco::CppParser::Struct* pStruct); + void writeNameSpacesSummary(std::ostream& ostr, const Poco::CppParser::NameSpace* pNameSpace); + void writeNameSpaces(std::ostream& ostr, const Poco::CppParser::NameSpace* pNameSpace); + void writeClassesSummary(std::ostream& ostr, const Poco::CppParser::NameSpace* pNameSpace); + void writeClasses(std::ostream& ostr, const Poco::CppParser::NameSpace* pNameSpace); + void writeClassSummary(std::ostream& ostr, const Poco::CppParser::Struct* pStruct); + void writeTypesSummary(std::ostream& ostr, const Poco::CppParser::NameSpace* pNameSpace); + void writeTypes(std::ostream& ostr, const Poco::CppParser::NameSpace* pNameSpace); + void writeType(std::ostream& ostr, const Poco::CppParser::TypeDef* pType); + void writeEnums(std::ostream& ostr, const Poco::CppParser::NameSpace* pNameSpace); + void writeEnum(std::ostream& ostr, const Poco::CppParser::Enum* pEnum); + void writeConstructors(std::ostream& ostr, const Poco::CppParser::Struct* pStruct); + void writeDestructor(std::ostream& ostr, const Poco::CppParser::Struct* pStruct); + void writeMethods(std::ostream& ostr, const Poco::CppParser::Struct* pNameSpace); + void writeFunctionsSummary(std::ostream& ostr, const Poco::CppParser::NameSpace* pNameSpace); + void writeFunctions(std::ostream& ostr, const Poco::CppParser::NameSpace* pNameSpace); + void writeFunction(std::ostream& ostr, const Poco::CppParser::Function* pFunc); + void writeVariables(std::ostream& ostr, const Poco::CppParser::NameSpace* pNameSpace); + void writeVariable(std::ostream& ostr, const Poco::CppParser::Variable* pVar); + static void writeNameListItem(std::ostream& ostr, const std::string& name, const Poco::CppParser::Symbol* pSymbol, const Poco::CppParser::NameSpace* pNameSpace, bool& first); + static void writeLink(std::ostream& ostr, const std::string& uri, const std::string& text); + static void writeLink(std::ostream& ostr, const Poco::CppParser::Symbol* pSymbol, const std::string& text); + static void writeLink(std::ostream& ostr, const std::string& uri, const std::string& text, const std::string& linkClass); + void writeTargetLink(std::ostream& ostr, const std::string& uri, const std::string& text, const std::string& target); + static void writeImageLink(std::ostream& ostr, const std::string& uri, const std::string& image, const std::string& alt); + static void writeImage(std::ostream& ostr, const std::string& uri, const std::string& caption); + static void writeIcon(std::ostream& ostr, const std::string& icon); + static void writeAnchor(std::ostream& ostr, const std::string& text, const Poco::CppParser::Symbol* pSymbol); + static void writeDeprecated(std::ostream& ostr, const std::string& what); + void libraries(std::set& libs); + void packages(const std::string& lib, std::set& packages); + + Poco::CppParser::NameSpace* rootNameSpace() const; + + static const std::string& tr(const std::string& id); + static void loadStrings(const std::string& language); + static void loadString(const std::string& id, const std::string& def, const std::string& language); + + static Poco::Logger& logger(); + + static const std::string RFC_URI; + static const std::string nbsp; + static const std::string copy; + static const std::string mdash; + +private: + bool _prettifyCode; + bool _noFrames; + bool _htmlMode; + bool _literalMode; + const Poco::CppParser::NameSpace::SymbolTable& _symbols; + std::string _path; + const Poco::CppParser::NameSpace* _pNameSpace; + PageMap _pages; + bool _pendingLine; + int _indent; + int _titleId; + + static std::string _language; + static StringMap _strings; + + static Poco::Logger* _pLogger; +}; + + +// +// inlines +// +inline Poco::Logger& DocWriter::logger() +{ + poco_check_ptr (_pLogger); + + return *_pLogger; +} + + +#endif // PocoDoc_DocWriter_INCLUDED diff --git a/PocoDoc/src/PocoDoc.cpp b/PocoDoc/src/PocoDoc.cpp new file mode 100644 index 000000000..00766a8ea --- /dev/null +++ b/PocoDoc/src/PocoDoc.cpp @@ -0,0 +1,494 @@ +// +// PocoDoc.cpp +// +// Copyright (c) 2005-2014, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// SPDX-License-Identifier: BSL-1.0 +// + + +#include "Poco/StringTokenizer.h" +#include "Poco/Glob.h" +#include "Poco/Path.h" +#include "Poco/File.h" +#include "Poco/DirectoryIterator.h" +#include "Poco/Process.h" +#include "Poco/Pipe.h" +#include "Poco/PipeStream.h" +#include "Poco/Environment.h" +#include "Poco/NumberFormatter.h" +#include "Poco/Exception.h" +#include "Poco/Stopwatch.h" +#include "Poco/DateTime.h" +#include "Poco/DateTimeFormatter.h" +#include "Poco/Timespan.h" +#include "Poco/DateTimeFormatter.h" +#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/CppParser/Parser.h" +#include "Poco/CppParser/NameSpace.h" +#include "Poco/CppParser/Struct.h" +#include "Poco/CppParser/Utility.h" +#include "DocWriter.h" +#include +#include +#include +#include +#include +#include +#include + + +using Poco::StringTokenizer; +using Poco::Glob; +using Poco::Path; +using Poco::File; +using Poco::DirectoryIterator; +using Poco::Process; +using Poco::ProcessHandle; +using Poco::Environment; +using Poco::NumberFormatter; +using Poco::Exception; +using Poco::Util::Application; +using Poco::Util::Option; +using Poco::Util::OptionSet; +using Poco::Util::OptionCallback; +using Poco::Util::HelpFormatter; +using Poco::Util::AbstractConfiguration; + +static std::string osName = Environment::osName(); + +class Preprocessor +{ +public: + Preprocessor(const ProcessHandle& proc, std::istream* pStream): + _proc(proc), + _pStream(pStream) + { + } + + Preprocessor(const ProcessHandle& proc, std::istream* pStream, const std::string& file): + _proc(proc), + _pStream(pStream), + _file(file) + { + } + + std::istream& stream() + { + return *_pStream; + } + + ~Preprocessor() + { + int c = _pStream->get(); + while (c != -1) c = _pStream->get(); + delete _pStream; + _proc.wait(); + if (!_file.empty()) + { + try + { + File f(_file); + f.remove(); + } + catch (Exception&) + { + } + } + } + +private: + ProcessHandle _proc; + std::istream* _pStream; + std::string _file; +}; + + +class PocoDocApp: public Application +{ +public: + PocoDocApp(): + _helpRequested(false), + _writeEclipseTOC(false) + { + std::setlocale(LC_ALL, ""); + } + + ~PocoDocApp() + { + } + +protected: + void initialize(Application& self) + { + loadConfiguration(); // load default configuration files, if present + Application::initialize(self); + } + + void uninitialize() + { + Application::uninitialize(); + } + + void reinitialize(Application& self) + { + Application::reinitialize(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(this, &PocoDocApp::handleHelp))); + + options.addOption( + Option("config-file", "f", "load configuration data from a file") + .required(false) + .repeatable(true) + .argument("file") + .callback(OptionCallback(this, &PocoDocApp::handleConfig))); + + options.addOption( + Option("eclipse", "e", "write Eclipse TOC file") + .required(false) + .repeatable(false) + .callback(OptionCallback(this, &PocoDocApp::handleEclipse))); + } + + void handleHelp(const std::string& name, const std::string& value) + { + _helpRequested = true; + displayHelp(); + stopOptionsProcessing(); + } + + void handleEclipse(const std::string& name, const std::string& value) + { + _writeEclipseTOC = true; + } + + void handleConfig(const std::string& name, const std::string& value) + { + loadConfiguration(value, -200); + } + + void displayHelp() + { + HelpFormatter helpFormatter(options()); + helpFormatter.setCommand(commandName()); + helpFormatter.setUsage("OPTIONS"); + helpFormatter.setHeader("Applied Informatics' super duper documentation builder."); + helpFormatter.format(std::cout); + } + + void buildFileList(std::set& files) + { + std::set temp; + std::string includes = config().getString("PocoDoc.files.include"); + std::string excludes = config().getString("PocoDoc.files.exclude", ""); + StringTokenizer incTokenizer(includes, ",\n", StringTokenizer::TOK_IGNORE_EMPTY | StringTokenizer::TOK_TRIM); + for (StringTokenizer::Iterator it = incTokenizer.begin(); it != incTokenizer.end(); ++it) + { + Glob::glob(*it, temp); + } + StringTokenizer excTokenizer(excludes, ",\n", StringTokenizer::TOK_IGNORE_EMPTY | StringTokenizer::TOK_TRIM); + for (std::set::const_iterator it = temp.begin(); it != temp.end(); ++it) + { + Path p(*it); + bool include = true; + for (StringTokenizer::Iterator itg = excTokenizer.begin(); itg != excTokenizer.end(); ++itg) + { + Glob glob(*itg); + if (glob.match(p.getFileName())) + include = false; + } + if (include) + files.insert(*it); + } + } + + Preprocessor* preprocess(const std::string& file) + { + Path pp(file); + pp.setExtension("i"); + std::string comp = "PocoDoc.compiler"; + if (Environment::osFamilyWindows()) + comp += ".windows"; + else + comp += ".unix"; + std::string exec = config().getString(comp + ".exec"); + std::string opts = config().getString(comp + ".options"); + std::string path = config().getString(comp + ".path", ""); + bool usePipe = config().getBool(comp + ".usePipe", false); + std::string popts; + for (std::string::const_iterator it = opts.begin(); it != opts.end(); ++it) + { + if (*it == '%') + popts += pp.getBaseName(); + else + popts += *it; + } + StringTokenizer tokenizer(popts, ",\n", StringTokenizer::TOK_IGNORE_EMPTY | StringTokenizer::TOK_TRIM); + std::vector args(tokenizer.begin(), tokenizer.end()); + args.push_back(file); + + if (!path.empty()) + { + std::string newPath(Environment::get("PATH")); + newPath += Path::pathSeparator(); + newPath += path; + Environment::set("PATH", path); + } + + if (usePipe) + { + Poco::Pipe inPipe; + ProcessHandle proc = Process::launch(exec, args, 0, &inPipe, 0); + return new Preprocessor(proc, new Poco::PipeInputStream(inPipe)); + } + else + { + ProcessHandle proc = Process::launch(exec, args); + proc.wait(); + return new Preprocessor(proc, new std::ifstream(pp.getFileName().c_str()), pp.getFileName()); + } + } + + void parse(const std::string& file) + { + logger().information("Preprocessing " + file); + std::unique_ptr pPreProc(preprocess(file)); + + logger().information("Parsing " + file); + if (pPreProc->stream().good()) + { + Poco::CppParser::Parser parser(_gst, file, pPreProc->stream()); + parser.parse(); + } + else throw Poco::OpenFileException("cannot read from preprocessor"); + } + + int parseAll() + { + int errors = 0; + std::set files; + buildFileList(files); + for (std::set::const_iterator it = files.begin(); it != files.end(); ++it) + { + try + { + parse(*it); + } + catch (Exception& exc) + { + logger().log(exc); + ++errors; + } + } + return errors; + } + + void fixup() + { + logger().information("Fixing-up class hierarchies"); + for (Poco::CppParser::NameSpace::SymbolTable::iterator it = _gst.begin(); it != _gst.end(); ++it) + { + Poco::CppParser::Struct* pStruct = dynamic_cast(it->second); + if (pStruct) + { + pStruct->fixupBases(); + } + } + } + + void writeDoc() + { + logger().information("Generating documentation"); + Path path(config().getString("PocoDoc.output", "doc")); + path.makeDirectory(); + File file(path); + file.createDirectories(); + + DocWriter writer(_gst, path.toString(), config().getBool("PocoDoc.prettifyCode", false), _writeEclipseTOC); + + if (config().hasProperty("PocoDoc.pages")) + { + std::string pages = config().getString("PocoDoc.pages"); + StringTokenizer tokenizer(pages, ",\n", StringTokenizer::TOK_IGNORE_EMPTY | StringTokenizer::TOK_TRIM); + std::set pageSet; + for (StringTokenizer::Iterator it = tokenizer.begin(); it != tokenizer.end(); ++it) + { + Glob::glob(*it, pageSet); + } + for (std::set::const_iterator it = pageSet.begin(); it != pageSet.end(); ++it) + { + writer.addPage(*it); + } + } + writer.write(); + + if (_writeEclipseTOC) + { + writer.writeEclipseTOC(); + } + } + + void copyResources() + { + logger().information("Copying resources"); + Path path(config().getString("PocoDoc.output", "doc")); + + if (config().hasProperty("PocoDoc.resources")) + { + std::string pages = config().getString("PocoDoc.resources"); + StringTokenizer tokenizer(pages, ",\n", StringTokenizer::TOK_IGNORE_EMPTY | StringTokenizer::TOK_TRIM); + std::set pageSet; + for (StringTokenizer::Iterator it = tokenizer.begin(); it != tokenizer.end(); ++it) + { + Glob::glob(*it, pageSet); + } + for (std::set::const_iterator it = pageSet.begin(); it != pageSet.end(); ++it) + { + try + { + copyResource(Path(*it), path); + } + catch (Poco::Exception& exc) + { + logger().log(exc); + } + } + } + } + + void copyResource(const Path& source, const Path& dest) + { + logger().information(std::string("Copying resource ") + source.toString() + " to " + dest.toString()); + File sf(source); + if (sf.isDirectory()) + copyDirectory(source, dest); + else + copyFile(source, dest); + } + + void copyFile(const Path& source, const Path& dest) + { + Path dd(dest); + dd.makeDirectory(); + File df(dd); + df.createDirectories(); + dd.setFileName(source.getFileName()); + if (source.getExtension() == "thtml") + { + dd.setExtension("html"); + std::ifstream istr(source.toString().c_str()); + std::ofstream ostr(dd.toString().c_str()); + while (istr.good()) + { + std::string line; + std::getline(istr, line); + ostr << config().expand(line) << std::endl; + } + } + else + { + File sf(source); + sf.copyTo(dd.toString()); + } + } + + void copyDirectory(const Path& source, const Path& dest) + { + Path src(source); + src.makeFile(); + DirectoryIterator it(src); + DirectoryIterator end; + for (; it != end; ++it) + { + Path dd(dest); + dd.makeDirectory(); + dd.pushDirectory(src.getFileName()); + copyResource(it.path(), dd); + } + } + + int main(const std::vector& args) + { + if (!_helpRequested) + { + Poco::DateTime now; + config().setString("PocoDoc.date", Poco::DateTimeFormatter::format(now, "%Y-%m-%d")); + config().setString("PocoDoc.year", Poco::DateTimeFormatter::format(now, "%Y")); + config().setString("PocoDoc.googleAnalyticsCode", generateGoogleAnalyticsCode()); + Poco::Stopwatch sw; + int errors = 0; + try + { + sw.start(); + errors = parseAll(); + fixup(); + writeDoc(); + copyResources(); + sw.stop(); + } + catch (Exception& exc) + { + std::cerr << exc.displayText() << std::endl; + } + logger().information(NumberFormatter::format(errors) + " errors."); + logger().information(std::string("Time: ") + Poco::DateTimeFormatter::format(Poco::Timespan(sw.elapsed()))); + } + return Application::EXIT_OK; + } + + std::string generateGoogleAnalyticsCode() + { + std::stringstream ostr; + std::string googleAnalyticsId(config().getString("PocoDoc.googleAnalyticsId", "")); + if (!googleAnalyticsId.empty()) + { + ostr << "\n"; + ostr << "\n"; + ostr << "\n"; + ostr << "\n"; + } + return ostr.str(); + } + +private: + bool _helpRequested; + bool _writeEclipseTOC; + Poco::CppParser::NameSpace::SymbolTable _gst; +}; + + +int main(int argc, char** argv) +{ + PocoDocApp app; + try + { + app.init(argc, argv); + } + catch (Poco::Exception& exc) + { + app.logger().log(exc); + return Application::EXIT_CONFIG; + } + return app.run(); +}