summaryrefslogtreecommitdiffstats
path: root/src/util.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/util.cpp')
-rw-r--r--src/util.cpp2174
1 files changed, 2174 insertions, 0 deletions
diff --git a/src/util.cpp b/src/util.cpp
new file mode 100644
index 0000000..6b4578d
--- /dev/null
+++ b/src/util.cpp
@@ -0,0 +1,2174 @@
+/******************************************************************************
+ *
+ * $Id$
+ *
+ * Copyright (C) 1997-1999 by Dimitri van Heesch.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation under the terms of the GNU General Public License is hereby
+ * granted. No representations are made about the suitability of this software
+ * for any purpose. It is provided "as is" without express or implied warranty.
+ * See the GNU General Public License for more details.
+ *
+ * All output generated with Doxygen is not covered by this license.
+ *
+ */
+
+#include <stdlib.h>
+#include <qregexp.h>
+#include <qstring.h>
+#include <ctype.h>
+#include "util.h"
+#include "message.h"
+#include "classdef.h"
+#include "filedef.h"
+#include "doxygen.h"
+#include "scanner.h"
+#include "outputlist.h"
+#include "defargs.h"
+#include "language.h"
+#include "config.h"
+
+// an inheritance tree of depth of 100000 should be enough for everyone :-)
+const int maxInheritanceDepth = 100000;
+
+bool isId(char c)
+{
+ return c=='_' || isalnum(c);
+}
+
+
+// try to determine if this files is a source or a header file by looking
+// at the extension (5 variations are allowed in both upper and lower case)
+// If anyone knows or uses another extension please let me know :-)
+int guessSection(const char *name)
+{
+ QString n=((QString)name).lower();
+ if (n.right(2)==".c" ||
+ n.right(3)==".cc" ||
+ n.right(4)==".cxx" ||
+ n.right(4)==".cpp" ||
+ n.right(4)==".c++"
+ ) return Entry::SOURCE_SEC;
+ if (n.right(2)==".h" ||
+ n.right(3)==".hh" ||
+ n.right(4)==".hxx" ||
+ n.right(4)==".hpp" ||
+ n.right(4)==".h++"
+ ) return Entry::HEADER_SEC;
+ return 0;
+}
+
+
+//QString resolveDefines(const char *n)
+//{
+// return n;
+// if (n)
+// {
+// Define *def=defineDict[n];
+// if (def && def->nargs==0 && !def->definition.isNull())
+// {
+// return def->definition;
+// }
+// return n;
+// }
+// return 0;
+//}
+
+QString resolveTypedefs(const QString &n)
+{
+ QString *subst=typedefDict[n];
+ if (subst && !subst->isNull())
+ {
+ return *subst;
+ }
+ else
+ {
+ return n;
+ }
+}
+
+ClassDef *getClass(const char *name)
+{
+ if (!name) return 0;
+ //QString key=resolveTypedefs(resolveDefines(name));
+ //Define *def=defineDict[key];
+ //if (def && def->nargs==0 && def->definition.length()>0) // normal define
+ // key=def->definition; // use substitution
+
+ return classDict[resolveTypedefs(name)];
+}
+
+QString removeRedundantWhiteSpace(const QString &s)
+{
+ if (s.length()==0) return s;
+ QString result;
+ uint i;
+ for (i=0;i<s.length();i++)
+ {
+ char c=s.at(i);
+ if (c!=' ' ||
+ (i!=0 && i!=s.length()-1 && isId(s.at(i-1)) && isId(s.at(i+1)))
+ )
+ {
+ if ((c=='*' || c=='&') &&
+ result.length()>0 && isId(result.at(result.length()-1))
+ ) result+=' ';
+ result+=c;
+ }
+ }
+ return result;
+}
+
+void writeTemplatePrefix(OutputList &ol,ArgumentList *al)
+{
+ ol.docify("template<");
+ Argument *a=al->first();
+ while (a)
+ {
+ ol.docify(a->type);
+ ol.docify(a->name);
+ if (a->defval.length()!=0)
+ {
+ ol.docify(" = ");
+ ol.docify(a->defval);
+ }
+ a=al->next();
+ if (a) ol.docify(", ");
+ }
+ ol.docify("> ");
+ bool latexEnabled = ol.isEnabled(OutputGenerator::Latex);
+ bool manEnabled = ol.isEnabled(OutputGenerator::Man);
+ if (latexEnabled) ol.disable(OutputGenerator::Latex);
+ if (manEnabled) ol.disable(OutputGenerator::Man);
+ ol.lineBreak();
+ if (latexEnabled) ol.enable(OutputGenerator::Latex);
+ if (manEnabled) ol.enable(OutputGenerator::Man);
+}
+
+QString addTemplateNames(const QString &s,const QString &n,const QString &t)
+{
+ //printf("addTemplateNames(%s)\n",s.data());
+ QString result;
+ QString clRealName=n;
+ int p=0,i;
+ if ((i=clRealName.find('<'))!=-1)
+ {
+ clRealName=clRealName.left(i); // strip template specialization
+ }
+ while ((i=s.find(clRealName,p))!=-1)
+ {
+ result+=s.mid(p,i-p);
+ uint j=clRealName.length()+i;
+ if (s.length()==j || (s.at(j)!='<' && !isId(s.at(j))))
+ { // add template names
+ //printf("Adding %s+%s\n",clRealName.data(),t.data());
+ result+=clRealName+t;
+ }
+ else
+ { // template names already present
+ //printf("Adding %s\n",clRealName.data());
+ result+=clRealName;
+ }
+ p=i+clRealName.length();
+ }
+ result+=s.right(s.length()-p);
+ //printf("result=%s\n",result.data());
+ return result;
+}
+
+static void linkifyText(OutputList &ol,const char *clName,const char *name,const char *text)
+{
+ //printf("class %s name %s Text: %s\n",clName,name,text);
+ QRegExp regExp("[a-z_A-Z0-9:<>]+");
+ QString txtStr=text;
+ OutputList result(&ol);
+ int matchLen;
+ int index=0;
+ int newIndex;
+ int skipIndex=0;
+ // read a word from the text string
+ while ((newIndex=regExp.match(txtStr,index,&matchLen))!=-1)
+ {
+ // add non-word part to the result
+ result.docify(txtStr.mid(skipIndex,newIndex-skipIndex));
+ // get word from string
+ QString word=txtStr.mid(newIndex,matchLen);
+ ClassDef *cd=0;
+ FileDef *fd=0;
+ MemberDef *md=0;
+
+ // check if `word' is a documented class name
+ if (word.length()>0 && word!=name && word!=clName)
+ {
+ if ((cd=getClass(word)))
+ {
+ // add link to the result
+ if (cd->isVisible())
+ {
+ result.writeObjectLink(cd->getReference(),cd->classFile(),0,word);
+ }
+ else
+ {
+ result.docify(word);
+ }
+ }
+ else if (getDefs(word,clName,0,md,cd,fd) && md->hasDocumentation())
+ {
+ if (cd && cd->isVisible() && !md->isFunction()) // word is a member of cd
+ {
+ result.writeObjectLink(cd->getReference(),
+ cd->classFile(),md->anchor(),word);
+ }
+ else if (fd && fd->hasDocumentation()) // word is a global in file fd
+ {
+ result.writeObjectLink(fd->getReference(),
+ fd->diskName(),md->anchor(),word);
+ }
+ else // add word to the result
+ {
+ result.docify(word);
+ }
+ }
+ else // add word to the result
+ {
+ result.docify(word);
+ }
+ }
+ else // add word to the result
+ {
+ result.docify(word);
+ }
+ // set next start point in the string
+ skipIndex=index=newIndex+matchLen;
+ }
+ // add last part of the string to the result.
+ result.docify(txtStr.right(txtStr.length()-skipIndex));
+ //printf("linkify: %s\n",result.data());
+ ol+=result;
+}
+
+static void writeDefArgumentList(OutputList &ol,ClassDef *cd,
+ const QString &scopeName,MemberDef *md)
+{
+ ArgumentList *argList=md->argumentList();
+ if (argList==0) return; // member has no function like argument list
+ ol.docify(" ("); // start argument list
+ Argument *a=argList->first();
+ QString cName;
+ if (cd && cd->templateArguments())
+ {
+ cName=cd->getTemplateNameString();
+ }
+ while (a)
+ {
+ QRegExp re(")(");
+ int vp;
+ if ((vp=a->type.find(re))!=-1) // argument type is a function pointer
+ {
+ QString n=a->type.left(vp);
+ if (cName.length()>0) n=addTemplateNames(n,cd->name(),cName);
+ linkifyText(ol,scopeName,md->name(),n);
+ }
+ else // non-function pointer type
+ {
+ QString n=a->type;
+ if (cName.length()>0) n=addTemplateNames(n,cd->name(),cName);
+ linkifyText(ol,scopeName,md->name(),n);
+ }
+ if (a->name.length()>0) // argument has a name
+ {
+ ol.docify(" ");
+ ol.disable(OutputGenerator::Man);
+ ol.startEmphasis();
+ ol.enable(OutputGenerator::Man);
+ ol.docify(a->name);
+ ol.disable(OutputGenerator::Man);
+ ol.endEmphasis();
+ ol.enable(OutputGenerator::Man);
+ }
+ if (vp!=-1) // write the part of the argument type
+ // that comes after the name
+ {
+ linkifyText(ol,scopeName,md->name(),a->type.right(a->type.length()-vp));
+ }
+ if (a->defval.length()>0) // write the default value
+ {
+ QString n=a->defval;
+ if (cName.length()>0) n=addTemplateNames(n,cd->name(),cName);
+ ol.docify(" = ");
+ linkifyText(ol,scopeName,md->name(),n);
+ }
+ a=argList->next();
+ if (a) ol.docify(", "); // there are more arguments
+ }
+ ol.docify(")"); // end argument list
+ if (argList->constSpecifier)
+ {
+ ol.docify(" const");
+ }
+ if (argList->volatileSpecifier)
+ {
+ ol.docify(" volatile");
+ }
+}
+
+QString argListToString(ArgumentList *al)
+{
+ QString result;
+ if (al==0) return result;
+ Argument *a=al->first();
+ result+="(";
+ while (a)
+ {
+ result+= a->type+" "+a->name;
+ a = al->next();
+ if (a) result+=",";
+ }
+ result+=")";
+ if (al->constSpecifier) result+=" const";
+ if (al->volatileSpecifier) result+=" volatile";
+ return result;
+}
+
+static void writeLink(OutputList &ol,ClassDef *cd,NamespaceDef *nd,
+ FileDef *fd,MemberDef *md,const char *name)
+{
+ if (nd)
+ ol.writeObjectLink(0 /*TODO: references */,nd->namespaceFile(),md->anchor(),name);
+ else if (fd)
+ ol.writeObjectLink(fd->getReference(),fd->diskName(),md->anchor(),name);
+ else
+ ol.writeObjectLink(cd->getReference(),cd->classFile(),md->anchor(),name);
+}
+
+static void warnForUndocumentedMember(MemberDef *md)
+{
+ ClassDef *cd=md->memberClass();
+ FileDef *fd=md->getFileDef();
+ if (cd)
+ {
+ if (!md->hasDocumentation() && md->name() && md->name()[0]!='@')
+ warn("Warning: Member %s of class %s is not documented\n",
+ md->name().data(),cd->name().data());
+ }
+ else if (fd)
+ {
+ if (!md->hasDocumentation() && md->name() && md->name()[0]!='@')
+ warn("Warning: Member %s of file %s is not documented\n",
+ md->name().data(),fd->name().data());
+ }
+}
+
+static bool manIsEnabled;
+
+void startTitle(OutputList &ol)
+{
+ ol.startTitleHead();
+ manIsEnabled=ol.isEnabled(OutputGenerator::Man);
+ if (manIsEnabled) ol.disable(OutputGenerator::Man);
+}
+
+void endTitle(OutputList &ol,const char *name)
+{
+ if (manIsEnabled) ol.enable(OutputGenerator::Man);
+ ol.endTitleHead(name);
+}
+
+void writeQuickLinks(OutputList &ol,bool compact,bool ext)
+{
+ bool manEnabled = ol.isEnabled(OutputGenerator::Man);
+ bool texEnabled = ol.isEnabled(OutputGenerator::Latex);
+ QString extLink,absPath;
+ if (ext) { extLink="_doc:"; absPath="/"; }
+ if (manEnabled) ol.disable(OutputGenerator::Man);
+ if (texEnabled) ol.disable(OutputGenerator::Latex);
+ if (compact) ol.startCenter(); else ol.startItemList();
+ if (documentedGroups>0)
+ {
+ if (!compact) ol.writeListItem();
+ ol.startQuickIndexItem(extLink,absPath+"modules.html");
+ parseDoc(ol,0,0,theTranslator->trModules());
+ ol.endQuickIndexItem();
+ }
+ if (documentedNamespaces>0)
+ {
+ if (!compact) ol.writeListItem();
+ ol.startQuickIndexItem(extLink,absPath+"namespaces.html");
+ parseDoc(ol,0,0,theTranslator->trNamespaces());
+ ol.endQuickIndexItem();
+ }
+ if (hierarchyClasses>0)
+ {
+ if (!compact) ol.writeListItem();
+ ol.startQuickIndexItem(extLink,absPath+"hierarchy.html");
+ parseDoc(ol,0,0,theTranslator->trClassHierarchy());
+ ol.endQuickIndexItem();
+ }
+ if (annotatedClasses>0)
+ {
+ if (!compact) ol.writeListItem();
+ ol.startQuickIndexItem(extLink,absPath+"annotated.html");
+ parseDoc(ol,0,0,theTranslator->trCompoundList());
+ ol.endQuickIndexItem();
+ }
+ if (documentedFiles>0)
+ {
+ if (!compact) ol.writeListItem();
+ ol.startQuickIndexItem(extLink,absPath+"files.html");
+ parseDoc(ol,0,0,theTranslator->trFileList());
+ ol.endQuickIndexItem();
+ }
+ if (includeFiles.count()>0 && verbatimHeaderFlag)
+ {
+ if (!compact) ol.writeListItem();
+ ol.startQuickIndexItem(extLink,absPath+"headers.html");
+ parseDoc(ol,0,0,theTranslator->trHeaderFiles());
+ ol.endQuickIndexItem();
+ }
+ if (documentedMembers>0)
+ {
+ if (!compact) ol.writeListItem();
+ ol.startQuickIndexItem(extLink,absPath+"functions.html");
+ parseDoc(ol,0,0,theTranslator->trCompoundMembers());
+ ol.endQuickIndexItem();
+ }
+ if (documentedFunctions>0)
+ {
+ if (!compact) ol.writeListItem();
+ ol.startQuickIndexItem(extLink,absPath+"globals.html");
+ parseDoc(ol,0,0,theTranslator->trFileMembers());
+ ol.endQuickIndexItem();
+ }
+ if (pageList.count()>0)
+ {
+ if (!compact) ol.writeListItem();
+ ol.startQuickIndexItem(extLink,absPath+"pages.html");
+ parseDoc(ol,0,0,theTranslator->trRelatedPages());
+ ol.endQuickIndexItem();
+ }
+ if (exampleList.count()>0)
+ {
+ if (!compact) ol.writeListItem();
+ ol.startQuickIndexItem(extLink,absPath+"examples.html");
+ parseDoc(ol,0,0,theTranslator->trExamples());
+ ol.endQuickIndexItem();
+ }
+ if (searchEngineFlag)
+ {
+ if (!compact) ol.writeListItem();
+ ol.startQuickIndexItem("_cgi:","");
+ parseDoc(ol,0,0,theTranslator->trSearch());
+ ol.endQuickIndexItem();
+ }
+ if (compact)
+ {
+ ol.endCenter();
+ ol.writeRuler();
+ }
+ else
+ {
+ ol.endItemList();
+ }
+ if (manEnabled) ol.enable(OutputGenerator::Man);
+ if (texEnabled) ol.enable(OutputGenerator::Latex);
+}
+
+void startFile(OutputList &ol,const char *name,const char *title,bool external)
+{
+ ol.startFile(name,title,external);
+ if (!noIndexFlag) writeQuickLinks(ol,TRUE,external);
+}
+
+void endFile(OutputList &ol,bool external)
+{
+ bool latexEnabled = ol.isEnabled(OutputGenerator::Latex);
+ bool manEnabled = ol.isEnabled(OutputGenerator::Man);
+ if (latexEnabled) ol.disable(OutputGenerator::Latex);
+ if (manEnabled) ol.disable(OutputGenerator::Man);
+ ol.writeFooter(0,external); // write the footer
+ if (footerFile.length()==0)
+ {
+ parseDoc(ol,0,0,theTranslator->trGeneratedAt(
+ dateToString(TRUE),
+ projectName
+ ));
+ }
+ ol.writeFooter(1,external); // write the link to the picture
+ if (footerFile.length()==0)
+ {
+ parseDoc(ol,0,0,theTranslator->trWrittenBy());
+ }
+ ol.writeFooter(2,external); // end the footer
+ if (latexEnabled) ol.enable(OutputGenerator::Latex);
+ if (manEnabled) ol.enable(OutputGenerator::Man);
+ ol.endFile();
+}
+
+
+static void writeMemberDef(OutputList &ol, ClassDef *cd, NamespaceDef *nd,
+ FileDef *fd, MemberDef *md)
+{
+ int i,l;
+ bool hasDocs=md->hasDocumentation();
+ if ((!hasDocs && hideMemberFlag) ||
+ (hideMemberFlag &&
+ md->documentation().isEmpty() &&
+ !briefMemDescFlag &&
+ !repeatBriefFlag
+ )
+ ) return;
+ QString type=md->typeString();
+ QRegExp r("@[0-9]+");
+ if ((i=r.match(type,0,&l))==-1 || !md->enumUsed())
+ {
+ // strip `static' keyword from type
+ if (type.left(7)=="static ") type=type.right(type.length()-7);
+ // strip `friend' keyword from type
+ if (type.left(7)=="friend ") type=type.right(type.length()-7);
+
+ if (genTagFile.length()>0)
+ {
+ tagFile << md->name() << " " << md->anchor() << " \""
+ << md->argsString() << "\"\n";
+ }
+
+ QString cname;
+ if (cd) cname=cd->name();
+ else if (nd) cname=nd->name();
+ else if (fd) cname=fd->name();
+
+ // If there is no detailed description we need to write the anchor here.
+ if (!md->detailsAreVisible() && !extractAllFlag)
+ {
+ ol.writeDoxyAnchor(cname,md->anchor(),md->name());
+ ol.addToIndex(md->name(),cname);
+ ol.addToIndex(cname,md->name());
+ ol.docify("\n");
+ }
+
+ ol.startMemberItem();
+
+ // write type
+ if (i!=-1)
+ {
+ QString newType = type.left(i) + " { ... } " +
+ type.right(type.length()-i-l);
+ type = newType;
+ ol.docify(type);
+ }
+ else
+ {
+ ol.docify(type);
+ }
+ QString name=md->name().copy();
+ if (type.length()>0) ol.writeString(" ");
+
+ // write name
+ if ( extractAllFlag ||
+ (md->briefDescription().isEmpty() || !briefMemDescFlag) &&
+ (!md->documentation().isEmpty() ||
+ (!md->briefDescription().isEmpty() &&
+ !briefMemDescFlag &&
+ repeatBriefFlag
+ )
+ )
+ )
+ {
+ //printf("writeLink %s->%d\n",name.data(),md->hasDocumentation());
+ writeLink(ol,cd,nd,fd,md,name);
+ }
+ else // there is a brief member description and brief member
+ // descriptions are enabled or there is no detailed description.
+ {
+ ol.writeBoldString(name);
+ }
+
+ if (md->argsString())
+ {
+ ol.writeString(" ");
+ ol.docify(md->argsString());
+ }
+
+ if (md->excpString())
+ {
+ ol.writeString(" ");
+ ol.docify(md->excpString());
+ }
+
+ ol.endMemberItem();
+
+ // write brief description
+ if (!md->briefDescription().isEmpty() && briefMemDescFlag)
+ {
+ ol.startMemberDescription();
+ parseDoc(ol,cname,md->name(),md->briefDescription());
+ if (!md->documentation().isEmpty())
+ {
+ ol.disableAllBut(OutputGenerator::Html);
+ ol.endEmphasis();
+ ol.docify(" ");
+ ol.startTextLink(0,md->anchor());
+ //ol.writeObjectLink(0,0,md->anchor()," More...");
+ parseDoc(ol,0,0,theTranslator->trMore());
+ ol.endTextLink();
+ ol.startEmphasis();
+ ol.enableAll();
+ }
+ ol.endMemberDescription();
+ ol.newParagraph();
+ }
+ }
+ warnForUndocumentedMember(md);
+}
+
+
+// write a list in HTML of all members of a certain category
+// cd!=0 => ml is a list of class members
+// fd!=0 => ml is a list of file `members'
+void writeMemberDecs(OutputList &ol,ClassDef *cd,NamespaceDef *nd, FileDef *fd,
+ const char *title, const char *subtitle,MemberList *ml)
+{
+ ml->countDecMembers();
+ if (ml->totalCount()==0) return;
+ if (title)
+ {
+ ol.startMemberHeader();
+ parseDoc(ol,0,0,title);
+ ol.endMemberHeader();
+ }
+ if (subtitle) ol.writeString(subtitle);
+
+
+ if (!fd && !nd) ol.startMemberList();
+ MemberDef *md;
+
+ if (fd && ml->defineCount()>0)
+ {
+ ol.startMemberHeader();
+ parseDoc(ol,0,0,theTranslator->trDefines());
+ ol.endMemberHeader();
+ ol.startMemberList();
+ MemberListIterator mli(*ml);
+ for ( ; (md=mli.current()); ++mli )
+ {
+ if (md->isDefine() &&
+ (md->argsString() || md->hasDocumentation() || extractAllFlag)
+ )
+ writeMemberDef(ol,cd,nd,fd,md);
+ }
+ ol.endMemberList();
+ }
+
+ if ((fd || nd) && ml->protoCount()>0)
+ {
+ ol.startMemberHeader();
+ parseDoc(ol,0,0,theTranslator->trFuncProtos());
+ ol.startMemberList();
+ MemberListIterator mli(*ml);
+ for ( ; (md=mli.current()); ++mli )
+ {
+ if (md->isPrototype()) writeMemberDef(ol,cd,nd,fd,md);
+ }
+ ol.endMemberList();
+ }
+
+ if (ml->typedefCount()>0)
+ {
+ if (fd || nd)
+ {
+ ol.startMemberHeader();
+ parseDoc(ol,0,0,theTranslator->trTypedefs());
+ ol.endMemberHeader();
+ //ol.writeMemberHeader("Typedefs");
+ ol.startMemberList();
+ }
+ MemberListIterator mli(*ml);
+ for ( ; (md=mli.current()) ; ++mli )
+ {
+ if (md->isTypedef()) writeMemberDef(ol,cd,nd,fd,md);
+ }
+ if (fd || nd) ol.endMemberList();
+ }
+
+ // write enums
+ if (ml->enumCount()>0)
+ {
+ if (fd || nd)
+ {
+ ol.startMemberHeader();
+ parseDoc(ol,0,0,theTranslator->trEnumerations());
+ ol.endMemberHeader();
+ ol.startMemberList();
+ }
+ MemberListIterator mli(*ml);
+ for ( ; (md=mli.current()) ; ++mli )
+ {
+ bool hasDocs=md->hasDocumentation();
+ QString type=md->typeString();
+ type=type.stripWhiteSpace();
+ if (md->isEnumerate() && (hasDocs || !hideMemberFlag))
+ {
+ // see if there are any documented enum values
+ // we need this info to decide if we need to generate a link.
+ QList<MemberDef> *fmdl=md->enumFieldList();
+ int documentedEnumValues=0;
+ if (fmdl)
+ {
+ MemberDef *fmd=fmdl->first();
+ while (fmd)
+ {
+ if (fmd->hasDocumentation()) documentedEnumValues++;
+ fmd=fmdl->next();
+ }
+ }
+ if (documentedEnumValues>0) md->setDocumentedEnumValues(TRUE);
+
+ if (!hideMemberFlag || // do not hide undocumented members or
+ !md->documentation().isEmpty() || // member has detailed descr. or
+ documentedEnumValues>0 || // member has documented enum vales.
+ briefMemDescFlag || // brief descr. is shown or
+ repeatBriefFlag // brief descr. is repeated.
+ )
+ {
+ OutputList typeDecl(&ol);
+ QString name=md->name().copy();
+ int i=name.findRev("::");
+ if (i!=-1) name=name.right(name.length()-i-2); // strip scope
+ if (name[0]!='@') // not an anonymous enum
+ {
+ if (extractAllFlag ||
+ (md->briefDescription().isEmpty() || !briefMemDescFlag) &&
+ (!md->documentation().isEmpty() || documentedEnumValues>0 ||
+ (!md->briefDescription().isEmpty() &&
+ !briefMemDescFlag &&
+ repeatBriefFlag
+ )
+ )
+ )
+ {
+ if (genTagFile.length()>0)
+ tagFile << md->name() << " " << md->anchor()
+ << " \"" << md->argsString() << "\"";
+ writeLink(typeDecl,cd,nd,fd,md,name);
+ }
+ else
+ {
+ typeDecl.writeBoldString(name);
+ }
+ typeDecl.writeChar(' ');
+ }
+
+ typeDecl.docify("{ ");
+ if (fmdl)
+ {
+ MemberDef *fmd=fmdl->first();
+ while (fmd)
+ {
+ if (fmd->hasDocumentation())
+ {
+ if (genTagFile.length()>0)
+ tagFile << fmd->name() << " " << fmd->anchor()
+ << " \"" << fmd->argsString() << "\"";
+ writeLink(typeDecl,cd,nd,fd,fmd,fmd->name());
+ }
+ else
+ typeDecl.writeBoldString(fmd->name());
+ fmd=fmdl->next();
+ if (fmd) typeDecl.writeString(", ");
+ typeDecl.disable(OutputGenerator::Man);
+ typeDecl.writeString("\n"); // to prevent too long lines in LaTeX
+ typeDecl.enable(OutputGenerator::Man);
+ }
+ }
+ typeDecl.docify(" }");
+ md->setEnumDecl(typeDecl);
+ int enumVars=0;
+ MemberListIterator vmli(*ml);
+ MemberDef *vmd;
+ if (name[0]=='@') // anonymous enum => append variables
+ {
+ for ( ; (vmd=vmli.current()) ; ++vmli)
+ {
+ QString vtype=vmd->typeString();
+ if ((vtype.find(name))!=-1) enumVars++;
+ }
+ }
+ if (enumVars==0) // no variable of this enum type
+ {
+ ol.startMemberItem();
+ ol.writeString("enum ");
+ ol+=typeDecl;
+ ol.endMemberItem();
+ //QString brief=md->briefDescription();
+ //brief=brief.stripWhiteSpace();
+ if (!md->briefDescription().isEmpty() && briefMemDescFlag)
+ {
+ ol.startMemberDescription();
+ parseDoc(ol,cd?cd->name().data():0,
+ md->name().data(),md->briefDescription());
+ if (!md->documentation().isEmpty() || documentedEnumValues>0)
+ {
+ ol.disableAllBut(OutputGenerator::Html);
+ ol.endEmphasis();
+ ol.docify(" ");
+ ol.startTextLink(0,md->anchor());
+ //ol.writeObjectLink(0,0,md->anchor()," More...");
+ parseDoc(ol,0,0,theTranslator->trMore());
+ ol.endTextLink();
+ ol.startEmphasis();
+ ol.enableAll();
+ }
+ ol.endMemberDescription();
+ ol.disable(OutputGenerator::Man);
+ ol.newParagraph();
+ ol.enable(OutputGenerator::Man);
+ }
+ }
+ warnForUndocumentedMember(md);
+ }
+ } // md->isEnumerate()
+ } // enum loop
+ if (fd || nd) ol.endMemberList();
+ } // write enums
+
+ // write functions
+ if (ml->funcCount()>0)
+ {
+ if (fd || nd)
+ {
+ ol.startMemberHeader();
+ parseDoc(ol,0,0,theTranslator->trFunctions());
+ ol.endMemberHeader();
+ ol.startMemberList();
+ }
+ MemberListIterator mli(*ml);
+ for ( ; (md=mli.current()) ; ++mli )
+ {
+ if ( md->isFunction() || md->isSignal() ||
+ md->isSlot())
+ writeMemberDef(ol,cd,nd,fd,md);
+ }
+ if (fd || nd) ol.endMemberList();
+ }
+
+ if (ml->friendCount()>0)
+ {
+ MemberListIterator mli(*ml);
+ for ( ; (md=mli.current()) ; ++mli )
+ {
+ if ( md->isFriend())
+ {
+ QString type=md->typeString();
+ //printf("Friend: type=%s name=%s\n",type.data(),md->name().data());
+ if (md->hasDocumentation() && type!="friend class")
+ {
+ writeMemberDef(ol,cd,nd,fd,md);
+ }
+ else // friend is undocumented as a member but it is a class,
+ // so generate a link to the class if that is documented.
+ {
+ ClassDef *cd=getClass(md->name());
+ if (md->hasDocumentation()) // friend is documented
+ {
+ ol.startMemberItem();
+ ol.docify("class ");
+ ol.writeObjectLink(0,0,md->anchor(),md->name());
+ ol.endMemberItem();
+ }
+ else if (cd && cd->isVisibleExt()) // class is documented
+ {
+ ol.startMemberItem();
+ ol.docify("class ");
+ ol.writeObjectLink(cd->getReference(),cd->classFile(),0,cd->name());
+ ol.endMemberItem();
+ }
+ else if (!hideMemberFlag) // no documentation
+ {
+ ol.startMemberItem();
+ ol.docify("class ");
+ ol.writeBoldString(md->name());
+ ol.endMemberItem();
+ }
+ }
+ }
+ }
+ }
+
+ // write variables
+ if (ml->varCount()>0)
+ {
+ if (fd || nd)
+ {
+ ol.startMemberHeader();
+ parseDoc(ol,0,0,theTranslator->trVariables());
+ ol.endMemberHeader();
+ ol.startMemberList();
+ }
+ MemberListIterator mli(*ml);
+ for ( ; (md=mli.current()) ; ++mli )
+ {
+ if (md->isVariable()) writeMemberDef(ol,cd,nd,fd,md);
+ }
+ if (fd || nd) ol.endMemberList();
+ }
+
+ if (!fd && !nd) { ol.endMemberList(); ol.writeChar('\n'); }
+}
+
+// compute the HTML anchors for a list of members
+void setAnchors(char id,MemberList *ml)
+{
+ int count=0;
+ MemberDef *md=ml->first();
+ while (md)
+ {
+ QString anchor;
+ anchor.sprintf("%c%d",id,count++);
+ //printf("Member %s anchor %s\n",md->name(),anchor.data());
+ md->setAnchor(anchor);
+ md=ml->next();
+ }
+}
+
+void writeMemberDocs(OutputList &ol,MemberList *ml,const char *scopeName,
+ MemberDef::MemberType m)
+{
+ MemberListIterator mli(*ml);
+ MemberDef *md;
+ for ( ; (md=mli.current()) ; ++mli)
+ {
+ bool hasDocs = md->detailsAreVisible();
+ // !md->documentation().isEmpty() || // member has a detailed description
+ // (md->memberType()==MemberDef::Enumeration && // or member is an enum and
+ // md->hasDocumentedEnumValues() // one of its values is documented
+ // ) || // or
+ // (!md->briefDescription().isEmpty() && // member has brief description and
+ // !briefMemDescFlag && // brief description not shown earlier and
+ // repeatBriefFlag // brief description should be repeated.
+ // );
+ if (md->memberType()==m && // filter member type
+ (extractAllFlag || hasDocs)
+ )
+ {
+ if (extractAllFlag && !hasDocs)
+ {
+ ol.disable(OutputGenerator::Latex); // Latex cannot insert a pagebreak
+ // if there are a lot of empty sections,
+ // so we disable LaTeX for all empty
+ // sections even if extractAllFlag is enabled
+ }
+ QString cname;
+ NamespaceDef *nd=md->getNamespace();
+ ClassDef *cd=md->memberClass();
+ FileDef *fd=md->getFileDef();
+ if (cd) cname=cd->name();
+ else if (nd) cname=nd->name();
+ else if (fd) cname=fd->name();
+ // get member name
+ QString doxyName=md->name().copy();
+ // prepend scope if there is any (TODO: prepend namespace scope as well)
+ if (scopeName) doxyName.prepend((QString)scopeName+"::");
+
+ QString def = md->definition();
+ if (md->isEnumerate()) def.prepend("enum ");
+ MemberDef *smd;
+ if (md->isEnumValue() && def[0]=='@') def = def.right(def.length()-2);
+ int i=0,l,dummy;
+ QRegExp r("@[0-9]+");
+ if (md->isEnumerate() && r.match(def,0,&l)!=-1) continue;
+ if (md->isEnumValue() && (smd = md->getEnumScope())
+ && r.match(smd->name(),0,&dummy)==-1) continue;
+ if ((md->isVariable() || md->isTypedef()) && (i=r.match(def,0,&l))!=-1)
+ {
+ // find enum type an insert it in the definition
+ MemberListIterator vmli(*ml);
+ MemberDef *vmd;
+ bool found=FALSE;
+ for ( ; (vmd=vmli.current()) && !found ; ++vmli)
+ {
+ if (vmd->isEnumerate() && def.mid(i,l)==vmd->name())
+ {
+ ol.startMemberDoc(cname,md->name(),md->anchor());
+ ol.writeDoxyAnchor(cname,md->anchor(),doxyName);
+ linkifyText(ol,scopeName,md->name(),def.left(i));
+ ol+=*vmd->enumDecl();
+ linkifyText(ol,scopeName,md->name(),def.right(def.length()-i-l));
+ found=TRUE;
+ }
+ }
+ if (!found) // anonymous compound
+ {
+ ol.startMemberDoc(cname,md->name(),md->anchor());
+ ol.writeDoxyAnchor(cname,md->anchor(),doxyName);
+ linkifyText(ol,scopeName,md->name(),def.left(i));
+ ol.docify(" { ... } ");
+ linkifyText(ol,scopeName,md->name(),def.right(def.length()-i-l));
+ }
+ }
+ else
+ {
+ ol.startMemberDoc(cname,md->name(),md->anchor());
+ ol.writeDoxyAnchor(cname,md->anchor(),doxyName);
+ ArgumentList *al=0;
+ if (cd && (!md->isRelated() || !md->templateArguments()) &&
+ (al=cd->templateArguments())) // class template prefix
+ {
+ writeTemplatePrefix(ol,al);
+ }
+ if (al && md->templateArguments()) ol.docify(" ");
+ al=md->templateArguments();
+ if (al) // function template prefix
+ {
+ writeTemplatePrefix(ol,al);
+ }
+ if (cd && cd->templateArguments())
+ {
+ // add template name lists to all occurrences of the class name.
+ def=addTemplateNames(def,cd->name(),cd->getTemplateNameString());
+ }
+ linkifyText(ol,scopeName,md->name(),def);
+ writeDefArgumentList(ol,cd,scopeName,md);
+ if (md->excpString())
+ {
+ ol.docify(" ");
+ linkifyText(ol,scopeName,md->name(),md->excpString());
+ }
+ }
+
+ Specifier virt=md->virtualness();
+ MemberDef *rmd=md->reimplements();
+ while (rmd && virt==Normal)
+ {
+ virt = rmd->virtualness()==Normal ? Normal : Virtual;
+ rmd = rmd->reimplements();
+ }
+
+ if (md->isStatic() || md->protection()!=Public ||
+ virt!=Normal || md->isSignal() || md->isFriend() ||
+ md->isRelated() || md->isSlot()
+ )
+ {
+ // write the member specifier list
+ ol.writeLatexSpacing();
+ ol.startTypewriter();
+ ol.docify(" [");
+ QStrList sl;
+ if (md->isFriend()) sl.append("friend");
+ else if (md->isRelated()) sl.append("related");
+ else
+ {
+ if (md->isStatic()) sl.append("static");
+ if (md->protection()==Protected) sl.append("protected");
+ else if (md->protection()==Private) sl.append("private");
+ if (virt==Virtual) sl.append("virtual");
+ else if (virt==Pure) sl.append("pure virtual");
+ if (md->isSignal()) sl.append("signal");
+ if (md->isSlot()) sl.append("slot");
+ }
+ const char *s=sl.first();
+ while (s)
+ {
+ ol.docify(s);
+ s=sl.next();
+ if (s) ol.docify(", ");
+ }
+ ol.docify("]");
+ ol.endTypewriter();
+ }
+ ol.endMemberDoc();
+ ol.startIndent();
+ ol.newParagraph();
+
+ if (!md->briefDescription().isEmpty() &&
+ (repeatBriefFlag ||
+ (!briefMemDescFlag && md->documentation().isEmpty())
+ )
+ )
+ {
+ parseDoc(ol,scopeName,md->name(),md->briefDescription());
+ ol.newParagraph();
+ }
+ if (!md->documentation().isEmpty())
+ {
+ parseDoc(ol,scopeName,md->name(),md->documentation()+"\n");
+ }
+
+ if (md->isEnumerate())
+ {
+ bool first=TRUE;
+ MemberList *fmdl=md->enumFieldList();
+ if (fmdl)
+ {
+ MemberDef *fmd=fmdl->first();
+ while (fmd)
+ {
+ if (fmd->hasDocumentation())
+ {
+ if (first)
+ {
+ ol.newParagraph();
+ ol.startBold();
+ parseDoc(ol,0,0,theTranslator->trEnumerationValues());
+ //ol.writeBoldString("Enumeration values:");
+ ol.docify(":");
+ ol.endBold();
+ ol.startMemberList();
+ }
+ ol.writeDoxyAnchor(cname,fmd->anchor(),fmd->name());
+ ol.addToIndex(fmd->name(),cname);
+ ol.addToIndex(cname,fmd->name());
+ ol.writeListItem();
+ first=FALSE;
+ ol.startBold();
+ ol.docify(fmd->name());
+ ol.endBold();
+ ol.newParagraph();
+
+ if (!fmd->briefDescription().isEmpty())
+ {
+ parseDoc(ol,scopeName,fmd->name(),fmd->briefDescription());
+ ol.newParagraph();
+ }
+ if (!fmd->documentation().isEmpty())
+ {
+ parseDoc(ol,scopeName,fmd->name(),fmd->documentation()+"\n");
+ }
+ ol.disable(OutputGenerator::Man);
+ ol.newParagraph();
+ ol.enable(OutputGenerator::Man);
+ }
+ fmd=fmdl->next();
+ }
+ }
+ if (!first) { ol.endMemberList(); ol.writeChar('\n'); }
+ }
+
+ MemberDef *bmd=md->reimplements();
+ if (bmd)
+ {
+ if (virt!=Normal) // search for virtual member of the deepest base class
+ {
+ MemberDef *lastBmd=bmd;
+ while (lastBmd)
+ {
+ if (lastBmd->virtualness()!=Normal) bmd=lastBmd;
+ lastBmd=lastBmd->reimplements();
+ }
+ }
+ // write class that contains a member that is reimplemented by this one
+ ClassDef *bcd = bmd->memberClass();
+ ol.newParagraph();
+ parseDoc(ol,0,0,theTranslator->trReimplementedFrom());
+ //ol.writeString("Reimplemented from ");
+ ol.docify(" ");
+ if (bmd->hasDocumentation())
+ {
+ ol.writeObjectLink(bcd->getReference(),bcd->classFile(),
+ bmd->anchor(),bcd->name());
+ if (
+ !bcd->isReference() &&
+ //(bcd->hasDocumentation() || !hideClassFlag) &&
+ //(bcd->protection()!=Private || extractPrivateFlag)
+ bcd->isVisible()
+ /*&& bmd->detailsAreVisible()*/
+ ) ol.writePageRef(bcd->name(),bmd->anchor());
+ }
+ else
+ {
+ ol.writeObjectLink(bcd->getReference(),bcd->classFile(),
+ 0,bcd->name());
+ if (
+ !bcd->isReference() &&
+ //(bcd->hasDocumentation() || !hideClassFlag) &&
+ //(bcd->protection()!=Private || extractPrivateFlag)
+ bcd->isVisible()
+ ) ol.writePageRef(bcd->name(),0);
+ }
+ ol.writeString(".");
+ }
+ MemberList *bml=md->reimplementedBy();
+ int count;
+ if (bml && (count=bml->count())>0)
+ {
+ // write the list of classes that overwrite this member
+ ol.newParagraph();
+ parseDoc(ol,0,0,theTranslator->trReimplementedIn());
+ //ol.writeString("Reimplemented in ");
+ ol.docify(" ");
+ bmd=bml->first();
+ while (bmd)
+ {
+ ClassDef *bcd = bmd->memberClass();
+ if (bmd->hasDocumentation())
+ {
+ ol.writeObjectLink(bcd->getReference(),bcd->classFile(),
+ bmd->anchor(),bcd->name());
+ if (
+ !bcd->isReference() &&
+ //(bcd->hasDocumentation() || !hideClassFlag) &&
+ //(bcd->protection()!=Private || extractPrivateFlag)
+ bcd->isVisible()
+ /*&& bmd->detailsAreVisible()*/
+ ) ol.writePageRef(bcd->name(),bmd->anchor());
+ }
+ else
+ {
+ ol.writeObjectLink(bcd->getReference(),bcd->classFile(),
+ 0,bcd->name());
+ if (
+ !bcd->isReference() &&
+ //(bcd->hasDocumentation() || !hideClassFlag) &&
+ //(bcd->protection()!=Private || extractPrivateFlag)
+ bcd->isVisible()
+ ) ol.writePageRef(bcd->name(),0);
+ }
+ bmd=bml->next();
+ if (bmd)
+ {
+ if (bml->at()==count-1)
+ //ol.writeString(" and ");
+ parseDoc(ol,0,0," "+theTranslator->trAnd()+" ");
+ else
+ ol.writeString(", ");
+ }
+ }
+ ol.writeString(".");
+ }
+ // write the list of examples that use this member
+ if (md->hasExamples())
+ {
+ ol.startDescList();
+ ol.startBold();
+ parseDoc(ol,0,0,theTranslator->trExamples()+": ");
+ //ol.writeBoldString("Examples: ");
+ ol.endBold();
+ ol.endDescTitle();
+ ol.writeDescItem();
+ md->writeExample(ol);
+ //ol.endDescItem();
+ ol.endDescList();
+ }
+ ol.endIndent();
+ // enable LaTeX again
+ if (extractAllFlag && !hasDocs) ol.enable(OutputGenerator::Latex);
+
+ }
+ }
+}
+
+//----------------------------------------------------------------------------
+// read a file with `name' to a string.
+
+QString fileToString(const char *name)
+{
+ if (name==0 || name[0]==0) return 0;
+ QFileInfo fi(name);
+ if (!fi.exists() || !fi.isFile())
+ {
+ err("Error: file `%s' not found\n",name);
+ exit(1);
+ }
+ QFile f(name);
+ if (!f.open(IO_ReadOnly))
+ {
+ err("Error: cannot open file `%s'\n",name);
+ exit(1);
+ }
+ int fsize=fi.size();
+ QString contents(fsize+1);
+ f.readBlock(contents.data(),fsize);
+ contents[fsize]='\0';
+ f.close();
+ return contents;
+}
+
+QString dateToString(bool includeTime)
+{
+ if (includeTime)
+ {
+ return QDateTime::currentDateTime().toString();
+ }
+ else
+ {
+ const QDate &d=QDate::currentDate();
+ QString result;
+ result.sprintf("%d %s %d",
+ d.day(),
+ d.monthName(d.month()),
+ d.year());
+ return result;
+ }
+ //QDate date=dt.date();
+ //QTime time=dt.time();
+ //QString dtString;
+ //dtString.sprintf("%02d:%02d, %04d/%02d/%02d",
+ // time.hour(),time.minute(),date.year(),date.month(),date.day());
+ //return dtString;
+}
+
+
+//----------------------------------------------------------------------
+// recursive function that returns the number of branches in the
+// inheritance tree that the base class `bcd' is below the class `cd'
+
+static int minClassDistance(ClassDef *cd,ClassDef *bcd,int level=0)
+{
+ if (cd==bcd) return level;
+ BaseClassListIterator bcli(*cd->baseClasses());
+ int m=maxInheritanceDepth;
+ for ( ; bcli.current() ; ++bcli)
+ {
+ m=QMIN(minClassDistance(bcli.current()->classDef,bcd,level+1),m);
+ }
+ return m;
+}
+
+//static void printArgList(ArgumentList *al)
+//{
+// if (al==0) return;
+// ArgumentListIterator ali(*al);
+// Argument *a;
+// printf("(");
+// for (;(a=ali.current());++ali)
+// {
+// printf("t=`%s' n=`%s' v=`%s' ",a->type.data(),a->name.length()>0?a->name.data():"",a->defval.length()>0?a->defval.data():"");
+// }
+// printf(")");
+//}
+
+// strip any template specifiers that follow className in string s
+static QString trimTemplateSpecifiers(const QString &className,const QString &s)
+{
+ // first we resolve any defines
+ //int i=0,p,l;
+ //QString result;
+ //QRegExp r("[A-Z_a-z][A-Z_a-z0-9]*");
+ //while ((p=r.match(s,i,&l))!=-1)
+ //{
+ // if (p>i) result+=s.mid(i,p-i);
+ // result+=resolveDefines(s.mid(p,l));
+ // i=p+l;
+ //}
+ //if (i<(int)s.length()) result+=s.mid(i,s.length()-i);
+
+ // We strip the template arguments following className (if any)
+ QString result=s.copy();
+ int l=className.length();
+ if (l>0) // there is a class name
+ {
+ int i,p=0;
+ while ((i=result.find(className,p))!=-1) // class name is in the argument type
+ {
+ uint s=i+l;
+ if (s<result.length() && result.at(s)=='<') // class has template args
+ {
+ int b=1;
+ uint e=s+1;
+ while (b>0 && e<result.length()) // find matching >
+ {
+ if (result.at(e)=='<') b++;
+ else if (result.at(e)=='>') b--;
+ e++;
+ }
+ // remove template argument
+ result=result.left(s)+result.right(result.length()-e);
+ if (result.length()>s && (result.at(s)=='*' || result.at(s)=='&'))
+ {
+ // insert a space to keep the argument in the canonical form
+ result=result.left(s)+" "+result.right(result.length()-s);
+ }
+ }
+ p=i+l;
+ }
+ }
+ return result;
+}
+
+// removes the (one and only) occurrence of name:: from s.
+static QString trimScope(const QString &name,const QString &s)
+{
+ int spos;
+ spos=s.find(name+"::");
+ if (spos!=-1)
+ {
+ return s.left(spos)+s.right(s.length()-spos-name.length()-2);
+ }
+ return s;
+}
+
+static QString trimBaseClassScope(BaseClassList *bcl,const QString &s)
+{
+ BaseClassListIterator bcli(*bcl);
+ BaseClassDef *bcd;
+ for (;(bcd=bcli.current());++bcli)
+ {
+ ClassDef *cd=bcd->classDef;
+ int spos=s.find(cd->name());
+ if (spos!=-1)
+ {
+ return s.left(spos)+s.right(
+ s.length()-spos-cd->name().length()-2
+ );
+ }
+ if (cd->baseClasses()->count()>0)
+ trimBaseClassScope(cd->baseClasses(),s);
+ }
+ return s;
+}
+
+//----------------------------------------------------------------------
+// Matches the arguments list srcAl with the argument list dstAl
+// Returns TRUE if the argument lists are equal. Two argument list are
+// considered equal if the number of arguments is equal and the types of all
+// arguments are equal. Furthermore the const and volatile specifiers
+// stored in the list should be equal.
+
+bool matchArguments(ArgumentList *srcAl,ArgumentList *dstAl,
+ const char *cl,const char *ns)
+{
+ QString className=cl;
+ QString namespaceName=ns;
+ //printf("matchArguments(%s,%s) className=%s namespaceName=%s\n",
+ // srcAl ? argListToString(srcAl).data() : "",
+ // dstAl ? argListToString(dstAl).data() : "",
+ // cl,ns);
+ if (srcAl==0 || dstAl==0)
+ {
+ return srcAl==dstAl; // at least one of the members is not a function
+ }
+ 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);
+ }
+ 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);
+ return TRUE;
+ }
+ if (srcAl->count() != dstAl->count())
+ {
+ return FALSE; // different number of arguments -> no match
+ }
+ if (srcAl->constSpecifier != dstAl->constSpecifier)
+ {
+ return FALSE; // one member is const, the other not -> no match
+ }
+ if (srcAl->volatileSpecifier != dstAl->volatileSpecifier)
+ {
+ 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)
+ {
+ QString srcAType=trimTemplateSpecifiers(className,srcA->type);
+ QString dstAType=trimTemplateSpecifiers(className,dstA->type);
+
+ if (srcAType!=dstAType) // check if the argument only differs on name
+ {
+ //printf("`%s' <=> `%s'\n",srcAType.data(),dstAType.data());
+
+ QString srcScope;
+ QString dstScope;
+
+ // strip redundant scope specifiers
+ if (!className.isEmpty())
+ {
+ srcAType=trimScope(className,srcAType);
+ dstAType=trimScope(className,dstAType);
+ ClassDef *cd=getClass(className);
+ if (cd->baseClasses()->count()>0)
+ {
+ srcAType=trimBaseClassScope(cd->baseClasses(),srcAType);
+ dstAType=trimBaseClassScope(cd->baseClasses(),dstAType);
+ }
+ }
+ if (!namespaceName.isEmpty())
+ {
+ srcAType=trimScope(namespaceName,srcAType);
+ dstAType=trimScope(namespaceName,dstAType);
+ }
+
+ //printf("`%s' <=> `%s'\n",srcAType.data(),dstAType.data());
+ uint srcPos=0,dstPos=0;
+ bool equal=TRUE;
+ while (srcPos<srcAType.length() && dstPos<dstAType.length() && equal)
+ {
+ equal=srcAType.at(srcPos)==dstAType.at(dstPos);
+ if (equal) srcPos++,dstPos++;
+ }
+ if (srcPos<srcAType.length() && dstPos<dstAType.length())
+ {
+ // if nothing matches or the match ends in the middle or at the
+ // end of a string then there is no match
+ //if (srcPos==0 || isalnum(srcAType.at(srcPos-1)) ||
+ // dstPos==0 || isalnum(dstAType.at(dstPos-1))) { printf("No match1\n"); return FALSE; }
+ int srcStart=srcPos;
+ int dstStart=dstPos;
+ if (srcPos==0 || dstPos==0) return FALSE;
+ if (isId(srcAType.at(srcPos)) && isId(dstAType.at(dstPos)))
+ {
+ // check if a name if already found -> if no then there is no match
+ if (srcA->name.length()>0 || dstA->name.length()>0) return FALSE;
+ while (srcPos<srcAType.length() && isId(srcAType.at(srcPos))) srcPos++;
+ while (dstPos<dstAType.length() && isId(dstAType.at(dstPos))) dstPos++;
+ if (srcPos<srcAType.length() || dstPos<dstAType.length()) return FALSE;
+ // find the start of the name
+ while (srcStart>=0 && isId(srcAType.at(srcStart))) srcStart--;
+ while (dstStart>=0 && isId(dstAType.at(dstStart))) dstStart--;
+ if (srcStart>0) // move the name from the type to the name field
+ {
+ srcA->name=srcAType.right(srcAType.length()-srcStart-1);
+ srcA->type=srcAType.left(srcStart+1).stripWhiteSpace();
+ }
+ if (dstStart>0) // move the name from the type to the name field
+ {
+ dstA->name=dstAType.right(dstAType.length()-dstStart-1);
+ dstA->type=dstAType.left(dstStart+1).stripWhiteSpace();
+ }
+ }
+ else
+ {
+ // otherwise we assume that a name starts at the current position.
+ while (srcPos<srcAType.length() && isId(srcAType.at(srcPos))) srcPos++;
+ while (dstPos<dstAType.length() && isId(dstAType.at(dstPos))) dstPos++;
+ // if nothing more follows for both types then we assume we have
+ // found a match. Note that now `signed int' and `signed' match, but
+ // seeing that int is not a name can only be done by looking at the
+ // semantics.
+
+ if (srcPos!=srcAType.length() || dstPos!=dstAType.length()) { return FALSE; }
+ dstA->name=dstAType.right(dstAType.length()-dstStart);
+ dstA->type=dstAType.left(dstStart).stripWhiteSpace();
+ srcA->name=srcAType.right(dstAType.length()-srcStart);
+ srcA->type=srcAType.left(srcStart).stripWhiteSpace();
+ }
+ }
+ else if (dstPos<dstAType.length())
+ {
+ if (!isspace(dstAType.at(dstPos))) // maybe the names differ
+ {
+ int startPos=dstPos;
+ while (dstPos<dstAType.length() && isId(dstAType.at(dstPos))) dstPos++;
+ if (dstPos!=dstAType.length()) return FALSE; // more than a difference in name -> no match
+ while (startPos>=0 && isId(dstAType.at(startPos))) startPos--;
+ if (startPos>0)
+ {
+ dstA->name=dstAType.right(dstAType.length()-startPos-1);
+ dstA->type=dstAType.left(startPos+1).stripWhiteSpace();
+ }
+ }
+ else // maybe dst has a name while src has not
+ {
+ dstPos++;
+ int startPos=dstPos;
+ while (dstPos<dstAType.length() && isId(dstAType.at(dstPos))) dstPos++;
+ if (dstPos!=dstAType.length()) return FALSE; // nope not a name -> no match
+ else // its a name (most probably) so move it
+ {
+ dstA->name=dstAType.right(dstAType.length()-startPos);
+ dstA->type=dstAType.left(startPos).stripWhiteSpace();
+ }
+ }
+ }
+ else if (srcPos<srcAType.length())
+ {
+ if (!isspace(srcAType.at(srcPos))) // maybe the names differ
+ {
+ int startPos=srcPos;
+ while (srcPos<srcAType.length() && isId(srcAType.at(srcPos))) srcPos++;
+ if (srcPos!=srcAType.length()) return FALSE; // more than a difference in name -> no match
+ while (startPos>=0 && isId(srcAType.at(startPos))) startPos--;
+ if (startPos>0)
+ {
+ srcA->name=srcAType.right(srcAType.length()-startPos-1);
+ srcA->type=srcAType.left(startPos+1).stripWhiteSpace();
+ }
+ }
+ else // maybe src has a name while dst has not
+ {
+ srcPos++;
+ int startPos=srcPos;
+ while (srcPos<srcAType.length() && isId(srcAType.at(srcPos))) srcPos++;
+ if (srcPos!=srcAType.length()) return FALSE; // nope not a name -> no match
+ else // its a name (most probably) so move it
+ {
+ srcA->name=srcAType.right(srcAType.length()-startPos);
+ srcA->type=srcAType.left(startPos).stripWhiteSpace();
+ }
+ }
+ }
+ else // without scopes the names match exactly
+ {
+ }
+ }
+ else if (srcA->name.length()==0 && dstA->name.length()==0)
+ // arguments match exactly but no name ->
+ // see if we can find the name
+ {
+ int i=srcAType.length()-1;
+ while (i>=0 && isId(srcAType.at(i))) i--;
+ if (i>0 && i<(int)srcAType.length()-1 && srcAType.at(i)!=':')
+ // there is (probably) a name
+ {
+ srcA->name=srcAType.right(srcAType.length()-i-1);
+ srcA->type=srcAType.left(i+1).stripWhiteSpace();
+ dstA->name=dstAType.right(dstAType.length()-i-1);
+ dstA->type=dstAType.left(i+1).stripWhiteSpace();
+ }
+ }
+ }
+ //printf("Match found!\n");
+ 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)
+{
+ //printf("mergeArguments `%s', `%s'\n",
+ // argListToString(srcAl).data(),argListToString(dstAl).data());
+ //printArgList(srcAl);printf(" <=> ");
+ //printArgList(dstAl);printf("\n");
+ if (srcAl==0 || dstAl==0 || srcAl->count()!=dstAl->count())
+ {
+ return; // invalid argument lists -> do not merge
+ }
+
+ ArgumentListIterator srcAli(*srcAl),dstAli(*dstAl);
+ Argument *srcA,*dstA;
+ for (;(srcA=srcAli.current(),dstA=dstAli.current());++srcAli,++dstAli)
+ {
+ if (srcA->defval.length()==0 && dstA->defval.length()>0)
+ {
+ //printf("Defval changing `%s'->`%s'\n",srcA->defval.data(),dstA->defval.data());
+ srcA->defval=dstA->defval.copy();
+ }
+ else if (srcA->defval.length()>0 && dstA->defval.length()==0)
+ {
+ //printf("Defval changing `%s'->`%s'\n",dstA->defval.data(),srcA->defval.data());
+ dstA->defval=srcA->defval.copy();
+ }
+ if (srcA->name.isEmpty() && !dstA->name.isEmpty())
+ {
+ //printf("type: `%s':=`%s'\n",srcA->type.data(),dstA->type.data());
+ //printf("name: `%s':=`%s'\n",srcA->name.data(),dstA->name.data());
+ srcA->type = dstA->type.copy();
+ srcA->name = dstA->name.copy();
+ }
+ else if (!srcA->name.isEmpty() && dstA->name.isEmpty())
+ {
+ //printf("type: `%s':=`%s'\n",dstA->type.data(),srcA->type.data());
+ //printf("name: `%s':=`%s'\n",dstA->name.data(),srcA->name.data());
+ dstA->type = srcA->type.copy();
+ dstA->name = dstA->name.copy();
+ }
+ int i1=srcA->type.find("::"),
+ i2=dstA->type.find("::"),
+ j1=srcA->type.length()-i1-2,
+ j2=dstA->type.length()-i2-2;
+ if (i1!=-1 && i2==-1 && srcA->type.right(j1)==dstA->type)
+ {
+ //printf("type: `%s':=`%s'\n",dstA->type.data(),srcA->type.data());
+ //printf("name: `%s':=`%s'\n",dstA->name.data(),srcA->name.data());
+ dstA->type = srcA->type.left(i1+2)+dstA->type;
+ dstA->name = dstA->name.copy();
+ }
+ else if (i1==-1 && i2!=-1 && dstA->type.right(j2)==srcA->type)
+ {
+ //printf("type: `%s':=`%s'\n",srcA->type.data(),dstA->type.data());
+ //printf("name: `%s':=`%s'\n",dstA->name.data(),srcA->name.data());
+ srcA->type = dstA->type.left(i2+2)+srcA->type;
+ srcA->name = dstA->name.copy();
+ }
+ }
+ //printf("result mergeArguments `%s', `%s'\n",
+ // argListToString(srcAl).data(),argListToString(dstAl).data());
+}
+
+//----------------------------------------------------------------------
+// searches for the class and member definitions corresponding with
+// memberName and className.
+// These classes are returned using `md' and `cd'.
+// returns TRUE if the class and member both could be found
+
+bool getDefs(const QString &memberName,const QString &className,
+ const char *args,MemberDef *&md, ClassDef *&cd, FileDef *&fd)
+{
+ //printf("Search for %s::%s %s\n",className.data(),memberName.data(),args);
+ fd=0; md=0; cd=0;
+ if (memberName.length()==0) return FALSE;
+ MemberName *mn;
+ if ((mn=memberNameDict[memberName]) && className.length()>0)
+ {
+ //printf(" >member name found\n");
+ ClassDef *fcd=0;
+ if ((fcd=getClass(className)))
+ {
+ //printf(" >member class found\n");
+ MemberDef *mmd=mn->first();
+ int mdist=maxInheritanceDepth;
+ while (mmd)
+ {
+ if ((mmd->protection()!=Private || extractPrivateFlag) &&
+ mmd->hasDocumentation()
+ /*mmd->detailsAreVisible()*/
+ /* && (args==0 || matchArgumentsOld(mmd->argsString(),args)) */
+ )
+ {
+ bool match=TRUE;
+ ArgumentList *argList=0;
+ if (args)
+ {
+ match=FALSE;
+ argList=new ArgumentList;
+ stringToArgumentList(args,argList);
+ match=matchArguments(mmd->argumentList(),argList);
+ }
+ if (match)
+ {
+ ClassDef *mcd=mmd->memberClass();
+ int m=minClassDistance(fcd,mcd);
+ if (m<mdist && mcd->isVisible())
+ {
+ mdist=m;
+ cd=mcd;
+ md=mmd;
+ fd=0;
+ }
+ }
+ if (argList)
+ {
+ delete argList;
+ }
+ }
+ mmd=mn->next();
+ }
+ if (mdist==maxInheritanceDepth && !strcmp(args,"()"))
+ // no exact match found, but if args="()" an arbitrary member will do
+ {
+ //printf(" >Searching for arbitrary member\n");
+ mmd=mn->first();
+ while (mmd)
+ {
+ if ((mmd->protection()!=Private || extractPrivateFlag) &&
+ (
+ mmd->hasDocumentation()
+ /*mmd->detailsAreVisible()*/
+ || mmd->isReference()
+ )
+ )
+ {
+ ClassDef *mcd=mmd->memberClass();
+ //printf(" >Class %s found\n",mcd->name().data());
+ int m=minClassDistance(fcd,mcd);
+ if (m<mdist && mcd->isVisible())
+ {
+ //printf("Class distance %d\n",m);
+ mdist=m;
+ cd=mcd;
+ md=mmd;
+ fd=0;
+ }
+ }
+ mmd=mn->next();
+ }
+ }
+ //printf(" >Succes=%d\n",mdist<maxInheritanceDepth);
+ return mdist<maxInheritanceDepth;
+ }
+ }
+ else // maybe an unrelated member ?
+ {
+ MemberName *mn;
+ if ((mn=functionNameDict[memberName]))
+ {
+ md=mn->first();
+ while (md)
+ {
+ if (/*md->detailsAreVisible()*/ md->hasDocumentation())
+ {
+ fd=md->getFileDef();
+ if (fd && fd->hasDocumentation())
+ {
+ cd=0;
+ return TRUE;
+ }
+ }
+ md=mn->next();
+ }
+ }
+ }
+ return FALSE;
+}
+
+//----------------------------------------------------------------------
+// Generate a hypertext link to the class with name `clName'.
+// If linkTxt is not null this text is used as the link, otherwise
+// the name of the class will be used. If the class could be found a
+// hypertext link (in HTML) is written, otherwise the text of the link will
+// be written.
+
+void generateClassRef(OutputList &ol,const char *clName,const char *linkTxt)
+{
+ QString className=clName;
+ QString linkText=linkTxt ? linkTxt : (const char *)className;
+ if (className.length()==0)
+ {
+ ol.docify(linkText);
+ return;
+ }
+ ClassDef *cd;
+ if ((cd=getClass(className)) && cd->isVisible())
+ {
+ ol.writeObjectLink(cd->getReference(),cd->classFile(),0,linkText);
+ if (!cd->isReference()) ol.writePageRef(cd->name(),0);
+ }
+ else
+ ol.docify(linkText);
+}
+
+//----------------------------------------------------------------------
+// generate a reference to a class or member.
+// `clName' is the name of the class that contains the documentation
+// string that is returned.
+// `name' is the name of the member or class that we want to link to.
+// `name' may have five formats:
+// 1) "ClassName"
+// 2) "memberName()" one of the (overloaded) function or define
+// with name memberName.
+// 3) "memberName(...)" a specific (overloaded) function or define
+// with name memberName
+// 4) "::memberName a non-function member or define
+// 5) ("ClassName::")+"memberName()"
+// 6) ("ClassName::")+"memberName(...)"
+// 7) ("ClassName::")+"memberName"
+
+void generateRef(OutputList &ol,const char *clName,
+ const char *name,bool inSeeBlock,const char *rt)
+{
+ //printf("generateRef(clName=%s,name=%s,rt=%s)\n",clName,name,rt);
+
+ // check if we have a plane name
+ QString tmpName = substitute(name,"#","::");
+ QString linkText = rt;
+ int scopePos=tmpName.findRev("::");
+ int bracePos=tmpName.find('(');
+ if (scopePos==-1 && bracePos==-1)
+ {
+ if (!inSeeBlock) /* check for class link */
+ {
+ if (linkText.isNull()) linkText=tmpName;
+ // check if this is a class reference
+ if (clName!=tmpName)
+ generateClassRef(ol,name,linkText);
+ else
+ ol.docify(linkText);
+ return;
+ }
+ else /* check if it is a class, if not continue to search */
+ {
+ if (clName!=tmpName && getClass(tmpName)!=0)
+ {
+ generateClassRef(ol,tmpName,linkText);
+ return;
+ }
+ }
+ }
+
+ // extract scope
+ QString scopeStr;
+ if (scopePos>0) scopeStr=tmpName.left(scopePos); else scopeStr=clName;
+
+ // extract name
+ int startNamePos=scopePos!=-1 ? scopePos+2 : 0;
+ int endNamePos=bracePos!=-1 ? bracePos : tmpName.length();
+ QString nameStr=tmpName.mid(startNamePos,endNamePos-startNamePos);
+
+ // extract arguments
+ QString argsStr;
+ if (bracePos!=-1) argsStr=tmpName.right(tmpName.length()-bracePos);
+
+ bool explicitLink=TRUE;
+ // create a default link text if none was explicitly given
+ if (linkText.isNull())
+ {
+ if (!scopeStr.isNull() && scopePos>0) linkText=scopeStr+"::";
+ linkText+=nameStr;
+ explicitLink=FALSE;
+ }
+
+ //printf("scope=`%s' name=`%s' arg=`%s' linkText=`%s'\n",
+ // scopeStr.data(),nameStr.data(),argsStr.data(),linkText.data());
+
+ //Define *d=0;
+ MemberDef *md;
+ ClassDef *cd;
+ FileDef *fd;
+ // check if nameStr is a member or global.
+ if (getDefs(nameStr,scopeStr,argsStr,md,cd,fd))
+ {
+ QString anchor = md->hasDocumentation() ? md->anchor() : 0;
+ QString cName,aName;
+ if (cd) // nameStr is a member of cd
+ {
+ //printf("addObjectLink(%s,%s,%s,%s)\n",cd->getReference(),
+ // cd->classFile(),anchor.data(),resultName.stripWhiteSpace().data());
+ ol.writeObjectLink(cd->getReference(),
+ cd->classFile(),anchor,
+ linkText.stripWhiteSpace());
+ cName=cd->name();
+ aName=md->anchor();
+ }
+ else if (fd) // nameStr is a global in file fd
+ {
+ //printf("addFileLink(%s,%s,%s)\n",fd->diskName(),anchor.data(),
+ // resultName.stripWhiteSpace().data());
+ ol.writeObjectLink(fd->getReference(),fd->diskName(),
+ anchor, linkText.stripWhiteSpace());
+ cName=fd->name();
+ aName=md->anchor();
+ }
+ else // should not be reached
+ {
+ //printf("add no link fd=cd=0\n");
+ ol.docify(linkText);
+ }
+
+ // for functions we add the arguments if explicitly specified or else "()"
+ if (!rt && (md->isFunction() || md->isPrototype() || md->isSignal() || md->isSlot()))
+ {
+ if (argsStr.isNull())
+ ol.writeString("()");
+ else
+ ol.docify(argsStr);
+ }
+
+ // generate the page reference (for LaTeX)
+ if (cName.length()>0 || aName.length()>0)
+ {
+ if (/*md->detailsAreVisible() &&*/
+ (
+ (cd && !cd->isReference() &&
+ // (cd->hasDocumentation() || !hideClassFlag) &&
+ // (cd->protection()!=Private || extractPrivateFlag)
+ cd->isVisible()
+ ) ||
+ (fd && !fd->isReference())
+ )
+ ) ol.writePageRef(cName,aName);
+ }
+ }
+// else if (!nameStr.isNull() && (d=defineDict[nameStr]))
+// // check if nameStr is perhaps a define
+// {
+// if (d->hasDocumentation() && d->fileDef)
+// {
+// ol.writeObjectLink(0,d->fileDef->diskName(),d->anchor,
+// linkText.stripWhiteSpace());
+// if (!explicitLink) ol.docify(argsStr);
+// }
+// }
+ else // nameStr is a false alarm or a typo.
+ {
+ if (rt)
+ ol.docify(rt);
+ else
+ {
+ ol.docify(linkText);
+ if (!argsStr.isNull()) ol.docify(argsStr);
+ }
+ }
+ return;
+}
+
+//----------------------------------------------------------------------
+// General function that generates the HTML code for a reference to some
+// file, class or member from text `lr' within the context of class `clName'.
+// This link has the text 'lt' (if not 0), otherwise `lr' is used as a
+// basis for the link's text.
+
+void generateLink(OutputList &ol,const char *clName,
+ const char *lr,bool inSeeBlock,const char *lt)
+{
+ QString linkRef=lr;
+ //PageInfo *pi=0;
+ //printf("generateLink(%s,%s)\n",lr,lt);
+ //FileInfo *fi=0;
+ FileDef *fd;
+ bool ambig;
+ if (linkRef.length()==0) // no reference name!
+ ol.docify(lt);
+ else if ((pageDict[linkRef])) // link to a page
+ ol.writeObjectLink(0,linkRef,0,lt);
+ else if ((exampleDict[linkRef])) // link to an example
+ ol.writeObjectLink(0,linkRef+"-example",0,lt);
+ else if ((fd=findFileDef(&inputNameDict,linkRef,ambig))
+ && fd->hasDocumentation())
+ // link to documented input file
+ ol.writeObjectLink(fd->getReference(),fd->diskName(),0,lt);
+ else // probably a class or member reference
+ generateRef(ol,clName,lr,inSeeBlock,lt);
+}
+
+void generateFileRef(OutputList &ol,const char *name,const char *text)
+{
+ QString linkText = text ? text : name;
+ //FileInfo *fi;
+ FileDef *fd;
+ bool ambig;
+ if ((fd=findFileDef(&inputNameDict,name,ambig)) &&
+ fd->hasDocumentation())
+ // link to documented input file
+ ol.writeObjectLink(fd->getReference(),fd->diskName(),0,linkText);
+ else
+ ol.docify(linkText);
+}
+
+//----------------------------------------------------------------------
+
+QString substituteClassNames(const QString &s)
+{
+ int i=0,l,p;
+ QString result;
+ QRegExp r("[a-z_A-Z][a-z_A-Z0-9]*");
+ while ((p=r.match(s,i,&l))!=-1)
+ {
+ QString *subst;
+ if (p>i) result+=s.mid(i,p-i);
+ if ((subst=substituteDict[s.mid(p,l)]))
+ {
+ result+=*subst;
+ }
+ else
+ {
+ result+=s.mid(p,l);
+ }
+ i=p+l;
+ }
+ result+=s.mid(i,s.length()-i);
+ return result;
+}
+
+//----------------------------------------------------------------------
+
+QString convertSlashes(const QString &s,bool dots)
+{
+ QString result;
+ int i,l=s.length();
+ for (i=0;i<l;i++)
+ if (s.at(i)!='/' && (!dots || s.at(i)!='.'))
+ {
+ if (caseSensitiveNames)
+ {
+ result+=s[i];
+ }
+ else
+ {
+ result+=tolower(s[i]);
+ }
+ }
+ else
+ result+="_";
+ return result;
+}
+
+//----------------------------------------------------------------------
+// substitute all occurences of `src' in `s' by `dst'
+
+QString substitute(const char *s,const char *src,const char *dst)
+{
+ QString input=s;
+ QString output;
+ int i=0,p;
+ while ((p=input.find(src,i))!=-1)
+ {
+ output+=input.mid(i,p-i);
+ output+=dst;
+ i=p+strlen(src);
+ }
+ output+=input.mid(i,input.length()-i);
+ return output;
+}
+
+//----------------------------------------------------------------------
+
+FileDef *findFileDef(const FileNameDict *fnDict,const char *n,bool &ambig)
+{
+ ambig=FALSE;
+ QString name=n;
+ QString path;
+ if (name.isNull()) return 0;
+ int slashPos=QMAX(name.findRev('/'),name.findRev('\\'));
+ if (slashPos!=-1)
+ {
+ path=name.left(slashPos+1);
+ name=name.right(name.length()-slashPos-1);
+ }
+ //printf("findFileDef path=`%s' name=`%s'\n",path.data(),name.data());
+ if (name.isNull()) return 0;
+ FileName *fn;
+ if ((fn=(*fnDict)[name]))
+ {
+ if (fn->count()==1)
+ {
+ return fn->first();
+ }
+ else // file name alone is ambigious
+ {
+ int count=0;
+ FileDef *fd=fn->first();
+ FileDef *lastMatch=0;
+ while (fd)
+ {
+ if (path.isNull() || fd->getPath().right(path.length())==path)
+ {
+ count++;
+ lastMatch=fd;
+ }
+ fd=fn->next();
+ }
+ ambig=(count>1);
+ return lastMatch;
+ }
+ }
+ return 0;
+}
+
+//----------------------------------------------------------------------
+
+void showFileDefMatches(const FileNameDict *fnDict,const char *n)
+{
+ QString name=n;
+ QString path;
+ int slashPos=QMAX(name.findRev('/'),name.findRev('\\'));
+ if (slashPos!=-1)
+ {
+ path=name.left(slashPos+1);
+ name=name.right(name.length()-slashPos-1);
+ }
+ FileName *fn;
+ if ((fn=(*fnDict)[name]))
+ {
+ FileDef *fd=fn->first();
+ while (fd)
+ {
+ if (path.isNull() || fd->getPath().right(path.length())==path)
+ {
+ msg(" %s\n",fd->absFilePath().data());
+ }
+ fd=fn->next();
+ }
+ }
+}
+