diff options
author | Dimitri van Heesch <dimitri@stack.nl> | 2004-11-14 19:44:16 (GMT) |
---|---|---|
committer | Dimitri van Heesch <dimitri@stack.nl> | 2004-11-14 19:44:16 (GMT) |
commit | 05930245579c006f2b5bfca53e0a1976d682f9b8 (patch) | |
tree | 181f9ebfd0706ecca5898b169bffa8bc4f5486cc /src | |
parent | 62d6edc6d0b299e93384e678748b635eb1bfe9b9 (diff) | |
download | Doxygen-05930245579c006f2b5bfca53e0a1976d682f9b8.zip Doxygen-05930245579c006f2b5bfca53e0a1976d682f9b8.tar.gz Doxygen-05930245579c006f2b5bfca53e0a1976d682f9b8.tar.bz2 |
Release-1.3.9.1-20041114
Diffstat (limited to 'src')
-rw-r--r-- | src/commentcnv.h | 3 | ||||
-rw-r--r-- | src/commentcnv.l | 207 | ||||
-rw-r--r-- | src/config.l | 9 | ||||
-rw-r--r-- | src/debug.cpp | 2 | ||||
-rw-r--r-- | src/debug.h | 3 | ||||
-rw-r--r-- | src/dirdef.cpp | 216 | ||||
-rw-r--r-- | src/dirdef.h | 52 | ||||
-rw-r--r-- | src/docparser.cpp | 4 | ||||
-rw-r--r-- | src/dot.cpp | 194 | ||||
-rw-r--r-- | src/dot.h | 8 | ||||
-rw-r--r-- | src/doxygen.cpp | 195 | ||||
-rw-r--r-- | src/doxygen.h | 1 | ||||
-rw-r--r-- | src/htmlgen.cpp | 17 | ||||
-rw-r--r-- | src/htmlgen.h | 2 | ||||
-rw-r--r-- | src/htmlhelp.cpp | 28 | ||||
-rw-r--r-- | src/latexgen.cpp | 9 | ||||
-rw-r--r-- | src/latexgen.h | 2 | ||||
-rw-r--r-- | src/mangen.h | 2 | ||||
-rw-r--r-- | src/outputgen.h | 3 | ||||
-rw-r--r-- | src/outputlist.cpp | 1 | ||||
-rw-r--r-- | src/outputlist.h | 6 | ||||
-rw-r--r-- | src/pre.l | 4 | ||||
-rw-r--r-- | src/rtfgen.cpp | 22 | ||||
-rw-r--r-- | src/rtfgen.h | 2 | ||||
-rw-r--r-- | src/scanner.l | 14 | ||||
-rw-r--r-- | src/sortdict.h | 2 | ||||
-rw-r--r-- | src/util.cpp | 175 |
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(" / "); } 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(" / "); + } + 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(" / "); + } + 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()+" → "+ + 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) @@ -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) @@ -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); |