summaryrefslogtreecommitdiff
path: root/cpp/src
diff options
context:
space:
mode:
authorMichi Henning <michi@zeroc.com>2006-11-22 08:35:01 +0000
committerMichi Henning <michi@zeroc.com>2006-11-22 08:35:01 +0000
commit9073302574725750291e339e0bb4a60b1475c114 (patch)
treee2cf193e77df8aa481b5f2683802e56b25113787 /cpp/src
parentchange .dll extension to .pyd to support Python 2.5 on Windows (diff)
downloadice-9073302574725750291e339e0bb4a60b1475c114.tar.bz2
ice-9073302574725750291e339e0bb4a60b1475c114.tar.xz
ice-9073302574725750291e339e0bb4a60b1475c114.zip
Intermediate check-in for slice2html.
Diffstat (limited to 'cpp/src')
-rw-r--r--cpp/src/IceUtil/OutputUtil.cpp26
-rw-r--r--cpp/src/Slice/JavaUtil.cpp4
-rw-r--r--cpp/src/slice2html/.depend2
-rw-r--r--cpp/src/slice2html/Gen.cpp1955
-rw-r--r--cpp/src/slice2html/Gen.h162
-rw-r--r--cpp/src/slice2html/Main.cpp193
-rw-r--r--cpp/src/slice2html/Makefile32
-rw-r--r--cpp/src/slice2html/Makefile.mak54
8 files changed, 2416 insertions, 12 deletions
diff --git a/cpp/src/IceUtil/OutputUtil.cpp b/cpp/src/IceUtil/OutputUtil.cpp
index b12cdc5871d..2d674303f5d 100644
--- a/cpp/src/IceUtil/OutputUtil.cpp
+++ b/cpp/src/IceUtil/OutputUtil.cpp
@@ -132,6 +132,12 @@ IceUtil::OutputBase::restoreIndent()
_indentSave.pop();
}
+int
+IceUtil::OutputBase::currIndent()
+{
+ return _indent;
+}
+
void
IceUtil::OutputBase::setIndent(int indentSize)
{
@@ -145,7 +151,7 @@ IceUtil::OutputBase::setUseTab(bool useTab)
}
void
-IceUtil::OutputBase::nl()
+IceUtil::OutputBase::newline()
{
_out << '\n';
_pos = 0;
@@ -183,7 +189,7 @@ IceUtil::OutputBase::nl()
}
void
-IceUtil::OutputBase::sp()
+IceUtil::OutputBase::separator()
{
if(_separator)
{
@@ -255,7 +261,7 @@ IceUtil::Output::sb()
{
if(_blockStart.length())
{
- nl();
+ newline();
_out << _blockStart;
}
++_pos;
@@ -269,7 +275,7 @@ IceUtil::Output::eb()
dec();
if(_blockEnd.length())
{
- nl();
+ newline();
_out << _blockEnd;
}
--_pos;
@@ -357,20 +363,20 @@ IceUtil::XMLOutput::print(const char* s)
}
void
-IceUtil::XMLOutput::nl()
+IceUtil::XMLOutput::newline()
{
if(_se)
{
_se = false;
_out << '>';
}
- OutputBase::nl();
+ OutputBase::newline();
}
void
-IceUtil::XMLOutput::se(const string& element)
+IceUtil::XMLOutput::startElement(const string& element)
{
- nl();
+ newline();
//
// If we're not in SGML mode the output of the '>' character is
@@ -404,7 +410,7 @@ IceUtil::XMLOutput::se(const string& element)
}
void
-IceUtil::XMLOutput::ee()
+IceUtil::XMLOutput::endElement()
{
string element = _elementStack.top();
_elementStack.pop();
@@ -428,7 +434,7 @@ IceUtil::XMLOutput::ee()
{
if(!_text)
{
- nl();
+ newline();
}
_out << "</" << element << '>';
}
diff --git a/cpp/src/Slice/JavaUtil.cpp b/cpp/src/Slice/JavaUtil.cpp
index b7f0640d026..91b82b347c0 100644
--- a/cpp/src/Slice/JavaUtil.cpp
+++ b/cpp/src/Slice/JavaUtil.cpp
@@ -116,8 +116,8 @@ Slice::JavaOutput::openClass(const string& cls, const string& prefix)
if(!package.empty())
{
- sp();
- nl();
+ separator();
+ separator();
print("package ");
print(package.c_str());
print(";");
diff --git a/cpp/src/slice2html/.depend b/cpp/src/slice2html/.depend
new file mode 100644
index 00000000000..e7b23adfc96
--- /dev/null
+++ b/cpp/src/slice2html/.depend
@@ -0,0 +1,2 @@
+Gen$(OBJEXT): Gen.cpp ../../include/IceUtil/DisableWarnings.h ../../include/IceUtil/Functional.h ../../include/IceUtil/Handle.h ../../include/IceUtil/Exception.h ../../include/IceUtil/Config.h Gen.h ../../include/Slice/Parser.h ../../include/IceUtil/Shared.h ../../include/IceUtil/InputUtil.h ../../include/IceUtil/OutputUtil.h
+Main$(OBJEXT): Main.cpp ../../include/IceUtil/Options.h ../../include/IceUtil/Config.h ../../include/IceUtil/RecMutex.h ../../include/IceUtil/Lock.h ../../include/IceUtil/ThreadException.h ../../include/IceUtil/Exception.h ../../include/IceUtil/Shared.h ../../include/IceUtil/Handle.h ../../include/Slice/Preprocessor.h Gen.h ../../include/Slice/Parser.h ../../include/IceUtil/InputUtil.h ../../include/IceUtil/OutputUtil.h
diff --git a/cpp/src/slice2html/Gen.cpp b/cpp/src/slice2html/Gen.cpp
new file mode 100644
index 00000000000..6ae96c6b1a7
--- /dev/null
+++ b/cpp/src/slice2html/Gen.cpp
@@ -0,0 +1,1955 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2006 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/DisableWarnings.h>
+#include <IceUtil/Functional.h>
+#include <Gen.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#ifdef _WIN32
+#include <direct.h>
+#else
+#include <unistd.h>
+#endif
+
+#ifdef __BCPLUSPLUS__
+# include <iterator>
+#endif
+
+using namespace std;
+using namespace Slice;
+using namespace IceUtil;
+
+namespace Slice
+{
+
+void
+generate(const UnitPtr& unit, const ::std::string& dir,
+ const ::std::string& header, const ::std::string& footer, unsigned indexCount)
+{
+ 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::setHeader(header);
+ GeneratorBase::setFooter(footer);
+ GeneratorBase::setIndexCount(indexCount);
+
+ IndexVisitor iv;
+ unit->visit(&iv, false);
+
+ Visitor v;
+ unit->visit(&v, false);
+}
+
+}
+
+string Slice::GeneratorBase::_dir = ".";
+string Slice::GeneratorBase::_header1;
+string Slice::GeneratorBase::_header2;
+string Slice::GeneratorBase::_footer;
+unsigned Slice::GeneratorBase::_indexCount = 0;
+
+void
+Slice::GeneratorBase::setOutputDir(const string& dir)
+{
+ if(!dir.empty())
+ {
+ _dir = dir;
+ makeDir(_dir);
+ }
+}
+
+void
+Slice::GeneratorBase::setHeader(const string& header)
+{
+ if(header.empty())
+ {
+ ostringstream hdr1;
+ XMLOutput O1(hdr1);
+ O1 << "<!-- Generated by Ice version " << ICE_STRING_VERSION << " -->";
+ O1 << sp;
+ O1 << nl << "<!DOCTYPE html PUBLIC \"-//W3C//dtD html 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">";
+ O1 << se("html");
+ O1 << se("head");
+ O1 << se("title") << nl;
+ _header1 = hdr1.str();
+
+ // _header1 and _header2 store the bit preceding and following the title.
+ // _header1, the title text, and _header2 are written by openDoc().
+
+ ostringstream hdr2;
+ XMLOutput O2(hdr2);
+ O2.inc();
+ O2.inc();
+ O2 << nl << "<title/>";
+ O2.dec();
+ O2 << nl << "</head>";
+ O2 << nl << "<body>";
+ _header2 = hdr2.str();
+ }
+ else
+ {
+ readFile(header, _header1, _header2);
+ }
+}
+
+void
+Slice::GeneratorBase::setFooter(const string& footer)
+{
+ ostringstream ftr;
+ XMLOutput O(ftr);
+ if(footer.empty())
+ {
+ O << " </body>";
+ }
+ else
+ {
+ O << readFile(footer);
+ }
+ O << nl << "</html>";
+ _footer = ftr.str();
+}
+
+void
+Slice::GeneratorBase::setIndexCount(int ic)
+{
+ _indexCount = ic;
+}
+
+Slice::GeneratorBase::GeneratorBase(XMLOutput& o)
+ : _out(o)
+{
+}
+
+Slice::GeneratorBase::~GeneratorBase()
+{
+}
+
+void
+Slice::GeneratorBase::openDoc(const string& file, const string& title)
+{
+ openStream(_dir + "/" + file);
+
+ _out << _header1;
+ _out << title;
+ _out << _header2;
+ _out.inc();
+ _out.inc();
+}
+
+void
+Slice::GeneratorBase::openDoc(const ContainedPtr& c)
+{
+ string path = _dir;
+ StringList components = toStringList(c);
+ StringList::const_iterator i = components.begin();
+ for(StringList::size_type num = 0; num < components.size() - 1; ++num, ++i)
+ {
+ path += "/" + *i;
+ makeDir(path);
+ }
+ path += "/" + *i + ".html";
+
+ openStream(path);
+
+ _out << _header1;
+ _out << c->scoped().substr(2); // Text for title element.
+ _out << _header2;
+ _out.inc();
+ _out.inc();
+}
+
+void
+Slice::GeneratorBase::closeDoc()
+{
+ _out.dec();
+ _out.dec();
+ _out << nl << _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 << se(s);
+}
+
+void
+Slice::GeneratorBase::end()
+{
+ _out << ee;
+}
+
+string
+Slice::GeneratorBase::getComment(const ContainedPtr& contained, const ContainerPtr& container, bool summary)
+{
+ string s = contained->comment();
+ string comment;
+ for(unsigned int i = 0; i < s.size(); ++i)
+ {
+ if(s[i] == '\\' && i + 1 < s.size() && s[i + 1] == '[')
+ {
+ comment += '[';
+ ++i;
+ }
+ else if(s[i] == '[')
+ {
+ string literal;
+ for(++i; i < s.size(); ++i)
+ {
+ if(s[i] == ']')
+ {
+ break;
+ }
+
+ literal += s[i];
+ }
+ comment += toString(literal, container);
+ }
+ else if(summary && s[i] == '.' && (i + 1 >= s.size() || isspace(s[i + 1])))
+ {
+ comment += '.';
+ break;
+ }
+ else
+ {
+ comment += s[i];
+ }
+
+ }
+ return comment;
+}
+
+void
+Slice::GeneratorBase::printComment(const ContainedPtr& p, const string& deprecateReason)
+{
+#ifndef NDEBUG
+ int indent = _out.currIndent();
+#endif
+
+ ContainerPtr container = ContainerPtr::dynamicCast(p);
+ if(!container)
+ {
+ container = p->container();
+ }
+
+ string comment = getComment(p, container, false);
+ 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);
+ _out.zeroIndent();
+ _out << nl << comment;
+ _out.restoreIndent();
+ }
+
+ if(!deprecateReason.empty())
+ {
+ end();
+ start("dd");
+ _out << nl << deprecateReason;
+ }
+
+ assert(_out.currIndent() == indent);
+
+ bool startedList = false;
+
+ if(!par.empty())
+ {
+ start("dl");
+ startedList = true;
+ start("dt", "Heading");
+ _out << "Parameters";
+ end();
+ start("dd");
+ 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);
+ }
+
+ start("dt", "Symbol");
+ _out << term;
+ end();
+ start("dd");
+ _out << nl << item;
+ end();
+ }
+ end();
+ end();
+ }
+
+ if(!ret.empty())
+ {
+ if(!startedList)
+ {
+ start("dl");
+ startedList = true;
+ }
+ start("dt");
+ _out << "Return Value";
+ end();
+ start("dd", "Symbol");
+ _out << ret.front();
+ end();
+ }
+
+
+ if(!throws.empty())
+ {
+ if(!startedList)
+ {
+ start("dl");
+ startedList = true;
+ }
+ start("dt", "Heading");
+ _out << "Exceptions";
+ end();
+ start("dd");
+ 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);
+ }
+
+ start("dt", "Symbol");
+ _out << toString(term, container);
+ end();
+ start("dd");
+ _out << nl << item;
+ end();
+ }
+ end();
+ end();
+ }
+
+
+ ClassList derivedClasses;
+ ClassDefPtr def = ClassDefPtr::dynamicCast(p);
+ if(def)
+ {
+ derivedClasses = p->unit()->findDerivedClasses(def);
+ }
+ if(!derivedClasses.empty())
+ {
+ if(!startedList)
+ {
+ start("dl");
+ startedList = true;
+ }
+ start("dt", "Heading");
+ _out << "Derived Classes and Interfaces";
+ end();
+ start("dd");
+ start("dl");
+ for(ClassList::const_iterator q = derivedClasses.begin(); q != derivedClasses.end(); ++q)
+ {
+ start("dt", "Symbol");
+ _out << toString(*q, container);
+ end();
+ }
+ end();
+ end();
+ }
+
+ ExceptionList derivedExceptions;
+ ExceptionPtr ex = ExceptionPtr::dynamicCast(p);
+ if(ex)
+ {
+ derivedExceptions = p->unit()->findDerivedExceptions(ex);
+ if(!derivedExceptions.empty())
+ {
+ if(!startedList)
+ {
+ start("dl");
+ startedList = true;
+ }
+ start("dt", "Heading");
+ _out << "Derived Exceptions";
+ end();
+ start("dd");
+ start("dl");
+ for(ExceptionList::const_iterator q = derivedExceptions.begin(); q != derivedExceptions.end(); ++q)
+ {
+ start("dt", "Symbol");
+ _out << toString(*q, container);
+ end();
+ }
+ end();
+ end();
+ }
+
+ ContainedList usedBy;
+ usedBy = p->unit()->findUsedBy(ex);
+ if(!usedBy.empty())
+ {
+ if(!startedList)
+ {
+ start("dl");
+ startedList = true;
+ }
+ start("dt", "Heading");
+ _out << "Used By";
+ end();
+ start("dd");
+ start("dl", "UsedBy");
+ //
+ // 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));
+ }
+ sl.sort();
+ for(StringList::const_iterator r = sl.begin(); r != sl.end(); ++r)
+ {
+ start("dt", "Symbol");
+ _out << *r;
+ end();
+ }
+ 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));
+ }
+ strings.sort();
+ strings.unique();
+
+ if(!startedList)
+ {
+ start("dl");
+ startedList = true;
+ }
+ start("dt", "Heading");
+ _out << "Used By";
+ end();
+ start("dd");
+ start("dl", "UsedBy");
+ for(list<string>::const_iterator p = strings.begin(); p != strings.end(); ++p)
+ {
+ start("dt", "Symbol");
+ _out << *p;
+ end();
+ }
+ end();
+ end();
+ }
+
+ if(!see.empty())
+ {
+ if(!startedList)
+ {
+ start("dl");
+ startedList = true;
+ }
+ start("dt", "Heading");
+ _out << "See Also";
+ end();
+ start("dd");
+ start("dl", "UsedBy");
+ for(StringList::const_iterator q = see.begin(); q != see.end(); ++q)
+ {
+ start("dt", "Symbol");
+ _out << toString(*q, container);
+ end();
+ }
+ end();
+ end();
+ }
+
+ if(startedList)
+ {
+ 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, bool deprecated)
+{
+ ContainerPtr container = ContainerPtr::dynamicCast(p);
+ if(!container)
+ {
+ container = p->container();
+ }
+
+ string summary = getComment(p, container, true);
+ start("dd", "Summary");
+ _out << nl << summary;
+ end();
+
+ if(deprecated)
+ {
+ start("dd", "Deprecated");
+ _out << nl << "Deprecated.";
+ end();
+ }
+}
+
+string
+Slice::GeneratorBase::toString(const SyntaxTreeBasePtr& p, const ContainerPtr& container, bool asTarget)
+{
+ string linkend;
+ 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()];
+ }
+
+ ProxyPtr proxy = ProxyPtr::dynamicCast(p);
+ if(proxy)
+ {
+ if(proxy->_class()->includeLevel() == 0)
+ {
+ linkend = containedToId(proxy->_class(), asTarget);
+ }
+ s = getScopedMinimized(proxy->_class(), container);
+ s += "*";
+ }
+
+ 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 && definition->includeLevel() == 0)
+ {
+ linkend = containedToId(definition, asTarget);
+ }
+ s = getScopedMinimized(cl, container);
+ }
+
+ ExceptionPtr ex = ExceptionPtr::dynamicCast(p);
+ if(ex)
+ {
+ if(ex->includeLevel() == 0)
+ {
+ linkend = containedToId(ex, asTarget);
+ }
+ s = getScopedMinimized(ex, container);
+ }
+
+ StructPtr st = StructPtr::dynamicCast(p);
+ if(st)
+ {
+ if(st->includeLevel() == 0)
+ {
+ linkend = containedToId(st, asTarget);
+ }
+ s = getScopedMinimized(st, container);
+ }
+
+ EnumeratorPtr en = EnumeratorPtr::dynamicCast(p);
+ if(en)
+ {
+ if(en->includeLevel() == 0)
+ {
+ linkend = containedToId(en, asTarget);
+ }
+ s = getScopedMinimized(en, container);
+ }
+
+ OperationPtr op = OperationPtr::dynamicCast(p);
+ if(op)
+ {
+ if(op->includeLevel() == 0)
+ {
+ linkend = containedToId(op, asTarget);
+ }
+ s = getScopedMinimized(op, container);
+ }
+
+ ParamDeclPtr pd = ParamDeclPtr::dynamicCast(p);
+ if(pd)
+ {
+ op = OperationPtr::dynamicCast(pd->container());
+ assert(op);
+ if(pd->includeLevel() == 0)
+ {
+ linkend = containedToId(op, asTarget);
+ }
+ s = getScopedMinimized(op, container);
+ }
+
+ if(s.empty())
+ {
+ ContainedPtr contained = ContainedPtr::dynamicCast(p);
+ assert(contained);
+ if(contained->includeLevel() == 0)
+ {
+ linkend = containedToId(contained, asTarget);
+ }
+ s = getScopedMinimized(contained, container);
+ }
+
+ if(linkend.empty())
+ {
+ return s;
+ }
+ else
+ {
+ string ret = "<a ";
+ ret += asTarget ? "name" : "href";
+ ret += "=" + linkend + + ">" + s + "</a>";
+ return ret;
+ }
+}
+
+string
+Slice::GeneratorBase::toString(const string& str, const ContainerPtr& container, bool asTarget)
+{
+ string s = str;
+
+ TypeList types = container->lookupType(s, false);
+ if(!types.empty())
+ {
+ return toString(types.front(), container, asTarget);
+ }
+
+ ContainedList contList = container->lookupContained(s, false);
+ if(!contList.empty())
+ {
+ return toString(contList.front(), container, asTarget);
+ }
+
+ //
+ // If we can't find the string, printing it in typewriter
+ // font is the best we can do.
+ //
+ return "<span class=Symbol>" + s + "</span>";
+}
+
+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;
+}
+
+#if 0
+string
+Slice::GeneratorBase::getScopedMinimized(const ContainedPtr& contained, const ContainerPtr& container)
+{
+ cerr << "contained is " << contained->scoped() << endl;
+ cerr << "container is " << ContainedPtr::dynamicCast(container)->scoped() << endl;
+ StringList anchors;
+ ContainedPtr c = contained;
+ while(!ExceptionPtr::dynamicCast(c) &&
+ !ClassDeclPtr::dynamicCast(c) &&
+ !ClassDefPtr::dynamicCast(c) &&
+ !StructPtr::dynamicCast(c) &&
+ !ModulePtr::dynamicCast(c))
+ {
+ cerr << "Pushing " << c->name() << endl;
+ anchors.push_front(c->name());
+ c = ContainedPtr::dynamicCast(c->container());
+ }
+
+ cerr << "c is " << ContainedPtr::dynamicCast(c)->scoped() << endl;
+#if 0
+ StringList from = toStringList(contained);
+ StringList to = toStringList(ContainedPtr::dynamicCast(container));
+
+ StringList::const_iterator f = from.begin();
+ StringList::const_iterator t = to.begin();
+ while(f != from.end() && t != to.end())
+ {
+ }
+#endif
+ cerr << "returning" << endl;
+ return "";
+}
+#endif
+
+string
+Slice::GeneratorBase::getScopedMinimized(const ContainedPtr& contained, const ContainerPtr& container)
+{
+ cerr << "get" << endl;
+ cerr << "contained: " << contained->scoped() << endl;
+ if(container)
+ {
+ cerr << "container: " << ContainedPtr::dynamicCast(container)->scoped() << endl;
+ }
+ 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;
+}
+
+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 + '"';
+}
+
+void
+Slice::GeneratorBase::openStream(const string& path)
+{
+ _out.open(path.c_str());
+ if(!_out.isOpen())
+ {
+ string err = "cannot open `" + path + "' for writing";
+ throw err;
+ }
+}
+
+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)
+ {
+ return;
+ }
+#ifdef _WIN32
+ rc = mkdir(dir.c_str())
+#else
+ rc = mkdir(dir.c_str(), S_IRWXU | S_IRWXG | S_IRWXO);
+#endif
+ if(rc != 0)
+ {
+ string err = "cannot create directory `" + dir + "'";
+ throw err;
+ }
+}
+
+string
+Slice::GeneratorBase::readFile(const string& file)
+{
+ ifstream in(file.c_str());
+ if(!in)
+ {
+ string err = "cannot open `" + file + "' for reading";
+ throw err;
+ }
+
+ ostringstream result;
+ string line;
+ getline(in, line);
+ while(!line.empty())
+ {
+ result << line << '\n';
+ getline(in, line);
+ }
+
+ return result.str();
+}
+
+void
+Slice::GeneratorBase::readFile(const string& file, string& part1, string& part2)
+{
+ ifstream in(file.c_str());
+ if(!in)
+ {
+ string err = "cannot open `" + file + "' for reading";
+ throw err;
+ }
+
+ string line;
+
+ ostringstream p1;
+ getline(in, line);
+ while(!line.empty() && line != "TITLE")
+ {
+ p1 << line << '\n';
+ getline(in, line);
+ }
+ part1 = p1.str();
+
+ if(line.empty())
+ {
+ string err = "no TITLE marker in `" + file + "'";
+ throw err;
+ }
+
+ ostringstream p2;
+ p2 << endl;
+ getline(in, line);
+ while(!line.empty())
+ {
+ p2 << line << '\n';
+ getline(in, line);
+ }
+ part2 = p2.str();
+}
+
+Slice::IndexGenerator::IndexGenerator()
+ : GeneratorBase(_out)
+{
+ openDoc("index.html", "Slice Documentation Index");
+}
+
+Slice::IndexGenerator::~IndexGenerator()
+{
+ ::std::sort(_modules.begin(), _modules.end());
+
+ start("dl");
+ start("dt");
+ _out << "Modules";
+ end();
+ start("dd");
+ start("dl");
+ for(ModuleDescriptions::const_iterator i = _modules.begin(); i != _modules.end(); ++i)
+ {
+ start("dt");
+ _out << i->first;
+ end();
+ start("dd");
+ _out << i->second;
+ end();
+ }
+ end();
+ end();
+ end();
+
+ closeDoc();
+}
+
+void
+Slice::IndexGenerator::generate(const ModulePtr& m)
+{
+ string name = toString(m, 0, false);
+ string comment = getComment(m, 0, true);
+ _modules.push_back(make_pair(name, comment));
+}
+
+Slice::IndexVisitor::IndexVisitor()
+{
+}
+
+bool
+Slice::IndexVisitor::visitUnitStart(const UnitPtr& unit)
+{
+ return true;
+}
+
+bool
+Slice::IndexVisitor::visitModuleStart(const ModulePtr& m)
+{
+ _ig.generate(m);
+ return false;
+}
+
+Slice::ModuleGenerator::ModuleGenerator(XMLOutput& o)
+ : GeneratorBase(o)
+{
+}
+
+void
+Slice::ModuleGenerator::generate(const ModulePtr& m)
+{
+#ifndef NDEBUG
+ int indent = _out.currIndent();
+#endif
+
+ openDoc(m);
+
+ start("dl");
+ start("dt", "Symbol");
+ _out << m->name();
+ end();
+
+ start("dd");
+ start("dl");
+ 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("dt", "Heading");
+ _out << "Overview";
+ end();
+ start("dd");
+ start("dl");
+ start("dt");
+ start("span", "Synopsis");
+ printMetaData(m);
+ _out << "module " << m->name();
+ end();
+ end();
+ start("dd");
+ printComment(m, deprecateReason);
+ end();
+ end();
+
+ visitContainer(m);
+
+ end();
+ end();
+ end();
+ end();
+
+ closeDoc();
+
+ assert(_out.currIndent() == indent);
+}
+
+void
+Slice::ModuleGenerator::visitContainer(const ContainerPtr& p)
+{
+#ifndef NDEBUG
+ int indent = _out.currIndent();
+#endif
+
+ ModuleList modules = p->modules();
+ modules.erase(remove_if(modules.begin(), modules.end(), ::IceUtil::constMemFun(&Contained::includeLevel)),
+ modules.end());
+
+ if(_indexCount > 0 && modules.size() >= _indexCount)
+ {
+ start("dt", "Heading");
+ _out << "Module Index";
+ end();
+ start("dd");
+ start("dl");
+ for(ModuleList::const_iterator q = modules.begin(); q != modules.end(); ++q)
+ {
+ start("dt", "Symbol");
+ _out << toString(*q, p);
+ end();
+ start("dd");
+ string metadata;
+ printSummary(*q, (*q)->findMetaData("deprecate", metadata));
+ end();
+ }
+ end();
+ end();
+ }
+
+ assert(_out.currIndent() == indent);
+
+ ClassList classesAndInterfaces = p->classes();
+ classesAndInterfaces.erase(remove_if(classesAndInterfaces.begin(), classesAndInterfaces.end(),
+ ::IceUtil::constMemFun(&Contained::includeLevel)),
+ classesAndInterfaces.end());
+ 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(_indexCount > 0 && classes.size() >= _indexCount)
+ {
+ start("dt", "Heading");
+ _out << "Class Index";
+ end();
+ start("dd");
+ start("dl");
+ for(ClassList::const_iterator q = classes.begin(); q != classes.end(); ++q)
+ {
+ start("dt", "Symbol");
+ _out << toString(*q, p);
+ end();
+ start("dd");
+ string metadata;
+ printSummary(*q, (*q)->findMetaData("deprecate", metadata));
+ end();
+ }
+ end();
+ end();
+ }
+
+ assert(_out.currIndent() == indent);
+
+ if(_indexCount > 0 && interfaces.size() >= _indexCount)
+ {
+ start("dt", "Heading");
+ _out << "Interface Index";
+ end();
+ start("dd");
+ start("dl");
+ for(ClassList::const_iterator q = interfaces.begin(); q != interfaces.end(); ++q)
+ {
+ start("dt", "Symbol");
+ _out << toString(*q, p);
+ end();
+ start("dd");
+ string metadata;
+ printSummary(*q, (*q)->findMetaData("deprecate", metadata));
+ end();
+ }
+ end();
+ end();
+ }
+
+ assert(_out.currIndent() == indent);
+
+ ExceptionList exceptions = p->exceptions();
+ exceptions.erase(remove_if(exceptions.begin(), exceptions.end(), ::IceUtil::constMemFun(&Contained::includeLevel)),
+ exceptions.end());
+
+ if(_indexCount > 0 && exceptions.size() >= _indexCount)
+ {
+ start("dt", "Heading");
+ _out << "Exception Index";
+ end();
+ start("dd");
+ start("dl");
+ for(ExceptionList::const_iterator q = exceptions.begin(); q != exceptions.end(); ++q)
+ {
+ start("dt", "Symbol");
+ _out << toString(*q, p);
+ end();
+ start("dd");
+ string metadata;
+ printSummary(*q, (*q)->findMetaData("deprecate", metadata));
+ end();
+ }
+ end();
+ end();
+ }
+
+ assert(_out.currIndent() == indent);
+
+ StructList structs = p->structs();
+ structs.erase(remove_if(structs.begin(), structs.end(), ::IceUtil::constMemFun(&Contained::includeLevel)),
+ structs.end());
+
+ if(_indexCount > 0 && structs.size() >= _indexCount)
+ {
+ start("dt", "Heading");
+ _out << "Structure Index";
+ end();
+ start("dd");
+ start("dl");
+ for(StructList::const_iterator q = structs.begin(); q != structs.end(); ++q)
+ {
+ start("dt", "Symbol");
+ _out << toString(*q, p);
+ end();
+ start("dd");
+ string metadata;
+ printSummary(*q, (*q)->findMetaData("deprecate", metadata));
+ end();
+ }
+ end();
+ end();
+ }
+
+ assert(_out.currIndent() == indent);
+
+ SequenceList sequences = p->sequences();
+ sequences.erase(remove_if(sequences.begin(), sequences.end(), ::IceUtil::constMemFun(&Contained::includeLevel)),
+ sequences.end());
+
+ if(_indexCount > 0 && sequences.size() >= _indexCount)
+ {
+ start("dt", "Heading");
+ _out << "Sequence Index";
+ end();
+ start("dd");
+ start("dl");
+ for(SequenceList::const_iterator q = sequences.begin(); q != sequences.end(); ++q)
+ {
+ start("dt", "Symbol");
+ _out << toString(*q, p);
+ end();
+ start("dd");
+ string metadata;
+ printSummary(*q, (*q)->findMetaData("deprecate", metadata));
+ end();
+ }
+ end();
+ end();
+ }
+
+ assert(_out.currIndent() == indent);
+
+ DictionaryList dictionaries = p->dictionaries();
+ dictionaries.erase(remove_if(dictionaries.begin(), dictionaries.end(),
+ ::IceUtil::constMemFun(&Contained::includeLevel)),
+ dictionaries.end());
+
+ if(_indexCount > 0 && dictionaries.size() >= _indexCount)
+ {
+ start("dt", "Heading");
+ _out << "Dictionary Index";
+ end();
+ start("dd");
+ start("dl");
+ for(DictionaryList::const_iterator q = dictionaries.begin(); q != dictionaries.end(); ++q)
+ {
+ start("dt", "Symbol");
+ _out << toString(*q, p);
+ end();
+ start("dd");
+ string metadata;
+ printSummary(*q, (*q)->findMetaData("deprecate", metadata));
+ end();
+ }
+ end();
+ end();
+ }
+
+ assert(_out.currIndent() == indent);
+
+ EnumList enums = p->enums();
+ enums.erase(remove_if(enums.begin(), enums.end(), ::IceUtil::constMemFun(&Contained::includeLevel)),
+ enums.end());
+
+ if(_indexCount > 0 && enums.size() >= _indexCount)
+ {
+ start("dt", "Heading");
+ _out << "Enumeration Index";
+ end();
+ start("dd");
+ start("dl");
+ for(EnumList::const_iterator q = enums.begin(); q != enums.end(); ++q)
+ {
+ start("dt", "Symbol");
+ _out << toString(*q, p);
+ end();
+ start("dd");
+ string metadata;
+ printSummary(*q, (*q)->findMetaData("deprecate", metadata));
+ end();
+ }
+ end();
+ end();
+ }
+
+ assert(_out.currIndent() == indent);
+
+ if(!sequences.empty())
+ {
+ start("dt", "Heading");
+ _out << "Sequences";
+ end();
+ start("dd");
+ 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) << "&gt; " << (*q)->name();
+ 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, deprecateReason);
+ end();
+ end();
+ }
+ end();
+ }
+
+ if(!dictionaries.empty())
+ {
+ start("dt", "Heading");
+ _out << "Dictionaries";
+ end();
+ start("dd");
+ 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) << ", " << toString(valueType, p) << "&gt; "
+ << (*q)->name();
+ 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, deprecateReason);
+ end();
+ end();
+ }
+ end();
+ }
+}
+
+Slice::ExceptionGenerator::ExceptionGenerator(XMLOutput& o)
+ : GeneratorBase(o)
+{
+}
+
+void
+Slice::ExceptionGenerator::generate(const ExceptionPtr& e)
+{
+#ifndef NDEBUG
+ int indent = _out.currIndent();
+#endif
+
+ openDoc(e);
+
+ start("dl");
+ start("dt", "Symbol, Heading");
+ _out << e->name();
+ 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("dd");
+ start("dl");
+ start("dt", "Heading");
+ _out << "Overview";
+ end();
+
+ start("dd");
+ start("dl");
+ start("dt");
+ start("span", "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);
+ _out.dec();
+ _out.dec();
+ }
+ end();
+ end();
+ start("dd");
+ printComment(e, deprecateReason);
+ end();
+ end();
+
+ DataMemberList dataMembers = e->dataMembers();
+ if(!dataMembers.empty())
+ {
+ start("dt", "Heading");
+ _out << "Data Members";
+ end();
+ start("dd");
+ 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) << " " << (*q)->name() << ";";
+ 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, reason);
+ end();
+ }
+ end();
+ end();
+ }
+ end();
+ end();
+ end();
+ end();
+
+ closeDoc();
+
+ assert(_out.currIndent() == indent);
+}
+
+Slice::ClassGenerator::ClassGenerator(XMLOutput& o)
+ : GeneratorBase(o)
+{
+}
+
+void
+Slice::ClassGenerator::generate(const ClassDefPtr& c)
+{
+#ifndef NDEBUG
+ int indent = _out.currIndent();
+#endif
+
+ openDoc(c);
+
+ start("dl");
+ start("dt", "Symbol");
+ _out << c->name();
+ 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("dd");
+ start("dl");
+ start("dt", "Heading");
+ _out << "Overview";
+ end();
+ start("dd");
+ start("dl");
+ start("dt");
+ start("span", "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);
+ 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);
+ if(++q != bases.end())
+ {
+ _out << ", ";
+ }
+ }
+ }
+ end();
+ end();
+
+ start("dd");
+ printComment(c, deprecateReason);
+ end();
+ end();
+ end();
+
+ OperationList operations = c->operations();
+ if(!operations.empty())
+ {
+ start("dt", "Heading");
+ _out << "Operations";
+ end();
+ start("dd");
+ start("dl");
+ for(OperationList::const_iterator q = operations.begin(); q != operations.end(); ++q)
+ {
+ start("dt");
+ start("span", "Synopsis");
+ TypePtr returnType = (*q)->returnType();
+ _out << (returnType ? toString(returnType, c) : string("void")) << " "<< (*q)->name() << "(";
+ ParamDeclList params = (*q)->parameters();
+ ParamDeclList::const_iterator r = params.begin();
+ while(r != params.end())
+ {
+ if((*r)->isOutParam())
+ {
+ _out << "out ";
+ }
+ _out << toString((*r)->type(), *q) << " " << (*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);
+ if(++t != throws.end())
+ {
+ _out << ", ";
+ }
+ }
+ }
+ end();
+ end();
+
+ start("dd");
+ 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, reason);
+ end();
+ }
+ end();
+ end();
+ }
+
+ DataMemberList dataMembers = c->dataMembers();
+ if(!dataMembers.empty())
+ {
+ start("dl");
+ start("dt", "Heading");
+ _out << "Data Members";
+ end();
+ start("dl");
+ for(DataMemberList::const_iterator q = dataMembers.begin(); q != dataMembers.end(); ++q)
+ {
+ start("dt");
+ start("span", "Synopsis");
+ printMetaData(*q);
+ TypePtr type = (*q)->type();
+ _out << toString(type, c) << " " << (*q)->name() << ";";
+ end();
+ end();
+
+ start("dd");
+ 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, reason);
+ end();
+ }
+ end();
+ end();
+ }
+
+ end();
+ end();
+ end();
+
+ closeDoc();
+
+ assert(_out.currIndent() == indent);
+}
+
+Slice::StructGenerator::StructGenerator(XMLOutput& o)
+ : GeneratorBase(o)
+{
+}
+
+void
+Slice::StructGenerator::generate(const StructPtr& s)
+{
+#ifndef NDEBUG
+ int indent = _out.currIndent();
+#endif
+
+ openDoc(s);
+
+ start("dl");
+ start("dt", "Symbol, Heading");
+ _out << s->name();
+ 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("dd");
+ start("dl");
+ start("dt", "Heading");
+ _out << "Overview";
+ end();
+
+ start("dd");
+ start("dl");
+ start("dt");
+ start("span", "Synopsis");
+ printMetaData(s);
+ if(s->isLocal())
+ {
+ _out << "local ";
+ }
+ _out << "struct " << s->name();
+ end();
+ end();
+ start("dd");
+ printComment(s, deprecateReason);
+ end();
+ end();
+
+ DataMemberList dataMembers = s->dataMembers();
+ if(!dataMembers.empty())
+ {
+ start("dt", "Heading");
+ _out << "Data Members";
+ end();
+ start("dd");
+ 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) << " " << (*q)->name() << ";";
+ 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, reason);
+ end();
+ }
+ end();
+ end();
+ }
+ end();
+ end();
+ end();
+ end();
+
+ closeDoc();
+
+ assert(_out.currIndent() == indent);
+}
+
+Slice::EnumGenerator::EnumGenerator(XMLOutput& o)
+ : GeneratorBase(o)
+{
+}
+
+void
+Slice::EnumGenerator::generate(const EnumPtr& e)
+{
+#ifndef NDEBUG
+ int indent = _out.currIndent();
+#endif
+
+ openDoc(e);
+
+ start("dl");
+ start("dt", "Symbol, Heading");
+ _out << e->name();
+ 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("dd");
+ start("dl");
+ start("dt", "Heading");
+ _out << "Overview";
+ end();
+
+ start("dd");
+ start("dl");
+ start("dt");
+ start("span", "Synopsis");
+ printMetaData(e);
+ if(e->isLocal())
+ {
+ _out << "local ";
+ }
+ _out << "enum " << e->name();
+ end();
+ end();
+
+ start("dd");
+ printComment(e, deprecateReason);
+ end();
+ end();
+
+ EnumeratorList enumerators = e->getEnumerators();
+ if(!enumerators.empty())
+ {
+ start("dt", "Heading");
+ _out << "Enumerators";
+ end();
+ start("dd");
+ 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, reason);
+ end();
+ }
+ end();
+ end();
+ }
+ end();
+ end();
+ end();
+ end();
+
+ closeDoc();
+
+ assert(_out.currIndent() == indent);
+}
+
+Slice::Visitor::Visitor()
+{
+}
+
+bool
+Slice::Visitor::visitUnitStart(const UnitPtr& unit)
+{
+ return true;
+}
+
+bool
+Slice::Visitor::visitModuleStart(const ModulePtr& m)
+{
+ XMLOutput O;
+ ModuleGenerator mg(O);
+ mg.generate(m);
+ return true;
+}
+
+bool
+Slice::Visitor::visitExceptionStart(const ExceptionPtr& e)
+{
+ XMLOutput O;
+ ExceptionGenerator eg(O);
+ eg.generate(e);
+ return true;
+}
+
+bool
+Slice::Visitor::visitClassDefStart(const ClassDefPtr& c)
+{
+ XMLOutput O;
+ ClassGenerator cg(O);
+ cg.generate(c);
+ return true;
+}
+
+bool
+Slice::Visitor::visitStructStart(const StructPtr& s)
+{
+ XMLOutput O;
+ StructGenerator sg(O);
+ sg.generate(s);
+ return true;
+}
+
+void
+Slice::Visitor::visitEnum(const EnumPtr& e)
+{
+ XMLOutput O;
+ EnumGenerator eg(O);
+ eg.generate(e);
+}
diff --git a/cpp/src/slice2html/Gen.h b/cpp/src/slice2html/Gen.h
new file mode 100644
index 00000000000..8fcb13e28a5
--- /dev/null
+++ b/cpp/src/slice2html/Gen.h
@@ -0,0 +1,162 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2006 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>
+
+namespace Slice
+{
+
+void generate(const UnitPtr&, const ::std::string&, const ::std::string&, const ::std::string&, unsigned);
+
+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 setIndexCount(const int);
+
+protected:
+
+ GeneratorBase(::IceUtil::XMLOutput&);
+ virtual ~GeneratorBase() = 0;
+
+ void openDoc(const ::std::string&, const std::string&);
+ void openDoc(const ContainedPtr&);
+ void closeDoc();
+
+ void start(const ::std::string&, const ::std::string& = ::std::string());
+ void end();
+
+ ::std::string getComment(const ContainedPtr&, const ContainerPtr&, bool);
+ void printComment(const ContainedPtr&, const ::std::string&);
+ void printMetaData(const ContainedPtr&);
+ void printSummary(const ContainedPtr&, bool);
+
+ ::std::string toString(const SyntaxTreeBasePtr&, const ContainerPtr&, bool = true);
+ ::std::string toString(const ::std::string&, const ContainerPtr&, bool = true);
+
+ ::IceUtil::XMLOutput& _out;
+
+ static unsigned _indexCount;
+
+private:
+
+ StringList getTagged(const ::std::string&, ::std::string&);
+ ::std::string getScopedMinimized(const ContainedPtr&, const ContainerPtr&);
+ ::std::string containedToId(const ContainedPtr&, bool);
+ void openStream(const ::std::string&);
+
+ 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 ::std::string _dir;
+ static ::std::string _header1;
+ static ::std::string _header2;
+ static ::std::string _footer;
+};
+
+class IndexGenerator : private GeneratorBase
+{
+public:
+
+ IndexGenerator();
+ ~IndexGenerator();
+ void generate(const ModulePtr&);
+
+private:
+ typedef ::std::pair< ::std::string, ::std::string> StringPair;
+ typedef ::std::vector<StringPair> ModuleDescriptions;
+ ModuleDescriptions _modules;
+ ::IceUtil::XMLOutput _out;
+};
+
+class IndexVisitor : private ::IceUtil::noncopyable, public ParserVisitor
+{
+public:
+
+ IndexVisitor();
+
+ virtual bool visitUnitStart(const UnitPtr&);
+ virtual bool visitModuleStart(const ModulePtr&);
+
+private:
+
+ IndexGenerator _ig;
+};
+
+class ModuleGenerator : private GeneratorBase
+{
+public:
+
+ ModuleGenerator(::IceUtil::XMLOutput&);
+ void generate(const ModulePtr&);
+
+private:
+
+ virtual void visitContainer(const ContainerPtr&);
+
+};
+
+class ExceptionGenerator : private GeneratorBase
+{
+public:
+
+ ExceptionGenerator(::IceUtil::XMLOutput&);
+ void generate(const ExceptionPtr&);
+};
+
+class ClassGenerator : private GeneratorBase
+{
+public:
+
+ ClassGenerator(::IceUtil::XMLOutput&);
+ void generate(const ClassDefPtr&);
+};
+
+class StructGenerator : private GeneratorBase
+{
+public:
+
+ StructGenerator(::IceUtil::XMLOutput&);
+ void generate(const StructPtr&);
+};
+
+class EnumGenerator : private GeneratorBase
+{
+public:
+
+ EnumGenerator(::IceUtil::XMLOutput&);
+ void generate(const EnumPtr&);
+};
+
+class Visitor : private ::IceUtil::noncopyable, public ParserVisitor
+{
+public:
+
+ Visitor();
+
+ 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&);
+};
+
+}
+
+#endif
diff --git a/cpp/src/slice2html/Main.cpp b/cpp/src/slice2html/Main.cpp
new file mode 100644
index 00000000000..a5f9cb83be5
--- /dev/null
+++ b/cpp/src/slice2html/Main.cpp
@@ -0,0 +1,193 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2006 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 <Slice/Preprocessor.h>
+#include <Gen.h>
+#include <stdlib.h>
+
+using namespace std;
+using namespace Slice;
+using namespace IceUtil;
+
+void
+usage(const char* n)
+{
+ cerr << "Usage: " << n << " [options] slice-files...\n";
+ cerr <<
+ "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"
+ "--header FILE Use the contents of FILE as the header.\n"
+ "--footer FILe Use the contents of FILE as the footer.\n"
+ "--index NUM Generate subindex if it has more than NUM entries (-1 for no index).\n"
+ "-d, --debug Print debug messages.\n"
+ "--ice Permit `Ice' prefix (for building Ice source code only).\n"
+ ;
+}
+
+int
+main(int argc, char* argv[])
+{
+ IceUtil::Options opts;
+ opts.addOpt("h", "help");
+ opts.addOpt("v", "version");
+ opts.addOpt("D", "", IceUtil::Options::NeedArg, "", IceUtil::Options::Repeat);
+ opts.addOpt("U", "", IceUtil::Options::NeedArg, "", IceUtil::Options::Repeat);
+ opts.addOpt("I", "", IceUtil::Options::NeedArg, "", IceUtil::Options::Repeat);
+ opts.addOpt("E");
+ opts.addOpt("", "output-dir", IceUtil::Options::NeedArg, ".");
+ opts.addOpt("", "header", IceUtil::Options::NeedArg);
+ opts.addOpt("", "footer", IceUtil::Options::NeedArg);
+ opts.addOpt("", "index", IceUtil::Options::NeedArg);
+ opts.addOpt("d", "debug");
+ opts.addOpt("", "ice");
+
+ vector<string> args;
+ try
+ {
+ args = opts.parse(argc, (const char**)argv);
+ }
+ catch(const IceUtil::BadOptException& e)
+ {
+ cerr << argv[0] << ": " << e.reason << endl;
+ usage(argv[0]);
+ return EXIT_FAILURE;
+ }
+
+ if(opts.isSet("help"))
+ {
+ usage(argv[0]);
+ return EXIT_SUCCESS;
+ }
+
+ if(opts.isSet("version"))
+ {
+ cout << ICE_STRING_VERSION << endl;
+ return EXIT_SUCCESS;
+ }
+
+ string cppArgs;
+ vector<string> optargs = opts.argVec("D");
+ for(vector<string>::const_iterator i = optargs.begin(); i != optargs.end(); ++i)
+ {
+ cppArgs += " -D\"" + *i + "\"";
+ }
+
+ optargs = opts.argVec("U");
+ for(vector<string>::const_iterator i = optargs.begin(); i != optargs.end(); ++i)
+ {
+ cppArgs += " -U\"" + *i + "\"";
+ }
+
+ optargs = opts.argVec("I");
+ for(vector<string>::const_iterator i = optargs.begin(); i != optargs.end(); ++i)
+ {
+ cppArgs += " -I\"" + *i + "\"";
+ }
+
+ bool preprocess = opts.isSet("E");
+
+ string output = opts.optArg("output-dir");
+
+ string header = opts.optArg("header");
+
+ string footer = opts.optArg("footer");
+
+ string ind = opts.optArg("index");
+ unsigned indexCount;
+ if(!ind.empty())
+ {
+ istringstream s(ind);
+ s >> indexCount;
+ if(!s)
+ {
+ cerr << argv[0] << ": the --index operation requires a positive integer argument" << endl;
+ usage(argv[0]);
+ return EXIT_FAILURE;
+ }
+ }
+
+ bool debug = opts.isSet("debug");
+
+ bool ice = opts.isSet("ice");
+
+ if(args.empty())
+ {
+ cerr << argv[0] << ": no input file" << endl;
+ usage(argv[0]);
+ return EXIT_FAILURE;
+ }
+
+ UnitPtr p = Unit::createUnit(true, false, ice, false);
+
+ int status = EXIT_SUCCESS;
+
+ for(vector<string>::size_type idx = 0; idx < args.size(); ++idx)
+ {
+ Preprocessor icecpp(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(cppHandle, debug);
+ }
+
+ if(!icecpp.close())
+ {
+ p->destroy();
+ return EXIT_FAILURE;
+ }
+ }
+
+ if(status == EXIT_SUCCESS && !preprocess)
+ {
+ try
+ {
+ Slice::generate(p, output, header, footer, indexCount);
+ }
+ catch(const string& err)
+ {
+ cerr << argv[0] << ": " << err << endl;
+ status = EXIT_FAILURE;
+ }
+ catch(const char* err)
+ {
+ cerr << argv[0] << ": " << err << endl;
+ status = EXIT_FAILURE;
+ }
+ }
+
+ p->destroy();
+
+ return status;
+}
diff --git a/cpp/src/slice2html/Makefile b/cpp/src/slice2html/Makefile
new file mode 100644
index 00000000000..3bc17fdf2ff
--- /dev/null
+++ b/cpp/src/slice2html/Makefile
@@ -0,0 +1,32 @@
+# **********************************************************************
+#
+# Copyright (c) 2003-2006 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/slice2html
+
+TARGETS = $(NAME)
+
+OBJS = Gen.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)
+
+install:: all
+ $(call installprogram,$(NAME),$(install_bindir))
+
+include .depend
diff --git a/cpp/src/slice2html/Makefile.mak b/cpp/src/slice2html/Makefile.mak
new file mode 100644
index 00000000000..9bd3d10d215
--- /dev/null
+++ b/cpp/src/slice2html/Makefile.mak
@@ -0,0 +1,54 @@
+# **********************************************************************
+#
+# Copyright (c) 2003-2006 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\slice2html.exe
+
+TARGETS = $(NAME)
+
+OBJS = Gen.obj \
+ Main.obj
+
+SRCS = $(OBJS:.obj=.cpp)
+
+!include $(top_srcdir)/config/Make.rules.mak
+
+CPPFLAGS = -I. $(CPPFLAGS) -DWIN32_LEAN_AND_MEAN
+
+!if "$(BORLAND_HOME)" == "" & "$(OPTIMIZE)" != "yes"
+PDBFLAGS = /pdb:$(NAME:.exe=.pdb)
+!endif
+
+$(NAME): $(OBJS)
+ $(LINK) $(LD_EXEFLAGS) $(PDBFLAGS) $(OBJS) $(PREOUT)$@ $(PRELIBS)slice$(LIBSUFFIX).lib $(BASELIBS)
+
+clean::
+ del /q $(NAME:.exe=.*)
+
+install:: all
+ copy $(NAME) $(install_bindir)
+
+!if "$(OPTIMIZE)" != "yes"
+
+!if "$(BORLAND_HOME)" == ""
+
+install:: all
+ copy $(NAME:.exe=.pdb) $(install_bindir)
+
+!else
+
+install:: all
+ copy $(NAME:.exe=.tds) $(install_bindir)
+
+!endif
+
+!endif
+
+!include .depend