summaryrefslogtreecommitdiffstats
path: root/src/doxygen.cpp
diff options
context:
space:
mode:
authormueller <mueller@afe2bf4a-e733-0410-8a33-86f594647bc7>1999-12-15 19:25:10 (GMT)
committermueller <mueller@afe2bf4a-e733-0410-8a33-86f594647bc7>1999-12-15 19:25:10 (GMT)
commit719f0a35063be88eddcc4ed8fe7a940de47ef20c (patch)
treecc1cd70cf5761ddf72ff114c0b65576c3f4c1d2a /src/doxygen.cpp
parentbd30c025c4651ddda467f1af09d4c7ccab397bde (diff)
downloadDoxygen-719f0a35063be88eddcc4ed8fe7a940de47ef20c.zip
Doxygen-719f0a35063be88eddcc4ed8fe7a940de47ef20c.tar.gz
Doxygen-719f0a35063be88eddcc4ed8fe7a940de47ef20c.tar.bz2
initial version
Diffstat (limited to 'src/doxygen.cpp')
-rw-r--r--src/doxygen.cpp3763
1 files changed, 3763 insertions, 0 deletions
diff --git a/src/doxygen.cpp b/src/doxygen.cpp
new file mode 100644
index 0000000..3d641ef
--- /dev/null
+++ b/src/doxygen.cpp
@@ -0,0 +1,3763 @@
+/******************************************************************************
+ *
+ * $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 <qstring.h>
+#include <qfileinf.h>
+#include <qfile.h>
+#include <qdir.h>
+#include <qdict.h>
+#include <qregexp.h>
+#include <qstrlist.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+
+#include "version.h"
+#include "doxygen.h"
+#include "scanner.h"
+#include "entry.h"
+#include "index.h"
+#include "logos.h"
+#include "instdox.h"
+#include "message.h"
+#include "code.h"
+#include "config.h"
+#include "util.h"
+#include "pre.h"
+#include "tag.h"
+
+#include "outputlist.h"
+#include "declinfo.h"
+#include "htmlgen.h"
+#include "latexgen.h"
+#include "mangen.h"
+#include "language.h"
+#include "debug.h"
+
+#if defined(_MSC_VER)
+#define popen _popen
+#endif
+
+
+// lists
+ClassList classList; // list of all documented classes
+NamespaceList namespaceList; // list of all namespaces
+PageList exampleList; // list of all example files
+PageList pageList; // list of all related documentation pages
+MemberNameList memberNameList; // list of class member + related functions
+MemberNameList functionNameList; // list of all unrelated functions
+FileNameList inputNameList; // list of all input files
+StringList inputFiles;
+FileList includeFiles;
+GroupList groupList; // list of all groups
+FormulaList formulaList; // list of all formulas
+
+// dictionaries
+PageDict pageDict(1009); // dictionary of all doc pages
+PageDict exampleDict(1009); // dictionary of all examples
+ClassDict classDict(1009); // dictionary of all documented classes
+NamespaceDict namespaceDict(257); // dictionary of all documented namespaces
+MemberNameDict memberNameDict(10007); // dictionary of all member names
+MemberNameDict functionNameDict(10007); // dictionary of all functions
+StringDict substituteDict(1009); // dictionary of class name substitutes
+SectionDict sectionDict(257); // dictionary of all page sections
+FileNameDict inputNameDict(1009); // dictionary of sections
+StringDict excludeNameDict(1009); // dictionary of sections
+FileNameDict includeNameDict(1009); // dictionary of include names
+FileNameDict exampleNameDict(1009); // dictionary of examples
+FileDict includeDict(1009); // dictionary of include files
+DefineDict defineDict(10007); // dictionary of all defines
+StringDict typedefDict(1009); // dictionary of all typedefs
+GroupDict groupDict(257); // dictionary of all groups
+FormulaDict formulaDict(1009); // dictionary of all formulas
+FormulaDict formulaNameDict(1009); // dictionary of the label name of all formulas
+
+OutputList *outputList; // list of output generating objects
+
+//bool unrelatedFunctionsUsed;
+
+//ClassDef unrelatedClass("nothing",ClassDef::Class);
+ // dummy class for unrelated functions
+
+int annotatedClasses;
+int hierarchyClasses;
+int documentedFunctions;
+int documentedMembers;
+int documentedFiles;
+int documentedGroups;
+int documentedNamespaces;
+
+QTextStream tagFile;
+
+void addMemberDocs(Entry *root,MemberDef *md, const char *funcDecl,
+ bool over_load);
+
+
+//----------------------------------------------------------------------
+// Returns the standard string that is generated when the \overload
+// command is used.
+
+const char *getOverloadDocs()
+{
+ return "This is an overloaded member function, "
+ "provided for convenience. It differs from the above "
+ "function only in what argument(s) it accepts.";
+}
+
+//----------------------------------------------------------------------------
+
+
+void buildGroupList(Entry *root)
+{
+ if (root->section==Entry::GROUPDOC_SEC && root->name.length()>0)
+ {
+ //printf("Found group %s title=`%s'\n",root->name.data(),root->type.data());
+
+ GroupDef *gd;
+
+ if ((gd=groupDict[root->name]))
+ {
+ warn("Warning: group %s already documented\n"
+ " skipping documentation in file %s at line %d\n",
+ root->name.data(),root->fileName.data(),root->startLine);
+ }
+ else
+ {
+ gd = new GroupDef(root->name,root->type);
+ gd->setBriefDescription(root->brief);
+ gd->setDocumentation(root->doc);
+ groupList.inSort(gd);
+ groupDict.insert(root->name,gd);
+ }
+ }
+ EntryListIterator eli(*root->sublist);
+ Entry *e;
+ for (;(e=eli.current());++eli)
+ {
+ buildGroupList(e);
+ }
+}
+
+//----------------------------------------------------------------------
+
+//void computeGroupRelations(Entry *root)
+//{
+// if (root->section==Entry::GROUPDOC_SEC && root->name.length()>0)
+// {
+// GroupDef *gd;
+//
+// if ((gd=groupDict[root->name]))
+// {
+// QListIterator<QString> sli(*root->groups);
+// QString *s;
+// for (;(s=sli.current());++sli)
+// {
+// GroupDef *pgd;
+// if (s->length()>0 && (pgd=groupDict[*s]))
+// {
+// pgd->addGroup(gd);
+// printf("Group %s: in group %s\n",gd->groupName(),s->data());
+// }
+// }
+// }
+// }
+// EntryListIterator eli(*root->sublist);
+// Entry *e;
+// for (;(e=eli.current());++eli)
+// {
+// computeGroupRelations(e);
+// }
+//}
+
+//----------------------------------------------------------------------
+
+void buildFileList(Entry *root)
+{
+ if (((root->section==Entry::FILEDOC_SEC) ||
+ ((root->section & Entry::FILE_MASK) && extractAllFlag)) &&
+ root->name.length()>0
+ )
+ {
+ bool ambig;
+ FileDef *fd=findFileDef(&inputNameDict,root->name,ambig);
+ if (fd && !ambig)
+ {
+ if ((root->doc.length()>0 && fd->documentation()) ||
+ (root->brief.length()>0 && fd->briefDescription()))
+ {
+ warn("Warning: file %s already documented\n"
+ " skipping documentation in file %s at line %d\n",
+ root->name.data(),root->fileName.data(),root->startLine);
+ }
+ else
+ {
+ fd->setDocumentation(root->doc);
+ fd->setBriefDescription(root->brief);
+ QListIterator<QString> sli(*root->groups);
+ QString *s;
+ for (;(s=sli.current());++sli)
+ {
+ GroupDef *gd=0;
+ if (s->length()>0 && (gd=groupDict[*s]))
+ {
+ gd->addFile(fd);
+ //printf("File %s: in group %s\n",fd->name().data(),s->data());
+ }
+ }
+ }
+ }
+ else
+ {
+ warn("Warning: the name `%s' supplied as "
+ "the second argument in the \\file statement in file "
+ "%s at line %d ",
+ root->name.data(),
+ root->fileName.data(),
+ root->startLine);
+ if (ambig) // name is ambigious
+ {
+ warn("matches the following input files:\n");
+ showFileDefMatches(&inputNameDict,root->name);
+ warn("Please use a more specific name by "
+ "including a (larger) part of the path!\n");
+ }
+ else // name is not an input file
+ warn("is not an input file\n");
+ }
+ }
+ EntryListIterator eli(*root->sublist);
+ Entry *e;
+ for (;(e=eli.current());++eli)
+ {
+ buildFileList(e);
+ }
+}
+
+void addIncludeFile(ClassDef *cd,FileDef *ifd,Entry *root)
+{
+ //printf(">>>>>> includeFile=%s\n",root->includeFile.data());
+
+ bool ambig;
+ FileDef *fd=0;
+ // see if we need to include a verbatim copy of the header file
+ if (!root->includeFile.isNull() &&
+ (fd=findFileDef(&inputNameDict,root->includeFile,ambig))==0
+ )
+ { // explicit request
+ warn("Warning: the name `%s' supplied as "
+ "the second argument in the \\class statement in file "
+ "%s at line %d ",
+ root->includeFile.data(),
+ root->fileName.data(),
+ root->startLine);
+ if (ambig) // name is ambigious
+ {
+ warn("matches the following input files:\n");
+ showFileDefMatches(&inputNameDict,root->includeFile);
+ warn("Please use a more specific name by "
+ "including a (larger) part of the path!\n");
+ }
+ else // name is not an input file
+ warn("is not an input file\n");
+ }
+ else if (root->includeFile.length()==0 &&
+ // see if the file extension makes sense
+ guessSection(root->includeFile)==Entry::HEADER_SEC)
+ { // implicit assumption
+ fd=ifd;
+ }
+
+ // if a file is found, we mark it for verbatim inclusion.
+ if (fd)
+ {
+ //printf("fd->name()=%s fd->absFilePath()=%s\n",fd->name().data(),
+ // fd->absFilePath().data());
+ // set include file definition
+ cd->setIncludeFile(fd);
+ // set include supplied name
+ cd->setIncludeName(root->includeName);
+ fd->setIncludeName((QString)cd->classFile()+"-include");
+ if (includeDict[fd->absFilePath()]==0) // include not inserted earlier
+ {
+ includeFiles.inSort(fd);
+ includeDict.insert(fd->absFilePath(),fd);
+ }
+ }
+}
+
+/*! Input is a scopeName, output is the scopename split into a
+ * namespace part (as large as possible) and a classname part.
+ */
+void extractNamespaceName(const QString &scopeName,
+ QString &className,QString &namespaceName)
+{
+ QString clName=scopeName.copy();
+ QString nsName;
+ if (clName.length()>0 && namespaceDict[clName])
+ { // the whole name is a namespace
+ namespaceName=clName.copy();
+ className.resize(0);
+ return;
+ }
+ int i,p=clName.length()-2;
+ while (p>=0 && (i=clName.findRev("::",p))!=-1)
+ // see if the first part is a namespace
+ {
+ if (i>0 && namespaceDict[clName.left(i)])
+ {
+ namespaceName=clName.left(i);
+ className=clName.right(clName.length()-i-2);
+ return;
+ }
+ p=i-2; // try a smaller piece of the scope
+ }
+ className=scopeName.copy();
+ namespaceName.resize(0);
+ return;
+}
+
+static bool addNamespace(Entry *root,ClassDef *cd)
+{
+ // see if this class is defined inside a namespace
+ if (root->section & Entry::COMPOUND_MASK)
+ {
+ Entry *e = root->parent;
+ while (e)
+ {
+ if (e->section==Entry::NAMESPACE_SEC)
+ {
+ NamespaceDef *nd=0;
+ if (!e->name.isEmpty() && (nd=namespaceDict[e->name]))
+ {
+ cd->setNamespace(nd);
+ nd->insertClass(cd);
+ return TRUE;
+ }
+ }
+ e=e->parent;
+ }
+ }
+ return FALSE;
+}
+
+//----------------------------------------------------------------------
+// build a list of all classes mentioned in the documentation
+// and all classes that have a documentation block before their definition.
+void buildClassList(Entry *root)
+{
+ if (
+ ((root->section & Entry::COMPOUNDDOC_MASK) ||
+ ((root->section & Entry::COMPOUND_MASK))) &&
+ root->name.length()>0
+ )
+ {
+ QString fullName=root->name.copy();
+ if (fullName.length()==0)
+ {
+ // this should not be called
+ warn("Warning: invalid class found in file %s at %d\n",
+ root->fileName.data(),root->startLine);
+ }
+ else
+ {
+ //QString className;
+ //QString namespaceName;
+ //extractNamespaceName(fullName,className,namespaceName);
+
+ //printf("Found class %s in %s at line %d\n",fullName.data(),
+ // root->fileName.data(),root->startLine);
+ // add class name substitution entry iff the class name is alterned by a
+ // define. This is needed to properly document Qt's template classes
+ // (although, it's quite general)
+ //if (resolveDefines(fullName)!=fullName)
+ //{
+ // substituteDict.insert(resolveDefines(fullName),new QString(fullName));
+ //}
+
+ bool ambig;
+ ClassDef *cd;
+ if ((cd=getClass(fullName)))
+ {
+ if (cd->templateArguments()==0)
+ {
+ //printf("existing ClassDef tempArgList=%p\n",root->tArgList);
+ cd->setTemplateArguments(root->tArgList);
+ }
+ if (root->doc.length()>0 || root->brief.length()>0) // block contains docs
+ {
+ if (cd->documentation()) // class already documented
+ {
+ warn("Warning: class %s already documented\n"
+ " skipping documentation in file %s at line %d\n",
+ fullName.data(),root->fileName.data(),root->startLine);
+ }
+ else // class not documented, use docs in block
+ {
+ cd->setDocumentation(root->doc);
+ cd->setBriefDescription(root->brief);
+ cd->setName(fullName); // change name to match docs
+ }
+ }
+ if (cd->includeFile()==0)
+ {
+ addIncludeFile(cd,
+ findFileDef(&inputNameDict,root->fileName,ambig),
+ root
+ );
+ }
+ addNamespace(root,cd);
+ }
+ else if (fullName[0]!='@' /* &&
+ (root->doc.length()>0 ||
+ root->brief.length()>0 ||
+ extractAllFlag
+ )*/
+ )
+ // new class
+ {
+ int sec=ClassDef::Class;
+ switch(root->section)
+ {
+ case Entry::UNION_SEC:
+ case Entry::UNIONDOC_SEC:
+ sec=ClassDef::Union; break;
+ case Entry::STRUCT_SEC:
+ case Entry::STRUCTDOC_SEC:
+ sec=ClassDef::Struct; break;
+ }
+ ClassDef *cd=new ClassDef(fullName,sec);
+ cd->setDocumentation(root->doc); // copy docs to definition
+ cd->setBriefDescription(root->brief);
+ //printf("new ClassDef tempArgList=%p\n",root->tArgList);
+ cd->setTemplateArguments(root->tArgList);
+ cd->setProtection(root->protection);
+
+ QListIterator<QString> sli(*root->groups);
+ QString *s;
+ for (;(s=sli.current());++sli)
+ {
+ GroupDef *gd=0;
+ if (s->length()>0 && (gd=groupDict[*s]))
+ {
+ gd->addClass(cd);
+ //printf("Compound %s: in group %s\n",cd->name().data(),s->data());
+ }
+ }
+
+ bool found=addNamespace(root,cd);
+
+ // file definition containing the class cd
+ FileDef *ifd=findFileDef(&inputNameDict,root->fileName,ambig);
+
+ addIncludeFile(cd,ifd,root);
+
+ // if the class is not in a namespace then we insert
+ // it in the file definition
+ if (!found && ifd) ifd->insertClass(cd);
+
+ // the empty string test is needed for extract all case
+ cd->setBriefDescription(root->brief);
+ cd->insertUsedFile(root->fileName);
+ // add class to the list
+ classList.inSort(cd);
+ //printf("ClassDict.insert(%s)\n",resolveDefines(fullName).data());
+ //classDict.insert(resolveDefines(fullName),cd);
+ classDict.insert(fullName,cd);
+ }
+ }
+ }
+ EntryListIterator eli(*root->sublist);
+ Entry *e;
+ for (;(e=eli.current());++eli)
+ {
+ buildClassList(e);
+ }
+}
+
+//----------------------------------------------------------------------
+// build a list of all namespaces mentioned in the documentation
+// and all namespaces that have a documentation block before their definition.
+void buildNamespaceList(Entry *root)
+{
+ if (
+ (root->section==Entry::NAMESPACE_SEC) ||
+ (root->section==Entry::NAMESPACEDOC_SEC) &&
+ root->name.length()>0
+ )
+ {
+ QString fullName=root->name.copy();
+ if (fullName.length()==0)
+ {
+ // this should not be called
+ warn("Warning: invalid namespace found in file %s at %d\n",
+ root->fileName.data(),root->startLine);
+ }
+ else
+ {
+ //printf("Found namespace %s in %s at line %d\n",root->name.data(),
+ // root->fileName.data(), root->startLine);
+ NamespaceDef *nd;
+ if ((nd=namespaceDict[fullName]))
+ {
+ if (root->doc.length()>0 || root->brief.length()>0) // block contains docs
+ {
+ if (nd->documentation().isEmpty() && root->doc.length()>0)
+ {
+ nd->setDocumentation(root->doc);
+ nd->setName(fullName); // change name to match docs
+ }
+ else if (!nd->documentation().isEmpty() && root->doc.length()>0)
+ {
+ warn("Warning: namespace %s already has a detailed description,\n"
+ " skipping documentation in file %s at line %d\n",
+ fullName.data(),root->fileName.data(),root->startLine);
+ }
+ if (nd->briefDescription().isEmpty() && root->brief.length()>0)
+ {
+ nd->setBriefDescription(root->brief);
+ nd->setName(fullName); // change name to match docs
+ }
+ else if (!nd->briefDescription().isEmpty() && root->brief.length()>0)
+ {
+ warn("Warning: namespace %s already has a brief description,\n"
+ " skipping documentation in file %s at line %d\n",
+ fullName.data(),root->fileName.data(),root->startLine);
+ }
+ }
+ }
+ else if (root->doc.length()>0 ||
+ root->brief.length()>0 ||
+ extractAllFlag
+ )
+ {
+ NamespaceDef *nd=new NamespaceDef(fullName);
+ nd->setDocumentation(root->doc); // copy docs to definition
+ nd->setBriefDescription(root->brief);
+
+ QListIterator<QString> sli(*root->groups);
+ QString *s;
+ for (;(s=sli.current());++sli)
+ {
+ GroupDef *gd=0;
+ if (s->length()>0 && (gd=groupDict[*s]))
+ gd->addNamespace(nd);
+ }
+
+ bool ambig;
+ // file definition containing the class cd
+ FileDef *fd=findFileDef(&inputNameDict,root->fileName,ambig);
+ // insert the namespace in the file definition
+ if (fd) fd->insertNamespace(nd);
+
+ // the empty string test is needed for extract all case
+ nd->setBriefDescription(root->brief);
+ nd->insertUsedFile(root->fileName);
+ // add class to the list
+ namespaceList.inSort(nd);
+ namespaceDict.insert(fullName,nd);
+ }
+ }
+ }
+ EntryListIterator eli(*root->sublist);
+ Entry *e;
+ for (;(e=eli.current());++eli)
+ {
+ buildNamespaceList(e);
+ }
+}
+
+
+//----------------------------------------------------------------------
+// Searches the Entry tree for Variable documentation sections.
+// If found they are stored in their class or in the global list.
+
+void buildVarList(Entry *root)
+{
+ QRegExp re("([^)]*)");
+ int i=-1;
+ if (root->name.length()>0 &&
+ root->type!="class" &&
+ (
+ (root->section==Entry::VARIABLE_SEC
+ ) ||
+ (root->section==Entry::FUNCTION_SEC && // function variable
+ !root->type.isNull() && root->type.find(re,0)!=-1 &&
+ root->type.find("operator")==-1 && root->type.find(")(")==-1
+ )
+ )
+ ) // documented variable
+ {
+ Debug::print(Debug::Variables,0,
+ "VARIABLE_SEC: \n"
+ " type=`%s' name=`%s' args=`%s'\n",
+ root->type.data(),
+ root->name.data(),
+ root->args.data()
+ );
+ //printf("root->parent->name=%s\n",root->parent->name.data());
+
+ if (root->type.isNull() && root->name.find("operator")==-1 &&
+ (root->name.find('*')!=-1 || root->name.find('&')!=-1))
+ {
+ // recover from parse error caused by redundant braces
+ root->type=root->name;
+ QRegExp re("[a-z_A-Z][a-z_A-Z0-9]*");
+ int i,l;
+ i=re.match(root->args,0,&l);
+ root->name=root->args.mid(i,l);
+ root->args=root->args.mid(i+l,
+ root->args.find(')',i+l)-i-l);
+ //printf("new: type=`%s' name=`%s' args=`%s'\n",
+ // root->type.data(),root->name.data(),root->args.data());
+ }
+ else
+ {
+ QRegExp re("([^)]*)");
+ i=root->type.find(re,0);
+ if (i!=-1) // function variable
+ {
+ root->type=root->type.left(root->type.length()-1);
+ root->args.prepend(")");
+ }
+ }
+
+ QString scope,name=root->name.copy();
+ bool stat=root->stat;
+ ClassDef *cd=0;
+ Entry *p = root->parent;
+ while ((p->section & Entry::COMPOUND_MASK))
+ {
+ if (p->name.length()>0 && p->name[0]!='@')
+ {
+ if (!scope.isEmpty()) scope.prepend("::");
+ scope.prepend(p->name);
+ }
+ p=p->parent;
+ }
+
+ //printf("scope=%s\n",scope.data());
+
+ int ni;
+ if ((ni=root->name.findRev("::"))!=-1)
+ {
+ if (scope.length()>0) scope+="::";
+ scope+=root->name.left(ni);
+ name=root->name.right(root->name.length()-ni-2);
+ stat=TRUE;
+ }
+
+ MemberDef::MemberType mtype;
+ QString type=root->type.stripWhiteSpace();
+ if (type=="@")
+ mtype=MemberDef::EnumValue;
+ else if (type.left(8)=="typedef ")
+ mtype=MemberDef::Typedef;
+ else if (type.left(7)=="friend ")
+ mtype=MemberDef::Friend;
+ else
+ mtype=MemberDef::Variable;
+
+ if (scope.length()>0 && name.length()>0 && (cd=getClass(scope)))
+ {
+
+ Debug::print(Debug::Variables,0,
+ " class variable:\n"
+ " %s' %s'::`%s' `%s' prot=`%d\n",
+ root->type.data(),
+ scope.data(),
+ name.data(),
+ root->args.data(),
+ root->protection
+ );
+ // add template names, if the class is a non-specialized template
+ //if (scope.find('<')==-1 && cd->templateArguments())
+ //{
+ // scope+=cd->getTemplateNameString();
+ //}
+ // generate member definition.
+ QString def;
+ if (root->type.length()>0)
+ {
+ if (mtype==MemberDef::Friend)
+ {
+ def=root->type+" "+name+root->args;
+ }
+ else
+ {
+ def=root->type+" "+scope+"::"+name+root->args;
+ }
+ }
+ else
+ {
+ def=scope+"::"+name+root->args;
+ }
+ if (def.left(7)=="static ") def=def.right(def.length()-7);
+
+ // see if the member is already found in the same scope
+ // (this may be the case for a static member that is initialized
+ // outside the class)
+ bool found=FALSE;
+ MemberName *mn=memberNameDict[name];
+ if (mn)
+ {
+ MemberDef *md=mn->first();
+ while (md)
+ {
+ if (md->memberClass()==cd) // member already in the scope
+ {
+ addMemberDocs(root,md,def,FALSE);
+ found=TRUE;
+ }
+ md=mn->next();
+ }
+ }
+ if (!found) // found a fresh variable
+ {
+ // new member variable, typedef or enum value
+ MemberDef *md=new MemberDef(root->type,name,root->args,0,
+ root->protection,Normal,stat,FALSE,
+ mtype,0,0);
+ md->setMemberClass(cd);
+ md->setDefFile(root->fileName);
+ md->setDefLine(root->startLine);
+ md->setDocumentation(root->doc);
+ md->setBriefDescription(root->brief);
+ md->setDefinition(def);
+
+ // add the member to the global list
+ if (mn)
+ {
+ //printf("Member already found! %s\n",md->name());
+ //addMemberDocs(root,mn->first(),def,FALSE);
+ //delete md;
+ mn->inSort(md);
+ }
+ else // new variable name
+ {
+ mn = new MemberName(name);
+ mn->inSort(md);
+ //printf("Adding memberName=%s\n",mn->memberName());
+ memberNameDict.insert(name,mn);
+ memberNameList.inSort(mn);
+ // add the member to the class
+ }
+ cd->insertMember(md);
+
+ //TODO: insert FileDef instead of filename strings.
+ cd->insertUsedFile(root->fileName);
+ }
+ }
+ else if (name.length()>0) // global variable
+ {
+ Debug::print(Debug::Variables,0,
+ " global variable:\n"
+ " type=`%s' scope=`%s' name=`%s' args=`%s' prot=`%d\n",
+ root->type.data(),
+ scope.data(),
+ name.data(),
+ root->args.data(),
+ root->protection
+ );
+
+ // new global variable, enum value or typedef
+ MemberDef *md=new MemberDef(root->type,name,root->args,0,
+ Public, Normal,root->stat,FALSE,
+ mtype,0,0);
+ md->setDefFile(root->fileName);
+ md->setDefLine(root->startLine);
+ md->setDocumentation(root->doc);
+ md->setBriefDescription(root->brief);
+ QString def;
+
+ // see if the function is inside a namespace
+ NamespaceDef *nd = 0;
+ if (root->parent->section == Entry::NAMESPACE_SEC )
+ {
+ nd = namespaceDict[root->parent->name];
+ }
+ if (nd)
+ {
+ nd->insertMember(md);
+ md->setNamespace(nd);
+ }
+ else
+ {
+ // find file definition
+ FileDef *fd=0;
+ bool ambig;
+ if (root->fileName.length()>0 &&
+ (fd=findFileDef(&inputNameDict,root->fileName,ambig))
+ )
+ {
+ fd->insertMember(md);
+ md->setFileDef(fd);
+ }
+ }
+
+ // determine the definition of the global variable
+ if (nd) // variable is inside a namespace, so put the scope
+ // before the name
+ {
+ if (root->type.length()>0)
+ {
+ def=root->type+" "+nd->name()+"::"+name+root->args;
+ }
+ else
+ {
+ def=nd->name()+"::"+name+root->args;
+ }
+ }
+ else
+ {
+ if (root->type.length()>0)
+ {
+ def=root->type+" "+name+root->args;
+ }
+ else
+ {
+ def=name+root->args;
+ }
+ }
+ if (def.left(7)=="static ") def=def.right(def.length()-7);
+ md->setDefinition(def);
+
+ MemberName *mn;
+ // add member definition to the list of globals
+ if ((mn=functionNameDict[name]))
+ {
+ mn->inSort(md);
+ }
+ else
+ {
+ mn = new MemberName(name);
+ mn->inSort(md);
+ functionNameDict.insert(name,mn);
+ functionNameList.inSort(mn);
+ }
+ }
+ }
+ EntryListIterator eli(*root->sublist);
+ Entry *e;
+ for (;(e=eli.current());++eli)
+ {
+ if (e->section!=Entry::ENUM_SEC) buildVarList(e);
+ }
+}
+
+//----------------------------------------------------------------------
+// Searches the Entry tree for Function sections.
+// If found they are stored in their class or in the global list.
+
+void buildMemberList(Entry *root)
+{
+ if (root->section==Entry::FUNCTION_SEC)
+ {
+ Debug::print(Debug::Functions,0,
+ "FUNCTION_SEC:\n"
+ " `%s' `%s'::`%s' `%s' relates=`%s' file=`%s' #targs=%d\n",
+ root->type.data(),
+ root->parent->name.data(),
+ root->name.data(),
+ root->args.data(),
+ root->relates.data(),
+ root->fileName.data(),
+ root->tArgList ? (int)root->tArgList->count() : -1
+ );
+
+ bool isFriend=root->type.find("friend ")!=-1;
+ //if (isFriend && root->relates.length()==0)
+ // root->relates=root->parent->name.copy();
+ if (root->name.length()>0 /* && !isFriend */)
+ {
+
+ ClassDef *cd=0;
+ // check if this function's parent is a class
+ QRegExp re("([a-zA-Z0-9: ]*[ *]*[ ]*");
+ //printf("root->parent=`%s' cd=%p root->type.find(re,0)=%d\n",
+ // root->parent->name.data(),getClass(root->parent->name),
+ // root->type.find(re,0));
+ int i;
+ if (root->parent &&
+ root->parent->name.length()>0 &&
+ (root->parent->section & Entry::COMPOUND_MASK) &&
+ (cd=getClass(root->parent->name)) &&
+ // do some fuzzy things to exclude function pointers
+ (root->type.isNull() || root->type.find(re,0)==-1 ||
+ root->type.find(")(")!=-1 || root->type.find("operator")!=-1
+ )
+ )
+ {
+ int l;
+ if ((i=re.match(root->type,0,&l))!=-1) // function variable
+ {
+ root->args+=root->type.right(root->type.length()-i-l);
+ root->type=root->type.left(i+l);
+ }
+
+ QString name=removeRedundantWhiteSpace(root->name);
+ if (name.left(2)=="::") name=name.right(name.length()-2);
+
+ MemberDef::MemberType mtype;
+ if (isFriend) mtype=MemberDef::Friend;
+ else if (root->sig) mtype=MemberDef::Signal;
+ else if (root->slot) mtype=MemberDef::Slot;
+ else mtype=MemberDef::Function;
+ // new member of function, signal or slot.
+ MemberDef *md=new MemberDef(root->type,name,root->args,root->exception,
+ root->protection,root->virt,root->stat,root->relates.length()>0,
+ mtype,root->tArgList,root->argList);
+ md->setMemberClass(cd);
+ md->setDefFile(root->fileName);
+ md->setDefLine(root->startLine);
+ md->setDocumentation(root->doc);
+ md->setBriefDescription(root->brief);
+ QString def;
+ if (root->relates.length()>0 || isFriend)
+ {
+ if (root->type.length()>0)
+ {
+ if (root->argList)
+ {
+ def=root->type+" "+name;
+ }
+ else
+ {
+ def=root->type+" "+name+root->args;
+ }
+ }
+ else
+ {
+ if (root->argList)
+ {
+ def=name;
+ }
+ else
+ {
+ def=name+root->args;
+ }
+ }
+ }
+ else
+ {
+ QString scope=root->parent->name.copy();
+ if (root->type.length()>0)
+ {
+ if (root->argList)
+ {
+ def=root->type+" "+scope+"::"+name;
+ }
+ else
+ {
+ def=root->type+" "+scope+"::"+name+root->args;
+ }
+ }
+ else
+ {
+ if (root->argList)
+ {
+ def=scope+"::"+name;
+ }
+ else
+ {
+ def=scope+"::"+name+root->args;
+ }
+ }
+ }
+ if (def.left(7)=="friend ") def=def.right(def.length()-7);
+ md->setDefinition(def);
+
+ Debug::print(Debug::Functions,0,
+ " Func Member:\n"
+ " `%s' `%s'::`%s' `%s' proto=%d\n"
+ " def=`%s'\n",
+ root->type.data(),
+ root->parent->name.data(),
+ root->name.data(),
+ root->args.data(),
+ root->proto,
+ def.data()
+ );
+
+ // add member to the global list of all members
+ MemberName *mn;
+ if ((mn=memberNameDict[name]))
+ {
+ mn->inSort(md);
+ }
+ else
+ {
+ mn = new MemberName(name);
+ mn->inSort(md);
+ //printf("Adding memberName=%s\n",mn->memberName());
+ memberNameDict.insert(name,mn);
+ memberNameList.inSort(mn);
+ }
+
+ // add member to the class cd
+ cd->insertMember(md);
+ // add file to list of used files
+ cd->insertUsedFile(root->fileName);
+ }
+ else if (root->parent &&
+ !(root->parent->section & Entry::COMPOUND_MASK) &&
+ root->name.find("::")==-1 &&
+ root->relates.length()==0 &&
+ root->type.left(7)!="extern ")
+ // no member => unrelated function
+ {
+ /* check the uniqueness of the function name in the file.
+ * A file could contain a function prototype and a function definition
+ * or even multiple function prototypes.
+ */
+ bool found=FALSE;
+ MemberName *mn;
+ //MemberDef *fmd;
+ if ((mn=functionNameDict[root->name]))
+ {
+ MemberDef *md=mn->first();
+ while (md && !found)
+ {
+ if (md->getFileDef() &&
+ md->getFileDef()->absFilePath()==root->fileName &&
+ /*matchArguments(md->argsString(),root->args)*/
+ matchArguments(md->argumentList(),root->argList)
+ )
+ {
+ // function already found in the same file, one is probably
+ // a prototype.
+ found=TRUE;
+ if (!md->documentation() && !root->doc.isEmpty())
+ {
+ md->setDocumentation(root->doc);
+ }
+ if (!md->briefDescription() && !root->brief.isEmpty())
+ {
+ md->setBriefDescription(root->brief);
+ }
+ }
+ md=mn->next();
+ }
+ }
+ if (!found) /* global function is unique with respect to the file */
+ {
+ //printf("New function type=`%s' name=`%s' args=`%s'\n",
+ // root->type.data(),root->name.data(),root->args.data());
+
+ // new global function
+ QString name=removeRedundantWhiteSpace(root->name);
+ MemberDef *md=new MemberDef(root->type,name,root->args,root->exception,
+ root->protection,root->virt,root->stat,FALSE,
+ MemberDef::Function,root->tArgList,root->argList);
+ md->setDefFile(root->fileName);
+ md->setDefLine(root->startLine);
+ md->setDocumentation(root->doc);
+ md->setBriefDescription(root->brief);
+ md->setPrototype(root->proto);
+ QString def;
+ if (root->type.length()>0)
+ {
+ if (root->argList)
+ {
+ def=root->type+" "+name;
+ }
+ else
+ {
+ def=root->type+" "+name+root->args;
+ }
+ }
+ else
+ {
+ if (root->argList)
+ {
+ def=name.copy();
+ }
+ else
+ {
+ def=name+root->args;
+ }
+ }
+ Debug::print(Debug::Functions,0,
+ " Global Function:\n"
+ " `%s' `%s'::`%s' `%s' proto=%d\n"
+ " def=`%s'\n",
+ root->type.data(),
+ root->parent->name.data(),
+ root->name.data(),
+ root->args.data(),
+ root->proto,
+ def.data()
+ );
+ md->setDefinition(def);
+
+ // see if the function is inside a namespace
+ NamespaceDef *nd = 0;
+ if (root->parent->section == Entry::NAMESPACE_SEC )
+ {
+ nd = namespaceDict[root->parent->name];
+ }
+ if (nd)
+ {
+ nd->insertMember(md);
+ md->setNamespace(nd);
+ }
+ else
+ {
+ // find file definition
+ FileDef *fd=0;
+ bool ambig;
+ if (root->fileName.length()>0 &&
+ (fd=findFileDef(&inputNameDict,root->fileName,ambig))
+ )
+ {
+ // add member to the file
+ fd->insertMember(md);
+ md->setFileDef(fd);
+ }
+ }
+
+ // add member to the list of file members
+ MemberName *mn;
+ if ((mn=functionNameDict[name]))
+ {
+ mn->inSort(md);
+ }
+ else
+ {
+ mn = new MemberName(name);
+ mn->inSort(md);
+ functionNameDict.insert(name,mn);
+ functionNameList.inSort(mn);
+ }
+ }
+ else
+ {
+ //printf("Function already found!\n");
+ }
+
+ //printf("unrelated function %d `%s' `%s' `%s'\n",
+ // root->parent->section,root->type.data(),root->name.data(),root->args.data());
+ }
+ }
+ else if (root->name.length()==0)
+ {
+ warn("Warning: Illegal member name found in file %s at line %d\n",
+ root->fileName.data(),root->startLine);
+ }
+ }
+ EntryListIterator eli(*root->sublist);
+ Entry *e;
+ for (;(e=eli.current());++eli)
+ {
+ buildMemberList(e);
+ }
+}
+
+//----------------------------------------------------------------------
+
+void findFriends()
+{
+ //printf("findFriends()\n");
+ MemberNameListIterator fnli(functionNameList);
+ MemberName *fn;
+ for (;(fn=fnli.current());++fnli) // for each global function name
+ {
+ //printf("Function name=`%s'\n",fn->memberName());
+ MemberName *mn;
+ if ((mn=memberNameDict[fn->memberName()]))
+ { // there are members with the same name
+ //printf("Function name is also a member name\n");
+ MemberNameIterator fni(*fn);
+ MemberDef *fmd;
+ for (;(fmd=fni.current());++fni) // for each function with that name
+ {
+ MemberNameIterator mni(*mn);
+ MemberDef *mmd;
+ for (;(mmd=mni.current());++mni) // for each member with that name
+ {
+ //printf("Checking for matching arguments
+ // mmd->isRelated()=%d mmd->isFriend()=%d mmd->isFunction()=%d\n",
+ // mmd->isRelated(),mmd->isFriend(),mmd->isFunction());
+ NamespaceDef *nd=mmd->getNamespace();
+ if ((mmd->isFriend() || (mmd->isRelated() && mmd->isFunction())) &&
+ matchArguments(mmd->argumentList(),
+ fmd->argumentList(),
+ mmd->memberClass()->name(),
+ nd ? nd->name().data() : 0
+ )
+ ) // if the member is related and the arguments match then the
+ // function is actually a friend.
+ {
+ //printf("Found friend function\n");
+ mergeArguments(mmd->argumentList(),fmd->argumentList());
+ if (fmd->documentation())
+ mmd->setDocumentation(fmd->documentation());
+ else if (mmd->documentation())
+ fmd->setDocumentation(mmd->documentation());
+ if (!mmd->briefDescription() && fmd->briefDescription())
+ mmd->setBriefDescription(fmd->briefDescription());
+ else if (mmd->briefDescription() && !fmd->briefDescription())
+ fmd->setBriefDescription(mmd->briefDescription());
+ }
+ }
+ }
+ }
+ }
+}
+
+//----------------------------------------------------------------------
+
+void transferFunctionDocumentation()
+{
+ //printf("transferFunctionDocumentation()\n");
+ MemberNameListIterator mnli(functionNameList);
+ MemberName *mn;
+ for (;(mn=mnli.current());++mnli)
+ {
+ MemberDef *md,*mdef=0,*mdec=0;
+ MemberNameIterator mni(*mn);
+ /* find a matching function declaration and definition for this function */
+ for (;(md=mni.current());++mni)
+ {
+ if (md->isPrototype()) mdec=md;
+ if (md->isFunction() && !md->isStatic() && !md->isPrototype()) mdef=md;
+ }
+ if (mdef && mdec &&
+ matchArguments(mdef->argumentList(),mdec->argumentList())
+ ) /* match found */
+ {
+ //printf("Found member %s: def in %s and dec in %s\n",
+ // mn->memberName(),mdef->getFileDef()->name(),mdec->getFileDef()->name());
+
+ /* copy documentation between function definition and declaration */
+ if (mdec->briefDescription())
+ {
+ mdef->setBriefDescription(mdec->briefDescription());
+ }
+ else if (mdef->briefDescription())
+ {
+ mdec->setBriefDescription(mdef->briefDescription());
+ }
+ if (mdef->documentation())
+ {
+ mdec->setDocumentation(mdef->documentation());
+ }
+ else if (mdec->documentation())
+ {
+ mdef->setDocumentation(mdec->documentation());
+ }
+ }
+ }
+}
+
+
+//----------------------------------------------------------------------
+// Computes the base and super classes for each class in the tree
+
+void computeClassRelations(Entry *root)
+{
+ if (
+ (
+ (
+ root->section & Entry::COMPOUND_MASK
+ )
+ ||
+ (
+ (root->section & Entry::COMPOUNDDOC_MASK) && root->extends->count()>0
+ )
+ )
+ &&
+ root->name.length()>0
+ )
+ {
+ ClassDef *cd;
+ if ((cd=getClass(root->name)))
+ {
+ //printf("Class %s %d\n",cd->name().data(),root->extends->count());
+ if (!cd->visited)
+ {
+ cd->visited=TRUE; // mark class as used (in case the are multiple classes
+ // with the same name!)
+ if (root->extends->count()>0) // there are base classes
+ {
+ QString scopePrefix;
+ Entry *p=root->parent;
+ // For nested classes the base class could also be nested!
+ // To find the correct scope, we try to prepend the scope to the base
+ // name, starting with the largest, most inner scope.
+ while (p->section&Entry::COMPOUND_MASK)
+ {
+ scopePrefix=p->name+"::";
+ QList<BaseInfo> *baseList=root->extends;
+ BaseInfo *bi=baseList->first();
+ while (bi) // for each base class
+ {
+ QString cName=scopePrefix+bi->name;
+ //printf("Base class %s\n",cName.data());
+ ClassDef *baseClass=getClass(cName);
+ if (baseClass) // base class is documented
+ {
+ //printf("Adding!\n");
+ // add base class to this class
+ cd->insertBaseClass(baseClass,bi->prot,bi->virt);
+ // add this class as super class to the base class
+ baseClass->insertSuperClass(cd,bi->prot,bi->virt);
+ }
+ //else // base class not documented
+ //{
+ // warn("Warning: Base class %s referred to in file %s at line %d is not "
+ // "documented\n",s->data(),root->fileName.data(),root->startLine);
+ //}
+ bi=baseList->next();
+ }
+ p=p->parent;
+ }
+ // The base class could ofcouse also be a non-nested class
+ QList<BaseInfo> *baseList=root->extends;
+ BaseInfo *bi=baseList->first();
+ while (bi) // for each base class
+ {
+ ClassDef *baseClass=getClass(bi->name);
+ //printf("baseClass %s of %s found (%s and %s)\n",
+ // bi->name.data(),
+ // root->name.data(),
+ // (bi->prot==Private)?"private":((bi->prot==Protected)?"protected":"public"),
+ // (bi->virt==Normal)?"normal":"virtual"
+ // );
+ int i;
+ QString templSpec,baseClassName=bi->name.copy();
+ if (!baseClass && (i=bi->name.find('<'))!=-1)
+ // base class has template specifiers
+ {
+ // TODO: here we should try to find the correct template specialization
+ // but for now, we only look for the unspecializated base class.
+ baseClassName=bi->name.left(i);
+ baseClass=getClass(baseClassName);
+ templSpec=bi->name.right(bi->name.length()-i);
+ }
+ if (baseClass) // base class is documented
+ {
+ // add base class to this class
+ cd->insertBaseClass(baseClass,bi->prot,bi->virt,templSpec);
+ // add this class as super class to the base class
+ baseClass->insertSuperClass(cd,bi->prot,bi->virt,templSpec);
+ }
+ else // base class not documented
+ {
+ //printf("Found undocumented base class %s\n",bi->name.data());
+ NamespaceDef *nd=cd->getNamespace();
+ if (nd && (baseClass=getClass(nd->name()+"::"+baseClassName)))
+ // class is defined inside namespace
+ {
+ // add base class to this class
+ cd->insertBaseClass(baseClass,bi->prot,bi->virt,templSpec);
+ // add this class as super class to the base class
+ baseClass->insertSuperClass(cd,bi->prot,bi->virt,templSpec);
+ }
+ else // undocumented base class
+ {
+ baseClass=new ClassDef(bi->name,Entry::CLASS_SEC);
+ // add base class to this class
+ cd->insertBaseClass(baseClass,bi->prot,bi->virt,templSpec);
+ // add this class as super class to the base class
+ baseClass->insertSuperClass(cd,bi->prot,bi->virt,templSpec);
+ // the undocumented base was found in this file
+ baseClass->insertUsedFile(root->fileName);
+ // add class to the list
+ classList.inSort(baseClass);
+ //printf("ClassDict.insert(%s)\n",resolveDefines(fullName).data());
+ //classDict.insert(resolveDefines(bi->name),baseClass);
+ classDict.insert(bi->name,baseClass);
+ }
+ }
+ bi=baseList->next();
+ }
+ }
+// else // class has no base classes
+// {
+// QString resName=resolveDefines(root->name);
+// int i;
+// // Check if this class is a template instance of another class.
+// // If this is the case, we act as if this class `inherits' from the
+// // template class.
+// if ((i=resName.find('<'))!=-1)
+// {
+// ClassDef *baseClass=getClass(resName.left(i));
+// if (baseClass)
+// {
+// // add base class to this class
+// cd->insertBaseClass(baseClass,Public,Normal);
+// // add this class as super class to the base class
+// baseClass->insertSuperClass(cd,Public,Normal);
+// }
+// }
+// }
+ } // else class is already found
+ }
+ else if (root->name.right(2)!="::")
+ {
+ if (root->name.length()>0 && root->name[0]!='@')
+ warn("Warning: Compound %s\n"
+ " defined in file %s at line %d\n"
+ " is not documented\n",
+ root->name.data(),root->fileName.data(),root->startLine);
+ }
+ }
+ EntryListIterator eli(*root->sublist);
+ Entry *e;
+ for (;(e=eli.current());++eli)
+ {
+ computeClassRelations(e);
+ }
+}
+
+//-----------------------------------------------------------------------
+// compute the references (anchors in HTML) for each member in the class
+
+void computeMemberReferences()
+{
+ ClassDef *cd=classList.first();
+ while (cd)
+ {
+ cd->computeAnchors();
+ cd=classList.next();
+ }
+}
+
+//-----------------------------------------------------------------------
+// compute the references (anchors in HTML) for each function in the file
+
+void computeFunctionReferences()
+{
+ FileName *fn=inputNameList.first();
+ while (fn)
+ {
+ FileDef *fd=fn->first();
+ while (fd)
+ {
+ fd->computeAnchors();
+ fd=fn->next();
+ }
+ fn=inputNameList.next();
+ }
+ NamespaceDef *nd=namespaceList.first();
+ while (nd)
+ {
+ nd->computeAnchors();
+ nd=namespaceList.next();
+ }
+}
+
+
+
+//----------------------------------------------------------------------
+// Copy the documentation in entry `root' to member definition `md' and
+// set the function declaration of the member to `funcDecl'. If the boolean
+// over_load is set the standard overload text is added.
+
+void addMemberDocs(Entry *root,MemberDef *md, const char *funcDecl,
+ bool over_load)
+{
+ //printf("addMemberDocs: `%s'::`%s' `%s' funcDecl=`%s'\n",
+ // root->parent->name.data(),md->name().data(),md->argsString(),funcDecl);
+ QString fDecl=funcDecl;
+ // strip extern specifier
+ if (fDecl.left(7)=="extern ") fDecl=fDecl.right(fDecl.length()-7);
+ md->setDefinition(fDecl);
+ ClassDef *cd=md->memberClass();
+ NamespaceDef *nd=md->getNamespace();
+ if (matchArguments(md->argumentList(),root->argList,
+ cd ? cd->name().data() : 0,
+ nd ? nd->name().data() : 0
+ )
+ ) mergeArguments(md->argumentList(),root->argList);
+ if (over_load) // the \overload keyword was used
+ {
+ QString doc=getOverloadDocs();
+ if (!root->doc.isNull())
+ {
+ doc+="<p>";
+ doc+=root->doc;
+ }
+ md->setDocumentation(doc);
+ }
+ else
+ {
+ // documentation outside a compound overrides the documentation inside it
+ if ( /* !md->isStatic() && !root->stat && do not replace doc of a static */
+ (
+ !md->documentation() || /* no docs yet */
+ (root->parent->name.isNull() && /* or overwrite prototype docs */
+ !root->proto && md->isPrototype() /* with member definition docs */
+ )
+ ) && root->doc.length()>0
+ )
+ {
+ md->setDocumentation(root->doc);
+ }
+
+ // brief descriptions inside a compound override the documentation
+ // outside it
+ if ( /* !md->isStatic() && !root->stat && do not replace doc of static */
+ (
+ !md->briefDescription() || /* no docs yet */
+ !root->parent->name.isNull() /* member of a class */
+ ) && root->brief.length()>0
+ )
+ {
+ md->setBriefDescription(root->brief);
+ }
+ }
+ md->setDefFile(root->fileName);
+ md->setDefLine(root->startLine);
+ if (cd) cd->insertUsedFile(root->fileName);
+}
+
+//----------------------------------------------------------------------
+// Adds the documentation contained in `root' to a global function
+// with name `name' and argument list `args' (for overloading) and
+// function declaration `decl' to the corresponding member definition.
+
+bool findUnrelatedFunction(Entry *root,
+ const QString &namespaceName,
+ const char *name,
+ const char *,
+ const char *decl)
+{
+ MemberName *mn=0;
+ QString n=name;
+ if (n.find("::")!=-1) return FALSE; // skip undefined class members
+ //printf("findUnrelatedFunction(%s)\n",name);
+ if (n.length()>0 && (mn=functionNameDict[n])) // function name defined
+ {
+ int count=0;
+ MemberDef *md=mn->first();
+ while (md)
+ {
+ NamespaceDef *nd=md->getNamespace();
+ QString nsName = nd ? nd->name().data() : "";
+ if (namespaceName.length()==0 ||
+ nsName==namespaceName)
+ {
+ //printf("Searching for match between %s and %s\n",
+ // argListToString(md->argumentList()).data(),
+ // argListToString(root->argList).data());
+ bool matching=
+ /*matchArguments(md->argsString(),args);*/
+ (md->argumentList()==0 && root->argList->count()==0) ||
+ matchArguments(md->argumentList(),root->argList,0,nsName);
+ if (matching) // add docs to the member
+ {
+ //printf("Match found\n");
+ addMemberDocs(root,md,decl,FALSE);
+ count++;
+ }
+ }
+ md=mn->next();
+ }
+ if (count==0) // more than one match (each member will get the same docs)!
+ {
+ warn("Warning: no matching members found for \n%s\n"
+ "in file %s at line %d\n",
+ decl,root->fileName.data(),root->startLine);
+ }
+#if 0
+ else if (count>1) // no match!
+ {
+ warn("Warning: multiple matching members for\n%s\n",decl);
+ if (mn->count()>0) // there is a member with that name
+ {
+ warn("Possible candidates are:\n");
+ MemberDef *md=mn->first();
+ while (md) // list all possible members with the same name
+ {
+ warn(" %s%s\n",md->name(),md->argsString());
+ md=mn->next();
+ }
+ }
+ }
+#endif
+ }
+ else // got docs for an undefined member!
+ {
+ warn("Warning: documented function `%s' in file %s at line %d "
+ "was not defined \n",decl,
+ root->fileName.data(),root->startLine);
+ }
+ return TRUE;
+}
+
+
+//----------------------------------------------------------------------
+// This function tries to find a member (in a documented class/file/namespace)
+// that corresponds to the function declaration given in `funcDecl'.
+//
+// The related field may be used to specify a related class name.
+// It is only used if the class name cannot be extracted from the function
+// declaration.
+//
+// The boolean overloaded is used to specify whether or not a standard
+// overload documentation line should be generated.
+
+void findMember(Entry *root,QString funcDecl,QString related,bool overloaded,
+ bool isFunc)
+{
+ Debug::print(Debug::FindMembers,0,
+ "findMember(root=%p,funcDecl=`%s',related=`%s',overload=%d,isFunc=%d)\n",
+ root,funcDecl.data(),related.data(),overloaded,isFunc
+ );
+
+ QString scopeName;
+ QString className;
+ QString namespaceName;
+ QString classTempList;
+ QString funcType;
+ QString funcName;
+ QString funcArgs;
+ QString funcTempList;
+ QString exceptions;
+ bool isRelated=FALSE;
+ bool isFriend=FALSE;
+
+ if (funcDecl.left(7)=="friend ") // treat friends as related members
+ {
+ funcDecl=funcDecl.right(funcDecl.length()-7);
+ isFriend=TRUE;
+ }
+
+ // delete any ; from the function declaration
+ int sep;
+ while ((sep=funcDecl.find(';'))!=-1)
+ {
+ funcDecl=(funcDecl.left(sep)+funcDecl.right(funcDecl.length()-sep-1)).stripWhiteSpace();
+ }
+
+ // make sure the first character is a space to simplify searching.
+ if (funcDecl.length()>0 && funcDecl[0]!=' ') funcDecl.prepend(" ");
+
+ // remove some superfluous spaces
+ funcDecl=substitute(
+ substitute(
+ substitute(funcDecl,"~ ","~"),
+ ":: ","::"
+ ),
+ " ::","::"
+ );
+
+ // extract information from the declarations
+ parseFuncDecl(funcDecl,scopeName,classTempList,funcType,funcName,
+ funcArgs,funcTempList,exceptions
+ );
+
+ // the class name can also be a namespace name, we decide this later.
+ // if a related class name is specified and the class name could
+ // not be derived from the function declaration, then use the
+ // related field.
+ //printf("scopeName=`%s' className=`%s'\n",scopeName.data(),className.data());
+ if (/*scopeName.isEmpty() &&*/ !related.isEmpty() && !isRelated)
+ {
+ isRelated=TRUE;
+ //scopeName=resolveDefines(related);
+ if (!scopeName.isEmpty() && scopeName!=related)
+ scopeName+="::"+related;
+ else
+ scopeName=related.copy();
+ }
+ else if (scopeName.isEmpty() && related.isEmpty() && root->parent &&
+ !root->parent->name.isNull())
+ {
+ Entry *p=root->parent;
+ while (p) // get full scope as class name
+ {
+ if (((p->section & Entry::COMPOUND_MASK) ||
+ p->section == Entry::NAMESPACE_SEC
+ ) && !p->name.isEmpty() && p->name[0]!='@'
+ )
+ {
+ if (!scopeName.isEmpty()) scopeName.prepend("::");
+ scopeName.prepend(p->name);
+ break; // stop here because the class name already contains
+ // the whole scope!
+ }
+ p=p->parent;
+ }
+ }
+
+ if (scopeName.length()>0 && scopeName.find('<')==-1 && classTempList.length()==0 )
+ { // class is a template, but no template name list found
+ ClassDef *cd=getClass(scopeName);
+ if (cd) // class exists
+ {
+ classTempList = cd->getTemplateNameString();
+ }
+ }
+
+ //printf("scopeName=`%s' className=`%s'\n",scopeName.data(),className.data());
+ // rebuild the function declaration (needed to get the scope right).
+ if (scopeName.length()>0 && !isRelated && !isFriend)
+ {
+ if (funcType.length()>0)
+ {
+ if (isFunc) // a function -> we use argList for the arguments
+ {
+ funcDecl=funcType+" "+scopeName+classTempList+"::"+funcName+funcTempList;
+ }
+ else
+ {
+ funcDecl=funcType+" "+scopeName+classTempList+"::"+funcName+funcArgs;
+ }
+ }
+ else
+ {
+ if (isFunc) // a function => we use argList for the arguments
+ {
+ funcDecl=scopeName+classTempList+"::"+funcName+funcTempList;
+ }
+ else // variable => add `argument' list
+ {
+ funcDecl=scopeName+classTempList+"::"+funcName+funcArgs;
+ }
+ }
+ }
+ else // build declaration without scope
+ {
+ if (funcType.length()>0) // but with a type
+ {
+ if (isFunc) // function => omit argument list
+ {
+ funcDecl=funcType+" "+funcName+funcTempList;
+ }
+ else // variable => add `argument' list
+ {
+ funcDecl=funcType+" "+funcName+funcArgs;
+ }
+ }
+ else // no type
+ {
+ if (isFunc)
+ {
+ funcDecl=funcName+funcTempList;
+ }
+ else
+ {
+ funcDecl=funcName+funcArgs;
+ }
+ }
+ }
+
+ QString fullFuncDecl=funcDecl.copy();
+ if (isFunc) fullFuncDecl+=argListToString(root->argList);
+
+ //printf("scopeName=`%s' className=`%s'\n",scopeName.data(),className.data());
+ // see if (part of) the scope name is a namespace name
+ extractNamespaceName(scopeName,className,namespaceName);
+ //printf("scopeName=`%s' className=`%s'\n",scopeName.data(),className.data());
+
+ // destructor => do backward class name substitution if needed
+ //if (funcName.length()>0 && funcName[0]=='~')
+ // funcName="~"+resolveDefines(className);
+ // constructor => do backward class name substitution if needed
+ //if (funcName==className) funcName=resolveDefines(className);
+ //if (funcDecl.left(7)=="inline ") funcDecl=funcDecl.right(funcDecl.length()-7);
+
+ Debug::print(Debug::FindMembers,0,
+ "findMember() Parse results:\n"
+ " namespaceName=`%s'\n"
+ " className=`%s`\n"
+ " classTempList=`%s'\n"
+ " funcType=`%s'\n"
+ " funcName=`%s'\n"
+ " funcArgs=`%s'\n"
+ " funcTempList=`%s'\n"
+ " funcDecl=`%s'\n"
+ " related=`%s'\n"
+ " exceptions=`%s'\n"
+ " isRelated=%d\n"
+ " isFiend=%d\n"
+ " isFunc=%d\n\n",
+ namespaceName.data(),className.data(),classTempList.data(),
+ funcType.data(),funcName.data(),funcArgs.data(),funcTempList.data(),
+ funcDecl.data(),related.data(),exceptions.data(),isRelated,isFriend,
+ isFunc
+ );
+
+ MemberName *mn;
+ if (funcName.length()>0) // function name is valid
+ {
+ if (!isRelated && (mn=memberNameDict[funcName])) // function name already found
+ {
+ if (className.length()>0) // class name is valid
+ {
+ int count=0;
+ MemberDef *md=mn->first();
+ while (md)
+ {
+ ClassDef *cd=md->memberClass();
+ //printf("Member %s member className=%s this className=%s\n",md->name().data(),cd->name().data(),className.data());
+ ClassDef *tcd=0;
+ if (classTempList.length()>0) // try to find the correct specialization
+ {
+ tcd=getClass(scopeName+classTempList);
+ if (!tcd) tcd=getClass(scopeName); // try general class
+ }
+ else
+ {
+ tcd=getClass(scopeName);
+ }
+ //printf("tcd=%p\n",tcd);
+ if (cd && tcd==cd)
+ {
+ //printf("Class %s\n",cd->name().data());
+ bool matching=
+ md->isVariable() || md->isTypedef() || // needed for function pointers
+ (md->argumentList()==0 && root->argList->count()==0) ||
+ matchArguments(md->argumentList(), root->argList,
+ className,namespaceName);
+ if (matching)
+ {
+ addMemberDocs(root,md,funcDecl,overloaded);
+ count++;
+ }
+ }
+ md=mn->next();
+ }
+ if (count==0)
+ warn("Warning: no matching member found for \n%s\n"
+ "in file %s at line %d\n",
+ fullFuncDecl.data(),root->fileName.data(),root->startLine);
+#if 0
+ else if (count>1)
+ {
+ warn("Warning: multiple matching members for\n%s\n",funcDecl.data());
+ int matchCount=0;
+ MemberDef *md=mn->first();
+ while (md)
+ {
+ if (md->memberClass() && className==md->memberClass()->name())
+ matchCount++;
+ md=mn->next();
+ }
+ if (matchCount>0)
+ {
+ warn("Possible candidates are:\n");
+ md=mn->first();
+ while (md)
+ {
+ ClassDef *cd=md->memberClass();
+ if (cd && className==cd->name())
+ warn(" %s::%s%s\n",md->memberClass()->name(),
+ md->name(),md->argsString());
+ md=mn->next();
+ }
+ }
+ }
+#endif
+ }
+ else if (overloaded) // check if the function belongs to only one class
+ {
+ // for unique overloaded member we allow the class to be
+ // omitted, this is to be Qt compatable. Using this should
+ // however be avoided, because it is error prone
+ MemberDef *md=mn->first();
+ ASSERT(md);
+ ClassDef *cd=md->memberClass();
+ ASSERT(cd);
+ QString className=cd->name().copy();
+ md=mn->next();
+ bool unique=TRUE;
+ while (md)
+ {
+ ClassDef *cd=md->memberClass();
+ if (className!=cd->name()) unique=FALSE;
+ md=mn->next();
+ }
+ if (unique)
+ {
+ MemberDef::MemberType mtype;
+ if (root->sig) mtype=MemberDef::Signal;
+ else if (root->slot) mtype=MemberDef::Slot;
+ else mtype=MemberDef::Function;
+
+ // new overloaded member function
+ MemberDef *md=new MemberDef(funcType,funcName,funcArgs,exceptions,
+ root->protection,root->virt,root->stat,TRUE,
+ mtype,root->tArgList,root->argList);
+ md->setMemberClass(cd);
+ md->setDefinition(funcDecl);
+ QString doc=getOverloadDocs();
+ doc+="<p>";
+ doc+=root->doc;
+ md->setDocumentation(doc);
+ //md->setDecFile(root->fileName);
+ //md->setDecLine(root->startLine);
+ md->setDefFile(root->fileName);
+ md->setDefLine(root->startLine);
+ md->setPrototype(root->proto);
+ mn->inSort(md);
+ cd->insertMember(md);
+ cd->insertUsedFile(root->fileName);
+ }
+ }
+ else // unrelated function with the same name as a member
+ {
+ if (!findUnrelatedFunction(root,namespaceName,funcName+funcTempList,funcArgs,funcDecl))
+ {
+ warn("Warning: Cannot determine class for function\n%s\n"
+ "in file %s at line %d\n",fullFuncDecl.data(),
+ root->fileName.data(),root->startLine);
+ }
+ }
+ }
+ else if (isRelated && related.length()>0)
+ {
+ if (className.isEmpty()) className=related.copy();
+ ClassDef *cd;
+ if ((cd=getClass(scopeName)))
+ {
+ bool newMember=TRUE; // assume we have a new member
+ bool newMemberName=FALSE;
+ if ((mn=memberNameDict[funcName])==0)
+ {
+ mn=new MemberName(funcName);
+ newMemberName=TRUE; // we create a new member name
+ }
+ else
+ {
+ MemberDef *rmd=mn->first();
+ while (rmd && newMember) // see if we got another member with matching arguments
+ {
+ newMember=newMember &&
+ !matchArguments(rmd->argumentList(),root->argList,className,namespaceName);
+ if (newMember) rmd=mn->next();
+ }
+ if (!newMember && rmd) // member already exists as rmd -> add docs
+ {
+ addMemberDocs(root,rmd,funcDecl,overloaded);
+ }
+ }
+ if (newMember) // need to create a new member
+ {
+ MemberDef::MemberType mtype;
+ if (root->sig)
+ mtype=MemberDef::Signal;
+ else if (root->slot)
+ mtype=MemberDef::Slot;
+ else
+ mtype=MemberDef::Function;
+
+ // new related (member) function
+ MemberDef *md=new MemberDef(funcType,funcName,funcArgs,exceptions,
+ root->protection,root->virt,root->stat,TRUE,
+ mtype,root->tArgList,root->argList);
+ //printf("Related member name=`%s' decl=`%s'\n",funcName.data(),funcDecl.data());
+ md->setMemberClass(cd);
+ md->setDefinition(funcDecl);
+ md->setDocumentation(root->doc);
+ md->setBriefDescription(root->brief);
+ md->setDefFile(root->fileName);
+ md->setDefLine(root->startLine);
+ md->setPrototype(root->proto);
+ mn->inSort(md);
+ cd->insertMember(md);
+ cd->insertUsedFile(root->fileName);
+ if (newMemberName)
+ {
+ //printf("Adding memberName=%s\n",mn->memberName());
+ memberNameList.inSort(mn);
+ memberNameDict.insert(funcName,mn);
+ }
+ }
+ }
+ else
+ {
+ warn("Warning: class `%s' for related function `%s' is not "
+ "documented\n", className.data(),funcName.data());
+ }
+ }
+ else // unrelated not overloaded member found
+ {
+ if (className.length()==0 &&
+ !findUnrelatedFunction(root,namespaceName,funcName+funcTempList,funcArgs,funcDecl))
+ {
+ warn("Warning: class for member %s (file %s at line %d) cannot "
+ "be found\n", funcName.data(),root->fileName.data(),
+ root->startLine);
+ }
+ }
+ }
+ else
+ {
+ // this should not be called
+ warn("Warning: member with no name found in %s at line %d\n",
+ root->fileName.data(),root->startLine);
+ }
+ return;
+}
+
+//----------------------------------------------------------------------
+// find the members corresponding to the different documentation blocks
+// that are extracted from the sources.
+
+void findMemberDocumentation(Entry *root)
+{
+ int i,l;
+ QRegExp re("([a-zA-Z0-9: ]*[ *]+[ ]*");
+ Debug::print(Debug::FindMembers,0,
+ "root->type=`%s' root->name=`%s' root->args=`%s'\n",
+ root->type.data(),root->name.data(),root->args.data()
+ );
+ bool isFunc=TRUE;
+ if ((i=re.match(root->type,0,&l))!=-1) // func variable/typedef to func ptr
+ {
+ root->args+=root->type.right(root->type.length()-i-l);
+ root->type=root->type.left(i+l);
+ isFunc=FALSE;
+ }
+ else if (root->name.find(re)!=-1 && root->name.find("operator")!=-1)
+ // func ptr entered with \fn, \var or \typedef
+ {
+ isFunc=FALSE;
+ }
+ else if ((root->type.isEmpty() && root->name.left(8)=="typedef ")
+ || root->args.find('(')==-1)
+ {
+ isFunc=FALSE;
+ }
+ //printf("Member %s isFunc=%d\n",root->name.data(),isFunc);
+ if (root->section==Entry::MEMBERDOC_SEC)
+ {
+ //printf("Documentation for inline member `%s' found args=`%s'\n",
+ // root->name.data(),root->args.data());
+ //if (root->relates.length()) printf(" Relates %s\n",root->relates.data());
+ findMember(root,root->name+root->args+root->exception,root->relates,FALSE,isFunc);
+ }
+ else if (root->section==Entry::OVERLOADDOC_SEC)
+ {
+ //printf("Overloaded member %s found\n",root->name.data());
+ findMember(root,root->name,root->relates,TRUE,isFunc);
+ }
+ else if (root->section==Entry::FUNCTION_SEC &&
+ (root->doc.length()>0 || root->brief.length()>0 || extractAllFlag))
+ {
+ //printf("Documentation for member `%s' found args=`%s' excp=`%s'\n",
+ // root->name.data(),root->args.data(),root->exception.data());
+ //if (root->relates.length()) printf(" Relates %s\n",root->relates.data());
+ //printf("Inside=%s\n Relates=%s\n",root->inside.data(),root->relates.data());
+ if (root->type.length()>0)
+ {
+ findMember(root,
+ root->type+" "+root->inside+root->name+root->args+root->exception,
+ root->relates,
+ FALSE,isFunc);
+ }
+ else
+ {
+ findMember(root,
+ root->inside+root->name+root->args+root->exception,
+ root->relates,
+ FALSE,isFunc);
+ }
+ }
+ else if (root->section==Entry::VARIABLEDOC_SEC)
+ {
+ //printf("Documentation for variable %s found\n",root->name.data());
+ //if (root->relates.length()>0) printf(" Relates %s\n",root->relates.data());
+ findMember(root,root->name,root->relates,FALSE,FALSE);
+ }
+ EntryListIterator eli(*root->sublist);
+ Entry *e;
+ for (;(e=eli.current());++eli)
+ {
+ if (e->section!=Entry::ENUM_SEC) findMemberDocumentation(e);
+ }
+}
+
+//----------------------------------------------------------------------
+// find and add the enumeration to their classes, namespaces or files
+
+void findEnums(Entry *root)
+{
+ if (root->section==Entry::ENUM_SEC)
+ // non anonymous enumeration
+ {
+ MemberDef *md=0;
+ ClassDef *cd=0;
+ FileDef *fd=0;
+ NamespaceDef *nd=0;
+ MemberNameDict *mnd=0;
+ MemberNameList *mnl=0;
+ bool isGlobal;
+ //printf("Found enum with name `%s'\n",root->name.data());
+ int i;
+
+ QString name;
+ if ((i=root->name.findRev("::"))!=-1) // scope is specified
+ {
+ QString scope=root->name.left(i); // extract scope
+ name=root->name.right(root->name.length()-i-2); // extract name
+ cd=getClass(scope);
+ if (!cd) nd=namespaceDict[scope];
+ }
+ else // no scope, check the scope in which the docs where found
+ {
+ if (( root->parent->section & Entry::COMPOUND_MASK )
+ && root->parent->name.length()>0
+ ) // found enum docs inside a compound
+ {
+ cd=getClass(root->parent->name);
+ }
+ name=root->name.copy();
+ }
+ if (cd && name.length()>0) // found a enum inside a compound
+ {
+ //printf("Enum `%s'::`%s'\n",cd->name(),name.data());
+ fd=0;
+ mnd=&memberNameDict;
+ mnl=&memberNameList;
+ isGlobal=FALSE;
+ }
+ else if (nd) // found enum inside namespace
+ {
+ mnd=&functionNameDict;
+ mnl=&functionNameList;
+ isGlobal=TRUE;
+ }
+ else // found a global enum
+ {
+ bool ambig;
+ fd=findFileDef(&inputNameDict,root->fileName,ambig);
+ mnd=&functionNameDict;
+ mnl=&functionNameList;
+ isGlobal=TRUE;
+ }
+ if (name.length()>0)
+ {
+ // new enum type
+ md = new MemberDef(0,name,0,0,root->protection,Normal,FALSE,FALSE,
+ MemberDef::Enumeration,0,0);
+ if (!isGlobal) md->setMemberClass(cd); else md->setFileDef(fd);
+ md->setDefFile(root->fileName);
+ md->setDefLine(root->startLine);
+ if (nd)
+ {
+ md->setDefinition(nd->name()+"::"+name);
+ nd->insertMember(md);
+ md->setNamespace(nd);
+ }
+ else if (isGlobal)
+ {
+ md->setDefinition(name);
+ fd->insertMember(md);
+ }
+ else if (cd)
+ {
+ md->setDefinition(cd->name()+"::"+name);
+ cd->insertMember(md);
+ cd->insertUsedFile(root->fileName);
+ }
+ md->setDocumentation(root->doc);
+ md->setBriefDescription(root->brief);
+
+ MemberName *mn;
+ if ((mn=(*mnd)[name]))
+ {
+ // this is used if the same enum is in multiple namespaces/classes
+ mn->inSort(md);
+ }
+ else // new enum name
+ {
+ mn = new MemberName(name);
+ mn->inSort(md);
+ mnd->insert(name,mn);
+ mnl->inSort(mn);
+ //printf("add %s to new memberName. Now %d members\n",
+ // name.data(),mn->count());
+ }
+
+ EntryListIterator eli(*root->sublist);
+ Entry *e;
+ for (;(e=eli.current());++eli)
+ {
+ MemberName *fmn=0;
+ if (e->name.length()>0 && (fmn=(*mnd)[e->name]))
+ // get list of members with the same name as the field
+ {
+ MemberDef *fmd=fmn->first();
+ while (fmd) // search for the class with the right name
+ {
+ if (nd)
+ {
+ NamespaceDef *fnd=fmd->getNamespace();
+ if (fnd==nd)
+ {
+ md->insertEnumField(fmd);
+ fmd->setEnumScope(md);
+ }
+ }
+ else if (isGlobal)
+ {
+ FileDef *ffd=fmd->getFileDef();
+ if (ffd==fd)
+ {
+ md->insertEnumField(fmd);
+ fmd->setEnumScope(md);
+ }
+ }
+ else
+ {
+ ClassDef *fcd=fmd->memberClass();
+ if (fcd==cd)
+ {
+ md->insertEnumField(fmd); // add field def to list
+ fmd->setEnumScope(md); // cross ref with enum name
+ }
+ }
+ fmd=fmn->next();
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ EntryListIterator eli(*root->sublist);
+ Entry *e;
+ for (;(e=eli.current());++eli)
+ {
+ findEnums(e);
+ }
+ }
+}
+
+//----------------------------------------------------------------------
+// find the documentation blocks for the enumerations
+
+void findEnumDocumentation(Entry *root)
+{
+ if (root->section==Entry::ENUMDOC_SEC
+ && root->name.length()>0
+ && root->name[0]!='@' // skip anonymous enums
+ )
+ {
+ //printf("Found docs for enum with name `%s'\n",root->name.data());
+ int i;
+ ClassDef *cd=0;
+ QString name;
+ if ((i=root->name.findRev("::"))!=-1) // scope is specified
+ {
+ QString scope=root->name.left(i); // extract scope
+ name=root->name.right(root->name.length()-i-2); // extract name
+ cd=getClass(scope);
+ //printf("Scope=`%s' Name=`%s'\n",scope.data(),name.data());
+ }
+ else // no scope, check the scope in which the docs where found
+ {
+ if (( root->parent->section & Entry::COMPOUND_MASK )
+ && root->parent->name.length()>0
+ ) // found enum docs inside a compound
+ {
+ cd=getClass(root->parent->name);
+ }
+ name=root->name.copy();
+ }
+ if (name.length()>0)
+ {
+ bool found=FALSE;
+ if (cd)
+ {
+ //printf("Enum: scope=`%s' name=`%s'\n",cd->name(),name.data());
+ QString className=cd->name().copy();
+ MemberName *mn=memberNameDict[name];
+ if (mn)
+ {
+ MemberDef *md=mn->first();
+ while (md && !found)
+ {
+ ClassDef *cd=md->memberClass();
+ if (cd && cd->name()==className)
+ {
+ // documentation outside a compound overrides the documentation inside it
+ if (!md->documentation() || root->parent->name.length()==0)
+ {
+ md->setDocumentation(root->doc);
+ }
+
+ // brief descriptions inside a compound override the documentation
+ // outside it
+ if (!md->briefDescription() || root->parent->name.length()>0)
+ {
+ md->setBriefDescription(root->brief);
+ }
+ found=TRUE;
+ }
+ md=mn->next();
+ }
+ }
+ else
+ {
+ //printf("MemberName %s not found!\n",name.data());
+ }
+ }
+ else // enum outside class
+ {
+ MemberDef *md;
+ MemberName *mn=functionNameDict[name];
+ if (mn && (md=mn->first()))
+ {
+ md->setDocumentation(root->doc);
+ md->setBriefDescription(root->brief);
+ found=TRUE;
+ }
+ }
+ if (!found)
+ {
+ warn("Warning: Documentation for undefined enum `%s' found at"
+ " line %d of file %s\n",name.data(),
+ root->startLine,root->fileName.data());
+ }
+ }
+ }
+ EntryListIterator eli(*root->sublist);
+ Entry *e;
+ for (;(e=eli.current());++eli)
+ {
+ findEnumDocumentation(e);
+ }
+}
+
+//----------------------------------------------------------------------
+// recursive function:
+// returns TRUE iff class definition `bcd' represents an (in)direct base
+// class of class definition `cd'.
+
+bool isBaseClass(ClassDef *bcd,ClassDef *cd)
+{
+ bool found=FALSE;
+ //printf("isBaseClass(cd=%s) looking for %s\n",cd->name().data(),bcd->name().data());
+ BaseClassListIterator bcli(*cd->baseClasses());
+ for ( ; bcli.current() && !found ; ++bcli)
+ {
+ ClassDef *ccd=bcli.current()->classDef;
+ //printf("isBaseClass() baseclass %s\n",ccd->name().data());
+ if (ccd==bcd)
+ found=TRUE;
+ else
+ found=isBaseClass(bcd,ccd);
+ }
+ return found;
+}
+
+//----------------------------------------------------------------------
+// computes the relation between all members. For each member `m'
+// the members that override the implementation of `m' are searched and
+// the member that `m' overrides is searched.
+
+void computeMemberRelations()
+{
+ MemberName *mn=memberNameList.first();
+ while (mn) // for each member name
+ {
+ MemberNameIterator mdi(*mn);
+ for ( ; mdi.current() ; ++mdi) // for each function with a specific name
+ {
+ MemberDef *md=mdi.current();
+ MemberNameIterator bmdi(*mn);
+ for ( ; bmdi.current() ; ++bmdi) // for each other function with that name
+ {
+ MemberDef *bmd=bmdi.current();
+ if (md!=bmd && bmd->memberClass() && md->memberClass() &&
+ isBaseClass(bmd->memberClass(),md->memberClass()))
+ {
+ //printf("Checking Base: %s\nWith normal : %s\n",bmd->definition(),md->definition());
+ if (/*matchArguments(bmd->argsString(),md->argsString())*/
+ matchArguments(bmd->argumentList(),md->argumentList())
+ )
+ {
+ //printf("Base: %s\nNorm: %s\n",bmd->definition(),md->definition());
+ ClassDef *bmcd = bmd->memberClass();
+ ClassDef *mcd = md->memberClass();
+ if (mcd && bmcd &&
+ (bmcd->protection()!=Private || extractPrivateFlag) &&
+ (bmcd->hasDocumentation() || !hideClassFlag) &&
+ (mcd->protection()!=Private || extractPrivateFlag) &&
+ (mcd->hasDocumentation() || !hideClassFlag)
+ )
+ {
+ md->setReimplements(bmd);
+ bmd->insertReimplementedBy(md);
+ }
+ }
+ }
+ }
+ }
+ mn=memberNameList.next();
+ }
+}
+
+//----------------------------------------------------------------------------
+// recusively merges the `all members' lists of class cd's base classes
+// with that of class `cd' itself.
+
+void mergeMembers(ClassDef *cd,BaseClassList *bcl)
+{
+ //if (mcd->flag==TRUE)
+ //{
+ // err("Error: Cyclic inhertance dependency found for class %s\n",mcd->name());
+ // return;
+ //}
+ //mcd->flag=TRUE;
+
+ BaseClassListIterator bcli(*bcl);
+ BaseClassDef *bcd;
+ for ( ; (bcd=bcli.current()) ; ++bcli )
+ {
+ ClassDef *bClass=bcd->classDef;
+ // merge the members of bClass with the onces from cd
+
+ mergeMembers(bClass,bClass->baseClasses());
+ // the all member list of the branch until bClass is now complete
+ // so we can merge it with cd
+
+ MemberNameInfoList *srcMnl = bClass->memberNameInfoList();
+ MemberNameInfoDict *dstMnd = cd->memberNameInfoDict();
+ MemberNameInfoList *dstMnl = cd->memberNameInfoList();
+
+ MemberNameInfoListIterator srcMnili(*srcMnl);
+ MemberNameInfo *srcMni;
+ for ( ; (srcMni=srcMnili.current()) ; ++srcMnili)
+ {
+ //printf("Base member name %s\n",srcMni->memberName());
+ MemberNameInfo *dstMni;
+ if ((dstMni=dstMnd->find(srcMni->memberName())))
+ // a member with that name is already in the class.
+ // the member may hide or reimplement the one in the super class
+ // or there may be another path to the base class that is already
+ // visited via another branch in the class hierarchy.
+ {
+ MemberNameInfoIterator srcMnii(*srcMni);
+ MemberInfo *srcMi;
+ for ( ; (srcMi=srcMnii.current()) ; ++srcMnii )
+ {
+ MemberDef *srcMd = srcMi->memberDef;
+ bool found=FALSE;
+ bool ambigue=FALSE;
+ MemberNameInfoIterator dstMnii(*dstMni);
+ MemberInfo *dstMi;
+ for ( ; (dstMi=dstMnii.current()) && !found; ++dstMnii )
+ {
+ MemberDef *dstMd = dstMi->memberDef;
+ if (srcMd!=dstMd) // different members
+ {
+ ClassDef *srcCd = srcMd->memberClass();
+ ClassDef *dstCd = dstMd->memberClass();
+ //printf("Is %s a base class of %s?\n",srcCd->name(),dstCd->name());
+ if (srcCd==dstCd || isBaseClass(srcCd,dstCd))
+ // member is in the same or a base class
+ {
+ found =
+ /*matchArguments(srcMd->argsString(),dstMd->argsString());*/
+ matchArguments(srcMd->argumentList(),dstMd->argumentList());
+ }
+ else // member is in a non base class => multiple inheritance
+ // using the same base class.
+ {
+ //printf("$$ Existing member %s %s add scope %s\n",
+ // dstMi->ambiguityResolutionScope.data(),
+ // dstMd->name().data(),
+ // dstMi->scopePath.left(dstMi->scopePath.find("::")+2).data());
+
+ QString scope=dstMi->scopePath.left(dstMi->scopePath.find("::")+2);
+ if (scope!=dstMi->ambiguityResolutionScope.left(scope.length()))
+ dstMi->ambiguityResolutionScope.prepend(scope);
+ ambigue=TRUE;
+ }
+ }
+ else // same members
+ {
+ // do not add if base class is virtual or
+ // if scope paths are equal
+ if ((srcMi->virt==Virtual && dstMi->virt==Virtual) ||
+ bClass->name()+"::"+srcMi->scopePath == dstMi->scopePath
+ ) found=TRUE;
+ else // member can be reached via multiple paths in the
+ // inheritance tree
+ {
+ //printf("$$ Existing member %s %s add scope %s\n",
+ // dstMi->ambiguityResolutionScope.data(),
+ // dstMd->name().data(),
+ // dstMi->scopePath.left(dstMi->scopePath.find("::")+2).data());
+
+ QString scope=dstMi->scopePath.left(dstMi->scopePath.find("::")+2);
+ if (scope!=dstMi->ambiguityResolutionScope.left(scope.length()))
+ dstMi->ambiguityResolutionScope.prepend(scope);
+ ambigue=TRUE;
+ }
+ }
+ }
+ if (!found && srcMd->protection()!=Private)
+ {
+ Specifier virt=srcMi->virt;
+ if (srcMi->virt==Normal && bcd->virt!=Normal) virt=bcd->virt;
+ MemberInfo *newMi = new MemberInfo(srcMd,bcd->prot,virt);
+ //if (srcMi->memberDef->memberClass()!=bClass)
+ newMi->scopePath=bClass->name()+"::"+srcMi->scopePath;
+ if (ambigue)
+ {
+ //printf("$$ New member %s %s add scope %s::\n",
+ // srcMi->ambiguityResolutionScope.data(),
+ // srcMd->name().data(),
+ // bClass->name().data());
+
+ QString scope=bClass->name().copy(); scope+="::";
+ if (scope!=srcMi->ambiguityResolutionScope.left(scope.length()))
+ newMi->ambiguityResolutionScope=
+ scope+srcMi->ambiguityResolutionScope;
+ }
+ dstMni->append(newMi);
+ }
+ }
+ }
+ else // base class has a member that is not in the super class => copy
+ {
+ // create a deep copy of the list (only the MemberInfo's will be
+ // copied, not the actual MemberDef's)
+ MemberNameInfo *newMni = new MemberNameInfo(srcMni->memberName());
+
+ // copy the member(s) from the base to the super class
+ MemberNameInfoIterator mnii(*srcMni);
+ MemberInfo *mi;
+ for (;(mi=mnii.current());++mnii)
+ {
+ if (mi->memberDef->protection()!=Private)
+ {
+ Specifier virt=mi->virt;
+ if (mi->virt==Normal && bcd->virt!=Normal) virt=bcd->virt;
+ MemberInfo *newMi=new MemberInfo(mi->memberDef,bcd->prot,virt);
+ //if (mi->memberDef->memberClass()!=bClass)
+ newMi->scopePath=bClass->name()+"::"+mi->scopePath;
+ newMi->ambiguityResolutionScope=mi->ambiguityResolutionScope.copy();
+ newMni->append(newMi);
+ }
+ }
+
+ // add it to the list and dictionary
+ dstMnl->inSort(newMni);
+ dstMnd->insert(newMni->memberName(),newMni);
+ }
+ }
+ }
+}
+
+//----------------------------------------------------------------------------
+// builds the list of all members for each class
+
+void buildCompleteMemberLists()
+{
+ ClassDef *cd;
+ ClassListIterator cli(classList);
+ for (;(cd=cli.current());++cli)
+ {
+ //if (!cd->isReference()) printf("Building member for class %s\n",cd->name());
+ //ClassListIterator vcli(classList);
+ //for (;(vcd=vcli.current());++vcli) vcd->flag = FALSE;
+ if (!cd->isReference() && // not an external class
+ cd->superClasses()->count()==0 && // is a root of the hierarchy
+ cd->baseClasses()->count()>0) // and has at least one base class
+ {
+ //printf("merging members for class %s\n",cd->name());
+ mergeMembers(cd,cd->baseClasses());
+ }
+ }
+}
+
+//----------------------------------------------------------------------------
+
+void generateFileDocs()
+{
+ if (documentedFiles==0) return;
+ writeFileIndex(*outputList);
+
+ if (inputNameList.count()>0)
+ {
+ FileName *fn=inputNameList.first();
+ while (fn)
+ {
+ FileDef *fd=fn->first();
+ while (fd)
+ {
+ if (!fd->isReference() && fd->hasDocumentation())
+ {
+ msg("Generating docs for file %s...\n",fd->name().data());
+ fd->writeDocumentation(*outputList);
+ }
+ fd=fn->next();
+ }
+ fn=inputNameList.next();
+ }
+ }
+}
+
+//----------------------------------------------------------------------------
+// generate the documentation of all classes
+
+void generateClassDocs()
+{
+ // write the installdox script if necessary
+ if (generateHtml && (tagFileList.count()>0 || searchEngineFlag))
+ writeInstallScript();
+
+ msg("Generating index page...\n");
+ writeIndex(*outputList);
+
+ msg("Generating compound index...\n");
+ writeAnnotatedIndex(*outputList);
+
+ msg("Generating hierarchical class index...\n");
+ writeHierarchicalIndex(*outputList);
+
+ if (includeFiles.count()>0)
+ {
+ msg("Generating header index...\n");
+ writeHeaderIndex(*outputList);
+ }
+
+ msg("Generating member index...\n");
+ writeMemberIndex(*outputList);
+
+ if (exampleList.count()>0)
+ {
+ msg("Generating example index...\n");
+ }
+
+ ClassListIterator cli(classList);
+ for ( ; cli.current() ; ++cli )
+ {
+ ClassDef *cd=cli.current();
+ if (!cd->isReference() &&
+ //!cd->name().isEmpty() &&
+ //cd->name().at(0)!='@' &&
+ //(cd->protection()!=Private || extractPrivateFlag) &&
+ //(cd->hasDocumentation() || !hideClassFlag)
+ cd->isVisible()
+ )
+ // skip external references and anonymous compounds
+ {
+ msg("Generating docs for compound %s...\n",cd->name().data());
+
+ cd->writeDocumentation(*outputList);
+ cd->writeMemberList(*outputList);
+ if (verbatimHeaderFlag) cd->writeIncludeFile(*outputList);
+ }
+ }
+}
+
+//----------------------------------------------------------------------------
+
+void findDefineDocumentation(Entry *root)
+{
+ if ((root->section==Entry::DEFINEDOC_SEC ||
+ root->section==Entry::DEFINE_SEC) && root->name.length()>0
+ )
+ {
+ //printf("found define `%s' `%s' brief=`%s' doc=`%s'\n",
+ // root->name.data(),root->args.data(),root->brief.data(),root->doc.data());
+ MemberName *mn=functionNameDict[root->name];
+ if (mn)
+ {
+ int count=0;
+ MemberDef *md=mn->first();
+ while (md)
+ {
+ if (md->memberType()==MemberDef::Define) count++;
+ md=mn->next();
+ }
+ if (count==1)
+ {
+ md=mn->first();
+ while (md)
+ {
+ if (md->memberType()==MemberDef::Define)
+ {
+ if (md->documentation().isEmpty())
+ md->setDocumentation(root->doc);
+ if (md->briefDescription().isEmpty())
+ md->setBriefDescription(root->brief);
+ }
+ md=mn->next();
+ }
+ }
+ else if (count>1 && (root->doc.length()>0 || root->brief.length()>0))
+ // multiple defines don't know where to add docs
+ {
+ md=mn->first();
+ while (md)
+ {
+ if (md->memberType()==MemberDef::Define)
+ {
+ FileDef *fd=md->getFileDef();
+ if (fd && fd->absFilePath()==root->fileName)
+ // doc and define in the same file assume they belong together.
+ {
+ if (md->documentation().isEmpty())
+ md->setDocumentation(root->doc);
+ if (md->briefDescription().isEmpty())
+ md->setBriefDescription(root->brief);
+ }
+ }
+ md=mn->next();
+ }
+ //warn("Warning: define %s found in the following files:\n",root->name.data());
+ //warn("Cannot determine where to add the documentation found "
+ // "at line %d of file %s. \n",
+ // root->startLine,root->fileName.data());
+ }
+ }
+ else // define not found
+ {
+ warn("Warning: documentation for unknown define %s found at line %d of "
+ "file %s\n",root->name.data(),root->startLine,root->fileName.data());
+ }
+ }
+ EntryListIterator eli(*root->sublist);
+ Entry *e;
+ for (;(e=eli.current());++eli)
+ {
+ findDefineDocumentation(e);
+ }
+}
+
+//----------------------------------------------------------------------------
+
+//----------------------------------------------------------------------------
+// create a (sorted) list of separate documentation pages
+
+void buildPageList(Entry *root)
+{
+ if (root->section == Entry::PAGEDOC_SEC)
+ {
+ if (root->name.length()>0)
+ {
+ PageInfo *pi=0;
+ if ((pi=pageDict[root->name]))
+ {
+ //warn("Warning: Page %s was already documented. Ignoring documentation "
+ // "at line %d of %s\n",root->name.data(),root->startLine,
+ // root->fileName.data());
+
+ // append documentation block to the page.
+ pi->doc+="\n\n"+root->doc;
+ }
+ else
+ {
+ QString baseName=root->name.copy();
+ if (baseName.right(4)==".tex")
+ baseName=baseName.left(baseName.length()-4);
+ else if (baseName.right(5)==".html")
+ baseName=baseName.left(baseName.length()-5);
+ pi=new PageInfo(baseName, root->doc,
+ root->args.stripWhiteSpace());
+ pageList.append(pi);
+ pageDict.insert(baseName,pi);
+ if (pi->title.length()>0)
+ {
+ QString pageName;
+ if (caseSensitiveNames)
+ pageName=pi->name.copy();
+ else
+ pageName=pi->name.lower();
+ //outputList->writeTitle(pi->name,pi->title);
+ SectionInfo *si=new SectionInfo(pageName+".html",
+ pi->name,pi->title,FALSE);
+ //printf("Adding section info %s\n",pi->name.data());
+ sectionDict.insert(pi->name,si);
+ }
+ }
+ }
+ }
+ EntryListIterator eli(*root->sublist);
+ Entry *e;
+ for (;(e=eli.current());++eli)
+ {
+ buildPageList(e);
+ }
+}
+
+//----------------------------------------------------------------------------
+// generate all separate documentation pages
+
+void generatePageDocs()
+{
+ PageInfo *pi=pageList.first();
+ while (pi)
+ {
+ if (!pi->title.isEmpty())
+ {
+ msg("Generating docs for page %s...\n",pi->title.data());
+ }
+ else
+ {
+ msg("Generating docs for page %s...\n",pi->name.data());
+ }
+ outputList->disable(OutputGenerator::Man);
+ QString pageName;
+ if (caseSensitiveNames)
+ pageName=pi->name.copy();
+ else
+ pageName=pi->name.lower();
+
+ startFile(*outputList,pageName,pi->title);
+ SectionInfo *si=0;
+ if (pi->title.length()>0 && pi->name.length()>0 &&
+ (si=sectionDict[pi->name])!=0)
+ {
+ outputList->writeSection(si->label,si->title,FALSE);
+ }
+ parseDoc(*outputList,0,0,pi->doc);
+ endFile(*outputList);
+ outputList->enable(OutputGenerator::Man);
+ pi=pageList.next();
+ }
+}
+
+//----------------------------------------------------------------------------
+// create a (sorted) list & dictionary of example pages
+
+void buildExampleList(Entry *root)
+{
+ if (root->section == Entry::EXAMPLE_SEC)
+ {
+ if (root->name.length()>0)
+ {
+ if (exampleDict[root->name])
+ {
+ warn("Warning: Example %s was already documented. Ignoring "
+ "documentation at line %d of %s\n",root->name.data(),
+ root->startLine,root->fileName.data());
+ }
+ else
+ {
+ PageInfo *pi=new PageInfo(root->name,root->doc,root->args);
+ exampleList.inSort(pi);
+ exampleDict.insert(root->name,pi);
+ }
+ }
+ }
+ //EntryList *entryList=root->sublist;
+ //Entry *e = entryList->first();
+ //while (e)
+ //{
+ // buildExampleList(e);
+ // e=entryList->next();
+ //}
+ EntryListIterator eli(*root->sublist);
+ Entry *e;
+ for (;(e=eli.current());++eli)
+ {
+ buildExampleList(e);
+ }
+}
+
+//----------------------------------------------------------------------------
+// generate the example documentation
+
+void generateExampleDocs()
+{
+ PageInfo *pi=exampleList.first();
+ while (pi)
+ {
+ msg("Generating docs for example %s...\n",pi->name.data());
+ QString n=convertSlashes(pi->name,TRUE)+"-example";
+ startFile(*outputList,n,"Example Documentation");
+ //outputList->writeTitle(pi->name,pi->name);
+ parseExample(*outputList,pi->doc+"\n\\include "+pi->name,pi->name);
+ endFile(*outputList);
+ pi=exampleList.next();
+ }
+}
+
+//----------------------------------------------------------------------------
+// generate module pages
+
+void generateGroupDocs()
+{
+ GroupListIterator gli(groupList);
+ GroupDef *gd;
+ for (;(gd=gli.current());++gli)
+ {
+ //printf("group %s #members=%d\n",gd->name().data(),gd->countMembers());
+ if (gd->countMembers()>0) gd->writeDocumentation(*outputList);
+ }
+}
+
+//----------------------------------------------------------------------------
+// generate module pages
+
+void generateNamespaceDocs()
+{
+ writeNamespaceIndex(*outputList);
+
+ NamespaceListIterator nli(namespaceList);
+ NamespaceDef *nd;
+ for (;(nd=nli.current());++nli)
+ {
+ msg("Generating docs for namespace %s\n",nd->name().data());
+ nd->writeDocumentation(*outputList);
+ }
+}
+
+//----------------------------------------------------------------------------
+// generate files for the search engine
+
+void generateSearchIndex()
+{
+ if (searchEngineFlag && generateHtml)
+ {
+ // create search index
+ QString fileName;
+ writeSearchButton(htmlOutputDir);
+
+ // create cgi script
+ fileName = htmlOutputDir+"/"+cgiName;
+ QFile f(fileName);
+ if (f.open(IO_WriteOnly))
+ {
+ QTextStream t(&f);
+ t << "#!/bin/sh" << endl
+ << "DOXYSEARCH=" << binAbsPath << "/doxysearch" << endl
+ << "DOXYPATH=" << docAbsPath << " ";
+
+ char *s=extDocPathList.first();
+ while (s)
+ {
+ t << s << " ";
+ s=extDocPathList.next();
+ }
+
+ t << endl
+ << "if [ -f $DOXYSEARCH ]" << endl
+ << "then" << endl
+ << " $DOXYSEARCH $DOXYPATH" << endl
+ << "else" << endl
+ << " echo \"Content-Type: text/html\"" << endl
+ << " echo \"\"" << endl
+ << " echo \"<H1>Error: $DOXYSEARCH not found. Check cgi script!\"" << endl
+ << "fi" << endl;
+
+ f.close();
+ struct stat stat_struct;
+ stat(fileName,&stat_struct);
+#if !defined(_WIN32)
+ chmod(fileName,stat_struct.st_mode|S_IXUSR|S_IXGRP|S_IXOTH);
+#endif
+ }
+ else
+ {
+ err("Error: Cannot open file %s for writing\n",fileName.data());
+ }
+
+ // create config file
+ fileName = htmlOutputDir+"/search.cfg";
+ f.setName(fileName);
+ if (f.open(IO_WriteOnly))
+ {
+ QTextStream t(&f);
+ t << docURL << endl << cgiURL << "/" << cgiName << endl;
+ f.close();
+ }
+ else
+ {
+ err("Error: Cannot open file %s for writing\n",fileName.data());
+ }
+ //outputList->generateExternalIndex();
+ outputList->disableAllBut(OutputGenerator::Html);
+ startFile(*outputList,"header.html","Search Engine",TRUE);
+ outputList->endPlainFile();
+ outputList->startPlainFile("footer.html");
+ endFile(*outputList,TRUE);
+ outputList->enableAll();
+ }
+}
+
+//----------------------------------------------------------------------------
+// generate the configuration file
+
+void generateConfigFile(const char *configFile,bool shortList)
+{
+ QFileInfo fi(configFile);
+ QFile f(configFile);
+
+ if (fi.exists()) // create a backup
+ {
+ QDir dir=fi.dir();
+ dir.rename(fi.fileName(),fi.fileName()+".bak");
+ }
+ if (f.open(IO_WriteOnly))
+ {
+ writeTemplateConfig(&f,shortList);
+ f.close();
+ msg("\n\nConfiguration file `%s' created.\n\n",configFile);
+ msg("Now edit the configuration file and enter\n\n");
+ if (strcmp(configFile,"Doxyfile") || strcmp(configFile,"doxyfile"))
+ msg(" doxygen %s\n\n",configFile);
+ else
+ msg(" doxygen\n\n");
+ msg("to generate the documentation for your project\n\n");
+ }
+ else
+ {
+ err("Error: Cannot open file %s for writing\n");
+ exit(1);
+ }
+}
+
+//----------------------------------------------------------------------------
+// read and parse a tag file
+
+bool readLineFromFile(QFile &f,QString &s)
+{
+ char c=0;
+ s.resize(0);
+ while (!f.atEnd() && (c=f.getch())!='\n') s+=c;
+ return f.atEnd();
+}
+
+void readTagFile(const char *file)
+{
+ QFileInfo fi(file);
+ if (!fi.exists() || !fi.isFile())
+ {
+ err("Error: Tag file `%s' does not exist or is not a file\n",file);
+ exit(1);
+ }
+ msg("Reading tag file %s...\n",file);
+ parseTagFile(file);
+}
+
+//----------------------------------------------------------------------------
+// returns TRUE if the name of the file represented by `fi' matches
+// one of the file patterns in the `patList' list.
+
+bool patternMatch(QFileInfo *fi,QStrList *patList)
+{
+ bool found=FALSE;
+ if (patList)
+ {
+ char *pattern=patList->first();
+ while (pattern && !found)
+ {
+ found = found || QDir::match(pattern,fi->fileName());
+ pattern=patList->next();
+ }
+ }
+ return found;
+}
+
+//----------------------------------------------------------------------------
+// reads a file into an array and filters out any 0x00 and 0x06 bytes,
+// because these are special for the parser.
+
+void copyAndFilterFile(const char *fileName,BufStr &dest)
+{
+ // try to open file
+ int size=0;
+ uint oldPos = dest.curPos();
+
+ QFileInfo fi(fileName);
+ if (!fi.exists()) return;
+ if (inputFilter.isEmpty())
+ {
+ QFile f(fileName);
+ if (!f.open(IO_ReadOnly))
+ {
+ err("Error: could not open file %s\n",fileName);
+ return;
+ }
+ size=fi.size();
+ // read the file
+ dest.skip(size);
+ if (f.readBlock(dest.data()+oldPos,size)!=size)
+ {
+ err("Error while reading file %s\n",fileName);
+ return;
+ }
+ }
+ else
+ {
+ int c;
+// char *p=dest;
+ QString cmd=inputFilter+" "+fileName;
+ FILE *f=popen(cmd,"r");
+ if (!f)
+ {
+ err("Error: could not execute filter %s\n",inputFilter.data());
+ return;
+ }
+ while ((c=fgetc(f))!=EOF) dest.addChar(c),size++;
+ }
+ // filter unwanted bytes from the resulting data
+ uchar *p=(uchar *)dest.data()+oldPos;
+ uchar conv[256];
+ int i;
+ for (i=0;i<256;i++) conv[i]=i;
+ conv[0x06]=0x20; // replace the offending characters with spaces
+ conv[0x00]=0x20;
+ // remove any special markers from the input
+ for (i=0;i<size;i++,p++) *p=conv[*p];
+ // adjust pointer
+}
+
+//----------------------------------------------------------------------------
+// Reads a file to a string.
+// The name of the file is written in front of the file's contents and
+// between 0x06 markers
+
+
+void readFiles(BufStr &output)
+{
+ QString *s=inputFiles.first();
+// char *p=output.data();
+ while (s)
+ {
+ QString fileName=*s;
+
+ //int fileSize=fi->fileInfo()->size();
+ int fileNameSize=fileName.length();
+ //int streamLength=fileSize+fileNameSize+4;
+
+ //QString fileText(streamLength);
+
+ // add begin filename marker
+// *p++=0x06;
+ output.addChar(0x06);
+ // copy filename
+// memcpy(p,fileName.data(),fileNameSize);
+// p+=fileNameSize;
+ output.addArray(fileName.data(),fileNameSize);
+
+ // add end filename marker
+// *p++=0x06;
+ output.addChar(0x06);
+// *p++='\n'; // to make ^ work while scanning the first line of a file!
+ output.addChar('\n');
+ if (preprocessingFlag)
+ {
+ msg("Preprocessing %s...\n",s->data());
+ preprocessFile(fileName,output);
+ }
+ else
+ {
+ msg("Reading %s...\n",s->data());
+ copyAndFilterFile(fileName,output);
+ }
+
+ s=inputFiles.next();
+ }
+// *p++='\0';
+ output.addChar(0);
+ //printf("Output after preprocessing:\n---------\n%s\n----------\n",output.data());
+ //printf("Final length = %d\n",p-output.data());
+}
+
+//----------------------------------------------------------------------------
+// Read all files matching at least one pattern in `patList' in the
+// directory represented by `fi'.
+// The directory is read iff the recusiveFlag is set.
+// The contents of all files is append to the input string
+
+int readDir(QFileInfo *fi,
+ FileNameList *fnList,
+ FileNameDict *fnDict,
+ StringDict *exclDict,
+ QStrList *patList,
+ QStrList *exclPatList,
+ StringList *resultList,
+ StringDict *resultDict
+ )
+{
+ QDir dir((const char *)fi->absFilePath());
+ dir.setFilter( QDir::Files | QDir::Dirs );
+ int totalSize=0;
+
+ const QFileInfoList *list = dir.entryInfoList();
+ QFileInfoListIterator it( *list );
+ QFileInfo *cfi;
+
+ while ((cfi=it.current()))
+ {
+ if (exclDict==0 || exclDict->find(cfi->absFilePath())==0)
+ { // file should not be excluded
+ if (!cfi->exists() || !cfi->isReadable())
+ {
+ err("Error: source %s is not a readable file or directory... skipping.\n",cfi->absFilePath().data());
+ }
+ else if (cfi->isFile() &&
+ patternMatch(cfi,patList) && !patternMatch(cfi,exclPatList))
+ {
+ totalSize+=cfi->size()+cfi->absFilePath().length()+3;
+ QString name=cfi->fileName();
+ if (fnDict)
+ {
+ FileDef *fd=new FileDef(cfi->dirPath()+"/",name);
+ FileName *fn=0;
+ if (name.length()>0 && (fn=(*fnDict)[name]))
+ {
+ fn->append(fd);
+ }
+ else
+ {
+ fn = new FileName(name);
+ fn->append(fd);
+ if (fnList) fnList->inSort(fn);
+ fnDict->insert(name,fn);
+ }
+ }
+ QString *rs=0;
+ if (resultList || resultDict)
+ {
+ rs=new QString(cfi->absFilePath());
+ }
+ if (resultList) resultList->append(rs);
+ if (resultDict) resultDict->insert(cfi->absFilePath(),rs);
+ }
+ else if (recursiveFlag && cfi->isDir() && cfi->fileName()!="." &&
+ cfi->fileName()!="..")
+ {
+ cfi->setFile(cfi->absFilePath());
+ totalSize+=readDir(cfi,fnList,fnDict,exclDict,
+ patList,exclPatList,resultList,resultDict);
+ }
+ }
+ ++it;
+ }
+ return totalSize;
+}
+
+//----------------------------------------------------------------------------
+// read the file with name `name' into a string.
+
+QString readExampleFile(const char *name)
+{
+ QString example;
+ QFileInfo fi(name);
+ if (fi.exists())
+ {
+ QFile f((const char *)fi.absFilePath());
+ if (f.open(IO_ReadOnly))
+ {
+ example.resize(fi.size()+1);
+ if ((int)fi.size()!=f.readBlock(example.data(),fi.size()))
+ {
+ err("Error while reading file %s\n",fi.absFilePath().data());
+ //exit(1);
+ return "";
+ }
+ example.at(fi.size())='\0';
+ }
+ else
+ {
+ err("Error opening file %s\n",fi.absFilePath().data());
+ //exit(1);
+ return "";
+ }
+ }
+ else
+ {
+ err("Error: example file %s does not exist\n",name);
+ exit(1);
+ }
+ return example;
+}
+
+//----------------------------------------------------------------------------
+// read a file or all files in a directory and append their contents to the
+// input string. The names of the files are appended to the `fiList' list.
+
+int readFileOrDirectory(const char *s,
+ FileNameList *fnList,
+ FileNameDict *fnDict,
+ StringDict *exclDict,
+ QStrList *patList,
+ QStrList *exclPatList,
+ StringList *resultList,
+ StringDict *resultDict
+ )
+{
+ QFileInfo fi(s);
+ int totalSize=0;
+ {
+ if (exclDict==0 || exclDict->find(fi.absFilePath())==0)
+ {
+ if (!fi.exists() || !fi.isReadable())
+ {
+ err("Error: source %s is not a readable file or directory... skipping.\n",s);
+ }
+ else if (fi.isFile())
+ {
+ totalSize+=fi.size()+fi.absFilePath().length()+3; //readFile(&fi,fiList,input);
+ //fiList->inSort(new FileInfo(fi));
+ QString name=fi.fileName();
+ if (fnDict)
+ {
+ FileDef *fd=new FileDef(fi.dirPath(TRUE)+"/",name);
+ FileName *fn=0;
+ if (name.length()>0 && (fn=(*fnDict)[name]))
+ {
+ fn->append(fd);
+ }
+ else
+ {
+ fn = new FileName(name);
+ fn->append(fd);
+ if (fnList) fnList->inSort(fn);
+ fnDict->insert(name,fn);
+ }
+ }
+ QString *rs=0;
+ if (resultList || resultDict)
+ {
+ rs=new QString(fi.absFilePath());
+ }
+ if (resultList) resultList->append(rs);
+ if (resultDict) resultDict->insert(fi.absFilePath(),rs);
+ }
+ else if (fi.isDir()) // readable dir
+ totalSize+=readDir(&fi,fnList,fnDict,exclDict,patList,
+ exclPatList,resultList,resultDict);
+ }
+ }
+ return totalSize;
+}
+
+//----------------------------------------------------------------------------
+
+void readFormulaRepository()
+{
+ QFile f(htmlOutputDir+"/formula.repository");
+ if (f.open(IO_ReadOnly)) // open repository
+ {
+ QTextStream t(&f);
+ QString line;
+ while (!t.eof())
+ {
+ line=t.readLine();
+ int se=line.find(':'); // find name and text separator.
+ if (se==-1)
+ {
+ warn("Warning: formula.repository is corrupted!\n");
+ break;
+ }
+ else
+ {
+ QString formName = line.left(se);
+ QString formText = line.right(line.length()-se-1);
+ Formula *f=new Formula(formText);
+ formulaList.append(f);
+ formulaDict.insert(formText,f);
+ formulaNameDict.insert(formName,f);
+ }
+ }
+ }
+}
+
+//----------------------------------------------------------------------------
+// print the usage of doxygen
+
+void usage(const char *name)
+{
+ msg("Doxygen version %s\nCopyright Dimitri van Heesch 1997-1999\n\n",versionString);
+ msg("You can use doxygen in two ways:\n\n");
+ msg("1) Use doxygen to generate a template configuration file:\n");
+ msg(" %s [-s] -g [configName]\n\n",name);
+ msg(" if -s is specified the comments in the config file will be omitted.\n\n");
+ msg("2) Use doxygen to generate documentation using an existing ");
+ msg("configuration file:\n");
+ msg(" %s [configName]\n\n",name);
+ msg("If configName is omitted `Doxyfile' will be used as a default.\n\n");
+ exit(1);
+}
+
+//----------------------------------------------------------------------------
+// read the argument of option `c' from the comment argument list and
+// update the option index `optind'.
+
+const char *getArg(int argc,char **argv,int &optind)
+{
+ char *s=0;
+ if (strlen(&argv[optind][2])>0)
+ s=&argv[optind][2];
+ else if (optind+1<argc)
+ s=argv[++optind];
+ return s;
+}
+
+//----------------------------------------------------------------------------
+
+int main(int argc,char **argv)
+{
+
+ initPreprocessor();
+
+ /**************************************************************************
+ * Handle arguments *
+ **************************************************************************/
+
+ char *s;
+ int optind=1;
+ const char *configName=0;
+ const char *debugLabel;
+ bool genConfig=FALSE;
+ bool shortList=FALSE;
+ while (optind<argc && argv[optind][0]=='-')
+ {
+ switch(argv[optind][1])
+ {
+ case 'g':
+ genConfig=TRUE;
+ configName=getArg(argc,argv,optind);
+ if (!configName) configName="Doxyfile";
+ break;
+ case 'd':
+ debugLabel=getArg(argc,argv,optind);
+ Debug::setFlag(debugLabel);
+ break;
+ case 's':
+ shortList=TRUE;
+ break;
+ case 'h':
+ case '?':
+ usage(argv[0]);
+ break;
+ default:
+ err("Unknown option -%c\n",argv[optind][1]);
+ usage(argv[0]);
+ }
+ optind++;
+ }
+
+ /**************************************************************************
+ * Parse or generate the config file *
+ **************************************************************************/
+
+ if (genConfig)
+ {
+ generateConfigFile(configName,shortList);
+ exit(1);
+ }
+
+ QFileInfo configFileInfo1("Doxyfile"),configFileInfo2("doxyfile");
+ QString config;
+ if (optind>=argc)
+ {
+ if (configFileInfo1.exists())
+ config=fileToString("Doxyfile");
+ else if (configFileInfo2.exists())
+ {
+ config=fileToString("doxyfile");
+ }
+ else
+ {
+ err("Doxyfile not found and no input file specified!\n");
+ usage(argv[0]);
+ }
+ }
+ else
+ config=fileToString(argv[1]);
+
+ parseConfig(config);
+
+ /**************************************************************************
+ * Initialize output generators *
+ **************************************************************************/
+
+ outputList = new OutputList(TRUE);
+ if (generateHtml)
+ {
+ outputList->add(new HtmlGenerator);
+ HtmlGenerator::init();
+ }
+ if (generateLatex)
+ {
+ outputList->add(new LatexGenerator);
+ LatexGenerator::init();
+ }
+ if (generateMan)
+ {
+ outputList->add(new ManGenerator);
+ ManGenerator::init();
+ }
+
+ /**************************************************************************
+ * Read and preprocess input *
+ **************************************************************************/
+
+ // gather names of all files in the include path
+ msg("Searching for include files...\n");
+ s=includePath.first();
+ while (s)
+ {
+ readFileOrDirectory(s,0,&includeNameDict,0,&filePatternList,
+ &excludePatternList,0,0);
+ s=includePath.next();
+ }
+
+ msg("Searching for example files...\n");
+ s=examplePath.first();
+ while (s)
+ {
+ readFileOrDirectory(s,0,&exampleNameDict,0,&filePatternList,
+ &excludePatternList,0,0);
+ s=examplePath.next();
+ }
+
+ msg("Searching for files to exclude\n");
+ s=excludeSources.first();
+ while (s)
+ {
+ readFileOrDirectory(s,0,0,0,&filePatternList,
+ 0,0,&excludeNameDict);
+ s=excludeSources.next();
+ }
+
+ msg("Reading input files...\n");
+ int inputSize=0;
+ s=inputSources.first();
+ while (s)
+ {
+ inputSize+=readFileOrDirectory(s,&inputNameList,
+ &inputNameDict,&excludeNameDict,
+ &filePatternList,&excludePatternList,
+ &inputFiles,0);
+ s=inputSources.next();
+ }
+ //msg("Input size %d bytes\n",inputSize);
+
+ BufStr input(inputSize+1); // Add one byte extra for \0 termination
+ readFiles(input);
+
+ if (input.length()==0)
+ {
+ warn("No input read, no output generated!\n");
+ exit(1);
+ }
+ else
+ {
+ msg("Read %d bytes\n",input.length());
+ }
+
+ /**************************************************************************
+ * Handle Tag Files *
+ **************************************************************************/
+
+ msg("Reading tag files\n");
+
+ s=tagFileList.first();
+ while (s)
+ {
+ readTagFile(s);
+ s=tagFileList.next();
+ }
+
+ QFile *tag =new QFile(genTagFile);
+ if (genTagFile.length()>0)
+ {
+ if (!tag->open(IO_WriteOnly))
+ {
+ err("Error: cannot open tag file %s for writing\n",genTagFile.data());
+ exit(1);
+ }
+ tagFile.setDevice(tag);
+ }
+
+ /**************************************************************************
+ * Gather information *
+ **************************************************************************/
+
+ // Notice: the order of the function calls below is very important!
+
+ if (generateHtml)
+ {
+ msg("Reading formula repository...\n");
+ readFormulaRepository();
+ }
+
+ Entry *root=new Entry;
+ root->program=input;
+
+ msg("Parsing input...\n");
+ parseMain(root); // build a tree of entries
+
+ msg("Freeing input...\n");
+ input.resize(0);
+
+ msg("Building namespace list...\n");
+ buildNamespaceList(root);
+
+ msg("Building group list...\n");
+ buildGroupList(root);
+
+ //msg("Computing group relations...\n");
+ //computeGroupRelations(root);
+
+ msg("Building file list...\n");
+ buildFileList(root);
+
+ msg("Building class list...\n");
+ buildClassList(root);
+
+ msg("Building example list...\n");
+ buildExampleList(root);
+
+ msg("Building page list...\n");
+ buildPageList(root);
+
+// msg("Adding compounds to file pages...\n");
+// findClassDefsInFiles(root);
+
+ msg("Building member list...\n"); // using class info only !
+ buildMemberList(root);
+ transferFunctionDocumentation();
+
+ msg("Searching for friends...\n");
+ findFriends();
+
+
+ msg("Searching for documented variables...\n");
+ buildVarList(root);
+
+ msg("Searching for documented defines...\n");
+ findDefineDocumentation(root);
+
+ msg("Computing class relations...\n");
+ computeClassRelations(root);
+
+ msg("Searching for enumerations...\n");
+ findEnums(root);
+ findEnumDocumentation(root);
+
+// msg("Searching for function prototypes...\n");
+// findPrototypes(root); // may introduce new members !
+
+ msg("Searching for member function documentation...\n");
+ findMemberDocumentation(root); // may introduce new members !
+
+ msg("Freeing entry tree\n");
+ delete root;
+
+ msg("Computing member references...\n");
+ computeMemberReferences();
+
+ msg("Computing function references...\n");
+ computeFunctionReferences();
+
+ msg("Computing member relations...\n");
+ computeMemberRelations();
+
+ msg("Building full member lists recursively...\n");
+ buildCompleteMemberLists();
+
+ //unrelatedFunctionsUsed=hasUnrelatedFunctions();
+
+ /**************************************************************************
+ * Generate documentation *
+ **************************************************************************/
+
+ // count the number of documented elements in the lists we have built.
+ // If the result is 0 we do not generate the lists and omit the
+ // corresponding links in the index.
+ msg("Counting data structures...\n");
+ annotatedClasses = countAnnotatedClasses();
+ hierarchyClasses = countClassHierarchy();
+ documentedMembers = countMemberList();
+ documentedFunctions = countFunctionList();
+ documentedFiles = countFileList();
+ documentedGroups = countGroupList();
+ documentedNamespaces = countNamespaceList();
+
+ // compute the shortest possible names of all files
+ // without loosing the uniqueness of the file names.
+ msg("Generating disk names...\n");
+ inputNameList.generateDiskNames();
+
+ msg("Generating example documentation...\n");
+ generateExampleDocs();
+
+ msg("Generating file documentation...\n");
+ generateFileDocs();
+
+ msg("Generating class documentation...\n");
+ generateClassDocs();
+
+ msg("Generating page documentation...\n");
+ generatePageDocs();
+
+ msg("Generating group documentation...\n");
+ generateGroupDocs();
+
+ msg("Generating namespace index...\n");
+ generateNamespaceDocs();
+
+ msg("Generating group index...\n");
+ writeGroupIndex(*outputList);
+
+ msg("Generating example index...\n");
+ writeExampleIndex(*outputList);
+
+ msg("Generating function index...\n");
+ writeFunctionIndex(*outputList);
+
+// msg("Generating define index...\n");
+// writeDefineIndex(*outputList);
+
+ msg("Generating page index...\n");
+ writePageIndex(*outputList);
+
+ msg("Generating search index...\n");
+ generateSearchIndex();
+
+ msg("Generating style sheet...\n");
+ outputList->writeStyleInfo(0); // write first part
+ outputList->disableAllBut(OutputGenerator::Latex);
+ parseDoc(*outputList,0,0,
+ theTranslator->trGeneratedAt(dateToString(TRUE),projectName)
+ );
+ outputList->writeStyleInfo(1); // write second part
+ parseDoc(*outputList,0,0, theTranslator->trWrittenBy());
+ outputList->writeStyleInfo(2); // write third part
+ parseDoc(*outputList,0,0,
+ theTranslator->trGeneratedAt(dateToString(TRUE),projectName)
+ );
+ outputList->writeStyleInfo(3); // write fourth part
+ parseDoc(*outputList,0,0, theTranslator->trWrittenBy());
+ outputList->writeStyleInfo(4); // write last part
+ outputList->enableAll();
+
+ if (formulaList.count()>0 && generateHtml)
+ {
+ msg("Generating bitmaps for formulas in HTML...\n");
+ formulaList.generateBitmaps(htmlOutputDir);
+ }
+
+ if (searchEngineFlag || tagFileList.count()>0)
+ {
+ msg("\nNow copy the file\n\n %s\n\nto the directory where the CGI binaries are "
+ "located and don't forget to run\n\n",(htmlOutputDir+"/"+cgiName).data());
+ msg(" %s/installdox\n\nto replace any dummy links.\n\n",
+ htmlOutputDir.data());
+ }
+
+ delete tag;
+ return 0;
+}