summaryrefslogtreecommitdiff
path: root/cpp/src/slice2confluence
diff options
context:
space:
mode:
authorShawn Hussey <shawn@zeroc.com>2011-08-16 13:39:10 -0230
committerShawn Hussey <shawn@zeroc.com>2011-08-16 13:39:10 -0230
commitb1e407d3c7ca1f08d5e822226a17ba381f9003fc (patch)
tree0d5aca236c4d567736860500100ebd7dd28c40fc /cpp/src/slice2confluence
parentAdded support for replica & name cert CN verification (diff)
downloadice-b1e407d3c7ca1f08d5e822226a17ba381f9003fc.tar.bz2
ice-b1e407d3c7ca1f08d5e822226a17ba381f9003fc.tar.xz
ice-b1e407d3c7ca1f08d5e822226a17ba381f9003fc.zip
Initial commit of slice2confluence.
Diffstat (limited to 'cpp/src/slice2confluence')
-rw-r--r--cpp/src/slice2confluence/.depend2
-rw-r--r--cpp/src/slice2confluence/.depend.mak2
-rw-r--r--cpp/src/slice2confluence/ConfluenceOutput.cpp452
-rw-r--r--cpp/src/slice2confluence/ConfluenceOutput.h170
-rwxr-xr-xcpp/src/slice2confluence/Gen.cpp2959
-rw-r--r--cpp/src/slice2confluence/Gen.h277
-rwxr-xr-xcpp/src/slice2confluence/Main.cpp338
-rw-r--r--cpp/src/slice2confluence/Makefile33
-rw-r--r--cpp/src/slice2confluence/Makefile.mak53
-rw-r--r--cpp/src/slice2confluence/Slice2Confluence.rc34
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 &amp;
+ //
+ 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 = "&gt;";
+ break;
+
+ case '<':
+ replace = "&lt;";
+ break;
+
+ case '\'':
+ replace = "&apos;";
+ break;
+
+ case '"':
+ replace = "&quot;";
+ 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&lt;" << toString(type, p, false, true) << "&gt; " << 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&lt;" << toString(keyType, p, false, true) << ", "
+ << toString(valueType, p, false, true) << "&gt; " << 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