diff options
author | Shawn Hussey <shawn@zeroc.com> | 2011-08-16 13:39:10 -0230 |
---|---|---|
committer | Shawn Hussey <shawn@zeroc.com> | 2011-08-16 13:39:10 -0230 |
commit | b1e407d3c7ca1f08d5e822226a17ba381f9003fc (patch) | |
tree | 0d5aca236c4d567736860500100ebd7dd28c40fc | |
parent | Added support for replica & name cert CN verification (diff) | |
download | ice-b1e407d3c7ca1f08d5e822226a17ba381f9003fc.tar.bz2 ice-b1e407d3c7ca1f08d5e822226a17ba381f9003fc.tar.xz ice-b1e407d3c7ca1f08d5e822226a17ba381f9003fc.zip |
Initial commit of slice2confluence.
-rw-r--r-- | cpp/src/slice2confluence/.depend | 2 | ||||
-rw-r--r-- | cpp/src/slice2confluence/.depend.mak | 2 | ||||
-rw-r--r-- | cpp/src/slice2confluence/ConfluenceOutput.cpp | 452 | ||||
-rw-r--r-- | cpp/src/slice2confluence/ConfluenceOutput.h | 170 | ||||
-rwxr-xr-x | cpp/src/slice2confluence/Gen.cpp | 2959 | ||||
-rw-r--r-- | cpp/src/slice2confluence/Gen.h | 277 | ||||
-rwxr-xr-x | cpp/src/slice2confluence/Main.cpp | 338 | ||||
-rw-r--r-- | cpp/src/slice2confluence/Makefile | 33 | ||||
-rw-r--r-- | cpp/src/slice2confluence/Makefile.mak | 53 | ||||
-rw-r--r-- | cpp/src/slice2confluence/Slice2Confluence.rc | 34 |
10 files changed, 4320 insertions, 0 deletions
diff --git a/cpp/src/slice2confluence/.depend b/cpp/src/slice2confluence/.depend new file mode 100644 index 00000000000..c38543ac755 --- /dev/null +++ b/cpp/src/slice2confluence/.depend @@ -0,0 +1,2 @@ +Gen$(OBJEXT): Gen.cpp $(includedir)/IceUtil/DisableWarnings.h $(includedir)/IceUtil/Functional.h $(includedir)/IceUtil/Handle.h $(includedir)/IceUtil/Exception.h $(includedir)/IceUtil/Config.h $(includedir)/IceUtil/StringUtil.h $(includedir)/Slice/FileTracker.h $(includedir)/IceUtil/Shared.h $(includedir)/Slice/Parser.h Gen.h $(includedir)/IceUtil/OutputUtil.h +Main$(OBJEXT): Main.cpp $(includedir)/IceUtil/Options.h $(includedir)/IceUtil/Config.h $(includedir)/IceUtil/RecMutex.h $(includedir)/IceUtil/Lock.h $(includedir)/IceUtil/ThreadException.h $(includedir)/IceUtil/Exception.h $(includedir)/IceUtil/Time.h $(includedir)/IceUtil/MutexProtocol.h $(includedir)/IceUtil/Shared.h $(includedir)/IceUtil/Handle.h $(includedir)/IceUtil/CtrlCHandler.h $(includedir)/IceUtil/Mutex.h $(includedir)/IceUtil/MutexPtrLock.h $(includedir)/Slice/Preprocessor.h $(includedir)/Slice/FileTracker.h $(includedir)/Slice/Parser.h $(includedir)/Slice/Util.h $(includedir)/IceUtil/OutputUtil.h Gen.h diff --git a/cpp/src/slice2confluence/.depend.mak b/cpp/src/slice2confluence/.depend.mak new file mode 100644 index 00000000000..11ef9b46339 --- /dev/null +++ b/cpp/src/slice2confluence/.depend.mak @@ -0,0 +1,2 @@ +Gen$(OBJEXT): Gen.cpp "$(includedir)/IceUtil/DisableWarnings.h" "$(includedir)/IceUtil/Functional.h" "$(includedir)/IceUtil/Handle.h" "$(includedir)/IceUtil/Exception.h" "$(includedir)/IceUtil/Config.h" "$(includedir)/IceUtil/StringUtil.h" "$(includedir)/Slice/FileTracker.h" "$(includedir)/IceUtil/Shared.h" "$(includedir)/Slice/Parser.h" Gen.h "$(includedir)/IceUtil/OutputUtil.h" +Main$(OBJEXT): Main.cpp "$(includedir)/IceUtil/Options.h" "$(includedir)/IceUtil/Config.h" "$(includedir)/IceUtil/RecMutex.h" "$(includedir)/IceUtil/Lock.h" "$(includedir)/IceUtil/ThreadException.h" "$(includedir)/IceUtil/Exception.h" "$(includedir)/IceUtil/Time.h" "$(includedir)/IceUtil/MutexProtocol.h" "$(includedir)/IceUtil/Shared.h" "$(includedir)/IceUtil/Handle.h" "$(includedir)/IceUtil/CtrlCHandler.h" "$(includedir)/IceUtil/Mutex.h" "$(includedir)/IceUtil/MutexPtrLock.h" "$(includedir)/Slice/Preprocessor.h" "$(includedir)/Slice/FileTracker.h" "$(includedir)/Slice/Parser.h" "$(includedir)/Slice/Util.h" "$(includedir)/IceUtil/OutputUtil.h" Gen.h diff --git a/cpp/src/slice2confluence/ConfluenceOutput.cpp b/cpp/src/slice2confluence/ConfluenceOutput.cpp new file mode 100644 index 00000000000..db2d566c9ee --- /dev/null +++ b/cpp/src/slice2confluence/ConfluenceOutput.cpp @@ -0,0 +1,452 @@ +#include <ConfluenceOutput.h> +#include <iostream> +#include <sstream> +#include <string.h> + +using namespace std; +using namespace IceUtilInternal; + +namespace Confluence +{ + + EndElement ee; + +} + +// ---------------------------------------------------------------------- +// ConfluenceOutput +// ---------------------------------------------------------------------- + +Confluence::ConfluenceOutput::ConfluenceOutput() : + OutputBase(), + _se(false), + _text(false), + _escape(false), + _listMarkers("") +{ +} + +Confluence::ConfluenceOutput::ConfluenceOutput(ostream& os) : + OutputBase(os), + _se(false), + _text(false), + _escape(false), + _listMarkers("") +{ +} + +Confluence::ConfluenceOutput::ConfluenceOutput(const char* s) : + OutputBase(s), + _se(false), + _text(false), + _escape(false), + _listMarkers("") +{ +} + +void +Confluence::ConfluenceOutput::print(const char* s) +{ + if(_se) + { + _se = false; + } + _text = true; + + if(_escape) + { + string escaped = escape(s); + OutputBase::print(escaped.c_str()); + } + else + { + OutputBase::print(s); + } +} + +void +Confluence::ConfluenceOutput::newline() +{ + if(_se) + { + _se = false; + } + OutputBase::newline(); +} + +void +Confluence::ConfluenceOutput::startElement(const string& element) +{ + string escaped; + if (_escape) + { + escaped = escape(element); + } + else + { + escaped = element; + } + + const char *tagname; + string::size_type tagpos = element.find_first_of(" "); + tagname = element.substr(0, tagpos).c_str(); + + + if (!strcmp(tagname, "p")) + { + _out << "\n"; + } else if (!strcmp(tagname, "dl")) + { + _out << "\n"; + } else if (!strcmp(tagname, "dt")) + { + _out << "+"; + } else if (!strcmp(tagname, "dd")) + { + _out << "* "; + } else if (!strcmp(tagname, "table")) + { + _out << "\n"; + } else if (!strcmp(tagname, "tbody")) + { + _out << "\n"; + } else if (!strcmp(tagname, "tr")) + { + _out << "\n"; + } else if (!strcmp(tagname, "td")) + { + _out << "|"; + } else if (!strcmp(tagname, "th")) + { + _out << "||"; + } else if (!strcmp(tagname, "div")) + { + _out << "{panel}"; + } else if (!strcmp(tagname, "span")) + { + _out << "{panel}"; + } else if (!strcmp(tagname, "ol")) + { + _listMarkers.append("#"); + _out << "\n"; + } else if (!strcmp(tagname, "ul")) + { + _listMarkers.append("*"); + _out << "\n"; + } else if (!strcmp(tagname, "li")) + { + _out << _listMarkers << " "; + } else if (!strcmp(tagname, "hr")) + { + _out << "----"; + } else if (!strcmp(tagname, "h1")) + { + _out << "h1. "; + } else if (!strcmp(tagname, "h2")) + { + _out << "h2. "; + } else if (!strcmp(tagname, "h3")) + { + _out << "h3. "; + } else if (!strcmp(tagname, "h4")) + { + _out << "h4. "; + } else if (!strcmp(tagname, "h5")) + { + _out << "h5. "; + } else if (!strcmp(tagname, "h6")) + { + _out << "h6. "; + } else { + _out << "{" << escaped << "}"; + } + + _se = true; + _text = false; + + string::size_type pos = element.find_first_of(" \t"); + if(pos == string::npos) + { + _elementStack.push(element); + } + else + { + _elementStack.push(element.substr(0, pos)); + } + + ++_pos; // TODO: ??? + inc(); + _separator = false; +} + +void +Confluence::ConfluenceOutput::endElement() +{ + string element = _elementStack.top(); + _elementStack.pop(); + + + string escaped; + if (_escape) + { + escaped = escape(element); + } + else + { + escaped = element; + } + + const char *tagname; + string::size_type tagpos = element.find_first_of(" "); + tagname = element.substr(0, tagpos).c_str(); + + if (!strcmp(tagname, "p")) + { + _out << "\n"; + } else if (!strcmp(tagname, "dl")) + { + _out << "\n"; + } else if (!strcmp(tagname, "dt")) + { + _out << "+\n"; + } else if (!strcmp(tagname, "dd")) + { + _out << "\n\n"; + } else if (!strcmp(tagname, "table")) + { + _out << "\n"; + } else if (!strcmp(tagname, "tbody")) + { + _out << ""; + } else if (!strcmp(tagname, "tr")) + { + _out << "|\n"; + } else if (!strcmp(tagname, "td")) + { + _out << ""; + } else if (!strcmp(tagname, "th")) + { + _out << ""; + } else if (!strcmp(tagname, "div")) + { + _out << "{panel}"; + } else if (!strcmp(tagname, "span")) + { + _out << "{panel}"; + } else if (!strcmp(tagname, "ol")) + { + _listMarkers.erase(_listMarkers.size()-1); + _out << "\n"; + } else if (!strcmp(tagname, "ul")) + { + _listMarkers.erase(_listMarkers.size()-1); + _out << "\n"; + } else if (!strcmp(tagname, "li")) + { + _out << "\n"; + } else if (!strcmp(tagname, "hr")) + { + _out << "\n\n"; + } else if (!strcmp(tagname, "h1")) + { + _out << "\n\n"; + } else if (!strcmp(tagname, "h2")) + { + _out << "\n\n"; + } else if (!strcmp(tagname, "h3")) + { + _out << "\n\n"; + } else if (!strcmp(tagname, "h4")) + { + _out << "\n\n"; + } else if (!strcmp(tagname, "h5")) + { + _out << "\n\n"; + } else if (!strcmp(tagname, "h6")) + { + _out << "\n\n"; + } else { + _out << "{" << escaped << "}"; + } + + dec(); + --_pos; // TODO: ??? + + _se = false; + _text = false; +} + +string +Confluence::ConfluenceOutput::getLinkMarkup(const std::string& url, const std::string& text, const std::string& anchor, const std::string& tip) +{ + ostringstream oss; + oss << "["; + if (!text.empty()) { + oss << text << "|"; + } + oss << url; + if (!anchor.empty()) + { + oss << "#" << anchor; + } + if (!tip.empty()) + { + oss << "|" << tip; + } + oss << "]"; + return oss.str(); +} + +string +Confluence::ConfluenceOutput::getImageMarkup(const string& url, const string& title) +{ + ostringstream oss; + oss << "!" << url; + if (!title.empty()) + { + oss << "|" << title; + } + oss << "!"; + return oss.str(); //leak? +} + +void +Confluence::ConfluenceOutput::attr(const string& name, const string& value) +{ + // + // Precondition: Attributes can only be attached to elements. + // + assert(_se); + _out << " " << name << "=\"" << escape(value) << "\""; +} + +void +Confluence::ConfluenceOutput::startEscapes() +{ + _escape = true; +} + +void +Confluence::ConfluenceOutput::endEscapes() +{ + _escape = false; +} + +string +Confluence::ConfluenceOutput::currentElement() const +{ + if(_elementStack.size() > 0) + { + return _elementStack.top(); + } + else + { + return string(); + } +} + +string +Confluence::ConfluenceOutput::escape(const string& input) const +{ + string v = input; + + // + // Find out whether there is a reserved character to avoid + // conversion if not necessary. + // + const string allReserved = "<>'\"&{}"; + if(v.find_first_of(allReserved) != string::npos) + { + // + // First convert all & to & + // + size_t pos = 0; + while((pos = v.find_first_of('&', pos)) != string::npos) + { + v.insert(pos+1, "amp;"); + pos += 4; + } + + // + // Next convert remaining reserved characters. + // + const string reserved = "<>'\"{}"; + pos = 0; + while((pos = v.find_first_of(reserved, pos)) != string::npos) + { + string replace; + switch(v[pos]) + { + case '>': + replace = ">"; + break; + + case '<': + replace = "<"; + break; + + case '\'': + replace = "'"; + break; + + case '"': + replace = """; + break; + + case '{': + replace = "\\{"; + break; + + case '}': + replace = "\\}"; + break; + + default: + assert(false); + } + + v.erase(pos, 1); + v.insert(pos, replace); + pos += replace.size(); + } + } + return v; +} + +Confluence::ConfluenceOutput& +Confluence::operator<<(ConfluenceOutput& out, ios_base& (*val)(ios_base&)) +{ + ostringstream s; + s << val; + out.print(s.str().c_str()); + return out; +} + +Confluence::StartElement::StartElement(const string& name) : +_name(name) +{ +} + +const string& +Confluence::StartElement::getName() const +{ + return _name; +} + +Confluence::Attribute::Attribute(const string& name, const string& value) : + _name(name), + _value(value) +{ +} + +const string& +Confluence::Attribute::getName() const +{ + return _name; +} + +const string& +Confluence::Attribute::getValue() const +{ + return _value; +} diff --git a/cpp/src/slice2confluence/ConfluenceOutput.h b/cpp/src/slice2confluence/ConfluenceOutput.h new file mode 100644 index 00000000000..2897f3086cd --- /dev/null +++ b/cpp/src/slice2confluence/ConfluenceOutput.h @@ -0,0 +1,170 @@ +#include <IceUtil/OutputUtil.h> + +#ifndef CONFLUENCE_OUTPUT +#define CONFLUENCE_OUTPUT + +namespace Confluence +{ + +// ---------------------------------------------------------------------- +// ConfluenceOutput +// ---------------------------------------------------------------------- + +class ICE_UTIL_API ConfluenceOutput : public IceUtilInternal::OutputBase +{ +public: + + ConfluenceOutput(); + ConfluenceOutput(std::ostream&); + ConfluenceOutput(const char*); + + virtual ~ConfluenceOutput(){}; + + virtual void print(const char*); // Print a string. + + virtual void newline(); // Print newline. + + void startElement(const std::string&); // Start an element. + void endElement(); // End an element. + void attr(const std::string&, const std::string&); // Add an attribute to an element. + + std::string getLinkMarkup(const std::string&, const std::string& = "", const std::string& = "", const std::string& = ""); + std::string getImageMarkup(const std::string&, const std::string& = ""); + + void startEscapes(); + void endEscapes(); + + std::string currentElement() const; + +private: + + std::string escape(const ::std::string&) const; + + std::stack<std::string> _elementStack; + + bool _se; + bool _text; + + bool _escape; + + std::string _listMarkers; +}; + +template<typename T> +inline ConfluenceOutput& +operator<<(ConfluenceOutput& out, const T& val) +{ + std::ostringstream s; + s << val; + out.print(s.str().c_str()); + return out; +} + +template<> +inline ConfluenceOutput& +operator<<(ConfluenceOutput& o, const IceUtilInternal::NextLine&) +{ + o.newline(); + return o; +} + +template<> +inline ConfluenceOutput& +operator<<(ConfluenceOutput& o, const IceUtilInternal::Separator&) +{ + o.separator(); + return o; +} + +class ICE_UTIL_API EndElement +{ +}; +extern ICE_UTIL_API EndElement ee; + +template<> +inline ConfluenceOutput& +operator<<(ConfluenceOutput& o, const EndElement&) +{ + o.endElement(); + return o; +} + +class ICE_UTIL_API StartElement +{ +public: + + StartElement(const std::string&); + + const std::string& getName() const; + +private: + + const std::string _name; +}; + +typedef StartElement se; + +template<> +inline ConfluenceOutput& +operator<<(ConfluenceOutput& o, const StartElement& e) +{ + o.startElement(e.getName()); + return o; +} + +class ICE_UTIL_API Attribute +{ +public: + + Attribute(const ::std::string&, const ::std::string&); + + const ::std::string& getName() const; + const ::std::string& getValue() const; + +private: + + const ::std::string _name; + const ::std::string _value; +}; + +typedef Attribute attr; + +template<> +inline ConfluenceOutput& +operator<<(ConfluenceOutput& o, const Attribute& e) +{ + o.attr(e.getName(), e.getValue()); + return o; +} + +class ICE_UTIL_API StartEscapes +{ +}; +extern ICE_UTIL_API StartEscapes startEscapes; + +class ICE_UTIL_API EndEscapes +{ +}; +extern ICE_UTIL_API EndEscapes endEscapes; + +template<> +inline ConfluenceOutput& +operator<<(ConfluenceOutput& o, const StartEscapes&) +{ + o.startEscapes(); + return o; +} + +template<> +inline ConfluenceOutput& +operator<<(ConfluenceOutput& o, const EndEscapes&) +{ + o.endEscapes(); + return o; +} + +ICE_UTIL_API ConfluenceOutput& operator<<(ConfluenceOutput&, std::ios_base& (*)(std::ios_base&)); + +} + +#endif diff --git a/cpp/src/slice2confluence/Gen.cpp b/cpp/src/slice2confluence/Gen.cpp new file mode 100755 index 00000000000..f89a4f94b6e --- /dev/null +++ b/cpp/src/slice2confluence/Gen.cpp @@ -0,0 +1,2959 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2011 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +#if defined(_MSC_VER) && _MSC_VER >= 1400 +# define _CRT_SECURE_NO_DEPRECATE 1 // C4996 '<C function>' was declared deprecated +#endif + +#include <IceUtil/DisableWarnings.h> +#include <IceUtil/Functional.h> +#include <IceUtil/StringUtil.h> +#include <Slice/FileTracker.h> +#include <Gen.h> + +#include <sys/types.h> +#include <sys/stat.h> + +#ifdef _WIN32 +#include <direct.h> +#else +#include <unistd.h> +#endif + +#include <iterator> + +#include <string> + +using namespace std; +using namespace Slice; +using namespace IceUtil; +using namespace IceUtilInternal; +using namespace Confluence; + +namespace Slice +{ + +void +generate(const UnitPtr& unit, const string& dir, const string& header, const string& footer, + const string& indexHeader, const string& indexFooter, const string& imageDir, const string& logoURL, + const string& searchAction, unsigned indexCount, unsigned warnSummary) +{ + unit->mergeModules(); + + // + // I don't want the top-level module to be sorted, therefore no + // p->sort() before or after the p->sortContents(). + // + unit->sortContents(false); + + GeneratorBase::setOutputDir(dir); + GeneratorBase::setFooter(footer); + GeneratorBase::setImageDir(imageDir); + GeneratorBase::setLogoURL(logoURL); + GeneratorBase::setSearchAction(searchAction); + GeneratorBase::setIndexCount(indexCount); + GeneratorBase::warnSummary(warnSummary); + + // + // The file visitor first runs over the tree and records + // the names of all files in this documentation set. + // This information is used later to check whether a referenced + // symbol is defined in this documentation set, as opposed to + // being defined in an included file that is not part of this + // documentation set. If the former, we can generate a link + // to the symbol; if the latter, we cannot. + // + Files files; + FileVisitor tv(files); + unit->visit(&tv, false); + + // + // Generate the start page. + // + StartPageVisitor spv(files); + unit->visit(&spv, false); + + // + // Generate the table of contents. + // + TOCVisitor tocv(files, indexHeader, indexFooter); + unit->visit(&tocv, false); + tocv.generate(); + + // + // Generate the individual HTML pages. + // + GeneratorBase::setSymbols(tocv.symbols()); + PageVisitor v(files); + unit->visit(&v, false); +} + +} + +string Slice::GeneratorBase::_dir = "."; +string Slice::GeneratorBase::_header1; +string Slice::GeneratorBase::_header2; +string Slice::GeneratorBase::_footer; +string Slice::GeneratorBase::_imageDir; +string Slice::GeneratorBase::_logoURL; +string Slice::GeneratorBase::_searchAction; +size_t Slice::GeneratorBase::_indexCount = 0; +size_t Slice::GeneratorBase::_warnSummary = 0; +ContainedList Slice::GeneratorBase::_symbols; + +// +// Set the output directory, creating it if necessary. +// + +void +Slice::GeneratorBase::setOutputDir(const string& dir) +{ + if(!dir.empty()) + { + _dir = dir; + makeDir(_dir); + } +} + +// +// Get the headers. If "header" is empty, use a default header. +// If a header file is specified, it is expected to include <body> +// and to contain a "TITLE" placeholder line (in column 1, no leading +// or trailing white space). The actual document title is later substituted +// where that TITLE placeholder appears. +// +void +Slice::GeneratorBase::setHeader(const string& header) +{ + getHeaders(header, _header1, _header2); +} + +// +// Get the footer. If "footer" is empty, use a default footer. +// The footer is expected to include </body>. +// +void +Slice::GeneratorBase::setFooter(const string& footer) +{ + _footer = getFooter(footer); +} + +// +// Set the directory for style sheet images. +// +void +Slice::GeneratorBase::setImageDir(const string& imageDir) +{ + _imageDir = imageDir; +} + +// +// Set URL for logo image, if any. +// +void +Slice::GeneratorBase::setLogoURL(const string& logoURL) +{ + _logoURL = logoURL; +} + +// +// Set search action, if any. +// +void +Slice::GeneratorBase::setSearchAction(const string& searchAction) +{ + _searchAction = searchAction; +} + +// +// Set the threshold at which we start generating sub-indexes. +// If a page has fewer entries than this, we don't generate a +// sub-index. (For example, with "ic" set to 3, we generate +// a sub-index only if, say, a structure has 3 or more members. +// +void +Slice::GeneratorBase::setIndexCount(int ic) +{ + _indexCount = ic; +} + +// +// If n > 0, we print a warning if a summary sentence exceeds n characters. +// +void +Slice::GeneratorBase::warnSummary(int n) +{ + _warnSummary = n; +} + +void +Slice::GeneratorBase::setSymbols(const ContainedList& symbols) +{ + _symbols = symbols; +} + +Slice::GeneratorBase::GeneratorBase(Confluence::ConfluenceOutput& o, const Files& files) + : _out(o), _files(files) +{ +} + +Slice::GeneratorBase::~GeneratorBase() +{ +} + +// +// Open a file for writing in the output directory (the output directory +// is created if necessary) and write the HTML header into the file. +// +void +Slice::GeneratorBase::openDoc(const string& file, const string& title, const string& header, const string& footer) +{ + makeDir(_dir); + openStream(_dir + "/" + file); + + _out.inc(); + _out.inc(); +} + +// +// Open an HTML file for writing for the specified construct. The +// path name of the file is relative to the output directory and +// is constructed from the Slice scoped name. Sub-directories are +// created as needed and the header is written to the file. +// +void +Slice::GeneratorBase::openDoc(const ContainedPtr& c) +{ + string path = _dir; + StringList components = getContainer(c); + StringList::size_type num = 0; + for(StringList::const_iterator i = components.begin(); i != components.end(); ++i) + { + path += "/" + *i; + ++num; + if(num < components.size()) + { + makeDir(path); + } + } + path += ".conf"; + + openStream(path); + _out.inc(); + _out.inc(); +} + +// +// Close an open HTML file after writing the footer. +// +void +Slice::GeneratorBase::closeDoc(const string& footer) +{ + _out.dec(); + _out.dec(); + _out << nl << (!footer.empty() ? footer : _footer); + _out << nl; +} + +void +Slice::GeneratorBase::start(const std::string& element, const std::string& classes) +{ + string s = element; + if(!classes.empty()) + { + s += " class=\"" + classes + "\""; + } + _out << Confluence::se(s); +} + +void +Slice::GeneratorBase::end() +{ + _out << Confluence::ee; +} + +std::string +Slice::GeneratorBase::getImageMarkup(const string& url, const string& title) +{ + return _out.getImageMarkup(url, title); +} + +string +Slice::GeneratorBase::getLinkMarkup(const string& url, const string& text, const string& anchor, const string& tip) +{ + return _out.getLinkMarkup(url, text, anchor, tip); +} + +void +Slice::GeneratorBase::removeNewlines(string str) +{ + str.erase(std::remove(str.begin(), str.end(), '\n'), str.end()); + str.erase(std::remove(str.begin(), str.end(), '\r'), str.end()); +} + +void +Slice::GeneratorBase::printComment(const ContainedPtr& p, const ContainerPtr& container, + const string& deprecateReason, bool forIndex) +{ +#ifndef NDEBUG + int indent = _out.currIndent(); +#endif + + string comment = getComment(p, container, false, forIndex); + StringList par = getTagged("param", comment); + StringList ret = getTagged("return", comment); + StringList throws = getTagged("throws", comment); + StringList see = getTagged("see", comment); + + string::size_type pos = comment.find_last_not_of(" \t\r\n"); + if(pos != string::npos) + { + comment.erase(pos + 1); + start("p"); + _out.zeroIndent(); + _out << nl << comment; + _out.restoreIndent(); + end(); + } + + if(!deprecateReason.empty()) + { + start("p", "Deprecated"); + _out << nl << deprecateReason; + end(); + } + + assert(_out.currIndent() == indent); + + if(!par.empty()) + { + start("h4"); + _out << "Parameters"; + end(); + start("dl"); + for(StringList::const_iterator q = par.begin(); q != par.end(); ++q) + { + string term; + pos = q->find_first_of(" \t\r\n"); + if(pos != string::npos) + { + term = q->substr(0, pos); + } + string item; + pos = q->find_first_not_of(" \t\r\n", pos); + if(pos != string::npos) + { + item = q->substr(pos); + removeNewlines(item); + } + + start("dt", "Symbol"); + _out << term; + end(); + start("dd"); + _out << item; + end(); + } + end(); + } + + if(!ret.empty()) + { + start("h4"); + _out << "Return Value"; + end(); + start("p"); + _out << ret.front(); + end(); + } + + if(!throws.empty()) + { + start("h4"); + _out << "Exceptions"; + end(); + start("dl"); + for(StringList::const_iterator q = throws.begin(); q != throws.end(); ++q) + { + string term; + pos = q->find_first_of(" \t\r\n"); + if(pos != string::npos) + { + term = q->substr(0, pos); + } + string item; + pos = q->find_first_not_of(" \t\r\n", pos); + if(pos != string::npos) + { + item = q->substr(pos); + removeNewlines(item); + } + + start("dt", "Symbol"); + _out << toString(toSliceID(term, container->definitionContext()->filename()), container, false, forIndex); + end(); + start("dd"); + _out << item; + end(); + } + end(); + } + + ClassList derivedClasses; + ClassDefPtr def = ClassDefPtr::dynamicCast(p); + if(def) + { + derivedClasses = p->unit()->findDerivedClasses(def); + } + if(!derivedClasses.empty()) + { + start("h4"); + _out << "Derived Classes and Interfaces"; + end(); + start("dl"); + for(ClassList::const_iterator q = derivedClasses.begin(); q != derivedClasses.end(); ++q) + { + start("dt", "Symbol"); + _out << toString(*q, container, false, forIndex); + end(); + } + end(); + } + + ExceptionList derivedExceptions; + ExceptionPtr ex = ExceptionPtr::dynamicCast(p); + if(ex) + { + derivedExceptions = p->unit()->findDerivedExceptions(ex); + if(!derivedExceptions.empty()) + { + start("h4"); + _out << "Derived Exceptions"; + end(); + start("dl"); + for(ExceptionList::const_iterator q = derivedExceptions.begin(); q != derivedExceptions.end(); ++q) + { + start("dt", "Symbol"); + _out << toString(*q, container, false, forIndex); + end(); + } + end(); + } + + ContainedList usedBy; + usedBy = p->unit()->findUsedBy(ex); + if(!usedBy.empty()) + { + start("h4"); + _out << "Used By"; + end(); + start("dl"); + // + // We first extract the symbol names from the used-by list and sort + // them, otherwise the symbols appear in random order. + // + StringList sl; + for(ContainedList::const_iterator q = usedBy.begin(); q != usedBy.end(); ++q) + { + sl.push_back(toString(*q, container, false, forIndex)); + } + sl.sort(); + for(StringList::const_iterator r = sl.begin(); r != sl.end(); ++r) + { + start("dt", "Symbol"); + _out << *r; + end(); + } + end(); + } + } + + ContainedList usedBy; + ConstructedPtr constructed; + if(def) + { + constructed = def->declaration(); + } + else + { + constructed = ConstructedPtr::dynamicCast(p); + } + if(constructed) + { + usedBy = p->unit()->findUsedBy(constructed); + } + if(!usedBy.empty()) + { + // + // We first accumulate the strings in a list instead of printing + // each stringified entry in the usedBy list. This is necessary because + // the usedBy list can contain operations and parameters. But toString() + // on a parameter returns the string for the parameter's operation, so + // we can end up printing the same operation name more than once. + // + StringList strings; + for(ContainedList::const_iterator q = usedBy.begin(); q != usedBy.end(); ++q) + { + strings.push_back(toString(*q, container, false, forIndex)); + } + strings.sort(); + strings.unique(); + + start("h4"); + _out << "Used By"; + end(); + start("dl"); + for(list<string>::const_iterator p = strings.begin(); p != strings.end(); ++p) + { + start("dt", "Symbol"); + _out << *p; + end(); + } + end(); + } + + if(!see.empty()) + { + start("h4"); + _out << "See Also"; + end(); + start("dl"); + for(StringList::const_iterator q = see.begin(); q != see.end(); ++q) + { + start("dt", "Symbol"); + _out << toString(toSliceID(*q, container->definitionContext()->filename()), container, false, forIndex); + end(); + } + end(); + } + + assert(_out.currIndent() == indent); +} + +void +Slice::GeneratorBase::printMetaData(const ContainedPtr& p) +{ + list<string> metaData = p->getMetaData(); + + if(!metaData.empty()) + { + _out << "["; + list<string>::const_iterator q = metaData.begin(); + while(q != metaData.end()) + { + _out << " \"" << *q << "\""; + if(++q != metaData.end()) + { + _out << ","; + } + } + _out << " ]" << nl; + } +} + +void +Slice::GeneratorBase::printSummary(const ContainedPtr& p, const ContainerPtr& module, bool deprecated, bool forIndex) +{ + ContainerPtr container = ContainerPtr::dynamicCast(p); + if(!container) + { + container = p->container(); + } + + if(module) + { + container = module; + } + + string summary = getComment(p, container, true, forIndex); + _out << summary; + + if(deprecated) + { + start("p", "Deprecated"); + _out << "Deprecated."; + end(); + } +} + +void +Slice::GeneratorBase::printHeaderFooter(const ContainedPtr& c) +{ + ContainerPtr container = ContainerPtr::dynamicCast(c); + string scoped = c->scoped(); + ContainedList::const_iterator prev = _symbols.end(); + ContainedList::const_iterator pos = _symbols.begin(); + while(pos != _symbols.end()) + { + if((*pos)->scoped() == scoped) + { + break; + } + prev = pos++; + } + ContainedList::const_iterator next = pos == _symbols.end() ? _symbols.end() : ++pos; + + bool isFirst = prev == _symbols.end(); + bool isLast = next == _symbols.end(); + bool hasParent = false; + if(EnumPtr::dynamicCast(c)) + { + hasParent = true; + } + else if(ModulePtr::dynamicCast(c)) + { + ModulePtr m = ModulePtr::dynamicCast(c); + if(ModulePtr::dynamicCast(m->container())) + { + hasParent = true; + } + } + else if(ContainedPtr::dynamicCast(c)) + { + hasParent = true; + } + + bool onEnumPage = EnumPtr::dynamicCast(c); + + string prevLink; + string prevClass; + if(!isFirst) + { + prevLink = getLinkPath(*prev, container, ModulePtr::dynamicCast(c), onEnumPage); + if(ModulePtr::dynamicCast(c)) + { + // + // If we are writing the header/footer for a module page, + // and the target is up from the current scope, + // we need to step up an extra level because modules + // are documented one directory up, at the same level as + // the module directory. + // + StringList source = getContainer(c); + StringList target = getContainer(*prev); + if(target.size() < source.size()) + { + prevLink = "../" + prevLink; + } + } + prevClass = "Button"; + } + else + { + prevClass = "ButtonGrey"; + } + + string nextLink; + string nextClass; + if(!isLast) + { + nextLink = getLinkPath(*next, container, ModulePtr::dynamicCast(c), onEnumPage); + if(ModulePtr::dynamicCast(c)) + { + // + // If we are writing the header/footer for a module page, + // and the target is up from the current scope, + // we need to step up an extra level because modules + // are documented one directory up, at the same level as + // the module directory. + // + StringList source = getContainer(c); + StringList target = getContainer(*next); + if(target.size() < source.size()) + { + nextLink = "../" + nextLink; + } + } + nextClass = "Button"; + } + else + { + nextClass = "ButtonGrey"; + } + + string upLink; + string upClass; + if(hasParent) + { + upLink = getLinkPath(c->container(), container, false, onEnumPage); + upClass = "Button"; + } + else + { + upClass = "ButtonGrey"; + } + + string homeLink = getLinkPath(0, container, false, onEnumPage); + if(!homeLink.empty()) + { + homeLink += "/"; + } + homeLink += "index.conf"; + + string indexLink = getLinkPath(0, container, false, onEnumPage); + if(!indexLink.empty()) + { + indexLink += "/"; + } + indexLink += "_sindex.conf"; + + string imageDir = getImageDir(); + + string prevImage = imageDir.empty() ? "Previous" : (isFirst ? "prevx.gif" : "prev.gif"); + string nextImage = imageDir.empty() ? "Next" : (isLast ? "nextx.gif" : "next.gif"); + string upImage = imageDir.empty()? "Up" : (hasParent ? "up.gif" : "upx.gif"); + + string homeImage = imageDir.empty() ? "Home" : "home.gif"; + string indexImage = imageDir.empty() ? "Index" : "index.gif"; + + if(!imageDir.empty()) + { + string path = getLinkPath(0, container, false, onEnumPage); + if(!path.empty()) + { + path += "/"; + } + path += imageDir + "/"; + + prevImage = path + prevImage; + nextImage = path + nextImage; + upImage = path + upImage; + homeImage = path + homeImage; + indexImage = path + indexImage; + } + + start("table", "HeaderFooter"); + start("tr"); + start("td align=\"left\""); + + start("table"); + start("tr"); + start("td"); + _out << getLinkMarkup(homeLink, homeImage); + end(); // td + + if(!imageDir.empty() || !isFirst) + { + start("td"); + if(!isFirst) + { + _out << getLinkMarkup(prevLink, prevImage); + } + end(); + } + + if(!imageDir.empty() || hasParent) + { + start("td"); + if(hasParent) + { + _out << getLinkMarkup(upLink, upImage); + } + end(); + } + + if(!imageDir.empty() || !isLast) + { + start("td"); + if(!isLast) + { + _out << getLinkMarkup(nextLink, nextImage); + } + end(); + } + + start("td"); + _out << getLinkMarkup(indexLink, indexImage); + end(); + + end(); // tr + end(); // table + end(); // td + + start("td align=\"center\""); + printSearch(); + end(); + + start("td align=\"right\""); + printLogo(c, container, onEnumPage); + end(); + + end(); // tr + end(); // table + +} + +void +Slice::GeneratorBase::printSearch() +{ + //Do nothing. Form components will not work in confluence markup. +} + +void +Slice::GeneratorBase::printLogo(const ContainedPtr& c, const ContainerPtr& container, bool forEnum) +{ + string imageDir = getImageDir(); + if(!imageDir.empty()) + { + string path = getLinkPath(0, container, false, forEnum); + if(!path.empty()) + { + path += "/"; + } + path += imageDir + "/logo.gif"; + start("table", "LogoTable"); + start("tr"); + start("td"); + if(!_logoURL.empty()) + { + _out << getLinkMarkup(_logoURL, getImageMarkup(path, "Logo")); + } + else + { + _out << getImageMarkup(path, "Logo"); + } + end(); + end(); + end(); + } +} + +string +Slice::GeneratorBase::toString(const SyntaxTreeBasePtr& p, const ContainerPtr& container, bool asTarget, bool forIndex, + size_t* summarySize, bool shortName) +{ + string anchor; + string linkpath; + string s; + + static const char* builtinTable[] = + { + "byte", + "bool", + "short", + "int", + "long", + "float", + "double", + "string", + "Object", + "Object*", + "LocalObject" + }; + + BuiltinPtr builtin = BuiltinPtr::dynamicCast(p); + if(builtin) + { + s = builtinTable[builtin->kind()]; + return s; + } + + ProxyPtr proxy = ProxyPtr::dynamicCast(p); + if(proxy) + { + if(_files.find(p->definitionContext()->filename()) != _files.end()) + { + linkpath = getLinkPath(proxy->_class()->definition(), container, forIndex); + } + s = getScopedMinimized(proxy->_class(), container, shortName); + } + + ClassDeclPtr cl = ClassDeclPtr::dynamicCast(p); + if(cl) + { + // + // We must generate the id from the definition, not from the + // declaration, provided that a definition is available. + // + ContainedPtr definition = cl->definition(); + if(definition && _files.find(p->definitionContext()->filename()) != _files.end()) + { + linkpath = getLinkPath(definition, container, forIndex); + } + s = getScopedMinimized(cl, container, shortName); + } + + ExceptionPtr ex = ExceptionPtr::dynamicCast(p); + if(ex) + { + if(_files.find(p->definitionContext()->filename()) != _files.end()) + { + linkpath = getLinkPath(ex, container, forIndex); + } + s = getScopedMinimized(ex, container, shortName); + } + + StructPtr st = StructPtr::dynamicCast(p); + if(st) + { + if(_files.find(p->definitionContext()->filename()) != _files.end()) + { + linkpath = getLinkPath(st, container, forIndex); + } + s = getScopedMinimized(st, container, shortName); + } + + EnumeratorPtr en = EnumeratorPtr::dynamicCast(p); + if(en) + { + if(_files.find(p->definitionContext()->filename()) != _files.end()) + { + anchor = getAnchor(en); + linkpath = getLinkPath(en, container, forIndex); + } + s = getScopedMinimized(en, container, shortName); + } + + OperationPtr op = OperationPtr::dynamicCast(p); + if(op) + { + if(_files.find(p->definitionContext()->filename()) != _files.end()) + { + anchor = getAnchor(op); + linkpath = getLinkPath(op, container, forIndex); + } + s = getScopedMinimized(op, container, shortName); + } + + ParamDeclPtr pd = ParamDeclPtr::dynamicCast(p); + if(pd) + { + op = OperationPtr::dynamicCast(pd->container()); + assert(op); + if(_files.find(p->definitionContext()->filename()) != _files.end()) + { + anchor = getAnchor(op); + linkpath = getLinkPath(op, container, forIndex); + } + s = getScopedMinimized(op, container, shortName); + } + + if(s.empty()) + { + ContainedPtr contained = ContainedPtr::dynamicCast(p); + assert(contained); + if(_files.find(p->definitionContext()->filename()) != _files.end()) + { + if(!(EnumPtr::dynamicCast(p) || ModulePtr::dynamicCast(p) || ClassDeclPtr::dynamicCast(p))) + { + anchor = getAnchor(contained); + } + + // + // Sequences and dictionaries are documented on the page for their + // enclosing module. + // + if(SequencePtr::dynamicCast(p) || DictionaryPtr::dynamicCast(p)) + { + linkpath = getLinkPath(contained->container(), container, forIndex); + } + else + { + linkpath = getLinkPath(contained, container, forIndex); + } + } + s = getScopedMinimized(contained, container, shortName); + } + + if(summarySize) + { + *summarySize = s.size(); + } + + if(linkpath.empty() && anchor.empty()) + { + if(ProxyPtr::dynamicCast(p)) + { + s += '*'; + if(summarySize) + { + ++(*summarySize); + } + } + return s; + } + + string ret = ""; + if (asTarget) + { + ret += getLinkMarkup("", s, anchor); + } + else + { + ret += getLinkMarkup(linkpath, s, anchor); + } + + if(ProxyPtr::dynamicCast(p)) + { + ret += '*'; + } + return ret; +} + +string +Slice::GeneratorBase::toString(const string& str, const ContainerPtr& container, bool asTarget, bool forIndex, + size_t* summarySize) +{ + + TypeList types = container->lookupType(str, false); + if(!types.empty()) + { + return toString(types.front(), container, asTarget, forIndex, summarySize); + } + + ContainedList contList = container->lookupContained(str, false); + if(!contList.empty()) + { + return toString(contList.front(), container, asTarget, forIndex, summarySize); + } + + // + // If we can't find the string, printing it in typewriter + // font is the best we can do. + // + return "{{" + str + "}}"; +} + +string +Slice::GeneratorBase::getComment(const ContainedPtr& contained, const ContainerPtr& container, + bool summary, bool forIndex) +{ + size_t summarySize = 0; + string s = contained->comment(); + string comment; + for(unsigned int i = 0; i < s.size(); ++i) + { + // + // TODO: Remove old-style link processing once we no longer support the [ident] syntax for links. + // + if(s[i] == '\\' && i + 1 < s.size() && s[i + 1] == '[') + { + comment += '['; + ++summarySize; + ++i; + } + else if(s[i] == '[') + { + string literal; + for(++i; i < s.size(); ++i) + { + if(s[i] == ']') + { + break; + } + + literal += s[i]; + } + size_t sz = 0; + comment += toString(literal, container, false, forIndex, summary ? &sz : 0); + summarySize += sz; + + // + // TODO: Remove this warning once we no longer support the old javadoc syntax. + // + string fileName = contained->file(); + if(_warnOldCommentFiles.find(fileName) == _warnOldCommentFiles.end()) + { + _warnOldCommentFiles.insert(fileName); + cerr << fileName << ": warning: file contains old-style javadoc link syntax: `[" << literal << "]'" + << endl; + } + } + else if(s[i] == '{') + { + static const string atLink = "{@link"; + string::size_type pos = s.find(atLink, i); + if(pos != i) + { + comment += '{'; + ++summarySize; + continue; + } + string::size_type endpos = s.find('}', pos); + if(endpos == string::npos) + { + continue; + } + string literal = s.substr(pos + atLink.size(), endpos - pos - atLink.size()); + size_t sz = 0; + comment += toString(toSliceID(literal, contained->file()), container, false, forIndex, summary ? &sz : 0); + summarySize += sz; + i = static_cast<unsigned int>(endpos); + } + else if(summary && s[i] == '.' && (i + 1 >= s.size() || isspace(static_cast<unsigned char>(s[i + 1])))) + { + comment += '.'; + ++summarySize; + break; + } + else + { + comment += s[i]; + ++summarySize; + } + } + + if(summary && _warnSummary && summarySize > _warnSummary) + { + cerr << contained->file() << ": warning: summary size (" << summarySize << ") exceeds " << _warnSummary + << " characters: `" << comment << "'" << endl; + } + + return comment; +} + +string +Slice::GeneratorBase::getAnchor(const SyntaxTreeBasePtr& p) +{ + StringList symbols = getContained(p); + string anchor; + for(StringList::const_iterator i = symbols.begin(); i != symbols.end(); ++i) + { + if(i != symbols.begin()) + { + anchor += "::"; + } + anchor += *i; + } + return anchor; +} + +string +Slice::GeneratorBase::getLinkPath(const SyntaxTreeBasePtr& p, const ContainerPtr& container, bool forIndex, bool forEnum) +{ + ContainerPtr c = container; + + // + // If we are in a sub-index, we need to "step up" one level, because the links all + // point at a section in the same file. + // + if(forIndex && ContainedPtr::dynamicCast(container)) + { + c = ContainedPtr::dynamicCast(c)->container(); + } + + // + // Find the first component where the two scopes differ. + // + bool commonEnclosingScope = false; + StringList target; + EnumeratorPtr enumerator = EnumeratorPtr::dynamicCast(p); + if(enumerator) + { + target = toStringList(enumerator->type()); + } + else + { + target = getContainer(p); + } + StringList from = getContainer(c); + + while(!target.empty() && !from.empty() && target.front() == from.front()) + { + target.pop_front(); + from.pop_front(); + commonEnclosingScope = true; + } + + if(commonEnclosingScope && target.empty()) + { + ModulePtr module = ModulePtr::dynamicCast(p); + if(module) + { + target.push_front(module->name()); + } + } + else if(!from.empty()) + { + from.pop_front(); + } + + // + // For each component in the source path, step up a level. + // + string path; + while(!from.empty()) + { + if(!path.empty()) + { + path += "/"; + } + path += ".."; + from.pop_front(); + } + + // + // Now append the scope to the target. + // + while(!target.empty()) + { + if(!path.empty()) + { + path += "/"; + } + path += target.front() == "index" ? string("_index") : target.front(); + target.pop_front(); + } + + if(forEnum) + { + if(!path.empty()) + { + path = "../" + path; + } + else + { + path = ".."; + } + } + return path; +} + +string +Slice::GeneratorBase::getImageDir() +{ + return _imageDir; +} + +string +Slice::GeneratorBase::getLogoURL() +{ + return _logoURL; +} + +void +Slice::GeneratorBase::openStream(const string& path) +{ + _out.open(path.c_str()); + if(!_out.isOpen()) + { + ostringstream os; + os << "cannot open file `" << path << "': " << strerror(errno); + throw FileException(__FILE__, __LINE__, os.str()); + } + FileTracker::instance()->addFile(path); +} + +void +Slice::GeneratorBase::closeStream() +{ + _out.close(); +} + +string +Slice::GeneratorBase::containedToId(const ContainedPtr& contained, bool asTarget) +{ + assert(contained); + + string scoped = contained->scoped(); + if(scoped[0] == ':') + { + scoped.erase(0, 2); + } + + string id; + id.reserve(scoped.size()); + + for(unsigned int i = 0; i < scoped.size(); ++i) + { + if(scoped[i] == ':') + { + id += '.'; + ++i; + } + else + { + id += scoped[i]; + } + } + + // + // A link name cannot start with a period. + // + if(id[0] == '.') + { + id.erase(0, 1); + } + + return '"' + id + '"'; +} + +StringList +Slice::GeneratorBase::getTagged(const string& tag, string& comment) +{ + StringList result; + string::size_type begin = 0; + while(begin < comment.size()) + { + begin = comment.find("@" + tag, begin); + if(begin == string::npos) + { + return result; + } + + string::size_type pos1 = comment.find_first_not_of(" \t\r\n", begin + tag.size() + 1); + if(pos1 == string::npos) + { + comment.erase(begin); + return result; + } + + string::size_type pos2 = comment.find('@', pos1); + string line = comment.substr(pos1, pos2 - pos1); + comment.erase(begin, pos2 - 1 - begin); + + string::size_type pos3 = line.find_last_not_of(" \t\r\n"); + if(pos3 != string::npos) + { + line.erase(pos3 + 1); + } + result.push_back(line); + } + + return result; +} + +string +Slice::GeneratorBase::getScopedMinimized(const ContainedPtr& contained, const ContainerPtr& container, bool shortName) +{ + if(shortName) + { + return contained->name(); + } + + string s = contained->scoped(); + ContainerPtr p = container; + ContainedPtr q = ContainedPtr::dynamicCast(p); + + if(!q) // Container is the global module + { + return s.substr(2); + } + + do + { + string s2 = q->scoped(); + s2 += "::"; + + if(s.find(s2) == 0) + { + return s.substr(s2.size()); + } + + p = q->container(); + q = ContainedPtr::dynamicCast(p); + } + while(q); + + return s; +} + +StringList +Slice::GeneratorBase::getContained(const SyntaxTreeBasePtr& p) +{ + StringList result; + if(!p) + { + return result; + } + + SyntaxTreeBasePtr c = p; + + do + { + ContainedPtr contained = ContainedPtr::dynamicCast(c); + assert(contained); + result.push_front(contained->name()); + c = contained->container(); + } + while(!ContainerPtr::dynamicCast(c)); + return result; +} + +StringList +Slice::GeneratorBase::getContainer(const SyntaxTreeBasePtr& p) +{ + StringList result; + + if(!p) + { + return result; + } + + ContainedPtr contained = ContainedPtr::dynamicCast(p); + while(contained && + !ModulePtr::dynamicCast(contained) && + !ExceptionPtr::dynamicCast(contained) && + !ClassDefPtr::dynamicCast(contained) && + !StructPtr::dynamicCast(contained) && + !EnumPtr::dynamicCast(contained)) + { + contained = ContainedPtr::dynamicCast(contained->container()); + } + + while(contained) + { + result.push_front(contained->name()); + contained = ContainedPtr::dynamicCast(contained->container()); + } + return result; +} + +// +// TODO: remove warnOldStyleIdent() function once we no longer support +// old-style javadoc comments ([...] instead of {@link ...} and +// X::Y::Z instead of X.Y#Z). +// +// +void +Slice::GeneratorBase::warnOldStyleIdent(const string& str, const string& fileName) +{ + string newName; + + string::size_type next = 0; + if(str.size() > 2 && str[0] == ':' && str[1] == ':') + { + next = 2; + } + + int numIdents = 0; + string::size_type endpos; + while((endpos = str.find("::", next)) != string::npos) + { + if(numIdents != 0) + { + newName += "."; + } + newName += str.substr(next, endpos - next); + ++numIdents; + next = endpos; + if(next != string::npos) + { + next += 2; + } + } + + if(numIdents != 0) + { + newName += "."; + } + newName += str.substr(next); + + if(_warnOldCommentFiles.find(fileName) == _warnOldCommentFiles.end()) + { + _warnOldCommentFiles.insert(fileName); + + string::size_type pos; + pos = newName.rfind('.'); + string alternateName; + string lastName; + if(pos != string::npos) + { + alternateName = newName; + alternateName[pos] = '#'; + lastName = newName.substr(pos + 1); + } + + cerr << fileName << ": warning: file contains old-style javadoc identifier syntax: `" << str << "'." + << " Use `'" << newName << "'"; + if(!alternateName.empty()) + { + cerr << " or `" << alternateName << "' if `" << lastName << "' is a member"; + } + cerr << endl; + } +} + +// +// Convert a string of the form X.Y#Z into X::Y::Z (#Z converts to Z). +// TODO: Remove the filename parameter once we no longer support old-style javadoc comments. +// +string +Slice::GeneratorBase::toSliceID(const string& str, const string& filename) +{ + + const string s = IceUtilInternal::trim(str); + string result; + string::size_type pos; + string::size_type next = 0; + while((pos = s.find_first_of(".#", next)) != string::npos) + { + result += s.substr(next, pos - next); + if(s[pos] != '#' || pos != 0) + { + result += "::"; + } + next = ++pos; + } + result += s.substr(next); + + // + // TODO: Remove the warning once we no longer support the old-style + // javadoc syntax. + // + if(str.find("::") != string::npos) + { + warnOldStyleIdent(s, filename); + } + + return result; +} + +StringList +Slice::GeneratorBase::toStringList(const ContainedPtr& c) +{ + string scoped = c->scoped(); + assert(scoped.size() > 2); + assert(scoped[0] == ':'); + assert(scoped[1] == ':'); + + StringList ids; + string::size_type next = 2; + string::size_type endpos; + while((endpos = scoped.find("::", next)) != string::npos) + { + ids.push_back(scoped.substr(next, endpos - next)); + next = endpos; + if(next != string::npos) + { + ++next; + ++next; + } + } + ids.push_back(scoped.substr(next)); + + return ids; +} + +void +Slice::GeneratorBase::makeDir(const string& dir) +{ + struct stat st; + int rc = stat(dir.c_str(), &st); + if(rc == 0) + { + if(!(st.st_mode & S_IFDIR)) + { + ostringstream os; + os << "failed to create package directory `" << dir + << "': file already exists and is not a directory"; + throw FileException(__FILE__, __LINE__, os.str()); + } + return; + } + +#ifdef _WIN32 + rc = _mkdir(dir.c_str()); +#else + rc = mkdir(dir.c_str(), S_IRWXU | S_IRWXG | S_IRWXO); +#endif + if(rc != 0) + { + ostringstream os; + os << "cannot create directory `" << dir << "': " << strerror(errno); + throw FileException(__FILE__, __LINE__, os.str()); + } + FileTracker::instance()->addDirectory(dir); +} + +string +Slice::GeneratorBase::readFile(const string& file) +{ + ifstream in(file.c_str()); + if(!in) + { + ostringstream os; + os << "cannot open file `" << file << "': " << strerror(errno); + throw FileException(__FILE__, __LINE__, os.str()); + } + + ostringstream result; + string line; + getline(in, line); + while(!line.empty()) + { + result << line << '\n'; + getline(in, line); + } + + return result.str(); +} + +void +Slice::GeneratorBase::getHeaders(const string& header, string& h1, string& h2) +{ + //do nothing. No headers in confluence markup. +} + +string +Slice::GeneratorBase::getFooter(const string& footer) +{ + //Confluence markup is all body, no header/footer mechanism or tags that need cleaning up + return ""; +} + +void +Slice::GeneratorBase::readFile(const string& file, string& part1, string& part2) +{ + ifstream in(file.c_str()); + if(!in) + { + ostringstream os; + os << "cannot open file `" << file << "': " << strerror(errno); + throw FileException(__FILE__, __LINE__, os.str()); + } + + string line; + bool foundTitle = false; + + ostringstream p1; + while(!foundTitle && getline(in, line)) + { + if(line == "TITLE") + { + foundTitle = true; + } + else + { + p1 << line << '\n'; + } + } + part1 = p1.str(); + + if(!foundTitle) + { + string err = "no TITLE marker in `" + file + "'"; + throw err; + } + + ostringstream p2; + p2 << endl; + while(getline(in, line)) + { + p2 << line << '\n'; + } + part2 = p2.str(); +} + +Slice::StartPageGenerator::StartPageGenerator(const Files& files) + : GeneratorBase(_out, files) +{ + openDoc("index.conf", "Slice API Documentation"); +} + +Slice::StartPageGenerator::~StartPageGenerator() +{ + ::std::sort(_modules.begin(), _modules.end()); + + printHeaderFooter(); + + start("hr"); + end(); + + start("h1"); + _out << "Slice API Documentation"; + end(); + start("h2"); + _out << "Modules"; + end(); + start("dl"); + for(ModuleDescriptions::const_iterator i = _modules.begin(); i != _modules.end(); ++i) + { + start("dt", "Symbol"); + _out << i->first; + end(); + start("dd"); + _out << i->second; + end(); + } + end(); + + start("hr"); + end(); + printHeaderFooter(); + + closeDoc(); +} + +void +Slice::StartPageGenerator::generate(const ModulePtr& m) +{ + string name = toString(m, 0, false); + string comment = getComment(m, m, true, true); + _modules.push_back(make_pair(name, comment)); +} + +void +Slice::StartPageGenerator::printHeaderFooter() +{ + start("table", "HeaderFooter"); + start("tr"); + start("td align=\"left\""); + start("table"); + start("tr"); + start("td"); + string imageDir = getImageDir(); + if(imageDir.empty()) + { + _out << getLinkMarkup("_sindex.conf", "Index"); + } + else + { + string src = imageDir + "/index.gif"; + _out << getLinkMarkup("_sindex.conf", getImageMarkup(src, "Index Button")); + } + end(); // td + end(); // tr + end(); // table + end(); // td + + start("td align=\"center\""); + printSearch(); + end(); // td + + if(!imageDir.empty()) + { + start("td align=\"right\""); + start("table"); + start("tr"); + start("td"); + string logoURL = getLogoURL(); + if(!logoURL.empty()) + { + _out << getLinkMarkup(logoURL, getImageMarkup(imageDir + "/logo.gif", "Logo")); + } + else + { + _out << getImageMarkup(imageDir + "/logo.gif", "Logo"); + } + end(); // td + end(); // tr + end(); // table + end(); // td + } + + end(); // tr + end(); // table +} + +Slice::FileVisitor::FileVisitor(Files& files) + : _files(files) +{ +} + +bool +Slice::FileVisitor::visitUnitStart(const UnitPtr& u) +{ + return true; +} + +bool +Slice::FileVisitor::visitModuleStart(const ModulePtr& m) +{ + _files.insert(m->file()); + return true; +} + +bool +Slice::FileVisitor::visitExceptionStart(const ExceptionPtr& e) +{ + _files.insert(e->file()); + return false; +} + +bool +Slice::FileVisitor::visitClassDefStart(const ClassDefPtr& c) +{ + _files.insert(c->file()); + return false; +} + +void +Slice::FileVisitor::visitClassDecl(const ClassDeclPtr& c) +{ + _files.insert(c->file()); +} + +bool +Slice::FileVisitor::visitStructStart(const StructPtr& s) +{ + _files.insert(s->file()); + return false; +} + +void +Slice::FileVisitor::visitSequence(const SequencePtr& s) +{ + _files.insert(s->file()); +} + +void +Slice::FileVisitor::visitDictionary(const DictionaryPtr& d) +{ + _files.insert(d->file()); +} + +void +Slice::FileVisitor::visitEnum(const EnumPtr& e) +{ + _files.insert(e->file()); +} + +Slice::StartPageVisitor::StartPageVisitor(const Files& files) + : _spg(files) +{ +} + +bool +Slice::StartPageVisitor::visitUnitStart(const UnitPtr& unit) +{ + return true; +} + +bool +Slice::StartPageVisitor::visitModuleStart(const ModulePtr& m) +{ + _spg.generate(m); + return false; +} + +TOCGenerator::TOCGenerator(const Files& files, const string& header, const string& footer) + : GeneratorBase(_out, files) +{ + _footer = footer; + openDoc("_sindex.conf", "Slice API Index", header, footer); + + start("h1"); + _out << "Slice API Index"; + end(); + + //ExpandCollapseButtonTable not added; no Confluence markup for buttons +} + +void +TOCGenerator::generate(const ModulePtr& m) +{ + _modules.push_back(m); +} + +void +TOCGenerator::writeTOC() +{ + _modules.sort(); + + start("ul"); + _out.inc(); + for(ModuleList::const_iterator i = _modules.begin(); i != _modules.end(); ++i) + { + writeEntry(*i); + } + _out.dec(); + end();//ul + + _symbols.sort(); + _symbols.unique(); + + string f = getFooter(_footer); + closeDoc(getFooter(_footer)); +} + +const ContainedList& +TOCGenerator::symbols() const +{ + return _symbols; +} + + +void +TOCGenerator::writeEntry(const ContainedPtr& c) +{ + ContainedList cl; + + ModulePtr m = ModulePtr::dynamicCast(c); + if(m) + { + cl = m->contents(); + } + + EnumPtr en = EnumPtr::dynamicCast(c); + if(en) + { + EnumeratorList enumerators = en->getEnumerators(); + for(EnumeratorList::const_iterator i = enumerators.begin(); i != enumerators.end(); ++i) + { + cl.push_back(*i); + } + } + + StructPtr s = StructPtr::dynamicCast(c); + if(s) + { + DataMemberList dml = s->dataMembers(); + for(DataMemberList::const_iterator i = dml.begin(); i != dml.end(); ++i) + { + cl.push_back(*i); + } + } + + ExceptionPtr e = ExceptionPtr::dynamicCast(c); + if(e) + { + DataMemberList dml = e->dataMembers(); + for(DataMemberList::const_iterator i = dml.begin(); i != dml.end(); ++i) + { + cl.push_back(*i); + } + } + + ClassDefPtr cdef = ClassDefPtr::dynamicCast(c); + if(!cdef) + { + ClassDeclPtr cdec = ClassDeclPtr::dynamicCast(c); + if(cdec) + { + cdef = cdec->definition(); + } + } + + if(cdef) + { + DataMemberList dml = cdef->dataMembers(); + for(DataMemberList::const_iterator i = dml.begin(); i != dml.end(); ++i) + { + cl.push_back(*i); + } + OperationList ol = cdef->operations(); + for(OperationList::const_iterator j = ol.begin(); j != ol.end(); ++j) + { + cl.push_back(*j); + } + } + + start("li"); + if(!cl.empty()) + { + cl.sort(); + cl.unique(); + + _out << toString(c, 0, false, true, 0, true); + start("ul"); + for(ContainedList::const_iterator i = cl.begin(); i != cl.end(); ++i) + { + writeEntry(*i); + } + end(); + } + else + { + _out << toString(c, 0, false, true, 0, true); + } + if(ModulePtr::dynamicCast(c) || ExceptionPtr::dynamicCast(c) || ClassDefPtr::dynamicCast(c) || + StructPtr::dynamicCast(c) || EnumPtr::dynamicCast(c)) + { + _symbols.push_back(c); + } + else if(ClassDeclPtr::dynamicCast(c)) + { + ContainedPtr definition = ClassDeclPtr::dynamicCast(c)->definition(); + if(definition) + { + _symbols.push_back(definition); + } + } + end(); +} + +TOCVisitor::TOCVisitor(const Files& files, const string& header, const string& footer) + : _tg(files, header, footer) +{ +} + +bool +TOCVisitor::visitUnitStart(const UnitPtr&) +{ + return true; +} + +bool +TOCVisitor::visitModuleStart(const ModulePtr& m) +{ + _tg.generate(m); + return false; +} + +void +TOCVisitor::generate() +{ + _tg.writeTOC(); +} + +const ContainedList& +TOCVisitor::symbols() const +{ + return _tg.symbols(); +} + +Slice::ModuleGenerator::ModuleGenerator(Confluence::ConfluenceOutput& o, const Files& files) + : GeneratorBase(o, files) +{ +} + +void +Slice::ModuleGenerator::generate(const ModulePtr& m) +{ +#ifndef NDEBUG + int indent = _out.currIndent(); +#endif + + openDoc(m); + + printHeaderFooter(m); + start("hr"); + end(); + + start("h1", "Symbol"); + _out << m->scoped().substr(2); + end(); + + string metadata, deprecateReason; + if(m->findMetaData("deprecate", metadata)) + { + deprecateReason = "This module is deprecated."; + if(metadata.find("deprecate:") == 0 && metadata.size() > 10) + { + deprecateReason = metadata.substr(10); + } + } + start("h2"); + _out << "Overview"; + end(); + start("h3", "Synopsis"); + printMetaData(m); + _out << "module " << m->name(); + end(); + + printComment(m, m, deprecateReason, true); + + visitContainer(m); + + start("hr"); + end(); + printHeaderFooter(m); + + closeDoc(); + + assert(_out.currIndent() == indent); +} + +void +Slice::ModuleGenerator::visitContainer(const ContainerPtr& p) +{ +#ifndef NDEBUG + int indent = _out.currIndent(); +#endif + + ModuleList modules = p->modules(); + + if(!modules.empty()) + { + start("h2"); + _out << "Module Index"; + end(); + start("dl"); + for(ModuleList::const_iterator q = modules.begin(); q != modules.end(); ++q) + { + start("dt", "Symbol"); + _out << toString(*q, p, false, true); + end(); + start("dd"); + string metadata; + printSummary(*q, p, (*q)->findMetaData("deprecate", metadata), true); + end(); + } + end(); + } + + assert(_out.currIndent() == indent); + + ClassList classesAndInterfaces = p->classes(); + ClassList classes; + ClassList interfaces; + remove_copy_if(classesAndInterfaces.begin(), classesAndInterfaces.end(), back_inserter(classes), + ::IceUtil::constMemFun(&ClassDef::isInterface)); + remove_copy_if(classesAndInterfaces.begin(), classesAndInterfaces.end(), back_inserter(interfaces), + not1(::IceUtil::constMemFun(&ClassDef::isInterface))); + + if(!classes.empty()) + { + start("h2"); + _out << "Class Index"; + end(); + start("dl"); + for(ClassList::const_iterator q = classes.begin(); q != classes.end(); ++q) + { + start("dt", "Symbol"); + _out << toString(*q, p, false, true); + end(); + start("dd"); + string metadata; + printSummary(*q, p, (*q)->findMetaData("deprecate", metadata), true); + end(); + } + end(); + } + + assert(_out.currIndent() == indent); + + if(!interfaces.empty()) + { + start("h2"); + _out << "Interface Index"; + end(); + start("dl"); + for(ClassList::const_iterator q = interfaces.begin(); q != interfaces.end(); ++q) + { + start("dt", "Symbol"); + _out << toString(*q, p, false, true); + end(); + start("dd"); + string metadata; + printSummary(*q, p, (*q)->findMetaData("deprecate", metadata), true); + end(); + } + end(); + } + + assert(_out.currIndent() == indent); + + ExceptionList exceptions = p->exceptions(); + + if(!exceptions.empty()) + { + start("h2"); + _out << "Exception Index"; + end(); + start("dl"); + for(ExceptionList::const_iterator q = exceptions.begin(); q != exceptions.end(); ++q) + { + start("dt", "Symbol"); + _out << toString(*q, p, false, true); + end(); + start("dd"); + string metadata; + printSummary(*q, p, (*q)->findMetaData("deprecate", metadata), true); + end(); + } + end(); + } + + assert(_out.currIndent() == indent); + + StructList structs = p->structs(); + + if(!structs.empty()) + { + start("h2"); + _out << "Structure Index"; + end(); + start("dl"); + for(StructList::const_iterator q = structs.begin(); q != structs.end(); ++q) + { + start("dt", "Symbol"); + _out << toString(*q, p, false, true); + end(); + start("dd"); + string metadata; + printSummary(*q, p, (*q)->findMetaData("deprecate", metadata), true); + end(); + } + end(); + } + + assert(_out.currIndent() == indent); + + SequenceList sequences = p->sequences(); + + if(!sequences.empty()) + { + start("h2"); + _out << "Sequence Index"; + end(); + start("dl"); + for(SequenceList::const_iterator q = sequences.begin(); q != sequences.end(); ++q) + { + start("dt", "Symbol"); + _out << toString(*q, p, false, true); + end(); + start("dd"); + string metadata; + printSummary(*q, p, (*q)->findMetaData("deprecate", metadata), true); + end(); + } + end(); + } + + assert(_out.currIndent() == indent); + + DictionaryList dictionaries = p->dictionaries(); + + if(!dictionaries.empty()) + { + start("h2"); + _out << "Dictionary Index"; + end(); + start("dl"); + for(DictionaryList::const_iterator q = dictionaries.begin(); q != dictionaries.end(); ++q) + { + start("dt", "Symbol"); + _out << toString(*q, p, false, true); + end(); + start("dd"); + string metadata; + printSummary(*q, p, (*q)->findMetaData("deprecate", metadata), true); + end(); + } + end(); + } + + assert(_out.currIndent() == indent); + + ConstList consts = p->consts(); + + if(!consts.empty()) + { + start("h2"); + _out << "Constant Index"; + end(); + start("dl"); + for(ConstList::const_iterator q = consts.begin(); q != consts.end(); ++q) + { + start("dt", "Symbol"); + _out << toString(*q, p, false, true); + end(); + start("dd"); + string metadata; + printSummary(*q, p, (*q)->findMetaData("deprecate", metadata), true); + end(); + } + end(); + } + + assert(_out.currIndent() == indent); + + EnumList enums = p->enums(); + + if(!enums.empty()) + { + start("h2"); + _out << "Enumeration Index"; + end(); + start("dl"); + for(EnumList::const_iterator q = enums.begin(); q != enums.end(); ++q) + { + start("dt", "Symbol"); + _out << toString(*q, p, false, true); + end(); + start("dd"); + string metadata; + printSummary(*q, p, (*q)->findMetaData("deprecate", metadata), true); + end(); + } + end(); + } + + assert(_out.currIndent() == indent); + + if(!sequences.empty()) + { + start("h2"); + _out << "Sequences"; + end(); + for(SequenceList::const_iterator q = sequences.begin(); q != sequences.end(); ++q) + { + start("dl"); + start("dt"); + start("span", "Synopsis"); + printMetaData(*q); + if((*q)->isLocal()) + { + _out << "local "; + } + TypePtr type = (*q)->type(); + _out << "sequence<" << toString(type, p, false, true) << "> " << toString(*q, p); + end(); + end(); + + start("dd"); + string metadata, deprecateReason; + if((*q)->findMetaData("deprecate", metadata)) + { + deprecateReason = "This type is deprecated."; + if(metadata.find("deprecate:") == 0 && metadata.size() > 10) + { + deprecateReason = metadata.substr(10); + } + } + + printComment(*q, p, deprecateReason, true); + end(); + end(); + } + } + + if(!dictionaries.empty()) + { + start("h2"); + _out << "Dictionaries"; + end(); + for(DictionaryList::const_iterator q = dictionaries.begin(); q != dictionaries.end(); ++q) + { + start("dl"); + start("dt"); + start("span", "Synopsis"); + printMetaData(*q); + if((*q)->isLocal()) + { + _out << "local "; + } + TypePtr keyType = (*q)->keyType(); + TypePtr valueType = (*q)->valueType(); + _out << "dictionary<" << toString(keyType, p, false, true) << ", " + << toString(valueType, p, false, true) << "> " << toString(*q, p); + end(); + end(); + + start("dd"); + string metadata, deprecateReason; + if((*q)->findMetaData("deprecate", metadata)) + { + deprecateReason = "This type is deprecated."; + if(metadata.find("deprecate:") == 0 && metadata.size() > 10) + { + deprecateReason = metadata.substr(10); + } + } + + printComment(*q, p, deprecateReason, true); + end(); + end(); + } + } + + if(!consts.empty()) + { + start("h2"); + _out << "Constants"; + end(); + for(ConstList::const_iterator q = consts.begin(); q != consts.end(); ++q) + { + start("dl"); + start("dt"); + start("span", "Synopsis"); + _out << "const " << toString((*q)->type(), p, false, true) << " " << toString(*q, p) << " = "; + if(EnumPtr::dynamicCast((*q)->type())) + { + _out << toString((*q)->value(), p, false, true); + } + else + { + _out << (*q)->literal(); + } + _out << ";"; + end(); + end(); + + start("dd"); + string metadata, deprecateReason; + if((*q)->findMetaData("deprecate", metadata)) + { + deprecateReason = "This type is deprecated."; + if(metadata.find("deprecate:") == 0 && metadata.size() > 10) + { + deprecateReason = metadata.substr(10); + } + } + + printComment(*q, p, deprecateReason, true); + end(); + end(); + } + } +} + +Slice::ExceptionGenerator::ExceptionGenerator(Confluence::ConfluenceOutput& o, const Files& files) + : GeneratorBase(o, files) +{ +} + +void +Slice::ExceptionGenerator::generate(const ExceptionPtr& e) +{ +#ifndef NDEBUG + int indent = _out.currIndent(); +#endif + + openDoc(e); + + printHeaderFooter(e); + start("hr"); + end(); + + start("h1", "Symbol"); + _out << e->scoped().substr(2); + end(); + + string metadata, deprecateReason; + bool deprecatedException = e->findMetaData("deprecate", metadata); + if(deprecatedException) + { + deprecateReason = "This module is deprecated."; + if(metadata.find("deprecate:") == 0 && metadata.size() > 10) + { + deprecateReason = metadata.substr(10); + } + } + + start("h2"); + _out << "Overview"; + end(); + + start("h3", "Synopsis"); + printMetaData(e); + if(e->isLocal()) + { + _out << "local "; + } + _out << "exception " << e->name(); + ExceptionPtr base = e->base(); + if(base) + { + _out.inc(); + _out << nl << "extends "; + _out.inc(); + _out << nl << toString(base, e, false); + _out.dec(); + _out.dec(); + } + end(); + + printComment(e, e, deprecateReason); + + DataMemberList dataMembers = e->dataMembers(); + + if(_indexCount > 0 && dataMembers.size() >= _indexCount) + { + start("h2"); + _out << "Data Member Index"; + end(); + start("dl"); + for(DataMemberList::const_iterator q = dataMembers.begin(); q != dataMembers.end(); ++q) + { + start("dt", "Symbol"); + _out << toString(*q, e, false); + end(); + start("dd"); + string metadata; + printSummary(*q, e, (*q)->findMetaData("deprecate", metadata), false); + end(); + } + end(); + } + + if(!dataMembers.empty()) + { + start("h2"); + _out << "Data Members"; + end(); + start("dl"); + for(DataMemberList::const_iterator q = dataMembers.begin(); q != dataMembers.end(); ++q) + { + start("dt", "Symbol"); + printMetaData(*q); + TypePtr type = (*q)->type(); + _out << toString(type, e) << " " << toString(*q, e) << ";"; + end(); + + start("dd"); + string reason; + metadata.clear(); + if(deprecatedException || (*q)->findMetaData("deprecate", metadata)) + { + reason = "This member is deprecated."; + if(metadata.find("deprecate:") == 0 && metadata.size() > 10) + { + reason = metadata.substr(10); + } + } + + printComment(*q, e, reason); + end(); + } + end(); + } + + start("hr"); + end(); + printHeaderFooter(e); + + closeDoc(); + + assert(_out.currIndent() == indent); +} + +Slice::ClassGenerator::ClassGenerator(Confluence::ConfluenceOutput& o, const Files& files) + : GeneratorBase(o, files) +{ +} + +void +Slice::ClassGenerator::generate(const ClassDefPtr& c) +{ +#ifndef NDEBUG + int indent = _out.currIndent(); +#endif + + openDoc(c); + + printHeaderFooter(c); + start("hr"); + end(); + + start("h1", "Symbol"); + _out << c->scoped().substr(2); + end(); + + string metadata, deprecateReason; + bool deprecatedClass = c->findMetaData("deprecate", metadata); + if(deprecatedClass) + { + deprecateReason = "This "; + deprecateReason += c->isInterface() ? "interface" : "class"; + deprecateReason += " is deprecated."; + if(metadata.find("deprecate:") == 0 && metadata.size() > 10) + { + deprecateReason = metadata.substr(10); + } + } + + start("h2"); + _out << "Overview"; + end(); + start("h3", "Synopsis"); + printMetaData(c); + if(c->isLocal()) + { + _out << "local "; + } + _out << (c->isInterface() ? "interface" : "class" )<< " " << c->name(); + + ClassList bases = c->bases(); + if(!bases.empty() && !bases.front()->isInterface()) + { + _out << " extends " << toString(bases.front(), c, false); + bases.pop_front(); + } + + if(!bases.empty()) + { + _out << (c->isInterface() ? " extends " : " implements "); + ClassList::const_iterator q = bases.begin(); + while(q != bases.end()) + { + _out << toString(*q, c, false); + if(++q != bases.end()) + { + _out << ", "; + } + } + } + end(); + + printComment(c, c, deprecateReason); + + OperationList operations = c->operations(); + + if(_indexCount > 0 && operations.size() >= _indexCount) + { + start("h2"); + _out << "Operation Index"; + end(); + start("dl"); + for(OperationList::const_iterator q = operations.begin(); q != operations.end(); ++q) + { + start("dt", "Symbol"); + _out << toString(*q, c, false); + end(); + start("dd"); + string metadata; + printSummary(*q, c, (*q)->findMetaData("deprecate", metadata), false); + end(); + } + end(); + } + + DataMemberList dataMembers = c->dataMembers(); + + if(_indexCount > 0 && dataMembers.size() >= _indexCount) + { + start("h2"); + _out << "Data Member Index"; + end(); + start("dl"); + for(DataMemberList::const_iterator q = dataMembers.begin(); q != dataMembers.end(); ++q) + { + start("dt", "Symbol"); + _out << toString(*q, c, false); + end(); + start("dd"); + string metadata; + printSummary(*q, c, (*q)->findMetaData("deprecate", metadata), false); + end(); + } + end(); + } + + if(!operations.empty()) + { + start("h2"); + _out << "Operations"; + end(); + for(OperationList::const_iterator q = operations.begin(); q != operations.end(); ++q) + { + start("h3", "Synopsis"); + TypePtr returnType = (*q)->returnType(); + _out << (returnType ? toString(returnType, c, false) : string("void")) << " " + << toString(*q, c) << "("; + ParamDeclList params = (*q)->parameters(); + ParamDeclList::const_iterator r = params.begin(); + while(r != params.end()) + { + if((*r)->isOutParam()) + { + _out << "out "; + } + _out << toString((*r)->type(), ContainedPtr::dynamicCast(*q)->container(), false) + << " " << (*r)->name(); + if(++r != params.end()) + { + _out << ", "; + } + } + _out << ")"; + ExceptionList throws = (*q)->throws(); + if(!throws.empty()) + { + _out << " throws "; + ExceptionList::const_iterator t = throws.begin(); + while(t != throws.end()) + { + _out << toString(*t, c, false); + if(++t != throws.end()) + { + _out << ", "; + } + } + } + end(); + + string reason; + metadata.clear(); + if(deprecatedClass || (*q)->findMetaData("deprecate", metadata)) + { + reason = "This operation is deprecated."; + if(metadata.find("deprecate:") == 0 && metadata.size() > 10) + { + reason = metadata.substr(10); + } + } + printComment(*q, c, reason); + } + } + + if(!dataMembers.empty()) + { + start("h2"); + _out << "Data Members"; + end(); + for(DataMemberList::const_iterator q = dataMembers.begin(); q != dataMembers.end(); ++q) + { + start("h3", "Synopsis"); + printMetaData(*q); + TypePtr type = (*q)->type(); + _out << toString(type, c, false) << " " << toString(*q, c) << ";"; + end(); + + string reason; + metadata.clear(); + if(deprecatedClass || (*q)->findMetaData("deprecate", metadata)) + { + reason = "This member is deprecated."; + if(metadata.find("deprecate:") == 0 && metadata.size() > 10) + { + reason = metadata.substr(10); + } + } + + printComment(*q, c, reason); + } + } + + start("hr"); + end(); + printHeaderFooter(c); + + closeDoc(); + + assert(_out.currIndent() == indent); +} + +Slice::StructGenerator::StructGenerator(Confluence::ConfluenceOutput& o, const Files& files) + : GeneratorBase(o, files) +{ +} + +void +Slice::StructGenerator::generate(const StructPtr& s) +{ +#ifndef NDEBUG + int indent = _out.currIndent(); +#endif + + openDoc(s); + + printHeaderFooter(s); + start("hr"); + end(); + + start("h1", "Symbol"); + _out << s->scoped().substr(2); + end(); + + string metadata, deprecateReason; + bool deprecatedException = s->findMetaData("deprecate", metadata); + if(deprecatedException) + { + deprecateReason = "This module is deprecated."; + if(metadata.find("deprecate:") == 0 && metadata.size() > 10) + { + deprecateReason = metadata.substr(10); + } + } + + start("h2"); + _out << "Overview"; + end(); + + start("h3", "Synopsis"); + printMetaData(s); + if(s->isLocal()) + { + _out << "local "; + } + _out << "struct " << s->name(); + end(); + + printComment(s, s, deprecateReason); + + DataMemberList dataMembers = s->dataMembers(); + + if(_indexCount > 0 && dataMembers.size() >= _indexCount) + { + start("h2"); + _out << "Data Member Index"; + end(); + start("dl"); + for(DataMemberList::const_iterator q = dataMembers.begin(); q != dataMembers.end(); ++q) + { + start("dt", "Symbol"); + _out << toString(*q, s, false); + end(); + start("dd"); + string metadata; + printSummary(*q, s, (*q)->findMetaData("deprecate", metadata), false); + end(); + } + end(); + } + + if(!dataMembers.empty()) + { + start("h2"); + _out << "Data Members"; + end(); + start("dl"); + for(DataMemberList::const_iterator q = dataMembers.begin(); q != dataMembers.end(); ++q) + { + start("dt", "Symbol"); + printMetaData(*q); + TypePtr type = (*q)->type(); + _out << toString(type, s, false) << " " << toString(*q, s) << ";"; + end(); + + start("dd"); + string reason; + metadata.clear(); + if(deprecatedException || (*q)->findMetaData("deprecate", metadata)) + { + reason = "This member is deprecated."; + if(metadata.find("deprecate:") == 0 && metadata.size() > 10) + { + reason = metadata.substr(10); + } + } + + printComment(*q, s, reason); + end(); + } + end(); + } + + start("hr"); + end(); + printHeaderFooter(s); + + closeDoc(); + + assert(_out.currIndent() == indent); +} + +Slice::EnumGenerator::EnumGenerator(Confluence::ConfluenceOutput& o, const Files& files) + : GeneratorBase(o, files) +{ +} + +void +Slice::EnumGenerator::generate(const EnumPtr& e) +{ +#ifndef NDEBUG + int indent = _out.currIndent(); +#endif + + openDoc(e); + + printHeaderFooter(e); + start("hr"); + end(); + + start("h1", "Symbol"); + _out << e->scoped().substr(2); + end(); + + string metadata, deprecateReason; + bool deprecatedException = e->findMetaData("deprecate", metadata); + if(deprecatedException) + { + deprecateReason = "This enumeration is deprecated."; + if(metadata.find("deprecate:") == 0 && metadata.size() > 10) + { + deprecateReason = metadata.substr(10); + } + } + + start("h2"); + _out << "Overview"; + end(); + + start("h3", "Synopsis"); + printMetaData(e); + if(e->isLocal()) + { + _out << "local "; + } + _out << "enum " << e->name(); + end(); + + printComment(e, e->container(), deprecateReason, false); + + EnumeratorList enumerators = e->getEnumerators(); + if(!enumerators.empty()) + { + start("h2"); + _out << "Enumerators"; + end(); + start("dl"); + for(EnumeratorList::const_iterator q = enumerators.begin(); q != enumerators.end(); ++q) + { + start("dt", "Symbol"); + _out << (*q)->name(); + end(); + + start("dd"); + string reason; + // + // Enumerators do not support metadata. + // + printComment(*q, e->container(), reason, false); + end(); + } + end(); + } + + closeDoc(); + + start("hr"); + end(); + printHeaderFooter(e); + + assert(_out.currIndent() == indent); +} + +Slice::PageVisitor::PageVisitor(const Files& files) + : _files(files) +{ +} + +bool +Slice::PageVisitor::visitUnitStart(const UnitPtr& unit) +{ + return true; +} + +bool +Slice::PageVisitor::visitModuleStart(const ModulePtr& m) +{ + Confluence::ConfluenceOutput O; + ModuleGenerator mg(O, _files); + mg.generate(m); + return true; +} + +bool +Slice::PageVisitor::visitExceptionStart(const ExceptionPtr& e) +{ + Confluence::ConfluenceOutput O; + ExceptionGenerator eg(O, _files); + eg.generate(e); + return true; +} + +bool +Slice::PageVisitor::visitClassDefStart(const ClassDefPtr& c) +{ + Confluence::ConfluenceOutput O; + ClassGenerator cg(O, _files); + cg.generate(c); + return true; +} + +bool +Slice::PageVisitor::visitStructStart(const StructPtr& s) +{ + Confluence::ConfluenceOutput O; + StructGenerator sg(O, _files); + sg.generate(s); + return true; +} + +void +Slice::PageVisitor::visitEnum(const EnumPtr& e) +{ + Confluence::ConfluenceOutput O; + EnumGenerator eg(O, _files); + eg.generate(e); +} diff --git a/cpp/src/slice2confluence/Gen.h b/cpp/src/slice2confluence/Gen.h new file mode 100644 index 00000000000..6e5bb970649 --- /dev/null +++ b/cpp/src/slice2confluence/Gen.h @@ -0,0 +1,277 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2011 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +#ifndef GEN_H +#define GEN_H + +#include <Slice/Parser.h> +#include <IceUtil/OutputUtil.h> +#include <ConfluenceOutput.h> + +namespace Slice +{ + +void generate(const UnitPtr&, const ::std::string&, const ::std::string&, const ::std::string&, const std::string&, + const ::std::string&, const ::std::string&, const ::std::string&, const ::std::string&, + unsigned, unsigned); + +typedef ::std::set< ::std::string> Files; + +class GeneratorBase : private ::IceUtil::noncopyable +{ +public: + + static void setOutputDir(const ::std::string&); + static void setHeader(const ::std::string&); + static void setFooter(const ::std::string&); + static void setImageDir(const ::std::string&); + static void setLogoURL(const ::std::string&); + static void setSearchAction(const ::std::string&); + static void setIndexCount(int); + static void warnSummary(int); + static void setSymbols(const ContainedList&); + + void closeStream(); + +protected: + + GeneratorBase(Confluence::ConfluenceOutput&, const Files&); + virtual ~GeneratorBase() = 0; + + void openDoc(const ::std::string&, const std::string&, const std::string& = "", const std::string& = ""); + void openDoc(const ContainedPtr&); + void closeDoc(const std::string& = ""); + + void start(const ::std::string&, const ::std::string& = ::std::string()); + void end(); + + std::string getImageMarkup(const std::string&, const std::string& = ""); + std::string getLinkMarkup(const std::string&, const std::string& = "", const std::string& = "", const std::string& = ""); + + void removeNewlines(std::string); + + void printComment(const ContainedPtr&, const ContainerPtr&, const ::std::string&, bool = false); + void printMetaData(const ContainedPtr&); + void printSummary(const ContainedPtr&, const ContainerPtr&, bool, bool); + + void printHeaderFooter(const ContainedPtr&); + void printSearch(); + void printLogo(const ContainedPtr&, const ContainerPtr&, bool); + + ::std::string toString(const SyntaxTreeBasePtr&, const ContainerPtr&, bool = true, bool = false, + size_t* = 0, bool = false); + ::std::string toString(const ::std::string&, const ContainerPtr&, bool = true, bool = false, size_t* = 0); + ::std::string getComment(const ContainedPtr&, const ContainerPtr&, bool, bool = false); + + static ::std::string getAnchor(const SyntaxTreeBasePtr&); + static StringList getTarget(const SyntaxTreeBasePtr&); + static ::std::string getLinkPath(const SyntaxTreeBasePtr&, const ContainerPtr&, bool, bool = false); + + static ::std::string getImageDir(); + static ::std::string getLogoURL(); + + static ::std::string getFooter(const ::std::string&); + + Confluence::ConfluenceOutput& _out; + + static size_t _indexCount; + static size_t _warnSummary; + +private: + + void openStream(const ::std::string&); + + static ::std::string containedToId(const ContainedPtr&, bool); + static StringList getTagged(const ::std::string&, ::std::string&); + static ::std::string getScopedMinimized(const ContainedPtr&, const ContainerPtr&, bool = false); + static StringList getContained(const SyntaxTreeBasePtr&); + static StringList getContainer(const SyntaxTreeBasePtr&); + static StringList toStringList(const ContainedPtr&); + static void makeDir(const ::std::string&); + static ::std::string readFile(const ::std::string&); + static void readFile(const ::std::string&, ::std::string&, ::std::string&); + static void getHeaders(const ::std::string&, ::std::string&, ::std::string&); + + ::std::string _indexFooter; + const Files _files; + + static ::std::string _dir; + static ::std::string _header1; + static ::std::string _header2; + static ::std::string _footer; + static ::std::string _imageDir; + static ::std::string _logoURL; + static ::std::string _searchAction; + static ContainedList _symbols; + + // + // TODO: + // Members below exist to emit warnings for old-style javadoc comments (using [...] instead of {@link ...}), + // and to emit warnings for old-style scoped names (X::Y::Z instead of X.Y#Z). + // Once we remove support for the old style comments, we also need to remove these members. + // + ::std::set< ::std::string> _warnOldCommentFiles; + ::std::string toSliceID(const ::std::string&, const ::std::string&); + void warnOldStyleIdent(const ::std::string&, const ::std::string&); +}; + +class StartPageGenerator : private GeneratorBase +{ +public: + + StartPageGenerator(const Files&); + ~StartPageGenerator(); + void generate(const ModulePtr&); + +private: + + using GeneratorBase::printHeaderFooter; + void printHeaderFooter(); + + typedef ::std::pair< ::std::string, ::std::string> StringPair; + typedef ::std::vector<StringPair> ModuleDescriptions; + ModuleDescriptions _modules; + Confluence::ConfluenceOutput _out; +}; + +class FileVisitor : private ::IceUtil::noncopyable, public ParserVisitor +{ +public: + + FileVisitor(Files&); + + virtual bool visitUnitStart(const UnitPtr&); + virtual bool visitModuleStart(const ModulePtr&); + virtual bool visitExceptionStart(const ExceptionPtr&); + virtual bool visitClassDefStart(const ClassDefPtr&); + virtual void visitClassDecl(const ClassDeclPtr&); + virtual bool visitStructStart(const StructPtr&); + virtual void visitSequence(const SequencePtr&); + virtual void visitDictionary(const DictionaryPtr&); + virtual void visitEnum(const EnumPtr&); + +private: + + Files& _files; +}; + +class StartPageVisitor : private ::IceUtil::noncopyable, public ParserVisitor +{ +public: + + StartPageVisitor(const Files&); + + virtual bool visitUnitStart(const UnitPtr&); + virtual bool visitModuleStart(const ModulePtr&); + +private: + + StartPageGenerator _spg; +}; + +class TOCGenerator : private GeneratorBase +{ +public: + + TOCGenerator(const Files&, const ::std::string&, const ::std::string&); + void generate(const ModulePtr&); + void writeTOC(); + const ContainedList& symbols() const; + +private: + + void writeEntry(const ContainedPtr&); + + ::std::string _footer; + ModuleList _modules; + ContainedList _symbols; + Confluence::ConfluenceOutput _out; +}; + +class TOCVisitor : private ::IceUtil::noncopyable, public ParserVisitor +{ +public: + + TOCVisitor(const Files&, const ::std::string&, const ::std::string&); + + virtual bool visitUnitStart(const UnitPtr&); + virtual bool visitModuleStart(const ModulePtr&); + void generate(); + const ContainedList& symbols() const; + +private: + + TOCGenerator _tg; +}; + +class ModuleGenerator : private GeneratorBase +{ +public: + + ModuleGenerator(Confluence::ConfluenceOutput&, const Files&); + void generate(const ModulePtr&); + +private: + + virtual void visitContainer(const ContainerPtr&); +}; + +class ExceptionGenerator : private GeneratorBase +{ +public: + + ExceptionGenerator(Confluence::ConfluenceOutput&, const Files&); + void generate(const ExceptionPtr&); +}; + +class ClassGenerator : private GeneratorBase +{ +public: + + ClassGenerator(Confluence::ConfluenceOutput&, const Files&); + void generate(const ClassDefPtr&); +}; + +class StructGenerator : private GeneratorBase +{ +public: + + StructGenerator(Confluence::ConfluenceOutput&, const Files&); + void generate(const StructPtr&); +}; + +class EnumGenerator : private GeneratorBase +{ +public: + + EnumGenerator(Confluence::ConfluenceOutput&, const Files&); + void generate(const EnumPtr&); +}; + +class PageVisitor : private ::IceUtil::noncopyable, public ParserVisitor +{ +public: + + PageVisitor(const Files&); + + virtual bool visitUnitStart(const UnitPtr&); + virtual bool visitModuleStart(const ModulePtr&); + virtual bool visitExceptionStart(const ExceptionPtr&); + virtual bool visitClassDefStart(const ClassDefPtr&); + virtual bool visitStructStart(const StructPtr&); + virtual void visitEnum(const EnumPtr&); + +private: + + const Files& _files; +}; + +} + +#endif diff --git a/cpp/src/slice2confluence/Main.cpp b/cpp/src/slice2confluence/Main.cpp new file mode 100755 index 00000000000..54749aa53be --- /dev/null +++ b/cpp/src/slice2confluence/Main.cpp @@ -0,0 +1,338 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2011 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +#include <IceUtil/Options.h> +#include <IceUtil/CtrlCHandler.h> +#include <IceUtil/Mutex.h> +#include <IceUtil/MutexPtrLock.h> +#include <Slice/Preprocessor.h> +#include <Slice/FileTracker.h> +#include <Slice/Util.h> +#include <Gen.h> +#include <stdlib.h> + +using namespace std; +using namespace Slice; +using namespace IceUtil; + +namespace +{ + +IceUtil::Mutex* mutex = 0; +bool interrupted = false; + +class Init +{ +public: + + Init() + { + mutex = new IceUtil::Mutex; + } + + ~Init() + { + delete mutex; + mutex = 0; + } +}; + +Init init; + +} + +void +interruptedCallback(int signal) +{ + IceUtilInternal::MutexPtrLock<IceUtil::Mutex> sync(mutex); + + interrupted = true; +} + +void +usage(const char* n) +{ + getErrorStream() << "Usage: " << n << " [options] slice-files...\n"; + getErrorStream() << + "Options:\n" + "-h, --help Show this message.\n" + "-v, --version Display the Ice version.\n" + "-DNAME Define NAME as 1.\n" + "-DNAME=DEF Define NAME as DEF.\n" + "-UNAME Remove any definition for NAME.\n" + "-IDIR Put DIR in the include file search path.\n" + "-E Print preprocessor output on stdout.\n" + "--output-dir DIR Create files in the directory DIR.\n" + "--hdr FILE Use the contents of FILE as the header.\n" + "--ftr FILe Use the contents of FILE as the footer.\n" + "--indexhdr FILE Use the contents of FILE as the header of the index/toc page (default=--hdr).\n" + "--indexftr FILE Use the contents of FILE as the footer of the index/toc page (default=--ftr).\n" + "--image-dir DIR Directory containing images for style sheets.\n" + "--logo-url URL Link to URL from logo image (requires --image-dir).\n" + "--search ACTION Generate search box with specified ACTION.\n" + "--index NUM Generate subindex if it has at least NUM entries (0 for no index, default=1).\n" + "--summary NUM Print a warning if a summary sentence exceeds NUM characters.\n" + "-d, --debug Print debug messages.\n" + "--ice Permit `Ice' prefix (for building Ice source code only).\n" + "--ice Permit underscores in Slice identifiers.\n" + ; +} + +int +compile(int argc, char* argv[]) +{ + IceUtilInternal::Options opts; + opts.addOpt("h", "help"); + opts.addOpt("v", "version"); + opts.addOpt("D", "", IceUtilInternal::Options::NeedArg, "", IceUtilInternal::Options::Repeat); + opts.addOpt("U", "", IceUtilInternal::Options::NeedArg, "", IceUtilInternal::Options::Repeat); + opts.addOpt("I", "", IceUtilInternal::Options::NeedArg, "", IceUtilInternal::Options::Repeat); + opts.addOpt("E"); + opts.addOpt("", "output-dir", IceUtilInternal::Options::NeedArg, "."); + opts.addOpt("", "hdr", IceUtilInternal::Options::NeedArg); + opts.addOpt("", "ftr", IceUtilInternal::Options::NeedArg); + opts.addOpt("", "indexhdr", IceUtilInternal::Options::NeedArg); + opts.addOpt("", "indexftr", IceUtilInternal::Options::NeedArg); + opts.addOpt("", "index", IceUtilInternal::Options::NeedArg, "1"); + opts.addOpt("", "image-dir", IceUtilInternal::Options::NeedArg); + opts.addOpt("", "logo-url", IceUtilInternal::Options::NeedArg); + opts.addOpt("", "search", IceUtilInternal::Options::NeedArg); + opts.addOpt("", "summary", IceUtilInternal::Options::NeedArg, "0"); + opts.addOpt("d", "debug"); + opts.addOpt("", "ice"); + opts.addOpt("", "underscore"); + + vector<string> args; + try + { + args = opts.parse(argc, (const char**)argv); + } + catch(const IceUtilInternal::BadOptException& e) + { + getErrorStream() << argv[0] << ": error: " << e.reason << endl; + usage(argv[0]); + return EXIT_FAILURE; + } + + if(opts.isSet("help")) + { + usage(argv[0]); + return EXIT_SUCCESS; + } + + if(opts.isSet("version")) + { + getErrorStream() << ICE_STRING_VERSION << endl; + return EXIT_SUCCESS; + } + + vector<string> cppArgs; + vector<string> optargs = opts.argVec("D"); + vector<string>::const_iterator i; + for(i = optargs.begin(); i != optargs.end(); ++i) + { + cppArgs.push_back("-D" + *i); + } + + optargs = opts.argVec("U"); + for(i = optargs.begin(); i != optargs.end(); ++i) + { + cppArgs.push_back("-U" + *i); + } + + optargs = opts.argVec("I"); + for(i = optargs.begin(); i != optargs.end(); ++i) + { + cppArgs.push_back("-I" + Preprocessor::normalizeIncludePath(*i)); + } + + bool preprocess = opts.isSet("E"); + + string output = opts.optArg("output-dir"); + + string header = opts.optArg("hdr"); + + string footer = opts.optArg("ftr"); + + string indexHeader = opts.optArg("indexhdr"); + + string indexFooter = opts.optArg("indexftr"); + + string ind = opts.optArg("index"); + unsigned indexCount = 0; + if(!ind.empty()) + { + istringstream s(ind); + s >> indexCount; + if(!s) + { + getErrorStream() << argv[0] << ": error: the --index operation requires a positive integer argument" + << endl; + usage(argv[0]); + return EXIT_FAILURE; + } + } + + string imageDir = opts.optArg("image-dir"); + + string logoURL = opts.optArg("logo-url"); + + string searchAction = opts.optArg("search"); + + string warnSummary = opts.optArg("summary"); + unsigned summaryCount = 0; + if(!warnSummary.empty()) + { + istringstream s(warnSummary); + s >> summaryCount; + if(!s) + { + getErrorStream() << argv[0] << ": error: the --summary operation requires a positive integer argument" + << endl; + usage(argv[0]); + return EXIT_FAILURE; + } + } + + bool debug = opts.isSet("debug"); + + bool ice = opts.isSet("ice"); + + bool underscore = opts.isSet("underscore"); + + if(args.empty()) + { + getErrorStream() << argv[0] << ": error: no input file" << endl; + usage(argv[0]); + return EXIT_FAILURE; + } + + UnitPtr p = Unit::createUnit(true, false, ice, underscore); + + int status = EXIT_SUCCESS; + + IceUtil::CtrlCHandler ctrlCHandler; + ctrlCHandler.setCallback(interruptedCallback); + + for(vector<string>::size_type idx = 0; idx < args.size(); ++idx) + { + PreprocessorPtr icecpp = Preprocessor::create(argv[0], args[idx], cppArgs); + FILE* cppHandle = icecpp->preprocess(true); + + if(cppHandle == 0) + { + p->destroy(); + return EXIT_FAILURE; + } + if(preprocess) + { + char buf[4096]; + while(fgets(buf, static_cast<int>(sizeof(buf)), cppHandle) != NULL) + { + if(fputs(buf, stdout) == EOF) + { + p->destroy(); + return EXIT_FAILURE; + } + } + } + else + { + status = p->parse(args[idx], cppHandle, debug); + } + + if(!icecpp->close()) + { + p->destroy(); + return EXIT_FAILURE; + } + + { + IceUtilInternal::MutexPtrLock<IceUtil::Mutex> sync(mutex); + + if(interrupted) + { + return EXIT_FAILURE; + } + } + } + + if(status == EXIT_SUCCESS && !preprocess) + { + try + { + Slice::generate(p, output, header, footer, indexHeader, indexFooter, imageDir, logoURL, + searchAction, indexCount, summaryCount); + } + catch(const Slice::FileException& ex) + { + // If a file could not be created, then cleanup any + // created files. + FileTracker::instance()->cleanup(); + p->destroy(); + getErrorStream() << argv[0] << ": error: " << ex.reason() << endl; + return EXIT_FAILURE; + } + catch(const string& err) + { + FileTracker::instance()->cleanup(); + getErrorStream() << argv[0] << ": error: " << err << endl; + status = EXIT_FAILURE; + } + catch(const char* err) + { + FileTracker::instance()->cleanup(); + getErrorStream() << argv[0] << ": error: " << err << endl; + status = EXIT_FAILURE; + } + } + + p->destroy(); + + { + IceUtilInternal::MutexPtrLock<IceUtil::Mutex> sync(mutex); + + if(interrupted) + { + FileTracker::instance()->cleanup(); + return EXIT_FAILURE; + } + } + + return status; +} + +int +main(int argc, char* argv[]) +{ + try + { + return compile(argc, argv); + } + catch(const std::exception& ex) + { + getErrorStream() << argv[0] << ": error:" << ex.what() << endl; + return EXIT_FAILURE; + } + catch(const std::string& msg) + { + getErrorStream() << argv[0] << ": error:" << msg << endl; + return EXIT_FAILURE; + } + catch(const char* msg) + { + getErrorStream() << argv[0] << ": error:" << msg << endl; + return EXIT_FAILURE; + } + catch(...) + { + getErrorStream() << argv[0] << ": error:" << "unknown exception" << endl; + return EXIT_FAILURE; + } +} diff --git a/cpp/src/slice2confluence/Makefile b/cpp/src/slice2confluence/Makefile new file mode 100644 index 00000000000..aa78fc974b7 --- /dev/null +++ b/cpp/src/slice2confluence/Makefile @@ -0,0 +1,33 @@ +# ********************************************************************** +# +# Copyright (c) 2003-2011 ZeroC, Inc. All rights reserved. +# +# This copy of Ice is licensed to you under the terms described in the +# ICE_LICENSE file included in this distribution. +# +# ********************************************************************** + +top_srcdir = ../.. + +NAME = $(top_srcdir)/bin/slice2confluence + +TARGETS = $(NAME) + +OBJS = Gen.o \ + ConfluenceOutput.o \ + Main.o + +SRCS = $(OBJS:.o=.cpp) + +include $(top_srcdir)/config/Make.rules + +CPPFLAGS := -I. $(CPPFLAGS) + +$(NAME): $(OBJS) + rm -f $@ + $(CXX) $(LDFLAGS) -o $@ $(OBJS) -lSlice $(BASELIBS) $(MCPP_RPATH_LINK) + +install:: all + $(call installprogram,$(NAME),$(install_bindir)) + +include .depend diff --git a/cpp/src/slice2confluence/Makefile.mak b/cpp/src/slice2confluence/Makefile.mak new file mode 100644 index 00000000000..2ace1809b29 --- /dev/null +++ b/cpp/src/slice2confluence/Makefile.mak @@ -0,0 +1,53 @@ +# **********************************************************************
+#
+# Copyright (c) 2003-2011 ZeroC, Inc. All rights reserved.
+#
+# This copy of Ice is licensed to you under the terms described in the
+# ICE_LICENSE file included in this distribution.
+#
+# **********************************************************************
+
+top_srcdir = ..\..
+
+NAME = $(top_srcdir)\bin\slice2confluence.exe
+
+TARGETS = $(NAME)
+
+OBJS = Gen.obj \
+ ConfluenceOutput.obj \
+ Main.obj
+
+SRCS = $(OBJS:.obj=.cpp)
+
+!include $(top_srcdir)/config/Make.rules.mak
+
+CPPFLAGS = -I. $(CPPFLAGS) -DWIN32_LEAN_AND_MEAN
+
+!if "$(GENERATE_PDB)" == "yes"
+PDBFLAGS = /pdb:$(NAME:.exe=.pdb)
+!endif
+
+RES_FILE = Slice2Confluence.res
+
+$(NAME): $(OBJS) Slice2Confluence.res
+ $(LINK) $(LD_EXEFLAGS) $(PDBFLAGS) $(OBJS) $(SETARGV) $(PREOUT)$@ $(PRELIBS)slice$(LIBSUFFIX).lib \
+ $(BASELIBS) $(RES_FILE)
+ @if exist $@.manifest echo ^ ^ ^ Embedding manifest using $(MT) && \
+ $(MT) -nologo -manifest $@.manifest -outputresource:$@;#1 && del /q $@.manifest
+
+clean::
+ del /q $(NAME:.exe=.*)
+ del /q Slice2Confluence.res
+
+install:: all
+ copy $(NAME) "$(install_bindir)"
+
+
+!if "$(GENERATE_PDB)" == "yes"
+
+install:: all
+ copy $(NAME:.exe=.pdb) "$(install_bindir)"
+
+!endif
+
+!include .depend.mak
diff --git a/cpp/src/slice2confluence/Slice2Confluence.rc b/cpp/src/slice2confluence/Slice2Confluence.rc new file mode 100644 index 00000000000..89be828530b --- /dev/null +++ b/cpp/src/slice2confluence/Slice2Confluence.rc @@ -0,0 +1,34 @@ +#include "winver.h"
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 3,4,2,0
+ PRODUCTVERSION 3,4,2,0
+ FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
+#ifdef _DEBUG
+ FILEFLAGS VS_FF_DEBUG
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x4L
+ FILETYPE VFT_APP
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904e4"
+ BEGIN
+ VALUE "CompanyName", "ZeroC, Inc.\0"
+ VALUE "FileDescription", "Slice To Confluence Markup Translator\0"
+ VALUE "FileVersion", "3.4.2\0"
+ VALUE "InternalName", "slice2confluence\0"
+ VALUE "LegalCopyright", "Copyright (c) 2003-2011 ZeroC, Inc. All rights reserved.\0"
+ VALUE "OriginalFilename", "slice2confluence.exe\0"
+ VALUE "ProductName", "Ice\0"
+ VALUE "ProductVersion", "3.4.2\0"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1252
+ END
+END
|