summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/commentcnv.h3
-rw-r--r--src/commentcnv.l207
-rw-r--r--src/config.l9
-rw-r--r--src/debug.cpp2
-rw-r--r--src/debug.h3
-rw-r--r--src/dirdef.cpp216
-rw-r--r--src/dirdef.h52
-rw-r--r--src/docparser.cpp4
-rw-r--r--src/dot.cpp194
-rw-r--r--src/dot.h8
-rw-r--r--src/doxygen.cpp195
-rw-r--r--src/doxygen.h1
-rw-r--r--src/htmlgen.cpp17
-rw-r--r--src/htmlgen.h2
-rw-r--r--src/htmlhelp.cpp28
-rw-r--r--src/latexgen.cpp9
-rw-r--r--src/latexgen.h2
-rw-r--r--src/mangen.h2
-rw-r--r--src/outputgen.h3
-rw-r--r--src/outputlist.cpp1
-rw-r--r--src/outputlist.h6
-rw-r--r--src/pre.l4
-rw-r--r--src/rtfgen.cpp22
-rw-r--r--src/rtfgen.h2
-rw-r--r--src/scanner.l14
-rw-r--r--src/sortdict.h2
-rw-r--r--src/util.cpp175
27 files changed, 1011 insertions, 172 deletions
diff --git a/src/commentcnv.h b/src/commentcnv.h
index 8d2079e..6b17ccd 100644
--- a/src/commentcnv.h
+++ b/src/commentcnv.h
@@ -20,7 +20,8 @@
class BufStr;
-extern void convertCppComments(BufStr *inBuf,BufStr *outBuf);
+extern void convertCppComments(BufStr *inBuf,BufStr *outBuf,
+ const char *fileName);
#endif
diff --git a/src/commentcnv.l b/src/commentcnv.l
index 76c624f..7c182e2 100644
--- a/src/commentcnv.l
+++ b/src/commentcnv.l
@@ -22,19 +22,36 @@
#include <stdio.h>
#include <stdlib.h>
+#include <qstack.h>
+#include <qregexp.h>
+
#include "bufstr.h"
#include "debug.h"
#include "message.h"
#include "config.h"
#include "doxygen.h"
-static BufStr *g_inBuf;
-static BufStr *g_outBuf;
-static int g_inBufPos;
-static int g_col;
-static int g_blockHeadCol;
-static bool g_mlBrief;
-static int g_readLineCtx;
+struct CondCtx
+{
+ CondCtx(int line,QCString id,bool b)
+ : lineNr(line),sectionId(id), skip(b) {}
+ int lineNr;
+ QCString sectionId;
+ bool skip;
+};
+
+static BufStr * g_inBuf;
+static BufStr * g_outBuf;
+static int g_inBufPos;
+static int g_col;
+static int g_blockHeadCol;
+static bool g_mlBrief;
+static int g_readLineCtx;
+static bool g_skip;
+static QCString g_fileName;
+static int g_lineNr;
+static int g_condCtx;
+static QStack<CondCtx> g_condStack;
static void replaceCommentMarker(const char *s,int len)
{
@@ -44,6 +61,7 @@ static void replaceCommentMarker(const char *s,int len)
while ((c=*p) && (c==' ' || c=='\t' || c=='\n'))
{
g_outBuf->addChar(c);
+ g_lineNr += c=='\n';
p++;
}
// replace start of comment marker by spaces
@@ -82,20 +100,115 @@ static inline int computeIndent(const char *s)
static inline void copyToOutput(const char *s,int len)
{
- g_outBuf->addArray(s,len);
int i;
- static int tabSize=Config_getInt("TAB_SIZE");
- for (i=0;i<len;i++)
+ if (g_skip) // only add newlines.
{
- switch (s[i])
+ for (i=0;i<len;i++)
{
- case '\n': g_col=0; break;
- case '\t': g_col+=tabSize-(g_col%tabSize); break;
- default: g_col++; break;
+ if (s[i]=='\n')
+ {
+ g_outBuf->addChar('\n');
+ g_lineNr++;
+ }
+ }
+ }
+ else
+ {
+ g_outBuf->addArray(s,len);
+ static int tabSize=Config_getInt("TAB_SIZE");
+ for (i=0;i<len;i++)
+ {
+ switch (s[i])
+ {
+ case '\n': g_col=0; g_lineNr++; break;
+ case '\t': g_col+=tabSize-(g_col%tabSize); break;
+ default: g_col++; break;
+ }
}
}
}
+static void startCondSection(const char *sectId)
+{
+ g_condStack.push(new CondCtx(g_lineNr,sectId,g_skip));
+ if (Config_getList("ENABLED_SECTIONS").find(sectId)!=-1)
+ {
+ //printf("*** Section is enabled!\n");
+ }
+ else
+ {
+ //printf("*** Section is disabled!\n");
+ g_skip=TRUE;
+ }
+}
+
+static void endCondSection()
+{
+ if (g_condStack.isEmpty())
+ {
+ warn(g_fileName,g_lineNr,"Found \\endcond command without matching \\cond");
+ g_skip=FALSE;
+ }
+ else
+ {
+ CondCtx *ctx = g_condStack.pop();
+ g_skip=ctx->skip;
+ }
+}
+
+/** remove and executes \\cond and \\endcond commands in \a s */
+static QCString handleCondCmdInAliases(const QCString &s)
+{
+ QCString result;
+ //printf("handleCondCmdInAliases(%s)\n",s.data());
+ static QRegExp cmdPat("[\\\\@][a-z_A-Z][a-z_A-Z0-9]*");
+ int p=0,i,l;
+ while ((i=cmdPat.match(s,p,&l))!=-1)
+ {
+ result+=s.mid(p,i-p);
+ QCString cmd = s.mid(i+1,l-1);
+ //printf("Found command %s\n",cmd.data());
+ if (cmd=="cond")
+ {
+ int sp=i+l,ep;
+ const char *arg=s.data()+sp;
+ char c;
+ // skip spaces
+ while ((c=*arg) && (c==' ' || c=='\t')) arg++,sp++;
+ // read argument
+ if (*arg=='\n') // no arg
+ {
+ startCondSection(" ");
+ ep=sp;
+ }
+ else // get argument
+ {
+ while ((c=*arg) && isId(c)) arg++,ep++;
+ if (ep>sp)
+ {
+ QCString id = s.mid(sp,ep-sp);
+ //printf("Found conditional section id %s\n",id.data());
+ startCondSection(id);
+ }
+ }
+ p=ep;
+ }
+ else if (cmd=="endcond")
+ {
+ endCondSection();
+ p=i+l;
+ }
+ else
+ {
+ result+=s.mid(i,l);
+ p=i+l;
+ }
+ }
+ result+=s.right(s.length()-p);
+ return result;
+}
+
+
#undef YY_INPUT
#define YY_INPUT(buf,result,max_size) result=yyread(buf,max_size);
@@ -122,6 +235,7 @@ CHARLIT (("'"\\[0-7]{1,3}"'")|("'"\\."'")|("'"[^' \\\n]{1,4}"'"))
%x CComment
%x Verbatim
%x ReadLine
+%x CondLine
%%
@@ -213,17 +327,6 @@ CHARLIT (("'"\\[0-7]{1,3}"'")|("'"\\."'")|("'"[^' \\\n]{1,4}"'"))
copyToOutput(yytext,yyleng);
BEGIN(Scan);
}
-<CComment>[\\@][a-z_A-Z][a-z_A-Z0-9]* { // expand alias
- QCString *pValue=Doxygen::aliasDict[yytext+1];
- if (pValue)
- {
- copyToOutput(pValue->data(),pValue->length());
- }
- else
- {
- copyToOutput(yytext,yyleng);
- }
- }
<CComment>. {
copyToOutput(yytext,yyleng);
}
@@ -276,11 +379,47 @@ CHARLIT (("'"\\[0-7]{1,3}"'")|("'"\\."'")|("'"[^' \\\n]{1,4}"'"))
copyToOutput(yytext,yyleng);
BEGIN(g_readLineCtx);
}
-<ReadLine>[\\@][a-z_A-Z][a-z_A-Z0-9]* { // expand alias
+<CComment,ReadLine>("\\\\"|"@@")[a-z_A-Z][a-z_A-Z0-9]*[ \t]* { // escaped command
+ copyToOutput(yytext,yyleng);
+ }
+<CComment,ReadLine>[\\@]"cond"[ \t]+ { // conditional section
+ g_condCtx = YY_START;
+ BEGIN(CondLine);
+ }
+<CComment,ReadLine>[\\@]"endcond"/[^a-z_A-Z0-9] { // end of conditional section
+ bool oldSkip=g_skip;
+ endCondSection();
+ if (YY_START==CComment && oldSkip && !g_skip)
+ {
+ //printf("** Adding start of comment!\n");
+ g_outBuf->addChar('/');
+ g_outBuf->addChar('*');
+ }
+ }
+<CondLine>[a-z_A-Z][a-z_A-Z0-9.\-]* {
+ bool oldSkip=g_skip;
+ startCondSection(yytext);
+ if (g_condCtx==CComment && !oldSkip && g_skip)
+ {
+ //printf("** Adding terminator for comment!\n");
+ g_outBuf->addChar('*');
+ g_outBuf->addChar('/');
+ }
+ BEGIN(g_condCtx);
+ }
+<CondLine>[ \t]*
+<CComment,ReadLine>[\\@]"cond"[ \t]*\n |
+<CondLine>. { // forgot section id?
+ startCondSection(" "); // fake section id causing the section to be hidden unconditionally
+ if (*yytext=='\n') g_lineNr++;
+ if (YY_START==CondLine) BEGIN(g_condCtx);
+ }
+<CComment,ReadLine>[\\@][a-z_A-Z][a-z_A-Z0-9]* { // expand alias
QCString *pValue=Doxygen::aliasDict[yytext+1];
if (pValue)
{
- copyToOutput(pValue->data(),pValue->length());
+ QCString val = handleCondCmdInAliases(*pValue);
+ copyToOutput(val.data(),val.length());
}
else
{
@@ -320,16 +459,28 @@ void replaceComment(int offset)
* -# It converts multi-line C++ style comment blocks (that are aligned)
* to C style comment blocks (if MULTILINE_CPP_IS_BRIEF is set to NO).
* -# It replaces aliases with their definition (see ALIASES)
+ * -# It handles conditional sections (\cond...\endcond blocks)
*/
-void convertCppComments(BufStr *inBuf,BufStr *outBuf)
+void convertCppComments(BufStr *inBuf,BufStr *outBuf,const char *fileName)
{
g_inBuf = inBuf;
g_outBuf = outBuf;
g_inBufPos = 0;
g_col = 0;
g_mlBrief = Config_getBool("MULTILINE_CPP_IS_BRIEF");
+ g_skip = FALSE;
+ g_fileName = fileName;
+ g_lineNr = 0;
+ g_condStack.clear();
+ g_condStack.setAutoDelete(TRUE);
BEGIN(Scan);
yylex();
+ while (!g_condStack.isEmpty())
+ {
+ CondCtx *ctx = g_condStack.pop();
+ warn(g_fileName,ctx->lineNr,"Conditional section with %s does not have "
+ "a corresponding \\endcond command within this file.",ctx->sectionId.data());
+ }
if (Debug::isFlagSet(Debug::CommentCnv))
{
msg("-------------\n%s\n-------------\n",g_outBuf->data());
diff --git a/src/config.l b/src/config.l
index 1b73bbd..be17859 100644
--- a/src/config.l
+++ b/src/config.l
@@ -2697,6 +2697,15 @@ void Config::create()
TRUE
);
cb->addDependency("HAVE_DOT");
+ cb = addBool(
+ "DIRECTORY_GRAPH",
+ "If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES \n"
+ "then doxygen will show the dependencies a directory has on other directories \n"
+ "in a graphical way. The dependency relations are determined by the #include\n"
+ "relations between the files in the directories.\n",
+ TRUE
+ );
+ cb->addDependency("HAVE_DOT");
ce = addEnum(
"DOT_IMAGE_FORMAT",
"The DOT_IMAGE_FORMAT tag can be used to set the image format of the images \n"
diff --git a/src/debug.cpp b/src/debug.cpp
index 7a0739e..ef79ee5 100644
--- a/src/debug.cpp
+++ b/src/debug.cpp
@@ -57,6 +57,8 @@ static int labelToEnumValue(const char *l)
return Debug::PrintTree;
else if (label=="time")
return Debug::Time;
+ else if (label=="extcmd")
+ return Debug::ExtCmd;
else
return 0;
}
diff --git a/src/debug.h b/src/debug.h
index ef2792d..40d4c5a 100644
--- a/src/debug.h
+++ b/src/debug.h
@@ -31,7 +31,8 @@ class Debug
CommentCnv = 0x00000020,
Validate = 0x00000040,
PrintTree = 0x00000080,
- Time = 0x00000100
+ Time = 0x00000100,
+ ExtCmd = 0x00000200
};
static void print(DebugMask mask,int prio,const char *fmt,...);
static void setFlag(const char *label);
diff --git a/src/dirdef.cpp b/src/dirdef.cpp
index 34743ea..b7959e2 100644
--- a/src/dirdef.cpp
+++ b/src/dirdef.cpp
@@ -5,6 +5,7 @@
#include "outputlist.h"
#include "language.h"
#include "message.h"
+#include "dot.h"
//----------------------------------------------------------------------
// method implementation
@@ -27,7 +28,6 @@ DirDef::DirDef(const char *path) : Definition(path,1,path)
m_shortName = m_shortName.mid(pi+1);
}
- m_subdirs.setAutoDelete(TRUE);
m_fileList = new FileList;
m_classSDict = new ClassSDict(17);
m_usedDirs = new QDict<UsedDir>(257);
@@ -141,6 +141,21 @@ void DirDef::writeDocumentation(OutputList &ol)
Doxygen::tagFile << " <filename>" << convertToXML(getOutputFileBase()) << Doxygen::htmlFileExtension << "</filename>" << endl;
}
+ // write graph dependency graph
+ if (Config_getBool("DIRECTORY_GRAPH") && Config_getBool("HAVE_DOT"))
+ {
+ DotDirDeps dirDep(this);
+ if (!dirDep.isTrivial())
+ {
+ msg("Generating dependency graph for directory %s\n",displayName().data());
+ ol.disable(OutputGenerator::Man);
+ ol.newParagraph();
+ ol.startDirDepGraph();
+ //TODO: ol.parseText(theTranslator->trDirDepGraph());
+ ol.endDirDepGraph(dirDep);
+ ol.enableAll();
+ }
+ }
ol.startMemberSections();
// write subdir list
@@ -154,7 +169,7 @@ void DirDef::writeDocumentation(OutputList &ol)
while (dd)
{
ol.startMemberItem(0);
- ol.parseText(theTranslator->trDir(FALSE,TRUE));
+ ol.parseText(theTranslator->trDir(FALSE,TRUE)+" ");
ol.insertMemberAlign();
ol.writeObjectLink(dd->getReference(),dd->getOutputFileBase(),0,dd->shortName());
ol.endMemberItem();
@@ -232,13 +247,11 @@ void DirDef::writeDocumentation(OutputList &ol)
ol.popGeneratorState();
}
-void DirDef::writePathFragment(OutputList &ol)
+void DirDef::writePathFragment(OutputList &ol) const
{
- if (getOuterScope()!=Doxygen::globalScope &&
- getOuterScope()->definitionType()==Definition::TypeDir)
+ if (m_parent)
{
- //printf("getOuterScope %s\n",getOuterScope()->name().data());
- ((DirDef*)getOuterScope())->writePathFragment(ol);
+ m_parent->writePathFragment(ol);
ol.writeString("&nbsp;/&nbsp;");
}
ol.writeObjectLink(getReference(),getOutputFileBase(),0,shortName());
@@ -276,7 +289,8 @@ void DirDef::setLevel()
/** Add as "uses" dependency between \a this dir and \a dir,
* that was caused by a dependency on file \a fd.
*/
-void DirDef::addUsesDependency(DirDef *dir,FileDef *fd,bool inherited)
+void DirDef::addUsesDependency(DirDef *dir,FileDef *srcFd,
+ FileDef *dstFd,bool inherited)
{
if (this==dir) return; // do not add self-dependencies
//printf(" > add dependency %s->%s due to %s\n",shortName().data(),
@@ -287,11 +301,12 @@ void DirDef::addUsesDependency(DirDef *dir,FileDef *fd,bool inherited)
UsedDir *usedDir = m_usedDirs->find(dir->getOutputFileBase());
if (usedDir) // dir dependency already present
{
- FileDef *usedFd = usedDir->findFile(fd->getOutputFileBase());
- if (usedFd==0) // new file dependency
+ FilePair *usedPair = usedDir->findFilePair(
+ srcFd->getOutputFileBase()+dstFd->getOutputFileBase());
+ if (usedPair==0) // new file dependency
{
//printf(" => new file\n");
- usedDir->addFile(fd);
+ usedDir->addFileDep(srcFd,dstFd);
added=TRUE;
}
else
@@ -303,19 +318,19 @@ void DirDef::addUsesDependency(DirDef *dir,FileDef *fd,bool inherited)
{
//printf(" => new file\n");
usedDir = new UsedDir(dir,inherited);
- usedDir->addFile(fd);
+ usedDir->addFileDep(srcFd,dstFd);
m_usedDirs->insert(dir->getOutputFileBase(),usedDir);
added=TRUE;
}
if (added && dir->parent())
{
// add relation to parent of used dir
- addUsesDependency(dir->parent(),fd,inherited);
+ addUsesDependency(dir->parent(),srcFd,dstFd,inherited);
}
if (parent())
{
// add relation for the parent of this dir as well
- parent()->addUsesDependency(dir,fd,TRUE);
+ parent()->addUsesDependency(dir,srcFd,dstFd,TRUE);
}
}
@@ -345,7 +360,7 @@ void DirDef::computeDependencies()
if (usedDir)
{
// add dependency: thisDir->usedDir
- addUsesDependency(usedDir,ii->fileDef,FALSE);
+ addUsesDependency(usedDir,fd,ii->fileDef,FALSE);
}
}
}
@@ -364,31 +379,46 @@ bool DirDef::isParentOf(DirDef *dir) const
return FALSE;
}
+bool DirDef::depGraphIsTrivial() const
+{
+ return FALSE;
+}
+
+//----------------------------------------------------------------------
+
+int FilePairDict::compareItems(GCI item1,GCI item2)
+{
+ FilePair *left = (FilePair*)item1;
+ FilePair *right = (FilePair*)item2;
+ int orderHi = stricmp(left->source()->name(),right->source()->name());
+ int orderLo = stricmp(left->destination()->name(),right->destination()->name());
+ return orderHi==0 ? orderLo : orderHi;
+}
+
//----------------------------------------------------------------------
UsedDir::UsedDir(DirDef *dir,bool inherited) :
- m_dir(dir), m_inherited(inherited)
+ m_dir(dir), m_filePairs(7), m_inherited(inherited)
{
+ m_filePairs.setAutoDelete(TRUE);
}
UsedDir::~UsedDir()
{
}
-void UsedDir::addFile(FileDef *fd)
+void UsedDir::addFileDep(FileDef *srcFd,FileDef *dstFd)
{
- m_files.insert(fd->getOutputFileBase(),fd);
+ m_filePairs.inSort(srcFd->getOutputFileBase()+dstFd->getOutputFileBase(),
+ new FilePair(srcFd,dstFd));
}
-FileDef *UsedDir::findFile(const char *name)
+FilePair *UsedDir::findFilePair(const char *name)
{
QCString n=name;
- return n.isEmpty() ? 0 : m_files.find(n);
+ return n.isEmpty() ? 0 : m_filePairs.find(n);
}
-//----------------------------------------------------------------------
-// helper functions
-
DirDef *DirDef::createNewDir(const char *path)
{
ASSERT(path!=0);
@@ -442,13 +472,27 @@ void DirDef::writeDepGraph(QTextStream &t)
{
t << "digraph G {\n";
t << " compound=true\n";
+ t << " node [ fontsize=10, fontname=\"Helvetica\"];\n";
+ t << " edge [ labelfontsize=9, labelfontname=\"Helvetica\"];\n";
QDict<DirDef> dirsInGraph(257);
dirsInGraph.insert(getOutputFileBase(),this);
+ if (parent())
+ {
+ t << " subgraph cluster" << parent()->getOutputFileBase() << " {\n";
+ t << " graph [ bgcolor=\"#ddddee\", pencolor=\"black\", label=\""
+ << parent()->shortName()
+ << "\" fontname=\"Helvetica\", fontsize=10, URL=\"";
+ t << parent()->getOutputFileBase() << Doxygen::htmlFileExtension;
+ t << "\"]\n";
+ }
if (isCluster())
{
t << " subgraph cluster" << getOutputFileBase() << " {\n";
+ t << " graph [ bgcolor=\"#eeeeff\", pencolor=\"black\", label=\"\""
+ << " URL=\"" << getOutputFileBase() << Doxygen::htmlFileExtension
+ << "\"];\n";
t << " " << getOutputFileBase() << " [shape=plaintext label=\""
<< shortName() << "\"];\n";
@@ -461,8 +505,15 @@ void DirDef::writeDepGraph(QTextStream &t)
<< sdir->shortName() << "\"";
if (sdir->isCluster())
{
- t << " color=\"red\" fillcolor=\"white\" style=\"filled\"";
+ t << " color=\"red\"";
+ }
+ else
+ {
+ t << " color=\"black\"";
}
+ t << " fillcolor=\"white\" style=\"filled\"";
+ t << " URL=\"" << sdir->getOutputFileBase()
+ << Doxygen::htmlFileExtension << "\"";
t << "];\n";
dirsInGraph.insert(sdir->getOutputFileBase(),sdir);
}
@@ -470,7 +521,14 @@ void DirDef::writeDepGraph(QTextStream &t)
}
else
{
- t << getOutputFileBase() << " [shape=box label=\"" << shortName() << "\"];\n";
+ t << " " << getOutputFileBase() << " [shape=box, label=\""
+ << shortName() << "\", style=\"filled\", fillcolor=\"#eeeeff\","
+ << " pencolor=\"black\", URL=\"" << getOutputFileBase()
+ << Doxygen::htmlFileExtension << "\"];\n";
+ }
+ if (parent())
+ {
+ t << " }\n";
}
// add nodes for other used directories
@@ -500,7 +558,8 @@ void DirDef::writeDepGraph(QTextStream &t)
{
t << " color=\"red\" fillcolor=\"white\" style=\"filled\"";
}
- t << "];\n";
+ t << " URL=\"" << usedDir->getOutputFileBase()
+ << Doxygen::htmlFileExtension << "\"];\n";
dirsInGraph.insert(usedDir->getOutputFileBase(),usedDir);
break;
}
@@ -523,11 +582,20 @@ void DirDef::writeDepGraph(QTextStream &t)
!usedDir->isParentOf(dir) && // don't point to own parent
dirsInGraph.find(usedDir->getOutputFileBase())) // only point to nodes that are in the graph
{
- int nrefs = udir->files().count();
+ QCString relationName;
+ relationName.sprintf("dir_%06d_%06d",dir->m_dirCount,usedDir->m_dirCount);
+ if (Doxygen::dirRelations.find(relationName)==0)
+ {
+ // new relation
+ Doxygen::dirRelations.append(relationName,
+ new DirRelation(relationName,dir,udir));
+ }
+ int nrefs = udir->filePairs().count();
t << " " << dir->getOutputFileBase() << "->"
- << usedDir->getOutputFileBase();
- t << " [headlabel=\"" << nrefs << "\" headhref=\"http://www.doxygen.org\"]";
- t << ";\n";
+ << usedDir->getOutputFileBase();
+ t << " [headlabel=\"" << nrefs << "\", labeldistance=1.5";
+ t << " headhref=\"" << relationName << Doxygen::htmlFileExtension
+ << "\"];\n";
}
}
}
@@ -536,6 +604,85 @@ void DirDef::writeDepGraph(QTextStream &t)
}
//----------------------------------------------------------------------
+
+static void writePartialDirPath(OutputList &ol,const DirDef *root,const DirDef *target)
+{
+ if (target->parent()!=root)
+ {
+ writePartialDirPath(ol,root,target->parent());
+ ol.writeString("&nbsp;/&nbsp;");
+ }
+ ol.writeObjectLink(target->getReference(),target->getOutputFileBase(),0,target->shortName());
+}
+
+static void writePartialFilePath(OutputList &ol,const DirDef *root,const FileDef *fd)
+{
+ if (fd->getDirDef() && fd->getDirDef()!=root)
+ {
+ writePartialDirPath(ol,root,fd->getDirDef());
+ ol.writeString("&nbsp;/&nbsp;");
+ }
+ if (fd->isLinkable())
+ {
+ ol.writeObjectLink(fd->getReference(),fd->getOutputFileBase(),0,fd->name());
+ }
+ else
+ {
+ ol.startBold();
+ ol.docify(fd->name());
+ ol.endBold();
+ }
+}
+
+void DirRelation::writeDocumentation(OutputList &ol)
+{
+ ol.pushGeneratorState();
+ ol.disableAllBut(OutputGenerator::Html);
+
+ QCString shortTitle=m_src->shortName()+" &rarr; "+
+ m_dst->dir()->shortName()+" Relation";//theTranslator->trDirRelation(m_shortName);
+ QCString title=m_src->displayName()+" -> "+
+ m_dst->dir()->shortName()+" Relation";//theTranslator->trDirRelation(m_dispName);
+ startFile(ol,getOutputFileBase(),getOutputFileBase(),title);
+
+ // write navigation path
+ m_src->writeNavigationPath(ol);
+
+ //startTitle(ol,getOutputFileBase());
+ // ol.parseText(shortTitle);
+ //endTitle(ol,getOutputFileBase(),title);
+ ol.writeString("<h3>"+shortTitle+"</h3>");
+
+ ol.writeString("<table class=\"dirtab\">");
+ ol.writeString("<tr class=\"dirtab\">");
+ ol.writeString("<th class=\"dirtab\">File in ");
+ m_src->writePathFragment(ol);
+ ol.writeString("</th>");
+ ol.writeString("<th class=\"dirtab\">Includes file in ");
+ m_dst->dir()->writePathFragment(ol);
+ ol.writeString("</th>");
+ ol.writeString("</tr>");
+
+ SDict<FilePair>::Iterator fpi(m_dst->filePairs());
+ FilePair *fp;
+ for (fpi.toFirst();(fp=fpi.current());++fpi)
+ {
+ ol.writeString("<tr class=\"dirtab\">");
+ ol.writeString("<td class=\"dirtab\">");
+ writePartialFilePath(ol,m_src,fp->source());
+ ol.writeString("</td>");
+ ol.writeString("<td class=\"dirtab\">");
+ writePartialFilePath(ol,m_dst->dir(),fp->destination());
+ ol.writeString("</td>");
+ ol.writeString("</tr>");
+ }
+ ol.writeString("</table>");
+
+ endFile(ol);
+ ol.popGeneratorState();
+}
+
+//----------------------------------------------------------------------
// external functions
void buildDirectories()
@@ -678,5 +825,14 @@ void generateDirDocs(OutputList &ol)
{
dir->writeDocumentation(ol);
}
+ if (Config_getBool("DIRECTORY_GRAPH"))
+ {
+ SDict<DirRelation>::Iterator rdi(Doxygen::dirRelations);
+ DirRelation *dr;
+ for (rdi.toFirst();(dr=rdi.current());++rdi)
+ {
+ dr->writeDocumentation(ol);
+ }
+ }
}
diff --git a/src/dirdef.h b/src/dirdef.h
index 09034a2..e331405 100644
--- a/src/dirdef.h
+++ b/src/dirdef.h
@@ -34,12 +34,14 @@ class QTextStream;
class DirDef;
+/** A list of directories */
class DirList : public QList<DirDef>
{
public:
int compareItems(GCI item1,GCI item2);
};
+/** A directory */
class DirDef : public Definition
{
public:
@@ -63,23 +65,25 @@ class DirDef : public Definition
DirDef *parent() const { return m_parent; }
const QDict<UsedDir> *usedDirs() const { return m_usedDirs; }
bool isParentOf(DirDef *dir) const;
+ bool depGraphIsTrivial() const;
// generate output
void writeDetailedDocumentation(OutputList &ol);
void writeDocumentation(OutputList &ol);
void writeNavigationPath(OutputList &ol);
void writeDepGraph(QTextStream &t);
+ void writePathFragment(OutputList &ol) const;
static DirDef *mergeDirectoryInTree(const QCString &path);
bool visited;
private:
friend void computeDirDependencies();
- void writePathFragment(OutputList &ol);
void setLevel();
static DirDef *createNewDir(const char *path);
static bool matchPath(const QCString &path,QStrList &l);
- void addUsesDependency(DirDef *usedDir,FileDef *fd,bool inherited);
+ void addUsesDependency(DirDef *usedDir,FileDef *srcFd,
+ FileDef *dstFd,bool inherited);
void computeDependencies();
DirList m_subdirs;
@@ -93,23 +97,59 @@ class DirDef : public Definition
QDict<UsedDir> *m_usedDirs;
};
+class FilePair
+{
+ public:
+ FilePair(FileDef *src,FileDef *dst) : m_src(src), m_dst(dst) {}
+ const FileDef *source() const { return m_src; }
+ const FileDef *destination() const { return m_dst; }
+ private:
+ FileDef *m_src;
+ FileDef *m_dst;
+};
+
+class FilePairDict : public SDict<FilePair>
+{
+ public:
+ FilePairDict(int size) : SDict<FilePair>(size) {}
+ int compareItems(GCI item1,GCI item2);
+};
+
+/** Usage information of a directory . */
class UsedDir
{
public:
UsedDir(DirDef *dir,bool inherited);
virtual ~UsedDir();
- void addFile(FileDef *fd);
- FileDef *findFile(const char *name);
- const QDict<FileDef> &files() const { return m_files; }
+ void addFileDep(FileDef *srcFd,FileDef *dstFd);
+ FilePair *findFilePair(const char *name);
+ const FilePairDict &filePairs() const { return m_filePairs; }
const DirDef *dir() const { return m_dir; }
bool inherited() const { return m_inherited; }
private:
DirDef *m_dir;
- QDict<FileDef> m_files;
+ FilePairDict m_filePairs;
bool m_inherited;
};
+/** A usage relation between two direction. */
+class DirRelation
+{
+ public:
+ DirRelation(const QCString &name,DirDef *src,UsedDir *dst)
+ : m_name(name), m_src(src), m_dst(dst) {}
+ DirDef *source() const { return m_src; }
+ UsedDir *destination() const { return m_dst; }
+ void writeDocumentation(OutputList &ol);
+ QCString getOutputFileBase() const { return m_name; }
+
+ private:
+ QCString m_name;
+ DirDef *m_src;
+ UsedDir *m_dst;
+};
+
inline int DirList::compareItems(GCI item1,GCI item2)
{
return stricmp(((DirDef *)item1)->shortName(),((DirDef *)item2)->shortName());
diff --git a/src/docparser.cpp b/src/docparser.cpp
index b69c98a..420a79d 100644
--- a/src/docparser.cpp
+++ b/src/docparser.cpp
@@ -4367,7 +4367,7 @@ reparsetoken:
k!=DocNode::Kind_SimpleSect &&
k!=DocNode::Kind_AutoList &&
k!=DocNode::Kind_SimpleList &&
- k!=DocNode::Kind_Verbatim &&
+ /*k!=DocNode::Kind_Verbatim &&*/
k!=DocNode::Kind_HtmlHeader &&
k!=DocNode::Kind_ParamSect &&
k!=DocNode::Kind_XRefItem
@@ -4518,7 +4518,7 @@ reparsetoken:
}
else if (retval==RetVal_OK)
{
- // the command ended normally, keep scanner for new tokens.
+ // the command ended normally, keep scanning for new tokens.
retval = 0;
}
else if (retval==TK_LISTITEM || retval==TK_ENDLIST || retval==TK_WORD)
diff --git a/src/dot.cpp b/src/dot.cpp
index 4627a8f..41d6901 100644
--- a/src/dot.cpp
+++ b/src/dot.cpp
@@ -27,6 +27,7 @@
#include "scanner.h"
#include "defargs.h"
#include "docparser.h"
+#include "debug.h"
#include <qdir.h>
#include <qfile.h>
@@ -1927,7 +1928,7 @@ DotInclDepGraph::DotInclDepGraph(FileDef *fd,int maxRecursionDepth,bool inverse)
m_diskName = fd->getFileBase().copy();
QCString tmp_url=fd->getReference()+"$"+fd->getFileBase();
m_startNode = new DotNode(m_curNodeNumber++,
- fd->name(),
+ fd->docName(),
tmp_url.data(),
0, // distance
TRUE // root node
@@ -1965,7 +1966,7 @@ QCString DotInclDepGraph::writeGraph(QTextStream &out,
err("Error: Output dir %s does not exist!\n",path); exit(1);
}
QCString oldDir = convertToQCString(QDir::currentDirPath());
- // go to the output directory (i.e. path)
+ // go to the html output directory (i.e. path)
QDir::setCurrent(d.absPath());
QDir thisDir;
@@ -1978,27 +1979,27 @@ QCString DotInclDepGraph::writeGraph(QTextStream &out,
QCString imgExt = Config_getEnum("DOT_IMAGE_FORMAT");
QCString md5 = computeMd5Signature(m_startNode, // root
- DotNode::Dependency, // gt
+ DotNode::CallGraph, // gt
format, // format
- FALSE, // lrRank
+ TRUE, // lrRank
FALSE, // renderParents
QMIN(m_recDepth,m_maxDistance), // maxDist
- !m_inverse // backArrows
+ FALSE // backArrows
);
if (checkAndUpdateMd5Signature(baseName,md5) ||
!QFileInfo(baseName+".map").exists()
)
{
- findMaximalDotGraph(m_startNode, // root
- QMIN(m_recDepth,m_maxDistance), // maxDist
- baseName, // baseName
- thisDir, // thisDir
- DotNode::Dependency, // gt
- format, // format
- FALSE, // lrRank
- FALSE, // renderParents
- !m_inverse // backArrows
- );
+ findMaximalDotGraph(m_startNode, // root
+ QMIN(m_recDepth,m_maxDistance), // maxDist
+ baseName, // baseName
+ thisDir, // thisDir
+ DotNode::CallGraph, // gt
+ format, // format
+ TRUE, // lrRank
+ FALSE, // renderParents
+ FALSE // backArrows
+ );
if (format==BITMAP)
{
// run dot to create a bitmap image
@@ -2045,16 +2046,13 @@ QCString DotInclDepGraph::writeGraph(QTextStream &out,
}
}
}
-
- if (Config_getBool("DOT_CLEANUP")) thisDir.remove(baseName+".dot");
}
if (format==BITMAP && generateImageMap)
{
out << "<p><center><img src=\"" << relPath << baseName << "."
- << imgExt << "\" border=\"0\" usemap=\"#"
- << mapName << "_map\" alt=\"";
- if (m_inverse) out << "Included by dependency graph"; else out << "Include dependency graph";
+ << imgExt << "\" border=\"0\" usemap=\"#"
+ << mapName << "_map\" alt=\"";
out << "\">";
out << "</center>" << endl;
QString tmpstr;
@@ -2066,6 +2064,7 @@ QCString DotInclDepGraph::writeGraph(QTextStream &out,
out << tmpstr;
out << "</map>" << endl;
}
+ //thisDir.remove(baseName+".map");
}
else if (format==EPS)
{
@@ -2076,18 +2075,19 @@ QCString DotInclDepGraph::writeGraph(QTextStream &out,
QDir::setCurrent(oldDir);
return baseName;
}
-
int maxWidth = 420; /* approx. page width in points */
-
+
out << "\\begin{figure}[H]\n"
- "\\begin{center}\n"
- "\\leavevmode\n"
- "\\includegraphics[width=" << QMIN(width/2,maxWidth)
- << "pt]{" << baseName << "}\n"
- "\\end{center}\n"
- "\\end{figure}\n";
+ "\\begin{center}\n"
+ "\\leavevmode\n"
+ "\\includegraphics[width=" << QMIN(width/2,maxWidth)
+ << "pt]{" << baseName << "}\n"
+ "\\end{center}\n"
+ "\\end{figure}\n";
}
+ if (Config_getBool("DOT_CLEANUP")) thisDir.remove(baseName+".dot");
+
QDir::setCurrent(oldDir);
return baseName;
}
@@ -2338,7 +2338,7 @@ bool DotCallGraph::isTrivial() const
//-------------------------------------------------------------
-DotDirDeps::DotDirDeps(DirDef *)
+DotDirDeps::DotDirDeps(DirDef *dir) : m_dir(dir)
{
}
@@ -2346,6 +2346,142 @@ DotDirDeps::~DotDirDeps()
{
}
+QCString DotDirDeps::writeGraph(QTextStream &out,
+ GraphOutputFormat format,
+ const char *path,
+ const char *relPath,
+ bool generateImageMap)
+{
+ QDir d(path);
+ // store the original directory
+ if (!d.exists())
+ {
+ err("Error: Output dir %s does not exist!\n",path); exit(1);
+ }
+ QCString oldDir = convertToQCString(QDir::currentDirPath());
+ // go to the html output directory (i.e. path)
+ QDir::setCurrent(d.absPath());
+ QDir thisDir;
+
+ QCString baseName=m_dir->getOutputFileBase()+"_dep";
+ QCString mapName=baseName;
+ QCString imgExt = Config_getEnum("DOT_IMAGE_FORMAT");
+
+ // todo: create check, update md5 checksum
+ {
+ QFile f(baseName+".dot");
+ if (!f.open(IO_WriteOnly))
+ {
+ err("Cannot create file %s.dot for writing!\n",baseName.data());
+ }
+ QTextStream t(&f);
+ m_dir->writeDepGraph(t);
+ f.close();
+
+ if (format==BITMAP)
+ {
+ // run dot to create a bitmap image
+ QCString dotArgs(maxCmdLine);
+ QCString imgName=baseName+"."+imgExt;
+ dotArgs.sprintf("\"%s.dot\" -T%s -o \"%s\"",
+ baseName.data(),imgExt.data(),imgName.data());
+ if (generateImageMap)
+ {
+ // run dot also to create an image map
+ dotArgs+=QCString(maxCmdLine).sprintf(" -Timap -o \"%s.map\"",
+ baseName.data());
+ }
+ if (iSystem(Config_getString("DOT_PATH")+"dot",dotArgs)!=0)
+ {
+ err("Problems running dot. Check your installation!\n");
+ QDir::setCurrent(oldDir);
+ return baseName;
+ }
+ checkDotResult(imgName);
+ }
+ else if (format==EPS)
+ {
+ // run dot to create a .eps image
+ QCString dotArgs(maxCmdLine);
+ dotArgs.sprintf("-Tps \"%s.dot\" -o \"%s.eps\"",
+ baseName.data(),baseName.data());
+ if (iSystem(Config_getString("DOT_PATH")+"dot",dotArgs)!=0)
+ {
+ err("Problems running dot. Check your installation!\n");
+ QDir::setCurrent(oldDir);
+ return baseName;
+ }
+ if (Config_getBool("USE_PDFLATEX"))
+ {
+ QCString epstopdfArgs(maxCmdLine);
+ epstopdfArgs.sprintf("\"%s.eps\" --outfile=\"%s.pdf\"",
+ baseName.data(),baseName.data());
+ if (iSystem("epstopdf",epstopdfArgs,TRUE)!=0)
+ {
+ err("Error: Problems running epstopdf. Check your TeX installation!\n");
+ QDir::setCurrent(oldDir);
+ return baseName;
+ }
+ }
+ }
+ }
+
+ if (format==BITMAP && generateImageMap)
+ {
+ out << "<p><center><img src=\"" << relPath << baseName << "."
+ << imgExt << "\" border=\"0\" usemap=\"#"
+ << mapName << "_map\" alt=\"";
+ out << m_dir->displayName();
+ out << "\">";
+ out << "</center>" << endl;
+ QString tmpstr;
+ QTextOStream tmpout(&tmpstr);
+ convertMapFile(tmpout,baseName+".map",relPath,TRUE);
+ if (!tmpstr.isEmpty())
+ {
+ out << "<map name=\"" << mapName << "_map\">" << endl;
+ out << tmpstr;
+ out << "</map>" << endl;
+ }
+ else
+ {
+ //printf("Map is empty!\n");
+ }
+ //thisDir.remove(baseName+".map");
+ }
+ else if (format==EPS)
+ {
+ int width,height;
+ if (!readBoundingBoxEPS(baseName+".eps",&width,&height))
+ {
+ err("Error: Could not extract bounding box from .eps!\n");
+ QDir::setCurrent(oldDir);
+ return baseName;
+ }
+ int maxWidth = 420; /* approx. page width in points */
+
+ out << "\\begin{figure}[H]\n"
+ "\\begin{center}\n"
+ "\\leavevmode\n"
+ "\\includegraphics[width=" << QMIN(width/2,maxWidth)
+ << "pt]{" << baseName << "}\n"
+ "\\end{center}\n"
+ "\\end{figure}\n";
+ }
+
+ if (Config_getBool("DOT_CLEANUP")) thisDir.remove(baseName+".dot");
+
+ QDir::setCurrent(oldDir);
+ return baseName;
+
+
+}
+
+bool DotDirDeps::isTrivial() const
+{
+ return m_dir->depGraphIsTrivial();
+}
+
//-------------------------------------------------------------
void generateGraphLegend(const char *path)
diff --git a/src/dot.h b/src/dot.h
index 5c5ed22..477eba4 100644
--- a/src/dot.h
+++ b/src/dot.h
@@ -207,6 +207,14 @@ class DotDirDeps
public:
DotDirDeps(DirDef *dir);
~DotDirDeps();
+ bool isTrivial() const;
+ QCString writeGraph(QTextStream &out,
+ GraphOutputFormat format,
+ const char *path,
+ const char *relPath,
+ bool writeImageMap=TRUE);
+ private:
+ DirDef *m_dir;
};
void generateGraphLegend(const char *path);
diff --git a/src/doxygen.cpp b/src/doxygen.cpp
index 0e57ce1..607ff85 100644
--- a/src/doxygen.cpp
+++ b/src/doxygen.cpp
@@ -122,6 +122,7 @@ bool Doxygen::outputToWizard=FALSE;
QDict<int> * Doxygen::htmlDirMap = 0;
QCache<LookupInfo> Doxygen::lookupCache(20000,20000);
DirSDict Doxygen::directories(17);
+SDict<DirRelation> Doxygen::dirRelations(257);
static StringList inputFiles;
static StringDict excludeNameDict(1009); // sections
@@ -4738,6 +4739,7 @@ static void findMember(Entry *root,
NamespaceSDict::Iterator nsdi(*nnl);
for (nsdi.toFirst();(nnd=nsdi.current());++nsdi)
{
+ Debug::print(Debug::FindMembers,0," adding used namespace %s\n",nnd->qualifiedName().data());
nl->append(nnd->qualifiedName(),nnd);
}
}
@@ -4751,6 +4753,7 @@ static void findMember(Entry *root,
NamespaceSDict::Iterator nsdi(*fnl);
for (nsdi.toFirst();(fnd=nsdi.current());++nsdi)
{
+ Debug::print(Debug::FindMembers,0," adding used namespace %s\n",fnd->qualifiedName().data());
nl->append(fnd->qualifiedName(),fnd);
}
}
@@ -4766,6 +4769,7 @@ static void findMember(Entry *root,
Definition *ncd;
for (csdi.toFirst();(ncd=csdi.current());++csdi)
{
+ Debug::print(Debug::FindMembers,0," adding used class %s\n",ncd->qualifiedName().data());
cl->append(ncd->qualifiedName(),ncd);
}
}
@@ -4779,6 +4783,7 @@ static void findMember(Entry *root,
Definition *fcd;
for (csdi.toFirst();(fcd=csdi.current());++csdi)
{
+ Debug::print(Debug::FindMembers,0," adding used class %s\n",fcd->qualifiedName().data());
cl->append(fcd->qualifiedName(),fcd);
}
}
@@ -7330,10 +7335,7 @@ static void readFiles(BufStr &output)
bufPtr->addChar('\n'); /* to prevent problems under Windows ? */
- //if (!multiLineIsBrief)
- //{
- convertCppComments(&tempBuf,&output);
- //}
+ convertCppComments(&tempBuf,&output,fileName);
s=inputFiles.next();
//printf("-------> adding new line\n");
@@ -7553,6 +7555,126 @@ static void readFormulaRepository()
}
//----------------------------------------------------------------------------
+
+static QDict<void> aliasesProcessed;
+
+static QCString expandAliasesRec(const QCString s)
+{
+ QCString result;
+ static QRegExp cmdPat("[\\\\@][a-z_A-Z][a-z_A-Z0-9]*");
+ QCString value=s;
+ int i,p=0,l;
+ while ((i=cmdPat.match(value,p,&l))!=-1)
+ {
+ result+=value.mid(p,i-p);
+ QCString cmd=value.mid(i+1,l-1);
+ //printf("Found command '%s'\n",cmd.data());
+ QCString *aliasText=Doxygen::aliasDict.find(cmd);
+ if (aliasesProcessed.find(cmd)==0 && aliasText) // expand the alias
+ {
+ aliasesProcessed.insert(cmd,(void *)0x8);
+ result+=expandAliasesRec(*aliasText);
+ aliasesProcessed.remove(cmd);
+ }
+ else // command is not an alias
+ {
+ result+=value.mid(i,l);
+ }
+ p=i+l;
+ }
+ result+=value.right(value.length()-p);
+
+ //printf("expandAliases '%s'->'%s'\n",s.data(),result.data());
+ return result;
+}
+
+static void expandAliases()
+{
+ QDictIterator<QCString> adi(Doxygen::aliasDict);
+ QCString *s;
+ for (adi.toFirst();(s=adi.current());++adi)
+ {
+ aliasesProcessed.clear();
+ *s = expandAliasesRec(*s);
+ }
+}
+
+//----------------------------------------------------------------------------
+
+static void escapeAliases()
+{
+ QDictIterator<QCString> adi(Doxygen::aliasDict);
+ QCString *s;
+ for (adi.toFirst();(s=adi.current());++adi)
+ {
+ QCString value=*s,newValue;
+ int in,p=0;
+ // for each \n in the alias command value
+ while ((in=value.find("\\n",p))!=-1)
+ {
+ newValue+=value.mid(p,in-p);
+ // expand \n's except if \n is part of a built-in command.
+ if (value.mid(in,5)!="\\note" &&
+ value.mid(in,5)!="\\name" &&
+ value.mid(in,10)!="\\namespace" &&
+ value.mid(in,14)!="\\nosubgrouping"
+ )
+ {
+ newValue+="\\_linebr ";
+ }
+ else
+ {
+ newValue+="\\n";
+ }
+ p=in+2;
+ }
+ newValue+=value.mid(p,value.length()-p);
+ *s=newValue;
+ //printf("Alias %s has value %s\n",adi.currentKey().data(),s->data());
+ }
+}
+
+//----------------------------------------------------------------------------
+
+static void readAliases()
+{
+ // add aliases to a dictionary
+ Doxygen::aliasDict.setAutoDelete(TRUE);
+ QStrList &aliasList = Config_getList("ALIASES");
+ const char *s=aliasList.first();
+ while (s)
+ {
+ if (Doxygen::aliasDict[s]==0)
+ {
+ QCString alias=s;
+ int i=alias.find('=');
+ if (i>0)
+ {
+ QCString name=alias.left(i).stripWhiteSpace();
+ QCString value=alias.right(alias.length()-i-1);
+ //printf("Alias: found name=`%s' value=`%s'\n",name.data(),value.data());
+ if (!name.isEmpty())
+ {
+ QCString *dn=Doxygen::aliasDict[name];
+ if (dn==0) // insert new alias
+ {
+ Doxygen::aliasDict.insert(name,new QCString(value));
+ }
+ else // overwrite previous alias
+ {
+ *dn=value;
+ }
+ }
+ }
+ }
+ s=aliasList.next();
+ }
+ expandAliases();
+ escapeAliases();
+ aliasesProcessed.clear();
+}
+
+//----------------------------------------------------------------------------
// print the usage of doxygen
static void usage(const char *name)
@@ -7620,6 +7742,8 @@ void initDoxygen()
Doxygen::memGrpInfoDict.setAutoDelete(TRUE);
Doxygen::tagDestinationDict.setAutoDelete(TRUE);
Doxygen::lookupCache.setAutoDelete(TRUE);
+ Doxygen::directories.setAutoDelete(TRUE);
+ Doxygen::dirRelations.setAutoDelete(TRUE);
}
void cleanUpDoxygen()
@@ -8088,60 +8212,8 @@ void parseInput()
s=expandAsDefinedList.next();
}
- // add aliases to a dictionary
- Doxygen::aliasDict.setAutoDelete(TRUE);
- QStrList &aliasList = Config_getList("ALIASES");
- s=aliasList.first();
- while (s)
- {
- if (Doxygen::aliasDict[s]==0)
- {
- QCString alias=s;
- int i=alias.find('=');
- if (i>0)
- {
- QCString name=alias.left(i).stripWhiteSpace();
- QCString value=alias.right(alias.length()-i-1);
- QCString newValue;
- int in,p=0;
- // for each \n in the alias command value
- while ((in=value.find("\\n",p))!=-1)
- {
- newValue+=value.mid(p,in-p);
- // expand \n's except if \n is part of a built-in command.
- if (value.mid(in,5)!="\\note" &&
- value.mid(in,5)!="\\name" &&
- value.mid(in,10)!="\\namespace" &&
- value.mid(in,14)!="\\nosubgrouping"
- )
- {
- newValue+="\n";
- }
- else
- {
- newValue+="\\n";
- }
- p=in+2;
- }
- newValue+=value.mid(p,value.length()-p);
- value=newValue;
- //printf("Alias: found name=`%s' value=`%s'\n",name.data(),value.data());
- if (!name.isEmpty())
- {
- QCString *dn=Doxygen::aliasDict[name];
- if (dn==0) // insert new alias
- {
- Doxygen::aliasDict.insert(name,new QCString(value));
- }
- else // overwrite previous alias
- {
- *dn=value;
- }
- }
- }
- }
- s=aliasList.next();
- }
+ // read aliases and store them in a dictionary
+ readAliases();
/**************************************************************************
* Handle Tag Files *
@@ -8448,8 +8520,11 @@ void parseInput()
msg("Adding todo/test/bug list items...\n");
addListReferences();
- msg("Computing dependencies between directories...\n");
- computeDirDependencies();
+ if (Config_getBool("SHOW_DIRECTORIES"))
+ {
+ msg("Computing dependencies between directories...\n");
+ computeDirDependencies();
+ }
}
void generateOutput()
diff --git a/src/doxygen.h b/src/doxygen.h
index a196432..0257fb2 100644
--- a/src/doxygen.h
+++ b/src/doxygen.h
@@ -115,6 +115,7 @@ class Doxygen
static QDict<int> *htmlDirMap;
static QCache<LookupInfo> lookupCache;
static DirSDict directories;
+ static SDict<DirRelation> dirRelations;
};
void initDoxygen();
diff --git a/src/htmlgen.cpp b/src/htmlgen.cpp
index 8223562..757c72c 100644
--- a/src/htmlgen.cpp
+++ b/src/htmlgen.cpp
@@ -319,8 +319,16 @@ static const char *defaultStyleSheet =
"}\n"
"a:visited {\n"
" color: #3D2185;\n"
+"}\n"
+".dirtab { padding: 4px;\n"
+" border-collapse: collapse;\n"
+" border: 1px solid #b0b0b0;\n"
+"}\n"
+"TH.dirtab { background: #eeeeff;\n"
+" font-weight: bold;\n"
"}\n";
+
static QCString g_header;
static QCString g_footer;
@@ -1246,6 +1254,15 @@ void HtmlGenerator::endCallGraph(DotCallGraph &g)
g.writeGraph(t,BITMAP,dir,relPath);
}
+void HtmlGenerator::startDirDepGraph()
+{
+}
+
+void HtmlGenerator::endDirDepGraph(DotDirDeps &g)
+{
+ g.writeGraph(t,BITMAP,dir,relPath);
+}
+
void HtmlGenerator::writeGraphicalHierarchy(DotGfxHierarchyTable &g)
{
g.writeGraph(t,dir);
diff --git a/src/htmlgen.h b/src/htmlgen.h
index ee2112a..ebaf4fa 100644
--- a/src/htmlgen.h
+++ b/src/htmlgen.h
@@ -192,6 +192,8 @@ class HtmlGenerator : public OutputGenerator
void endInclDepGraph(DotInclDepGraph &g);
void startCallGraph();
void endCallGraph(DotCallGraph &g);
+ void startDirDepGraph();
+ void endDirDepGraph(DotDirDeps &g);
void writeGraphicalHierarchy(DotGfxHierarchyTable &g);
void startTextBlock(bool) {}
diff --git a/src/htmlhelp.cpp b/src/htmlhelp.cpp
index a90a919..0d5b9c8 100644
--- a/src/htmlhelp.cpp
+++ b/src/htmlhelp.cpp
@@ -174,7 +174,27 @@ void HtmlHelpIndex::writeFields(QTextStream &t)
{ // finish old list at level 2
if (level2Started) t << " </UL>" << endl;
level2Started=FALSE;
-
+
+ // <Antony>
+ // Added this code so that an item with only one subitem is written
+ // without any subitem.
+ // For example:
+ // a1, b1 -> will create only a1, not separate subitem for b1
+ // a2, b2
+ // a2, b3
+ QCString nextLevel1;
+ IndexField* fnext = ++ifli;
+ if (fnext)
+ {
+ nextLevel1 = fnext->name.left(fnext->name.find('?'));
+ --ifli;
+ }
+ if (level1 != nextLevel1)
+ {
+ level2 = "";
+ }
+ // </Antony>
+
if (level2.isEmpty())
{
t << " <LI><OBJECT type=\"text/sitemap\">";
@@ -189,7 +209,9 @@ void HtmlHelpIndex::writeFields(QTextStream &t)
if (f->link)
{
t << " <LI><OBJECT type=\"text/sitemap\">";
- t << "<param name=\"Local\" value=\"" << f->url << Doxygen::htmlFileExtension << "\">";
+ t << "<param name=\"Local\" value=\"" << f->url << Doxygen::htmlFileExtension;
+ if (!f->anchor.isEmpty()) t << "#" << f->anchor;
+ t << "\">";
t << "<param name=\"Name\" value=\"" << level1 << "\">"
"</OBJECT>\n";
}
@@ -530,6 +552,6 @@ void HtmlHelp::addIndexItem(const char *level1, const char *level2,
const char *ref, const char *anchor)
{
index->addItem(level1,level2,ref,anchor,TRUE);
- index->addItem(level2,level1,ref,anchor,FALSE);
+ index->addItem(level2,level1,ref,anchor,TRUE);
}
diff --git a/src/latexgen.cpp b/src/latexgen.cpp
index 87dca72..70630ae 100644
--- a/src/latexgen.cpp
+++ b/src/latexgen.cpp
@@ -1457,6 +1457,15 @@ void LatexGenerator::endCallGraph(DotCallGraph &g)
g.writeGraph(t,EPS,Config_getString("LATEX_OUTPUT"),relPath);
}
+void LatexGenerator::startDirDepGraph()
+{
+}
+
+void LatexGenerator::endDirDepGraph(DotDirDeps &g)
+{
+ g.writeGraph(t,EPS,Config_getString("LATEX_OUTPUT"),relPath);
+}
+
void LatexGenerator::startDescription()
{
t << "\\begin{description}" << endl;
diff --git a/src/latexgen.h b/src/latexgen.h
index faf9f98..237e4f0 100644
--- a/src/latexgen.h
+++ b/src/latexgen.h
@@ -185,6 +185,8 @@ class LatexGenerator : public OutputGenerator
void endInclDepGraph(DotInclDepGraph &);
void startCallGraph();
void endCallGraph(DotCallGraph &);
+ void startDirDepGraph();
+ void endDirDepGraph(DotDirDeps &g);
void writeGraphicalHierarchy(DotGfxHierarchyTable &) {}
void startTextBlock(bool) {}
diff --git a/src/mangen.h b/src/mangen.h
index ddc5adb..e4a145b 100644
--- a/src/mangen.h
+++ b/src/mangen.h
@@ -231,6 +231,8 @@ class ManGenerator : public OutputGenerator
void endInclDepGraph(DotInclDepGraph &) {}
void startCallGraph() {}
void endCallGraph(DotCallGraph &) {}
+ void startDirDepGraph() {}
+ void endDirDepGraph(DotDirDeps &) {}
void writeGraphicalHierarchy(DotGfxHierarchyTable &) {}
void startTextBlock(bool) {}
diff --git a/src/outputgen.h b/src/outputgen.h
index 8d02b82..16e56a8 100644
--- a/src/outputgen.h
+++ b/src/outputgen.h
@@ -30,6 +30,7 @@ class ClassDiagram;
class DotClassGraph;
class DotInclDepGraph;
class DotCallGraph;
+class DotDirDeps;
class DotGfxHierarchyTable;
class DocNode;
class MemberDef;
@@ -339,6 +340,8 @@ class OutputGenerator : public BaseOutputDocInterface
virtual void endInclDepGraph(DotInclDepGraph &g) = 0;
virtual void startCallGraph() = 0;
virtual void endCallGraph(DotCallGraph &g) = 0;
+ virtual void startDirDepGraph() = 0;
+ virtual void endDirDepGraph(DotDirDeps &g) = 0;
virtual void writeGraphicalHierarchy(DotGfxHierarchyTable &g) = 0;
//virtual void startQuickIndexItem(const char *s,const char *l) = 0;
//virtual void endQuickIndexItem() = 0;
diff --git a/src/outputlist.cpp b/src/outputlist.cpp
index 248e9b9..a0878f3 100644
--- a/src/outputlist.cpp
+++ b/src/outputlist.cpp
@@ -266,6 +266,7 @@ FORALL1(int a1,a1)
FORALL1(DotClassGraph &a1,a1)
FORALL1(DotInclDepGraph &a1,a1)
FORALL1(DotCallGraph &a1,a1)
+FORALL1(DotDirDeps &a1,a1)
FORALL1(DotGfxHierarchyTable &a1,a1)
FORALL1(SectionTypes a1,a1)
#if defined(HAS_BOOL_TYPE) || defined(Q_HAS_BOOL_TYPE)
diff --git a/src/outputlist.h b/src/outputlist.h
index a4be838..12c76ff 100644
--- a/src/outputlist.h
+++ b/src/outputlist.h
@@ -34,6 +34,7 @@
class ClassDiagram;
class DotClassGraph;
+class DotDirDeps;
class DotInclDepGraph;
class DotGfxHierarchyTable;
class SectionDict;
@@ -322,6 +323,10 @@ class OutputList : public OutputDocInterface
{ forall(&OutputGenerator::startCallGraph); }
void endCallGraph(DotCallGraph &g)
{ forall(&OutputGenerator::endCallGraph,g); }
+ void startDirDepGraph()
+ { forall(&OutputGenerator::startDirDepGraph); }
+ void endDirDepGraph(DotDirDeps &g)
+ { forall(&OutputGenerator::endDirDepGraph,g); }
void writeGraphicalHierarchy(DotGfxHierarchyTable &g)
{ forall(&OutputGenerator::writeGraphicalHierarchy,g); }
void startTextBlock(bool dense=FALSE)
@@ -387,6 +392,7 @@ class OutputList : public OutputDocInterface
FORALLPROTO1(DotClassGraph &);
FORALLPROTO1(DotInclDepGraph &);
FORALLPROTO1(DotCallGraph &);
+ FORALLPROTO1(DotDirDeps &);
FORALLPROTO1(DotGfxHierarchyTable &);
FORALLPROTO1(SectionTypes);
#if defined(HAS_BOOL_TYPE) || defined(Q_HAS_BOOL_TYPE)
diff --git a/src/pre.l b/src/pre.l
index 8266c1c..99d581c 100644
--- a/src/pre.l
+++ b/src/pre.l
@@ -1079,7 +1079,7 @@ static void readIncludeFile(const QCString &inc)
if (g_yyFileDef)
{
//printf("Adding include dependency %s->%s\n",oldFileDef->name().data(),incFileName.data());
- g_yyFileDef->addIncludedByDependency(oldFileDef,oldFileDef->name(),localInclude,g_isImported);
+ g_yyFileDef->addIncludedByDependency(oldFileDef,oldFileDef->docName(),localInclude,g_isImported);
}
}
FileState *fs=new FileState;
@@ -1114,7 +1114,7 @@ static void readIncludeFile(const QCString &inc)
if (fd)
{
//printf("Adding include dependency (2) %s->%s ambig=%d\n",oldFileDef->name().data(),fd->name().data(),ambig);
- fd->addIncludedByDependency(oldFileDef,oldFileDef->name(),localInclude,g_isImported);
+ fd->addIncludedByDependency(oldFileDef,oldFileDef->docName(),localInclude,g_isImported);
}
}
if (Debug::isFlagSet(Debug::Preprocessor))
diff --git a/src/rtfgen.cpp b/src/rtfgen.cpp
index f243d1b..ad240f3 100644
--- a/src/rtfgen.cpp
+++ b/src/rtfgen.cpp
@@ -2258,6 +2258,28 @@ void RTFGenerator::endCallGraph(DotCallGraph &g)
DBG_RTF(t << "{\\comment (endCallGraph)}" << endl)
}
+void RTFGenerator::startDirDepGraph()
+{
+ DBG_RTF(t << "{\\comment (startDirDepGraph)}" << endl)
+}
+
+void RTFGenerator::endDirDepGraph(DotDirDeps &g)
+{
+ newParagraph();
+
+ QCString fileName = g.writeGraph(t,BITMAP,Config_getString("RTF_OUTPUT"),
+ relPath,FALSE);
+
+ // display the file
+ t << "{" << endl;
+ t << rtf_Style_Reset << endl;
+ t << "\\par\\pard \\qc {\\field\\flddirty {\\*\\fldinst INCLUDEPICTURE \"";
+ t << fileName << "." << Config_getEnum("DOT_IMAGE_FORMAT");
+ t << "\" \\\\d \\\\*MERGEFORMAT}{\\fldrslt IMAGE}}\\par" << endl;
+ t << "}" << endl;
+ DBG_RTF(t << "{\\comment (endDirDepGraph)}" << endl)
+}
+
/** Tests the integrity of the result by counting brackets.
*
*/
diff --git a/src/rtfgen.h b/src/rtfgen.h
index b4c1dac..1c92bee 100644
--- a/src/rtfgen.h
+++ b/src/rtfgen.h
@@ -227,6 +227,8 @@ class RTFGenerator : public OutputGenerator
void endInclDepGraph(DotInclDepGraph &);
void startCallGraph();
void endCallGraph(DotCallGraph &);
+ void startDirDepGraph();
+ void endDirDepGraph(DotDirDeps &g);
void writeGraphicalHierarchy(DotGfxHierarchyTable &) {}
void startMemberGroupHeader(bool);
diff --git a/src/scanner.l b/src/scanner.l
index 9cd310e..8dbd70c 100644
--- a/src/scanner.l
+++ b/src/scanner.l
@@ -5612,18 +5612,22 @@ PHPKW ("require"|"require_once"|"include"|"include_once"|"echo")[^a-zA-Z0-9_;]
unput('/');unput('*');
BEGIN( tmpDocType );
}
+<Doc,JavaDoc,LineDoc,ClassDocBrief,AfterDocBrief,AfterDocLine,CopyArgCommentLine,ClassDoc,PageDoc,AfterDoc,CopyArgComment>"\\_linebr " {
+ // used to compensate for misalignments due to \n's inside ALIASES
+ current->doc += '\n';
+ }
<Doc,JavaDoc,ClassDoc,PageDoc,ReadFormulaShort,ReadFormulaLong,AfterDoc>^{B}*(("//"{B}*)?)"*"+[ \t]*"-"("#")?{B}+ {
- current->doc += yytext;
+ current->doc += yytext;
}
<Doc,JavaDoc,ClassDoc,PageDoc,ReadFormulaShort,ReadFormulaLong,AfterDoc>^{B}*(("//"{B}*)?)"*"+[ \t]*"."{B}*\n {
- current->doc += yytext;
- yyLineNr++;
+ current->doc += yytext;
+ yyLineNr++;
}
<ClassDocBrief,AfterDocBrief>^{B}*(("//"{B}*)?)"*"+[ \t]*"-"("#")?{B}+ {
- current->brief += "-";
+ current->brief += "-";
}
<ClassDocBrief,AfterDocBrief>^{B}*(("//"{B}*)?)"*"+[ \t]*"."{B}*\n {
- current->brief += "."; yyLineNr++;
+ current->brief += "."; yyLineNr++;
}
<Doc,JavaDoc,ClassDoc,PageDoc,ReadFormulaShort,ReadFormulaLong,ClassDocBrief,AfterDoc,AfterDocBrief>^{B}*(("//"{B}*)?)"*"+/[^/]
<Doc,JavaDoc,ClassDoc,PageDoc,ReadFormulaShort,ReadFormulaLong,ClassDocBrief,AfterDoc,AfterDocBrief>^{B}*(("//"{B}*)?)"*"+{B}+ {
diff --git a/src/sortdict.h b/src/sortdict.h
index 3b8be02..5a04a11 100644
--- a/src/sortdict.h
+++ b/src/sortdict.h
@@ -234,7 +234,7 @@ class SDict
/*! Returns the number of items stored in the dictionary
*/
- int count()
+ int count() const
{
return m_list->count();
}
diff --git a/src/util.cpp b/src/util.cpp
index 6b011bd..1f625c6 100644
--- a/src/util.cpp
+++ b/src/util.cpp
@@ -45,6 +45,7 @@
#include "groupdef.h"
#include "reflist.h"
#include "pagedef.h"
+#include "debug.h"
#if !defined(_WIN32) || defined(__CYGWIN__)
#include <unistd.h>
@@ -140,7 +141,7 @@ int iSystem(const char *command,const char *args,bool isBatchFile)
}
fullCmd += " ";
fullCmd += args;
- //printf("iSystem: Executing %s\n",fullCmd.data());
+ Debug::print(Debug::ExtCmd,0,"Executing external command \"%s\"\n",fullCmd.data());
#if !defined(_WIN32) || defined(__CYGWIN__)
isBatchFile=isBatchFile;
@@ -2597,6 +2598,172 @@ bool matchArguments(ArgumentList *srcAl,ArgumentList *dstAl,
return TRUE; // all arguments match
}
+static QCString extractCanonicalType(Definition *d,FileDef *fs,const Argument *arg)
+{
+ QCString type = arg->type;
+ QCString name = arg->name;
+ if ((type=="const" || type=="volatile") && !name.isEmpty())
+ { // name is part of type => correct
+ type+=" ";
+ type+=name;
+ }
+ if (name=="const" || name=="volatile")
+ { // name is part of type => correct
+ if (!type.isEmpty()) type+=" ";
+ type+=name;
+ }
+
+ // strip const and volatile keywords that are not relatevant for the type
+ stripIrrelevantConstVolatile(type);
+
+ // strip leading keywords
+ if (type.left(6)=="class ") type=type.right(type.length()-6);
+ else if (type.left(7)=="struct ") type=type.right(type.length()-7);
+ else if (type.left(6)=="union ") type=type.right(type.length()-6);
+ else if (type.left(5)=="enum ") type=type.right(type.length()-5);
+ else if (type.left(9)=="typename ") type=type.right(type.length()-9);
+
+ static QRegExp id("[a-z_A-Z][a-z_A-Z0-9]*");
+
+
+ QCString canType;
+ int i,p=0,l;
+ while ((i=id.match(type,p,&l))) // foreach identifier in the type
+ {
+ canType += type.mid(p,i-p);
+ QCString word = type.mid(i,l);
+ ClassDef *cd = getResolvedClass(d,fs,word);
+ if (cd)
+ {
+ canType+=cd->qualifiedName();
+ }
+ else
+ {
+ canType+=word;
+ }
+ p=i+l;
+ }
+ canType += type.right(type.length()-p);
+
+ return removeRedundantWhiteSpace(canType);
+}
+
+static bool matchArgument2(
+ Definition *srcScope,FileDef *srcFileScope,const Argument *srcA,
+ Definition *dstScope,FileDef *dstFileScope,const Argument *dstA
+ )
+{
+ //printf("match argument start `%s|%s' <-> `%s|%s' using nsp=%p class=%p\n",
+ // srcA->type.data(),srcA->name.data(),
+ // dstA->type.data(),dstA->name.data(),
+ // usingNamespaces,
+ // usingClasses);
+
+ if (srcA->array!=dstA->array) // nomatch for char[] against char
+ {
+ NOMATCH
+ return FALSE;
+ }
+
+ QCString canonicalSrcType = extractCanonicalType(srcScope,srcFileScope,srcA);
+ QCString canonicalDstType = extractCanonicalType(dstScope,dstFileScope,dstA);
+
+ if (canonicalSrcType==canonicalDstType)
+ {
+ MATCH
+ return TRUE;
+ }
+ else
+ {
+ NOMATCH
+ return FALSE;
+ }
+}
+
+
+// new algorithm for argument matching
+bool matchArguments2(Definition *srcScope,FileDef *srcFileScope,ArgumentList *srcAl,
+ Definition *dstScope,FileDef *dstFileScope,ArgumentList *dstAl,
+ bool checkCV
+ )
+{
+ ASSERT(srcScope!=0 && dstScope!=0);
+
+ if (srcAl==0 || dstAl==0)
+ {
+ bool match = srcAl==dstAl; // at least one of the members is not a function
+ if (match)
+ {
+ MATCH
+ return TRUE;
+ }
+ else
+ {
+ NOMATCH
+ return FALSE;
+ }
+ }
+
+ // handle special case with void argument
+ if ( srcAl->count()==0 && dstAl->count()==1 &&
+ dstAl->getFirst()->type=="void" )
+ { // special case for finding match between func() and func(void)
+ Argument *a=new Argument;
+ a->type = "void";
+ srcAl->append(a);
+ MATCH
+ return TRUE;
+ }
+ if ( dstAl->count()==0 && srcAl->count()==1 &&
+ srcAl->getFirst()->type=="void" )
+ { // special case for finding match between func(void) and func()
+ Argument *a=new Argument;
+ a->type = "void";
+ dstAl->append(a);
+ MATCH
+ return TRUE;
+ }
+
+ if (srcAl->count() != dstAl->count())
+ {
+ NOMATCH
+ return FALSE; // different number of arguments -> no match
+ }
+
+ if (checkCV)
+ {
+ if (srcAl->constSpecifier != dstAl->constSpecifier)
+ {
+ NOMATCH
+ return FALSE; // one member is const, the other not -> no match
+ }
+ if (srcAl->volatileSpecifier != dstAl->volatileSpecifier)
+ {
+ NOMATCH
+ return FALSE; // one member is volatile, the other not -> no match
+ }
+ }
+
+ // so far the argument list could match, so we need to compare the types of
+ // all arguments.
+ ArgumentListIterator srcAli(*srcAl),dstAli(*dstAl);
+ Argument *srcA,*dstA;
+ for (;(srcA=srcAli.current(),dstA=dstAli.current());++srcAli,++dstAli)
+ {
+ if (!matchArgument2(srcScope,srcFileScope,srcA,
+ dstScope,dstFileScope,dstA)
+ )
+ {
+ NOMATCH
+ return FALSE;
+ }
+ }
+ MATCH
+ return TRUE; // all arguments match
+}
+
+
+
// merges the initializer of two argument lists
// pre: the types of the arguments in the list should match.
void mergeArguments(ArgumentList *srcAl,ArgumentList *dstAl,bool forceNameOverwrite)
@@ -2934,7 +3101,7 @@ bool getDefs(const QCString &scName,const QCString &memberName,
{ // namespace is found
bool match=TRUE;
ArgumentList *argList=0;
- if (args)
+ if (args && strcmp(args,"()")!=0)
{
argList=new ArgumentList;
stringToArgumentList(args,argList);
@@ -3001,10 +3168,10 @@ bool getDefs(const QCString &scName,const QCString &memberName,
(gd && gd->isLinkable()) || (fd && fd->isLinkable())
)
{
- //printf("fd=%p gd=%p inGroup=`%d' args=`%s'\n",fd,gd,inGroup,args);
+ //printf(" fd=%p gd=%p args=`%s'\n",fd,gd,args);
bool match=TRUE;
ArgumentList *argList=0;
- if (args && !md->isDefine())
+ if (args && !md->isDefine() && strcmp(args,"()")!=0)
{
argList=new ArgumentList;
stringToArgumentList(args,argList);