doxygen.cpp

Go to the documentation of this file.
00001 /******************************************************************************
00002  *
00003  * $Id: doxygen.cpp,v 1.87 2001/03/19 19:27:40 root Exp $
00004  *
00005  *
00006  * Copyright (C) 1997-2008 by Dimitri van Heesch.
00007  *
00008  * Permission to use, copy, modify, and distribute this software and its
00009  * documentation under the terms of the GNU General Public License is hereby 
00010  * granted. No representations are made about the suitability of this software 
00011  * for any purpose. It is provided "as is" without express or implied warranty.
00012  * See the GNU General Public License for more details.
00013  *
00014  * Documents produced by Doxygen are derivative works derived from the
00015  * input used in their production; they are not affected by this license.
00016  *
00017  */
00018 
00019 #include "qtbc.h"
00020 #include <qfileinfo.h>
00021 #include <qfile.h>
00022 #include <qdir.h>
00023 #include <qdict.h>
00024 #include <qregexp.h>
00025 #include <qstrlist.h>
00026 #include <stdio.h>
00027 #include <stdlib.h>
00028 #include <sys/stat.h>
00029 #include <qtextcodec.h>
00030 #include <unistd.h>
00031 #include <errno.h>
00032 
00033 #include "version.h"
00034 #include "doxygen.h"
00035 #include "scanner.h"
00036 #include "entry.h"
00037 #include "index.h"
00038 #include "logos.h"
00039 #include "instdox.h"
00040 #include "message.h"
00041 #include "config.h"
00042 #include "util.h"
00043 #include "pre.h"
00044 #include "tagreader.h"
00045 #include "dot.h"
00046 #include "docparser.h"
00047 #include "dirdef.h"
00048 #include "outputlist.h"
00049 #include "declinfo.h"
00050 #include "htmlgen.h"
00051 #include "latexgen.h"
00052 #include "mangen.h"
00053 #include "language.h"
00054 #include "debug.h"
00055 #include "htmlhelp.h"
00056 #include "ftvhelp.h"
00057 #include "defargs.h"
00058 #include "rtfgen.h"
00059 #include "xmlgen.h"
00060 #include "defgen.h"
00061 #include "perlmodgen.h"
00062 #include "reflist.h"
00063 #include "pagedef.h"
00064 #include "bufstr.h"
00065 #include "commentcnv.h"
00066 #include "cmdmapper.h"
00067 #include "searchindex.h"
00068 #include "parserintf.h"
00069 #include "htags.h"
00070 #include "pyscanner.h"
00071 #include "fortranscanner.h"
00072 #include "code.h"
00073 #include "objcache.h"
00074 #include "store.h"
00075 #include "marshal.h"
00076 #include "portable.h"
00077 #include "vhdlscanner.h"
00078 
00079 #define RECURSE_ENTRYTREE(func,var) \
00080   do { if (var->children()) { \
00081     EntryNavListIterator eli(*var->children()); \
00082     for (;eli.current();++eli) func(eli.current()); \
00083   } } while(0) 
00084 
00085 
00086 #if !defined(_WIN32) || defined(__CYGWIN__)
00087 #include <signal.h>
00088 #define HAS_SIGNALS
00089 #endif
00090 
00091 // globally accessible variables
00092 ClassSDict      *Doxygen::classSDict = 0;
00093 ClassSDict      *Doxygen::hiddenClasses = 0;
00094 NamespaceSDict  *Doxygen::namespaceSDict = 0;
00095 MemberNameSDict *Doxygen::memberNameSDict = 0;
00096 MemberNameSDict *Doxygen::functionNameSDict = 0;   
00097 FileNameList    *Doxygen::inputNameList = 0;       // all input files
00098 FileNameDict    *Doxygen::inputNameDict = 0;          
00099 GroupSDict      *Doxygen::groupSDict = 0;
00100 FormulaList      Doxygen::formulaList;             // all formulas
00101 FormulaDict      Doxygen::formulaDict(1009);       // all formulas
00102 FormulaDict      Doxygen::formulaNameDict(1009);   // the label name of all formulas
00103 PageSDict       *Doxygen::pageSDict = 0;
00104 PageSDict       *Doxygen::exampleSDict = 0;
00105 SectionDict      Doxygen::sectionDict(257);        // all page sections
00106 StringDict       Doxygen::aliasDict(257);          // aliases
00107 FileNameDict    *Doxygen::includeNameDict = 0;     // include names
00108 FileNameDict    *Doxygen::exampleNameDict = 0;     // examples
00109 FileNameDict    *Doxygen::imageNameDict = 0;       // images
00110 FileNameDict    *Doxygen::dotFileNameDict = 0;     // dot files
00111 StringDict       Doxygen::namespaceAliasDict(257); // all namespace aliases
00112 StringDict       Doxygen::tagDestinationDict(257); // all tag locations
00113 QDict<void>      Doxygen::expandAsDefinedDict(257); // all macros that should be expanded
00114 QIntDict<MemberGroupInfo> Doxygen::memGrpInfoDict(1009); // dictionary of the member groups heading
00115 PageDef         *Doxygen::mainPage = 0;           
00116 bool             Doxygen::insideMainPage = FALSE; // are we generating docs for the main page?
00117 QTextStream      Doxygen::tagFile;
00118 NamespaceDef    *Doxygen::globalScope = 0;
00119 QDict<RefList>  *Doxygen::xrefLists = new QDict<RefList>; // dictionary of cross-referenced item lists
00120 bool             Doxygen::parseSourcesNeeded = FALSE;
00121 double           Doxygen::sysElapsedTime = 0.0;
00122 QTime            Doxygen::runningTime;
00123 SearchIndex *    Doxygen::searchIndex=0;
00124 QDict<DefinitionIntf> *Doxygen::symbolMap;
00125 bool             Doxygen::outputToWizard=FALSE;
00126 QDict<int> *     Doxygen::htmlDirMap = 0;
00127 QCache<LookupInfo> Doxygen::lookupCache(50000,50000);
00128 DirSDict        *Doxygen::directories;
00129 SDict<DirRelation> Doxygen::dirRelations(257);
00130 ParserManager   *Doxygen::parserManager = 0;
00131 QCString Doxygen::htmlFileExtension;
00132 bool             Doxygen::suppressDocWarnings = FALSE;
00133 ObjCache        *Doxygen::symbolCache = 0;
00134 Store           *Doxygen::symbolStorage;
00135 QCString         Doxygen::objDBFileName;
00136 QCString         Doxygen::entryDBFileName;
00137 bool             Doxygen::gatherDefines = TRUE;
00138 IndexList        Doxygen::indexList;
00139 
00140 bool             Doxygen::userComments = FALSE;
00141 
00142 // locally accessible globals
00143 static QDict<EntryNav>   classEntries(1009);
00144 static StringList     inputFiles;         
00145 static StringDict     excludeNameDict(1009);   // sections
00146 static QDict<void>    compoundKeywordDict(7);  // keywords recognised as compounds
00147 static OutputList     *outputList = 0;         // list of output generating objects
00148 static QDict<FileDef> g_usingDeclarations(1009); // used classes
00149 static const char     idMask[] = "[A-Za-z_][A-Za-z_0-9]*";
00150 
00151 FileStorage *g_storage = 0;
00152 
00153 QCString       spaces;
00154 
00155 static bool g_successfulRun = FALSE;
00156 static bool g_dumpSymbolMap = FALSE;
00157 
00158 
00159 
00160 void clearAll()
00161 {
00162   inputFiles.clear();      
00163   excludeNameDict.clear();  
00164   delete outputList; outputList=0;
00165 
00166   Doxygen::classSDict->clear();       
00167   Doxygen::namespaceSDict->clear();   
00168   Doxygen::pageSDict->clear();         
00169   Doxygen::exampleSDict->clear();      
00170   Doxygen::inputNameList->clear();   
00171   Doxygen::formulaList.clear();     
00172   Doxygen::sectionDict.clear();       
00173   Doxygen::inputNameDict->clear();    
00174   Doxygen::includeNameDict->clear();  
00175   Doxygen::exampleNameDict->clear();  
00176   Doxygen::imageNameDict->clear();     
00177   Doxygen::dotFileNameDict->clear();     
00178   Doxygen::formulaDict.clear();      
00179   Doxygen::formulaNameDict.clear();  
00180   Doxygen::tagDestinationDict.clear();
00181   delete Doxygen::mainPage; Doxygen::mainPage=0;
00182 }
00183 
00184 void statistics()
00185 {
00186   fprintf(stderr,"--- inputNameDict stats ----\n");
00187   Doxygen::inputNameDict->statistics();
00188   fprintf(stderr,"--- includeNameDict stats ----\n");
00189   Doxygen::includeNameDict->statistics();
00190   fprintf(stderr,"--- exampleNameDict stats ----\n");
00191   Doxygen::exampleNameDict->statistics();
00192   fprintf(stderr,"--- imageNameDict stats ----\n");
00193   Doxygen::imageNameDict->statistics();
00194   fprintf(stderr,"--- dotFileNameDict stats ----\n");
00195   Doxygen::dotFileNameDict->statistics();
00196   fprintf(stderr,"--- excludeNameDict stats ----\n");
00197   excludeNameDict.statistics();
00198   fprintf(stderr,"--- aliasDict stats ----\n");
00199   Doxygen::aliasDict.statistics();
00200   fprintf(stderr,"--- typedefDict stats ----\n");
00201   fprintf(stderr,"--- namespaceAliasDict stats ----\n");
00202   Doxygen::namespaceAliasDict.statistics();
00203   fprintf(stderr,"--- formulaDict stats ----\n");
00204   Doxygen::formulaDict.statistics();
00205   fprintf(stderr,"--- formulaNameDict stats ----\n");
00206   Doxygen::formulaNameDict.statistics();
00207   fprintf(stderr,"--- tagDestinationDict stats ----\n");
00208   Doxygen::tagDestinationDict.statistics();
00209   fprintf(stderr,"--- compoundKeywordDict stats ----\n");
00210   compoundKeywordDict.statistics();
00211   fprintf(stderr,"--- expandAsDefinedDict stats ----\n");
00212   Doxygen::expandAsDefinedDict.statistics();
00213   fprintf(stderr,"--- memGrpInfoDict stats ----\n");
00214   Doxygen::memGrpInfoDict.statistics();
00215 }
00216 
00217 
00218 
00219 static void addMemberDocs(EntryNav *rootNav,MemberDef *md, const char *funcDecl,
00220                    ArgumentList *al,bool over_load,NamespaceSDict *nl=0);
00221 static void findMember(EntryNav *rootNav,
00222                        QCString funcDecl,
00223                        bool overloaded,
00224                        bool isFunc
00225                       );
00226 
00227 
00228 struct STLInfo
00229 {
00230   const char *className;
00231   const char *baseClass1;
00232   const char *baseClass2;
00233   const char *templType1;
00234   const char *templName1;
00235   const char *templType2;
00236   const char *templName2;
00237   bool virtualInheritance;
00238   bool iterators;
00239 };
00240 
00241 static STLInfo g_stlinfo[] =
00242 {
00243   // className              baseClass1                      baseClass2             templType1     templName1     templType2    templName2     virtInheritance  // iterators
00244 #if 0
00245   { "allocator",            0,                              0,                     "T",           "elements",    0,            0,             FALSE,              FALSE },
00246   { "auto_ptr",             0,                              0,                     "T",           "ptr",         0,            0,             FALSE,              FALSE },
00247   { "ios_base",             0,                              0,                     0,             0,             0,            0,             FALSE,              FALSE },
00248   { "basic_ios",            "ios_base",                     0,                     "Char",        0,             0,            0,             FALSE,              FALSE },
00249   { "basic_istream",        "basic_ios<Char>",              0,                     "Char",        0,             0,            0,             TRUE,               FALSE },
00250   { "basic_ostream",        "basic_ios<Char>",              0,                     "Char",        0,             0,            0,             TRUE,               FALSE },
00251   { "basic_iostream",       "basic_istream<Char>",          "basic_ostream<Char>", "Char",        0,             0,            0,             FALSE,              FALSE },
00252   { "basic_ifstream",       "basic_istream<Char>",          0,                     "Char",        0,             0,            0,             FALSE,              FALSE },
00253   { "basic_ofstream",       "basic_ostream<Char>",          0,                     "Char",        0,             0,            0,             FALSE,              FALSE },
00254   { "basic_fstream",        "basic_iostream<Char>",         0,                     "Char",        0,             0,            0,             FALSE,              FALSE },
00255   { "basic_istringstream",  "basic_istream<Char>",          0,                     "Char",        0,             0,            0,             FALSE,              FALSE },
00256   { "basic_ostringstream",  "basic_ostream<Char>",          0,                     "Char",        0,             0,            0,             FALSE,              FALSE },
00257   { "basic_stringstream",   "basic_iostream<Char>",         0,                     "Char",        0,             0,            0,             FALSE,              FALSE },
00258   { "ios",                  "basic_ios<char>",              0,                     0,             0,             0,            0,             FALSE,              FALSE },
00259   { "wios",                 "basic_ios<wchar_t>",           0,                     0,             0,             0,            0,             FALSE,              FALSE },
00260   { "istream",              "basic_istream<char>",          0,                     0,             0,             0,            0,             FALSE,              FALSE },
00261   { "wistream",             "basic_istream<wchar_t>",       0,                     0,             0,             0,            0,             FALSE,              FALSE },
00262   { "ostream",              "basic_ostream<char>",          0,                     0,             0,             0,            0,             FALSE,              FALSE },
00263   { "wostream",             "basic_ostream<wchar_t>",       0,                     0,             0,             0,            0,             FALSE,              FALSE },
00264   { "ifstream",             "basic_ifstream<char>",         0,                     0,             0,             0,            0,             FALSE,              FALSE },
00265   { "wifstream",            "basic_ifstream<wchar_t>",      0,                     0,             0,             0,            0,             FALSE,              FALSE },
00266   { "ofstream",             "basic_ofstream<char>",         0,                     0,             0,             0,            0,             FALSE,              FALSE },
00267   { "wofstream",            "basic_ofstream<wchar_t>",      0,                     0,             0,             0,            0,             FALSE,              FALSE },
00268   { "fstream",              "basic_fstream<char>",          0,                     0,             0,             0,            0,             FALSE,              FALSE },
00269   { "wfstream",             "basic_fstream<wchar_t>",       0,                     0,             0,             0,            0,             FALSE,              FALSE },
00270   { "istringstream",        "basic_istringstream<char>",    0,                     0,             0,             0,            0,             FALSE,              FALSE },
00271   { "wistringstream",       "basic_istringstream<wchar_t>", 0,                     0,             0,             0,            0,             FALSE,              FALSE },
00272   { "ostringstream",        "basic_ostringstream<char>",    0,                     0,             0,             0,            0,             FALSE,              FALSE },
00273   { "wostringstream",       "basic_ostringstream<wchar_t>", 0,                     0,             0,             0,            0,             FALSE,              FALSE },
00274   { "stringstream",         "basic_stringstream<char>",     0,                     0,             0,             0,            0,             FALSE,              FALSE },
00275   { "wstringstream",        "basic_stringstream<wchar_t>",  0,                     0,             0,             0,            0,             FALSE,              FALSE },
00276   { "basic_string",         0,                              0,                     "Char",        0,             0,            0,             FALSE,              TRUE  },
00277   { "string",               "basic_string<char>",           0,                     0,             0,             0,            0,             FALSE,              TRUE  },
00278   { "wstring",              "basic_string<wchar_t>",        0,                     0,             0,             0,            0,             FALSE,              TRUE  },
00279   { "complex",              0,                              0,                     0,             0,             0,            0,             FALSE,              FALSE },
00280   { "bitset",               0,                              0,                     "Bits",        0,             0,            0,             FALSE,              FALSE },
00281   { "deque",                0,                              0,                     "T",           "elements",    0,            0,             FALSE,              TRUE  },
00282   { "list",                 0,                              0,                     "T",           "elements",    0,            0,             FALSE,              TRUE  },
00283   { "map",                  0,                              0,                     "K",           "keys",        "T",          "elements",    FALSE,              TRUE  },
00284   { "multimap",             0,                              0,                     "K",           "keys",        "T",          "elements",    FALSE,              TRUE  },
00285   { "set",                  0,                              0,                     "K",           "keys",        0,            0,             FALSE,              TRUE  },
00286   { "multiset",             0,                              0,                     "K",           "keys",        0,            0,             FALSE,              TRUE  },
00287 #endif
00288   { "vector",               0,                              0,                     "T",           "elements",    0,            0,             FALSE,              TRUE  },
00289 #if 0
00290   { "queue",                0,                              0,                     "T",           "elements",    0,            0,             FALSE,              FALSE },
00291   { "priority_queue",       0,                              0,                     "T",           "elements",    0,            0,             FALSE,              FALSE },
00292   { "stack",                0,                              0,                     "T",           "elements",    0,            0,             FALSE,              FALSE },
00293   { "valarray",             0,                              0,                     "T",           "elements",    0,            0,             FALSE,              FALSE },
00294   { "exception",            0,                              0,                     0,             0,             0,            0,             FALSE,              FALSE },
00295   { "bad_alloc",            "exception",                    0,                     0,             0,             0,            0,             FALSE,              FALSE },
00296   { "bad_cast",             "exception",                    0,                     0,             0,             0,            0,             FALSE,              FALSE },
00297   { "bad_typeid",           "exception",                    0,                     0,             0,             0,            0,             FALSE,              FALSE },
00298   { "logic_error",          "exception",                    0,                     0,             0,             0,            0,             FALSE,              FALSE },
00299   { "ios_base::failure",    "exception",                    0,                     0,             0,             0,            0,             FALSE,              FALSE },
00300   { "runtime_error",        "exception",                    0,                     0,             0,             0,            0,             FALSE,              FALSE },
00301   { "bad_exception",        "exception",                    0,                     0,             0,             0,            0,             FALSE,              FALSE },
00302   { "domain_error",         "logic_error",                  0,                     0,             0,             0,            0,             FALSE,              FALSE },
00303   { "invalid_argument",     "logic_error",                  0,                     0,             0,             0,            0,             FALSE,              FALSE },
00304   { "length_error",         "logic_error",                  0,                     0,             0,             0,            0,             FALSE,              FALSE },
00305   { "out_of_range",         "logic_error",                  0,                     0,             0,             0,            0,             FALSE,              FALSE },
00306   { "range_error",          "runtime_error",                0,                     0,             0,             0,            0,             FALSE,              FALSE },
00307   { "overflow_error",       "runtime_error",                0,                     0,             0,             0,            0,             FALSE,              FALSE },
00308   { "underflow_error",      "runtime_error",                0,                     0,             0,             0,            0,             FALSE,              FALSE },
00309 #endif
00310   { 0,                      0,                              0,                     0,             0,             0,            0,             FALSE,              FALSE }
00311 };
00312 
00313 static void addSTLMember(EntryNav *rootNav,const char *type,const char *name)
00314 {
00315   Entry *memEntry = new Entry;
00316   memEntry->name       = name;
00317   memEntry->type       = type;
00318   memEntry->protection = Private;
00319   memEntry->section    = Entry::VARIABLE_SEC;
00320   memEntry->brief      = "STL member";
00321   memEntry->hidden     = FALSE; 
00322   memEntry->artificial = TRUE;
00323   //memEntry->parent     = root;
00324   //root->addSubEntry(memEntry);
00325   EntryNav *memEntryNav = new EntryNav(rootNav,memEntry);
00326   memEntryNav->setEntry(memEntry);
00327   rootNav->addChild(memEntryNav);
00328 }
00329 
00330 static void addSTLIterator(EntryNav *classEntryNav,const char *name)
00331 {
00332   Entry *iteratorClassEntry = new Entry;
00333   iteratorClassEntry->fileName  = "[STL]";
00334   iteratorClassEntry->startLine = 1;
00335   iteratorClassEntry->name      = name;
00336   iteratorClassEntry->section   = Entry::CLASS_SEC;
00337   iteratorClassEntry->brief     = "STL iterator class";
00338   iteratorClassEntry->hidden    = FALSE;
00339   iteratorClassEntry->artificial= TRUE;
00340   EntryNav *iteratorClassEntryNav = new EntryNav(classEntryNav,iteratorClassEntry);
00341   iteratorClassEntryNav->setEntry(iteratorClassEntry);
00342   classEntryNav->addChild(iteratorClassEntryNav);
00343 }
00344 
00345 
00346 static void addSTLClasses(EntryNav *rootNav)
00347 {
00348   Entry *namespaceEntry = new Entry;
00349   namespaceEntry->fileName  = "[STL]";
00350   namespaceEntry->startLine = 1;
00351   //namespaceEntry->parent    = rootNav->entry();
00352   namespaceEntry->name      = "std";
00353   namespaceEntry->section   = Entry::NAMESPACE_SEC;
00354   namespaceEntry->brief     = "STL namespace";
00355   namespaceEntry->hidden    = FALSE;
00356   namespaceEntry->artificial= TRUE;
00357   //root->addSubEntry(namespaceEntry);
00358   EntryNav *namespaceEntryNav = new EntryNav(rootNav,namespaceEntry);
00359   namespaceEntryNav->setEntry(namespaceEntry);
00360   rootNav->addChild(namespaceEntryNav);
00361   
00362   STLInfo *info = g_stlinfo;
00363   while (info->className)
00364   {
00365     //printf("Adding STL class %s\n",info->className);
00366     QCString fullName = info->className;
00367     fullName.prepend("std::");
00368 
00369     // add fake Entry for the class
00370     Entry *classEntry = new Entry;
00371     classEntry->fileName  = "[STL]";
00372     classEntry->startLine = 1;
00373     classEntry->name      = fullName;
00374     //classEntry->parent    = namespaceEntry;
00375     classEntry->section   = Entry::CLASS_SEC;
00376     classEntry->brief     = "STL class";
00377     classEntry->hidden    = FALSE;
00378     classEntry->artificial= TRUE;
00379     //namespaceEntry->addSubEntry(classEntry);
00380     EntryNav *classEntryNav = new EntryNav(namespaceEntryNav,classEntry);
00381     classEntryNav->setEntry(classEntry);
00382     namespaceEntryNav->addChild(classEntryNav);
00383 
00384     // add template arguments to class
00385     if (info->templType1)
00386     {
00387       ArgumentList *al = new ArgumentList;
00388       Argument *a=new Argument;
00389       a->type="typename";
00390       a->name=info->templType1;
00391       al->append(a);
00392       if (info->templType2) // another template argument
00393       {
00394         a=new Argument;
00395         a->type="typename";
00396         a->name=info->templType2;
00397         al->append(a);
00398       }
00399       classEntry->tArgLists = new QList<ArgumentList>;
00400       classEntry->tArgLists->setAutoDelete(TRUE);
00401       classEntry->tArgLists->append(al);
00402     }
00403     // add member variables
00404     if (info->templName1)
00405     {
00406       addSTLMember(classEntryNav,info->templType1,info->templName1);
00407     }
00408     if (info->templName2)
00409     {
00410       addSTLMember(classEntryNav,info->templType2,info->templName2);
00411     }
00412     if (info->baseClass1)
00413     {
00414       classEntry->extends->append(new BaseInfo(info->baseClass1,Public,info->virtualInheritance?Virtual:Normal));
00415     }
00416     if (info->baseClass2)
00417     {
00418       classEntry->extends->append(new BaseInfo(info->baseClass2,Public,info->virtualInheritance?Virtual:Normal));
00419     }
00420     if (info->iterators)
00421     {
00422       // add iterator class
00423       addSTLIterator(classEntryNav,fullName+"::iterator");
00424       addSTLIterator(classEntryNav,fullName+"::const_iterator");
00425       addSTLIterator(classEntryNav,fullName+"::reverse_iterator");
00426       addSTLIterator(classEntryNav,fullName+"::const_reverse_iterator");
00427     }
00428     info++;
00429   }
00430 }
00431 
00432 //----------------------------------------------------------------------------
00433 
00434 static Definition *findScopeFromQualifiedName(Definition *startScope,const QCString &n,
00435                                               FileDef *fileScope=0);
00436 
00437 static void addPageToContext(PageDef *pd,EntryNav *rootNav)
00438 {
00439   if (rootNav->parent()) // add the page to it's scope
00440   {
00441     QCString scope = rootNav->parent()->name();
00442     if (rootNav->parent()->section()==Entry::PACKAGEDOC_SEC)
00443     {
00444       scope=substitute(scope,".","::");
00445     }
00446     scope = stripAnonymousNamespaceScope(scope);
00447     scope+="::"+pd->name();
00448     Definition *d = findScopeFromQualifiedName(Doxygen::globalScope,scope);
00449     if (d) 
00450     {
00451       pd->setPageScope(d);
00452     }
00453   }
00454 }
00455 
00456 static void addRelatedPage(EntryNav *rootNav)
00457 {
00458   Entry *root = rootNav->entry();
00459   GroupDef *gd=0;
00460   QListIterator<Grouping> gli(*root->groups);
00461   Grouping *g;
00462   for (;(g=gli.current());++gli)
00463   {
00464     if (!g->groupname.isEmpty() && (gd=Doxygen::groupSDict->find(g->groupname))) break;
00465   }
00466   //printf("---> addRelatedPage() %s gd=%p\n",root->name.data(),gd);
00467   QCString doc;
00468   if (root->brief.isEmpty())
00469   {
00470     doc=root->doc;
00471   }
00472   else
00473   {
00474     doc=root->brief+"\n\n"+root->doc;
00475   }
00476   PageDef *pd = addRelatedPage(root->name,root->args,doc,root->anchors,
00477       root->fileName,root->startLine,
00478       root->sli,
00479       gd,rootNav->tagInfo()
00480      );
00481   if (pd)
00482   {
00483     pd->addSectionsToDefinition(root->anchors);
00484     addPageToContext(pd,rootNav);
00485   }
00486 }
00487 
00488 static void buildGroupListFiltered(EntryNav *rootNav,bool additional)
00489 {
00490   if (rootNav->section()==Entry::GROUPDOC_SEC && !rootNav->name().isEmpty())
00491   {
00492     //printf("Found group %s title=`%s type=%d'\n",
00493     //    root->name.data(),root->type.data(),root->groupDocType);
00494 
00495     rootNav->loadEntry(g_storage);
00496     Entry *root = rootNav->entry();
00497     
00498     if ((root->groupDocType==Entry::GROUPDOC_NORMAL && !additional) ||
00499         (root->groupDocType!=Entry::GROUPDOC_NORMAL && additional))
00500     {
00501       GroupDef *gd;
00502 
00503       if ((gd=Doxygen::groupSDict->find(root->name)))
00504       {
00505 #if 0
00506         if ( root->groupDocType==Entry::GROUPDOC_NORMAL )
00507         {
00508           warn(root->fileName,root->startLine,
00509               "Warning: group %s already documented. "
00510               "Skipping documentation.",
00511               root->name.data());
00512         }
00513         else
00514 #endif
00515         {
00516           if ( !gd->hasGroupTitle() )
00517             gd->setGroupTitle( root->type );
00518           else if ( root->type.length() > 0 && root->name != root->type && gd->groupTitle() != root->type )
00519             warn( root->fileName,root->startLine,
00520                 "group %s: ignoring title \"%s\" that does not match old title \"%s\"\n",
00521                 root->name.data(), root->type.data(), gd->groupTitle() );
00522           //if ( gd->briefDescription().isEmpty() )
00523             gd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
00524           //if ( !root->doc.stripWhiteSpace().isEmpty() )
00525             gd->setDocumentation( root->doc, root->docFile, root->docLine );
00526           gd->addSectionsToDefinition(root->anchors);
00527           gd->setRefItems(root->sli);
00528           //addGroupToGroups(root,gd);
00529         }
00530       }
00531       else
00532       {
00533         if (rootNav->tagInfo())
00534         {
00535           gd = new GroupDef(root->fileName,root->startLine,root->name,root->type,rootNav->tagInfo()->fileName);
00536           gd->setReference(rootNav->tagInfo()->tagName);
00537         }
00538         else
00539         {
00540           gd = new GroupDef(root->fileName,root->startLine,root->name,root->type);
00541         }
00542         gd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
00543         gd->setDocumentation(root->doc,root->docFile,root->docLine);
00544         gd->addSectionsToDefinition(root->anchors);
00545         Doxygen::groupSDict->append(root->name,gd);
00546         gd->setRefItems(root->sli);
00547       }
00548     }
00549 
00550     rootNav->releaseEntry();
00551   }
00552   if (rootNav->children())
00553   {
00554     EntryNavListIterator eli(*rootNav->children());
00555     EntryNav *e;
00556     for (;(e=eli.current());++eli)
00557     {
00558       buildGroupListFiltered(e,additional);
00559     }
00560   }
00561 }
00562 
00563 static void buildGroupList(EntryNav *rootNav)
00564 {
00565   // first process the @defgroups blocks
00566   buildGroupListFiltered(rootNav,FALSE);
00567   // then process the @addtogroup, @weakgroup blocks
00568   buildGroupListFiltered(rootNav,TRUE);
00569 }
00570 
00571 static void findGroupScope(EntryNav *rootNav)
00572 {
00573   if (rootNav->section()==Entry::GROUPDOC_SEC && !rootNav->name().isEmpty() && 
00574       rootNav->parent() && !rootNav->parent()->name().isEmpty())
00575   {
00576     GroupDef *gd;
00577     if ((gd=Doxygen::groupSDict->find(rootNav->name())))
00578     {
00579       QCString scope = rootNav->parent()->name();
00580       if (rootNav->parent()->section()==Entry::PACKAGEDOC_SEC)
00581       {
00582         scope=substitute(scope,".","::");
00583       }
00584       scope = stripAnonymousNamespaceScope(scope);
00585       scope+="::"+gd->name();
00586       Definition *d = findScopeFromQualifiedName(Doxygen::globalScope,scope);
00587       if (d) 
00588       {
00589         gd->setGroupScope(d);
00590       }
00591     }
00592   }
00593   RECURSE_ENTRYTREE(findGroupScope,rootNav);
00594 }
00595 
00596 static void organizeSubGroupsFiltered(EntryNav *rootNav,bool additional)
00597 {
00598   if (rootNav->section()==Entry::GROUPDOC_SEC && !rootNav->name().isEmpty())
00599   {
00600     rootNav->loadEntry(g_storage);
00601     Entry *root = rootNav->entry();
00602 
00603     if ((root->groupDocType==Entry::GROUPDOC_NORMAL && !additional) ||
00604         (root->groupDocType!=Entry::GROUPDOC_NORMAL && additional))
00605     {
00606       GroupDef *gd;
00607       if ((gd=Doxygen::groupSDict->find(root->name)))
00608       {
00609         //printf("adding %s to group %s\n",root->name.data(),gd->name().data());
00610         addGroupToGroups(root,gd);
00611       }
00612     }
00613 
00614     rootNav->releaseEntry();
00615   }
00616   if (rootNav->children())
00617   {
00618     EntryNavListIterator eli(*rootNav->children());
00619     EntryNav *e;
00620     for (;(e=eli.current());++eli)
00621     {
00622       organizeSubGroupsFiltered(e,additional);
00623     }
00624   }
00625 }
00626 
00627 static void organizeSubGroups(EntryNav *rootNav)
00628 {
00629   //printf("Defining groups\n");
00630   // first process the @defgroups blocks
00631   organizeSubGroupsFiltered(rootNav,FALSE);
00632   //printf("Additional groups\n");
00633   // then process the @addtogroup, @weakgroup blocks
00634   organizeSubGroupsFiltered(rootNav,TRUE);
00635 }
00636 
00637 //----------------------------------------------------------------------
00638 
00639 static void buildFileList(EntryNav *rootNav)
00640 {
00641   if (((rootNav->section()==Entry::FILEDOC_SEC) ||
00642         ((rootNav->section() & Entry::FILE_MASK) && Config_getBool("EXTRACT_ALL"))) &&
00643       !rootNav->name().isEmpty() && !rootNav->tagInfo() // skip any file coming from tag files
00644      )
00645   {
00646     rootNav->loadEntry(g_storage);
00647     Entry *root = rootNav->entry();
00648 
00649     bool ambig;
00650     FileDef *fd=findFileDef(Doxygen::inputNameDict,root->name,ambig);
00651     //printf("**************** root->name=%s fd=%p\n",root->name.data(),fd);
00652     if (fd && !ambig)
00653     {
00654 #if 0
00655       if ((!root->doc.isEmpty() && !fd->documentation().isEmpty()) ||
00656           (!root->brief.isEmpty() && !fd->briefDescription().isEmpty()))
00657       {
00658         warn(
00659             root->fileName,root->startLine,
00660             "Warning: file %s already documented. "
00661             "Skipping documentation.",
00662             root->name.data()
00663             );
00664       }
00665       else
00666 #endif
00667       {
00668         //printf("Adding documentation!\n");
00669         // using FALSE in setDocumentation is small hack to make sure a file 
00670         // is documented even if a \file command is used without further 
00671         // documentation
00672         fd->setDocumentation(root->doc,root->docFile,root->docLine,FALSE);
00673         fd->setBriefDescription(root->brief,root->briefFile,root->briefLine); 
00674         fd->addSectionsToDefinition(root->anchors);
00675         fd->setRefItems(root->sli);
00676         QListIterator<Grouping> gli(*root->groups);
00677         Grouping *g;
00678         for (;(g=gli.current());++gli)
00679         {
00680           GroupDef *gd=0;
00681           if (!g->groupname.isEmpty() && (gd=Doxygen::groupSDict->find(g->groupname)))
00682           {
00683             gd->addFile(fd);
00684             //printf("File %s: in group %s\n",fd->name().data(),s->data());
00685           }
00686         }
00687       }
00688     }
00689     else
00690     {
00691       const char *fn = root->fileName.data();
00692       QCString text;
00693       text.sprintf("Warning: the name `%s' supplied as "
00694           "the second argument in the \\file statement ",
00695           root->name.data()
00696                   );
00697       if (ambig) // name is ambigious
00698       {
00699         text+="matches the following input files:\n";
00700         text+=showFileDefMatches(Doxygen::inputNameDict,root->name);
00701         text+="Please use a more specific name by "
00702           "including a (larger) part of the path!";
00703       }
00704       else // name is not an input file
00705       {
00706         text+="is not an input file";
00707       }
00708       warn(fn,root->startLine,text);
00709     }
00710 
00711     rootNav->releaseEntry();
00712   }
00713   RECURSE_ENTRYTREE(buildFileList,rootNav);
00714 }
00715 
00716 static void addIncludeFile(ClassDef *cd,FileDef *ifd,Entry *root)
00717 {
00718   if ( 
00719       (!root->doc.stripWhiteSpace().isEmpty() || 
00720        !root->brief.stripWhiteSpace().isEmpty() || 
00721        Config_getBool("EXTRACT_ALL")
00722       ) && root->protection!=Private
00723      )
00724   { 
00725     //printf(">>>>>> includeFile=%s\n",root->includeFile.data());
00726 
00727     bool ambig;
00728     FileDef *fd=0;
00729     // see if we need to include a verbatim copy of the header file
00730     //printf("root->includeFile=%s\n",root->includeFile.data());
00731     if (!root->includeFile.isEmpty() && 
00732         (fd=findFileDef(Doxygen::inputNameDict,root->includeFile,ambig))==0
00733        )
00734     { // explicit request
00735       QCString text;
00736       text.sprintf("Warning: the name `%s' supplied as "
00737                   "the argument of the \\class, \\struct, \\union, or \\include command ",
00738                   root->includeFile.data()
00739                  );
00740       if (ambig) // name is ambigious
00741       {
00742         text+="matches the following input files:\n";
00743         text+=showFileDefMatches(Doxygen::inputNameDict,root->includeFile);
00744         text+="Please use a more specific name by "
00745             "including a (larger) part of the path!";
00746       }
00747       else // name is not an input file
00748       {
00749         text+="is not an input file";
00750       }
00751       warn(root->fileName,root->startLine,text);
00752     }
00753     else if (root->includeFile.isEmpty() && ifd &&
00754         // see if the file extension makes sense
00755         guessSection(ifd->name())==Entry::HEADER_SEC)
00756     { // implicit assumption
00757       fd=ifd;
00758     }
00759 
00760     // if a file is found, we mark it as a source file.
00761     if (fd)
00762     {
00763       QCString iName = !root->includeName.isEmpty() ? 
00764                        root->includeName.data() : root->includeFile.data();
00765       bool local=FALSE;
00766       if (!iName.isEmpty()) // user specified include file
00767       {
00768         local = iName.at(0)=='"'; // is it a local include file
00769         if (local || iName.at(0)=='<')
00770         {
00771           iName=iName.mid(1,iName.length()-2); // strip quotes or brackets
00772         }
00773       }
00774       else if (!Config_getList("STRIP_FROM_INC_PATH").isEmpty()) 
00775       {
00776         iName=stripFromIncludePath(fd->absFilePath());
00777       }
00778       else // use name of the file containing the class definition
00779       {
00780         iName=fd->name();
00781       }
00782       if (fd->generateSourceFile()) // generate code for header
00783       {
00784         cd->setIncludeFile(fd,iName,local,!root->includeName.isEmpty());
00785       }
00786       else // put #include in the class documentation without link
00787       {
00788         cd->setIncludeFile(0,iName,local,TRUE);
00789       }
00790     }
00791   }
00792 }
00793 
00794 #if 0
00795 static bool addNamespace(Entry *root,ClassDef *cd)
00796 {
00797   // see if this class is defined inside a namespace
00798   if (root->section & Entry::COMPOUND_MASK)
00799   {
00800     Entry *e = root->parent;
00801     while (e)
00802     {
00803       if (e->section==Entry::NAMESPACE_SEC)
00804       {
00805         NamespaceDef *nd=0;
00806         QCString nsName = stripAnonymousNamespaceScope(e->name);
00807         //printf("addNameSpace() trying: %s\n",nsName.data());
00808         if (!nsName.isEmpty() && nsName.at(0)!='@' &&
00809             (nd=getResolvedNamespace(nsName))
00810            )
00811         {
00812           cd->setNamespace(nd);
00813           cd->setOuterScope(nd);
00814           nd->insertClass(cd);
00815           return TRUE;
00816         }
00817       }
00818       e=e->parent;
00819     } 
00820   }
00821   return FALSE;
00822 }
00823 #endif
00824 
00825 #if 0
00826 static Definition *findScope(Entry *root,int level=0)
00827 {
00828   if (root==0) return 0;
00829   //printf("start findScope name=%s\n",root->name.data());
00830   Definition *result=0;
00831   if (root->section&Entry::SCOPE_MASK)
00832   {
00833     result = findScope(root->parent,level+1); // traverse to the root of the tree
00834     if (result)
00835     {
00836       //printf("Found %s inside %s at level %d\n",root->name.data(),result->name().data(),level);
00837       // TODO: look at template arguments
00838       result = result->findInnerCompound(root->name);
00839     }
00840     else // reached the global scope
00841     {
00842       // TODO: look at template arguments
00843       result = Doxygen::globalScope->findInnerCompound(root->name);
00844       //printf("Found in globalScope %s at level %d\n",result->name().data(),level);
00845     }
00846   }
00847   //printf("end findScope(%s,%d)=%s\n",root->name.data(),
00848   //       level,result==0 ? "<none>" : result->name().data());
00849   return result;
00850 }
00851 #endif
00852 
00857 static Definition *buildScopeFromQualifiedName(const QCString name,int level)
00858 {
00859   int i=0;
00860   int p=0,l;
00861   Definition *prevScope=Doxygen::globalScope;
00862   QCString fullScope;
00863   while (i<level)
00864   {
00865     int idx=getScopeFragment(name,p,&l);
00866     QCString nsName = name.mid(idx,l);
00867     if (nsName.isEmpty()) return prevScope;
00868     if (!fullScope.isEmpty()) fullScope+="::";
00869     fullScope+=nsName;
00870     NamespaceDef *nd=Doxygen::namespaceSDict->find(fullScope);
00871     Definition *innerScope = nd;
00872     ClassDef *cd=0; 
00873     if (nd==0) cd = getClass(fullScope);
00874     if (nd==0 && cd) // scope is a class
00875     {
00876       innerScope = cd;
00877     }
00878     else if (nd==0 && cd==0) // scope is not known!
00879     {
00880       // introduce bogus namespace
00881       //printf("adding dummy namespace %s to %s\n",nsName.data(),prevScope->name().data());
00882       nd=new NamespaceDef(
00883         "[generated]",1,fullScope);
00884 
00885       // add namespace to the list
00886       Doxygen::namespaceSDict->inSort(fullScope,nd);
00887       innerScope = nd;
00888     }
00889     else // scope is a namespace
00890     {
00891     }
00892     // make the parent/child scope relation
00893     prevScope->addInnerCompound(innerScope);
00894     innerScope->setOuterScope(prevScope);
00895     // proceed to the next scope fragment
00896     p=idx+l+2;
00897     prevScope=innerScope;
00898     i++;
00899   }
00900   return prevScope;
00901 }
00902 
00903 static Definition *findScopeFromQualifiedName(Definition *startScope,const QCString &n,
00904                                               FileDef *fileScope)
00905 {
00906   //printf("<findScopeFromQualifiedName(%s,%s)\n",startScope ? startScope->name().data() : 0, n.data());
00907   Definition *resultScope=startScope;
00908   if (resultScope==0) resultScope=Doxygen::globalScope;
00909   QCString scope=stripTemplateSpecifiersFromScope(n,FALSE);
00910   int l1=0,i1;
00911   i1=getScopeFragment(scope,0,&l1);
00912   if (i1==-1) 
00913   {
00914     //printf(">no fragments!\n");
00915     return resultScope;
00916   }
00917   int p=i1+l1,l2=0,i2;
00918   while ((i2=getScopeFragment(scope,p,&l2))!=-1)
00919   {
00920     QCString nestedNameSpecifier = scope.mid(i1,l1);
00921     Definition *orgScope = resultScope;
00922     //printf("  nestedNameSpecifier=%s\n",nestedNameSpecifier.data());
00923     resultScope = resultScope->findInnerCompound(nestedNameSpecifier);
00924     //printf("  resultScope=%p\n",resultScope);
00925     if (resultScope==0) 
00926     {
00927       NamespaceSDict *usedNamespaces;
00928       if (orgScope==Doxygen::globalScope && fileScope &&
00929           (usedNamespaces = fileScope->getUsedNamespaces())) 
00930         // also search for used namespaces 
00931       {
00932         NamespaceSDict::Iterator ni(*usedNamespaces);
00933         NamespaceDef *nd;
00934         for (ni.toFirst();((nd=ni.current()) && resultScope==0);++ni)
00935         {
00936           // restart search within the used namespace
00937           resultScope = findScopeFromQualifiedName(nd,n,fileScope);
00938         }
00939         if (resultScope) 
00940         {
00941           // for a nested class A::I in used namespace N, we get
00942           // N::A::I while looking for A, so we should compare
00943           // resultScope->name() against scope.left(i2+l2)
00944           //printf("  -> result=%s scope=%s\n",resultScope->name().data(),scope.data());
00945           if (rightScopeMatch(resultScope->name(),scope.left(i2+l2)))
00946           {
00947             break;
00948           }
00949           goto nextFragment;
00950         }
00951       }
00952 
00953       // also search for used classes. Complication: we haven't been able 
00954       // to put them in the right scope yet, because we are still resolving
00955       // the scope relations!
00956       // Therefore loop through all used classes and see if there is a right 
00957       // scope match between the used class and nestedNameSpecifier.
00958       QDictIterator<FileDef> ui(g_usingDeclarations);
00959       FileDef *usedFd;
00960       for (ui.toFirst();(usedFd=ui.current());++ui)
00961       {
00962         //printf("Checking using class %s\n",ui.currentKey());
00963         if (rightScopeMatch(ui.currentKey(),nestedNameSpecifier))
00964         {
00965           // ui.currentKey() is the fully qualified name of nestedNameSpecifier
00966           // so use this instead.
00967           QCString fqn = QCString(ui.currentKey())+
00968                          scope.right(scope.length()-p);
00969           resultScope = buildScopeFromQualifiedName(fqn,fqn.contains("::"));
00970           //printf("Creating scope from fqn=%s result %p\n",fqn.data(),resultScope);
00971           if (resultScope) 
00972           {
00973             //printf("> Match! resultScope=%s\n",resultScope->name().data());
00974             return resultScope;
00975           }
00976         }
00977       }
00978       
00979       //printf("> name %s not found in scope %s\n",nestedNameSpecifier.data(),orgScope->name().data());
00980       return 0;
00981     }
00982  nextFragment:
00983     i1=i2;
00984     l1=l2;
00985     p=i2+l2;
00986   }
00987   //printf(">findScopeFromQualifiedName scope %s\n",resultScope->name().data());
00988   return resultScope;
00989 }
00990 
00991 ArgumentList *getTemplateArgumentsFromName(
00992                   const QCString &name,
00993                   const QList<ArgumentList> *tArgLists)
00994 {
00995   if (tArgLists==0) return 0;
00996   
00997   QListIterator<ArgumentList> ali(*tArgLists);
00998   // for each scope fragment, check if it is a template and advance through
00999   // the list if so.
01000   int i,p=0;
01001   while ((i=name.find("::",p))!=-1)
01002   {
01003     NamespaceDef *nd = Doxygen::namespaceSDict->find(name.left(i));
01004     if (nd==0)
01005     {
01006       ClassDef *cd = getClass(name.left(i));
01007       if (cd)
01008       {
01009         if (cd->templateArguments())
01010         {
01011           ++ali;
01012         }
01013       }
01014     }
01015     p=i+2;
01016   }
01017   return ali.current();
01018 }
01019 
01020 static ClassDef::CompoundType convertToCompoundType(int section,int specifier)
01021 {
01022     ClassDef::CompoundType sec=ClassDef::Class; 
01023     if (specifier&Entry::Struct) 
01024       sec=ClassDef::Struct;
01025     else if (specifier&Entry::Union) 
01026       sec=ClassDef::Union;
01027     else if (specifier&Entry::Interface) 
01028       sec=ClassDef::Interface;
01029     else if (specifier&Entry::Protocol) 
01030       sec=ClassDef::Protocol;
01031     else if (specifier&Entry::Category) 
01032       sec=ClassDef::Category;
01033     else if (specifier&Entry::Exception) 
01034       sec=ClassDef::Exception;
01035 
01036     switch(section)
01037     {
01038       //case Entry::UNION_SEC: 
01039       case Entry::UNIONDOC_SEC: 
01040         sec=ClassDef::Union; 
01041         break;
01042       //case Entry::STRUCT_SEC:
01043       case Entry::STRUCTDOC_SEC: 
01044         sec=ClassDef::Struct; 
01045         break;
01046       //case Entry::INTERFACE_SEC:
01047       case Entry::INTERFACEDOC_SEC:
01048         sec=ClassDef::Interface; 
01049         break;
01050       //case Entry::PROTOCOL_SEC:
01051       case Entry::PROTOCOLDOC_SEC:
01052         sec=ClassDef::Protocol; 
01053         break;
01054       //case Entry::CATEGORY_SEC:
01055       case Entry::CATEGORYDOC_SEC:
01056         sec=ClassDef::Category; 
01057         break;
01058       //case Entry::EXCEPTION_SEC:
01059       case Entry::EXCEPTIONDOC_SEC:
01060         sec=ClassDef::Exception; 
01061         break;
01062     }
01063     return sec;
01064 }
01065 
01066 
01067 static void addClassToContext(EntryNav *rootNav)
01068 {
01069   //printf("Loading entry for rootNav=%p name=%s\n",rootNav,rootNav->name().data());
01070   rootNav->loadEntry(g_storage);
01071   Entry *root = rootNav->entry();
01072 
01073   //NamespaceDef *nd = 0;
01074   FileDef *fd = rootNav->fileDef();
01075 
01076   QCString scName;
01077   if (rootNav->parent()->section()&Entry::SCOPE_MASK)
01078   {
01079      scName=rootNav->parent()->name();
01080   }
01081   // name without parent's scope: TODO: is this still true?
01082   QCString fullName = root->name;
01083 
01084   // strip off any template parameters (but not those for specializations)
01085   fullName=stripTemplateSpecifiersFromScope(fullName);
01086 
01087   // name with scope
01088   QCString qualifiedName = fullName;
01089   if (!scName.isEmpty() && !leftScopeMatch(fullName,scName))
01090   {
01091     qualifiedName.prepend(scName+"::");
01092   }
01093 
01094   ClassDef *cd = getClass(qualifiedName);
01095 
01096   Debug::print(Debug::Classes,0, "  Found class with name %s (qualifiedName=%s -> cd=%p)\n",
01097       cd ? cd->name().data() : root->name.data(), qualifiedName.data(),cd);
01098   
01099   if (cd) 
01100   {
01101     fullName=cd->name();
01102     Debug::print(Debug::Classes,0,"  Existing class %s!\n",cd->name().data());
01103     //if (cd->templateArguments()==0)
01104     //{
01105     //  //printf("existing ClassDef tempArgList=%p specScope=%s\n",root->tArgList,root->scopeSpec.data());
01106     //  cd->setTemplateArguments(tArgList);
01107     //}
01108 #if 0
01109     if (!root->doc.isEmpty() || !root->brief.isEmpty() || 
01110         (root->bodyLine!=-1 && Config_getBool("SOURCE_BROWSER"))
01111        ) 
01112       // block contains something that ends up in the docs
01113     { 
01114       if (!root->doc.isEmpty() && !cd->documentation().isEmpty())
01115       {
01116         warn(
01117             root->fileName,root->startLine,
01118             "Warning: class %s already has a detailed description found in file %s at line %d. "
01119             "Skipping the one found here.",
01120             fullName.data(),cd->docFile().data(),cd->docLine()
01121             );
01122       }
01123       else if (!root->doc.isEmpty())
01124 #endif
01125       {
01126         cd->setDocumentation(root->doc,root->docFile,root->docLine);
01127       }
01128 #if 0
01129       if (!root->brief.isEmpty() && !cd->briefDescription().isEmpty())
01130       {
01131         warn(
01132             root->fileName,root->startLine,
01133             "Warning: class %s already has a brief description found in file %s at line %d\n"
01134             "         skipping the one found here.",
01135             fullName.data(),cd->briefFile().data(),cd->briefLine()
01136             );
01137       }
01138       else if (!root->brief.isEmpty())
01139 #endif
01140       {
01141         cd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
01142       }
01143       if (root->bodyLine!=-1 && cd->getStartBodyLine()==-1)
01144       {
01145         cd->setBodySegment(root->bodyLine,root->endBodyLine);
01146         cd->setBodyDef(fd);
01147       }
01148       //cd->setName(fullName); // change name to match docs
01149 #if 0
01150     }
01151 #endif
01152 
01153     if (cd->templateArguments()==0) 
01154     {
01155       // this happens if a template class declared with @class is found
01156       // before the actual definition.
01157       ArgumentList *tArgList = 
01158         getTemplateArgumentsFromName(cd->name(),root->tArgLists);
01159       cd->setTemplateArguments(tArgList);
01160     }
01161 
01162     cd->setCompoundType(convertToCompoundType(root->section,root->spec));
01163   }
01164   else // new class
01165   {
01166     ClassDef::CompoundType sec = convertToCompoundType(root->section,root->spec);
01167 
01168     QCString className;
01169     QCString namespaceName;
01170     extractNamespaceName(fullName,className,namespaceName);
01171 
01172     //printf("New class: fullname %s namespace `%s' name=`%s' brief=`%s' docs=`%s'\n",
01173     //    fullName.data(),namespaceName.data(),className.data(),root->brief.data(),root->doc.data());
01174 
01175     QCString tagName;
01176     QCString refFileName;
01177     if (rootNav->tagInfo())
01178     {
01179       tagName     = rootNav->tagInfo()->tagName;
01180       refFileName = rootNav->tagInfo()->fileName;
01181     }
01182     cd=new ClassDef(root->fileName,root->startLine,fullName,sec,
01183         tagName,refFileName);
01184     Debug::print(Debug::Classes,0,"  New class `%s' (sec=0x%08x)! #tArgLists=%d cd=%p\n",
01185         fullName.data(),root->section,root->tArgLists ? (int)root->tArgLists->count() : -1,cd);
01186     cd->setDocumentation(root->doc,root->docFile,root->docLine); // copy docs to definition
01187     cd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
01188     cd->setIsObjectiveC(root->objc);
01189     cd->setHidden(root->hidden);
01190     cd->setArtificial(root->artificial);
01191     cd->setTypeConstraints(root->typeConstr);
01192     //printf("new ClassDef %s tempArgList=%p specScope=%s\n",fullName.data(),root->tArgList,root->scopeSpec.data());
01193 
01194     ArgumentList *tArgList = 
01195       getTemplateArgumentsFromName(fullName,root->tArgLists);
01196     //printf("class %s template args=%s\n",fullName.data(),
01197     //    tArgList ? tempArgListToString(tArgList).data() : "<none>");
01198     cd->setTemplateArguments(tArgList);
01199     cd->setProtection(root->protection);
01200     cd->setIsStatic(root->stat);
01201 
01202     // file definition containing the class cd
01203     cd->setBodySegment(root->bodyLine,root->endBodyLine);
01204     cd->setBodyDef(fd);
01205 
01206     // see if the class is found inside a namespace 
01207     //bool found=addNamespace(root,cd);
01208 
01209 
01210     // the empty string test is needed for extract all case
01211     cd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
01212     cd->insertUsedFile(root->fileName);
01213 
01214     // add class to the list
01215     //printf("ClassDict.insert(%s)\n",resolveDefines(fullName).data());
01216     Doxygen::classSDict->append(fullName,cd);
01217 
01218   }
01219 
01220   cd->addSectionsToDefinition(root->anchors);
01221   if (!root->subGrouping) cd->setSubGrouping(FALSE);
01222   if (cd->hasDocumentation())
01223   {
01224     addIncludeFile(cd,fd,root);
01225   }
01226   if (fd && (root->section & Entry::COMPOUND_MASK)) 
01227   {
01228     //printf(">> Inserting class `%s' in file `%s' (root->fileName=`%s')\n",
01229     //    cd->name().data(),
01230     //    fd->name().data(),
01231     //    root->fileName.data()
01232     //   );
01233     cd->setFileDef(fd);
01234     fd->insertClass(cd);
01235   }
01236   addClassToGroups(root,cd);
01237   cd->setRefItems(root->sli);
01238 
01239   rootNav->releaseEntry();
01240 }
01241             
01242 //----------------------------------------------------------------------
01243 // build a list of all classes mentioned in the documentation
01244 // and all classes that have a documentation block before their definition.
01245 static void buildClassList(EntryNav *rootNav)
01246 {
01247   if (
01248         ((rootNav->section() & Entry::COMPOUND_MASK) || 
01249          rootNav->section()==Entry::OBJCIMPL_SEC) && !rootNav->name().isEmpty()
01250      )
01251   {
01252     addClassToContext(rootNav);
01253   }
01254   RECURSE_ENTRYTREE(buildClassList,rootNav);
01255 }
01256 
01257 static void buildClassDocList(EntryNav *rootNav)
01258 {
01259   if (
01260        (rootNav->section() & Entry::COMPOUNDDOC_MASK) && !rootNav->name().isEmpty()
01261      )
01262   {
01263     addClassToContext(rootNav);
01264   }
01265   RECURSE_ENTRYTREE(buildClassDocList,rootNav);
01266 }
01267 
01268 static void resolveClassNestingRelations()
01269 {
01270   ClassSDict::Iterator cli(*Doxygen::classSDict);
01271   for (cli.toFirst();cli.current();++cli) cli.current()->visited=FALSE;
01272 
01273   bool done=FALSE;
01274   int iteration=0;
01275   while (!done)
01276   {
01277     done=TRUE;
01278     ++iteration;
01279     ClassDef *cd=0;
01280     for (cli.toFirst();(cd=cli.current());++cli)
01281     {
01282       if (!cd->visited)
01283       {
01284         QCString name = stripAnonymousNamespaceScope(cd->name());
01285         //printf("processing=%s, iteration=%d\n",cd->name().data(),iteration);
01286         // also add class to the correct structural context 
01287         Definition *d = findScopeFromQualifiedName(Doxygen::globalScope,
01288                                                  name,cd->getFileDef());
01289         if (d)
01290         {
01291           //printf("****** adding %s to scope %s in iteration %d\n",cd->name().data(),d->name().data(),iteration);
01292           d->addInnerCompound(cd);
01293           cd->setOuterScope(d);
01294           cd->visited=TRUE;
01295           done=FALSE;
01296         }
01297         //else
01298         //{
01299         //  printf("****** ignoring %s: scope not (yet) found in iteration %d\n",cd->name().data(),iteration);
01300         //}
01301       }
01302     }
01303   }
01304 
01305   //give warnings for unresolved compounds
01306   ClassDef *cd=0;
01307   for (cli.toFirst();(cd=cli.current());++cli)
01308   {
01309     if (!cd->visited)
01310     {
01311       QCString name = stripAnonymousNamespaceScope(cd->name());
01312       //printf("processing unresolved=%s, iteration=%d\n",cd->name().data(),iteration);
01314       // anyway, so we can at least relate scopes properly.
01315       Definition *d = buildScopeFromQualifiedName(name,name.contains("::"));
01316       if (d!=cd) // avoid recursion in case of redundant scopes, i.e: namespace N { class N::C {}; }
01317                  // for this case doxygen assumes the exitance of a namespace N::N in which C is to be found!
01318       {
01319         d->addInnerCompound(cd);
01320         cd->setOuterScope(d);
01321         warn(cd->getDefFileName(),cd->getDefLine(),
01322             "Warning: Internal inconsistency: scope for class %s not "
01323             "found!",name.data()
01324             );
01325       }
01326     }
01327   }
01328 }
01329 
01330 
01331 //----------------------------------------------------------------------
01332 // build a list of all namespaces mentioned in the documentation
01333 // and all namespaces that have a documentation block before their definition.
01334 static void buildNamespaceList(EntryNav *rootNav)
01335 {
01336   if (
01337        (rootNav->section()==Entry::NAMESPACE_SEC ||
01338         rootNav->section()==Entry::NAMESPACEDOC_SEC ||
01339         rootNav->section()==Entry::PACKAGEDOC_SEC
01340        ) && 
01341        !rootNav->name().isEmpty()
01342      )
01343   {
01344     rootNav->loadEntry(g_storage);
01345     Entry *root = rootNav->entry();
01346 
01347     //printf("** buildNamespaceList(%s)\n",root->name.data());
01348 
01349     QCString fName = root->name;
01350     if (root->section==Entry::PACKAGEDOC_SEC)
01351     {
01352       fName=substitute(fName,".","::");
01353     }
01354 
01355     QCString fullName = stripAnonymousNamespaceScope(fName);
01356     if (!fullName.isEmpty())
01357     {
01358       //printf("Found namespace %s in %s at line %d\n",root->name.data(),
01359       //        root->fileName.data(), root->startLine);
01360       NamespaceDef *nd;
01361       if ((nd=Doxygen::namespaceSDict->find(fullName))) // existing namespace
01362       {
01363 #if 0
01364         if (!root->doc.isEmpty() || !root->brief.isEmpty()) // block contains docs
01365         { 
01366           if (nd->documentation().isEmpty() && !root->doc.isEmpty())
01367           {
01368 #endif
01369             nd->setDocumentation(root->doc,root->docFile,root->docLine);
01370             nd->setName(fullName); // change name to match docs
01371             nd->addSectionsToDefinition(root->anchors);
01372 #if 0
01373           }
01374           else if (!nd->documentation().isEmpty() && !root->doc.isEmpty())
01375           {
01376             warn(
01377                  root->fileName,root->startLine,
01378                  "Warning: namespace %s already has a detailed description found in file %s at line %d. "
01379                  "Skipping the documentation found here.",
01380                  fullName.data(),nd->docFile().data(),nd->docLine());
01381           }
01382           if (nd->briefDescription().isEmpty() && !root->brief.isEmpty())
01383           {
01384 #endif
01385             nd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
01386 #if 0
01387             nd->setName(fullName); // change name to match docs
01388           }
01389           else if (!nd->briefDescription().isEmpty() && !root->brief.isEmpty())
01390           {
01391             warn(root->fileName,root->startLine,
01392                  "Warning: namespace %s already has a brief description found in file %s at line %d. "
01393                  "Skipping the documentation found here.",
01394                  fullName.data(),nd->docFile().data(),nd->docLine()
01395                 );
01396           }
01397         }
01398 #endif
01399 
01400         // file definition containing the namespace nd
01401         FileDef *fd=rootNav->fileDef();
01402         // insert the namespace in the file definition
01403         if (fd) fd->insertNamespace(nd);
01404         addNamespaceToGroups(root,nd);
01405         nd->setRefItems(root->sli);
01406       }
01407       else // fresh namespace
01408       {
01409         QCString tagName;
01410         QCString tagFileName;
01411         if (rootNav->tagInfo())
01412         {
01413           tagName=rootNav->tagInfo()->tagName;
01414           tagFileName=rootNav->tagInfo()->fileName;
01415         }
01416         NamespaceDef *nd=new NamespaceDef(root->fileName,root->startLine,fullName,tagName,tagFileName);
01417         nd->setDocumentation(root->doc,root->docFile,root->docLine); // copy docs to definition
01418         nd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
01419         nd->addSectionsToDefinition(root->anchors);
01420         nd->setHidden(root->hidden);
01421         nd->setArtificial(root->artificial);
01422 
01423         //printf("Adding namespace to group\n");
01424         addNamespaceToGroups(root,nd);
01425         nd->setRefItems(root->sli);
01426 
01427         // file definition containing the namespace nd
01428         FileDef *fd=rootNav->fileDef();
01429         // insert the namespace in the file definition
01430         if (fd) fd->insertNamespace(nd);
01431 
01432         // the empty string test is needed for extract all case
01433         nd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
01434         nd->insertUsedFile(root->fileName);
01435         nd->setBodySegment(root->bodyLine,root->endBodyLine);
01436         nd->setBodyDef(fd);
01437         // add class to the list
01438         Doxygen::namespaceSDict->inSort(fullName,nd);
01439 
01440         // also add namespace to the correct structural context 
01441         Definition *d = findScopeFromQualifiedName(Doxygen::globalScope,fullName);
01442         //printf("adding namespace %s to context %s\n",nd->name().data(),d?d->name().data():"<none>");
01443         if (d==0) // we didn't find anything, create the scope artificially
01444                   // anyway, so we can at least relate scopes properly.
01445         {
01446           Definition *d = buildScopeFromQualifiedName(fullName,fullName.contains("::"));
01447           d->addInnerCompound(nd);
01448           nd->setOuterScope(d);
01449           // TODO: Due to the order in which the tag file is written
01450           // a nested class can be found before its parent!
01451         }
01452         else
01453         {
01454           d->addInnerCompound(nd);
01455           nd->setOuterScope(d);
01456         }
01457       }
01458     }
01459 
01460     rootNav->releaseEntry();
01461   }
01462   RECURSE_ENTRYTREE(buildNamespaceList,rootNav);
01463 }
01464 
01465 //----------------------------------------------------------------------
01466 
01467 static NamespaceDef *findUsedNamespace(const NamespaceSDict *unl,
01468                               const QCString &name)
01469 {
01470   NamespaceDef *usingNd =0;
01471   if (unl)
01472   {
01473     //printf("Found namespace dict %d\n",unl->count());
01474     NamespaceSDict::Iterator unli(*unl);
01475     NamespaceDef *und;
01476     for (unli.toFirst();(und=unli.current());++unli)
01477     {
01478       QCString uScope=und->name()+"::";
01479       usingNd = getResolvedNamespace(uScope+name);
01480       //printf("Also trying with scope=`%s' usingNd=%p\n",(uScope+name).data(),usingNd);
01481     }
01482   }
01483   return usingNd;
01484 }
01485 
01486 static void findUsingDirectives(EntryNav *rootNav)
01487 {
01488   if (rootNav->section()==Entry::USINGDIR_SEC)
01489   {
01490     rootNav->loadEntry(g_storage);
01491     Entry *root = rootNav->entry();
01492 
01493     //printf("Found using directive %s at line %d of %s\n",
01494     //    root->name.data(),root->startLine,root->fileName.data());
01495     QCString name=substitute(root->name,".","::");
01496     if (!name.isEmpty())
01497     {
01498       NamespaceDef *usingNd = 0;
01499       NamespaceDef *nd = 0;
01500       FileDef      *fd = rootNav->fileDef();
01501       QCString nsName;
01502 
01503       // see if the using statement was found inside a namespace or inside
01504       // the global file scope.
01505       if (rootNav->parent() && rootNav->parent()->section()==Entry::NAMESPACE_SEC &&
01506           (fd==0 || !fd->isJava()) // not a .java file
01507          )
01508       {
01509         nsName=stripAnonymousNamespaceScope(rootNav->parent()->name());
01510         if (!nsName.isEmpty())
01511         {
01512           nd = getResolvedNamespace(nsName);
01513         }
01514       }
01515 
01516       // find the scope in which the `using' namespace is defined by prepending
01517       // the possible scopes in which the using statement was found, starting
01518       // with the most inner scope and going to the most outer scope (i.e. 
01519       // file scope). 
01520       int scopeOffset = nsName.length();
01521       do
01522       {
01523         QCString scope=scopeOffset>0 ? 
01524                       nsName.left(scopeOffset)+"::" : QCString();
01525         usingNd = getResolvedNamespace(scope+name);
01526         //printf("Trying with scope=`%s' usingNd=%p\n",(scope+name).data(),usingNd);
01527         if (scopeOffset==0)
01528         {
01529           scopeOffset=-1;
01530         }
01531         else if ((scopeOffset=nsName.findRev("::",scopeOffset-1))==-1)
01532         {
01533           scopeOffset=0;
01534         }
01535       } while (scopeOffset>=0 && usingNd==0);
01536 
01537       if (usingNd==0 && nd) // not found, try used namespaces in this scope
01538                             // or in one of the parent namespace scopes
01539       {
01540         NamespaceDef *pnd = nd;
01541         while (pnd && usingNd==0)
01542         {
01543           // also try with one of the used namespaces found earlier
01544           usingNd = findUsedNamespace(pnd->getUsedNamespaces(),name);
01545 
01546           // goto the parent
01547           Definition *s = pnd->getOuterScope();
01548           if (s && s->definitionType()==Definition::TypeNamespace)
01549           {
01550             pnd = (NamespaceDef*)s;
01551           }
01552           else
01553           {
01554             pnd = 0;
01555           }
01556         }
01557       }
01558       if (usingNd==0 && fd) // still nothing, also try used namespace in the
01559                             // global scope
01560       {
01561         usingNd = findUsedNamespace(fd->getUsedNamespaces(),name);
01562       }
01563 
01564       //printf("%s -> %s\n",name.data(),usingNd?usingNd->name().data():"<none>");
01565 
01566       // add the namespace the correct scope
01567       if (usingNd)
01568       {
01569         //printf("using fd=%p nd=%p\n",fd,nd);
01570         if (nd)
01571         {
01572           //printf("Inside namespace %s\n",nd->name().data());
01573           nd->addUsingDirective(usingNd);
01574         }
01575         else if (fd)
01576         {
01577           //printf("Inside file %s\n",fd->name().data());
01578           fd->addUsingDirective(usingNd);
01579         }
01580       }
01581       else // unknown namespace, but add it anyway.
01582       {
01583         NamespaceDef *nd=new NamespaceDef(root->fileName,root->startLine,name);
01584         nd->setDocumentation(root->doc,root->docFile,root->docLine); // copy docs to definition
01585         nd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
01586         nd->addSectionsToDefinition(root->anchors);
01587         //printf("** Adding namespace %s hidden=%d\n",name.data(),root->hidden);
01588         nd->setHidden(root->hidden);
01589         nd->setArtificial(TRUE);
01590 
01591         QListIterator<Grouping> gli(*root->groups);
01592         Grouping *g;
01593         for (;(g=gli.current());++gli)
01594         {
01595           GroupDef *gd=0;
01596           if (!g->groupname.isEmpty() && (gd=Doxygen::groupSDict->find(g->groupname)))
01597             gd->addNamespace(nd);
01598         }
01599 
01600         // insert the namespace in the file definition
01601         if (fd) 
01602         {
01603           fd->insertNamespace(nd);
01604           fd->addUsingDirective(nd);
01605         }
01606 
01607         // the empty string test is needed for extract all case
01608         nd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
01609         nd->insertUsedFile(root->fileName);
01610         // add class to the list
01611         Doxygen::namespaceSDict->inSort(name,nd);
01612         nd->setRefItems(root->sli);
01613       }
01614     }
01615 
01616     rootNav->releaseEntry();
01617   }
01618   RECURSE_ENTRYTREE(findUsingDirectives,rootNav);
01619 }
01620 
01621 //----------------------------------------------------------------------
01622 
01623 static void buildListOfUsingDecls(EntryNav *rootNav)
01624 {
01625   if (rootNav->section()==Entry::USINGDECL_SEC &&
01626       !(rootNav->parent()->section()&Entry::COMPOUND_MASK) // not a class/struct member
01627      )
01628   {
01629     rootNav->loadEntry(g_storage);
01630     Entry *root = rootNav->entry();
01631 
01632     QCString name = substitute(root->name,".","::");
01633     if (g_usingDeclarations.find(name)==0)
01634     {
01635       FileDef *fd = rootNav->fileDef();
01636       if (fd)
01637       {
01638         g_usingDeclarations.insert(name,fd);
01639       }
01640     }
01641 
01642     rootNav->releaseEntry();
01643   }
01644   RECURSE_ENTRYTREE(buildListOfUsingDecls,rootNav);
01645 }
01646 
01647   
01648 static void findUsingDeclarations(EntryNav *rootNav)
01649 {
01650   if (rootNav->section()==Entry::USINGDECL_SEC &&
01651       !(rootNav->parent()->section()&Entry::COMPOUND_MASK) // not a class/struct member
01652      )
01653   {
01654     rootNav->loadEntry(g_storage);
01655     Entry *root = rootNav->entry();
01656 
01657     //printf("Found using declaration %s at line %d of %s inside section %x\n",
01658     //    root->name.data(),root->startLine,root->fileName.data(),
01659     //    root->parent->section);
01660     if (!root->name.isEmpty())
01661     {
01662       ClassDef *usingCd = 0;
01663       NamespaceDef *nd = 0;
01664       FileDef      *fd = rootNav->fileDef();
01665       QCString scName;
01666 
01667       // see if the using statement was found inside a namespace or inside
01668       // the global file scope.
01669       if (rootNav->parent()->section() == Entry::NAMESPACE_SEC)
01670       {
01671         scName=rootNav->parent()->name();
01672         if (!scName.isEmpty())
01673         {
01674           nd = getResolvedNamespace(scName);
01675         }
01676       }
01677 
01678       // Assume the using statement was used to import a class.
01679       // Find the scope in which the `using' namespace is defined by prepending
01680       // the possible scopes in which the using statement was found, starting
01681       // with the most inner scope and going to the most outer scope (i.e. 
01682       // file scope).
01683 
01684       QCString name = substitute(root->name,".","::");
01685       //MemberDef *mtd=0;
01686       //usingCd = getResolvedClass(nd,fd,name,&mtd);
01687       usingCd = getClass(name);
01688       if (usingCd==0)
01689       {
01690         usingCd = Doxygen::hiddenClasses->find(name);
01691       }
01692 
01693       //printf("%s -> %p\n",root->name.data(),usingCd);
01694       if (usingCd==0) // definition not in the input => add an artificial class
01695       {
01696         Debug::print(Debug::Classes,0,"  New using class `%s' (sec=0x%08x)! #tArgLists=%d\n",
01697              name.data(),root->section,root->tArgLists ? (int)root->tArgLists->count() : -1);
01698         usingCd = new ClassDef(
01699                      "<using>",1,
01700                      name,ClassDef::Class);
01701         Doxygen::hiddenClasses->append(root->name,usingCd);
01702         usingCd->setArtificial(TRUE);
01703       }
01704       else
01705       {
01706         Debug::print(Debug::Classes,0,"  Found used class %s in scope=%s\n",
01707             usingCd->name().data(),nd?nd->name().data():fd->name().data());
01708       }
01709 
01710 #if 0
01711       if (mtd) // add the typedef to the correct scope
01712       {
01713         if (nd)
01714         {
01715           //printf("Inside namespace %s\n",nd->name().data());
01716           nd->addUsingDeclaration(mtd);
01717         }
01718         else if (fd)
01719         {
01720           //printf("Inside file %s\n",nd->name().data());
01721           fd->addUsingDeclaration(mtd);
01722         }
01723       }
01724       else 
01725 #endif
01726       if (usingCd) // add the class to the correct scope
01727       {
01728         if (nd)
01729         {
01730           //printf("Inside namespace %s\n",nd->name().data());
01731           nd->addUsingDeclaration(usingCd);
01732         }
01733         else if (fd)
01734         {
01735           //printf("Inside file %s\n",nd->name().data());
01736           fd->addUsingDeclaration(usingCd);
01737         }
01738       }
01739     }
01740 
01741     rootNav->releaseEntry();
01742   }
01743   RECURSE_ENTRYTREE(findUsingDeclarations,rootNav);
01744 }
01745 
01746 //----------------------------------------------------------------------
01747 
01748 static void findUsingDeclImports(EntryNav *rootNav)
01749 {
01750   if (rootNav->section()==Entry::USINGDECL_SEC &&
01751       (rootNav->parent()->section()&Entry::COMPOUND_MASK) // in a class/struct member
01752      )
01753   {
01754     //printf("Found using declaration %s at line %d of %s inside section %x\n",
01755     //    root->name.data(),root->startLine,root->fileName.data(),
01756     //    root->parent->section);
01757     QCString fullName=removeRedundantWhiteSpace(rootNav->parent()->name());
01758     fullName=stripAnonymousNamespaceScope(fullName);
01759     fullName=stripTemplateSpecifiersFromScope(fullName);
01760     ClassDef *cd = getClass(fullName);
01761     if (cd)
01762     {
01763       //printf("found class %s\n",cd->name().data());
01764       int i=rootNav->name().find("::");
01765       if (i!=-1)
01766       {
01767         QCString scope=rootNav->name().left(i);
01768         QCString memName=rootNav->name().right(rootNav->name().length()-i-2);
01769         ClassDef *bcd = getResolvedClass(cd,0,scope); // todo: file in fileScope parameter
01770         if (bcd)
01771         {
01772           //printf("found class %s\n",bcd->name().data());
01773           MemberNameInfoSDict *mndict=bcd->memberNameInfoSDict();
01774           if (mndict)
01775           {
01776             MemberNameInfo *mni = mndict->find(memName);
01777             if (mni)
01778             {
01779               MemberNameInfoIterator mnii(*mni); 
01780               MemberInfo *mi;
01781               for ( ; (mi=mnii.current()) ; ++mnii )
01782               {
01783                 MemberDef *md = mi->memberDef;
01784                 if (md && md->protection()!=Private)
01785                 {
01786 
01787                   rootNav->loadEntry(g_storage);
01788                   Entry *root = rootNav->entry();
01789 
01790                   //printf("found member %s\n",mni->memberName());
01791                   MemberDef *newMd = 0;
01792                   {
01793                     LockingPtr<ArgumentList> templAl = md->templateArguments();
01794                     LockingPtr<ArgumentList> al = md->templateArguments();
01795                     newMd = new MemberDef(
01796                       root->fileName,root->startLine,
01797                       md->typeString(),memName,md->argsString(),
01798                       md->excpString(),root->protection,root->virt,
01799                       md->isStatic(),FALSE,md->memberType(),
01800                       templAl.pointer(),al.pointer()
01801                       );
01802                   }
01803                   newMd->setMemberClass(cd);
01804                   cd->insertMember(newMd);
01805                   if (!root->doc.isEmpty() || !root->brief.isEmpty())
01806                   {
01807                     newMd->setDocumentation(root->doc,root->docFile,root->docLine);
01808                     newMd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
01809                     newMd->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
01810                   }
01811                   else
01812                   {
01813                     newMd->setDocumentation(md->documentation(),md->docFile(),md->docLine());
01814                     newMd->setBriefDescription(md->briefDescription(),md->briefFile(),md->briefLine());
01815                     newMd->setInbodyDocumentation(md->inbodyDocumentation(),md->inbodyFile(),md->inbodyLine());
01816                   }
01817                   newMd->setDefinition(md->definition());
01818                   newMd->enableCallGraph(root->callGraph);
01819                   newMd->enableCallerGraph(root->callerGraph);
01820                   newMd->setBitfields(md->bitfieldString());
01821                   newMd->addSectionsToDefinition(root->anchors);
01822                   newMd->setBodySegment(md->getStartBodyLine(),md->getEndBodyLine());
01823                   newMd->setBodyDef(md->getBodyDef());
01824                   newMd->setInitializer(md->initializer());
01825                   newMd->setMaxInitLines(md->initializerLines());
01826                   newMd->setMemberGroupId(root->mGrpId);
01827                   newMd->setMemberSpecifiers(md->getMemberSpecifiers());
01828 
01829                   rootNav->releaseEntry();
01830                 }
01831               }
01832             }
01833           }
01834         }
01835       }
01836     }
01837 
01838   }
01839   RECURSE_ENTRYTREE(findUsingDeclImports,rootNav);
01840 }
01841 
01842 //----------------------------------------------------------------------
01843 
01844 static void findIncludedUsingDirectives()
01845 {
01846   // first mark all files as not visited
01847   FileNameListIterator fnli(*Doxygen::inputNameList); 
01848   FileName *fn;
01849   for (fnli.toFirst();(fn=fnli.current());++fnli)
01850   {
01851     FileNameIterator fni(*fn);
01852     FileDef *fd;
01853     for (;(fd=fni.current());++fni)
01854     {
01855       fd->visited=FALSE;
01856     }
01857   }
01858   // then recursively add using directives found in #include files
01859   // to files that have not been visited.
01860   for (fnli.toFirst();(fn=fnli.current());++fnli)
01861   {
01862     FileNameIterator fni(*fn);
01863     FileDef *fd;
01864     for (fni.toFirst();(fd=fni.current());++fni)
01865     {
01866       if (!fd->visited) 
01867       {
01868         //printf("----- adding using directives for file %s\n",fd->name().data());
01869         fd->addIncludedUsingDirectives();
01870       }
01871     }
01872   }
01873 }
01874 
01875 //----------------------------------------------------------------------
01876 
01877 static MemberDef *addVariableToClass(
01878     EntryNav *rootNav,
01879     ClassDef *cd,
01880     MemberDef::MemberType mtype,
01881     const QCString &name,
01882     bool fromAnnScope,
01883     MemberDef *fromAnnMemb,
01884     Protection prot,
01885     bool related)
01886 {
01887   Entry *root = rootNav->entry();
01888 
01889   QCString qualScope = cd->qualifiedNameWithTemplateParameters();
01890   QCString scopeSeparator="::";
01891   if (Config_getBool("OPTIMIZE_OUTPUT_JAVA"))
01892   {
01893     qualScope = substitute(qualScope,"::",".");
01894     scopeSeparator=".";
01895   }
01896   Debug::print(Debug::Variables,0,
01897       "  class variable:\n"
01898       "    `%s' `%s'::`%s' `%s' prot=`%d ann=%d init=`%s'\n",
01899       root->type.data(),
01900       qualScope.data(), 
01901       name.data(),
01902       root->args.data(),
01903       root->protection,
01904       fromAnnScope,
01905       root->initializer.data()
01906               );
01907 
01908   QCString def;
01909   if (!root->type.isEmpty())
01910   {
01911     if (related || mtype==MemberDef::Friend || Config_getBool("HIDE_SCOPE_NAMES"))
01912     {
01913       def=root->type+" "+name+root->args;
01914     }
01915     else
01916     {
01917       def=root->type+" "+qualScope+scopeSeparator+name+root->args;
01918     }
01919   }
01920   else
01921   {
01922     if (Config_getBool("HIDE_SCOPE_NAMES"))
01923     {
01924       def=name+root->args;
01925     }
01926     else
01927     {
01928       def=qualScope+scopeSeparator+name+root->args;
01929     }
01930   }
01931   def.stripPrefix("static ");
01932 
01933   // see if the member is already found in the same scope
01934   // (this may be the case for a static member that is initialized
01935   //  outside the class)
01936   MemberName *mn=Doxygen::memberNameSDict->find(name);
01937   if (mn)
01938   {
01939     MemberNameIterator mni(*mn);
01940     MemberDef *md;
01941     for (mni.toFirst();(md=mni.current());++mni)
01942     {
01943       if (md->getClassDef()==cd && root->type==md->typeString()) 
01944         // member already in the scope
01945       {
01946         addMemberDocs(rootNav,md,def,0,FALSE);
01947         //printf("    Member already found!\n");
01948         return md;
01949       }
01950     } 
01951   }
01952   // new member variable, typedef or enum value
01953   MemberDef *md=new MemberDef(
01954       root->fileName,root->startLine,
01955       root->type,name,root->args,0,
01956       prot,Normal,root->stat,related,
01957       mtype,0,0);
01958   md->setTagInfo(rootNav->tagInfo());
01959   md->setMemberClass(cd); // also sets outer scope (i.e. getOuterScope())
01960   //md->setDefFile(root->fileName);
01961   //md->setDefLine(root->startLine);
01962   md->setDocumentation(root->doc,root->docFile,root->docLine);
01963   md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
01964   md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
01965   md->setDefinition(def);
01966   md->setBitfields(root->bitfields);
01967   md->addSectionsToDefinition(root->anchors);
01968   md->setFromAnonymousScope(fromAnnScope);
01969   md->setFromAnonymousMember(fromAnnMemb);
01970   //md->setIndentDepth(indentDepth);
01971   md->setBodySegment(root->bodyLine,root->endBodyLine);
01972   md->setInitializer(root->initializer);
01973   md->setMaxInitLines(root->initLines);
01974   md->setMemberGroupId(root->mGrpId);
01975   md->setMemberSpecifiers(root->spec);
01976   md->setReadAccessor(root->read);
01977   md->setWriteAccessor(root->write);
01978   md->enableCallGraph(root->callGraph);
01979   md->enableCallerGraph(root->callerGraph);
01980   md->setHidden(root->hidden);
01981   md->setArtificial(root->artificial);
01982   addMemberToGroups(root,md);
01983   //if (root->mGrpId!=-1) 
01984   //{
01985   //  printf("memberdef %s in memberGroup %d\n",name.data(),root->mGrpId);
01986   //  md->setMemberGroup(memberGroupDict[root->mGrpId]);
01987   //
01988   md->setBodyDef(rootNav->fileDef());
01989 
01990   //printf("Adding member=%s\n",md->name().data());
01991   // add the member to the global list
01992   if (mn)
01993   {
01994     mn->append(md);
01995   }
01996   else // new variable name
01997   {
01998     mn = new MemberName(name);
01999     mn->append(md);
02000     //printf("Adding memberName=%s\n",mn->memberName());
02001     //Doxygen::memberNameDict.insert(name,mn);
02002     //Doxygen::memberNameList.append(mn);
02003     Doxygen::memberNameSDict->append(name,mn);
02004     // add the member to the class
02005   }
02006   //printf("    New member adding to %s (%p)!\n",cd->name().data(),cd);
02007   cd->insertMember(md);
02008   md->setRefItems(root->sli);
02009 
02010   //TODO: insert FileDef instead of filename strings.
02011   cd->insertUsedFile(root->fileName);
02012   rootNav->changeSection(Entry::EMPTY_SEC);
02013   return md;
02014 }
02015 
02016 //----------------------------------------------------------------------
02017 
02018 static MemberDef *addVariableToFile(
02019     EntryNav *rootNav,
02020     MemberDef::MemberType mtype,
02021     const QCString &scope,
02022     const QCString &name,
02023     bool fromAnnScope,
02024     /*int indentDepth,*/
02025     MemberDef *fromAnnMemb)
02026 {
02027   Entry *root = rootNav->entry();
02028   Debug::print(Debug::Variables,0,
02029       "  global variable:\n"
02030       "    type=`%s' scope=`%s' name=`%s' args=`%s' prot=`%d mtype=%d\n",
02031       root->type.data(),
02032       scope.data(), 
02033       name.data(),
02034       root->args.data(),
02035       root->protection,
02036       mtype
02037               );
02038 
02039   FileDef *fd = rootNav->fileDef();
02040 
02041   // see if the function is inside a namespace
02042   NamespaceDef *nd = 0;
02043   QCString nscope;
02044   if (!scope.isEmpty())
02045   {
02046     nscope=removeAnonymousScopes(scope);
02047     if (!nscope.isEmpty())
02048     {
02049       nd = getResolvedNamespace(nscope);
02050     }
02051   }
02052   QCString def;
02053 
02054   // determine the definition of the global variable
02055   if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@' && 
02056       !Config_getBool("HIDE_SCOPE_NAMES")
02057      )
02058     // variable is inside a namespace, so put the scope before the name
02059   {
02060     static bool optimizeForJava = Config_getBool("OPTIMIZE_OUTPUT_JAVA");
02061     QCString sep="::";
02062     if (optimizeForJava) sep=".";
02063     
02064     if (!root->type.isEmpty())
02065     {
02066       def=root->type+" "+nd->name()+sep+name+root->args;
02067     }
02068     else
02069     {
02070       def=nd->name()+sep+name+root->args;
02071     }
02072   }
02073   else
02074   {
02075     if (!root->type.isEmpty() && !root->name.isEmpty())
02076     {
02077       if (name.at(0)=='@') // dummy variable representing annonymous union
02078         def=root->type;
02079       else
02080         def=root->type+" "+name+root->args;
02081     }
02082     else
02083     {
02084       def=name+root->args;
02085     }
02086   }
02087   def.stripPrefix("static ");
02088 
02089   MemberName *mn=Doxygen::functionNameSDict->find(name);
02090   if (mn)
02091   {
02092     //QCString nscope=removeAnonymousScopes(scope);
02093     //NamespaceDef *nd=0;
02094     //if (!nscope.isEmpty())
02095     //{
02096     //  nd = getResolvedNamespace(nscope);
02097     //}
02098     MemberNameIterator mni(*mn);
02099     MemberDef *md;
02100     for (mni.toFirst();(md=mni.current());++mni)
02101     {
02102       if (
02103           ((nd==0 && md->getNamespaceDef()==0 && md->getFileDef() && 
02104             root->fileName==md->getFileDef()->absFilePath()
02105            ) // both variable names in the same file
02106            || (nd!=0 && md->getNamespaceDef()==nd) // both in same namespace
02107           )
02108           && !md->isDefine() // function style #define's can be "overloaded" by typedefs or variables
02109          )
02110         // variable already in the scope
02111       {
02112         if (md->getFileDef() &&
02113             ! // not a php array
02114              (
02115                (getLanguageFromFileName(md->getFileDef()->name())==SrcLangExt_PHP) &&
02116                (md->argsString()!=root->args && root->args.find('[')!=-1)
02117              )
02118            ) 
02119           // not a php array variable
02120         {
02121 
02122           Debug::print(Debug::Variables,0,
02123               "    variable already found: scope=%s\n",md->getOuterScope()->name().data());
02124           addMemberDocs(rootNav,md,def,0,FALSE);
02125           md->setRefItems(root->sli);
02126           return md;
02127         }
02128       }
02129     } 
02130   }
02131   Debug::print(Debug::Variables,0,
02132     "    new variable, nd=%s!\n",nd?nd->name().data():"<global>");
02133   // new global variable, enum value or typedef
02134   MemberDef *md=new MemberDef(
02135       root->fileName,root->startLine,
02136       root->type,name,root->args,0,
02137       Public, Normal,root->stat,FALSE,
02138       mtype,0,0);
02139   md->setTagInfo(rootNav->tagInfo());
02140   md->setDocumentation(root->doc,root->docFile,root->docLine);
02141   md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
02142   md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
02143   md->addSectionsToDefinition(root->anchors);
02144   md->setFromAnonymousScope(fromAnnScope);
02145   md->setFromAnonymousMember(fromAnnMemb);
02146   md->setInitializer(root->initializer);
02147   md->setMaxInitLines(root->initLines);
02148   md->setMemberGroupId(root->mGrpId);
02149   md->setDefinition(def);
02150   md->enableCallGraph(root->callGraph);
02151   md->enableCallerGraph(root->callerGraph);
02152   md->setExplicitExternal(root->explicitExternal);
02153   //md->setOuterScope(fd);
02154   if (!root->explicitExternal)
02155   {
02156     md->setBodySegment(root->bodyLine,root->endBodyLine);
02157     md->setBodyDef(fd);
02158   }
02159   addMemberToGroups(root,md);
02160 
02161   md->setRefItems(root->sli);
02162   if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@')
02163   {
02164     md->setNamespace(nd);
02165     nd->insertMember(md); 
02166   }
02167 
02168   // add member to the file (we do this even if we have already inserted
02169   // it into the namespace. 
02170   if (fd)
02171   {
02172     md->setFileDef(fd); 
02173     fd->insertMember(md);
02174   }
02175 
02176   // add member definition to the list of globals 
02177   if (mn)
02178   {
02179     mn->append(md);
02180   }
02181   else
02182   {
02183     mn = new MemberName(name);
02184     mn->append(md);
02185     Doxygen::functionNameSDict->append(name,mn);
02186   }
02187   rootNav->changeSection(Entry::EMPTY_SEC);
02188   return md;
02189 }
02190 
02195 static int findFunctionPtr(const QCString &type,int *pLength=0)
02196 {
02197   static const QRegExp re("([^)]*\\*[^)]*)");
02198   int i=-1,l;
02199   if (!type.isEmpty() &&             // return type is non-empty
02200       (i=re.match(type,0,&l))!=-1 && // contains (...*...)
02201       type.find("operator")==-1 &&   // not an operator
02202       (type.find(")(")==-1 || type.find("typedef ")!=-1)
02203                                     // not a function pointer return type
02204      )
02205   {
02206     if (pLength) *pLength=l;
02207     return i;
02208   }
02209   else
02210   {
02211     return -1;
02212   }
02213 }
02214 
02215 
02219 static bool isVarWithConstructor(EntryNav *rootNav)
02220 {
02221   static QRegExp initChars("[0-9\"'&*!^]+");
02222   static QRegExp idChars("[a-z_A-Z][a-z_A-Z0-9]*");
02223   bool result=FALSE;
02224   bool typeIsClass;
02225   QCString type;
02226   Definition *ctx = 0;
02227   FileDef *fd = 0;
02228   int ti;
02229 
02230   //printf("isVarWithConstructor(%s)\n",rootNav->name().data());
02231   rootNav->loadEntry(g_storage);
02232   Entry *root = rootNav->entry();
02233 
02234   if (rootNav->parent()->section() & Entry::COMPOUND_MASK)
02235   { // inside a class
02236     result=FALSE;
02237     goto done;
02238   }
02239   else if ((fd = rootNav->fileDef()) &&
02240        fd->name().right(2)==".c"
02241      )
02242   { // inside a .c file
02243     result=FALSE;
02244     goto done;
02245   }
02246   if (root->type.isEmpty()) 
02247   {
02248     result=FALSE;
02249     goto done;
02250   }
02251   if (!rootNav->parent()->name().isEmpty()) 
02252   {
02253     ctx=Doxygen::namespaceSDict->find(rootNav->parent()->name());
02254   }
02255   type = root->type;
02256   // remove qualifiers
02257   findAndRemoveWord(type,"const");
02258   findAndRemoveWord(type,"static");
02259   findAndRemoveWord(type,"volatile");
02260   //if (type.left(6)=="const ") type=type.right(type.length()-6);
02261   typeIsClass=getResolvedClass(ctx,fd,type)!=0;
02262   if (!typeIsClass && (ti=type.find('<'))!=-1)
02263   {
02264     typeIsClass=getResolvedClass(ctx,fd,type.left(ti))!=0;
02265   }
02266   if (typeIsClass) // now we still have to check if the arguments are 
02267                    // types or values. Since we do not have complete type info
02268                    // we need to rely on heuristics :-(
02269   {
02270     //printf("typeIsClass\n");
02271     ArgumentList *al = root->argList;
02272     if (al==0 || al->isEmpty()) 
02273     {
02274       result=FALSE; // empty arg list -> function prototype.
02275       goto done;
02276     }
02277     ArgumentListIterator ali(*al);
02278     Argument *a;
02279     for (ali.toFirst();(a=ali.current());++ali)
02280     {
02281       if (!a->name.isEmpty() || !a->defval.isEmpty()) 
02282       {
02283         if (a->name.find(initChars)==0)
02284         {
02285           result=TRUE;
02286         }
02287         else
02288         {
02289           result=FALSE; // arg has (type,name) pair -> function prototype
02290         }
02291         goto done;
02292       }
02293       if (a->type.isEmpty() || getResolvedClass(ctx,fd,a->type)!=0) 
02294       {
02295         result=FALSE; // arg type is a known type
02296         goto done;
02297       }
02298       if (checkIfTypedef(ctx,fd,a->type))
02299       {
02300          //printf("%s:%d: false (arg is typedef)\n",__FILE__,__LINE__);
02301          result=FALSE; // argument is a typedef
02302          goto done;
02303       }
02304       if (a->type.at(a->type.length()-1)=='*' ||
02305           a->type.at(a->type.length()-1)=='&')  
02306                      // type ends with * or & => pointer or reference
02307       {
02308         result=FALSE;
02309         goto done;
02310       }
02311       if (a->type.find(initChars)==0) 
02312       {
02313         result=TRUE; // argument type starts with typical initializer char
02314         goto done;
02315       }
02316       QCString resType=resolveTypeDef(ctx,a->type);
02317       if (resType.isEmpty()) resType=a->type;
02318       int len;
02319       if (idChars.match(resType,0,&len)==0) // resType starts with identifier
02320       {
02321         resType=resType.left(len);
02322         //printf("resType=%s\n",resType.data());
02323         if (resType=="int"    || resType=="long" || resType=="float" || 
02324             resType=="double" || resType=="char" || resType=="signed" || 
02325             resType=="const"  || resType=="unsigned" || resType=="void") 
02326         {
02327           result=FALSE; // type keyword -> function prototype
02328           goto done;
02329         }
02330       }
02331     }
02332     result=TRUE;
02333   }
02334 
02335 done:
02336   rootNav->releaseEntry();
02337   //printf("isVarWithConstructor(%s,%s)=%d\n",root->parent->name.data(),
02338   //                                       root->type.data(),result);
02339   return result;
02340 }
02341 
02342 //----------------------------------------------------------------------
02343 // Searches the Entry tree for Variable documentation sections.
02344 // If found they are stored in their class or in the global list.
02345 
02346 static void buildVarList(EntryNav *rootNav)
02347 {
02348   //printf("buildVarList(%s)\n",rootNav->name().data());
02349   int isFuncPtr=-1;
02350   if (!rootNav->name().isEmpty() &&
02351       (rootNav->type().isEmpty() || compoundKeywordDict.find(rootNav->type())==0) &&
02352       (
02353        (rootNav->section()==Entry::VARIABLE_SEC    // it's a variable
02354        ) ||
02355        (rootNav->section()==Entry::FUNCTION_SEC && // or maybe a function pointer variable 
02356         (isFuncPtr=findFunctionPtr(rootNav->type()))!=-1
02357        ) ||
02358        (rootNav->section()==Entry::FUNCTION_SEC && // class variable initialized by constructor
02359         isVarWithConstructor(rootNav)
02360        )
02361       ) 
02362      ) // documented variable
02363   {
02364     rootNav->loadEntry(g_storage);
02365     Entry *root = rootNav->entry();
02366 
02367     Debug::print(Debug::Variables,0,
02368                   "VARIABLE_SEC: \n"
02369                   "  type=`%s' name=`%s' args=`%s' bodyLine=`%d' mGrpId=%d\n",
02370                    root->type.data(),
02371                    root->name.data(),
02372                    root->args.data(),
02373                    root->bodyLine,
02374                    root->mGrpId
02375                 );
02376     //printf("root->parent->name=%s\n",root->parent->name.data());
02377 
02378     if (root->type.isEmpty() && root->name.find("operator")==-1 &&
02379         (root->name.find('*')!=-1 || root->name.find('&')!=-1))
02380     {
02381       // recover from parse error caused by redundant braces 
02382       // like in "int *(var[10]);", which is parsed as
02383       // type="" name="int *" args="(var[10])"
02384 
02385       root->type=root->name;
02386       static const QRegExp reName("[a-z_A-Z][a-z_A-Z0-9]*");
02387       int l;
02388       int i=root->args.isEmpty() ? -1 : reName.match(root->args,0,&l);
02389       root->name=root->args.mid(i,l);
02390       root->args=root->args.mid(i+l,root->args.find(')',i+l)-i-l);
02391       //printf("new: type=`%s' name=`%s' args=`%s'\n",
02392       //    root->type.data(),root->name.data(),root->args.data());
02393     }
02394     else
02395     {
02396       int i=isFuncPtr;
02397       if (i==-1) i=findFunctionPtr(root->type); // for typedefs isFuncPtr is not yet set
02398       if (i!=-1) // function pointer
02399       {
02400         int ai = root->type.find('[',i);
02401         if (ai>i) // function pointer array
02402         {
02403           root->args.prepend(root->type.right(root->type.length()-ai));
02404           root->type=root->type.left(ai);
02405         }
02406         else if (root->type.find(')',i)!=-1) // function ptr, not variable like "int (*bla)[10]"
02407         {
02408           root->type=root->type.left(root->type.length()-1);
02409           root->args.prepend(")");
02410           //printf("root->type=%s root->args=%s\n",root->type.data(),root->args.data());
02411         }
02412       }
02413       else if (root->type.find("typedef ")!=-1 && root->type.right(2)=="()") // typedef void (func)(int)
02414       {
02415         root->type=root->type.left(root->type.length()-1);
02416         root->args.prepend(")");
02417       }
02418     }
02419     
02420     QCString scope,name=removeRedundantWhiteSpace(root->name);
02421 
02422     // find the scope of this variable 
02423     EntryNav *p = rootNav->parent();
02424     while ((p->section() & Entry::SCOPE_MASK))
02425     {
02426       QCString scopeName = p->name();
02427       if (!scopeName.isEmpty())
02428       {
02429         scope.prepend(scopeName);
02430         break;
02431       }
02432       p=p->parent();
02433     }
02434     
02435     MemberDef::MemberType mtype;
02436     QCString type=root->type.stripWhiteSpace();
02437     ClassDef *cd=0;
02438     bool isRelated=FALSE;
02439 
02440     QCString classScope=stripAnonymousNamespaceScope(scope);
02441     classScope=stripTemplateSpecifiersFromScope(classScope,FALSE);
02442     QCString annScopePrefix=scope.left(scope.length()-classScope.length());
02443 
02444     if (root->name.findRev("::")!=-1) 
02445     {
02446       if (root->type=="friend class" || root->type=="friend struct" || 
02447           root->type=="friend union")
02448       {
02449          cd=getClass(scope);
02450          if (cd)
02451          {
02452            addVariableToClass(rootNav,  // entry
02453                               cd,    // class to add member to
02454                               MemberDef::Friend, // type of member
02455                               name, // name of the member
02456                               FALSE,  // from Anonymous scope
02457                               0,      // anonymous member
02458                               Public, // protection
02459                               FALSE   // related to a class
02460                              );
02461          }
02462       }
02463       goto nextMember;
02464                /* skip this member, because it is a 
02465                 * static variable definition (always?), which will be
02466                 * found in a class scope as well, but then we know the
02467                 * correct protection level, so only then it will be
02468                 * inserted in the correct list!
02469                 */
02470     }
02471 
02472     if (type=="@") 
02473       mtype=MemberDef::EnumValue;
02474     else if (type.left(8)=="typedef ") 
02475       mtype=MemberDef::Typedef;
02476     else if (type.left(7)=="friend ")
02477       mtype=MemberDef::Friend;
02478     else if (root->mtype==Property)
02479       mtype=MemberDef::Property;
02480     else if (root->mtype==Event)
02481       mtype=MemberDef::Event;
02482     else
02483       mtype=MemberDef::Variable;
02484 
02485 #if 0 // does not work correctly
02486     //static bool typedefHidesStruct = Config_getBool("TYPEDEF_HIDES_STRUCT");
02487     if (typedefHidesStruct) // substitute names with typedef'ed names
02488     {
02489       QCString baseType = type;
02490       baseType.stripPrefix("typedef ");
02491       if (baseType.stripPrefix("enum "))
02492       {
02493         MemberName *mn=Doxygen::functionNameSDict->find(baseType.stripWhiteSpace());
02494         MemberNameIterator mni(*mn);
02495         MemberDef *md;
02496         for (mni.toFirst();(md=mni.current());++mni)
02497         {
02498           if (md->isEnumerate())
02499           {
02500             md->setName(name);
02501             md->setDefinition(name);
02502             goto nextMember;
02503           }
02504         }
02505       }
02506       else
02507       {
02508         baseType.stripPrefix("struct ");
02509         baseType.stripPrefix("union ");
02510         {
02511           ClassDef *typedefClass = Doxygen::classSDict->find(baseType);
02512           if (typedefClass)
02513           {
02514             typedefClass->setName(name);
02515             typedefClass->setClassName(name);
02516             goto nextMember;
02517           }
02518         }
02519       }
02520     }
02521 #endif
02522 
02523     if (!root->relates.isEmpty()) // related variable
02524     {
02525       isRelated=TRUE;
02526       if (getClass(root->relates)==0 && !scope.isEmpty())
02527         scope=mergeScopes(scope,root->relates);
02528       else 
02529         scope=root->relates;
02530     }
02531     
02532     cd=getClass(scope);
02533     if (cd==0 && classScope!=scope) cd=getClass(classScope);
02534     if (cd)
02535     {
02536       MemberDef *md=0;
02537 
02538       // if cd is an annonymous scope we insert the member 
02539       // into a non-annonymous scope as well. This is needed to
02540       // be able to refer to it using \var or \fn
02541 
02542       //int indentDepth=0;
02543       int si=scope.find('@');
02544       //int anonyScopes = 0;
02545       bool added=FALSE;
02546       
02547       if (si!=-1) // anonymous scope
02548       {
02549         QCString pScope;
02550         ClassDef *pcd=0;
02551         pScope = scope.left(QMAX(si-2,0));
02552         if (!pScope.isEmpty())
02553           pScope.prepend(annScopePrefix);
02554         else if (annScopePrefix.length()>2)
02555           pScope=annScopePrefix.left(annScopePrefix.length()-2);
02556         if (name.at(0)!='@')
02557         {
02558           if (!pScope.isEmpty() && (pcd=getClass(pScope)))
02559           {
02560             md=addVariableToClass(rootNav,  // entry
02561                                   pcd,   // class to add member to
02562                                   mtype, // member type
02563                                   name,  // member name
02564                                   TRUE,  // from anonymous scope
02565                                   0,     // from anonymous member
02566                                   root->protection,
02567                                   isRelated
02568                                  );
02569             added=TRUE;
02570           }
02571           else // anonymous scope inside namespace or file => put variable in the global scope
02572           {
02573             if (mtype==MemberDef::Variable)
02574             {
02575               md=addVariableToFile(rootNav,mtype,pScope,name,TRUE,0); 
02576             }
02577             added=TRUE;
02578           }
02579         }
02580       }
02581       //printf("name=`%s' scope=%s scope.right=%s\n",
02582       //                   name.data(),scope.data(),
02583       //                   scope.right(scope.length()-si).data());
02584       addVariableToClass(rootNav,   // entry
02585                          cd,     // class to add member to
02586                          mtype,  // member type
02587                          name,   // name of the member
02588                          FALSE,  // from anonymous scope
02589                          md,     // from anonymous member
02590                          root->protection, 
02591                          isRelated);
02592     }
02593     else if (!name.isEmpty()) // global variable
02594     {
02595       //printf("Inserting member in global scope %s!\n",scope.data());
02596       addVariableToFile(rootNav,mtype,scope,name,FALSE,/*0,*/0);
02597     }
02598 nextMember:
02599 
02600     rootNav->releaseEntry();
02601   }
02602   if (rootNav->children())
02603   {
02604     EntryNavListIterator eli(*rootNav->children());
02605     EntryNav *e;
02606     for (;(e=eli.current());++eli)
02607     {
02608       if (e->section()!=Entry::ENUM_SEC) 
02609       {
02610         buildVarList(e);
02611       }
02612     }
02613   }
02614 }
02615 
02616 //----------------------------------------------------------------------
02617 // Searches the Entry tree for Function sections.
02618 // If found they are stored in their class or in the global list.
02619 
02620 static void addMethodToClass(EntryNav *rootNav,ClassDef *cd,
02621                   const QCString &rname,bool isFriend)
02622 {
02623   Entry *root = rootNav->entry();
02624   FileDef *fd=rootNav->fileDef();
02625 
02626   int l,i=-1;
02627   static QRegExp re("([a-z_A-Z0-9: ]*[ &*]+[ ]*");
02628 
02629   if (!root->type.isEmpty() && (i=re.match(root->type,0,&l))!=-1) // function variable
02630   {
02631     root->args+=root->type.right(root->type.length()-i-l);
02632     root->type=root->type.left(i+l);
02633   }
02634 
02635   QCString name=removeRedundantWhiteSpace(rname);
02636   if (name.left(2)=="::") name=name.right(name.length()-2);
02637 
02638   MemberDef::MemberType mtype;
02639   if (isFriend)                 mtype=MemberDef::Friend;
02640   else if (root->mtype==Signal) mtype=MemberDef::Signal;
02641   else if (root->mtype==Slot)   mtype=MemberDef::Slot;
02642   else if (root->mtype==DCOP)   mtype=MemberDef::DCOP;
02643   else                          mtype=MemberDef::Function;
02644 
02645   // strip redundant template specifier for constructors
02646   if ((fd==0 || getLanguageFromFileName(fd->name())==SrcLangExt_Cpp) &&
02647      name.left(9)!="operator " && (i=name.find('<'))!=-1 && name.find('>')!=-1)
02648   {
02649     name=name.left(i); 
02650   }
02651 
02652   //printf("root->name=`%s; root->args=`%s' root->argList=`%s'\n", 
02653   //    root->name.data(),root->args.data(),argListToString(root->argList).data()
02654   //   );
02655 
02656   // adding class member
02657   MemberDef *md=new MemberDef(
02658       root->fileName,root->startLine,
02659       root->type,name,root->args,root->exception,
02660       root->protection,root->virt,root->stat,!root->relates.isEmpty(),
02661       mtype,root->tArgLists ? root->tArgLists->last() : 0,root->argList);
02662   md->setTagInfo(rootNav->tagInfo());
02663   md->setMemberClass(cd);
02664   md->setDocumentation(root->doc,root->docFile,root->docLine);
02665   md->setDocsForDefinition(!root->proto);
02666   md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
02667   md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
02668   md->setBodySegment(root->bodyLine,root->endBodyLine);
02669   md->setMemberSpecifiers(root->spec);
02670   md->setMemberGroupId(root->mGrpId);
02671   md->setTypeConstraints(root->typeConstr);
02672   md->setBodyDef(fd);
02673   md->setFileDef(fd);
02674   //md->setScopeTemplateArguments(root->tArgList);
02675   md->addSectionsToDefinition(root->anchors);
02676   QCString def;
02677   QCString qualScope = cd->qualifiedNameWithTemplateParameters();
02678   QCString scopeSeparator="::";
02679   if (Config_getBool("OPTIMIZE_OUTPUT_JAVA"))
02680   {
02681     qualScope = substitute(qualScope,"::",".");
02682     scopeSeparator=".";
02683   }
02684   if (!root->relates.isEmpty() || isFriend || Config_getBool("HIDE_SCOPE_NAMES"))
02685   {
02686     if (!root->type.isEmpty())
02687     {
02688       if (root->argList)
02689       {
02690         def=root->type+" "+name;
02691       }
02692       else
02693       {
02694         def=root->type+" "+name+root->args;
02695       }
02696     }
02697     else
02698     {
02699       if (root->argList)
02700       {
02701         def=name;
02702       }
02703       else
02704       {
02705         def=name+root->args;
02706       }
02707     }
02708   }
02709   else
02710   {
02711     if (!root->type.isEmpty())
02712     {
02713       if (root->argList)
02714       {
02715         def=root->type+" "+qualScope+scopeSeparator+name;
02716       }
02717       else
02718       {
02719         def=root->type+" "+qualScope+scopeSeparator+name+root->args;
02720       }
02721     }
02722     else
02723     {
02724       if (root->argList)
02725       {
02726         def=qualScope+scopeSeparator+name;
02727       }
02728       else
02729       {
02730         def=qualScope+scopeSeparator+name+root->args;
02731       }
02732     }
02733   }
02734   if (def.left(7)=="friend ") def=def.right(def.length()-7);
02735   md->setDefinition(def);
02736   md->enableCallGraph(root->callGraph);
02737   md->enableCallerGraph(root->callerGraph);
02738 
02739   Debug::print(Debug::Functions,0,
02740       "  Func Member:\n"
02741       "    `%s' `%s'::`%s' `%s' proto=%d\n"
02742       "    def=`%s'\n",
02743       root->type.data(),
02744       qualScope.data(),
02745       rname.data(),
02746       root->args.data(),
02747       root->proto,
02748       def.data()
02749               );
02750 
02751   // add member to the global list of all members
02752   //printf("Adding member=%s class=%s\n",md->name().data(),cd->name().data());
02753   MemberName *mn;
02754   if ((mn=Doxygen::memberNameSDict->find(name)))
02755   {
02756     mn->append(md);
02757   }
02758   else
02759   {
02760     mn = new MemberName(name);
02761     mn->append(md);
02762     Doxygen::memberNameSDict->append(name,mn);
02763   }
02764 
02765   // add member to the class cd
02766   cd->insertMember(md);
02767   // add file to list of used files
02768   cd->insertUsedFile(root->fileName);
02769 
02770   addMemberToGroups(root,md);
02771   rootNav->changeSection(Entry::EMPTY_SEC);
02772   md->setRefItems(root->sli);
02773 }
02774 
02775 
02776 static void buildFunctionList(EntryNav *rootNav)
02777 {
02778   if (rootNav->section()==Entry::FUNCTION_SEC)
02779   {
02780     rootNav->loadEntry(g_storage);
02781     Entry *root = rootNav->entry();
02782 
02783     Debug::print(Debug::Functions,0,
02784                  "FUNCTION_SEC:\n"
02785                  "  `%s' `%s'::`%s' `%s' relates=`%s' relatesDup=`%d' file=`%s' line=`%d' bodyLine=`%d' #tArgLists=%d mGrpId=%d spec=%d proto=%d docFile=%s\n",
02786                  root->type.data(),
02787                  rootNav->parent()->name().data(),
02788                  root->name.data(),
02789                  root->args.data(),
02790                  root->relates.data(),
02791                  root->relatesDup,
02792                  root->fileName.data(),
02793                  root->startLine,
02794                  root->bodyLine,
02795                  root->tArgLists ? (int)root->tArgLists->count() : -1,
02796                  root->mGrpId,
02797                  root->spec,
02798                  root->proto,
02799                  root->docFile.data()
02800                 );
02801 
02802     bool isFriend=root->type.find("friend ")!=-1;
02803     QCString rname = removeRedundantWhiteSpace(root->name);
02804     //printf("rname=%s\n",rname.data());
02805 
02806     if (!rname.isEmpty())
02807     {
02808       
02809       ClassDef *cd=0;
02810       // check if this function's parent is a class
02811       QCString scope=rootNav->parent()->name(); //stripAnonymousNamespaceScope(root->parent->name);
02812       scope=stripTemplateSpecifiersFromScope(scope,FALSE);
02813 
02814       FileDef *rfd=rootNav->fileDef();
02815 
02816       int memIndex=rname.findRev("::");
02817 
02818       cd=getClass(scope);
02819       if (cd && scope+"::"==rname.left(scope.length()+2)) // found A::f inside A
02820       {
02821         // strip scope from name
02822         rname=rname.right(rname.length()-rootNav->parent()->name().length()-2); 
02823       }
02824 
02825       NamespaceDef *nd = 0;
02826       bool isMember=FALSE;
02827       if (memIndex!=-1)
02828       {
02829         int ts=rname.find('<');
02830         int te=rname.find('>');
02831         if (memIndex>0 && (ts==-1 || te==-1))
02832         {
02833           nd = Doxygen::namespaceSDict->find(rname.left(memIndex));
02834           isMember = nd==0;
02835           if (nd)
02836           {
02837             // strip namespace scope from name
02838             scope=rname.left(memIndex);
02839             rname=rname.right(rname.length()-memIndex-2);
02840           }
02841         }
02842         else
02843         {
02844           isMember=memIndex<ts || memIndex>te;
02845         }
02846       
02847       }
02848 
02849       static QRegExp re("([a-z_A-Z0-9: ]*[ &*]+[ ]*");
02850       if (!rootNav->parent()->name().isEmpty() &&
02851           (rootNav->parent()->section() & Entry::COMPOUND_MASK) && 
02852           cd &&
02853           // do some fuzzy things to exclude function pointers 
02854           (root->type.isEmpty() || 
02855            (root->type.find(re,0)==-1 || root->args.find(")[")!=-1) ||  // type contains ..(..* and args not )[.. -> function pointer
02856            root->type.find(")(")!=-1 || root->type.find("operator")!=-1 // type contains ..)(.. and not "operator"
02857           )
02858          )
02859       {
02860         Debug::print(Debug::Functions,0,"  --> member %s of class %s!\n",
02861             rname.data(),cd->name().data());
02862         addMethodToClass(rootNav,cd,rname,isFriend);
02863       }
02864       else if (!((rootNav->parent()->section() & Entry::COMPOUND_MASK) 
02865                  || rootNav->parent()->section()==Entry::OBJCIMPL_SEC
02866                 ) &&
02867                !isMember &&
02868                (root->relates.isEmpty() || root->relatesDup) &&
02869                root->type.left(7)!="extern " && root->type.left(8)!="typedef " 
02870               )
02871       // no member => unrelated function 
02872       {
02873         /* check the uniqueness of the function name in the file.
02874          * A file could contain a function prototype and a function definition
02875          * or even multiple function prototypes.
02876          */
02877         bool found=FALSE;
02878         MemberName *mn;
02879         MemberDef *md=0;
02880         if ((mn=Doxygen::functionNameSDict->find(rname)))
02881         {
02882           Debug::print(Debug::Functions,0,"  --> function %s already found!\n",rname.data());
02883           MemberNameIterator mni(*mn);
02884           for (mni.toFirst();(!found && (md=mni.current()));++mni)
02885           {
02886             NamespaceDef *mnd = md->getNamespaceDef();
02887             NamespaceDef *rnd = 0;
02888             //printf("root namespace=%s\n",rootNav->parent()->name().data());
02889             QCString fullScope = scope;
02890             QCString parentScope = rootNav->parent()->name();
02891             if (!parentScope.isEmpty() && !leftScopeMatch(parentScope,scope))
02892             {
02893               if (!scope.isEmpty()) fullScope.prepend("::");
02894               fullScope.prepend(parentScope);
02895             }
02896             //printf("fullScope=%s\n",fullScope.data());
02897             rnd = getResolvedNamespace(fullScope);
02898             FileDef *mfd = md->getFileDef();
02899             QCString nsName,rnsName;
02900             if (mnd)  nsName = mnd->name().copy();
02901             if (rnd) rnsName = rnd->name().copy();
02902             //printf("matching arguments for %s%s %s%s\n",
02903             //    md->name().data(),md->argsString(),rname.data(),argListToString(root->argList).data());
02904             LockingPtr<ArgumentList> mdAl = md->argumentList();
02905             if ( 
02906                 matchArguments2(md->getOuterScope(),mfd,mdAl.pointer(),
02907                                 rnd ? rnd : Doxygen::globalScope,rfd,root->argList,
02908                                 FALSE)
02909                )
02910             {
02911               GroupDef *gd=0;
02912               if (root->groups->first()!=0)
02913               {
02914                 gd = Doxygen::groupSDict->find(root->groups->first()->groupname.data());
02915               }
02916               //printf("match!\n");
02917               //printf("mnd=%p rnd=%p nsName=%s rnsName=%s\n",mnd,rnd,nsName.data(),rnsName.data());
02918               // see if we need to create a new member
02919               found=(mnd && rnd && nsName==rnsName) ||   // members are in the same namespace
02920                     ((mnd==0 && rnd==0 && mfd!=0 &&       // no external reference and
02921                       mfd->absFilePath()==root->fileName // prototype in the same file
02922                      ) 
02923                     ); 
02924               // otherwise, allow a duplicate global member with the same argument list
02925               if (!found && gd && gd==md->getGroupDef())
02926               {
02927                 // member is already in the group, so we don't want to add it again.
02928                 found=TRUE;
02929               }
02930               
02931               //printf("combining function with prototype found=%d in namespace %s\n",
02932               //    found,nsName.data());
02933 
02934               if (found)
02935               {
02936                 // merge argument lists
02937                 mergeArguments(mdAl.pointer(),root->argList,!root->doc.isEmpty());
02938                 // merge documentation
02939                 if (md->documentation().isEmpty() && !root->doc.isEmpty())
02940                 {
02941                   ArgumentList *argList = new ArgumentList;
02942                   stringToArgumentList(root->args,argList);
02943                   if (root->proto)
02944                   {
02945                     //printf("setDeclArgumentList to %p\n",argList);
02946                     md->setDeclArgumentList(argList);
02947                   }
02948                   else
02949                   {
02950                     md->setArgumentList(argList);
02951                   }
02952                 }
02953 #if 0
02954                 else if (!md->documentation().isEmpty() && !root->doc.isEmpty() && mnd==rnd)
02955                 {
02956                   warn(root->docFile,root->docLine,"Warning: member %s: ignoring the detailed description found here, since another one was found at line %d of file %s!",md->name().data(),md->docLine(),md->docFile().data());
02957                   //printf("md->docs=[%s] root->docs=[%s]\n",md->documentation().data(),root->doc.data());
02958                 }
02959 #endif
02960                 md->setDocumentation(root->doc,root->docFile,root->docLine);
02961                 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
02962                 md->setDocsForDefinition(!root->proto);
02963 
02964                 if (md->briefDescription().isEmpty() && !root->brief.isEmpty())
02965                 {
02966                   md->setArgsString(root->args);
02967                 }
02968 #if 0
02969                 else if (!md->briefDescription().isEmpty() && !root->brief.isEmpty() && mnd==rnd)
02970                 {
02971                   warn(root->briefFile,root->briefLine,"Warning: member %s: ignoring the brief description found here, since another one was found at line %d of file %s!",md->name().data(),md->briefLine(),md->briefFile().data());
02972                 }
02973 #endif
02974                 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
02975 
02976                 md->addSectionsToDefinition(root->anchors);
02977 
02978                 md->enableCallGraph(md->hasCallGraph() || root->callGraph);
02979                 md->enableCallerGraph(md->hasCallerGraph() || root->callerGraph);
02980 
02981                 // merge ingroup specifiers
02982                 if (md->getGroupDef()==0 && root->groups->first()!=0)
02983                 {
02984                   addMemberToGroups(root,md);
02985                 }
02986                 else if (md->getGroupDef()!=0 && root->groups->count()==0)
02987                 {
02988                   //printf("existing member is grouped, new member not\n");
02989                   root->groups->append(new Grouping(md->getGroupDef()->name(), md->getGroupPri()));
02990                 }
02991                 else if (md->getGroupDef()!=0 && root->groups->first()!=0)
02992                 {
02993                   //printf("both members are grouped\n");
02994                 }
02995               }
02996             }
02997           }
02998         }
02999         if (!found) /* global function is unique with respect to the file */
03000         {
03001           Debug::print(Debug::Functions,0,"  --> new function %s found!\n",rname.data());
03002           //printf("New function type=`%s' name=`%s' args=`%s' bodyLine=%d\n",
03003           //       root->type.data(),rname.data(),root->args.data(),root->bodyLine);
03004           
03005           // new global function
03006           ArgumentList *tArgList = root->tArgLists ? root->tArgLists->last() : 0;
03007           QCString name=removeRedundantWhiteSpace(rname);
03008           md=new MemberDef(
03009               root->fileName,root->startLine,
03010               root->type,name,root->args,root->exception,
03011               root->protection,root->virt,root->stat,FALSE,
03012               MemberDef::Function,tArgList,root->argList);
03013 
03014           md->setTagInfo(rootNav->tagInfo());
03015           //md->setDefFile(root->fileName);
03016           //md->setDefLine(root->startLine);
03017           md->setDocumentation(root->doc,root->docFile,root->docLine);
03018           md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
03019           md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
03020           md->setPrototype(root->proto);
03021           md->setDocsForDefinition(!root->proto);
03022           md->setTypeConstraints(root->typeConstr);
03023           //md->setBody(root->body);
03024           md->setBodySegment(root->bodyLine,root->endBodyLine);
03025           FileDef *fd=rootNav->fileDef();
03026           md->setBodyDef(fd);
03027           md->addSectionsToDefinition(root->anchors);
03028           md->setMemberSpecifiers(root->spec);
03029           md->setMemberGroupId(root->mGrpId);
03030 
03031           // see if the function is inside a namespace that was not part of
03032           // the name already (in that case nd should be non-zero already)
03033           if (nd==0 && rootNav->parent()->section() == Entry::NAMESPACE_SEC )
03034           {
03035             QCString nscope=removeAnonymousScopes(rootNav->parent()->name());
03036             if (!nscope.isEmpty())
03037             {
03038               nd = getResolvedNamespace(nscope);
03039             }
03040           }
03041 
03042           if (!scope.isEmpty())
03043           {
03044             if (Config_getBool("OPTIMIZE_OUTPUT_JAVA"))
03045             {
03046               scope = substitute(scope,"::",".")+".";
03047             }
03048             else
03049             {
03050               scope+="::";
03051             }
03052           }
03053 
03054           QCString def;
03055           if (!root->type.isEmpty())
03056           {
03057             if (root->argList)
03058             {
03059               def=root->type+" "+scope+name;
03060             }
03061             else
03062             {
03063               def=root->type+" "+scope+name+root->args;
03064             }
03065           }
03066           else
03067           {
03068             if (root->argList)
03069             {
03070               def=scope+name.copy();
03071             }
03072             else
03073             {
03074               def=scope+name+root->args;
03075             }
03076           }
03077           Debug::print(Debug::Functions,0,
03078                      "  Global Function:\n"
03079                      "    `%s' `%s'::`%s' `%s' proto=%d\n"
03080                      "    def=`%s'\n",
03081                      root->type.data(),
03082                      rootNav->parent()->name().data(),
03083                      rname.data(),
03084                      root->args.data(),
03085                      root->proto,
03086                      def.data()
03087                     );
03088           md->setDefinition(def);
03089           md->enableCallGraph(root->callGraph);
03090           md->enableCallerGraph(root->callerGraph);
03091           //if (root->mGrpId!=-1) 
03092           //{
03093           //  md->setMemberGroup(memberGroupDict[root->mGrpId]);
03094           //}
03095 
03096           md->setRefItems(root->sli);
03097           if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@')
03098           {
03099             // add member to namespace
03100             md->setNamespace(nd);
03101             nd->insertMember(md); 
03102           }
03103           if (fd)
03104           {
03105             // add member to the file (we do this even if we have already
03106             // inserted it into the namespace)
03107             md->setFileDef(fd); 
03108             fd->insertMember(md);
03109           }
03110 
03111           // add member to the list of file members
03112           //printf("Adding member=%s\n",md->name().data());
03113           MemberName *mn;
03114           if ((mn=Doxygen::functionNameSDict->find(name)))
03115           {
03116             mn->append(md);
03117           }
03118           else 
03119           {
03120             mn = new MemberName(name);
03121             mn->append(md);
03122             Doxygen::functionNameSDict->append(name,mn);
03123           }
03124           addMemberToGroups(root,md);
03125           if (!root->relatesDup) // if this is a relatesalso command, allow find
03126                                  // Member to pick it up
03127           {
03128             rootNav->changeSection(Entry::EMPTY_SEC); // Otherwise we have finished 
03129                                                       // with this entry.
03130 
03131           }
03132         }
03133         else
03134         {
03135           FileDef *fd=rootNav->fileDef();
03136           if (fd)
03137           {
03138             // add member to the file (we do this even if we have already
03139             // inserted it into the namespace)
03140             fd->insertMember(md);
03141           }
03142         }
03143 
03144         //printf("unrelated function %d `%s' `%s' `%s'\n",
03145         //    root->parent->section,root->type.data(),rname.data(),root->args.data());
03146       }
03147       else
03148       {
03149           Debug::print(Debug::Functions,0,"  --> %s not processed!\n",rname.data());
03150       }
03151     }
03152     else if (rname.isEmpty())
03153     {
03154         warn(root->fileName,root->startLine,
03155              "Warning: Illegal member name found."
03156             );
03157     }
03158 
03159     rootNav->releaseEntry();
03160   }
03161   RECURSE_ENTRYTREE(buildFunctionList,rootNav);
03162 }
03163 
03164 //----------------------------------------------------------------------
03165 
03166 static void findFriends()
03167 {
03168   //printf("findFriends()\n");
03169   MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict);
03170   MemberName *fn;
03171   for (;(fn=fnli.current());++fnli) // for each global function name
03172   {
03173     //printf("Function name=`%s'\n",fn->memberName());
03174     MemberName *mn;
03175     if ((mn=Doxygen::memberNameSDict->find(fn->memberName())))
03176     { // there are members with the same name
03177       //printf("Function name is also a member name\n");
03178       MemberNameIterator fni(*fn);
03179       MemberDef *fmd;
03180       for (;(fmd=fni.current());++fni) // for each function with that name
03181       {
03182         MemberNameIterator mni(*mn);
03183         MemberDef *mmd;
03184         for (;(mmd=mni.current());++mni) // for each member with that name
03185         {
03186           //printf("Checking for matching arguments 
03187           //        mmd->isRelated()=%d mmd->isFriend()=%d mmd->isFunction()=%d\n",
03188           //    mmd->isRelated(),mmd->isFriend(),mmd->isFunction());
03189           LockingPtr<ArgumentList> mmdAl = mmd->argumentList();
03190           LockingPtr<ArgumentList> fmdAl = fmd->argumentList();
03191           if ((mmd->isFriend() || (mmd->isRelated() && mmd->isFunction())) &&
03192               matchArguments2(mmd->getOuterScope(), mmd->getFileDef(), mmdAl.pointer(),
03193                               fmd->getOuterScope(), fmd->getFileDef(), fmdAl.pointer(),
03194                               TRUE
03195                              )
03196                              
03197              ) // if the member is related and the arguments match then the 
03198                // function is actually a friend.
03199           {
03200             mergeArguments(mmdAl.pointer(),fmdAl.pointer());
03201             if (!fmd->documentation().isEmpty())
03202             {
03203               mmd->setDocumentation(fmd->documentation(),fmd->docFile(),fmd->docLine());
03204             }
03205             else if (!mmd->documentation().isEmpty())
03206             {
03207               fmd->setDocumentation(mmd->documentation(),mmd->docFile(),mmd->docLine());
03208             }
03209             if (mmd->briefDescription().isEmpty() && !fmd->briefDescription().isEmpty())
03210             {
03211               mmd->setBriefDescription(fmd->briefDescription(),fmd->briefFile(),fmd->briefLine());
03212             }
03213             else if (!mmd->briefDescription().isEmpty() && !fmd->briefDescription().isEmpty())
03214             {
03215               fmd->setBriefDescription(mmd->briefDescription(),mmd->briefFile(),mmd->briefLine());
03216             }
03217             if (!fmd->inbodyDocumentation().isEmpty())
03218             {
03219               mmd->setInbodyDocumentation(fmd->inbodyDocumentation(),fmd->inbodyFile(),fmd->inbodyLine());
03220             }
03221             else if (!mmd->inbodyDocumentation().isEmpty())
03222             {
03223               fmd->setInbodyDocumentation(mmd->inbodyDocumentation(),mmd->inbodyFile(),mmd->inbodyLine());
03224             }
03225             //printf("body mmd %d fmd %d\n",mmd->getStartBodyLine(),fmd->getStartBodyLine());
03226             if (mmd->getStartBodyLine()==-1 && fmd->getStartBodyLine()!=-1)
03227             {
03228               mmd->setBodySegment(fmd->getStartBodyLine(),fmd->getEndBodyLine());
03229               mmd->setBodyDef(fmd->getBodyDef());
03230               //mmd->setBodyMember(fmd);
03231             }
03232             else if (mmd->getStartBodyLine()!=-1 && fmd->getStartBodyLine()==-1)
03233             {
03234               fmd->setBodySegment(mmd->getStartBodyLine(),mmd->getEndBodyLine());
03235               fmd->setBodyDef(mmd->getBodyDef());
03236               //fmd->setBodyMember(mmd);
03237             }
03238             mmd->setDocsForDefinition(fmd->isDocsForDefinition());
03239 
03240             mmd->enableCallGraph(mmd->hasCallGraph() || fmd->hasCallGraph());
03241             mmd->enableCallerGraph(mmd->hasCallerGraph() || fmd->hasCallerGraph());
03242             fmd->enableCallGraph(mmd->hasCallGraph() || fmd->hasCallGraph());
03243             fmd->enableCallerGraph(mmd->hasCallerGraph() || fmd->hasCallerGraph());
03244           }
03245         }
03246       }
03247     }
03248   }
03249 }
03250 
03251 //----------------------------------------------------------------------
03252 
03253 static void transferArgumentDocumentation(ArgumentList *decAl,ArgumentList *defAl)
03254 {
03255   if (decAl && defAl)
03256   {
03257     ArgumentListIterator decAli(*decAl);
03258     ArgumentListIterator defAli(*defAl);
03259     Argument *decA,*defA;
03260     for (decAli.toFirst(),defAli.toFirst();
03261         (decA=decAli.current()) && (defA=defAli.current());
03262         ++decAli,++defAli)
03263     {
03264       //printf("Argument decA->name=%s (doc=%s) defA->name=%s (doc=%s)\n",
03265       //    decA->name.data(),decA->docs.data(),
03266       //    defA->name.data(),defA->docs.data()
03267       //      );
03268       if (decA->docs.isEmpty() && !defA->docs.isEmpty())
03269       {
03270         decA->docs = defA->docs.copy();
03271       }
03272       else if (defA->docs.isEmpty() && !decA->docs.isEmpty())
03273       {
03274         defA->docs = decA->docs.copy();
03275       }
03276     }
03277   }
03278 }
03279 
03280 static void transferFunctionDocumentation()
03281 {
03282   //printf("transferFunctionDocumentation()\n");
03283 
03284   // find matching function declaration and definitions.
03285   MemberNameSDict::Iterator mnli(*Doxygen::functionNameSDict);
03286   MemberName *mn;
03287   for (;(mn=mnli.current());++mnli)
03288   {
03289     //printf("memberName=%s count=%d\n",mn->memberName(),mn->count());
03290     MemberDef *mdef=0,*mdec=0;
03291     MemberNameIterator mni1(*mn);
03292     /* find a matching function declaration and definition for this function */
03293     for (;(mdec=mni1.current());++mni1)
03294     {
03295       if (mdec->isPrototype() ||
03296           (mdec->isVariable() && mdec->isExternal()) 
03297          )
03298       {
03299         MemberNameIterator mni2(*mn);
03300         for (;(mdef=mni2.current());++mni2)
03301         {
03302           if (
03303               (mdef->isFunction() && !mdef->isStatic() && !mdef->isPrototype()) ||
03304               (mdef->isVariable() && !mdef->isExternal() && !mdef->isStatic())
03305              )
03306           {
03307             //printf("mdef=(%p,%s) mdec=(%p,%s)\n",
03308             //    mdef, mdef ? mdef->name().data() : "",
03309             //    mdec, mdec ? mdec->name().data() : "");
03310 
03311             LockingPtr<ArgumentList> mdefAl = mdef->argumentList();
03312             LockingPtr<ArgumentList> mdecAl = mdec->argumentList();
03313             if (matchArguments2(mdef->getOuterScope(),mdef->getFileDef(),mdefAl.pointer(),
03314                                 mdec->getOuterScope(),mdec->getFileDef(),mdecAl.pointer(),
03315                                 TRUE
03316                                )
03317                ) /* match found */
03318             {
03319               //printf("Found member %s: definition in %s (doc=`%s') and declaration in %s (doc=`%s')\n",
03320               //    mn->memberName(),
03321               //    mdef->getFileDef()->name().data(),mdef->documentation().data(),
03322               //    mdec->getFileDef()->name().data(),mdec->documentation().data()
03323               //    );
03324 
03325               // first merge argument documentation
03326               transferArgumentDocumentation(mdecAl.pointer(),mdefAl.pointer());
03327 
03328               /* copy documentation between function definition and declaration */
03329               if (!mdec->briefDescription().isEmpty())
03330               {
03331                 mdef->setBriefDescription(mdec->briefDescription(),mdec->briefFile(),mdec->briefLine());
03332               }
03333               else if (!mdef->briefDescription().isEmpty())
03334               {
03335                 mdec->setBriefDescription(mdef->briefDescription(),mdef->briefFile(),mdef->briefLine());
03336               }
03337               if (!mdef->documentation().isEmpty())
03338               {
03339                 //printf("transfering docs mdef->mdec (%s->%s)\n",mdef->argsString(),mdec->argsString());
03340                 mdec->setDocumentation(mdef->documentation(),mdef->docFile(),mdef->docLine());
03341                 mdec->setDocsForDefinition(mdef->isDocsForDefinition());
03342                 if (mdefAl!=0)
03343                 {
03344                   ArgumentList *mdefAlComb = new ArgumentList;
03345                   stringToArgumentList(mdef->argsString(),mdefAlComb);
03346                   transferArgumentDocumentation(mdefAl.pointer(),mdefAlComb);
03347                   mdec->setArgumentList(mdefAlComb);
03348                 }
03349               }
03350               else if (!mdec->documentation().isEmpty())
03351               {
03352                 //printf("transfering docs mdec->mdef (%s->%s)\n",mdec->argsString(),mdef->argsString());
03353                 mdef->setDocumentation(mdec->documentation(),mdec->docFile(),mdec->docLine());
03354                 mdef->setDocsForDefinition(mdec->isDocsForDefinition());
03355                 if (mdecAl!=0)
03356                 {
03357                   ArgumentList *mdecAlComb = new ArgumentList;
03358                   stringToArgumentList(mdec->argsString(),mdecAlComb);
03359                   transferArgumentDocumentation(mdecAl.pointer(),mdecAlComb);
03360                   mdef->setDeclArgumentList(mdecAlComb);
03361                 }
03362               }
03363               if (!mdef->inbodyDocumentation().isEmpty())
03364               {
03365                 mdec->setInbodyDocumentation(mdef->inbodyDocumentation(),mdef->inbodyFile(),mdef->inbodyLine());
03366               }
03367               else if (!mdec->inbodyDocumentation().isEmpty())
03368               {
03369                 mdef->setInbodyDocumentation(mdec->inbodyDocumentation(),mdec->inbodyFile(),mdec->inbodyLine());
03370               }
03371               if (mdec->getStartBodyLine()!=-1 && mdef->getStartBodyLine()==-1)
03372               {
03373                 //printf("body mdec->mdef %d-%d\n",mdec->getStartBodyLine(),mdef->getEndBodyLine());
03374                 mdef->setBodySegment(mdec->getStartBodyLine(),mdec->getEndBodyLine());
03375                 mdef->setBodyDef(mdec->getBodyDef());
03376                 //mdef->setBodyMember(mdec);
03377               }
03378               else if (mdef->getStartBodyLine()!=-1 && mdec->getStartBodyLine()==-1)
03379               {
03380                 //printf("body mdef->mdec %d-%d\n",mdef->getStartBodyLine(),mdec->getEndBodyLine());
03381                 mdec->setBodySegment(mdef->getStartBodyLine(),mdef->getEndBodyLine());
03382                 mdec->setBodyDef(mdef->getBodyDef());
03383                 //mdec->setBodyMember(mdef);
03384               }
03385               mdec->mergeMemberSpecifiers(mdef->getMemberSpecifiers());
03386               mdef->mergeMemberSpecifiers(mdec->getMemberSpecifiers());
03387 
03388 
03389               // copy group info.
03390               if (mdec->getGroupDef()==0 && mdef->getGroupDef()!=0)
03391               {
03392                 mdec->setGroupDef(mdef->getGroupDef(),
03393                                   mdef->getGroupPri(),
03394                                   mdef->docFile(),
03395                                   mdef->docLine(),
03396                                   mdef->hasDocumentation(),
03397                                   mdef
03398                                  );
03399               }
03400               else if (mdef->getGroupDef()==0 && mdec->getGroupDef()!=0)
03401               {
03402                 mdef->setGroupDef(mdec->getGroupDef(),
03403                                   mdec->getGroupPri(),
03404                                   mdec->docFile(),
03405                                   mdec->docLine(),
03406                                   mdec->hasDocumentation(),
03407                                   mdec
03408                                  );
03409               }
03410 
03411 
03412               mdec->mergeRefItems(mdef);
03413               mdef->mergeRefItems(mdec);
03414 
03415               mdef->setMemberDeclaration(mdec);
03416               mdec->setMemberDefinition(mdef);
03417 
03418               mdef->enableCallGraph(mdec->hasCallGraph() || mdef->hasCallGraph());
03419               mdef->enableCallerGraph(mdec->hasCallerGraph() || mdef->hasCallerGraph());
03420               mdec->enableCallGraph(mdec->hasCallGraph() || mdef->hasCallGraph());
03421               mdec->enableCallerGraph(mdec->hasCallerGraph() || mdef->hasCallerGraph());
03422             }
03423           }
03424         }
03425       }
03426     }
03427   }
03428 }
03429 
03430 //----------------------------------------------------------------------
03431 
03432 static void transferFunctionReferences()
03433 {
03434   MemberNameSDict::Iterator mnli(*Doxygen::functionNameSDict);
03435   MemberName *mn;
03436   for (;(mn=mnli.current());++mnli)
03437   {
03438     MemberDef *md,*mdef=0,*mdec=0;
03439     MemberNameIterator mni(*mn);
03440     /* find a matching function declaration and definition for this function */
03441     for (;(md=mni.current());++mni)
03442     {
03443       if (md->isPrototype()) 
03444         mdec=md;
03445       else if (md->isVariable() && md->isExternal()) 
03446         mdec=md;
03447       
03448       if (md->isFunction() && !md->isStatic() && !md->isPrototype()) 
03449         mdef=md;
03450       else if (md->isVariable() && !md->isExternal() && !md->isStatic())
03451         mdef=md;
03452     }
03453     if (mdef && mdec)
03454     {
03455       LockingPtr<ArgumentList> mdefAl = mdef->argumentList();
03456       LockingPtr<ArgumentList> mdecAl = mdec->argumentList();
03457       if (
03458           matchArguments2(mdef->getOuterScope(),mdef->getFileDef(),mdefAl.pointer(),
03459                           mdec->getOuterScope(),mdec->getFileDef(),mdecAl.pointer(),
03460                           TRUE
03461             )
03462          ) /* match found */
03463       {
03464         LockingPtr<MemberSDict> defDict = mdef->getReferencesMembers();
03465         LockingPtr<MemberSDict> decDict = mdec->getReferencesMembers();
03466         if (defDict!=0)
03467         {
03468           MemberSDict::Iterator msdi(*defDict);
03469           MemberDef *rmd;
03470           for (msdi.toFirst();(rmd=msdi.current());++msdi)
03471           {
03472             if (decDict==0 || decDict->find(rmd->name())==0)
03473             {
03474               mdec->addSourceReferences(rmd);
03475             }
03476           }
03477         }
03478         if (decDict!=0)
03479         {
03480           MemberSDict::Iterator msdi(*decDict);
03481           MemberDef *rmd;
03482           for (msdi.toFirst();(rmd=msdi.current());++msdi)
03483           {
03484             if (defDict==0 || defDict->find(rmd->name())==0)
03485             {
03486               mdef->addSourceReferences(rmd);
03487             }
03488           }
03489         }
03490 
03491         defDict = mdef->getReferencedByMembers();
03492         decDict = mdec->getReferencedByMembers();
03493         if (defDict!=0)
03494         {
03495           MemberSDict::Iterator msdi(*defDict);
03496           MemberDef *rmd;
03497           for (msdi.toFirst();(rmd=msdi.current());++msdi)
03498           {
03499             if (decDict==0 || decDict->find(rmd->name())==0)
03500             {
03501               mdec->addSourceReferencedBy(rmd);
03502             }
03503           }
03504         }
03505         if (decDict!=0)
03506         {
03507           MemberSDict::Iterator msdi(*decDict);
03508           MemberDef *rmd;
03509           for (msdi.toFirst();(rmd=msdi.current());++msdi)
03510           {
03511             if (defDict==0 || defDict->find(rmd->name())==0)
03512             {
03513               mdef->addSourceReferencedBy(rmd);
03514             }
03515           }
03516         }
03517       }
03518     }
03519   }
03520 }
03521 
03522 //----------------------------------------------------------------------
03523 
03524 static void transferRelatedFunctionDocumentation()
03525 {
03526   // find match between function declaration and definition for 
03527   // related functions
03528   MemberNameSDict::Iterator mnli(*Doxygen::functionNameSDict);
03529   MemberName *mn;
03530   for (mnli.toFirst();(mn=mnli.current());++mnli)
03531   {
03532     MemberDef *md;
03533     MemberNameIterator mni(*mn);
03534     /* find a matching function declaration and definition for this function */
03535     for (mni.toFirst();(md=mni.current());++mni) // for each global function
03536     {
03537       //printf("  Function `%s'\n",md->name().data());
03538       MemberName *rmn;
03539       if ((rmn=Doxygen::memberNameSDict->find(md->name()))) // check if there is a member with the same name
03540       {
03541         //printf("  Member name found\n");
03542         MemberDef *rmd;
03543         MemberNameIterator rmni(*rmn);
03544         for (rmni.toFirst();(rmd=rmni.current());++rmni) // for each member with the same name
03545         {
03546           LockingPtr<ArgumentList>  mdAl = md->argumentList();
03547           LockingPtr<ArgumentList> rmdAl = rmd->argumentList();
03548           //printf("  Member found: related=`%d'\n",rmd->isRelated());
03549           if (rmd->isRelated() && // related function
03550               matchArguments2( md->getOuterScope(), md->getFileDef(), mdAl.pointer(),
03551                               rmd->getOuterScope(),rmd->getFileDef(),rmdAl.pointer(),
03552                               TRUE
03553                              )
03554              )
03555           {
03556             //printf("  Found related member `%s'\n",md->name().data());
03557             if (rmd->relatedAlso())
03558               md->setRelatedAlso(rmd->relatedAlso());
03559             else
03560               md->makeRelated();
03561           } 
03562         }
03563       } 
03564     }
03565   }
03566 }
03567 
03568 //----------------------------------------------------------------------
03569 
03575 static QDict<int> *getTemplateArgumentsInName(ArgumentList *templateArguments,const QCString &name)
03576 {
03577   QDict<int> *templateNames = new QDict<int>(17);
03578   templateNames->setAutoDelete(TRUE);
03579   static QRegExp re("[a-z_A-Z][a-z_A-Z0-9:]*");
03580   if (templateArguments)
03581   {
03582     ArgumentListIterator ali(*templateArguments);
03583     Argument *arg;
03584     int count=0;
03585     for (ali.toFirst();(arg=ali.current());++ali,count++)
03586     {
03587       int i,p=0,l;
03588       while ((i=re.match(name,p,&l))!=-1)
03589       {
03590         QCString n = name.mid(i,l);
03591         if (n==arg->name)
03592         {
03593           if (templateNames->find(n)==0)
03594           {
03595             templateNames->insert(n,new int(count));
03596           }
03597         }
03598         p=i+l;
03599       }
03600     }
03601   }
03602   return templateNames;
03603 }
03604 
03608 static ClassDef *findClassWithinClassContext(Definition *context,ClassDef *cd,const QCString &name)
03609 {
03610   FileDef *fd=cd->getFileDef();
03611   ClassDef *result=0;
03612   if (context && cd!=context)
03613   {
03614     result = getResolvedClass(context,0,name,0,0,TRUE,TRUE);
03615   }
03616   if (result==0)
03617   {
03618     result = getResolvedClass(cd,fd,name,0,0,TRUE,TRUE);
03619   }
03620   //printf("** Trying to find %s within context %s class %s result=%s lookup=%p\n",
03621   //       name.data(),
03622   //       context ? context->name().data() : "<none>",
03623   //       cd      ? cd->name().data()      : "<none>",
03624   //       result  ? result->name().data()  : "<none>",
03625   //       Doxygen::classSDict.find(name)
03626   //      );
03627   return result;
03628 }
03629 
03630 enum FindBaseClassRelation_Mode 
03631 { 
03632   TemplateInstances, 
03633   DocumentedOnly, 
03634   Undocumented 
03635 };
03636 
03637 static bool findClassRelation(
03638                            EntryNav *rootNav,
03639                            Definition *context,
03640                            ClassDef *cd,
03641                            BaseInfo *bi,
03642                            QDict<int> *templateNames,
03643                            /*bool insertUndocumented*/
03644                            FindBaseClassRelation_Mode mode,
03645                            bool isArtificial
03646                           );
03647 
03648 
03649 static void findUsedClassesForClass(EntryNav *rootNav,
03650                            Definition *context,
03651                            ClassDef *masterCd,
03652                            ClassDef *instanceCd,
03653                            bool isArtificial,
03654                            ArgumentList *actualArgs=0,
03655                            QDict<int> *templateNames=0
03656                            )
03657 {
03658   masterCd->visited=TRUE;
03659   ArgumentList *formalArgs = masterCd->templateArguments();
03660   if (masterCd->memberNameInfoSDict())
03661   {
03662     MemberNameInfoSDict::Iterator mnili(*masterCd->memberNameInfoSDict());
03663     MemberNameInfo *mni;
03664     for (;(mni=mnili.current());++mnili)
03665     {
03666       MemberNameInfoIterator mnii(*mni);
03667       MemberInfo *mi;
03668       for (mnii.toFirst();(mi=mnii.current());++mnii)
03669       {
03670         MemberDef *md=mi->memberDef;
03671         if (md->isVariable()) // for each member variable in this class
03672         {
03673           //printf("    Found variable %s in class %s\n",md->name().data(),masterCd->name().data());
03674           QCString type=removeRedundantWhiteSpace(md->typeString());
03675           QCString typedefValue = resolveTypeDef(masterCd,type);
03676           if (!typedefValue.isEmpty())
03677           {
03678             type = typedefValue;
03679           }
03680           int pos=0;
03681           QCString usedClassName;
03682           QCString templSpec;
03683           bool found=FALSE;
03684           // the type can contain template variables, replace them if present
03685           if (actualArgs)
03686           {
03687             type = substituteTemplateArgumentsInString(type,formalArgs,actualArgs);
03688           }
03689 
03690           //printf("      template substitution gives=%s\n",type.data());
03691           while (!found && extractClassNameFromType(type,pos,usedClassName,templSpec)!=-1)
03692           {
03693             // find the type (if any) that matches usedClassName
03694             ClassDef *typeCd = getResolvedClass(masterCd,
03695                 masterCd->getFileDef(),
03696                 usedClassName,
03697                 0,0,
03698                 FALSE,TRUE
03699                 );
03700             //printf("====>  usedClassName=%s -> typeCd=%s\n",
03701             //     usedClassName.data(),typeCd?typeCd->name().data():"<none>");
03702             if (typeCd)
03703             {
03704               usedClassName = typeCd->name();
03705             }
03706 
03707             int sp=usedClassName.find('<');
03708             if (sp==-1) sp=0;
03709             int si=usedClassName.findRev("::",sp);
03710             if (si!=-1)
03711             {
03712               // replace any namespace aliases
03713               replaceNamespaceAliases(usedClassName,si);
03714             }
03715             // add any template arguments to the class
03716             QCString usedName = removeRedundantWhiteSpace(usedClassName+templSpec);
03717             //printf("    usedName=%s\n",usedName.data());
03718 
03719             bool delTempNames=FALSE;
03720             if (templateNames==0)
03721             {
03722               templateNames = getTemplateArgumentsInName(formalArgs,usedName);
03723               delTempNames=TRUE;
03724             }
03725             BaseInfo bi(usedName,Public,Normal);
03726             findClassRelation(rootNav,context,instanceCd,&bi,templateNames,TemplateInstances,isArtificial);
03727 
03728             if (masterCd->templateArguments())
03729             {
03730               ArgumentListIterator ali(*masterCd->templateArguments());
03731               Argument *arg;
03732               int count=0;
03733               for (ali.toFirst();(arg=ali.current());++ali,++count)
03734               {
03735                 if (arg->name==usedName) // type is a template argument
03736                 {
03737                   found=TRUE;
03738                   Debug::print(Debug::Classes,0,"    New used class `%s'\n", usedName.data());
03739 
03740                   ClassDef *usedCd = Doxygen::hiddenClasses->find(usedName);
03741                   if (usedCd==0)
03742                   {
03743                     usedCd = new ClassDef(
03744                         masterCd->getDefFileName(),masterCd->getDefLine(),
03745                         usedName,ClassDef::Class);
03746                     //printf("making %s a template argument!!!\n",usedCd->name().data());
03747                     usedCd->makeTemplateArgument();
03748                     usedCd->setUsedOnly(TRUE);
03749                     Doxygen::hiddenClasses->append(usedName,usedCd);
03750                   }
03751                   if (usedCd)
03752                   {
03753                     if (isArtificial) usedCd->setArtificial(TRUE);
03754                     Debug::print(Debug::Classes,0,"      Adding used class `%s' (1)\n", usedCd->name().data());
03755                     instanceCd->addUsedClass(usedCd,md->name());
03756                     usedCd->addUsedByClass(instanceCd,md->name());
03757                   }
03758                 }
03759               }
03760             }
03761 
03762             if (!found)
03763             {
03764               ClassDef *usedCd=findClassWithinClassContext(context,masterCd,usedName);
03765               //printf("Looking for used class %s: result=%s master=%s\n",
03766               //    usedName.data(),usedCd?usedCd->name().data():"<none>",masterCd?masterCd->name().data():"<none>");
03767 
03768               if (usedCd) 
03769               {
03770                 found=TRUE;
03771                 Debug::print(Debug::Classes,0,"    Adding used class `%s' (2)\n", usedCd->name().data());
03772                 instanceCd->addUsedClass(usedCd,md->name()); // class exists 
03773                 usedCd->addUsedByClass(instanceCd,md->name());
03774               }
03775             }
03776             if (delTempNames)
03777             {
03778               delete templateNames;
03779               templateNames=0;
03780             }
03781           }
03782           if (!found && !type.isEmpty()) // used class is not documented in any scope
03783           {
03784             ClassDef *usedCd = Doxygen::hiddenClasses->find(type);
03785             if (usedCd==0 && !Config_getBool("HIDE_UNDOC_RELATIONS"))
03786             {
03787               if (type.right(2)=="(*") // type is a function pointer
03788               {
03789                 type+=md->argsString();
03790               }
03791               Debug::print(Debug::Classes,0,"  New undocumented used class `%s'\n", type.data());
03792               usedCd = new ClassDef(
03793                   masterCd->getDefFileName(),masterCd->getDefLine(),
03794                   type,ClassDef::Class);
03795               usedCd->setUsedOnly(TRUE);
03796               Doxygen::hiddenClasses->append(type,usedCd);
03797             }
03798             if (usedCd)
03799             {
03800               if (isArtificial) usedCd->setArtificial(TRUE);
03801               Debug::print(Debug::Classes,0,"    Adding used class `%s' (3)\n", usedCd->name().data());
03802               instanceCd->addUsedClass(usedCd,md->name()); 
03803               usedCd->addUsedByClass(instanceCd,md->name());
03804             }
03805           }
03806         }
03807       }
03808     }
03809   }
03810   else
03811   {
03812     //printf("no members for class %s (%p)\n",masterCd->name().data(),masterCd);
03813   }
03814 }
03815 
03816 static void findBaseClassesForClass(
03817       EntryNav *rootNav,
03818       Definition *context,
03819       ClassDef *masterCd,
03820       ClassDef *instanceCd,
03821       FindBaseClassRelation_Mode mode,
03822       bool isArtificial,
03823       ArgumentList *actualArgs=0,
03824       QDict<int> *templateNames=0
03825     )
03826 {
03827   Entry *root = rootNav->entry();
03828   //if (masterCd->visited) return;
03829   masterCd->visited=TRUE;
03830   // The base class could ofcouse also be a non-nested class
03831   ArgumentList *formalArgs = masterCd->templateArguments();
03832   QListIterator<BaseInfo> bii(*root->extends);
03833   BaseInfo *bi=0;
03834   for (bii.toFirst();(bi=bii.current());++bii)
03835   {
03836     //printf("masterCd=%s bi->name=%s #actualArgs=%d\n",
03837     //    masterCd->localName().data(),bi->name.data(),actualArgs?(int)actualArgs->count():-1);
03838     bool delTempNames=FALSE;
03839     if (templateNames==0)
03840     {
03841       templateNames = getTemplateArgumentsInName(formalArgs,bi->name);
03842       delTempNames=TRUE;
03843     }
03844     BaseInfo tbi(bi->name,bi->prot,bi->virt);
03845     if (actualArgs) // substitute the formal template arguments of the base class
03846     {
03847       tbi.name = substituteTemplateArgumentsInString(bi->name,formalArgs,actualArgs);
03848     }
03849     //printf("bi->name=%s tbi.name=%s\n",bi->name.data(),tbi.name.data());
03850 
03851     if (mode==DocumentedOnly)
03852     {
03853       // find a documented base class in the correct scope
03854       if (!findClassRelation(rootNav,context,instanceCd,&tbi,templateNames,DocumentedOnly,isArtificial))
03855       {
03856         if (!Config_getBool("HIDE_UNDOC_RELATIONS"))
03857         {
03858           // no documented base class -> try to find an undocumented one
03859           findClassRelation(rootNav,context,instanceCd,&tbi,templateNames,Undocumented,isArtificial);
03860         }
03861       }
03862     }
03863     else if (mode==TemplateInstances)
03864     {
03865       findClassRelation(rootNav,context,instanceCd,&tbi,templateNames,TemplateInstances,isArtificial);
03866     }
03867     if (delTempNames)
03868     {
03869       delete templateNames;
03870       templateNames=0;
03871     }  
03872   }
03873 }
03874 
03875 //----------------------------------------------------------------------
03876 
03877 static bool findTemplateInstanceRelation(Entry *root,
03878             Definition *context,
03879             ClassDef *templateClass,const QCString &templSpec,
03880             QDict<int> *templateNames,
03881             bool isArtificial)
03882 {
03883   Debug::print(Debug::Classes,0,"    derived from template %s with parameters %s\n",
03884          templateClass->name().data(),templSpec.data());
03885   //printf("findTemplateInstanceRelation(base=%s templSpec=%s templateNames=",
03886   //    templateClass->name().data(),templSpec.data());
03887   //if (templateNames)
03888   //{
03889   //  QDictIterator<int> qdi(*templateNames);
03890   //  int *tempArgIndex;
03891   //  for (;(tempArgIndex=qdi.current());++qdi)
03892   //  {
03893   //    printf("(%s->%d) ",qdi.currentKey().data(),*tempArgIndex);
03894   //  }
03895   //}
03896   //printf("\n");
03897   
03898   bool existingClass = (templSpec==tempArgListToString(templateClass->templateArguments()));
03899   if (existingClass) return TRUE;
03900 
03901   bool freshInstance=FALSE;
03902   ClassDef *instanceClass = templateClass->insertTemplateInstance(
03903                      root->fileName,root->startLine,templSpec,freshInstance);
03904   if (isArtificial) instanceClass->setArtificial(TRUE);
03905   instanceClass->setIsObjectiveC(root->objc);
03906 
03907   if (freshInstance)
03908   {
03909     Debug::print(Debug::Classes,0,"      found fresh instance '%s'!\n",instanceClass->name().data());
03910     Doxygen::classSDict->append(instanceClass->name(),instanceClass);
03911     instanceClass->setTemplateBaseClassNames(templateNames);
03912 
03913     // search for new template instances caused by base classes of 
03914     // instanceClass 
03915     EntryNav *templateRootNav = classEntries.find(templateClass->name());
03916     if (templateRootNav)
03917     {
03918       bool unloadNeeded=FALSE;
03919       Entry *templateRoot = templateRootNav->entry();
03920       if (templateRoot==0) // not yet loaded
03921       {
03922         templateRootNav->loadEntry(g_storage);
03923         templateRoot = templateRootNav->entry();
03924         ASSERT(templateRoot!=0); // now it should really be loaded
03925         unloadNeeded=TRUE;
03926       }
03927 
03928       Debug::print(Debug::Classes,0,"        template root found %s templSpec=%s!\n",
03929           templateRoot->name.data(),templSpec.data());
03930       ArgumentList *templArgs = new ArgumentList;
03931       stringToArgumentList(templSpec,templArgs);
03932       findBaseClassesForClass(templateRootNav,context,templateClass,instanceClass,
03933           TemplateInstances,isArtificial,templArgs,templateNames);
03934 
03935       findUsedClassesForClass(templateRootNav,context,templateClass,instanceClass,
03936           isArtificial,templArgs,templateNames);
03937       delete templArgs;
03938 
03939       if (unloadNeeded) // still cleanup to do
03940       {
03941         templateRootNav->releaseEntry();
03942       }
03943     }
03944     else
03945     {
03946       Debug::print(Debug::Classes,0,"        no template root entry found!\n");
03947       // TODO: what happened if we get here?
03948     }
03949 
03950     //Debug::print(Debug::Classes,0,"    Template instance %s : \n",instanceClass->name().data());
03951     //ArgumentList *tl = templateClass->templateArguments();
03952   }
03953   else
03954   {
03955     Debug::print(Debug::Classes,0,"      instance already exists!\n");
03956   }
03957   return TRUE;
03958 }
03959 
03960 static bool isRecursiveBaseClass(const QCString &scope,const QCString &name)
03961 {
03962   QCString n=name;
03963   int index=n.find('<');
03964   if (index!=-1)
03965   {
03966     n=n.left(index);
03967   }
03968   bool result = rightScopeMatch(scope,n);
03969   return result;
03970 }
03971 
03985 static int findEndOfTemplate(const QCString &s,int startPos)
03986 {
03987   // locate end of template
03988   int e=startPos;
03989   int brCount=1;
03990   int roundCount=0;
03991   int len = s.length();
03992   bool insideString=FALSE;
03993   bool insideChar=FALSE;
03994   char pc = 0;
03995   while (e<len && brCount!=0)
03996   {
03997     char c=s.at(e);
03998     switch(c)
03999     {
04000       case '<': 
04001         if (!insideString && !insideChar)
04002         {
04003           if (e<len-1 && s.at(e+1)=='<') 
04004             e++; 
04005           else if (roundCount==0)
04006             brCount++;
04007         }
04008         break;
04009       case '>':
04010         if (!insideString && !insideChar)
04011         {
04012           if (e<len-1 && s.at(e+1)=='>') 
04013             e++; 
04014           else if (roundCount==0)
04015             brCount--;
04016         }
04017         break;
04018       case '(':
04019         if (!insideString && !insideChar) 
04020           roundCount++;
04021         break;
04022       case ')':
04023         if (!insideString && !insideChar) 
04024           roundCount--;
04025         break;
04026       case '"':
04027         if (!insideChar)
04028         {
04029           if (insideString && pc!='\\') 
04030             insideString=FALSE;
04031           else
04032             insideString=TRUE;
04033         }
04034         break;
04035       case '\'':
04036         if (!insideString)
04037         {
04038           if (insideChar && pc!='\\')
04039             insideChar=FALSE;
04040           else
04041             insideChar=TRUE;
04042         }
04043         break;
04044     }
04045     pc = c;
04046     e++;
04047   }
04048   return brCount==0 ? e : -1;
04049 }
04050 
04051 static bool findClassRelation(
04052                            EntryNav *rootNav,
04053                            Definition *context,
04054                            ClassDef *cd,
04055                            BaseInfo *bi,
04056                            QDict<int> *templateNames,
04057                            FindBaseClassRelation_Mode mode,
04058                            bool isArtificial
04059                           )
04060 {
04061   //printf("findClassRelation(class=%s base=%s templateNames=",
04062   //    cd->name().data(),bi->name.data());
04063   //if (templateNames)
04064   //{
04065   //  QDictIterator<int> qdi(*templateNames);
04066   //  int *tempArgIndex;
04067   //  for (;(tempArgIndex=qdi.current());++qdi)
04068   //  {
04069   //    printf("(%s->%d) ",qdi.currentKey(),*tempArgIndex);
04070   //  }
04071   //}
04072   //printf("\n");
04073 
04074   Entry *root = rootNav->entry();
04075 
04076   QCString biName=bi->name;
04077   bool explicitGlobalScope=FALSE;
04078   if (biName.left(2)=="::") // explicit global scope
04079   {
04080      biName=biName.right(biName.length()-2);
04081      explicitGlobalScope=TRUE;
04082   }
04083   //printf("biName=`%s'\n",biName.data());
04084 
04085   EntryNav *parentNode=rootNav->parent();
04086   bool lastParent=FALSE;
04087   do // for each parent scope, starting with the largest scope 
04088      // (in case of nested classes)
04089   {
04090     QCString scopeName= parentNode ? parentNode->name().data() : "";
04091     int scopeOffset=explicitGlobalScope ? 0 : scopeName.length();
04092     do // try all parent scope prefixes, starting with the largest scope
04093     {
04094       //printf("scopePrefix=`%s' biName=`%s'\n",
04095       //    scopeName.left(scopeOffset).data(),biName.data());
04096 
04097       QCString baseClassName=biName;
04098       if (scopeOffset>0)
04099       {
04100         baseClassName.prepend(scopeName.left(scopeOffset)+"::");
04101       }
04102       baseClassName=stripTemplateSpecifiersFromScope
04103                           (removeRedundantWhiteSpace(baseClassName));
04104       MemberDef *baseClassTypeDef=0;
04105       QCString templSpec;
04106       ClassDef *baseClass=getResolvedClass(explicitGlobalScope ? 0 : cd,
04107                                            cd->getFileDef(), 
04108                                            baseClassName,
04109                                            &baseClassTypeDef,
04110                                            &templSpec,
04111                                            mode==Undocumented,
04112                                            TRUE
04113                                           );
04114       //printf("baseClassName=%s baseClass=%p cd=%p explicitGlobalScope=%d\n",
04115       //    baseClassName.data(),baseClass,cd,explicitGlobalScope);
04116       //printf("    scope=`%s' baseClassName=`%s' baseClass=%s templSpec=%s\n",
04117       //                    cd ? cd->name().data():"<none>",
04118       //                    baseClassName.data(),
04119       //                    baseClass?baseClass->name().data():"<none>",
04120       //                    templSpec.data()
04121       //      );
04122       //if (baseClassName.left(root->name.length())!=root->name ||
04123       //    baseClassName.at(root->name.length())!='<'
04124       //   ) // Check for base class with the same name.
04125       //     // If found then look in the outer scope for a match
04126       //     // and prevent recursion.
04127       if (!isRecursiveBaseClass(rootNav->name(),baseClassName) || explicitGlobalScope)
04128       {
04129         Debug::print(
04130             Debug::Classes,0,"    class relation %s inherited/used by %s found (%s and %s) templSpec='%s'\n",
04131             baseClassName.data(),
04132             rootNav->name().data(),
04133             (bi->prot==Private)?"private":((bi->prot==Protected)?"protected":"public"),
04134             (bi->virt==Normal)?"normal":"virtual",
04135             templSpec.data()
04136            );
04137 
04138         int i=baseClassName.find('<');
04139         int si=baseClassName.findRev("::",i==-1 ? baseClassName.length() : i);
04140         if (si==-1) si=0;
04141         if (baseClass==0 && i!=-1) 
04142           // base class has template specifiers
04143         {
04144           // TODO: here we should try to find the correct template specialization
04145           // but for now, we only look for the unspecializated base class.
04146           int e=findEndOfTemplate(baseClassName,i+1);
04147           if (e!=-1) // end of template was found at e
04148           {
04149             templSpec=baseClassName.mid(i,e-i);
04150             baseClassName=baseClassName.left(i)+baseClassName.right(baseClassName.length()-e);
04151             baseClass=getResolvedClass(cd,
04152                                        cd->getFileDef(),
04153                                        baseClassName,
04154                                        &baseClassTypeDef,
04155                                        0, //&templSpec,
04156                                        mode==Undocumented,
04157                                        TRUE
04158                                       );
04159             //printf("baseClass=%p -> baseClass=%s templSpec=%s\n",
04160             //      baseClass,baseClassName.data(),templSpec.data());
04161           }
04162         }
04163         else if (baseClass && !templSpec.isEmpty()) // we have a known class, but also
04164                                                     // know it is a template, so see if
04165                                                     // we can also link to the explicit
04166                                                     // instance (for instance if a class
04167                                                     // derived from a template argument)
04168         {
04169           ClassDef *templClass=getClass(baseClass->name()+templSpec);
04170           if (templClass)
04171           {
04172             // use the template instance instead of the template base.
04173             baseClass = templClass;
04174             templSpec.resize(0);
04175           }
04176         }
04177 
04178         //printf("cd=%p baseClass=%p\n",cd,baseClass);
04179         bool found=baseClass!=0 && (baseClass!=cd || mode==TemplateInstances);
04180         if (!found && si!=-1)
04181         {
04182           QCString tmpTemplSpec;
04183           // replace any namespace aliases
04184           replaceNamespaceAliases(baseClassName,si);
04185           baseClass=getResolvedClass(cd,
04186                                      cd->getFileDef(),
04187                                      baseClassName,
04188                                      &baseClassTypeDef,
04189                                      &tmpTemplSpec,
04190                                      mode==Undocumented,
04191                                      TRUE
04192                                     );
04193           found=baseClass!=0 && baseClass!=cd;
04194           if (found) templSpec = tmpTemplSpec;
04195         }
04196         
04197         //printf("root->name=%s biName=%s baseClassName=%s\n",
04198         //        root->name.data(),biName.data(),baseClassName.data());
04199 
04200         //FileDef *fd=cd->getFileDef();
04201         //NamespaceDef *nd=cd->getNamespaceDef();
04202         if (!found)
04203         {
04204           baseClass=findClassWithinClassContext(context,cd,baseClassName);
04205           //printf("findClassWithinClassContext(%s,%s)=%p\n",
04206           //    cd->name().data(),baseClassName.data(),baseClass);
04207           found = baseClass!=0 && baseClass!=cd;
04208 
04209         }
04210         bool isATemplateArgument = templateNames!=0 && templateNames->find(biName)!=0;
04211         // make templSpec canonical
04212         templSpec = getCanonicalTemplateSpec(cd, cd->getFileDef(), templSpec);
04213 
04214         if (found)
04215         {
04216           Debug::print(Debug::Classes,0,"    Documented base class `%s' templSpec=%s\n",biName.data(),templSpec.isEmpty()?"":templSpec.data());
04217           // add base class to this class
04218 
04219           // if templSpec is not empty then we should "instantiate"
04220           // the template baseClass. A new ClassDef should be created
04221           // to represent the instance. To be able to add the (instantiated)
04222           // members and documentation of a template class 
04223           // (inserted in that template class at a later stage), 
04224           // the template should know about its instances. 
04225           // the instantiation process, should be done in a recursive way, 
04226           // since instantiating a template may introduce new inheritance 
04227           // relations.
04228           if (!templSpec.isEmpty() && mode==TemplateInstances)
04229           {
04230             //printf("       => findTemplateInstanceRelation\n");
04231             findTemplateInstanceRelation(root,context,baseClass,templSpec,templateNames,isArtificial);
04232           }
04233           else if (mode==DocumentedOnly || mode==Undocumented)
04234           {
04235             //printf("       => insert base class\n");
04236             QCString usedName;
04237             if (baseClassTypeDef) 
04238             {
04239               usedName=biName;
04240               //printf("***** usedName=%s templSpec=%s\n",usedName.data(),templSpec.data());
04241             }
04242             if (Config_getBool("SIP_SUPPORT")) bi->prot=Public;
04243             cd->insertBaseClass(baseClass,usedName,bi->prot,bi->virt,templSpec);
04244             // add this class as super class to the base class
04245             baseClass->insertSubClass(cd,bi->prot,bi->virt,templSpec);
04246           }
04247           return TRUE;
04248         }
04249         else if (mode==Undocumented && (scopeOffset==0 || isATemplateArgument))
04250         {
04251           Debug::print(Debug::Classes,0,
04252                        "    New undocumented base class `%s' baseClassName=%s\n",
04253                        biName.data(),baseClassName.data()
04254                       );
04255           baseClass=0;
04256           if (isATemplateArgument)
04257           {
04258             baseClass=Doxygen::hiddenClasses->find(baseClassName);
04259             if (baseClass==0)
04260             {
04261               baseClass=new ClassDef(root->fileName,root->startLine,
04262                                  baseClassName,ClassDef::Class);
04263               Doxygen::hiddenClasses->append(baseClassName,baseClass);
04264               if (isArtificial) baseClass->setArtificial(TRUE);
04265             }
04266           }
04267           else
04268           {
04269             baseClass=Doxygen::classSDict->find(baseClassName);
04270             //printf("*** classDDict->find(%s)=%p biName=%s templSpec=%s\n",
04271             //    baseClassName.data(),baseClass,biName.data(),templSpec.data());
04272             if (baseClass==0)
04273             {
04274               baseClass=new ClassDef(root->fileName,root->startLine,
04275                   baseClassName,ClassDef::Class);
04276               Doxygen::classSDict->append(baseClassName,baseClass);
04277               if (isArtificial) baseClass->setArtificial(TRUE);
04278             }
04279           }
04280           // add base class to this class
04281           cd->insertBaseClass(baseClass,biName,bi->prot,bi->virt,templSpec);
04282           // add this class as super class to the base class
04283           baseClass->insertSubClass(cd,bi->prot,bi->virt,templSpec);
04284           // the undocumented base was found in this file
04285           baseClass->insertUsedFile(root->fileName);
04286           baseClass->setOuterScope(Doxygen::globalScope);
04287           return TRUE;
04288         }
04289         else
04290         {
04291           Debug::print(Debug::Classes,0,"    Base class `%s' not found\n",biName.data());
04292         }
04293       }
04294       else
04295       {
04296         if (mode!=TemplateInstances)
04297         {
04298           warn(root->fileName,root->startLine,
04299               "Detected potential recursive class relation "
04300               "between class %s and base class %s!\n",
04301               root->name.data(),baseClassName.data()
04302               );
04303         }
04304         // for mode==TemplateInstance this case is quite common and
04305         // indicates a relation between a template class and a template 
04306         // instance with the same name.
04307       }
04308       if (scopeOffset==0)
04309       {
04310         scopeOffset=-1;
04311       }
04312       else if ((scopeOffset=scopeName.findRev("::",scopeOffset-1))==-1)
04313       {
04314         scopeOffset=0;
04315       }
04316       //printf("new scopeOffset=`%d'",scopeOffset);
04317     } while (scopeOffset>=0);
04318 
04319     if (parentNode==0)
04320     {
04321       lastParent=TRUE;
04322     }
04323     else
04324     {
04325       parentNode=parentNode->parent();
04326     }
04327   } while (lastParent);
04328 
04329   return FALSE;
04330 }
04331 
04332 //----------------------------------------------------------------------
04333 // Computes the base and super classes for each class in the tree
04334 
04335 static bool isClassSection(EntryNav *rootNav)
04336 {
04337   if ( !rootNav->name().isEmpty() )
04338   {
04339     if (rootNav->section() & Entry::COMPOUND_MASK)
04340          // is it a compound (class, struct, union, interface ...)
04341     {
04342       return TRUE;
04343     }
04344     else if (rootNav->section() & Entry::COMPOUNDDOC_MASK) 
04345          // is it a documentation block with inheritance info.
04346     {
04347       rootNav->loadEntry(g_storage);
04348       Entry *root = rootNav->entry();
04349       bool extends = root->extends->count()>0;
04350       rootNav->releaseEntry(); 
04351       if (extends) return TRUE;
04352     }
04353   }
04354   return FALSE;
04355 }
04356 
04357 
04360 static void findClassEntries(EntryNav *rootNav)
04361 {
04362   if (isClassSection(rootNav))
04363   {
04364     classEntries.insert(rootNav->name(),rootNav);
04365   }
04366   RECURSE_ENTRYTREE(findClassEntries,rootNav);
04367 }
04368 
04374 static void findInheritedTemplateInstances()
04375 {
04376   ClassSDict::Iterator cli(*Doxygen::classSDict);
04377   for (cli.toFirst();cli.current();++cli) cli.current()->visited=FALSE;
04378   QDictIterator<EntryNav> edi(classEntries);
04379   EntryNav *rootNav;
04380   for (;(rootNav=edi.current());++edi)
04381   {
04382     ClassDef *cd;
04383     // strip any annonymous scopes first 
04384     QCString bName=stripAnonymousNamespaceScope(rootNav->name());
04385     bName=stripTemplateSpecifiersFromScope(bName);
04386     Debug::print(Debug::Classes,0,"  Inheritance: Class %s : \n",bName.data());
04387     if ((cd=getClass(bName)))
04388     {
04389       rootNav->loadEntry(g_storage);
04390       //printf("Class %s %d\n",cd->name().data(),root->extends->count());
04391       findBaseClassesForClass(rootNav,cd,cd,cd,TemplateInstances,FALSE);
04392       rootNav->releaseEntry();
04393     }
04394   }
04395 }
04396 
04397 static void findUsedTemplateInstances()
04398 {
04399   ClassSDict::Iterator cli(*Doxygen::classSDict);
04400   for (cli.toFirst();cli.current();++cli) cli.current()->visited=FALSE;
04401   QDictIterator<EntryNav> edi(classEntries);
04402   EntryNav *rootNav;
04403   for (;(rootNav=edi.current());++edi)
04404   {
04405     ClassDef *cd;
04406     // strip any annonymous scopes first 
04407     QCString bName=stripAnonymousNamespaceScope(rootNav->name());
04408     bName=stripTemplateSpecifiersFromScope(bName);
04409     Debug::print(Debug::Classes,0,"  Usage: Class %s : \n",bName.data());
04410     if ((cd=getClass(bName)))
04411     {
04412       rootNav->loadEntry(g_storage);
04413       findUsedClassesForClass(rootNav,cd,cd,cd,TRUE);
04414       rootNav->releaseEntry();
04415     }
04416   }
04417 }
04418 
04419 static void computeClassRelations()
04420 {
04421   ClassSDict::Iterator cli(*Doxygen::classSDict);
04422   for (cli.toFirst();cli.current();++cli) cli.current()->visited=FALSE;
04423   QDictIterator<EntryNav> edi(classEntries);
04424   EntryNav *rootNav;
04425   for (;(rootNav=edi.current());++edi)
04426   {
04427     ClassDef *cd;
04428 
04429     rootNav->loadEntry(g_storage);
04430     Entry *root = rootNav->entry();
04431 
04432     // strip any annonymous scopes first 
04433     QCString bName=stripAnonymousNamespaceScope(rootNav->name());
04434     bName=stripTemplateSpecifiersFromScope(bName);
04435     Debug::print(Debug::Classes,0,"  Relations: Class %s : \n",bName.data());
04436     if ((cd=getClass(bName)))
04437     {
04438       findBaseClassesForClass(rootNav,cd,cd,cd,DocumentedOnly,FALSE);
04439     }
04440     if ((cd==0 || (!cd->hasDocumentation() && !cd->isReference())) && 
04441         bName.right(2)!="::")
04442     {
04443       if (!root->name.isEmpty() && root->name.find('@')==-1 && // normal name
04444           (guessSection(root->fileName)==Entry::HEADER_SEC || 
04445            Config_getBool("EXTRACT_LOCAL_CLASSES")) && // not defined in source file
04446           (root->protection!=Private || Config_getBool("EXTRACT_PRIVATE")) && // hidden by protection
04447           !Config_getBool("HIDE_UNDOC_CLASSES") // undocumented class are visible
04448          )
04449         warn_undoc(
04450                    root->fileName,root->startLine,
04451                    "Warning: Compound %s is not documented.",
04452                    root->name.data()
04453              );
04454     }
04455 
04456     rootNav->releaseEntry();
04457   }
04458 }
04459 
04460 static void computeTemplateClassRelations()
04461 {
04462   QDictIterator<EntryNav> edi(classEntries);
04463   EntryNav *rootNav;
04464   for (;(rootNav=edi.current());++edi)
04465   {
04466     rootNav->loadEntry(g_storage);
04467     Entry *root = rootNav->entry();
04468 
04469     QCString bName=stripAnonymousNamespaceScope(root->name);
04470     bName=stripTemplateSpecifiersFromScope(bName);
04471     ClassDef *cd=getClass(bName);
04472     // strip any annonymous scopes first 
04473     QDict<ClassDef> *templInstances = 0;
04474     if (cd && (templInstances=cd->getTemplateInstances()))
04475     {
04476       Debug::print(Debug::Classes,0,"  Template class %s : \n",cd->name().data());
04477       QDictIterator<ClassDef> tdi(*templInstances);
04478       ClassDef *tcd;
04479       for (tdi.toFirst();(tcd=tdi.current());++tdi) // for each template instance
04480       {
04481         Debug::print(Debug::Classes,0,"    Template instance %s : \n",tcd->name().data());
04482         QCString templSpec = tdi.currentKey();
04483         ArgumentList *templArgs = new ArgumentList;
04484         stringToArgumentList(templSpec,templArgs);
04485         QList<BaseInfo> *baseList=root->extends;
04486         BaseInfo *bi=baseList->first();
04487         while (bi) // for each base class of the template
04488         {
04489           // check if the base class is a template argument
04490           BaseInfo tbi(bi->name,bi->prot,bi->virt);
04491           ArgumentList *tl = cd->templateArguments();
04492           if (tl)
04493           {
04494             QDict<int> *baseClassNames = tcd->getTemplateBaseClassNames();
04495             QDict<int> *templateNames = getTemplateArgumentsInName(tl,bi->name);
04496             // for each template name that we inherit from we need to
04497             // substitute the formal with the actual arguments
04498             QDict<int> *actualTemplateNames = new QDict<int>(17);
04499             actualTemplateNames->setAutoDelete(TRUE);
04500             QDictIterator<int> qdi(*templateNames);
04501             for (qdi.toFirst();qdi.current();++qdi)
04502             {
04503               int templIndex = *qdi.current();
04504               Argument *actArg = 0;
04505               if (templIndex<(int)templArgs->count()) 
04506               {
04507                 actArg=templArgs->at(templIndex);
04508               }
04509               if (actArg!=0 &&
04510                   baseClassNames!=0 &&
04511                   baseClassNames->find(actArg->type)!=0 &&
04512                   actualTemplateNames->find(actArg->type)==0
04513                  )
04514               {
04515                 actualTemplateNames->insert(actArg->type,new int(templIndex));
04516               }
04517             }
04518             delete templateNames;
04519             
04520             tbi.name = substituteTemplateArgumentsInString(bi->name,tl,templArgs);
04521             // find a documented base class in the correct scope
04522             if (!findClassRelation(rootNav,cd,tcd,&tbi,actualTemplateNames,DocumentedOnly,FALSE))
04523             {
04524               // no documented base class -> try to find an undocumented one
04525               findClassRelation(rootNav,cd,tcd,&tbi,actualTemplateNames,Undocumented,FALSE);
04526             }
04527             delete actualTemplateNames;
04528           }
04529           bi=baseList->next();
04530         }
04531         delete templArgs;
04532       } // class has no base classes
04533     }
04534 
04535     rootNav->releaseEntry();
04536   }
04537 }
04538 
04539 //-----------------------------------------------------------------------
04540 // compute the references (anchors in HTML) for each function in the file
04541 
04542 static void computeMemberReferences()
04543 {
04544   ClassSDict::Iterator cli(*Doxygen::classSDict);
04545   ClassDef *cd=0;
04546   for (cli.toFirst();(cd=cli.current());++cli)
04547   {
04548     cd->computeAnchors();
04549   } 
04550   FileName *fn=Doxygen::inputNameList->first();
04551   while (fn)
04552   {
04553     FileDef *fd=fn->first();
04554     while (fd)
04555     {
04556       fd->computeAnchors();
04557       fd=fn->next();
04558     }
04559     fn=Doxygen::inputNameList->next();
04560   }
04561   NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
04562   NamespaceDef *nd=0;
04563   for (nli.toFirst();(nd=nli.current());++nli)
04564   {
04565     nd->computeAnchors();
04566   }
04567   GroupSDict::Iterator gli(*Doxygen::groupSDict);
04568   GroupDef *gd;
04569   for (gli.toFirst();(gd=gli.current());++gli)
04570   {
04571     gd->computeAnchors();
04572   }
04573 }
04574 
04575 //----------------------------------------------------------------------
04576 
04577 static void addListReferences()
04578 {
04579   MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
04580   MemberName *mn=0;
04581   for (mnli.toFirst();(mn=mnli.current());++mnli)
04582   {
04583     MemberNameIterator mni(*mn);
04584     MemberDef *md=0;
04585     for (mni.toFirst();(md=mni.current());++mni)
04586     {
04587       md->visited=FALSE;
04588     }
04589   }
04590   MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict);
04591   for (fnli.toFirst();(mn=fnli.current());++fnli)
04592   {
04593     MemberNameIterator mni(*mn);
04594     MemberDef *md=0;
04595     for (mni.toFirst();(md=mni.current());++mni)
04596     {
04597       md->visited=FALSE;
04598     }
04599   }
04600 
04601   ClassSDict::Iterator cli(*Doxygen::classSDict);
04602   ClassDef *cd=0;
04603   for (cli.toFirst();(cd=cli.current());++cli)
04604   {
04605     cd->addListReferences();
04606   } 
04607   FileName *fn=Doxygen::inputNameList->first();
04608   while (fn)
04609   {
04610     FileDef *fd=fn->first();
04611     while (fd)
04612     {
04613       fd->addListReferences();
04614       fd=fn->next();
04615     }
04616     fn=Doxygen::inputNameList->next();
04617   }
04618   NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
04619   NamespaceDef *nd=0;
04620   for (nli.toFirst();(nd=nli.current());++nli)
04621   {
04622     nd->addListReferences();
04623   }
04624   GroupSDict::Iterator gli(*Doxygen::groupSDict);
04625   GroupDef *gd;
04626   for (gli.toFirst();(gd=gli.current());++gli)
04627   {
04628     gd->addListReferences();
04629   }
04630   PageSDict::Iterator pdi(*Doxygen::pageSDict);
04631   PageDef *pd=0;
04632   for (pdi.toFirst();(pd=pdi.current());++pdi)
04633   {
04634     QCString name = pd->name();
04635     if (pd->getGroupDef())
04636     {
04637       name = pd->getGroupDef()->getOutputFileBase().copy();
04638     }
04639     {
04640       LockingPtr< QList<ListItemInfo> > xrefItems = pd->xrefListItems();
04641       addRefItem(xrefItems.pointer(),
04642           theTranslator->trPage(TRUE,TRUE),
04643           name,pd->title());
04644     }
04645   }
04646 }
04647 
04648 //----------------------------------------------------------------------
04649 // Copy the documentation in entry `root' to member definition `md' and
04650 // set the function declaration of the member to `funcDecl'. If the boolean 
04651 // over_load is set the standard overload text is added. 
04652 
04653 static void addMemberDocs(EntryNav *rootNav,
04654                    MemberDef *md, const char *funcDecl,
04655                    ArgumentList *al,
04656                    bool over_load,
04657                    NamespaceSDict *
04658                   )
04659 {
04660   Entry *root = rootNav->entry();
04661   //printf("addMemberDocs: `%s'::`%s' `%s' funcDecl=`%s' mSpec=%d\n",
04662   //     root->parent->name.data(),md->name().data(),md->argsString(),funcDecl,root->spec);
04663   QCString fDecl=funcDecl;
04664   // strip extern specifier
04665   fDecl.stripPrefix("extern ");
04666   md->setDefinition(fDecl);
04667   md->enableCallGraph(root->callGraph);
04668   md->enableCallerGraph(root->callerGraph);
04669   ClassDef     *cd=md->getClassDef();
04670   NamespaceDef *nd=md->getNamespaceDef();
04671   QCString fullName;
04672   if (cd) 
04673     fullName = cd->name();
04674   else if (nd) 
04675     fullName = nd->name();
04676 
04677   if (!fullName.isEmpty()) fullName+="::";
04678   fullName+=md->name();
04679   FileDef *rfd=rootNav->fileDef();
04680 
04681   // TODO determine scope based on root not md
04682   Definition *rscope = md->getOuterScope();
04683   
04684   LockingPtr<ArgumentList> mdAl = md->argumentList();
04685   if (al)
04686   {
04687     //printf("merging arguments (1) docs=%d\n",root->doc.isEmpty());
04688     mergeArguments(mdAl.pointer(),al,!root->doc.isEmpty());
04689   }
04690   else
04691   {
04692     if ( 
04693           matchArguments2( md->getOuterScope(), md->getFileDef(), mdAl.pointer(),
04694                            rscope,rfd,root->argList,
04695                            TRUE
04696                          )
04697        ) 
04698     {
04699       //printf("merging arguments (2)\n");
04700       mergeArguments(mdAl.pointer(),root->argList,!root->doc.isEmpty());
04701     }
04702   }
04703   if (over_load)  // the \overload keyword was used
04704   {
04705     QCString doc=getOverloadDocs();
04706     if (!root->doc.isEmpty())
04707     {
04708       doc+="<p>";
04709       doc+=root->doc;
04710     }
04711     md->setDocumentation(doc,root->docFile,root->docLine); 
04712     md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
04713     md->setDocsForDefinition(!root->proto);
04714   }
04715   else  
04716   {
04717     //printf("Adding docs md->docs=`%s' root->docs=`%s'!\n",
04718     //     md->documentation().data(),root->doc.data());
04719     // documentation outside a compound overrides the documentation inside it
04720 
04721 #if 0
04722     if ( /* !md->isStatic() && !root->stat &&   do not replace doc of a static */
04723         (
04724          md->documentation().isEmpty() ||    /* no docs yet */
04725          (rootNav->parent()->name().isEmpty() &&     /* or overwrite prototype docs */
04726           !root->proto && md->isPrototype()  /* with member definition docs */
04727          )
04728         ) && !root->doc.isEmpty() 
04729        )
04730 #endif
04731     {
04732       //printf("overwrite!\n");
04733       md->setDocumentation(root->doc,root->docFile,root->docLine);
04734       md->setDocsForDefinition(!root->proto);
04735     }
04736 
04737     //printf("Adding brief md->brief=`%s' root->brief=`%s'!\n",
04738     //     md->briefDescription().data(),root->brief.data());
04739     // brief descriptions inside a compound override the documentation 
04740     // outside it
04741 #if 0
04742     if ( /* !md->isStatic() && !root->stat &&  do not replace doc of static */
04743         ( 
04744          md->briefDescription().isEmpty() ||  /* no docs yet */
04745          !rootNav->parent()->name().isEmpty()         /* member of a class */
04746         ) && !root->brief.isEmpty()
04747        )
04748 #endif
04749     {
04750       //printf("overwrite!\n");
04751       md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
04752     }
04753 
04754     if (
04755         (md->inbodyDocumentation().isEmpty() ||
04756          !rootNav->parent()->name().isEmpty()
04757         ) && !root->inbodyDocs.isEmpty()
04758        )
04759     {
04760       md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
04761     }
04762   }
04763 
04764   //printf("initializer: '%s'(isEmpty=%d) '%s'(isEmpty=%d)\n",
04765   //    md->initializer().data(),md->initializer().isEmpty(),
04766   //    root->initializer.data(),root->initializer.isEmpty()
04767   //   );
04768   if (md->initializer().isEmpty() && !root->initializer.isEmpty())
04769   {
04770     //printf("setInitializer\n");
04771     md->setInitializer(root->initializer);
04772   }
04773   
04774   md->setMaxInitLines(root->initLines);
04775 
04776   if (rfd)
04777   {
04778 
04779     if ((md->getStartBodyLine()==-1 && root->bodyLine!=-1) 
04780        // || (md->isVariable() && !root->explicitExternal)
04781        )
04782     {
04783       //printf("Setting new body segment [%d,%d]\n",root->bodyLine,root->endBodyLine);
04784       md->setBodySegment(root->bodyLine,root->endBodyLine);
04785       md->setBodyDef(rfd);
04786     }
04787 
04788     md->setRefItems(root->sli);
04789   }
04790 
04791   md->enableCallGraph(md->hasCallGraph() || root->callGraph);
04792   md->enableCallerGraph(md->hasCallerGraph() || root->callerGraph);
04793 
04794   md->mergeMemberSpecifiers(root->spec);
04795   md->addSectionsToDefinition(root->anchors);
04796   addMemberToGroups(root,md);
04797   if (cd) cd->insertUsedFile(root->fileName);
04798   //printf("root->mGrpId=%d\n",root->mGrpId);
04799   if (root->mGrpId!=-1)
04800   {
04801     if (md->getMemberGroupId()!=-1)
04802     {
04803       if (md->getMemberGroupId()!=root->mGrpId)
04804       {
04805         warn(
04806              root->fileName,root->startLine,
04807              "Warning: member %s belongs to two different groups. The second "
04808              "one found here will be ignored.",
04809              md->name().data()
04810             );
04811       }
04812     }
04813     else // set group id
04814     {
04815       //printf("setMemberGroupId=%d md=%s\n",root->mGrpId,md->name().data());
04816       md->setMemberGroupId(root->mGrpId);
04817     }
04818   }
04819 }
04820 
04821 //----------------------------------------------------------------------
04822 // find a class definition given the scope name and (optionally) a 
04823 // template list specifier
04824 
04825 static ClassDef *findClassDefinition(FileDef *fd,NamespaceDef *nd,
04826                          const char *scopeName)
04827 {
04828   ClassDef *tcd = getResolvedClass(nd,fd,scopeName,0,0,TRUE,TRUE);
04829   return tcd;
04830 }
04831 
04832 
04833 //----------------------------------------------------------------------
04834 // Adds the documentation contained in `root' to a global function
04835 // with name `name' and argument list `args' (for overloading) and
04836 // function declaration `decl' to the corresponding member definition.
04837 
04838 static bool findGlobalMember(EntryNav *rootNav, 
04839                            const QCString &namespaceName,
04840                            const char *name, 
04841                            const char *tempArg,
04842                            const char *, 
04843                            const char *decl)
04844 {
04845   Entry *root = rootNav->entry();
04846   Debug::print(Debug::FindMembers,0,
04847        "2. findGlobalMember(namespace=%s,name=%s,tempArg=%s,decl=%s)\n",
04848           namespaceName.data(),name,tempArg,decl);
04849   QCString n=name;
04850   if (n.isEmpty()) return FALSE;
04851   if (n.find("::")!=-1) return FALSE; // skip undefined class members
04852   MemberName *mn=Doxygen::functionNameSDict->find(n+tempArg); // look in function dictionary
04853   if (mn==0)
04854   {
04855     mn=Doxygen::functionNameSDict->find(n); // try without template arguments
04856   }
04857   if (mn) // function name defined
04858   {
04859     Debug::print(Debug::FindMembers,0,"3. Found function scope\n");
04860     //int count=0;
04861     MemberNameIterator mni(*mn);
04862     MemberDef *md;
04863     bool found=FALSE;
04864     for (mni.toFirst();(md=mni.current()) && !found;++mni)
04865     {
04866       NamespaceDef *nd=md->getNamespaceDef();
04867 
04868       //printf("Namespace namespaceName=%s nd=%s\n",
04869       //    namespaceName.data(),nd ? nd->name().data() : "<none>");
04870 
04871       FileDef *fd=rootNav->fileDef();
04872       //printf("File %s\n",fd ? fd->name().data() : "<none>");
04873       NamespaceSDict *nl    = fd ? fd->getUsedNamespaces() : 0;
04874       //SDict<Definition> *cl = fd ? fd->getUsedClasses()    : 0;
04875       //printf("NamespaceList %p\n",nl);
04876 
04877       // search in the list of namespaces that are imported via a 
04878       // using declaration
04879       bool viaUsingDirective = nl && nd && nl->find(nd->qualifiedName())!=0;
04880 
04881       if ((namespaceName.isEmpty() && nd==0) ||  // not in a namespace
04882           (nd && nd->name()==namespaceName) ||   // or in the same namespace 
04883           viaUsingDirective                      // member in `using' namespace
04884          )     
04885       {
04886         Debug::print(Debug::FindMembers,0,"4. Try to add member `%s' to scope `%s'\n",
04887             md->name().data(),namespaceName.data());
04888         QCString nsName = nd ? nd->name().data() : "";
04889 
04890         NamespaceDef *rnd = 0;
04891         if (!namespaceName.isEmpty()) rnd = Doxygen::namespaceSDict->find(namespaceName);
04892         
04893         LockingPtr<ArgumentList> mdAl = md->argumentList();
04894         bool matching=
04895           (mdAl==0 && root->argList->count()==0) ||
04896           md->isVariable() || md->isTypedef() || /* in case of function pointers */
04897           matchArguments2(md->getOuterScope(),md->getFileDef(),mdAl.pointer(),
04898                           rnd ? rnd : Doxygen::globalScope,fd,root->argList,
04899                           FALSE);
04900 
04901         //printf("%s<->%s\n",
04902         //    argListToString(md->argumentList()).data(),
04903         //    argListToString(root->argList).data());
04904 
04905         // for static members we also check if the comment block was found in 
04906         // the same file. This is needed because static members with the same
04907         // name can be in different files. Thus it would be wrong to just
04908         // put the comment block at the first syntactically matching member.
04909         if (matching && md->isStatic() && 
04910             md->getDefFileName()!=root->fileName && 
04911             mn->count()>1)
04912         {
04913           matching = FALSE;
04914         }
04915 
04916         if (matching) // add docs to the member
04917         {
04918           Debug::print(Debug::FindMembers,0,"5. Match found\n");
04919           addMemberDocs(rootNav,md,decl,root->argList,FALSE);
04920           found=TRUE;
04921         }
04922       }
04923     } 
04924     if (!found && !root->relatesDup) // no match
04925     {
04926       QCString fullFuncDecl=decl;
04927       if (root->argList) fullFuncDecl+=argListToString(root->argList,TRUE);
04928       warn(root->fileName,root->startLine,
04929            "Warning: no matching file member found for \n%s",fullFuncDecl.data());   
04930       if (mn->count()>0)
04931       {
04932         warn_cont("Possible candidates:\n");
04933         for (mni.toFirst();(md=mni.current());++mni)
04934         {
04935           warn_cont("  %s\n",md->declaration());
04936         }
04937       }
04938     }
04939   }
04940   else // got docs for an undefined member!
04941   {
04942     if (root->type!="friend class" && 
04943         root->type!="friend struct" &&
04944         root->type!="friend union")
04945     {
04946       warn(root->fileName,root->startLine,
04947            "Warning: documented function `%s' was not declared or defined.",decl
04948           );
04949     }
04950   }
04951   return TRUE;
04952 }
04953 
04954 static bool isSpecialization(
04955                   const QList<ArgumentList> &srcTempArgLists,
04956                   const QList<ArgumentList> &dstTempArgLists
04957     )
04958 {
04959     QListIterator<ArgumentList> srclali(srcTempArgLists);
04960     QListIterator<ArgumentList> dstlali(dstTempArgLists);
04961     for (;srclali.current();++srclali,++dstlali)
04962     {
04963       ArgumentList *sal = srclali.current();
04964       ArgumentList *dal = dstlali.current();
04965       if (!(sal && dal && sal->count()==dal->count())) return TRUE;
04966     }
04967     return FALSE;
04968 }
04969 
04970 
04971 static QCString substituteTemplatesInString(
04972     const QList<ArgumentList> &srcTempArgLists,
04973     const QList<ArgumentList> &dstTempArgLists,
04974     ArgumentList *funcTempArgList, // can be used to match template specializations
04975     const QCString &src
04976     )
04977 {
04978   QCString dst;
04979   QRegExp re(idMask);
04980   //printf("type=%s\n",sa->type.data());
04981 
04982   int i,p=0,l; 
04983   while ((i=re.match(src,p,&l))!=-1) // for each word in srcType
04984   {
04985     bool found=FALSE;
04986     dst+=src.mid(p,i-p);
04987     QCString name=src.mid(i,l);
04988 
04989     QListIterator<ArgumentList> srclali(srcTempArgLists);
04990     QListIterator<ArgumentList> dstlali(dstTempArgLists);
04991     for (;srclali.current() && !found;++srclali,++dstlali)
04992     {
04993       ArgumentListIterator tsali(*srclali.current());
04994       ArgumentListIterator tdali(*dstlali.current());
04995       Argument *tsa =0,*tda=0, *fa=0;
04996       if (funcTempArgList)
04997       {
04998         fa=funcTempArgList->first();
04999       }
05000 
05001       for (tsali.toFirst();(tsa=tsali.current()) && !found;++tsali)
05002       {
05003         tda = tdali.current();
05004         if (name==tsa->name)
05005         {
05006           if (tda)
05007           {
05008             name=tda->name; // substitute
05009             found=TRUE;
05010           }
05011           else if (fa)
05012           {
05013             name=fa->type;
05014             found=TRUE;
05015           }
05016         }
05017         if (tda) 
05018           ++tdali; 
05019         else if (fa) 
05020           fa=funcTempArgList->next();
05021       }
05022     }
05023     dst+=name; 
05024     p=i+l;
05025   }
05026   dst+=src.right(src.length()-p);
05027   return dst;
05028 }
05029 
05030 static void substituteTemplatesInArgList(
05031                   const QList<ArgumentList> &srcTempArgLists,
05032                   const QList<ArgumentList> &dstTempArgLists,
05033                   ArgumentList *src,
05034                   ArgumentList *dst,
05035                   ArgumentList *funcTempArgs = 0
05036                  )
05037 {
05038   ArgumentListIterator sali(*src);
05039   Argument *sa=0;
05040   Argument *da=dst->first();
05041 
05042   for (sali.toFirst();(sa=sali.current());++sali) // for each member argument
05043   {
05044     QCString dstType = substituteTemplatesInString(
05045                                   srcTempArgLists,dstTempArgLists,funcTempArgs,
05046                                   sa->type);
05047     QCString dstArray = substituteTemplatesInString(
05048                                   srcTempArgLists,dstTempArgLists,funcTempArgs,
05049                                   sa->array);
05050     if (da==0)
05051     {
05052       da=new Argument(*sa);
05053       dst->append(da);
05054       da->type=dstType;
05055       da->array=dstArray;
05056       da=0;
05057     }
05058     else
05059     {
05060       da->type=dstType;
05061       da->type=dstArray;
05062       da=dst->next();
05063     }
05064   }
05065   dst->constSpecifier    = src->constSpecifier;
05066   dst->volatileSpecifier = src->volatileSpecifier;
05067   dst->pureSpecifier     = src->pureSpecifier;
05068   //printf("substituteTemplatesInArgList: replacing %s with %s\n",
05069   //    argListToString(src).data(),argListToString(dst).data());
05070 }
05071 
05072 
05073 
05083 static void findMember(EntryNav *rootNav,
05084                        QCString funcDecl,
05085                        bool overloaded,
05086                        bool isFunc
05087                       )
05088 {
05089   Entry *root = rootNav->entry();
05090 
05091   Debug::print(Debug::FindMembers,0,
05092                "findMember(root=%p,funcDecl=`%s',related=`%s',overload=%d,"
05093                "isFunc=%d mGrpId=%d tArgList=%p (#=%d) "
05094                "spec=%d isObjC=%d\n",
05095                root,funcDecl.data(),root->relates.data(),overloaded,isFunc,root->mGrpId,
05096                root->tArgLists,root->tArgLists ? root->tArgLists->count() : 0,
05097                root->spec,root->objc
05098               );
05099 
05100   QCString scopeName;
05101   QCString className;
05102   QCString namespaceName;
05103   QCString funcType;
05104   QCString funcName;
05105   QCString funcArgs;
05106   QCString funcTempList;
05107   QCString exceptions;
05108   QCString funcSpec;
05109   bool isRelated=FALSE;
05110   bool isFriend=FALSE;
05111   bool done;
05112   do
05113   {
05114     done=TRUE;
05115     if (funcDecl.stripPrefix("friend ")) // treat friends as related members
05116     {
05117       isFriend=TRUE;
05118       done=FALSE;
05119     }
05120     if (funcDecl.stripPrefix("inline "))
05121     {
05122       root->spec|=Entry::Inline;
05123       done=FALSE;
05124     }
05125     if (funcDecl.stripPrefix("explicit "))
05126     {
05127       root->spec|=Entry::Explicit;
05128       done=FALSE;
05129     }
05130     if (funcDecl.stripPrefix("mutable "))
05131     {
05132       root->spec|=Entry::Mutable;
05133       done=FALSE;
05134     }
05135     if (funcDecl.stripPrefix("virtual "))
05136     {
05137       done=FALSE;
05138     }
05139   } while (!done);
05140 
05141   // delete any ; from the function declaration
05142   int sep;
05143   while ((sep=funcDecl.find(';'))!=-1)
05144   {
05145     funcDecl=(funcDecl.left(sep)+funcDecl.right(funcDecl.length()-sep-1)).stripWhiteSpace();
05146   }
05147   
05148   // make sure the first character is a space to simplify searching.
05149   if (!funcDecl.isEmpty() && funcDecl[0]!=' ') funcDecl.prepend(" ");
05150   
05151   // remove some superfluous spaces
05152   funcDecl= substitute(
05153               substitute(
05154                 substitute(funcDecl,"~ ","~"),
05155                 ":: ","::"
05156               ),
05157               " ::","::"
05158             ).stripWhiteSpace();
05159   
05160   //printf("funcDecl=`%s'\n",funcDecl.data());
05161   if (isFriend && funcDecl.left(6)=="class ")
05162   {
05163     //printf("friend class\n");
05164     funcDecl=funcDecl.right(funcDecl.length()-6);
05165     funcName = funcDecl.copy();
05166   }
05167   else if (isFriend && funcDecl.left(7)=="struct ")
05168   {
05169     funcDecl=funcDecl.right(funcDecl.length()-7);
05170     funcName = funcDecl.copy();
05171   }
05172   else
05173   {
05174     // extract information from the declarations
05175     parseFuncDecl(funcDecl,root->objc,scopeName,funcType,funcName,
05176                 funcArgs,funcTempList,exceptions
05177                );
05178   }
05179   //printf("scopeName=`%s' funcType=`%s' funcName=`%s' funcArgs=`%s'\n",
05180   //    scopeName.data(),funcType.data(),funcName.data(),funcArgs.data());
05181 
05182   // the class name can also be a namespace name, we decide this later.
05183   // if a related class name is specified and the class name could
05184   // not be derived from the function declaration, then use the
05185   // related field.
05186   //printf("scopeName=`%s' className=`%s' namespaceName=`%s'\n",
05187   //    scopeName.data(),className.data(),namespaceName.data());
05188   if (!root->relates.isEmpty()) 
05189   {                             // related member, prefix user specified scope
05190     isRelated=TRUE;
05191     if (getClass(root->relates)==0 && !scopeName.isEmpty())
05192       scopeName= mergeScopes(scopeName,root->relates);
05193     else 
05194       scopeName = root->relates;
05195   }
05196 
05197   if (root->relates.isEmpty() && rootNav->parent() && 
05198       ((rootNav->parent()->section()&Entry::SCOPE_MASK) ||
05199        (rootNav->parent()->section()==Entry::OBJCIMPL_SEC)
05200       ) &&
05201       !rootNav->parent()->name().isEmpty()) // see if we can combine scopeName 
05202                                      // with the scope in which it was found
05203   {
05204     QCString joinedName = rootNav->parent()->name()+"::"+scopeName;
05205     if (!scopeName.isEmpty() && 
05206         (getClass(joinedName) || Doxygen::namespaceSDict->find(joinedName)))
05207     {
05208       scopeName = joinedName;
05209     }
05210     else
05211     {
05212       scopeName = mergeScopes(rootNav->parent()->name(),scopeName);
05213     }
05214   }
05215   else // see if we can prefix a namespace or class that is used from the file
05216   {
05217      FileDef *fd=rootNav->fileDef();
05218      if (fd)
05219      {
05220        NamespaceSDict *fnl = fd->getUsedNamespaces();
05221        if (fnl)
05222        {
05223          QCString joinedName;
05224          NamespaceDef *fnd;
05225          NamespaceSDict::Iterator nsdi(*fnl);
05226          for (nsdi.toFirst();(fnd=nsdi.current());++nsdi)
05227          {
05228            joinedName = fnd->name()+"::"+scopeName;
05229            if (Doxygen::namespaceSDict->find(joinedName))
05230            {
05231              scopeName=joinedName;
05232              break;
05233            }
05234          }
05235        }
05236      }
05237   }
05238   scopeName=stripTemplateSpecifiersFromScope(
05239       removeRedundantWhiteSpace(scopeName),FALSE,&funcSpec); 
05240 
05241   // funcSpec contains the last template specifiers of the given scope.
05242   // If this method does not have any template arguments or they are 
05243   // empty while funcSpec is not empty we assume this is a 
05244   // specialization of a method. If not, we clear the funcSpec and treat
05245   // this as a normal method of a template class.
05246   if (!(root->tArgLists && 
05247         root->tArgLists->count()>0 &&
05248         root->tArgLists->first()->count()==0
05249        )
05250      ) 
05251   {
05252     funcSpec.resize(0);
05253   }
05254   
05255   // split scope into a namespace and a class part
05256   extractNamespaceName(scopeName,className,namespaceName,TRUE);
05257   //printf("scopeName=`%s' className=`%s' namespaceName=`%s'\n",
05258   //       scopeName.data(),className.data(),namespaceName.data());
05259   
05260   namespaceName=removeAnonymousScopes(namespaceName);
05261   //printf("namespaceName=`%s' className=`%s'\n",namespaceName.data(),className.data());
05262   // merge class and namespace scopes again
05263   scopeName.resize(0);
05264   if (!namespaceName.isEmpty())
05265   {
05266     if (className.isEmpty())
05267     {
05268       scopeName=namespaceName;
05269     }
05270     else if (!getClass(className)) // class name only exists in a namespace
05271     {
05272       scopeName=namespaceName+"::"+className;
05273     }
05274     else
05275     {
05276       scopeName=className;
05277     }
05278   }
05279   else if (!className.isEmpty())
05280   {
05281     scopeName=className;
05282   }
05283   //printf("new scope=`%s'\n",scopeName.data());
05284 
05285   QCString tempScopeName=scopeName;
05286   ClassDef *cd=getClass(scopeName);
05287   if (cd)
05288   {
05289     if (root->tArgLists) root->tArgLists->first();
05290     if (funcSpec.isEmpty())
05291     {
05292       tempScopeName=cd->qualifiedNameWithTemplateParameters(root->tArgLists);
05293     }
05294     else
05295     {
05296       tempScopeName=scopeName+funcSpec;
05297     }
05298   }
05299   //printf("scopeName=%s cd=%p root->tArgLists=%p result=%s\n",
05300   //    scopeName.data(),cd,root->tArgLists,tempScopeName.data());
05301   
05302   //printf("scopeName=`%s' className=`%s'\n",scopeName.data(),className.data());
05303   // rebuild the function declaration (needed to get the scope right).
05304   if (!scopeName.isEmpty() && !isRelated && !isFriend && !Config_getBool("HIDE_SCOPE_NAMES"))
05305   {
05306     if (!funcType.isEmpty())
05307     {
05308       if (isFunc) // a function -> we use argList for the arguments
05309       {
05310         funcDecl=funcType+" "+tempScopeName+"::"+funcName+funcTempList;
05311       }
05312       else
05313       {
05314         funcDecl=funcType+" "+tempScopeName+"::"+funcName+funcArgs;
05315       }
05316     }
05317     else
05318     {
05319       if (isFunc) // a function => we use argList for the arguments
05320       {
05321         funcDecl=tempScopeName+"::"+funcName+funcTempList;
05322       }
05323       else // variable => add `argument' list
05324       {
05325         funcDecl=tempScopeName+"::"+funcName+funcArgs;
05326       }
05327     }
05328   }
05329   else // build declaration without scope
05330   {
05331     if (!funcType.isEmpty()) // but with a type
05332     {
05333       if (isFunc) // function => omit argument list
05334       {
05335         funcDecl=funcType+" "+funcName+funcTempList;
05336       }
05337       else // variable => add `argument' list
05338       {
05339         funcDecl=funcType+" "+funcName+funcArgs;
05340       }
05341     }
05342     else // no type
05343     {
05344       if (isFunc)
05345       {
05346         funcDecl=funcName+funcTempList;
05347       }
05348       else
05349       {
05350         funcDecl=funcName+funcArgs;
05351       }
05352     }
05353   }
05354   
05355   if (funcType=="template class" && !funcTempList.isEmpty())
05356     return;   // ignore explicit template instantiations
05357   
05358   Debug::print(Debug::FindMembers,0,
05359            "findMember() Parse results:\n"
05360            "  namespaceName=`%s'\n"
05361            "  className=`%s`\n"
05362            "  funcType=`%s'\n"
05363            "  funcSpec=`%s'\n"
05364            "  funcName=`%s'\n"
05365            "  funcArgs=`%s'\n"
05366            "  funcTempList=`%s'\n"
05367            "  funcDecl=`%s'\n"
05368            "  related=`%s'\n" 
05369            "  exceptions=`%s'\n"
05370            "  isRelated=%d\n"
05371            "  isFriend=%d\n"
05372            "  isFunc=%d\n\n",
05373            namespaceName.data(),className.data(),
05374            funcType.data(),funcSpec.data(),funcName.data(),funcArgs.data(),funcTempList.data(),
05375            funcDecl.data(),root->relates.data(),exceptions.data(),isRelated,isFriend,
05376            isFunc
05377           );
05378 
05379   MemberName *mn=0;
05380   if (!funcName.isEmpty()) // function name is valid
05381   { 
05382     Debug::print(Debug::FindMembers,0,
05383                  "1. funcName=`%s'\n",funcName.data());
05384     if (funcName.left(9)=="operator ") // strip class scope from cast operator
05385     {
05386       funcName = substitute(funcName,className+"::","");
05387     }
05388     if (!funcTempList.isEmpty()) // try with member specialization
05389     {
05390       mn=Doxygen::memberNameSDict->find(funcName+funcTempList);
05391     }
05392     if (mn==0) // try without specialization
05393     {
05394       mn=Doxygen::memberNameSDict->find(funcName);
05395     }
05396     if (!isRelated && mn) // function name already found
05397     {
05398       Debug::print(Debug::FindMembers,0,
05399                    "2. member name exists (%d members with this name)\n",mn->count());
05400       if (!className.isEmpty()) // class name is valid
05401       {
05402         if (funcSpec.isEmpty()) // not a member specialization
05403         {
05404           int count=0;
05405           int noMatchCount=0;
05406           MemberNameIterator mni(*mn);
05407           MemberDef *md;
05408           bool memFound=FALSE;
05409           for (mni.toFirst();!memFound && (md=mni.current());++mni)
05410           {
05411             ClassDef *cd=md->getClassDef();
05412             Debug::print(Debug::FindMembers,0,
05413                 "3. member definition found, "
05414                 "scope needed=`%s' scope=`%s' args=`%s' fileName=%s\n",
05415                 scopeName.data(),cd ? cd->name().data() : "<none>",
05416                 md->argsString(),
05417                 root->fileName.data());
05418             //printf("Member %s (member scopeName=%s) (this scopeName=%s) classTempList=%s\n",md->name().data(),cd->name().data(),scopeName.data(),classTempList.data());
05419             FileDef *fd=rootNav->fileDef();
05420             NamespaceDef *nd=0;
05421             if (!namespaceName.isEmpty()) nd=getResolvedNamespace(namespaceName);
05422 
05423             ClassDef *tcd=findClassDefinition(fd,nd,scopeName);
05424             if (tcd==0 && stripAnonymousNamespaceScope(cd->name())==scopeName)
05425             {
05426               // don't be fooled by anonymous scopes
05427               tcd=cd;
05428             }
05429             //printf("Looking for %s inside nd=%s result=%p (%s) cd=%p\n",
05430             //    scopeName.data(),nd?nd->name().data():"<none>",tcd,tcd?tcd->name().data():"",cd);
05431 
05432             if (cd && tcd==cd) // member's classes match
05433             {
05434               Debug::print(Debug::FindMembers,0,
05435                   "4. class definition %s found\n",cd->name().data());
05436 
05437               // get the template parameter lists found at the member declaration
05438               QList<ArgumentList> declTemplArgs;
05439               cd->getTemplateParameterLists(declTemplArgs);
05440               LockingPtr<ArgumentList> templAl = md->templateArguments();
05441               if (templAl!=0)
05442               {
05443                 declTemplArgs.append(templAl.pointer());
05444               }
05445 
05446               // get the template parameter lists found at the member definition
05447               QList<ArgumentList> *defTemplArgs = root->tArgLists;
05448               //printf("defTemplArgs=%p\n",defTemplArgs);
05449 
05450               // do we replace the decl argument lists with the def argument lists?
05451               bool substDone=FALSE;
05452               ArgumentList *argList=0;
05453 
05454               /* substitute the occurrences of class template names in the 
05455                * argument list before matching 
05456                */
05457               LockingPtr<ArgumentList> mdAl = md->argumentList();
05458               if (declTemplArgs.count()>0 && defTemplArgs &&
05459                   declTemplArgs.count()==defTemplArgs->count() &&
05460                   mdAl.pointer()
05461                  )
05462               {
05463                 /* the function definition has template arguments
05464                  * and the class definition also has template arguments, so
05465                  * we must substitute the template names of the class by that
05466                  * of the function definition before matching.
05467                  */
05468                 argList = new ArgumentList;
05469                 substituteTemplatesInArgList(declTemplArgs,*defTemplArgs,
05470                     mdAl.pointer(),argList);
05471 
05472                 substDone=TRUE;
05473               }
05474               else /* no template arguments, compare argument lists directly */
05475               {
05476                 argList = mdAl.pointer();
05477               }
05478 
05479               Debug::print(Debug::FindMembers,0,
05480                   "5. matching `%s'<=>`%s' className=%s namespaceName=%s\n",
05481                   argListToString(argList,TRUE).data(),argListToString(root->argList,TRUE).data(),
05482                   className.data(),namespaceName.data()
05483                   );
05484 
05485               bool matching=
05486                 md->isVariable() || md->isTypedef() || // needed for function pointers
05487                 (mdAl.pointer()==0 && root->argList->count()==0) || 
05488                 matchArguments2(
05489                     md->getClassDef(),md->getFileDef(),argList, 
05490                     cd,fd,root->argList,
05491                     TRUE);
05492 
05493               Debug::print(Debug::FindMembers,0,
05494                   "6. match results of matchArguments2 = %d\n",matching);
05495 
05496               if (substDone) // found a new argument list
05497               {
05498                 if (matching) // replace member's argument list
05499                 {
05500                   md->setDefinitionTemplateParameterLists(root->tArgLists);
05501                   md->setArgumentList(argList); // new owner of the list => no delete
05502                 }
05503                 else // no match 
05504                 {
05505                   if (!funcTempList.isEmpty() && 
05506                       isSpecialization(declTemplArgs,*defTemplArgs))
05507                   {
05508                     // check if we are dealing with a partial template
05509                     // specialization. In this case we add it to the class
05510                     // even though the member arguments do not match.
05511                     
05512                     // TODO: copy other aspects?
05513                     root->protection=md->protection(); // copy protection level
05514                     addMethodToClass(rootNav,cd,md->name(),isFriend);
05515                     return;
05516                   }
05517                   delete argList;
05518                 }
05519               }
05520               if (matching) 
05521               {
05522                 addMemberDocs(rootNav,md,funcDecl,0,overloaded,0/* TODO */);
05523                 count++;
05524                 memFound=TRUE;
05525               }
05526             } 
05527             else if (cd && cd!=tcd) // we did find a class with the same name as cd
05528                                     // but in a different namespace
05529             {
05530               noMatchCount++;
05531             }
05532           } 
05533           if (count==0 && rootNav->parent() && 
05534               rootNav->parent()->section()==Entry::OBJCIMPL_SEC)
05535           {
05536             goto localObjCMethod;
05537           }
05538           if (count==0 && !(isFriend && funcType=="class"))
05539           {
05540             int candidates=0;
05541             if (mn->count()>0)
05542             {
05543               //printf("Assume template class\n");
05544               for (mni.toFirst();(md=mni.current());++mni)
05545               {
05546                 ClassDef *cd=md->getClassDef();
05547                 //printf("cd->name()==%s className=%s\n",cd->name().data(),className.data());
05548                 if (cd!=0 && rightScopeMatch(cd->name(),className)) 
05549                 {
05550                   LockingPtr<ArgumentList> templAl = md->templateArguments();
05551                   if (root->tArgLists && templAl!=0 &&
05552                       root->tArgLists->getLast()->count()<=templAl->count())
05553                   { 
05554                     addMethodToClass(rootNav,cd,md->name(),isFriend);
05555                     return;
05556                   }
05557                   candidates++;
05558                 }
05559               }
05560             }
05561 
05562             warn(root->fileName,root->startLine,
05563                 "Warning: no %smatching class member found for",
05564                 noMatchCount>1 ? "uniquely " : ""
05565                 );   
05566 
05567             if (root->tArgLists)
05568             {
05569               QListIterator<ArgumentList> alli(*root->tArgLists);
05570               ArgumentList *al;
05571               for (;(al=alli.current());++alli)
05572               {
05573                 warn_cont("  template %s\n",tempArgListToString(al).data());
05574               }
05575             }
05576             QCString fullFuncDecl=funcDecl.copy();
05577             if (isFunc) fullFuncDecl+=argListToString(root->argList,TRUE);
05578 
05579             warn_cont("  %s\n",fullFuncDecl.data());
05580 
05581             if (candidates>0)
05582             {
05583               warn_cont("Possible candidates:\n");
05584               for (mni.toFirst();(md=mni.current());++mni)
05585               {
05586                 ClassDef *cd=md->getClassDef();
05587                 if (cd!=0 && rightScopeMatch(cd->name(),className))
05588                 {
05589                   LockingPtr<ArgumentList> templAl = md->templateArguments();
05590                   if (templAl!=0)
05591                   {
05592                     warn_cont("  template %s\n",tempArgListToString(templAl.pointer()).data());
05593                   }
05594                   warn_cont("  ");
05595                   if (md->typeString()) 
05596                   {
05597                     warn_cont("%s ",md->typeString());
05598                   }
05599                   QCString qScope = cd->qualifiedNameWithTemplateParameters();
05600                   if (!qScope.isEmpty()) warn_cont("%s::%s",qScope.data(),md->name().data());
05601                   if (md->argsString()) warn_cont("%s",md->argsString());
05602                   if (noMatchCount>1) warn_cont(" at line %d of file %s",md->getDefLine(),md->getDefFileName().data());
05603                   warn_cont("\n");
05604                 }
05605               }
05606             }
05607           }
05608         }
05609         else if (cd) // member specialization
05610         {
05611           MemberDef::MemberType mtype=MemberDef::Function;
05612           ArgumentList *tArgList = new ArgumentList;
05613           //  getTemplateArgumentsFromName(cd->name()+"::"+funcName,root->tArgLists);
05614           MemberDef *md=new MemberDef(
05615               root->fileName,root->startLine,
05616               funcType,funcName,funcArgs,exceptions,
05617               root->protection,root->virt,root->stat,FALSE,
05618               mtype,tArgList,root->argList);
05619           //printf("new specialized member %s args=`%s'\n",md->name().data(),funcArgs.data());
05620           md->setTagInfo(rootNav->tagInfo());
05621           md->setMemberClass(cd);
05622           md->setTemplateSpecialization(TRUE);
05623           md->setTypeConstraints(root->typeConstr);
05624           md->setDefinition(funcDecl);
05625           md->enableCallGraph(root->callGraph);
05626           md->enableCallerGraph(root->callerGraph);
05627           md->setDocumentation(root->doc,root->docFile,root->docLine);
05628           md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
05629           md->setDocsForDefinition(!root->proto);
05630           md->setPrototype(root->proto);
05631           md->addSectionsToDefinition(root->anchors);
05632           md->setBodySegment(root->bodyLine,root->endBodyLine);
05633           FileDef *fd=rootNav->fileDef();
05634           md->setBodyDef(fd);
05635           md->setMemberSpecifiers(root->spec);
05636           md->setMemberGroupId(root->mGrpId);
05637           mn->append(md);
05638           cd->insertMember(md);
05639           md->setRefItems(root->sli);
05640           delete tArgList;
05641         }
05642         else
05643         {
05644           //printf("*** Specialized member %s of unknown scope %s%s found!\n",
05645           //        scopeName.data(),funcName.data(),funcArgs.data());
05646         }
05647       }
05648       else if (overloaded) // check if the function belongs to only one class 
05649       {
05650         // for unique overloaded member we allow the class to be
05651         // omitted, this is to be Qt compatable. Using this should 
05652         // however be avoided, because it is error prone
05653         MemberNameIterator mni(*mn);
05654         MemberDef *md=mni.toFirst();
05655         ASSERT(md);
05656         ClassDef *cd=md->getClassDef();
05657         ASSERT(cd);
05658         QCString className=cd->name().copy();
05659         ++mni;
05660         bool unique=TRUE;
05661         for (;(md=mni.current());++mni)
05662         {
05663           ClassDef *cd=md->getClassDef();
05664           if (className!=cd->name()) unique=FALSE; 
05665         } 
05666         if (unique)
05667         {
05668           MemberDef::MemberType mtype;
05669           if      (root->mtype==Signal)  mtype=MemberDef::Signal;
05670           else if (root->mtype==Slot)    mtype=MemberDef::Slot;
05671           else if (root->mtype==DCOP)    mtype=MemberDef::DCOP;
05672           else                 mtype=MemberDef::Function;
05673           
05674           // new overloaded member function
05675           ArgumentList *tArgList = 
05676             getTemplateArgumentsFromName(cd->name()+"::"+funcName,root->tArgLists);
05677           //printf("new related member %s args=`%s'\n",md->name().data(),funcArgs.data());
05678           MemberDef *md=new MemberDef(
05679               root->fileName,root->startLine,
05680               funcType,funcName,funcArgs,exceptions,
05681               root->protection,root->virt,root->stat,TRUE,
05682               mtype,tArgList,root->argList);
05683           md->setTagInfo(rootNav->tagInfo());
05684           md->setTypeConstraints(root->typeConstr);
05685           md->setMemberClass(cd);
05686           md->setDefinition(funcDecl);
05687           md->enableCallGraph(root->callGraph);
05688           md->enableCallerGraph(root->callerGraph);
05689           QCString doc=getOverloadDocs();
05690           doc+="<p>";
05691           doc+=root->doc;
05692           md->setDocumentation(doc,root->docFile,root->docLine);
05693           md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
05694           md->setDocsForDefinition(!root->proto);
05695           md->setPrototype(root->proto);
05696           md->addSectionsToDefinition(root->anchors);
05697           md->setBodySegment(root->bodyLine,root->endBodyLine);
05698           FileDef *fd=rootNav->fileDef();
05699           md->setBodyDef(fd);
05700           md->setMemberSpecifiers(root->spec);
05701           md->setMemberGroupId(root->mGrpId);
05702           mn->append(md);
05703           cd->insertMember(md);
05704           cd->insertUsedFile(root->fileName);
05705           md->setRefItems(root->sli);
05706         }
05707       }
05708       else // unrelated function with the same name as a member
05709       {
05710         if (!findGlobalMember(rootNav,namespaceName,funcName,funcTempList,funcArgs,funcDecl))
05711         {
05712           QCString fullFuncDecl=funcDecl.copy();
05713           if (isFunc) fullFuncDecl+=argListToString(root->argList,TRUE);
05714           warn(root->fileName,root->startLine,
05715                "Warning: Cannot determine class for function\n%s",
05716                fullFuncDecl.data()
05717               );   
05718         }
05719       }
05720     }
05721     else if (isRelated && !root->relates.isEmpty())
05722     {
05723       Debug::print(Debug::FindMembers,0,"2. related function\n"
05724               "  scopeName=%s className=%s\n",scopeName.data(),className.data());
05725       if (className.isEmpty()) className=root->relates.copy();
05726       ClassDef *cd;
05727       //printf("scopeName=`%s' className=`%s'\n",scopeName.data(),className.data());
05728       if ((cd=getClass(scopeName)))
05729       {
05730         bool newMember=TRUE; // assume we have a new member
05731         bool newMemberName=FALSE; 
05732         bool isDefine=FALSE;
05733         {
05734           MemberName *mn = Doxygen::functionNameSDict->find(funcName);
05735           if (mn)
05736           {
05737             MemberDef *md = mn->first();
05738             while (md && !isDefine)
05739             {
05740               isDefine = isDefine || md->isDefine();
05741               md = mn->next();
05742             }
05743           }
05744         }
05745 
05746         FileDef *fd=rootNav->fileDef();
05747 
05748         if ((mn=Doxygen::memberNameSDict->find(funcName))==0)
05749         {
05750           mn=new MemberName(funcName);
05751           newMemberName=TRUE; // we create a new member name
05752         }
05753         else
05754         {
05755           MemberDef *rmd=mn->first();
05756           while (rmd && newMember) // see if we got another member with matching arguments
05757           {
05758             LockingPtr<ArgumentList> rmdAl = rmd->argumentList();
05759 
05760             newMember=newMember && 
05761               !matchArguments2(rmd->getOuterScope(),rmd->getFileDef(),rmdAl.pointer(),
05762                                cd,fd,root->argList,
05763                                TRUE);
05764             if (newMember) rmd=mn->next();
05765           }
05766           if (!newMember && rmd) // member already exists as rmd -> add docs
05767           {
05768             //printf("addMemberDocs for related member %s\n",root->name.data());
05769             //rmd->setMemberDefTemplateArguments(root->mtArgList);
05770             addMemberDocs(rootNav,rmd,funcDecl,0,overloaded);
05771           }
05772         }
05773 
05774         if (newMember) // need to create a new member
05775         {
05776           MemberDef::MemberType mtype;
05777           if (isDefine)
05778             mtype=MemberDef::Define;
05779           else if (root->mtype==Signal)  
05780             mtype=MemberDef::Signal;
05781           else if (root->mtype==Slot) 
05782             mtype=MemberDef::Slot;
05783           else if (root->mtype==DCOP)
05784             mtype=MemberDef::DCOP;
05785           else
05786             mtype=MemberDef::Function;
05787 
05788           //printf("New related name `%s' `%d'\n",funcName.data(),
05789           //    root->argList ? (int)root->argList->count() : -1);
05790 
05791           // new related (member) function
05792 #if 0 // removed as it doesn't handle related template functions correctly
05793           ArgumentList *tArgList = 
05794             getTemplateArgumentsFromName(scopeName+"::"+funcName,root->tArgLists);
05795           MemberDef *md=new MemberDef(
05796               root->fileName,root->startLine,
05797               funcType,funcName,funcArgs,exceptions,
05798               root->protection,root->virt,root->stat,TRUE,
05799               mtype,tArgList,funcArgs.isEmpty() ? 0 : root->argList);
05800 #endif
05801           // first note that we pass:
05802           //   (root->tArgLists ? root->tArgLists->last() : 0)
05803           // for the template arguments fo the new "member."
05804           // this accurately reflects the template arguments of
05805           // the related function, which don't have to do with
05806           // those of the related class.
05807           MemberDef *md=new MemberDef(
05808               root->fileName,root->startLine,
05809               funcType,funcName,funcArgs,exceptions,
05810               root->protection,root->virt,root->stat,TRUE,
05811               mtype,
05812               (root->tArgLists ? root->tArgLists->last() : 0),
05813               funcArgs.isEmpty() ? 0 : root->argList);
05814           // 
05815           // we still have the problem that
05816           // MemberDef::writeDocumentation() in memberdef.cpp
05817           // writes the template argument list for the class,
05818           // as if this member is a member of the class.
05819           // fortunately, MemberDef::writeDocumentation() has
05820           // a special mechanism that allows us to totally
05821           // override the set of template argument lists that
05822           // are printed.  We use that and set it to the
05823           // template argument lists of the related function.
05824           //
05825           md->setDefinitionTemplateParameterLists(root->tArgLists);
05826 
05827           md->setTagInfo(rootNav->tagInfo());
05828 
05829 
05830 
05831           //printf("Related member name=`%s' decl=`%s' bodyLine=`%d'\n",
05832           //       funcName.data(),funcDecl.data(),root->bodyLine);
05833 
05834           // try to find the matching line number of the body from the
05835           // global function list 
05836           bool found=FALSE;
05837           if (root->bodyLine==-1)
05838           {
05839             MemberName *rmn=Doxygen::functionNameSDict->find(funcName);
05840             if (rmn)
05841             {
05842               MemberDef *rmd=rmn->first();
05843               while (rmd && !found) // see if we got another member with matching arguments
05844               {
05845                 LockingPtr<ArgumentList> rmdAl = rmd->argumentList();
05846                 // check for matching argument lists
05847                 if (
05848                     matchArguments2(rmd->getOuterScope(),rmd->getFileDef(),rmdAl.pointer(),
05849                                     cd,fd,root->argList,
05850                                     TRUE)
05851                    )
05852                 {
05853                   found=TRUE;
05854                 }
05855                 if (!found) rmd=rmn->next();
05856               }
05857               if (rmd) // member found -> copy line number info
05858               {
05859                 md->setBodySegment(rmd->getStartBodyLine(),rmd->getEndBodyLine());
05860                 md->setBodyDef(rmd->getBodyDef());
05861                 //md->setBodyMember(rmd);
05862               }
05863             }
05864           }
05865           if (!found) // line number could not be found or is available in this
05866                       // entry
05867           {
05868             md->setBodySegment(root->bodyLine,root->endBodyLine);
05869             md->setBodyDef(fd);
05870           }
05871 
05872           //if (root->mGrpId!=-1) 
05873           //{
05874           //  md->setMemberGroup(memberGroupDict[root->mGrpId]);
05875           //}
05876           md->setMemberClass(cd);
05877           md->setMemberSpecifiers(root->spec);
05878           md->setDefinition(funcDecl);
05879           md->enableCallGraph(root->callGraph);
05880           md->enableCallerGraph(root->callerGraph);
05881           md->setDocumentation(root->doc,root->docFile,root->docLine);
05882           md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
05883           md->setDocsForDefinition(!root->proto);
05884           md->setPrototype(root->proto);
05885           md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
05886           md->addSectionsToDefinition(root->anchors);
05887           md->setMemberGroupId(root->mGrpId);
05888           //md->setMemberDefTemplateArguments(root->mtArgList);
05889           mn->append(md);
05890           cd->insertMember(md);
05891           cd->insertUsedFile(root->fileName);
05892           md->setRefItems(root->sli);
05893           if (root->relatesDup) md->setRelatedAlso(cd);
05894           addMemberToGroups(root,md);
05895           //printf("Adding member=%s\n",md->name().data());
05896           if (newMemberName)
05897           {
05898             //Doxygen::memberNameList.append(mn);
05899             //Doxygen::memberNameDict.insert(funcName,mn);
05900             Doxygen::memberNameSDict->append(funcName,mn);
05901           }
05902         }
05903         if (root->relatesDup)
05904         {
05905           if (!findGlobalMember(rootNav,namespaceName,funcName,funcTempList,funcArgs,funcDecl))
05906           {
05907             QCString fullFuncDecl=funcDecl.copy();
05908             if (isFunc) fullFuncDecl+=argListToString(root->argList,TRUE);
05909             warn(root->fileName,root->startLine,
05910                "Warning: Cannot determine file/namespace for relatedalso function\n%s",
05911                fullFuncDecl.data()
05912               );   
05913           }
05914         }
05915       }
05916       else
05917       {
05918         warn_undoc(root->fileName,root->startLine,
05919                    "Warning: class `%s' for related function `%s' is not "
05920                    "documented.", 
05921                    className.data(),funcName.data()
05922                   );
05923       }
05924     }
05925     else if (rootNav->parent() && rootNav->parent()->section()==Entry::OBJCIMPL_SEC)
05926     {
05927 localObjCMethod:
05928       ClassDef *cd;
05929       //printf("scopeName=`%s' className=`%s'\n",scopeName.data(),className.data());
05930       if (Config_getBool("EXTRACT_LOCAL_METHODS") && (cd=getClass(scopeName)))
05931       {
05932         //printf("Local objective C method `%s' of class `%s' found\n",root->name.data(),cd->name().data());
05933         MemberDef *md=new MemberDef(
05934             root->fileName,root->startLine,
05935             funcType,funcName,funcArgs,exceptions,
05936             root->protection,root->virt,root->stat,FALSE,
05937             MemberDef::Function,0,root->argList);
05938         md->setTagInfo(rootNav->tagInfo());
05939         md->makeImplementationDetail();
05940         md->setMemberClass(cd);
05941         md->setDefinition(funcDecl);
05942         md->enableCallGraph(root->callGraph);
05943         md->enableCallerGraph(root->callerGraph);
05944         md->setDocumentation(root->doc,root->docFile,root->docLine);
05945         md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
05946         md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
05947         md->setDocsForDefinition(!root->proto);
05948         md->setPrototype(root->proto);
05949         md->addSectionsToDefinition(root->anchors);
05950         md->setBodySegment(root->bodyLine,root->endBodyLine);
05951         FileDef *fd=rootNav->fileDef();
05952         md->setBodyDef(fd);
05953         md->setMemberSpecifiers(root->spec);
05954         md->setMemberGroupId(root->mGrpId);
05955         cd->insertMember(md);
05956         cd->insertUsedFile(root->fileName);
05957         md->setRefItems(root->sli);
05958         if ((mn=Doxygen::memberNameSDict->find(root->name)))
05959         {
05960           mn->append(md);
05961         }
05962         else 
05963         {
05964           mn = new MemberName(root->name);
05965           mn->append(md);
05966           Doxygen::memberNameSDict->append(root->name,mn);
05967         }
05968       }
05969       else
05970       {
05971         // local objective C method found for class without interface
05972       }
05973     }
05974     else // unrelated not overloaded member found
05975     {
05976       bool globMem = findGlobalMember(rootNav,namespaceName,funcName,funcTempList,funcArgs,funcDecl);
05977       if (className.isEmpty() && !globMem)
05978       {
05979         warn(root->fileName,root->startLine,
05980              "Warning: class for member `%s' cannot "
05981              "be found.", funcName.data()
05982             ); 
05983       }
05984       else if (!className.isEmpty() && !globMem)
05985       {
05986         warn(root->fileName,root->startLine,
05987              "Warning: member `%s' of class `%s' cannot be found",
05988              funcName.data(),className.data());
05989       }
05990     }
05991   }
05992   else
05993   {
05994     // this should not be called
05995     warn(root->fileName,root->startLine,
05996          "Warning: member with no name found.");
05997   }
05998   return;
05999 } 
06000 
06001 //----------------------------------------------------------------------
06002 // find the members corresponding to the different documentation blocks
06003 // that are extracted from the sources.
06004 
06005 static void filterMemberDocumentation(EntryNav *rootNav)
06006 {
06007   Entry *root = rootNav->entry();
06008   int i=-1,l;
06009   Debug::print(Debug::FindMembers,0,
06010       "findMemberDocumentation(): root->type=`%s' root->inside=`%s' root->name=`%s' root->args=`%s' section=%x root->spec=%d root->mGrpId=%d\n",
06011       root->type.data(),root->inside.data(),root->name.data(),root->args.data(),root->section,root->spec,root->mGrpId
06012       );
06013   //printf("rootNav->parent()->name()=%s\n",rootNav->parent()->name().data());
06014   bool isFunc=TRUE;
06015 
06016   if (root->relatesDup && !root->relates.isEmpty())
06017   {
06018     QCString tmp = root->relates;
06019     root->relates.resize(0);
06020     filterMemberDocumentation(rootNav);
06021     root->relates = tmp;
06022   }
06023 
06024   if ( // detect func variable/typedef to func ptr
06025       (i=findFunctionPtr(root->type,&l))!=-1 
06026      )
06027   {
06028     //printf("Fixing function pointer!\n");
06029     // fix type and argument
06030     root->args.prepend(root->type.right(root->type.length()-i-l));
06031     root->type=root->type.left(i+l);
06032     //printf("Results type=%s,name=%s,args=%s\n",root->type.data(),root->name.data(),root->args.data());
06033     isFunc=FALSE;
06034   }
06035   else if ((root->type.left(8)=="typedef " && root->args.find('(')!=-1)) 
06036     // detect function types marked as functions
06037   {
06038     isFunc=FALSE;
06039   }
06040 
06041   //printf("Member %s isFunc=%d\n",root->name.data(),isFunc);
06042   if (root->section==Entry::MEMBERDOC_SEC)
06043   {
06044     //printf("Documentation for inline member `%s' found args=`%s'\n",
06045     //    root->name.data(),root->args.data());
06046     //if (root->relates.length()) printf("  Relates %s\n",root->relates.data());
06047     if (root->type.isEmpty())
06048     {
06049       findMember(rootNav,root->name+root->args+root->exception,FALSE,isFunc);
06050     }
06051     else
06052     {
06053       findMember(rootNav,root->type+" "+root->name+root->args+root->exception,FALSE,isFunc);
06054     }
06055   }
06056   else if (root->section==Entry::OVERLOADDOC_SEC) 
06057   {
06058     //printf("Overloaded member %s found\n",root->name.data());
06059     findMember(rootNav,root->name,TRUE,isFunc);
06060   }
06061   else if 
06062     ((root->section==Entry::FUNCTION_SEC      // function
06063       ||   
06064       (root->section==Entry::VARIABLE_SEC &&  // variable
06065        !root->type.isEmpty() &&                // with a type
06066        compoundKeywordDict.find(root->type)==0 // that is not a keyword 
06067        // (to skip forward declaration of class etc.)
06068       )
06069      ) 
06070     )
06071     {
06072       //printf("Documentation for member `%s' found args=`%s' excp=`%s'\n",
06073       //    root->name.data(),root->args.data(),root->exception.data());
06074       //if (root->relates.length()) printf("  Relates %s\n",root->relates.data());
06075       //printf("Inside=%s\n Relates=%s\n",root->inside.data(),root->relates.data());
06076       if (root->type=="friend class" || root->type=="friend struct" || 
06077           root->type=="friend union")
06078       {
06079         findMember(rootNav,
06080             root->type+" "+
06081             root->name,
06082             FALSE,FALSE);
06083 
06084       }
06085       else if (!root->type.isEmpty())
06086       {
06087         findMember(rootNav,
06088             root->type+" "+
06089             root->inside+
06090             root->name+
06091             root->args+
06092             root->exception,
06093             FALSE,isFunc);
06094       }
06095       else
06096       {
06097         findMember(rootNav,
06098             root->inside+
06099             root->name+
06100             root->args+
06101             root->exception,
06102             FALSE,isFunc);
06103       }
06104     }
06105   else if (root->section==Entry::DEFINE_SEC && !root->relates.isEmpty())
06106   {
06107     findMember(rootNav,root->name+root->args,FALSE,!root->args.isEmpty());
06108   }
06109   else if (root->section==Entry::VARIABLEDOC_SEC)
06110   {
06111     //printf("Documentation for variable %s found\n",root->name.data());
06112     //if (!root->relates.isEmpty()) printf("  Relates %s\n",root->relates.data());
06113     findMember(rootNav,root->name,FALSE,FALSE);
06114   }
06115   else
06116   {
06117     // skip section 
06118     //printf("skip section\n");
06119   }
06120 }
06121 
06122 static void findMemberDocumentation(EntryNav *rootNav)
06123 {
06124   if (rootNav->section()==Entry::MEMBERDOC_SEC ||
06125       rootNav->section()==Entry::OVERLOADDOC_SEC ||
06126       rootNav->section()==Entry::FUNCTION_SEC ||
06127       rootNav->section()==Entry::VARIABLE_SEC ||
06128       rootNav->section()==Entry::VARIABLEDOC_SEC ||
06129       rootNav->section()==Entry::DEFINE_SEC
06130      )
06131   {
06132     rootNav->loadEntry(g_storage);
06133 
06134     filterMemberDocumentation(rootNav);
06135 
06136     rootNav->releaseEntry();
06137   }
06138   if (rootNav->children())
06139   {
06140     EntryNavListIterator eli(*rootNav->children());
06141     EntryNav *e;
06142     for (;(e=eli.current());++eli)
06143     {
06144       if (e->section()!=Entry::ENUM_SEC) findMemberDocumentation(e);
06145     }
06146   }
06147 }
06148 
06149 //----------------------------------------------------------------------
06150 
06151 static void findObjCMethodDefinitions(EntryNav *rootNav)
06152 {
06153   if (rootNav->children())
06154   {
06155     EntryNavListIterator eli(*rootNav->children());
06156     EntryNav *objCImplNav;
06157     for (;(objCImplNav=eli.current());++eli)
06158     {
06159       if (objCImplNav->section()==Entry::OBJCIMPL_SEC && objCImplNav->children())
06160       {
06161         EntryNavListIterator seli(*objCImplNav->children());
06162         EntryNav *objCMethodNav;
06163         for (;(objCMethodNav=seli.current());++seli)
06164         {
06165           if (objCMethodNav->section()==Entry::FUNCTION_SEC)
06166           {
06167             objCMethodNav->loadEntry(g_storage);
06168             Entry *objCMethod = objCMethodNav->entry();
06169 
06170             //Printf("  Found ObjC method definition %s\n",objCMethod->name.data());
06171             findMember(objCMethodNav, objCMethod->type+" "+objCImplNav->name()+"::"+
06172                        objCMethod->name+" "+objCMethod->args, FALSE,TRUE);
06173             objCMethod->section=Entry::EMPTY_SEC;
06174 
06175             objCMethodNav->releaseEntry();
06176           }
06177         }
06178       }
06179     }
06180   }
06181 }
06182 
06183 //----------------------------------------------------------------------
06184 // find and add the enumeration to their classes, namespaces or files
06185 
06186 static void findEnums(EntryNav *rootNav)
06187 {
06188   if (rootNav->section()==Entry::ENUM_SEC)
06189     // non anonymous enumeration
06190   {
06191     rootNav->loadEntry(g_storage);
06192     Entry *root = rootNav->entry();
06193 
06194     MemberDef      *md=0;
06195     ClassDef       *cd=0;
06196     FileDef        *fd=0;
06197     NamespaceDef   *nd=0;
06198     MemberNameSDict *mnsd=0;
06199     bool isGlobal;
06200     bool isRelated=FALSE;
06201     //printf("Found enum with name `%s' relates=%s\n",root->name.data(),root->relates.data());
06202     int i;
06203 
06204     QCString name;
06205     QCString scope;
06206 
06207     if ((i=root->name.findRev("::"))!=-1) // scope is specified
06208     {
06209       scope=root->name.left(i); // extract scope
06210       name=root->name.right(root->name.length()-i-2); // extract name
06211       if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope);
06212     }
06213     else // no scope, check the scope in which the docs where found
06214     {
06215       if (( rootNav->parent()->section() & Entry::SCOPE_MASK )
06216           && !rootNav->parent()->name().isEmpty()
06217          ) // found enum docs inside a compound
06218       {
06219         scope=rootNav->parent()->name();
06220         if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope);
06221       }
06222       name=root->name;
06223     }
06224 
06225     if (!root->relates.isEmpty()) 
06226     {   // related member, prefix user specified scope
06227       isRelated=TRUE;
06228       if (getClass(root->relates)==0 && !scope.isEmpty())
06229         scope=mergeScopes(scope,root->relates);
06230       else 
06231         scope=root->relates.copy();
06232       if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope);
06233     }
06234 
06235     if (cd && !name.isEmpty()) // found a enum inside a compound
06236     {
06237       //printf("Enum `%s'::`%s'\n",cd->name(),name.data());
06238       fd=0;
06239       mnsd=Doxygen::memberNameSDict;
06240       isGlobal=FALSE;
06241     }
06242     else if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@') // found enum inside namespace
06243     {
06244       mnsd=Doxygen::functionNameSDict;
06245       isGlobal=TRUE;
06246     }
06247     else // found a global enum
06248     {
06249       fd=rootNav->fileDef();
06250       mnsd=Doxygen::functionNameSDict;
06251       isGlobal=TRUE;
06252     }
06253 
06254     if (!name.isEmpty())
06255     {
06256       // new enum type
06257       md = new MemberDef(
06258           root->fileName,root->startLine,
06259           0,name,0,0,
06260           root->protection,Normal,FALSE,isRelated,MemberDef::Enumeration,
06261           0,0);
06262       md->setTagInfo(rootNav->tagInfo());
06263       if (!isGlobal) md->setMemberClass(cd); else md->setFileDef(fd);
06264       md->setBodySegment(root->bodyLine,root->endBodyLine);
06265       md->setBodyDef(rootNav->fileDef());
06266       //printf("Enum %s definition at line %d of %s: protection=%d\n",
06267       //    root->name.data(),root->bodyLine,root->fileName.data(),root->protection);
06268       md->addSectionsToDefinition(root->anchors);
06269       md->setMemberGroupId(root->mGrpId);
06270       md->enableCallGraph(root->callGraph);
06271       md->enableCallerGraph(root->callerGraph);
06272       md->setRefItems(root->sli);
06273       //printf("found enum %s nd=%p\n",name.data(),nd);
06274       bool defSet=FALSE;
06275       if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@')
06276       {
06277         if (isRelated || Config_getBool("HIDE_SCOPE_NAMES"))
06278         {
06279           md->setDefinition(name);  
06280         }
06281         else
06282         {
06283           md->setDefinition(nd->name()+"::"+name);  
06284         }
06285         //printf("definition=%s\n",md->definition());
06286         defSet=TRUE;
06287         md->setNamespace(nd);
06288         nd->insertMember(md);
06289       }
06290 
06291       // even if we have already added the enum to a namespace, we still
06292       // also want to add it to other appropriate places such as file
06293       // or class.
06294       if (isGlobal)
06295       {
06296         if (!defSet) md->setDefinition(name);
06297         if (fd==0 && rootNav->parent())
06298         {
06299           fd=rootNav->parent()->fileDef();
06300         }
06301         if (fd) 
06302         {
06303           md->setFileDef(fd);
06304           fd->insertMember(md);
06305         }
06306       }
06307       else if (cd)
06308       {
06309         if (isRelated || Config_getBool("HIDE_SCOPE_NAMES"))
06310         {
06311           md->setDefinition(name);  
06312         }
06313         else
06314         {
06315           md->setDefinition(cd->name()+"::"+name);  
06316         }
06317         cd->insertMember(md);
06318         cd->insertUsedFile(root->fileName);
06319       }
06320       md->setDocumentation(root->doc,root->docFile,root->docLine);
06321       md->setDocsForDefinition(!root->proto);
06322       md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
06323       md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
06324 
06325       //printf("Adding member=%s\n",md->name().data());
06326       MemberName *mn;
06327       if ((mn=(*mnsd)[name]))
06328       {
06329         // this is used if the same enum is in multiple namespaces/classes
06330         mn->append(md);
06331       }
06332       else // new enum name
06333       {
06334         mn = new MemberName(name);
06335         mn->append(md);
06336         mnsd->append(name,mn);
06337         //printf("add %s to new memberName. Now %d members\n",
06338         //       name.data(),mn->count());
06339       }
06340       addMemberToGroups(root,md);
06341 
06342 #if 0
06343       if (rootNav->children())
06344       {
06345         EntryNavListIterator eli(*rootNav->children());
06346         EntryNav *e;
06347         for (;(e=eli.current());++eli)
06348         {
06349           //printf("e->name=%s isRelated=%d\n",e->name.data(),isRelated);
06350           MemberName *fmn=0;
06351           MemberNameSDict *emnsd = isRelated ? Doxygen::functionNameSDict : mnsd;
06352           if (!e->name().isEmpty() && (fmn=(*emnsd)[e->name()])) 
06353             // get list of members with the same name as the field
06354           {
06355             MemberNameIterator fmni(*fmn);
06356             MemberDef *fmd;
06357             for (fmni.toFirst(); (fmd=fmni.current()) ; ++fmni) 
06358             {
06359               if (fmd->isEnumValue())
06360               {
06361                 //printf("found enum value with same name\n");
06362                 if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@')
06363                 {
06364                   NamespaceDef *fnd=fmd->getNamespaceDef();
06365                   if (fnd==nd) // enum value is inside a namespace
06366                   {
06367                     md->insertEnumField(fmd);
06368                     fmd->setEnumScope(md);
06369                   }
06370                 }
06371                 else if (isGlobal)
06372                 {
06373                   FileDef *ffd=fmd->getFileDef();
06374                   if (ffd==fd) // enum value has file scope
06375                   {
06376                     md->insertEnumField(fmd);
06377                     fmd->setEnumScope(md);
06378                   }
06379                 }
06380                 else if (isRelated && cd) // reparent enum value to
06381                   // match the enum's scope
06382                 {
06383                   md->insertEnumField(fmd);   // add field def to list
06384                   fmd->setEnumScope(md);      // cross ref with enum name
06385                   fmd->setEnumClassScope(cd); // cross ref with enum name
06386                   fmd->setOuterScope(cd);
06387                   fmd->makeRelated();
06388                   cd->insertMember(fmd);
06389                 }
06390                 else
06391                 {
06392                   ClassDef *fcd=fmd->getClassDef();
06393                   if (fcd==cd) // enum value is inside a class
06394                   {
06395                     //printf("Inserting enum field %s in enum scope %s\n",
06396                     //    fmd->name().data(),md->name().data());
06397                     md->insertEnumField(fmd); // add field def to list
06398                     fmd->setEnumScope(md);    // cross ref with enum name
06399                   }
06400                 }
06401               } 
06402             }
06403           }
06404         }
06405       }
06406 #endif
06407     }
06408 
06409     rootNav->releaseEntry();
06410   }
06411   else
06412   {
06413     RECURSE_ENTRYTREE(findEnums,rootNav);
06414   }
06415 }
06416 
06417 //----------------------------------------------------------------------
06418 
06419 static void addEnumValuesToEnums(EntryNav *rootNav)
06420 {
06421   if (rootNav->section()==Entry::ENUM_SEC)
06422     // non anonymous enumeration
06423   {
06424     rootNav->loadEntry(g_storage);
06425     Entry *root = rootNav->entry();
06426 
06427     ClassDef       *cd=0;
06428     FileDef        *fd=0;
06429     NamespaceDef   *nd=0;
06430     MemberNameSDict *mnsd=0;
06431     bool isGlobal;
06432     bool isRelated=FALSE;
06433     //printf("Found enum with name `%s' relates=%s\n",root->name.data(),root->relates.data());
06434     int i;
06435 
06436     QCString name;
06437     QCString scope;
06438 
06439     if ((i=root->name.findRev("::"))!=-1) // scope is specified
06440     {
06441       scope=root->name.left(i); // extract scope
06442       name=root->name.right(root->name.length()-i-2); // extract name
06443       if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope);
06444     }
06445     else // no scope, check the scope in which the docs where found
06446     {
06447       if (( rootNav->parent()->section() & Entry::SCOPE_MASK )
06448           && !rootNav->parent()->name().isEmpty()
06449          ) // found enum docs inside a compound
06450       {
06451         scope=rootNav->parent()->name();
06452         if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope);
06453       }
06454       name=root->name;
06455     }
06456 
06457     if (!root->relates.isEmpty()) 
06458     {   // related member, prefix user specified scope
06459       isRelated=TRUE;
06460       if (getClass(root->relates)==0 && !scope.isEmpty())
06461         scope=mergeScopes(scope,root->relates);
06462       else 
06463         scope=root->relates.copy();
06464       if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope);
06465     }
06466 
06467     if (cd && !name.isEmpty()) // found a enum inside a compound
06468     {
06469       //printf("Enum in class `%s'::`%s'\n",cd->name().data(),name.data());
06470       fd=0;
06471       mnsd=Doxygen::memberNameSDict;
06472       isGlobal=FALSE;
06473     }
06474     else if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@') // found enum inside namespace
06475     {
06476       //printf("Enum in namespace `%s'::`%s'\n",nd->name().data(),name.data());
06477       mnsd=Doxygen::functionNameSDict;
06478       isGlobal=TRUE;
06479     }
06480     else // found a global enum
06481     {
06482       fd=rootNav->fileDef();
06483       //printf("Enum in file `%s': `%s'\n",fd->name().data(),name.data());
06484       mnsd=Doxygen::functionNameSDict;
06485       isGlobal=TRUE;
06486     }
06487 
06488     if (!name.isEmpty())
06489     {
06490       MemberName *mn = mnsd->find(name); // for all members with this name
06491       if (mn)
06492       {
06493         MemberNameIterator mni(*mn);
06494         MemberDef *md;
06495         for (mni.toFirst(); (md=mni.current()) ; ++mni)  // for each enum in this list
06496         {
06497           if (md->isEnumerate() && rootNav->children())
06498           {
06499             EntryNavListIterator eli(*rootNav->children()); // for each enum value
06500             EntryNav *e;
06501             for (;(e=eli.current());++eli)
06502             {
06503               SrcLangExt sle;
06504               if (rootNav->fileDef() &&
06505                   ( (sle=getLanguageFromFileName(rootNav->fileDef()->name()))==SrcLangExt_CSharp
06506                   || sle==SrcLangExt_Java
06507                   )
06508                  )
06509               {
06510                 // For C# enum value are only inside the enum scope, so we
06511                 // must create them here
06512                 e->loadEntry(g_storage);
06513                 MemberDef *fmd = addVariableToFile(e,MemberDef::EnumValue,
06514                                  md->getOuterScope() ? md->getOuterScope()->name() : QCString(),
06515                                  e->name(),TRUE,0); 
06516                 md->insertEnumField(fmd);
06517                 fmd->setEnumScope(md);
06518                 e->releaseEntry();
06519               }
06520               else
06521               {
06522                 //printf("e->name=%s isRelated=%d\n",e->name().data(),isRelated);
06523                 MemberName *fmn=0;
06524                 MemberNameSDict *emnsd = isRelated ? Doxygen::functionNameSDict : mnsd;
06525                 if (!e->name().isEmpty() && (fmn=(*emnsd)[e->name()])) 
06526                   // get list of members with the same name as the field
06527                 {
06528                   MemberNameIterator fmni(*fmn);
06529                   MemberDef *fmd;
06530                   for (fmni.toFirst(); (fmd=fmni.current()) ; ++fmni) 
06531                   {
06532                     if (fmd->isEnumValue() && fmd->getOuterScope()==md->getOuterScope()) // in same scope
06533                     {
06534                       //printf("found enum value with same name %s in scope %s\n",
06535                       //    fmd->name().data(),fmd->getOuterScope()->name().data());
06536                       if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@')
06537                       {
06538                         NamespaceDef *fnd=fmd->getNamespaceDef();
06539                         if (fnd==nd) // enum value is inside a namespace
06540                         {
06541                           md->insertEnumField(fmd);
06542                           fmd->setEnumScope(md);
06543                         }
06544                       }
06545                       else if (isGlobal)
06546                       {
06547                         FileDef *ffd=fmd->getFileDef();
06548                         if (ffd==fd) // enum value has file scope
06549                         {
06550                           md->insertEnumField(fmd);
06551                           fmd->setEnumScope(md);
06552                         }
06553                       }
06554                       else if (isRelated && cd) // reparent enum value to
06555                                                 // match the enum's scope
06556                       {
06557                         md->insertEnumField(fmd);   // add field def to list
06558                         fmd->setEnumScope(md);      // cross ref with enum name
06559                         fmd->setEnumClassScope(cd); // cross ref with enum name
06560                         fmd->setOuterScope(cd);
06561                         fmd->makeRelated();
06562                         cd->insertMember(fmd);
06563                       }
06564                       else
06565                       {
06566                         ClassDef *fcd=fmd->getClassDef();
06567                         if (fcd==cd) // enum value is inside a class
06568                         {
06569                           //printf("Inserting enum field %s in enum scope %s\n",
06570                           //    fmd->name().data(),md->name().data());
06571                           md->insertEnumField(fmd); // add field def to list
06572                           fmd->setEnumScope(md);    // cross ref with enum name
06573                         }
06574                       }
06575                     } 
06576                   }
06577                 }
06578               }
06579             }
06580           }
06581         }
06582       }
06583     }
06584 
06585     rootNav->releaseEntry();
06586   }
06587   else
06588   {
06589     RECURSE_ENTRYTREE(addEnumValuesToEnums,rootNav);
06590   }
06591 }
06592 
06593 
06594 //----------------------------------------------------------------------
06595 // find the documentation blocks for the enumerations
06596 
06597 static void findEnumDocumentation(EntryNav *rootNav)
06598 {
06599   if (rootNav->section()==Entry::ENUMDOC_SEC
06600       && !rootNav->name().isEmpty()
06601       && rootNav->name().at(0)!='@'        // skip anonymous enums
06602      )
06603   {
06604     rootNav->loadEntry(g_storage);
06605     Entry *root = rootNav->entry();
06606 
06607     //printf("Found docs for enum with name `%s' in context %s\n",
06608     //    root->name.data(),root->parent->name.data());
06609     int i;
06610     QCString name;
06611     QCString scope;
06612     if ((i=root->name.findRev("::"))!=-1) // scope is specified as part of the name
06613     {
06614       name=root->name.right(root->name.length()-i-2); // extract name
06615       scope=root->name.left(i); // extract scope
06616       //printf("Scope=`%s' Name=`%s'\n",scope.data(),name.data());
06617     }
06618     else // just the name
06619     {
06620       name=root->name;
06621     }
06622     if (( rootNav->parent()->section() & Entry::SCOPE_MASK )
06623         && !rootNav->parent()->name().isEmpty()
06624        ) // found enum docs inside a compound
06625     {
06626       if (!scope.isEmpty()) scope.prepend("::");
06627       scope.prepend(rootNav->parent()->name());
06628     }
06629     ClassDef *cd=getClass(scope);
06630 
06631     if (!name.isEmpty())
06632     {
06633       bool found=FALSE;
06634       if (cd)
06635       {
06636         //printf("Enum: scope=`%s' name=`%s'\n",cd->name(),name.data());
06637         QCString className=cd->name().copy();
06638         MemberName *mn=Doxygen::memberNameSDict->find(name);
06639         if (mn)
06640         {
06641           MemberNameIterator mni(*mn);
06642           MemberDef *md;
06643           for (mni.toFirst();(md=mni.current()) && !found;++mni)
06644           {
06645             ClassDef *cd=md->getClassDef();
06646             if (cd && cd->name()==className && md->isEnumerate())
06647             {
06648               // documentation outside a compound overrides the documentation inside it
06649 #if 0
06650               if (!md->documentation() || rootNav->parent()->name().isEmpty()) 
06651 #endif
06652               {
06653                 md->setDocumentation(root->doc,root->docFile,root->docLine);
06654                 md->setDocsForDefinition(!root->proto);
06655               }
06656 
06657               // brief descriptions inside a compound override the documentation 
06658               // outside it
06659 #if 0
06660               if (!md->briefDescription() || !rootNav->parent()->name().isEmpty())
06661 #endif
06662               {
06663                 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
06664               }
06665 
06666               if (!md->inbodyDocumentation() || !rootNav->parent()->name().isEmpty())
06667               {
06668                 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
06669               }
06670 
06671               if (root->mGrpId!=-1 && md->getMemberGroupId()==-1)
06672               {
06673                 md->setMemberGroupId(root->mGrpId);
06674               }
06675               
06676               md->addSectionsToDefinition(root->anchors);
06677 
06678               GroupDef *gd=md->getGroupDef();
06679               if (gd==0 &&root->groups->first()!=0) // member not grouped but out-of-line documentation is
06680               {
06681                 addMemberToGroups(root,md);
06682               }
06683 
06684               found=TRUE;
06685             }
06686           }
06687         }
06688         else
06689         {
06690           //printf("MemberName %s not found!\n",name.data());
06691         }
06692       }
06693       else // enum outside class 
06694       {
06695         //printf("Enum outside class: %s grpId=%d\n",name.data(),root->mGrpId);
06696         MemberName *mn=Doxygen::functionNameSDict->find(name);
06697         if (mn)
06698         {
06699           MemberNameIterator mni(*mn);
06700           MemberDef *md;
06701           for (mni.toFirst();(md=mni.current()) && !found;++mni)
06702           {
06703             if (md->isEnumerate())
06704             {
06705               md->setDocumentation(root->doc,root->docFile,root->docLine);
06706               md->setDocsForDefinition(!root->proto);
06707               md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
06708               md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
06709               md->addSectionsToDefinition(root->anchors);
06710               md->setMemberGroupId(root->mGrpId);
06711 
06712               GroupDef *gd=md->getGroupDef();
06713               if (gd==0 && root->groups->first()!=0) // member not grouped but out-of-line documentation is
06714               {
06715                 addMemberToGroups(root,md);
06716               }
06717 
06718               found=TRUE;
06719             }
06720           }
06721         }
06722       } 
06723       if (!found)
06724       {
06725         warn(root->fileName,root->startLine,
06726              "Warning: Documentation for undefined enum `%s' found.",
06727              name.data()
06728             );
06729       }
06730     }
06731 
06732     rootNav->releaseEntry();
06733   }
06734   RECURSE_ENTRYTREE(findEnumDocumentation,rootNav);
06735 }
06736 
06737 // seach for each enum (member or function) in mnl if it has documented 
06738 // enum values.
06739 static void findDEV(const MemberNameSDict &mnsd)
06740 {
06741   MemberName *mn;
06742   MemberNameSDict::Iterator mnli(mnsd);
06743   // for each member name
06744   for (mnli.toFirst();(mn=mnli.current());++mnli)
06745   {
06746     MemberDef *md;
06747     MemberNameIterator mni(*mn);
06748     // for each member definition
06749     for (mni.toFirst();(md=mni.current());++mni)
06750     {
06751       if (md->isEnumerate()) // member is an enum
06752       {
06753         LockingPtr<MemberList> fmdl = md->enumFieldList();
06754         int documentedEnumValues=0;
06755         if (fmdl!=0) // enum has values
06756         {
06757           MemberListIterator fmni(*fmdl);
06758           MemberDef *fmd;
06759           // for each enum value
06760           for (fmni.toFirst();(fmd=fmni.current());++fmni)
06761           {
06762             if (fmd->isLinkableInProject()) documentedEnumValues++;
06763           }
06764         }
06765         // at least one enum value is documented
06766         if (documentedEnumValues>0) md->setDocumentedEnumValues(TRUE);
06767       }
06768     }
06769   }
06770 }
06771 
06772 // seach for each enum (member or function) if it has documented enum 
06773 // values.
06774 static void findDocumentedEnumValues()
06775 {
06776   findDEV(*Doxygen::memberNameSDict);
06777   findDEV(*Doxygen::functionNameSDict); 
06778 }
06779 
06780 //----------------------------------------------------------------------
06781 
06782 static void addMembersToIndex()
06783 {
06784   MemberName *mn;
06785   MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
06786   // for each member name
06787   for (mnli.toFirst();(mn=mnli.current());++mnli)
06788   {
06789     MemberDef *md;
06790     MemberNameIterator mni(*mn);
06791     // for each member definition
06792     for (mni.toFirst();(md=mni.current());++mni)
06793     {
06794       addClassMemberNameToIndex(md);
06795     }
06796   }
06797   MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict);
06798   // for each member name
06799   for (fnli.toFirst();(mn=fnli.current());++fnli)
06800   {
06801     MemberDef *md;
06802     MemberNameIterator mni(*mn);
06803     // for each member definition
06804     for (mni.toFirst();(md=mni.current());++mni)
06805     {
06806       if (md->getNamespaceDef())
06807       {
06808         addNamespaceMemberNameToIndex(md);
06809       }
06810       else
06811       {
06812         addFileMemberNameToIndex(md);
06813       }
06814     }
06815   }
06816 }
06817 
06818 //----------------------------------------------------------------------
06819 // computes the relation between all members. For each member `m'
06820 // the members that override the implementation of `m' are searched and
06821 // the member that `m' overrides is searched.
06822 
06823 static void computeMemberRelations()
06824 {
06825   MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
06826   MemberName *mn;
06827   for ( ; (mn=mnli.current()) ; ++mnli ) // for each member name
06828   {
06829     MemberNameIterator mdi(*mn);
06830     MemberDef *md;
06831     for ( ; (md=mdi.current()) ; ++mdi ) // for each member with a specific arg list
06832     {
06833       MemberNameIterator bmdi(*mn);
06834       MemberDef *bmd;
06835       for ( ; (bmd=bmdi.current()) ; ++bmdi ) // for each other member with that signature
06836       {
06837         ClassDef *bmcd = bmd->getClassDef();
06838         ClassDef *mcd  = md->getClassDef();
06839         //printf("Check relation between `%s'::`%s' (%p) and `%s'::`%s' (%p)\n",
06840         //       mcd->name().data(),md->name().data(),md,
06841         //       bmcd->name().data(),bmd->name().data(),bmd
06842         //      );
06843         if (md!=bmd && bmcd && mcd && bmcd!=mcd && mcd->isBaseClass(bmcd,TRUE))
06844         {
06845           //printf(" Base argList=`%s'\n Super argList=`%s'\n",
06846           //        argListToString(bmd->argumentList()).data(),
06847           //        argListToString(md->argumentList()).data()
06848           //      );
06849           LockingPtr<ArgumentList> bmdAl = bmd->argumentList();
06850           LockingPtr<ArgumentList>  mdAl =  md->argumentList();
06851           if ( 
06852               matchArguments2(bmd->getOuterScope(),bmd->getFileDef(),bmdAl.pointer(),
06853                                md->getOuterScope(), md->getFileDef(), mdAl.pointer(),
06854                               TRUE
06855                              ) 
06856              )
06857           {
06858             //printf("  match found!\n");
06859             if (mcd && bmcd && 
06860                 mcd->isLinkable() && bmcd->isLinkable()
06861                )
06862             {
06863               MemberDef *rmd;
06864               if ((rmd=md->reimplements())==0 ||
06865                   minClassDistance(mcd,bmcd)<minClassDistance(mcd,rmd->getClassDef())
06866                  )
06867               {
06868                 //printf("setting (new) reimplements member\n");
06869                 md->setReimplements(bmd);
06870               }
06871               //printf("%s: add reimplements member %s\n",mcd->name().data(),bmcd->name().data());
06872               //md->setImplements(bmd);
06873               //printf("%s: add reimplementedBy member %s\n",bmcd->name().data(),mcd->name().data());
06874               bmd->insertReimplementedBy(md);
06875             }
06876           }  
06877         }
06878       }
06879     }
06880   }  
06881 }
06882 
06883 
06884 //----------------------------------------------------------------------------
06885 //static void computeClassImplUsageRelations()
06886 //{
06887 //  ClassDef *cd;
06888 //  ClassSDict::Iterator cli(*Doxygen::classSDict);
06889 //  for (;(cd=cli.current());++cli)
06890 //  {
06891 //    cd->determineImplUsageRelation();
06892 //  }
06893 //}
06894 
06895 //----------------------------------------------------------------------------
06896 
06897 static void createTemplateInstanceMembers()
06898 {
06899   ClassSDict::Iterator cli(*Doxygen::classSDict);
06900   ClassDef *cd;
06901   // for each class
06902   for (cli.toFirst();(cd=cli.current());++cli)
06903   {
06904     // that is a template
06905     QDict<ClassDef> *templInstances = cd->getTemplateInstances();
06906     if (templInstances)
06907     {
06908       QDictIterator<ClassDef> qdi(*templInstances);
06909       ClassDef *tcd=0;
06910       // for each instance of the template
06911       for (qdi.toFirst();(tcd=qdi.current());++qdi)
06912       {
06913         tcd->addMembersToTemplateInstance(cd,qdi.currentKey());
06914       }
06915     }
06916   }
06917 }
06918 
06919 //----------------------------------------------------------------------------
06920 
06921 // builds the list of all members for each class
06922 
06923 static void buildCompleteMemberLists()
06924 {
06925   ClassDef *cd;
06926   // merge members of categories into the class they extend
06927   ClassSDict::Iterator cli(*Doxygen::classSDict);
06928   for (cli.toFirst();(cd=cli.current());++cli)
06929   {
06930     int i=cd->name().find('(');
06931     if (i!=-1) // it is an Objective-C category
06932     {
06933       QCString baseName=cd->name().left(i);
06934       ClassDef *baseClass=Doxygen::classSDict->find(baseName);
06935       if (baseClass)
06936       {
06937         //printf("*** merging members of category %s into %s\n",
06938         //    cd->name().data(),baseClass->name().data());
06939         baseClass->mergeCategory(cd);
06940       }
06941     }
06942   }
06943   // merge the member list of base classes into the inherited classes.
06944   for (cli.toFirst();(cd=cli.current());++cli)
06945   {
06946     if (// !cd->isReference() && // not an external class
06947          cd->subClasses()==0 && // is a root of the hierarchy
06948          cd->baseClasses()) // and has at least one base class
06949     {
06950       //printf("*** merging members for %s\n",cd->name().data());
06951       cd->mergeMembers();
06952     }
06953   }
06954   // now sort the member list of all classes.
06955   for (cli.toFirst();(cd=cli.current());++cli)
06956   {
06957     if (cd->memberNameInfoSDict()) cd->memberNameInfoSDict()->sort();
06958   }
06959 }
06960 
06961 //----------------------------------------------------------------------------
06962 
06963 static void generateFileSources()
06964 {
06965   if (documentedHtmlFiles==0) return;
06966   if (Doxygen::inputNameList->count()>0)
06967   {
06968     FileNameListIterator fnli(*Doxygen::inputNameList); 
06969     FileName *fn;
06970     for (;(fn=fnli.current());++fnli)
06971     {
06972       FileNameIterator fni(*fn);
06973       FileDef *fd;
06974       for (;(fd=fni.current());++fni)
06975       {
06976         if (fd->generateSourceFile()) // sources need to be shown in the output
06977         {
06978           msg("Generating code for file %s...\n",fd->docName().data());
06979           fd->writeSource(*outputList);
06980         }
06981         else if (!fd->isReference() && Doxygen::parseSourcesNeeded)
06982           // we needed to parse the sources even if we do not show them
06983         {
06984           msg("Parsing code for file %s...\n",fd->docName().data());
06985           fd->parseSource();
06986         }
06987       }
06988     }
06989   }
06990 }
06991 
06992 //----------------------------------------------------------------------------
06993 
06994 static void generateFileDocs()
06995 {
06996   if (documentedHtmlFiles==0) return;
06997   
06998   if (Doxygen::inputNameList->count()>0)
06999   {
07000     FileNameListIterator fnli(*Doxygen::inputNameList);
07001     FileName *fn;
07002     for (fnli.toFirst();(fn=fnli.current());++fnli)
07003     {
07004       FileNameIterator fni(*fn);
07005       FileDef *fd;
07006       for (fni.toFirst();(fd=fni.current());++fni)
07007       {
07008         bool doc = fd->isLinkableInProject();
07009         if (doc)
07010         {
07011           msg("Generating docs for file %s...\n",fd->docName().data());
07012           fd->writeDocumentation(*outputList);
07013         }
07014       }
07015     }
07016   }
07017 }
07018 
07019 //----------------------------------------------------------------------------
07020 
07021 static void addSourceReferences()
07022 {
07023   // add source references for class definitions
07024   ClassSDict::Iterator cli(*Doxygen::classSDict);
07025   ClassDef *cd=0;
07026   for (cli.toFirst();(cd=cli.current());++cli)
07027   {
07028     FileDef *fd=cd->getBodyDef();
07029     if (fd && cd->isLinkableInProject() && cd->getStartBodyLine()!=-1)
07030     {
07031       fd->addSourceRef(cd->getStartBodyLine(),cd,0);
07032     }
07033   }
07034   // add source references for namespace definitions
07035   NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
07036   NamespaceDef *nd=0;
07037   for (nli.toFirst();(nd=nli.current());++nli)
07038   {
07039     FileDef *fd=nd->getBodyDef();
07040     if (fd && nd->isLinkableInProject() && nd->getStartBodyLine()!=-1)
07041     {
07042       fd->addSourceRef(nd->getStartBodyLine(),nd,0);
07043     }
07044   }
07045   
07046   // add source references for member names
07047   MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
07048   MemberName *mn=0;
07049   for (mnli.toFirst();(mn=mnli.current());++mnli)
07050   {
07051     MemberNameIterator mni(*mn);
07052     MemberDef *md=0;
07053     for (mni.toFirst();(md=mni.current());++mni)
07054     {
07055       //printf("class member %s\n",md->name().data());
07056       FileDef *fd=md->getBodyDef();
07057       if (fd && 
07058           md->getStartBodyLine()!=-1 &&
07059           md->isLinkableInProject() &&
07060           (fd->generateSourceFile() || Doxygen::parseSourcesNeeded)
07061          )
07062       {
07063         //printf("Found member `%s' in file `%s' at line `%d' def=%s\n",
07064         //    md->name().data(),fd->name().data(),md->getStartBodyLine(),md->getOuterScope()->name().data()); 
07065         fd->addSourceRef(md->getStartBodyLine(),md->getOuterScope(),md);
07066       }
07067     }
07068   }
07069   MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict);
07070   for (fnli.toFirst();(mn=fnli.current());++fnli)
07071   {
07072     MemberNameIterator mni(*mn);
07073     MemberDef *md=0;
07074     for (mni.toFirst();(md=mni.current());++mni)
07075     {
07076       FileDef *fd=md->getBodyDef();
07077       //printf("member %s body=[%d,%d] fd=%p link=%d parseSources=%d\n",
07078       //    md->name().data(),
07079       //    md->getStartBodyLine(),md->getEndBodyLine(),fd,
07080       //    md->isLinkableInProject(),
07081       //    Doxygen::parseSourcesNeeded);
07082       if (fd && 
07083           md->getStartBodyLine()!=-1 && 
07084           md->isLinkableInProject() && 
07085           (fd->generateSourceFile() || Doxygen::parseSourcesNeeded)
07086          )
07087       {
07088         //printf("Found member `%s' in file `%s' at line `%d' def=%s\n",
07089         //    md->name().data(),fd->name().data(),md->getStartBodyLine(),md->getOuterScope()->name().data()); 
07090         fd->addSourceRef(md->getStartBodyLine(),md->getOuterScope(),md);
07091       }  
07092     }
07093   }
07094 }
07095 
07096 //----------------------------------------------------------------------------
07097 // generate the documentation of all classes
07098   
07099 static void generateClassList(ClassSDict &classSDict)
07100 {
07101   ClassSDict::Iterator cli(classSDict);
07102   for ( ; cli.current() ; ++cli )
07103   {
07104     ClassDef *cd=cli.current();
07105    
07106     //printf("cd=%s getOuterScope=%p global=%p\n",cd->name().data(),cd->getOuterScope(),Doxygen::globalScope);
07107     if ((cd->getOuterScope()==0 || // <-- should not happen, but can if we read an old tag file
07108          cd->getOuterScope()==Doxygen::globalScope // only look at global classes
07109         ) && !cd->isHidden()
07110        ) 
07111     {
07112       // skip external references, anonymous compounds and 
07113       // template instances 
07114       if ( cd->isLinkableInProject() && cd->templateMaster()==0)
07115       {
07116         msg("Generating docs for compound %s...\n",cd->name().data());
07117 
07118         cd->writeDocumentation(*outputList);
07119         cd->writeMemberList(*outputList);
07120       }
07121       // even for undocumented classes, the inner classes can be documented.
07122       cd->writeDocumentationForInnerClasses(*outputList);
07123     }
07124   }
07125 }
07126 
07127 static void generateClassDocs()
07128 {
07129   // write the installdox script if necessary
07130   if (Config_getBool("GENERATE_HTML") && 
07131       (Config_getList("TAGFILES").count()>0 || 
07132        Config_getBool("SEARCHENGINE")
07133       )
07134      ) 
07135   {
07136     writeInstallScript();
07137   }
07138   
07139   msg("Generating annotated compound index...\n");
07140   writeAnnotatedIndex(*outputList);
07141 
07142   if (Config_getBool("ALPHABETICAL_INDEX"))
07143   {
07144     msg("Generating alphabetical compound index...\n");
07145     writeAlphabeticalIndex(*outputList);
07146   }
07147 
07148   msg("Generating hierarchical class index...\n");
07149   writeHierarchicalIndex(*outputList);
07150 
07151   msg("Generating member index...\n");
07152   writeClassMemberIndex(*outputList);
07153 
07154   if (Doxygen::exampleSDict->count()>0)
07155   {
07156     msg("Generating example index...\n");
07157   }
07158 
07159   generateClassList(*Doxygen::classSDict);
07160   generateClassList(*Doxygen::hiddenClasses);
07161 }
07162 
07163 //----------------------------------------------------------------------------
07164 
07165 static void inheritDocumentation()
07166 {
07167   MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
07168   MemberName *mn;
07169   //int count=0;
07170   for (;(mn=mnli.current());++mnli)
07171   {
07172     MemberNameIterator mni(*mn);
07173     MemberDef *md;
07174     for (;(md=mni.current());++mni)
07175     {
07176       //printf("%04d Member `%s'\n",count++,md->name().data());
07177       if (md->documentation().isEmpty() && md->briefDescription().isEmpty())
07178       { // no documentation yet
07179         MemberDef *bmd = md->reimplements();
07180         while (bmd && bmd->documentation().isEmpty() && 
07181                       bmd->briefDescription().isEmpty()
07182               )
07183         { // search up the inheritance tree for a documentation member
07184           //printf("bmd=%s class=%s\n",bmd->name().data(),bmd->getClassDef()->name().data());
07185           bmd = bmd->reimplements();
07186         }
07187         if (bmd) // copy the documentation from the reimplemented member
07188         {
07189           md->setInheritsDocsFrom(bmd);
07190           md->setDocumentation(bmd->documentation(),bmd->docFile(),bmd->docLine());
07191           md->setDocsForDefinition(bmd->isDocsForDefinition());
07192           md->setBriefDescription(bmd->briefDescription(),bmd->briefFile(),bmd->briefLine());
07193           md->copyArgumentNames(bmd);
07194           md->setInbodyDocumentation(bmd->inbodyDocumentation(),bmd->inbodyFile(),bmd->inbodyLine());
07195         }
07196       }
07197     }
07198   }
07199 }
07200 
07201 //----------------------------------------------------------------------------
07202 
07203 static void combineUsingRelations()
07204 {
07205   // for each file
07206   FileNameListIterator fnli(*Doxygen::inputNameList);
07207   FileName *fn;
07208   for (fnli.toFirst();(fn=fnli.current());++fnli)
07209   {
07210     FileNameIterator fni(*fn);
07211     FileDef *fd;
07212     for (fni.toFirst();(fd=fni.current());++fni)
07213     {
07214       fd->visited=FALSE;
07215     }
07216   }
07217   for (fnli.toFirst();(fn=fnli.current());++fnli)
07218   {
07219     FileNameIterator fni(*fn);
07220     FileDef *fd;
07221     for (fni.toFirst();(fd=fni.current());++fni)
07222     {
07223       fd->combineUsingRelations();
07224     }
07225   }
07226 
07227   // for each namespace
07228   NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
07229   NamespaceDef *nd;
07230   for (nli.toFirst() ; (nd=nli.current()) ; ++nli )
07231   {
07232     nd->visited=FALSE;
07233   }
07234   for (nli.toFirst() ; (nd=nli.current()) ; ++nli )
07235   {
07236     nd->combineUsingRelations();
07237   }
07238 }
07239 
07240 //----------------------------------------------------------------------------
07241   
07242 static void addMembersToMemberGroup()
07243 {
07244   // for each class
07245   ClassSDict::Iterator cli(*Doxygen::classSDict);
07246   ClassDef *cd;
07247   for ( ; (cd=cli.current()) ; ++cli )
07248   {
07249     cd->addMembersToMemberGroup();
07250   }
07251   // for each file
07252   FileName *fn=Doxygen::inputNameList->first();
07253   while (fn)
07254   {
07255     FileDef *fd=fn->first();
07256     while (fd)
07257     {
07258       fd->addMembersToMemberGroup();
07259       fd=fn->next();
07260     }
07261     fn=Doxygen::inputNameList->next();
07262   }
07263   // for each namespace
07264   NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
07265   NamespaceDef *nd;
07266   for ( ; (nd=nli.current()) ; ++nli )
07267   {
07268     nd->addMembersToMemberGroup();
07269   }
07270   // for each group
07271   GroupSDict::Iterator gli(*Doxygen::groupSDict);
07272   GroupDef *gd;
07273   for (gli.toFirst();(gd=gli.current());++gli)
07274   {
07275     gd->addMembersToMemberGroup();
07276   }
07277 }
07278 
07279 //----------------------------------------------------------------------------
07280 
07281 static void distributeMemberGroupDocumentation()
07282 {
07283   // for each class
07284   ClassSDict::Iterator cli(*Doxygen::classSDict);
07285   ClassDef *cd;
07286   for ( ; (cd=cli.current()) ; ++cli )
07287   {
07288     cd->distributeMemberGroupDocumentation();
07289   }
07290   // for each file
07291   FileName *fn=Doxygen::inputNameList->first();
07292   while (fn)
07293   {
07294     FileDef *fd=fn->first();
07295     while (fd)
07296     {
07297       fd->distributeMemberGroupDocumentation();
07298       fd=fn->next();
07299     }
07300     fn=Doxygen::inputNameList->next();
07301   }
07302   // for each namespace
07303   NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
07304   NamespaceDef *nd;
07305   for ( ; (nd=nli.current()) ; ++nli )
07306   {
07307     nd->distributeMemberGroupDocumentation();
07308   }
07309   // for each group
07310   GroupSDict::Iterator gli(*Doxygen::groupSDict);
07311   GroupDef *gd;
07312   for (gli.toFirst();(gd=gli.current());++gli)
07313   {
07314     gd->distributeMemberGroupDocumentation();
07315   }
07316 }
07317 
07318 //----------------------------------------------------------------------------
07319 
07320 static void findSectionsInDocumentation()
07321 {
07322   // for each class
07323   ClassSDict::Iterator cli(*Doxygen::classSDict);
07324   ClassDef *cd;
07325   for ( ; (cd=cli.current()) ; ++cli )
07326   {
07327     cd->findSectionsInDocumentation();
07328   }
07329   // for each file
07330   FileName *fn=Doxygen::inputNameList->first();
07331   while (fn)
07332   {
07333     FileDef *fd=fn->first();
07334     while (fd)
07335     {
07336       fd->findSectionsInDocumentation();
07337       fd=fn->next();
07338     }
07339     fn=Doxygen::inputNameList->next();
07340   }
07341   // for each namespace
07342   NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
07343   NamespaceDef *nd;
07344   for ( ; (nd=nli.current()) ; ++nli )
07345   {
07346     nd->findSectionsInDocumentation();
07347   }
07348   // for each group
07349   GroupSDict::Iterator gli(*Doxygen::groupSDict);
07350   GroupDef *gd;
07351   for (gli.toFirst();(gd=gli.current());++gli)
07352   {
07353     gd->findSectionsInDocumentation();
07354   }
07355   // for each page
07356   PageSDict::Iterator pdi(*Doxygen::pageSDict);
07357   PageDef *pd=0;
07358   for (pdi.toFirst();(pd=pdi.current());++pdi)
07359   {
07360     pd->findSectionsInDocumentation();
07361   }
07362   if (Doxygen::mainPage) Doxygen::mainPage->findSectionsInDocumentation();
07363 }
07364 
07365 static void flushCachedTemplateRelations()
07366 {
07367   // remove all references to classes from the cache
07368   // as there can be new template instances in the inheritance path
07369   // to this class. Optimization: only remove those classes that
07370   // have inheritance instances as direct or indirect sub classes.
07371   QCacheIterator<LookupInfo> ci(Doxygen::lookupCache);
07372   LookupInfo *li=0;
07373   for (ci.toFirst();(li=ci.current());++ci)
07374   {
07375     if (li->classDef)
07376     {
07377       Doxygen::lookupCache.remove(ci.currentKey());
07378     }
07379   }
07380   // remove all cached typedef resolutions whose target is a
07381   // template class as this may now be a template instance
07382   MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict);
07383   MemberName *fn;
07384   for (;(fn=fnli.current());++fnli) // for each global function name
07385   {
07386     MemberNameIterator fni(*fn);
07387     MemberDef *fmd;
07388     for (;(fmd=fni.current());++fni) // for each function with that name
07389     {
07390       if (fmd->isTypedefValCached())
07391       {
07392         ClassDef *cd = fmd->getCachedTypedefVal();
07393         if (cd->isTemplate()) fmd->invalidateTypedefValCache();
07394       }
07395     }
07396   }
07397   MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
07398   for (;(fn=mnli.current());++mnli) // for each class method name
07399   {
07400     MemberNameIterator mni(*fn);
07401     MemberDef *fmd;
07402     for (;(fmd=mni.current());++mni) // for each function with that name
07403     {
07404       if (fmd->isTypedefValCached())
07405       {
07406         ClassDef *cd = fmd->getCachedTypedefVal();
07407         if (cd->isTemplate()) fmd->invalidateTypedefValCache();
07408       }
07409     }
07410   }
07411 }
07412 
07413 //----------------------------------------------------------------------------
07414 
07415 static void flushUnresolvedRelations()
07416 {
07417   // Remove all unresolved references to classes from the cache.
07418   // This is needed before resolving the inheritance relations, since
07419   // it would otherwise not find the inheritance relation
07420   // for C in the example below, as B::I was already found to be unresolvable 
07421   // (which is correct if you igore the inheritance relation between A and B).
07422   // 
07423   // class A { class I {} };
07424   // class B : public A {};
07425   // class C : public B::I {};
07426   //
07427   QCacheIterator<LookupInfo> ci(Doxygen::lookupCache);
07428   LookupInfo *li=0;
07429   for (ci.toFirst();(li=ci.current());++ci)
07430   {
07431     if (li->classDef==0 && li->typeDef==0)
07432     {
07433       Doxygen::lookupCache.remove(ci.currentKey());
07434     }
07435   }
07436 }
07437 
07438 //----------------------------------------------------------------------------
07439 
07440 static void findDefineDocumentation(EntryNav *rootNav)
07441 {
07442   if ((rootNav->section()==Entry::DEFINEDOC_SEC ||
07443        rootNav->section()==Entry::DEFINE_SEC) && !rootNav->name().isEmpty()
07444      )
07445   {
07446     rootNav->loadEntry(g_storage);
07447     Entry *root = rootNav->entry();
07448     
07449     //printf("found define `%s' `%s' brief=`%s' doc=`%s'\n",
07450     //       root->name.data(),root->args.data(),root->brief.data(),root->doc.data());
07451 
07452     if (rootNav->tagInfo() && !root->name.isEmpty()) // define read from a tag file
07453     {
07454       MemberDef *md=new MemberDef("<tagfile>",1,
07455                     "#define",root->name,root->args,0,
07456                     Public,Normal,FALSE,FALSE,MemberDef::Define,0,0);
07457       md->setTagInfo(rootNav->tagInfo());
07458       //printf("Searching for `%s' fd=%p\n",filePathName.data(),fd);
07459       md->setFileDef(rootNav->parent()->fileDef());
07460       //printf("Adding member=%s\n",md->name().data());
07461       MemberName *mn;
07462       if ((mn=Doxygen::functionNameSDict->find(root->name)))
07463       {
07464         mn->append(md);
07465       }
07466       else 
07467       {
07468         mn = new MemberName(root->name);
07469         mn->append(md);
07470         Doxygen::functionNameSDict->append(root->name,mn);
07471       }
07472     }
07473     MemberName *mn=Doxygen::functionNameSDict->find(root->name);
07474     if (mn)
07475     {
07476       int count=0;
07477       MemberDef *md=mn->first();
07478       while (md)
07479       {
07480         if (md->memberType()==MemberDef::Define) count++;
07481         md=mn->next();
07482       }
07483       if (count==1)
07484       {
07485         md=mn->first();
07486         while (md)
07487         {
07488           if (md->memberType()==MemberDef::Define)
07489           {
07490 #if 0
07491             if (md->documentation().isEmpty())
07492 #endif
07493             {
07494               md->setDocumentation(root->doc,root->docFile,root->docLine);
07495               md->setDocsForDefinition(!root->proto);
07496             }
07497 #if 0
07498             if (md->briefDescription().isEmpty())
07499 #endif
07500             {
07501               md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
07502             }
07503             if (md->inbodyDocumentation().isEmpty())
07504             {
07505               md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
07506             }
07507             md->setBodySegment(root->bodyLine,root->endBodyLine);
07508             md->setBodyDef(rootNav->fileDef());
07509             md->addSectionsToDefinition(root->anchors);
07510             md->setMaxInitLines(root->initLines);
07511             md->setRefItems(root->sli);
07512             if (root->mGrpId!=-1) md->setMemberGroupId(root->mGrpId);
07513             addMemberToGroups(root,md);
07514           }
07515           md=mn->next();
07516         }
07517       }
07518       else if (count>1 && 
07519                (!root->doc.isEmpty() || 
07520                 !root->brief.isEmpty() || 
07521                 root->bodyLine!=-1
07522                )
07523               ) 
07524         // multiple defines don't know where to add docs
07525         // but maybe they are in different files together with their documentation
07526       {
07527         md=mn->first();
07528         while (md)
07529         {
07530           if (md->memberType()==MemberDef::Define)
07531           {
07532             FileDef *fd=md->getFileDef();
07533             if (fd && fd->absFilePath()==root->fileName) 
07534               // doc and define in the same file assume they belong together.
07535             {
07536 #if 0
07537               if (md->documentation().isEmpty())
07538 #endif
07539               {
07540                 md->setDocumentation(root->doc,root->docFile,root->docLine);
07541                 md->setDocsForDefinition(!root->proto);
07542               }
07543 #if 0
07544               if (md->briefDescription().isEmpty())
07545 #endif
07546               {
07547                 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
07548               }
07549               if (md->inbodyDocumentation().isEmpty())
07550               {
07551                 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
07552               }
07553               md->setBodySegment(root->bodyLine,root->endBodyLine);
07554               md->setBodyDef(rootNav->fileDef());
07555               md->addSectionsToDefinition(root->anchors);
07556               md->setRefItems(root->sli);
07557               if (root->mGrpId!=-1) md->setMemberGroupId(root->mGrpId);
07558               addMemberToGroups(root,md);
07559             }
07560           }
07561           md=mn->next();
07562         }
07563         //warn("Warning: define %s found in the following files:\n",root->name.data());
07564         //warn("Cannot determine where to add the documentation found "
07565         //     "at line %d of file %s. \n",
07566         //     root->startLine,root->fileName.data());
07567       }
07568     }
07569     else if (!root->doc.isEmpty() || !root->brief.isEmpty()) // define not found
07570     {
07571       static bool preEnabled = Config_getBool("ENABLE_PREPROCESSING");
07572       if (preEnabled)
07573       {
07574         warn(root->fileName,root->startLine,
07575              "Warning: documentation for unknown define %s found.\n",
07576              root->name.data()
07577             );
07578       }
07579       else
07580       {
07581         warn(root->fileName,root->startLine,
07582              "Warning: found documented #define but ignoring it because "
07583              "ENABLE_PREPROCESSING is NO.\n",
07584              root->name.data()
07585             );
07586       }
07587     }
07588 
07589     rootNav->releaseEntry();
07590   }
07591   RECURSE_ENTRYTREE(findDefineDocumentation,rootNav);
07592 }
07593 
07594 //----------------------------------------------------------------------------
07595 
07596 static void findDirDocumentation(EntryNav *rootNav)
07597 {
07598   if (rootNav->section() == Entry::DIRDOC_SEC)
07599   {
07600     rootNav->loadEntry(g_storage);
07601     Entry *root = rootNav->entry();
07602 
07603     QCString normalizedName = root->name;
07604     normalizedName = substitute(normalizedName,"\\","/");
07605     if (normalizedName.at(normalizedName.length()-1)!='/')
07606     {
07607       normalizedName+='/';
07608     }
07609     DirDef *dir,*matchingDir=0;
07610     SDict<DirDef>::Iterator sdi(*Doxygen::directories);
07611     for (sdi.toFirst();(dir=sdi.current());++sdi)
07612     {
07613       //printf("Dir: %s<->%s\n",dir->name().data(),normalizedName.data());
07614       if (dir->name().right(normalizedName.length())==normalizedName)
07615       {
07616         if (matchingDir)
07617         {
07618            warn(root->fileName,root->startLine,
07619              "Warning: \\dir command matches multiple directories.\n"
07620              "  Applying the command for directory %s\n"
07621              "  Ignoring the command for directory %s\n",
07622              matchingDir->name().data(),dir->name().data()
07623            );
07624         }
07625         else
07626         {
07627           matchingDir=dir;
07628         }
07629       }
07630     }
07631     if (matchingDir)
07632     {
07633       //printf("Match for with dir %s\n",matchingDir->name().data());
07634       matchingDir->setBriefDescription(root->brief,root->briefFile,root->briefLine);
07635       matchingDir->setDocumentation(root->doc,root->docFile,root->docLine);
07636       addDirToGroups(root,matchingDir);
07637     }
07638     else
07639     {
07640       warn(root->fileName,root->startLine,"Warning: No matching "
07641           "directory found for command \\dir %s\n",root->name.data());
07642     }
07643     rootNav->releaseEntry();
07644   }
07645   RECURSE_ENTRYTREE(findDirDocumentation,rootNav);
07646 }
07647 
07648 
07649 //----------------------------------------------------------------------------
07650 // create a (sorted) list of separate documentation pages
07651 
07652 static void buildPageList(EntryNav *rootNav)
07653 {
07654   if (rootNav->section() == Entry::PAGEDOC_SEC)
07655   {
07656     rootNav->loadEntry(g_storage);
07657     Entry *root = rootNav->entry();
07658 
07659     if (!root->name.isEmpty())
07660     {
07661       addRelatedPage(rootNav);
07662     }
07663 
07664     rootNav->releaseEntry();
07665   }
07666   else if (rootNav->section() == Entry::MAINPAGEDOC_SEC)
07667   {
07668     rootNav->loadEntry(g_storage);
07669     Entry *root = rootNav->entry();
07670 
07671     QCString title=root->args.stripWhiteSpace();
07672     if (title.isEmpty()) title=theTranslator->trMainPage();
07673     addRefItem(root->sli,"page",
07674                Config_getBool("GENERATE_TREEVIEW")?"main":"index",
07675                title
07676               );
07677 
07678     rootNav->releaseEntry();
07679   }
07680   RECURSE_ENTRYTREE(buildPageList,rootNav);
07681 }
07682 
07683 static void findMainPage(EntryNav *rootNav)
07684 {
07685   if (rootNav->section() == Entry::MAINPAGEDOC_SEC)
07686   {
07687     rootNav->loadEntry(g_storage);
07688     Entry *root = rootNav->entry();
07689 
07690     if (Doxygen::mainPage==0)
07691     {
07692       //printf("Found main page! \n======\n%s\n=======\n",root->doc.data());
07693       QCString title=root->args.stripWhiteSpace();
07694       QCString indexName=Config_getBool("GENERATE_TREEVIEW")?"main":"index";
07695       Doxygen::mainPage = new PageDef(root->fileName,root->startLine,
07696                               indexName, root->brief+root->doc,title);
07697       //setFileNameForSections(root->anchors,"index",Doxygen::mainPage);
07698       Doxygen::mainPage->setFileName(indexName);
07699       addPageToContext(Doxygen::mainPage,rootNav);
07700           
07701       // a page name is a label as well!
07702       SectionInfo *si=new SectionInfo(
07703           indexName,
07704           Doxygen::mainPage->name(),
07705           Doxygen::mainPage->title(),
07706           SectionInfo::Section);
07707       Doxygen::sectionDict.insert(indexName,si);
07708       Doxygen::mainPage->addSectionsToDefinition(root->anchors);
07709     }
07710     else
07711     {
07712       warn(root->fileName,root->startLine,
07713            "Warning: found more than one \\mainpage comment block! Skipping this "
07714            "block."
07715           );
07716     }
07717 
07718     rootNav->releaseEntry();
07719   }
07720   RECURSE_ENTRYTREE(findMainPage,rootNav);
07721 }
07722 
07723 static void computePageRelations(EntryNav *rootNav)
07724 {
07725   if ((rootNav->section()==Entry::PAGEDOC_SEC || 
07726        rootNav->section()==Entry::MAINPAGEDOC_SEC
07727       )
07728       && !rootNav->name().isEmpty()
07729      )
07730   {
07731     rootNav->loadEntry(g_storage);
07732     Entry *root = rootNav->entry();
07733 
07734     PageDef *pd = root->section==Entry::PAGEDOC_SEC ?
07735                     Doxygen::pageSDict->find(root->name) : 
07736                     Doxygen::mainPage; 
07737     if (pd)
07738     {
07739       QListIterator<BaseInfo> bii(*root->extends);
07740       BaseInfo *bi;
07741       for (bii.toFirst();(bi=bii.current());++bii)
07742       {
07743         PageDef *subPd = Doxygen::pageSDict->find(bi->name);
07744         if (subPd)
07745         {
07746           pd->addInnerCompound(subPd);
07747           //printf("*** Added subpage relation: %s->%s\n",
07748           //    pd->name().data(),subPd->name().data());
07749         }
07750       }
07751     }
07752 
07753     rootNav->releaseEntry();
07754   }
07755   RECURSE_ENTRYTREE(computePageRelations,rootNav);
07756 }
07757 
07758 static void checkPageRelations()
07759 {
07760   PageSDict::Iterator pdi(*Doxygen::pageSDict);
07761   PageDef *pd=0;
07762   for (pdi.toFirst();(pd=pdi.current());++pdi)
07763   {
07764     Definition *ppd = pd->getOuterScope();
07765     while (ppd)
07766     {
07767       if (ppd==pd)
07768       {
07769         err("Warning: page defined at line %d of file %s with label %s is a subpage "
07770             "of itself! Please remove this cyclic dependency.\n",
07771             pd->docLine(),pd->docFile().data(),pd->name().data());
07772         exit(1);
07773       }
07774       ppd=ppd->getOuterScope();
07775     }
07776   }
07777 }
07778 
07779 //----------------------------------------------------------------------------
07780 
07781 static void resolveUserReferences()
07782 {
07783   QDictIterator<SectionInfo> sdi(Doxygen::sectionDict);
07784   SectionInfo *si;
07785   for (;(si=sdi.current());++sdi)
07786   {
07787     //printf("si->label=`%s' si->definition=%s si->fileName=`%s'\n",
07788     //        si->label.data(),si->definition?si->definition->name().data():"<none>",
07789     //        si->fileName.data());
07790     PageDef *pd=0;
07791 
07792     // hack: the items of a todo/test/bug/deprecated list are all fragments from 
07793     // different files, so the resulting section's all have the wrong file 
07794     // name (not from the todo/test/bug/deprecated list, but from the file in 
07795     // which they are defined). We correct this here by looking at the 
07796     // generated section labels!
07797     QDictIterator<RefList> rli(*Doxygen::xrefLists);
07798     RefList *rl;
07799     for (rli.toFirst();(rl=rli.current());++rli)
07800     {
07801       QCString label="_"+rl->listName(); // "_todo", "_test", ...
07802       if (si->label.left(label.length())==label)
07803       {
07804         si->fileName=rl->listName();
07805         si->generated=TRUE;
07806         break;
07807       }
07808     }
07809 
07810     //printf("start: si->label=%s si->fileName=%s\n",si->label.data(),si->fileName.data());
07811     if (!si->generated)
07812     {
07813       // if this section is in a page and the page is in a group, then we
07814       // have to adjust the link file name to point to the group.
07815       if (!si->fileName.isEmpty() && 
07816           (pd=Doxygen::pageSDict->find(si->fileName)) &&
07817           pd->getGroupDef())
07818       {
07819         si->fileName=pd->getGroupDef()->getOutputFileBase().copy();
07820       }
07821 
07822       if (si->definition)
07823       {
07824         // TODO: there should be one function in Definition that returns
07825         // the file to link to, so we can avoid the following tests.
07826         GroupDef *gd=0;
07827         if (si->definition->definitionType()==Definition::TypeMember)
07828         {
07829           gd = ((MemberDef *)si->definition)->getGroupDef();
07830         }
07831 
07832         if (gd)
07833         {
07834           si->fileName=gd->getOutputFileBase().copy();
07835         }
07836         else
07837         {
07838           //si->fileName=si->definition->getOutputFileBase().copy();
07839           //printf("Setting si->fileName to %s\n",si->fileName.data());
07840         }
07841       }
07842     }
07843     //printf("end: si->label=%s si->fileName=%s\n",si->label.data(),si->fileName.data());
07844   }
07845 }
07846 
07847 
07848 //----------------------------------------------------------------------------
07849 // generate all separate documentation pages
07850 
07851 
07852 static void generatePageDocs()
07853 {
07854   //printf("documentedPages=%d real=%d\n",documentedPages,Doxygen::pageSDict->count());
07855   if (documentedPages==0) return;
07856   PageSDict::Iterator pdi(*Doxygen::pageSDict);
07857   PageDef *pd=0;
07858   for (pdi.toFirst();(pd=pdi.current());++pdi)
07859   {
07860     if (!pd->getGroupDef() && !pd->isReference())
07861     {
07862       msg("Generating docs for page %s...\n",pd->name().data());
07863       Doxygen::insideMainPage=TRUE;
07864       pd->writeDocumentation(*outputList);
07865       Doxygen::insideMainPage=FALSE;
07866     }
07867   }
07868 }
07869 
07870 //----------------------------------------------------------------------------
07871 // create a (sorted) list & dictionary of example pages
07872 
07873 static void buildExampleList(EntryNav *rootNav)
07874 {
07875   if (rootNav->section()==Entry::EXAMPLE_SEC && !rootNav->name().isEmpty()) 
07876   {
07877     rootNav->loadEntry(g_storage);
07878     Entry *root = rootNav->entry();
07879 
07880     if (Doxygen::exampleSDict->find(root->name))
07881     {
07882       warn(root->fileName,root->startLine,
07883           "Warning: Example %s was already documented. Ignoring "
07884           "documentation found here.",
07885           root->name.data()
07886           );
07887     }
07888     else
07889     {
07890       PageDef *pd=new PageDef(root->fileName,root->startLine,
07891           root->name,root->brief+root->doc,root->args);
07892       pd->setFileName(convertNameToFile(pd->name()+"-example"));
07893       pd->addSectionsToDefinition(root->anchors);
07894       //pi->addSections(root->anchors);
07895 
07896       Doxygen::exampleSDict->inSort(root->name,pd);
07897       //we don't add example to groups 
07898       //addExampleToGroups(root,pd);
07899     }
07900 
07901     rootNav->releaseEntry();
07902   }
07903   RECURSE_ENTRYTREE(buildExampleList,rootNav);
07904 }
07905 
07906 //----------------------------------------------------------------------------
07907 // prints the Entry tree (for debugging)
07908 
07909 void printNavTree(EntryNav *rootNav,int indent)
07910 {
07911   QCString indentStr;
07912   indentStr.fill(' ',indent);
07913   msg("%s%s (sec=0x%x)\n",
07914       indentStr.isEmpty()?"":indentStr.data(),
07915       rootNav->name().isEmpty()?"<empty>":rootNav->name().data(),
07916       rootNav->section());
07917   if (rootNav->children()) 
07918   {
07919     EntryNavListIterator eli(*rootNav->children());
07920     for (;eli.current();++eli) printNavTree(eli.current(),indent+2);
07921   }
07922 }
07923 
07924 
07925 //----------------------------------------------------------------------------
07926 // generate the example documentation 
07927 
07928 static void generateExampleDocs()
07929 {
07930   outputList->disable(OutputGenerator::Man);
07931   PageSDict::Iterator pdi(*Doxygen::exampleSDict);
07932   PageDef *pd=0;
07933   for (pdi.toFirst();(pd=pdi.current());++pdi)
07934   {
07935     msg("Generating docs for example %s...\n",pd->name().data());
07936     resetCCodeParserState();
07937     QCString n=pd->getOutputFileBase();
07938     startFile(*outputList,n,n,pd->name());
07939     startTitle(*outputList,n);
07940     outputList->docify(pd->name());
07941     endTitle(*outputList,n,0);
07942     outputList->parseDoc(pd->docFile(),                            // file
07943                          pd->docLine(),                            // startLine
07944                          pd,                                       // context
07945                          0,                                        // memberDef
07946                          pd->documentation()+"\n\n\\include "+pd->name(),          // docs
07947                          TRUE,                                     // index words
07948                          TRUE,                                     // is example
07949                          pd->name()
07950                         );
07951     endFile(*outputList);
07952   }
07953   outputList->enable(OutputGenerator::Man);
07954 }
07955 
07956 //----------------------------------------------------------------------------
07957 // generate module pages
07958 
07959 static void generateGroupDocs()
07960 {
07961   GroupSDict::Iterator gli(*Doxygen::groupSDict);
07962   GroupDef *gd;
07963   for (gli.toFirst();(gd=gli.current());++gli)
07964   {
07965     if (!gd->isReference())
07966     {
07967       gd->writeDocumentation(*outputList);
07968     }
07969   }
07970 }
07971 
07972 //----------------------------------------------------------------------------
07973 
07974 //static void generatePackageDocs()
07975 //{
07976 //  writePackageIndex(*outputList);
07977 //  
07978 //  if (Doxygen::packageDict.count()>0)
07979 //  {
07980 //    PackageSDict::Iterator pdi(Doxygen::packageDict);
07981 //    PackageDef *pd;
07982 //    for (pdi.toFirst();(pd=pdi.current());++pdi)
07983 //    {
07984 //      pd->writeDocumentation(*outputList);
07985 //    }
07986 //  }
07987 //}
07988 
07989 //----------------------------------------------------------------------------
07990 // generate module pages
07991 
07992 static void generateNamespaceDocs()
07993 {
07994   writeNamespaceIndex(*outputList);
07995   
07996   NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
07997   NamespaceDef *nd;
07998   // for each namespace...
07999   for (;(nd=nli.current());++nli)
08000   {
08001     if (nd->isLinkableInProject())
08002     {
08003       msg("Generating docs for namespace %s\n",nd->name().data());
08004       nd->writeDocumentation(*outputList);
08005     }
08006     // for each class in the namespace...
08007     ClassSDict::Iterator cli(*nd->getClassSDict());
08008     for ( ; cli.current() ; ++cli )
08009     {
08010       ClassDef *cd=cli.current();
08011       if ( ( cd->isLinkableInProject() && 
08012              cd->templateMaster()==0
08013            ) // skip external references, anonymous compounds and 
08014              // template instances and nested classes
08015            && !cd->isHidden()
08016          )
08017       {
08018         msg("Generating docs for compound %s...\n",cd->name().data());
08019 
08020         cd->writeDocumentation(*outputList);
08021         cd->writeMemberList(*outputList);
08022       }
08023       cd->writeDocumentationForInnerClasses(*outputList);
08024     }
08025   }
08026 }
08027 
08028 #if defined(_WIN32)
08029 static QCString fixSlashes(QCString &s)
08030 {
08031   QCString result;
08032   uint i;
08033   for (i=0;i<s.length();i++)
08034   {
08035     switch(s.at(i))
08036     {
08037       case '/': 
08038       case '\\': 
08039         result+="\\\\"; 
08040         break;
08041       default:
08042         result+=s.at(i);
08043     }
08044   }
08045   return result;
08046 }
08047 #endif
08048 
08049 
08050 //----------------------------------------------------------------------------
08051 // generate files for the search engine
08052 
08053 //static void generateSearchIndex()
08054 //{
08055 //  if (Config_getBool("SEARCHENGINE") && Config_getBool("GENERATE_HTML"))
08056 //  {
08057 //    // create search index
08058 //    QCString fileName;
08059 //    writeSearchButton(Config_getString("HTML_OUTPUT"));
08060 //
08061 //#if !defined(_WIN32)
08062 //    // create cgi script
08063 //    fileName = Config_getString("HTML_OUTPUT")+"/"+Config_getString("CGI_NAME");
08064 //    QFile f(fileName);
08065 //    if (f.open(IO_WriteOnly))
08066 //    {
08067 //      QTextStream t(&f);
08068 //      t << "#!/bin/sh"   << endl
08069 //        << "DOXYSEARCH=" << Config_getString("BIN_ABSPATH") << "/doxysearch" << endl
08070 //        << "DOXYPATH=\"" << Config_getString("DOC_ABSPATH") << " ";
08071 //
08072 //      QStrList &extDocPaths=Config_getList("EXT_DOC_PATHS");
08073 //      char *s= extDocPaths.first();
08074 //      while (s)
08075 //      {
08076 //        t << s << " ";
08077 //        s=extDocPaths.next();
08078 //      }
08079 //
08080 //      t << "\"" << endl 
08081 //        << "if [ -f $DOXYSEARCH ]" << endl
08082 //        << "then" << endl
08083 //        << "  $DOXYSEARCH $DOXYPATH" << endl 
08084 //        << "else" << endl
08085 //        << "  echo \"Content-Type: text/html\"" << endl
08086 //        << "  echo \"\"" << endl
08087 //        << "  echo \"<h2>Error: $DOXYSEARCH not found. Check cgi script!</h2>\"" << endl
08088 //        << "fi" << endl;
08089 //
08090 //      f.close();
08091 //      struct stat stat_struct;
08092 //      stat(fileName,&stat_struct);
08093 //      chmod(fileName,stat_struct.st_mode|S_IXUSR|S_IXGRP|S_IXOTH);
08094 //    }
08095 //    else
08096 //    {
08097 //      err("Error: Cannot open file %s for writing\n",fileName.data());
08098 //    }
08099 //#else /* Windows platform */
08100 //    // create cgi program
08101 //    fileName = Config_getString("CGI_NAME").copy();
08102 //    if (fileName.right(4)==".cgi") 
08103 //      fileName=fileName.left(fileName.length()-4);
08104 //    fileName+=".c";
08105 //    fileName.prepend(Config_getString("HTML_OUTPUT")+"/");
08106 //    QFile f(fileName);
08107 //    if (f.open(IO_WriteOnly))
08108 //    {
08109 //      QTextStream t(&f);
08110 //      t << "#include <stdio.h>" << endl;
08111 //      t << "#include <stdlib.h>" << endl;
08112 //      t << "#include <process.h>" << endl;
08113 //      t << endl;
08114 //      t << "const char *DOXYSEARCH = \"" << 
08115 //           fixSlashes(Config_getString("BIN_ABSPATH")) << "\\\\doxysearch.exe\";" << endl;
08116 //      t << "const char *DOXYPATH = \"" << 
08117 //           fixSlashes(Config_getString("DOC_ABSPATH")) << "\";" << endl;
08118 //      t << endl;
08119 //      t << "int main(void)" << endl;
08120 //      t << "{" << endl;
08121 //      t << "  char buf[1024];" << endl;
08122 //      t << "  sprintf(buf,\"%s %s\",DOXYSEARCH,DOXYPATH);" << endl; 
08123 //      t << "  if (system(buf))" << endl;
08124 //      t << "  {" << endl;
08125 //      t << "    printf(\"Content-Type: text/html\\n\\n\");" << endl;
08126 //      t << "    printf(\"<h2>Error: failed to execute %s</h2>\\n\",DOXYSEARCH);" << endl;
08127 //      t << "    exit(1);" << endl;
08128 //      t << "  }" << endl;
08129 //      t << "  return 0;" << endl;
08130 //      t << "}" << endl;
08131 //      f.close();
08132 //    }
08133 //    else
08134 //    {
08135 //      err("Error: Cannot open file %s for writing\n",fileName.data());
08136 //    }
08137 //#endif /* !defined(_WIN32) */
08138 //    
08139 //    // create config file
08140 //    fileName = Config_getString("HTML_OUTPUT")+"/search.cfg";
08141 //    f.setName(fileName);
08142 //    if (f.open(IO_WriteOnly))
08143 //    {
08144 //      QTextStream t(&f);
08145 //      t << Config_getString("DOC_URL") << "/" << endl 
08146 //        << Config_getString("CGI_URL") << "/" << Config_getString("CGI_NAME") << endl;
08147 //      f.close();
08148 //    }
08149 //    else
08150 //    {
08151 //      err("Error: Cannot open file %s for writing\n",fileName.data());
08152 //    }
08153 //    //outputList->generateExternalIndex();
08154 //    outputList->pushGeneratorState();
08155 //    outputList->disableAllBut(OutputGenerator::Html);
08156 //    startFile(*outputList,"header"+Doxygen::htmlFileExtension,0,"Search Engine",TRUE);
08157 //    outputList->endPlainFile();
08158 //    outputList->startPlainFile("footer"+Doxygen::htmlFileExtension);
08159 //    endFile(*outputList,TRUE);
08160 //    outputList->popGeneratorState();
08161 //  }
08162 //}
08163 
08164 //----------------------------------------------------------------------------
08165 
08166 static bool openOutputFile(const char *outFile,QFile &f)
08167 {
08168   bool fileOpened=FALSE;
08169   bool writeToStdout=(outFile[0]=='-' && outFile[1]=='\0');
08170   if (writeToStdout) // write to stdout
08171   {
08172     fileOpened = f.open(IO_WriteOnly,stdout);
08173   }
08174   else // write to file
08175   {
08176     QFileInfo fi(outFile);
08177     if (fi.exists()) // create a backup
08178     {
08179       QDir dir=fi.dir();
08180       QFileInfo backup(fi.fileName()+".bak");
08181       if (backup.exists()) // remove existing backup
08182         dir.remove(backup.fileName());
08183       dir.rename(fi.fileName(),fi.fileName()+".bak");
08184     } 
08185     f.setName(outFile);
08186     fileOpened = f.open(IO_WriteOnly|IO_Translate);
08187   }
08188   return fileOpened;
08189 }
08190 
08195 static void generateConfigFile(const char *configFile,bool shortList,
08196                                bool updateOnly=FALSE)
08197 {
08198   QFile f;
08199   bool fileOpened=openOutputFile(configFile,f);
08200   bool writeToStdout=(configFile[0]=='-' && configFile[1]=='\0');
08201   if (fileOpened)
08202   {
08203     QTextStream t(&f);
08204     t.setEncoding(QTextStream::UnicodeUTF8);
08205     Config::instance()->writeTemplate(t,shortList,updateOnly);
08206     if (!writeToStdout)
08207     {
08208       if (!updateOnly)
08209       {
08210         msg("\n\nConfiguration file `%s' created.\n\n",configFile);
08211         msg("Now edit the configuration file and enter\n\n");
08212         if (strcmp(configFile,"Doxyfile") || strcmp(configFile,"doxyfile"))
08213           msg("  doxygen %s\n\n",configFile);
08214         else
08215           msg("  doxygen\n\n");
08216         msg("to generate the documentation for your project\n\n");
08217       }
08218       else
08219       {
08220         msg("\n\nConfiguration file `%s' updated.\n\n",configFile);
08221       }
08222     }
08223   }
08224   else
08225   {
08226     err("Error: Cannot open file %s for writing\n",configFile);
08227     exit(1);
08228   }
08229 }
08230 
08231 //----------------------------------------------------------------------------
08232 // read and parse a tag file
08233 
08234 //static bool readLineFromFile(QFile &f,QCString &s)
08235 //{
08236 //  char c=0;
08237 //  s.resize(0);
08238 //  while (!f.atEnd() && (c=f.getch())!='\n') s+=c;
08239 //  return f.atEnd();
08240 //}
08241 
08242 //----------------------------------------------------------------------------
08243 
08244 static void readTagFile(Entry *root,const char *tl)
08245 {
08246   QCString tagLine = tl;
08247   QCString fileName;
08248   QCString destName;
08249   int eqPos = tagLine.find('=');
08250   if (eqPos!=-1) // tag command contains a destination
08251   {
08252     fileName = tagLine.left(eqPos).stripWhiteSpace();
08253     destName = tagLine.right(tagLine.length()-eqPos-1).stripWhiteSpace();
08254     QFileInfo fi(fileName);
08255     Doxygen::tagDestinationDict.insert(fi.fileName(),new QCString(destName));
08256     //printf("insert tagDestination %s->%s\n",fi.fileName().data(),destName.data());
08257   }
08258   else
08259   {
08260     fileName = tagLine;
08261   }
08262     
08263   QFileInfo fi(fileName);
08264   if (!fi.exists() || !fi.isFile())
08265   {
08266     err("Error: Tag file `%s' does not exist or is not a file. Skipping it...\n",
08267         fileName.data());
08268     return;
08269   }
08270 
08271   if (!destName.isEmpty())
08272     msg("Reading tag file `%s', location `%s'...\n",fileName.data(),destName.data());
08273   else
08274     msg("Reading tag file `%s'...\n",fileName.data());
08275 
08276   parseTagFile(root,fi.absFilePath(),fi.fileName());
08277 
08278 }
08279 
08280 //----------------------------------------------------------------------------
08281 // returns TRUE if the name of the file represented by `fi' matches
08282 // one of the file patterns in the `patList' list.
08283 
08284 static bool patternMatch(QFileInfo *fi,QStrList *patList)
08285 {
08286   bool found=FALSE;
08287   if (patList)
08288   { 
08289     QCString pattern=patList->first();
08290     while (!pattern.isEmpty() && !found)
08291     {
08292       int i=pattern.find('=');
08293       if (i!=-1) pattern=pattern.left(i); // strip of the extension specific filter name
08294 
08295 #if defined(_WIN32) // windows
08296       QRegExp re(pattern,FALSE,TRUE); // case insensitive match 
08297 #else                // unix
08298       QRegExp re(pattern,TRUE,TRUE);  // case sensitive match
08299 #endif
08300       found = found || re.match(fi->fileName())!=-1 || 
08301                        re.match(fi->filePath())!=-1 ||
08302                        re.match(fi->absFilePath())!=-1;
08303       //printf("Matching `%s' against pattern `%s' found=%d\n",
08304       //    fi->fileName().data(),pattern.data(),found);
08305       pattern=patList->next();
08306     }
08307   }
08308   return found;
08309 }
08310 
08311 static int transcodeCharacterBuffer(BufStr &srcBuf,int size,
08312            const char *inputEncoding,const char *outputEncoding)
08313 {
08314   if (inputEncoding==0 || outputEncoding==0) return size;
08315   if (qstricmp(inputEncoding,outputEncoding)==0) return size;
08316   void *cd = portable_iconv_open(outputEncoding,inputEncoding);
08317   if (cd==(void *)(-1)) 
08318   {
08319     err("Error: unsupported character conversion: '%s'->'%s': %s\n"
08320         "Check the INPUT_ENCODING setting in the config file!\n",
08321         inputEncoding,outputEncoding,strerror(errno));
08322     exit(1);
08323   }
08324   int tmpBufSize=size*4+1;
08325   BufStr tmpBuf(tmpBufSize);
08326   size_t iLeft=size;
08327   size_t oLeft=tmpBufSize;
08328   const char *srcPtr = srcBuf.data();
08329   char *dstPtr = tmpBuf.data();
08330   uint newSize=0;
08331   if (!portable_iconv(cd, &srcPtr, &iLeft, &dstPtr, &oLeft))
08332   {
08333     newSize = tmpBufSize-oLeft;
08334     srcBuf.shrink(newSize);
08335     strncpy(srcBuf.data(),tmpBuf.data(),newSize);
08336     //printf("iconv: input size=%d output size=%d\n[%s]\n",size,newSize,srcBuf.data());
08337   }
08338   else
08339   {
08340     err("Error: failed to translate characters from %s to %s: check INPUT_ENCODING\n",
08341         inputEncoding,outputEncoding);
08342     exit(1);
08343   }
08344   portable_iconv_close(cd);
08345   return newSize;
08346 }
08347 
08348 //----------------------------------------------------------------------------
08349 // reads a file into an array and filters out any 0x00 and 0x06 bytes,
08350 // because these are special for the parser.
08351 
08352 void copyAndFilterFile(const char *fileName,BufStr &dest)
08353 {
08354   // try to open file
08355   int size=0;
08356   //uint oldPos = dest.curPos();
08357   //printf(".......oldPos=%d\n",oldPos);
08358 
08359   QFileInfo fi(fileName);
08360   if (!fi.exists()) return;
08361   QCString filterName = getFileFilter(fileName);
08362   if (filterName.isEmpty())
08363   {
08364     QFile f(fileName);
08365     if (!f.open(IO_ReadOnly))
08366     {
08367       err("Error: could not open file %s\n",fileName);
08368       return;
08369     }
08370     size=fi.size();
08371     // read the file
08372     dest.skip(size);
08373     if (f.readBlock(dest.data()/*+oldPos*/,size)!=size)
08374     {
08375       err("Error while reading file %s\n",fileName);
08376       return;
08377     }
08378   }
08379   else
08380   {
08381     QCString cmd=filterName+" \""+fileName+"\"";
08382     Debug::print(Debug::ExtCmd,0,"Executing popen(`%s`)\n",cmd.data());
08383     FILE *f=portable_popen(cmd,"r");
08384     if (!f)
08385     {
08386       err("Error: could not execute filter %s\n",filterName.data());
08387       return;
08388     }
08389     const int bufSize=1024;
08390     char buf[bufSize];
08391     int numRead;
08392     while ((numRead=fread(buf,1,bufSize,f))>0) 
08393     {
08394       //printf(">>>>>>>>Reading %d bytes\n",numRead);
08395       dest.addArray(buf,numRead),size+=numRead;
08396     }
08397     portable_pclose(f);
08398   }
08399   // filter unwanted bytes from the resulting data
08400   uchar conv[256];
08401   int i;
08402   for (i=0;i<256;i++) conv[i]=i;
08403   conv[0x06]=0x20; // replace the offending characters with spaces
08404   conv[0x00]=0x20;
08405   // remove any special markers from the input
08406   uchar *p=(uchar *)dest.data()/*+oldPos*/;
08407   for (i=0;i<size;i++,p++) *p=conv[*p];
08408   // and translate CR's
08409   int newSize=filterCRLF(dest.data()/*+oldPos*/,size);
08410   //printf("filter char at %p size=%d newSize=%d\n",dest.data()+oldPos,size,newSize);
08411   if (newSize!=size) // we removed chars
08412   {
08413     dest.shrink(/*oldPos+*/newSize); // resize the array
08414     //printf(".......resizing from %d to %d result=[%s]\n",oldPos+size,oldPos+newSize,dest.data());
08415   }
08416 }
08417 
08418 //----------------------------------------------------------------------------
08419 static void copyStyleSheet()
08420 {
08421   QCString &htmlStyleSheet = Config_getString("HTML_STYLESHEET");
08422   if (!htmlStyleSheet.isEmpty())
08423   {
08424     QFile cssf(htmlStyleSheet);
08425     QFileInfo cssfi(htmlStyleSheet);
08426     if (cssf.open(IO_ReadOnly))
08427     {
08428       QCString destFileName = Config_getString("HTML_OUTPUT")+"/"+cssfi.fileName().data();
08429       QFile df(destFileName);
08430       if (df.open(IO_WriteOnly))
08431       {
08432         char *buffer = new char[cssf.size()];
08433         cssf.readBlock(buffer,cssf.size());
08434         df.writeBlock(buffer,cssf.size());
08435         df.flush();
08436         delete[] buffer;
08437       }
08438       else
08439       {
08440         err("Error: could not write to style sheet %s\n",destFileName.data());
08441       }
08442     }
08443     else
08444     {
08445       err("Error: could not open user specified style sheet %s\n",Config_getString("HTML_STYLESHEET").data());
08446       htmlStyleSheet.resize(0); // revert to the default
08447     }
08448   }
08449 }
08450 
08451 static void parseFiles(Entry *root,EntryNav *rootNav)
08452 {
08453   void *cd = 0;
08454   QCString inpEncoding = Config_getString("INPUT_ENCODING");
08455   bool needsTranscoding = !inpEncoding.isEmpty();
08456   if (needsTranscoding)
08457   {
08458     if (!(cd = portable_iconv_open("UTF-8", inpEncoding)))
08459     {
08460        err("Error: unsupported character enconding: '%s'",inpEncoding.data());
08461        exit(1);
08462     }
08463   }
08464 
08465   QCString *s=inputFiles.first();
08466   while (s)
08467   {
08468     QCString fileName=*s;
08469     QCString extension;
08470     int ei = fileName.findRev('.');
08471     if (ei!=-1) extension=fileName.right(fileName.length()-ei);
08472     ParserInterface *parser = Doxygen::parserManager->getParser(extension);
08473 
08474     QFileInfo fi(fileName);
08475     BufStr preBuf(fi.size()+4096);
08476     //BufStr *bufPtr = &preBuf;
08477 
08478     if (Config_getBool("ENABLE_PREPROCESSING") && 
08479         parser->needsPreprocessing(extension))
08480     {
08481       msg("Preprocessing %s...\n",s->data());
08482       preprocessFile(fileName,preBuf);
08483     }
08484     else
08485     {
08486       msg("Reading %s...\n",s->data());
08487       copyAndFilterFile(fileName,preBuf);
08488     }
08489 
08490     preBuf.addChar('\n'); /* to prevent problems under Windows ? */
08491 
08492     // do character transcoding if needed.
08493     transcodeCharacterBuffer(preBuf,preBuf.curPos(),
08494                              Config_getString("INPUT_ENCODING"),"UTF-8");
08495 
08496     BufStr convBuf(preBuf.curPos()+1024);
08497 
08498     // convert multi-line C++ comments to C style comments
08499     convertCppComments(&preBuf,&convBuf,fileName);
08500 
08501     convBuf.addChar('\0');
08502 
08503     // use language parse to parse the file
08504     parser->parseInput(fileName,convBuf.data(),root);
08505 
08506     // store the Entry tree in a file and create an index to
08507     // navigate/load entries
08508     bool ambig;
08509     FileDef *fd=findFileDef(Doxygen::inputNameDict,fileName,ambig);
08510     ASSERT(fd!=0);
08511     root->createNavigationIndex(rootNav,g_storage,fd);
08512 
08513     s=inputFiles.next();
08514   }
08515 }
08516 
08517 
08518 //----------------------------------------------------------------------------
08519 // Read all files matching at least one pattern in `patList' in the 
08520 // directory represented by `fi'.
08521 // The directory is read iff the recusiveFlag is set.
08522 // The contents of all files is append to the input string
08523 
08524 int readDir(QFileInfo *fi,
08525             FileNameList *fnList,
08526             FileNameDict *fnDict,
08527             StringDict  *exclDict,
08528             QStrList *patList,
08529             QStrList *exclPatList,
08530             StringList *resultList,
08531             StringDict *resultDict,
08532             bool errorIfNotExist,
08533             bool recursive,
08534             QDict<void> *killDict
08535            )
08536 {
08537   QDir dir((const char *)fi->absFilePath());
08538   dir.setFilter( QDir::Files | QDir::Dirs | QDir::Hidden );
08539   int totalSize=0;
08540   msg("Searching for files in directory %s\n", fi->absFilePath().data());
08541   //printf("killDict=%p count=%d\n",killDict,killDict->count());
08542   
08543   const QFileInfoList *list = dir.entryInfoList();
08544   QFileInfoListIterator it( *list );
08545   QFileInfo *cfi;
08546   
08547   while ((cfi=it.current()))
08548   {
08549     if (exclDict==0 || exclDict->find(cfi->absFilePath())==0) 
08550     { // file should not be excluded
08551       //printf("killDict->find(%s)\n",cfi->absFilePath().data());
08552       if (!cfi->exists() || !cfi->isReadable())
08553       {
08554         if (errorIfNotExist)
08555         {
08556           err("Warning: source %s is not a readable file or directory... skipping.\n",cfi->absFilePath().data());
08557         }
08558       }
08559       else if (cfi->isFile() && 
08560           (!Config_getBool("EXCLUDE_SYMLINKS") || !cfi->isSymLink()) &&
08561           (patList==0 || patternMatch(cfi,patList)) && 
08562           !patternMatch(cfi,exclPatList) &&
08563           (killDict==0 || killDict->find(cfi->absFilePath())==0)
08564          )
08565       {
08566         totalSize+=cfi->size()+cfi->absFilePath().length()+4;
08567         QCString name=convertToQCString(cfi->fileName());
08568         //printf("New file %s\n",name.data());
08569         if (fnDict)
08570         {
08571           FileDef  *fd=new FileDef(cfi->dirPath()+"/",name);
08572           FileName *fn=0;
08573           if (!name.isEmpty() && (fn=(*fnDict)[name]))
08574           {
08575             fn->append(fd);
08576           }
08577           else
08578           {
08579             fn = new FileName(cfi->absFilePath(),name);
08580             fn->append(fd);
08581             if (fnList) fnList->inSort(fn);
08582             fnDict->insert(name,fn);
08583           }
08584         }
08585         QCString *rs=0;
08586         if (resultList || resultDict)
08587         {
08588           rs=new QCString(cfi->absFilePath());
08589         }
08590         if (resultList) resultList->append(rs);
08591         if (resultDict) resultDict->insert(cfi->absFilePath(),rs);
08592         if (killDict) killDict->insert(cfi->absFilePath(),(void *)0x8);
08593       }
08594       else if (recursive &&
08595           (!Config_getBool("EXCLUDE_SYMLINKS") || !cfi->isSymLink()) &&
08596           cfi->isDir() && cfi->fileName()!="." && 
08597           !patternMatch(cfi,exclPatList) &&
08598           cfi->fileName()!="..")
08599       {
08600         cfi->setFile(cfi->absFilePath());
08601         totalSize+=readDir(cfi,fnList,fnDict,exclDict,
08602             patList,exclPatList,resultList,resultDict,errorIfNotExist,
08603             recursive,killDict);
08604       }
08605     }
08606     ++it;
08607   }
08608   return totalSize;
08609 }
08610 
08611 
08612 //----------------------------------------------------------------------------
08613 // read a file or all files in a directory and append their contents to the
08614 // input string. The names of the files are appended to the `fiList' list.
08615 
08616 int readFileOrDirectory(const char *s,
08617                         FileNameList *fnList,
08618                         FileNameDict *fnDict,
08619                         StringDict *exclDict,
08620                         QStrList *patList,
08621                         QStrList *exclPatList,
08622                         StringList *resultList,
08623                         StringDict *resultDict,
08624                         bool recursive,
08625                         bool errorIfNotExist,
08626                         QDict<void> *killDict
08627                        )
08628 {
08629   //printf("killDict=%p count=%d\n",killDict,killDict->count());
08630   // strip trailing slashes
08631   if (s==0) return 0;
08632   QCString fs = s;
08633   char lc = fs.at(fs.length()-1);
08634   if (lc=='/' || lc=='\\') fs = fs.left(fs.length()-1);
08635 
08636   QFileInfo fi(fs);
08637   //printf("readFileOrDirectory(%s)\n",s);
08638   int totalSize=0;
08639   {
08640     if (exclDict==0 || exclDict->find(fi.absFilePath())==0)
08641     {
08642       if (!fi.exists() || !fi.isReadable())
08643       {
08644         if (errorIfNotExist)
08645         {
08646           err("Warning: source %s is not a readable file or directory... skipping.\n",s);
08647         }
08648       }
08649       else if (!Config_getBool("EXCLUDE_SYMLINKS") || !fi.isSymLink())
08650       {
08651         if (fi.isFile())
08652         {
08653           //printf("killDict->find(%s)\n",fi.absFilePath().data());
08654           if (killDict==0 || killDict->find(fi.absFilePath())==0)
08655           {
08656             totalSize+=fi.size()+fi.absFilePath().length()+4; //readFile(&fi,fiList,input); 
08657             //fiList->inSort(new FileInfo(fi));
08658             QCString name=convertToQCString(fi.fileName());
08659             //printf("New file %s\n",name.data());
08660             if (fnDict)
08661             {
08662               FileDef  *fd=new FileDef(fi.dirPath(TRUE)+"/",name);
08663               FileName *fn=0;
08664               if (!name.isEmpty() && (fn=(*fnDict)[name]))
08665               {
08666                 fn->append(fd);
08667               }
08668               else
08669               {
08670                 fn = new FileName(fi.absFilePath(),name);
08671                 fn->append(fd);
08672                 if (fnList) fnList->inSort(fn);
08673                 fnDict->insert(name,fn);
08674               }
08675             }
08676             QCString *rs=0;
08677             if (resultList || resultDict)
08678             {
08679               rs=new QCString(fi.absFilePath());
08680               if (resultList) resultList->append(rs);
08681               if (resultDict) resultDict->insert(fi.absFilePath(),rs);
08682             }
08683 
08684             if (killDict) killDict->insert(fi.absFilePath(),(void *)0x8);
08685           }
08686         }
08687         else if (fi.isDir()) // readable dir
08688         {
08689           totalSize+=readDir(&fi,fnList,fnDict,exclDict,patList,
08690               exclPatList,resultList,resultDict,errorIfNotExist,
08691               recursive,killDict);
08692         }
08693       }
08694     }
08695   }
08696   return totalSize;
08697 }
08698 
08699 //----------------------------------------------------------------------------
08700 
08701 void readFormulaRepository()
08702 {
08703   QFile f(Config_getString("HTML_OUTPUT")+"/formula.repository");
08704   if (f.open(IO_ReadOnly)) // open repository
08705   {
08706     msg("Reading formula repository...\n");
08707     QTextStream t(&f);
08708     QCString line;
08709     while (!t.eof())
08710     {
08711       line=t.readLine();
08712       int se=line.find(':'); // find name and text separator.
08713       if (se==-1)
08714       {
08715         err("Warning: formula.repository is corrupted!\n");
08716         break;
08717       }
08718       else
08719       {
08720         QCString formName = line.left(se);
08721         QCString formText = line.right(line.length()-se-1); 
08722         Formula *f=new Formula(formText);
08723         Doxygen::formulaList.append(f);
08724         Doxygen::formulaDict.insert(formText,f);
08725         Doxygen::formulaNameDict.insert(formName,f);
08726       }
08727     }
08728   }
08729 }
08730 
08731 //----------------------------------------------------------------------------
08732 
08733 static void expandAliases()
08734 {
08735   QDictIterator<QCString> adi(Doxygen::aliasDict);
08736   QCString *s;
08737   for (adi.toFirst();(s=adi.current());++adi)
08738   {
08739     *s = expandAlias(adi.currentKey(),*s);
08740   }
08741 }
08742 
08743 //----------------------------------------------------------------------------
08744 
08745 static void escapeAliases()
08746 {
08747   QDictIterator<QCString> adi(Doxygen::aliasDict);
08748   QCString *s;
08749   for (adi.toFirst();(s=adi.current());++adi)
08750   {
08751     QCString value=*s,newValue;
08752     int in,p=0;
08753     // for each \n in the alias command value
08754     while ((in=value.find("\\n",p))!=-1)
08755     {
08756       newValue+=value.mid(p,in-p);
08757       // expand \n's except if \n is part of a built-in command.
08758       if (value.mid(in,5)!="\\note" && 
08759           value.mid(in,5)!="\\name" && 
08760           value.mid(in,10)!="\\namespace" && 
08761           value.mid(in,14)!="\\nosubgrouping"
08762          ) 
08763       {
08764         newValue+="\\_linebr ";
08765       }
08766       else 
08767       {
08768         newValue+="\\n";
08769       }
08770       p=in+2;
08771     }
08772     newValue+=value.mid(p,value.length()-p);
08773     *s=newValue;
08774     //printf("Alias %s has value %s\n",adi.currentKey().data(),s->data());
08775   }
08776 }
08777 
08778 //----------------------------------------------------------------------------
08779 
08780 void readAliases()
08781 { 
08782   // add aliases to a dictionary
08783   Doxygen::aliasDict.setAutoDelete(TRUE);
08784   QStrList &aliasList = Config_getList("ALIASES");
08785   const char *s=aliasList.first();
08786   while (s)
08787   {
08788     if (Doxygen::aliasDict[s]==0)
08789     {
08790       QCString alias=s;
08791       int i=alias.find('=');
08792       if (i>0)
08793       {
08794         QCString name=alias.left(i).stripWhiteSpace();
08795         QCString value=alias.right(alias.length()-i-1);
08796         //printf("Alias: found name=`%s' value=`%s'\n",name.data(),value.data()); 
08797         if (!name.isEmpty())
08798         {
08799           QCString *dn=Doxygen::aliasDict[name];
08800           if (dn==0) // insert new alias
08801           {
08802             Doxygen::aliasDict.insert(name,new QCString(value));
08803           }
08804           else // overwrite previous alias
08805           {
08806             *dn=value;
08807           }
08808         }
08809       }
08810     }
08811     s=aliasList.next();
08812   }
08813   expandAliases();
08814   escapeAliases();
08815 }
08816 
08817 //----------------------------------------------------------------------------
08818 
08819 static void dumpSymbol(QTextStream &t,Definition *d)
08820 {
08821   QCString anchor;
08822   if (d->definitionType()==Definition::TypeMember)
08823   {
08824     MemberDef *md = (MemberDef *)d;
08825     anchor=":"+md->anchor();
08826   }
08827   QCString scope;
08828   if (d->getOuterScope() && d->getOuterScope()!=Doxygen::globalScope) 
08829   {
08830     scope = d->getOuterScope()->getOutputFileBase()+Doxygen::htmlFileExtension;
08831   }
08832   t << "REPLACE INTO symbols (symbol_id,scope_id,name,file,line) VALUES('"
08833     << d->getOutputFileBase()+Doxygen::htmlFileExtension+anchor << "','"
08834     << scope << "','"
08835     << d->name() << "','"
08836     << d->getDefFileName() << "','"
08837     << d->getDefLine()
08838     << "');" << endl;
08839 }
08840 
08841 static void dumpSymbolMap()
08842 { 
08843   QFile f("symbols.sql");
08844   if (f.open(IO_WriteOnly))
08845   {
08846     QTextStream t(&f);
08847     QDictIterator<DefinitionIntf> di(*Doxygen::symbolMap);
08848     DefinitionIntf *intf;
08849     for (;(intf=di.current());++di)
08850     {
08851       if (intf->definitionType()==DefinitionIntf::TypeSymbolList) // list of symbols
08852       {
08853         DefinitionListIterator dli(*(DefinitionList*)intf);
08854         Definition *d;
08855         // for each symbol
08856         for (dli.toFirst();(d=dli.current());++dli)
08857         {
08858           dumpSymbol(t,d);
08859         }
08860       }
08861       else // single symbol
08862       {
08863         Definition *d = (Definition *)intf;
08864         if (d!=Doxygen::globalScope) dumpSymbol(t,d);
08865       }
08866     }
08867   }
08868 }
08869 
08870 
08871 //----------------------------------------------------------------------------
08872 // print the usage of doxygen
08873 
08874 static void usage(const char *name)
08875 {
08876   msg("Doxygen version %s\nCopyright Dimitri van Heesch 1997-2008\n\n",versionString);
08877   msg("You can use doxygen in a number of ways:\n\n");
08878   msg("1) Use doxygen to generate a template configuration file:\n");
08879   msg("    %s [-s] -g [configName]\n\n",name);
08880   msg("    If - is used for configName doxygen will write to standard output.\n\n");
08881   msg("2) Use doxygen to update an old configuration file:\n");
08882   msg("    %s [-s] -u [configName]\n\n",name);
08883   msg("3) Use doxygen to generate documentation using an existing ");
08884   msg("configuration file:\n");
08885   msg("    %s [configName]\n\n",name);
08886   msg("    If - is used for configName doxygen will read from standard input.\n\n");
08887   msg("4) Use doxygen to generate a template style sheet file for RTF, HTML or Latex.\n");
08888   msg("    RTF:   %s -w rtf styleSheetFile\n",name);
08889   msg("    HTML:  %s -w html headerFile footerFile styleSheetFile [configFile]\n",name);
08890   msg("    LaTeX: %s -w latex headerFile styleSheetFile [configFile]\n\n",name);
08891   msg("5) Use doxygen to generate an rtf extensions file\n");
08892   msg("    RTF:   %s -e rtf extensionsFile\n\n",name);
08893   msg("If -s is specified the comments in the config file will be omitted.\n");
08894   msg("If configName is omitted `Doxyfile' will be used as a default.\n\n");
08895   exit(1);
08896 }
08897 
08898 //----------------------------------------------------------------------------
08899 // read the argument of option `c' from the comment argument list and
08900 // update the option index `optind'.
08901 
08902 static const char *getArg(int argc,char **argv,int &optind)
08903 {
08904   char *s=0;
08905   if (strlen(&argv[optind][2])>0)
08906     s=&argv[optind][2];
08907   else if (optind+1<argc && argv[optind+1][0]!='-')
08908     s=argv[++optind];
08909   return s;
08910 }
08911 
08912 //----------------------------------------------------------------------------
08913 
08914 extern void commentScanTest();
08915 
08916 void initDoxygen()
08917 {
08918 #if QT_VERSION >= 200
08919   setlocale(LC_ALL,"");
08920   setlocale(LC_NUMERIC,"C");
08921 #endif 
08922 
08923   //Doxygen::symbolMap->setAutoDelete(TRUE);
08924 
08925   Doxygen::runningTime.start();
08926   initPreprocessor();
08927 
08928   ParserInterface *defaultParser = new CLanguageScanner;
08929   Doxygen::parserManager = new ParserManager(defaultParser);
08930   Doxygen::parserManager->registerParser(".py",  new PythonLanguageScanner);
08931   Doxygen::parserManager->registerParser(".f",   new FortranLanguageScanner);
08932   Doxygen::parserManager->registerParser(".f90", new FortranLanguageScanner);
08933   Doxygen::parserManager->registerParser(".vhd", new VHDLLanguageScanner);
08934 
08935 
08936   // register any additional parsers here...
08937 
08938 
08939   initClassMemberIndices();
08940   initNamespaceMemberIndices();
08941   initFileMemberIndices();
08942 }
08943 
08944 void cleanUpDoxygen()
08945 {
08946   delete Doxygen::inputNameDict;
08947   delete Doxygen::includeNameDict;
08948   delete Doxygen::exampleNameDict;
08949   delete Doxygen::imageNameDict;
08950   delete Doxygen::dotFileNameDict;
08951   delete Doxygen::mainPage;
08952   delete Doxygen::pageSDict;  
08953   delete Doxygen::exampleSDict;
08954   delete Doxygen::globalScope;
08955   delete Doxygen::xrefLists;
08956   delete Doxygen::parserManager;
08957   cleanUpPreprocessor();
08958   delete theTranslator;
08959   delete outputList;
08960   Mappers::freeMappers();
08961   codeFreeScanner();
08962 
08963   if (Doxygen::symbolMap)
08964   {
08965     // iterate through Doxygen::symbolMap and delete all
08966     // DefinitionList objects, since they have no owner
08967     QDictIterator<DefinitionIntf> dli(*Doxygen::symbolMap);
08968     DefinitionIntf *di;
08969     for (dli.toFirst();(di=dli.current());)
08970     {
08971       if (di->definitionType()==DefinitionIntf::TypeSymbolList)
08972       {
08973         DefinitionIntf *tmp = Doxygen::symbolMap->take(dli.currentKey());
08974         delete (DefinitionList *)tmp;
08975       }
08976       else
08977       {
08978         ++dli;
08979       }
08980     } 
08981   }
08982 
08983   delete Doxygen::inputNameList;
08984   delete Doxygen::memberNameSDict;
08985   delete Doxygen::functionNameSDict;
08986   delete Doxygen::groupSDict;
08987   delete Doxygen::classSDict;
08988   delete Doxygen::hiddenClasses;
08989   delete Doxygen::namespaceSDict;
08990   delete Doxygen::directories;
08991 
08992   //delete Doxygen::symbolMap; <- we cannot do this unless all static lists 
08993   //                              (such as Doxygen::namespaceSDict)
08994   //                              with objects based on Definition are made
08995   //                              dynamic first
08996 }
08997 
08998 void readConfiguration(int argc, char **argv)
08999 {
09000   /**************************************************************************
09001    *             Handle arguments                                           *
09002    **************************************************************************/
09003 
09004   int optind=1;
09005   const char *configName=0;
09006   const char *debugLabel;
09007   const char *formatName;
09008   bool genConfig=FALSE;
09009   bool shortList=FALSE;
09010   bool updateConfig=FALSE;
09011   while (optind<argc && argv[optind][0]=='-' && 
09012                (isalpha(argv[optind][1]) || argv[optind][1]=='?' || 
09013                 argv[optind][1]=='-')
09014         )
09015   {
09016     switch(argv[optind][1])
09017     {
09018       case 'g':
09019         genConfig=TRUE;
09020         configName=getArg(argc,argv,optind);
09021         if (strcmp(argv[optind+1],"-")==0)
09022         { configName="-"; optind++; }
09023         if (!configName) 
09024         { configName="Doxyfile"; }
09025         break;
09026       case 'd':
09027         debugLabel=getArg(argc,argv,optind);
09028         Debug::setFlag(debugLabel);
09029         break;
09030       case 's':
09031         shortList=TRUE;
09032         break;
09033       case 'u':
09034         updateConfig=TRUE;
09035         break;
09036       case 'e':
09037         formatName=getArg(argc,argv,optind);
09038         if (!formatName)
09039         {
09040           err("Error:option -e is missing format specifier rtf.\n");
09041           cleanUpDoxygen();
09042           exit(1);
09043         }
09044         if (stricmp(formatName,"rtf")==0)
09045         {
09046           if (optind+1>=argc)
09047           {
09048             err("Error: option \"-e rtf\" is missing an extensions file name\n");
09049             cleanUpDoxygen();
09050             exit(1);
09051           }
09052           QFile f;
09053           if (openOutputFile(argv[optind+1],f))
09054           {
09055             RTFGenerator::writeExtensionsFile(f);
09056           }
09057           cleanUpDoxygen();
09058           exit(1);
09059         }
09060         err("Error: option \"-e\" has invalid format specifier.\n");
09061         cleanUpDoxygen();
09062         exit(1);
09063         break; 
09064       case 'w':
09065         formatName=getArg(argc,argv,optind);
09066         if (!formatName)
09067         {
09068           err("Error: option -w is missing format specifier rtf, html or latex\n");
09069           cleanUpDoxygen();
09070           exit(1);
09071         } 
09072         if (stricmp(formatName,"rtf")==0)
09073         {
09074           if (optind+1>=argc)
09075           {
09076             err("Error: option \"-w rtf\" is missing a style sheet file name\n");
09077             cleanUpDoxygen();
09078             exit(1);
09079           }
09080           QFile f;
09081           if (openOutputFile(argv[optind+1],f))
09082           {
09083             RTFGenerator::writeStyleSheetFile(f);
09084           }
09085           cleanUpDoxygen();
09086           exit(1);
09087         }
09088         else if (stricmp(formatName,"html")==0)
09089         {
09090           if (optind+4<argc)
09091           {
09092             if (!Config::instance()->parse(argv[optind+4]))
09093             {
09094               err("Error opening or reading configuration file %s!\n",argv[optind+4]);
09095               cleanUpDoxygen();
09096               exit(1);
09097             }
09098             Config::instance()->substituteEnvironmentVars();
09099             Config::instance()->convertStrToVal();
09100             Config::instance()->check();
09101           }
09102           else
09103           {
09104             Config::instance()->init();
09105           }
09106           if (optind+3>=argc)
09107           {
09108             err("Error: option \"-w html\" does not have enough arguments\n");
09109             cleanUpDoxygen();
09110             exit(1);
09111           }
09112 
09113           QCString outputLanguage=Config_getEnum("OUTPUT_LANGUAGE");
09114           if (!setTranslator(outputLanguage))
09115           {
09116             err("Warning: Output language %s not supported! Using English instead.\n", outputLanguage.data());
09117           }
09118 
09119           QFile f;
09120           if (openOutputFile(argv[optind+1],f))
09121           {
09122             HtmlGenerator::writeHeaderFile(f);
09123           }
09124           f.close();
09125           if (openOutputFile(argv[optind+2],f))
09126           {
09127             HtmlGenerator::writeFooterFile(f);
09128           }
09129           f.close();
09130           if (openOutputFile(argv[optind+3],f))
09131           {
09132             HtmlGenerator::writeStyleSheetFile(f);
09133           } 
09134           cleanUpDoxygen();
09135           exit(0);
09136         }
09137         else if (stricmp(formatName,"latex")==0)
09138         {
09139           if (optind+3<argc) // use config file to get settings
09140           {
09141             if (!Config::instance()->parse(argv[optind+3]))
09142             {
09143               err("Error opening or reading configuration file %s!\n",argv[optind+3]);
09144               exit(1);
09145             }
09146             Config::instance()->substituteEnvironmentVars();
09147             Config::instance()->convertStrToVal();
09148             Config::instance()->check();
09149           }
09150           else // use default config
09151           {
09152             Config::instance()->init();
09153           }
09154           if (optind+2>=argc)
09155           {
09156             err("Error: option \"-w latex\" does not have enough arguments\n");
09157             cleanUpDoxygen();
09158             exit(1);
09159           }
09160 
09161           QCString outputLanguage=Config_getEnum("OUTPUT_LANGUAGE");
09162           if (!setTranslator(outputLanguage))
09163           {
09164             err("Warning: Output language %s not supported! Using English instead.\n", outputLanguage.data());
09165           }
09166 
09167           QFile f;
09168           if (openOutputFile(argv[optind+1],f))
09169           {
09170             LatexGenerator::writeHeaderFile(f);
09171           }
09172           f.close();
09173           if (openOutputFile(argv[optind+2],f))
09174           {
09175             LatexGenerator::writeStyleSheetFile(f);
09176           }
09177           cleanUpDoxygen();
09178           exit(0);
09179         }
09180         else 
09181         {
09182           err("Error: Illegal format specifier %s: should be one of rtf, html, or latex\n",formatName);
09183           cleanUpDoxygen();
09184           exit(1);
09185         }
09186         break;
09187       case 'm':
09188         g_dumpSymbolMap = TRUE;
09189         break;
09190       case '-':
09191         if (strcmp(&argv[optind][2],"help")==0)
09192         {
09193           usage(argv[0]);
09194         }
09195         else if (strcmp(&argv[optind][2],"version")==0)
09196         {
09197           msg("%s\n",versionString); 
09198           cleanUpDoxygen();
09199           exit(0);
09200         }
09201         break;
09202       case 'b':
09203         setvbuf(stdout,NULL,_IONBF,0);
09204         Doxygen::outputToWizard=TRUE;
09205         break;
09206       case 'h':
09207       case '?':
09208         usage(argv[0]);
09209         break;
09210       default:
09211         err("Unknown option -%c\n",argv[optind][1]);
09212         usage(argv[0]);
09213     }
09214     optind++;
09215   }
09216   
09217   /**************************************************************************
09218    *            Parse or generate the config file                           *
09219    **************************************************************************/
09220 
09221   Config::instance()->init();
09222 
09223   if (genConfig)
09224   {
09225     generateConfigFile(configName,shortList);
09226     cleanUpDoxygen();
09227     exit(0);
09228   }
09229 
09230   QFileInfo configFileInfo1("Doxyfile"),configFileInfo2("doxyfile");
09231   if (optind>=argc)
09232   { 
09233     if (configFileInfo1.exists()) 
09234     {
09235       configName="Doxyfile";
09236     }
09237     else if (configFileInfo2.exists())
09238     {
09239       configName="doxyfile";
09240     }
09241     else
09242     {
09243       err("Doxyfile not found and no input file specified!\n");
09244       usage(argv[0]);
09245     }
09246   }
09247   else
09248   {
09249     QFileInfo fi(argv[optind]);
09250     if (fi.exists() || strcmp(argv[optind],"-")==0)
09251     {
09252       configName=argv[optind];
09253     }
09254     else
09255     {
09256       err("Error: configuration file %s not found!\n",argv[optind]);
09257       usage(argv[0]);
09258     }
09259   }
09260 
09261 
09262   if (!Config::instance()->parse(configName))
09263   {
09264     err("Error: could not open or read configuration file %s!\n",configName);
09265     cleanUpDoxygen();
09266     exit(1);
09267   }
09268 
09269   if (updateConfig)
09270   {
09271     generateConfigFile(configName,shortList,TRUE);
09272     cleanUpDoxygen();
09273     exit(0);
09274   }
09275 
09276   /* Perlmod wants to know the path to the config file.*/
09277   QFileInfo configFileInfo(configName);
09278   setPerlModDoxyfile(configFileInfo.absFilePath());
09279 }
09280 
09281 void checkConfiguration()
09282 {
09283   
09284   Config::instance()->substituteEnvironmentVars();
09285   Config::instance()->convertStrToVal();
09286   Config::instance()->check();
09287   
09288   initWarningFormat();
09289 
09290   QCString outputLanguage=Config_getEnum("OUTPUT_LANGUAGE");
09291   if (!setTranslator(outputLanguage))
09292   {
09293     err("Warning: Output language %s not supported! Using English instead.\n",
09294        outputLanguage.data());
09295   }
09296   QStrList &includePath = Config_getList("INCLUDE_PATH");
09297   char *s=includePath.first();
09298   while (s)
09299   {
09300     QFileInfo fi(s);
09301     addSearchDir(fi.absFilePath());
09302     s=includePath.next();
09303   }
09304 
09305   /* Set the global html file extension. */ 
09306   Doxygen::htmlFileExtension = Config_getString("HTML_FILE_EXTENSION");
09307 
09308 
09309   Doxygen::xrefLists->setAutoDelete(TRUE);
09310 
09311   Doxygen::parseSourcesNeeded = Config_getBool("CALL_GRAPH") || 
09312                                 Config_getBool("CALLER_GRAPH") ||
09313                                 Config_getBool("REFERENCES_RELATION") ||
09314                                 Config_getBool("REFERENCED_BY_RELATION");
09315   
09316 
09317 }
09318 
09319 #ifdef HAS_SIGNALS
09320 static void stopDoxygen(int)
09321 {
09322   QDir thisDir;
09323   msg("Cleaning up...\n");
09324   if (!Doxygen::entryDBFileName.isEmpty())
09325   {
09326     thisDir.remove(Doxygen::entryDBFileName);
09327   }
09328   if (!Doxygen::objDBFileName.isEmpty())
09329   {
09330     thisDir.remove(Doxygen::objDBFileName);
09331   }
09332   exit(1);
09333 }
09334 #endif
09335 
09336 static void exitDoxygen()
09337 {
09338   if (!g_successfulRun)  // premature exit
09339   {
09340     QDir thisDir;
09341     msg("Exiting...\n");
09342     if (!Doxygen::entryDBFileName.isEmpty())
09343     {
09344       thisDir.remove(Doxygen::entryDBFileName);
09345     }
09346     if (!Doxygen::objDBFileName.isEmpty())
09347     {
09348       thisDir.remove(Doxygen::objDBFileName);
09349     }
09350   }
09351 }
09352 
09353 void parseInput()
09354 {
09355   atexit(exitDoxygen);
09356 
09357   /**************************************************************************
09358    *            Make sure the output directory exists
09359    **************************************************************************/
09360   QCString &outputDirectory = Config_getString("OUTPUT_DIRECTORY");
09361   if (outputDirectory.isEmpty()) 
09362   {
09363     outputDirectory=QDir::currentDirPath();
09364   }
09365   else
09366   {
09367     QDir dir(outputDirectory);
09368     if (!dir.exists())
09369     {
09370       dir.setPath(QDir::currentDirPath());
09371       if (!dir.mkdir(outputDirectory))
09372       {
09373         err("Error: tag OUTPUT_DIRECTORY: Output directory `%s' does not "
09374             "exist and cannot be created\n",outputDirectory.data());
09375         cleanUpDoxygen();
09376         exit(1);
09377       }
09378       else if (!Config_getBool("QUIET"))
09379       {
09380         err("Notice: Output directory `%s' does not exist. "
09381             "I have created it for you.\n", outputDirectory.data());
09382       }
09383       dir.cd(outputDirectory);
09384     }
09385     outputDirectory=dir.absPath();
09386   }
09387 
09388   /**************************************************************************
09389    *            Initialize global lists and dictionaries
09390    **************************************************************************/
09391 
09392   Doxygen::symbolMap     = new QDict<DefinitionIntf>(1000);
09393   Doxygen::symbolCache   = new ObjCache(16); // 16 -> room for 65536 elements, 
09394                                              //       ~2.0 MByte "overhead"
09395   Doxygen::symbolStorage = new Store;
09396 
09397 #ifdef HAS_SIGNALS
09398   signal(SIGINT, stopDoxygen);
09399 #endif
09400 
09401   uint pid = portable_pid();
09402   Doxygen::objDBFileName.sprintf("doxygen_objdb_%d.tmp",pid);
09403   Doxygen::objDBFileName.prepend(outputDirectory+"/");
09404   Doxygen::entryDBFileName.sprintf("doxygen_entrydb_%d.tmp",pid);
09405   Doxygen::entryDBFileName.prepend(outputDirectory+"/");
09406   
09407   if (Doxygen::symbolStorage->open(Doxygen::objDBFileName)==-1)
09408   {
09409     err("Failed to open temporary file %s\n",Doxygen::objDBFileName.data());
09410     exit(1);
09411   }
09412 
09413   Doxygen::inputNameList = new FileNameList;
09414   Doxygen::inputNameList->setAutoDelete(TRUE);
09415   Doxygen::memberNameSDict = new MemberNameSDict(10000);   
09416   Doxygen::memberNameSDict->setAutoDelete(TRUE);
09417   Doxygen::functionNameSDict = new MemberNameSDict(10000);   
09418   Doxygen::functionNameSDict->setAutoDelete(TRUE);
09419   Doxygen::groupSDict = new GroupSDict(17);          
09420   Doxygen::groupSDict->setAutoDelete(TRUE);
09421   Doxygen::globalScope = new NamespaceDef("<globalScope>",1,"<globalScope>");
09422   Doxygen::namespaceSDict = new NamespaceSDict(20);      
09423   Doxygen::namespaceSDict->setAutoDelete(TRUE);
09424   Doxygen::classSDict = new ClassSDict(1009);         
09425   Doxygen::classSDict->setAutoDelete(TRUE);
09426   Doxygen::hiddenClasses = new ClassSDict(257);
09427   Doxygen::hiddenClasses->setAutoDelete(TRUE);
09428   Doxygen::directories = new DirSDict(17);
09429   Doxygen::directories->setAutoDelete(TRUE);
09430   Doxygen::pageSDict = new PageSDict(1009);          // all doc pages
09431   Doxygen::pageSDict->setAutoDelete(TRUE);
09432   Doxygen::exampleSDict = new PageSDict(1009);       // all examples
09433   Doxygen::exampleSDict->setAutoDelete(TRUE);
09434   Doxygen::inputNameDict = new FileNameDict(10007);
09435   Doxygen::includeNameDict = new FileNameDict(10007);
09436   Doxygen::exampleNameDict = new FileNameDict(1009);
09437   Doxygen::exampleNameDict->setAutoDelete(TRUE);
09438   Doxygen::imageNameDict = new FileNameDict(257);
09439   Doxygen::dotFileNameDict = new FileNameDict(257);
09440   Doxygen::sectionDict.setAutoDelete(TRUE);
09441   Doxygen::memGrpInfoDict.setAutoDelete(TRUE);
09442   Doxygen::tagDestinationDict.setAutoDelete(TRUE);
09443   Doxygen::lookupCache.setAutoDelete(TRUE);
09444   Doxygen::dirRelations.setAutoDelete(TRUE);
09445   excludeNameDict.setAutoDelete(TRUE);
09446 
09447   /**************************************************************************
09448    *            Initialize some global constants
09449    **************************************************************************/
09450   
09451   int &tabSize = Config_getInt("TAB_SIZE");
09452   spaces.resize(tabSize+1);
09453   int sp;for (sp=0;sp<tabSize;sp++) spaces.at(sp)=' ';
09454   spaces.at(tabSize)='\0';
09455 
09456   compoundKeywordDict.insert("template class",(void *)8);
09457   compoundKeywordDict.insert("template struct",(void *)8);
09458   compoundKeywordDict.insert("class",(void *)8);
09459   compoundKeywordDict.insert("struct",(void *)8);
09460   compoundKeywordDict.insert("union",(void *)8);
09461   compoundKeywordDict.insert("interface",(void *)8);
09462   compoundKeywordDict.insert("exception",(void *)8);
09463 
09464   bool alwaysRecursive = Config_getBool("RECURSIVE");
09465 
09466   /**************************************************************************
09467    *            Check/create output directorties                            *
09468    **************************************************************************/
09469 
09470   QCString &htmlOutput = Config_getString("HTML_OUTPUT");
09471   bool &generateHtml = Config_getBool("GENERATE_HTML");
09472   if (htmlOutput.isEmpty() && generateHtml)
09473   {
09474     htmlOutput=outputDirectory+"/html";
09475   }
09476   else if (htmlOutput && htmlOutput[0]!='/' && htmlOutput[1]!=':')
09477   {
09478     htmlOutput.prepend(outputDirectory+'/');
09479   }
09480   QDir htmlDir(htmlOutput);
09481   if (generateHtml && !htmlDir.exists() && !htmlDir.mkdir(htmlOutput))
09482   {
09483     err("Could not create output directory %s\n",htmlOutput.data());
09484     cleanUpDoxygen();
09485     exit(1);
09486   }
09487 
09488   QCString &xmlOutput = Config_getString("XML_OUTPUT");
09489   bool &generateXml = Config_getBool("GENERATE_XML");
09490   if (xmlOutput.isEmpty() && generateXml)
09491   {
09492     xmlOutput=outputDirectory+"/xml";
09493   }
09494   else if (xmlOutput && xmlOutput[0]!='/' && xmlOutput[1]!=':')
09495   {
09496     xmlOutput.prepend(outputDirectory+'/');
09497   }
09498   QDir xmlDir(xmlOutput);
09499   if (generateXml && !xmlDir.exists() && !xmlDir.mkdir(xmlOutput))
09500   {
09501     err("Could not create output directory %s\n",xmlOutput.data());
09502     cleanUpDoxygen();
09503     exit(1);
09504   }
09505   
09506   QCString &latexOutput = Config_getString("LATEX_OUTPUT");
09507   bool &generateLatex = Config_getBool("GENERATE_LATEX");
09508   if (latexOutput.isEmpty() && generateLatex)
09509   {
09510     latexOutput=outputDirectory+"/latex";
09511   }
09512   else if (latexOutput && latexOutput[0]!='/' && latexOutput[1]!=':')
09513   {
09514     latexOutput.prepend(outputDirectory+'/');
09515   }
09516   QDir latexDir(latexOutput);
09517   if (generateLatex && !latexDir.exists() && !latexDir.mkdir(latexOutput))
09518   {
09519     err("Could not create output directory %s\n",latexOutput.data());
09520     cleanUpDoxygen();
09521     exit(1);
09522   }
09523   
09524   QCString &rtfOutput = Config_getString("RTF_OUTPUT");
09525   bool &generateRtf = Config_getBool("GENERATE_RTF");
09526   if (rtfOutput.isEmpty() && generateRtf)
09527   {
09528     rtfOutput=outputDirectory+"/rtf";
09529   }
09530   else if (rtfOutput && rtfOutput[0]!='/' && rtfOutput[1]!=':')
09531   {
09532     rtfOutput.prepend(outputDirectory+'/');
09533   }
09534   QDir rtfDir(rtfOutput);
09535   if (generateRtf && !rtfDir.exists() && !rtfDir.mkdir(rtfOutput))
09536   {
09537     err("Could not create output directory %s\n",rtfOutput.data());
09538     cleanUpDoxygen();
09539     exit(1);
09540   }
09541 
09542   QCString &manOutput = Config_getString("MAN_OUTPUT");
09543   bool &generateMan = Config_getBool("GENERATE_MAN");
09544   if (manOutput.isEmpty() && generateMan)
09545   {
09546     manOutput=outputDirectory+"/man";
09547   }
09548   else if (manOutput && manOutput[0]!='/' && manOutput[1]!=':')
09549   {
09550     manOutput.prepend(outputDirectory+'/');
09551   }
09552   QDir manDir(manOutput);
09553   if (generateMan && !manDir.exists() && !manDir.mkdir(manOutput))
09554   {
09555     err("Could not create output directory %s\n",manOutput.data());
09556     cleanUpDoxygen();
09557     exit(1);
09558   }
09559   /**************************************************************************
09560    *             Read and preprocess input                                  *
09561    **************************************************************************/
09562  
09563   QStrList &exclPatterns = Config_getList("EXCLUDE_PATTERNS");
09564   // prevent search in the output directories
09565   if (generateHtml)  exclPatterns.append(htmlOutput);
09566   if (generateXml)   exclPatterns.append(xmlOutput);
09567   if (generateLatex) exclPatterns.append(latexOutput);
09568   if (generateRtf)   exclPatterns.append(rtfOutput);
09569   if (generateMan)   exclPatterns.append(manOutput);
09570 
09571   // gather names of all files in the include path
09572   msg("Searching for include files...\n");
09573   QStrList &includePathList = Config_getList("INCLUDE_PATH");
09574   char *s=includePathList.first();
09575   while (s)
09576   {
09577     QStrList &pl = Config_getList("INCLUDE_FILE_PATTERNS");
09578     if (pl.count()==0) 
09579     {
09580       pl = Config_getList("FILE_PATTERNS");
09581     }
09582     readFileOrDirectory(s,0,Doxygen::includeNameDict,0,&pl,
09583                         &exclPatterns,0,0,
09584                         alwaysRecursive);
09585     s=includePathList.next(); 
09586   }
09587   
09588   msg("Searching for example files...\n");
09589   QStrList &examplePathList = Config_getList("EXAMPLE_PATH");
09590   s=examplePathList.first();
09591   while (s)
09592   {
09593     readFileOrDirectory(s,0,Doxygen::exampleNameDict,0,
09594                         &Config_getList("EXAMPLE_PATTERNS"),
09595                         0,0,0,
09596                         (alwaysRecursive || Config_getBool("EXAMPLE_RECURSIVE")));
09597     s=examplePathList.next(); 
09598   }
09599 
09600   msg("Searching for images...\n");
09601   QStrList &imagePathList=Config_getList("IMAGE_PATH");
09602   s=imagePathList.first();
09603   while (s)
09604   {
09605     readFileOrDirectory(s,0,Doxygen::imageNameDict,0,0,
09606                         0,0,0,
09607                         alwaysRecursive);
09608     s=imagePathList.next(); 
09609   }
09610 
09611   msg("Searching for dot files...\n");
09612   QStrList &dotFileList=Config_getList("DOTFILE_DIRS");
09613   s=dotFileList.first();
09614   while (s)
09615   {
09616     readFileOrDirectory(s,0,Doxygen::dotFileNameDict,0,0,
09617                         0,0,0,
09618                         alwaysRecursive);
09619     s=dotFileList.next(); 
09620   }
09621 
09622   msg("Searching for files to exclude\n");
09623   QStrList &excludeList = Config_getList("EXCLUDE");
09624   s=excludeList.first();
09625   while (s)
09626   {
09627     readFileOrDirectory(s,0,0,0,&Config_getList("FILE_PATTERNS"),
09628                         0,0,&excludeNameDict,
09629                         alwaysRecursive,
09630                         FALSE);
09631     s=excludeList.next();
09632   }
09633 
09634   /**************************************************************************
09635    *             Determine Input Files                                      *
09636    **************************************************************************/
09637 
09638   msg("Searching for files to process...\n");
09639   QDict<void> *killDict = new QDict<void>(10007);
09640   int inputSize=0;
09641   QStrList &inputList=Config_getList("INPUT");
09642   inputFiles.setAutoDelete(TRUE);
09643   s=inputList.first();
09644   while (s)
09645   {
09646     QCString path=s;
09647     uint l = path.length();
09648     // strip trailing slashes
09649     if (path.at(l-1)=='\\' || path.at(l-1)=='/') path=path.left(l-1);
09650 
09651     inputSize+=readFileOrDirectory(
09652         path,
09653         Doxygen::inputNameList,
09654         Doxygen::inputNameDict,
09655         &excludeNameDict,
09656         &Config_getList("FILE_PATTERNS"),
09657         &exclPatterns,
09658         &inputFiles,0,
09659         alwaysRecursive,
09660         TRUE,
09661         killDict);
09662     s=inputList.next();
09663   }
09664   delete killDict;
09665   
09666   // add predefined macro name to a dictionary
09667   QStrList &expandAsDefinedList =Config_getList("EXPAND_AS_DEFINED");
09668   s=expandAsDefinedList.first();
09669   while (s)
09670   {
09671     if (Doxygen::expandAsDefinedDict[s]==0)
09672     {
09673       Doxygen::expandAsDefinedDict.insert(s,(void *)666);
09674     }
09675     s=expandAsDefinedList.next();
09676   }
09677 
09678   // read aliases and store them in a dictionary
09679   readAliases();
09680 
09681 
09682   // Notice: the order of the function calls below is very important!
09683   
09684   if (Config_getBool("GENERATE_HTML"))
09685   {
09686     readFormulaRepository();
09687   }
09688   
09689   /**************************************************************************
09690    *             Handle Tag Files                                           *
09691    **************************************************************************/
09692 
09693   g_storage = new FileStorage;
09694   g_storage->setName(Doxygen::entryDBFileName);
09695   if (!g_storage->open(IO_WriteOnly))
09696   {
09697     err("Failed to create temporary storage file %s\n",
09698         Doxygen::entryDBFileName.data());
09699     exit(1);
09700   }
09701   Entry *root=new Entry;
09702   EntryNav *rootNav = new EntryNav(0,root);
09703   rootNav->setEntry(root);
09704   msg("Reading and parsing tag files\n");
09705   
09706   QStrList &tagFileList = Config_getList("TAGFILES");
09707   s=tagFileList.first();
09708   while (s)
09709   {
09710     readTagFile(root,s);
09711     root->createNavigationIndex(rootNav,g_storage,0);
09712     s=tagFileList.next();
09713   }
09714   
09715   /**************************************************************************
09716    *             Parse source files                                         * 
09717    **************************************************************************/
09718 
09719   parseFiles(root,rootNav);
09720   g_storage->close();
09721   if (!g_storage->open(IO_ReadOnly))
09722   {
09723     err("Failed to open temporary storage file %s for reading",
09724         Doxygen::entryDBFileName.data());
09725     exit(1);
09726   }
09727 
09728   //printNavTree(rootNav,0);
09729 
09730   // we are done with input scanning now, so free up the buffers used by flex
09731   // (can be around 4MB)
09732   preFreeScanner();
09733   scanFreeScanner();
09734   pyscanFreeScanner();
09735 
09736   //delete rootNav;
09737   //g_storage.close();
09738   //exit(1);
09739 
09740   /**************************************************************************
09741    *             Gather information                                         * 
09742    **************************************************************************/
09743   
09744   msg("Building group list...\n");
09745   buildGroupList(rootNav);
09746   organizeSubGroups(rootNav);
09747 
09748   msg("Building directory list...\n");
09749   buildDirectories();
09750   findDirDocumentation(rootNav);
09751 
09752   if (Config_getBool("BUILTIN_STL_SUPPORT"))
09753   {
09754     addSTLClasses(rootNav);
09755   }
09756 
09757   msg("Building namespace list...\n");
09758   buildNamespaceList(rootNav);
09759   findUsingDirectives(rootNav);
09760 
09761   msg("Building file list...\n");
09762   buildFileList(rootNav);
09763   //generateFileTree();
09764   
09765   msg("Searching for included using directives...\n");
09766   findIncludedUsingDirectives();
09767 
09768   msg("Building class list...\n");
09769   buildClassList(rootNav);
09770 
09771   msg("Associating documentation with classes...\n");
09772   buildClassDocList(rootNav);
09773 
09774   // build list of using declarations here (global list)
09775   buildListOfUsingDecls(rootNav);
09776   
09777   msg("Computing nesting relations for classes...\n");
09778   resolveClassNestingRelations();
09779 
09780   // calling buildClassList may result in cached relations that
09781   // become invalid after resolveClassNestingRelation(), that's why
09782   // we need to clear the cache here
09783   Doxygen::lookupCache.clear();
09784   // we don't need the list of using declaration anymore
09785   g_usingDeclarations.clear();
09786 
09787   msg("Searching for members imported via using declarations...\n");
09788   findUsingDeclImports(rootNav);
09789   findUsingDeclarations(rootNav);
09790 
09791   msg("Building example list...\n");
09792   buildExampleList(rootNav);
09793   
09794   msg("Searching for enumerations...\n");
09795   findEnums(rootNav);
09796   
09797   msg("Searching for documented variables...\n");
09798   buildVarList(rootNav);
09799 
09800   msg("Building member list...\n"); // using class info only !
09801   buildFunctionList(rootNav);
09802 
09803   msg("Searching for friends...\n");
09804   findFriends();
09805   
09806   msg("Searching for documented defines...\n");
09807   findDefineDocumentation(rootNav); 
09808   
09809   findClassEntries(rootNav);         
09810   msg("Computing class inheritance relations...\n");
09811   findInheritedTemplateInstances();       
09812   msg("Computing class usage relations...\n");
09813   findUsedTemplateInstances();       
09814 
09815   msg("Flushing cached template relations that have become invalid...\n");
09816   flushCachedTemplateRelations();
09817   
09818   msg("Creating members for template instances...\n");
09819   createTemplateInstanceMembers();
09820 
09821   msg("Computing class relations...\n");
09822   computeTemplateClassRelations(); 
09823   flushUnresolvedRelations();
09824   //if (Config_getBool("OPTIMIZE_OUTPUT_VHDL"))
09825   //{
09826   //  VhdlDocGen::computeVhdlComponentRelations(classEntries,g_storage);
09827   //}
09828   //else
09829   //{
09830     computeClassRelations();        
09831   //}
09832   classEntries.clear();          
09833 
09834   addEnumValuesToEnums(rootNav);
09835   findEnumDocumentation(rootNav);
09836 
09837   msg("Searching for member function documentation...\n");
09838   findObjCMethodDefinitions(rootNav);
09839   findMemberDocumentation(rootNav); // may introduce new members !
09840 
09841   transferRelatedFunctionDocumentation();
09842   transferFunctionDocumentation();
09843   
09844   msg("Building page list...\n");
09845   buildPageList(rootNav);
09846 
09847   msg("Search for main page...\n");
09848   findMainPage(rootNav);
09849 
09850   msg("Computing page relations...\n");
09851   computePageRelations(rootNav);
09852   checkPageRelations();
09853 
09854   msg("Determining the scope of groups...\n");
09855   findGroupScope(rootNav);
09856 
09857   msg("Sorting lists...\n");
09858   Doxygen::memberNameSDict->sort();
09859   Doxygen::functionNameSDict->sort();
09860   Doxygen::hiddenClasses->sort();
09861   Doxygen::classSDict->sort();
09862   
09863   msg("Freeing entry tree\n");
09864   delete rootNav;
09865   g_storage->close();
09866   delete g_storage;
09867   g_storage=0;
09868 
09869   QDir thisDir;
09870   thisDir.remove(Doxygen::entryDBFileName);
09871   
09872   msg("Determining which enums are documented\n");
09873   findDocumentedEnumValues();
09874 
09875   msg("Computing member relations...\n");
09876   computeMemberRelations();
09877 
09878   msg("Building full member lists recursively...\n");
09879   buildCompleteMemberLists();
09880   
09881   msg("Adding members to member groups.\n");
09882   addMembersToMemberGroup();
09883 
09884   if (Config_getBool("DISTRIBUTE_GROUP_DOC"))
09885   {
09886     msg("Distributing member group documentation.\n");
09887     distributeMemberGroupDocumentation();
09888   }
09889   
09890   msg("Computing member references...\n");
09891   computeMemberReferences(); 
09892 
09893   if (Config_getBool("INHERIT_DOCS"))
09894   {
09895     msg("Inheriting documentation...\n");
09896     inheritDocumentation();
09897   }
09898 
09899   // compute the shortest possible names of all files
09900   // without loosing the uniqueness of the file names.
09901   msg("Generating disk names...\n");
09902   Doxygen::inputNameList->generateDiskNames();
09903   
09904   msg("Adding source references...\n");
09905   addSourceReferences();
09906 
09907   msg("Adding todo/test/bug list items...\n");
09908   addListReferences();
09909 
09910   if (Config_getBool("SHOW_DIRECTORIES") && Config_getBool("DIRECTORY_GRAPH"))
09911   {
09912     msg("Computing dependencies between directories...\n");
09913     computeDirDependencies();
09914   }
09915 
09916   msg("Counting data structures...\n");
09917   countDataStructures();
09918  
09919   msg("Resolving user defined references...\n");
09920   resolveUserReferences();
09921 
09922   msg("Finding anchors and sections in the documentation...\n");
09923   findSectionsInDocumentation();
09924 
09925   transferFunctionReferences();
09926 
09927   msg("Combining using relations...\n");
09928   combineUsingRelations();
09929 
09930 }
09931 
09932 void generateOutput()
09933 {
09934   /**************************************************************************
09935    *            Initialize output generators                                *
09936    **************************************************************************/
09937 
09939   //SDict<DefinitionList>::Iterator sdi(Doxygen::symbolMap);
09940   //DefinitionList *dl;
09941   //for (sdi.toFirst();(dl=sdi.current());++sdi)
09942   //{
09943   //  DefinitionListIterator dli(*dl);
09944   //  Definition *d;
09945   //  printf("Symbol: ");
09946   //  for (dli.toFirst();(d=dli.current());++dli)
09947   //  {
09948   //    printf("%s ",d->qualifiedName().data());
09949   //  }
09950   //  printf("\n");
09951   //}
09952   if (g_dumpSymbolMap)
09953   {
09954      dumpSymbolMap();
09955      exit(0);
09956   }
09957 
09958   initDocParser();
09959 
09960   outputList = new OutputList(TRUE);
09961   if (Config_getBool("GENERATE_HTML"))  
09962   {
09963     outputList->add(new HtmlGenerator);
09964     HtmlGenerator::init();
09965     if (Config_getBool("GENERATE_HTMLHELP")) Doxygen::indexList.addIndex(new HtmlHelp);
09966     if (Config_getBool("GENERATE_TREEVIEW")) Doxygen::indexList.addIndex(new FTVHelp);
09967     if (Config_getBool("GENERATE_DOCSET"))   Doxygen::indexList.addIndex(new DocSets);
09968     Doxygen::indexList.initialize();
09969     if (Config_getBool("HTML_DYNAMIC_SECTIONS")) HtmlGenerator::generateSectionImages();
09970     copyStyleSheet();
09971   }
09972   if (Config_getBool("GENERATE_LATEX")) 
09973   {
09974     outputList->add(new LatexGenerator);
09975     LatexGenerator::init();
09976   }
09977   if (Config_getBool("GENERATE_MAN"))
09978   {
09979     outputList->add(new ManGenerator);
09980     ManGenerator::init();
09981   }
09982   if (Config_getBool("GENERATE_RTF"))
09983   {
09984     outputList->add(new RTFGenerator);
09985     RTFGenerator::init();
09986   }
09987 
09988   if (Config_getBool("USE_HTAGS"))
09989   {
09990     Htags::useHtags = TRUE;
09991     QCString htmldir = Config_getString("HTML_OUTPUT");
09992     if (!Htags::execute(htmldir))
09993        err("Error: USE_HTAGS is YES but htags(1) failed. \n");
09994     if (!Htags::loadFilemap(htmldir))
09995        err("Error: htags(1) ended normally but failed to load the filemap. \n");
09996   }
09997   
09998   /**************************************************************************
09999    *                        Generate documentation                          *
10000    **************************************************************************/
10001 
10002   QFile *tag=0;
10003   QCString &generateTagFile = Config_getString("GENERATE_TAGFILE");
10004   if (!generateTagFile.isEmpty())
10005   {
10006     tag=new QFile(generateTagFile);
10007     if (!tag->open(IO_WriteOnly))
10008     {
10009       err("Error: cannot open tag file %s for writing\n",
10010           generateTagFile.data()
10011          );
10012       cleanUpDoxygen();
10013       exit(1);
10014     }
10015     Doxygen::tagFile.setDevice(tag);
10016     Doxygen::tagFile.setEncoding(QTextStream::UnicodeUTF8);
10017     Doxygen::tagFile << "<?xml version='1.0' encoding='ISO-8859-1' standalone='yes' ?>" << endl;
10018     Doxygen::tagFile << "<tagfile>" << endl;
10019   }
10020 
10021   if (Config_getBool("GENERATE_HTML"))  writeDoxFont(Config_getString("HTML_OUTPUT"));
10022   if (Config_getBool("GENERATE_LATEX")) writeDoxFont(Config_getString("LATEX_OUTPUT"));
10023   if (Config_getBool("GENERATE_RTF"))   writeDoxFont(Config_getString("RTF_OUTPUT"));
10024 
10025   msg("Generating style sheet...\n");
10026   //printf("writing style info\n");
10027   QCString genString = 
10028         theTranslator->trGeneratedAt(dateToString(TRUE),Config_getString("PROJECT_NAME"));
10029   outputList->writeStyleInfo(0); // write first part
10030   outputList->disableAllBut(OutputGenerator::Latex);
10031   outputList->parseText(genString);
10032   outputList->writeStyleInfo(1); // write second part
10033   //parseText(*outputList,theTranslator->trWrittenBy());
10034   outputList->writeStyleInfo(2); // write third part
10035   outputList->parseText(genString);
10036   outputList->writeStyleInfo(3); // write fourth part
10037   //parseText(*outputList,theTranslator->trWrittenBy());
10038   outputList->writeStyleInfo(4); // write last part
10039   outputList->enableAll();
10040   
10041   //statistics();
10042   
10043   // count the number of documented elements in the lists we have built. 
10044   // If the result is 0 we do not generate the lists and omit the 
10045   // corresponding links in the index.
10046   msg("Generating index page...\n"); 
10047   writeIndex(*outputList);
10048 
10049   msg("Generating page index...\n");
10050   writePageIndex(*outputList);
10051   
10052   msg("Generating example documentation...\n");
10053   generateExampleDocs();
10054 
10055   msg("Generating file sources...\n");
10056   if (!Htags::useHtags)
10057   {
10058     generateFileSources();
10059   }
10060 
10061   msg("Generating file documentation...\n");
10062   generateFileDocs();
10063   
10064   msg("Generating page documentation...\n");
10065   generatePageDocs();
10066   
10067   msg("Generating group documentation...\n");
10068   generateGroupDocs();
10069 
10070   msg("Generating group index...\n");
10071   writeGroupIndex(*outputList);
10072  
10073   msg("Generating class documentation...\n");
10074   addMembersToIndex();
10075   generateClassDocs();
10076   
10077   if (Config_getBool("HAVE_DOT") && Config_getBool("GRAPHICAL_HIERARCHY"))
10078   {
10079     msg("Generating graphical class hierarchy...\n");
10080     writeGraphicalClassHierarchy(*outputList);
10081   }
10082 
10083   msg("Generating namespace index...\n");
10084   generateNamespaceDocs();
10085   
10086   msg("Generating namespace member index...\n");
10087   writeNamespaceMemberIndex(*outputList);
10088 
10089   if (Config_getBool("GENERATE_LEGEND"))
10090   {
10091     msg("Generating graph info page...\n");
10092     writeGraphInfo(*outputList);
10093   }
10094 
10095   if (Config_getBool("SHOW_DIRECTORIES"))
10096   {
10097     msg("Generating directory documentation...\n");
10098     generateDirDocs(*outputList);
10099   }
10100 
10101   msg("Generating file index...\n");
10102   writeFileIndex(*outputList);
10103  
10104   if (Config_getBool("SHOW_DIRECTORIES"))
10105   {
10106     msg("Generating directory index...\n");
10107     writeDirIndex(*outputList);
10108   }
10109 
10110   msg("Generating example index...\n");
10111   writeExampleIndex(*outputList);
10112   
10113   msg("Generating file member index...\n");
10114   writeFileMemberIndex(*outputList);
10115   
10116   //writeDirDependencyGraph(Config_getString("HTML_OUTPUT"));
10117   
10118   if (Config_getBool("GENERATE_RTF"))
10119   {
10120     msg("Combining RTF output...\n");
10121     if (!RTFGenerator::preProcessFileInplace(Config_getString("RTF_OUTPUT"),"refman.rtf"))
10122     {
10123       err("An error occurred during post-processing the RTF files!\n");
10124     }
10125   }
10126   
10127   if (Doxygen::formulaList.count()>0 && Config_getBool("GENERATE_HTML"))
10128   {
10129     msg("Generating bitmaps for formulas in HTML...\n");
10130     Doxygen::formulaList.generateBitmaps(Config_getString("HTML_OUTPUT"));
10131   }
10132   
10133   //if (Config_getBool("GENERATE_HTML") && Config_getBool("GENERATE_HTMLHELP"))  
10134   //{
10135   //  HtmlHelp::getInstance()->finalize();
10136   //}
10137   //if (Config_getBool("GENERATE_HTML") && Config_getBool("GENERATE_TREEVIEW"))  
10138   //{
10139   //  FTVHelp::getInstance()->finalize();
10140   //}
10141 
10142   Doxygen::indexList.finalize();
10143 
10144   if (!Config_getString("GENERATE_TAGFILE").isEmpty())
10145   {
10146     Doxygen::tagFile << "</tagfile>" << endl;
10147     delete tag;
10148   }
10149 
10150   if (Config_getBool("GENERATE_HTML") && Config_getBool("DOT_CLEANUP")) removeDoxFont(Config_getString("HTML_OUTPUT"));
10151   if (Config_getBool("GENERATE_RTF") && Config_getBool("DOT_CLEANUP"))  removeDoxFont(Config_getString("RTF_OUTPUT"));
10152 
10153   if (Config_getBool("GENERATE_XML"))
10154   {
10155     msg("Generating XML output...\n");
10156     generateXML();
10157   }
10158   if (Config_getBool("GENERATE_AUTOGEN_DEF"))
10159   {
10160     msg("Generating AutoGen DEF output...\n");
10161     generateDEF();
10162   }
10163   if (Config_getBool("GENERATE_PERLMOD"))
10164   {
10165     msg("Generating Perl module output...\n");
10166     generatePerlMod();
10167   }
10168   if (Config_getBool("GENERATE_HTMLHELP") && !Config_getString("HHC_LOCATION").isEmpty())
10169   {
10170     msg("Running html help compiler...\n");
10171     QString oldDir = QDir::currentDirPath();
10172     QDir::setCurrent(Config_getString("HTML_OUTPUT"));
10173     if (portable_system(Config_getString("HHC_LOCATION"), "index.hhp", FALSE))
10174     {
10175       err("Error: failed to run html help compiler on index.hhp\n");
10176     }
10177     QDir::setCurrent(oldDir);
10178   }
10179   if (Config_getBool("SEARCHENGINE"))
10180   {
10181     msg("Generating search index\n");
10182     HtmlGenerator::writeSearchPage();
10183     Doxygen::searchIndex->write(Config_getString("HTML_OUTPUT")+"/search.idx");
10184   }
10185   if (Debug::isFlagSet(Debug::Time))
10186   {
10187     msg("Total elapsed time: %.3f seconds\n(of which %.3f seconds waiting for external tools to finish)\n",
10188          ((double)Doxygen::runningTime.elapsed())/1000.0,
10189          Doxygen::sysElapsedTime
10190         );
10191   }
10192 
10193   /**************************************************************************
10194    *                        Start cleaning up                               *
10195    **************************************************************************/
10196 
10197   //Doxygen::symbolCache->printStats();
10198   //Doxygen::symbolStorage->printStats();
10199   cleanUpDoxygen();
10200 
10201   finializeDocParser();
10202   Doxygen::symbolStorage->close();
10203   QDir thisDir;
10204   thisDir.remove(Doxygen::objDBFileName);
10205   Config::deleteInstance();
10206   QTextCodec::deleteAllCodecs();
10207   delete Doxygen::symbolCache;
10208   delete Doxygen::symbolMap;
10209   delete Doxygen::symbolStorage;
10210   g_successfulRun=TRUE;
10211 }
10212 



Generated on Mon Mar 31 10:58:37 2008 by  doxygen 1.5.1