Orb/Doxygen/src/doxygen.cpp
changeset 0 42188c7ea2d9
child 1 82f11024044a
equal deleted inserted replaced
-1:000000000000 0:42188c7ea2d9
       
     1 /******************************************************************************
       
     2  *
       
     3  * Copyright (C) 1997-2008 by Dimitri van Heesch.
       
     4  *
       
     5  * Permission to use, copy, modify, and distribute this software and its
       
     6  * documentation under the terms of the GNU General Public License is hereby 
       
     7  * granted. No representations are made about the suitability of this software 
       
     8  * for any purpose. It is provided "as is" without express or implied warranty.
       
     9  * See the GNU General Public License for more details.
       
    10  *
       
    11  * Documents produced by Doxygen are derivative works derived from the
       
    12  * input used in their production; they are not affected by this license.
       
    13  *
       
    14  */
       
    15 
       
    16 #include "qtbc.h"
       
    17 #include <qfileinfo.h>
       
    18 #include <qfile.h>
       
    19 #include <qdir.h>
       
    20 #include <qdict.h>
       
    21 #include <qregexp.h>
       
    22 #include <qstrlist.h>
       
    23 #include <stdio.h>
       
    24 #include <stdlib.h>
       
    25 #include <sys/stat.h>
       
    26 #include <qtextcodec.h>
       
    27 #include <unistd.h>
       
    28 #include <errno.h>
       
    29 
       
    30 #include "version.h"
       
    31 #include "doxygen.h"
       
    32 #include "scanner.h"
       
    33 #include "entry.h"
       
    34 #include "index.h"
       
    35 #include "logos.h"
       
    36 #include "instdox.h"
       
    37 #include "message.h"
       
    38 #include "config.h"
       
    39 #include "util.h"
       
    40 #include "pre.h"
       
    41 #include "tagreader.h"
       
    42 #include "dot.h"
       
    43 #include "docparser.h"
       
    44 #include "dirdef.h"
       
    45 #include "outputlist.h"
       
    46 #include "declinfo.h"
       
    47 #include "htmlgen.h"
       
    48 #include "latexgen.h"
       
    49 #include "mangen.h"
       
    50 #include "language.h"
       
    51 #include "debug.h"
       
    52 #include "htmlhelp.h"
       
    53 #include "qhp.h"
       
    54 #include "indexlog.h"
       
    55 #include "ftvhelp.h"
       
    56 #include "defargs.h"
       
    57 #include "rtfgen.h"
       
    58 #include "xmlgen.h"
       
    59 #include "xmlditagen.h"
       
    60 #include "defgen.h"
       
    61 #include "perlmodgen.h"
       
    62 #include "reflist.h"
       
    63 #include "pagedef.h"
       
    64 #include "bufstr.h"
       
    65 #include "commentcnv.h"
       
    66 #include "cmdmapper.h"
       
    67 #include "searchindex.h"
       
    68 #include "parserintf.h"
       
    69 #include "htags.h"
       
    70 #include "pyscanner.h"
       
    71 #include "fortranscanner.h"
       
    72 #include "dbusxmlscanner.h"
       
    73 #include "code.h"
       
    74 #include "objcache.h"
       
    75 #include "store.h"
       
    76 #include "marshal.h"
       
    77 #include "portable.h"
       
    78 #include "vhdlscanner.h"
       
    79 #include "vhdldocgen.h"
       
    80 #include "eclipsehelp.h"
       
    81 
       
    82 #include "layout.h"
       
    83 
       
    84 #define RECURSE_ENTRYTREE(func,var) \
       
    85   do { if (var->children()) { \
       
    86     EntryNavListIterator eli(*var->children()); \
       
    87     for (;eli.current();++eli) func(eli.current()); \
       
    88   } } while(0) 
       
    89 
       
    90 
       
    91 #if !defined(_WIN32) || defined(__CYGWIN__)
       
    92 #include <signal.h>
       
    93 #define HAS_SIGNALS
       
    94 #endif
       
    95 
       
    96 // globally accessible variables
       
    97 ClassSDict      *Doxygen::classSDict = 0;
       
    98 ClassSDict      *Doxygen::hiddenClasses = 0;
       
    99 NamespaceSDict  *Doxygen::namespaceSDict = 0;
       
   100 MemberNameSDict *Doxygen::memberNameSDict = 0;
       
   101 MemberNameSDict *Doxygen::functionNameSDict = 0;   
       
   102 FileNameList    *Doxygen::inputNameList = 0;       // all input files
       
   103 FileNameDict    *Doxygen::inputNameDict = 0;          
       
   104 GroupSDict      *Doxygen::groupSDict = 0;
       
   105 FormulaList      Doxygen::formulaList;             // all formulas
       
   106 FormulaDict      Doxygen::formulaDict(1009);       // all formulas
       
   107 FormulaDict      Doxygen::formulaNameDict(1009);   // the label name of all formulas
       
   108 PageSDict       *Doxygen::pageSDict = 0;
       
   109 PageSDict       *Doxygen::exampleSDict = 0;
       
   110 SectionDict      Doxygen::sectionDict(257);        // all page sections
       
   111 StringDict       Doxygen::aliasDict(257);          // aliases
       
   112 FileNameDict    *Doxygen::includeNameDict = 0;     // include names
       
   113 FileNameDict    *Doxygen::exampleNameDict = 0;     // examples
       
   114 FileNameDict    *Doxygen::imageNameDict = 0;       // images
       
   115 FileNameDict    *Doxygen::dotFileNameDict = 0;     // dot files
       
   116 StringDict       Doxygen::namespaceAliasDict(257); // all namespace aliases
       
   117 StringDict       Doxygen::tagDestinationDict(257); // all tag locations
       
   118 QDict<void>      Doxygen::expandAsDefinedDict(257); // all macros that should be expanded
       
   119 QIntDict<MemberGroupInfo> Doxygen::memGrpInfoDict(1009); // dictionary of the member groups heading
       
   120 PageDef         *Doxygen::mainPage = 0;
       
   121 bool             Doxygen::insideMainPage = FALSE; // are we generating docs for the main page?
       
   122 QTextStream      Doxygen::tagFile;
       
   123 NamespaceDef    *Doxygen::globalScope = 0;
       
   124 QDict<RefList>  *Doxygen::xrefLists = new QDict<RefList>; // dictionary of cross-referenced item lists
       
   125 bool             Doxygen::parseSourcesNeeded = FALSE;
       
   126 QTime            Doxygen::runningTime;
       
   127 SearchIndex *    Doxygen::searchIndex=0;
       
   128 QDict<DefinitionIntf> *Doxygen::symbolMap;
       
   129 bool             Doxygen::outputToWizard=FALSE;
       
   130 QDict<int> *     Doxygen::htmlDirMap = 0;
       
   131 QCache<LookupInfo> Doxygen::lookupCache(50000,50000);
       
   132 DirSDict        *Doxygen::directories;
       
   133 SDict<DirRelation> Doxygen::dirRelations(257);
       
   134 ParserManager   *Doxygen::parserManager = 0;
       
   135 QCString Doxygen::htmlFileExtension;
       
   136 bool             Doxygen::suppressDocWarnings = FALSE;
       
   137 ObjCache        *Doxygen::symbolCache = 0;
       
   138 Store           *Doxygen::symbolStorage;
       
   139 QCString         Doxygen::objDBFileName;
       
   140 QCString         Doxygen::entryDBFileName;
       
   141 bool             Doxygen::gatherDefines = TRUE;
       
   142 IndexList        Doxygen::indexList;
       
   143 int              Doxygen::subpageNestingLevel = 0;
       
   144 bool             Doxygen::userComments = FALSE;
       
   145 QCString         Doxygen::spaces;
       
   146 
       
   147 // locally accessible globals
       
   148 static QDict<EntryNav>  g_classEntries(1009);
       
   149 static StringList       g_inputFiles;         
       
   150 static QDict<void>      g_compoundKeywordDict(7);  // keywords recognised as compounds
       
   151 static OutputList      *g_outputList = 0;          // list of output generating objects
       
   152 static QDict<FileDef>   g_usingDeclarations(1009); // used classes
       
   153 static FileStorage     *g_storage = 0;
       
   154 static bool             g_successfulRun = FALSE;
       
   155 static bool             g_dumpSymbolMap = FALSE;
       
   156 static bool             g_dumpConfigAsXML = FALSE;
       
   157 
       
   158 
       
   159 
       
   160 void clearAll()
       
   161 {
       
   162   g_inputFiles.clear();      
       
   163   //g_excludeNameDict.clear();  
       
   164   //delete g_outputList; g_outputList=0;
       
   165 
       
   166   Doxygen::classSDict->clear();       
       
   167   Doxygen::namespaceSDict->clear();   
       
   168   Doxygen::pageSDict->clear();         
       
   169   Doxygen::exampleSDict->clear();      
       
   170   Doxygen::inputNameList->clear();   
       
   171   Doxygen::formulaList.clear();     
       
   172   Doxygen::sectionDict.clear();       
       
   173   Doxygen::inputNameDict->clear();    
       
   174   Doxygen::includeNameDict->clear();  
       
   175   Doxygen::exampleNameDict->clear();  
       
   176   Doxygen::imageNameDict->clear();     
       
   177   Doxygen::dotFileNameDict->clear();     
       
   178   Doxygen::formulaDict.clear();      
       
   179   Doxygen::formulaNameDict.clear();  
       
   180   Doxygen::tagDestinationDict.clear();
       
   181   delete Doxygen::mainPage; Doxygen::mainPage=0;
       
   182 }
       
   183 
       
   184 void statistics()
       
   185 {
       
   186   fprintf(stderr,"--- inputNameDict stats ----\n");
       
   187   Doxygen::inputNameDict->statistics();
       
   188   fprintf(stderr,"--- includeNameDict stats ----\n");
       
   189   Doxygen::includeNameDict->statistics();
       
   190   fprintf(stderr,"--- exampleNameDict stats ----\n");
       
   191   Doxygen::exampleNameDict->statistics();
       
   192   fprintf(stderr,"--- imageNameDict stats ----\n");
       
   193   Doxygen::imageNameDict->statistics();
       
   194   fprintf(stderr,"--- dotFileNameDict stats ----\n");
       
   195   Doxygen::dotFileNameDict->statistics();
       
   196   //fprintf(stderr,"--- g_excludeNameDict stats ----\n");
       
   197   //g_excludeNameDict.statistics();
       
   198   fprintf(stderr,"--- aliasDict stats ----\n");
       
   199   Doxygen::aliasDict.statistics();
       
   200   fprintf(stderr,"--- typedefDict stats ----\n");
       
   201   fprintf(stderr,"--- namespaceAliasDict stats ----\n");
       
   202   Doxygen::namespaceAliasDict.statistics();
       
   203   fprintf(stderr,"--- formulaDict stats ----\n");
       
   204   Doxygen::formulaDict.statistics();
       
   205   fprintf(stderr,"--- formulaNameDict stats ----\n");
       
   206   Doxygen::formulaNameDict.statistics();
       
   207   fprintf(stderr,"--- tagDestinationDict stats ----\n");
       
   208   Doxygen::tagDestinationDict.statistics();
       
   209   fprintf(stderr,"--- g_compoundKeywordDict stats ----\n");
       
   210   g_compoundKeywordDict.statistics();
       
   211   fprintf(stderr,"--- expandAsDefinedDict stats ----\n");
       
   212   Doxygen::expandAsDefinedDict.statistics();
       
   213   fprintf(stderr,"--- memGrpInfoDict stats ----\n");
       
   214   Doxygen::memGrpInfoDict.statistics();
       
   215 }
       
   216 
       
   217 
       
   218 
       
   219 static void addMemberDocs(EntryNav *rootNav,MemberDef *md, const char *funcDecl,
       
   220                    ArgumentList *al,bool over_load,NamespaceSDict *nl=0);
       
   221 static void findMember(EntryNav *rootNav,
       
   222                        QCString funcDecl,
       
   223                        bool overloaded,
       
   224                        bool isFunc
       
   225                       );
       
   226 
       
   227 
       
   228 struct STLInfo
       
   229 {
       
   230   const char *className;
       
   231   const char *baseClass1;
       
   232   const char *baseClass2;
       
   233   const char *templType1;
       
   234   const char *templName1;
       
   235   const char *templType2;
       
   236   const char *templName2;
       
   237   bool virtualInheritance;
       
   238   bool iterators;
       
   239 };
       
   240 
       
   241 static STLInfo g_stlinfo[] =
       
   242 {
       
   243   // className              baseClass1                      baseClass2             templType1     templName1     templType2    templName2     virtInheritance  // iterators
       
   244   { "allocator",            0,                              0,                     "T",           "elements",    0,            0,             FALSE,              FALSE },
       
   245   { "auto_ptr",             0,                              0,                     "T",           "ptr",         0,            0,             FALSE,              FALSE },
       
   246   { "ios_base",             0,                              0,                     0,             0,             0,            0,             FALSE,              FALSE },
       
   247   { "basic_ios",            "ios_base",                     0,                     "Char",        0,             0,            0,             FALSE,              FALSE },
       
   248   { "basic_istream",        "basic_ios<Char>",              0,                     "Char",        0,             0,            0,             TRUE,               FALSE },
       
   249   { "basic_ostream",        "basic_ios<Char>",              0,                     "Char",        0,             0,            0,             TRUE,               FALSE },
       
   250   { "basic_iostream",       "basic_istream<Char>",          "basic_ostream<Char>", "Char",        0,             0,            0,             FALSE,              FALSE },
       
   251   { "basic_ifstream",       "basic_istream<Char>",          0,                     "Char",        0,             0,            0,             FALSE,              FALSE },
       
   252   { "basic_ofstream",       "basic_ostream<Char>",          0,                     "Char",        0,             0,            0,             FALSE,              FALSE },
       
   253   { "basic_fstream",        "basic_iostream<Char>",         0,                     "Char",        0,             0,            0,             FALSE,              FALSE },
       
   254   { "basic_istringstream",  "basic_istream<Char>",          0,                     "Char",        0,             0,            0,             FALSE,              FALSE },
       
   255   { "basic_ostringstream",  "basic_ostream<Char>",          0,                     "Char",        0,             0,            0,             FALSE,              FALSE },
       
   256   { "basic_stringstream",   "basic_iostream<Char>",         0,                     "Char",        0,             0,            0,             FALSE,              FALSE },
       
   257   { "ios",                  "basic_ios<char>",              0,                     0,             0,             0,            0,             FALSE,              FALSE },
       
   258   { "wios",                 "basic_ios<wchar_t>",           0,                     0,             0,             0,            0,             FALSE,              FALSE },
       
   259   { "istream",              "basic_istream<char>",          0,                     0,             0,             0,            0,             FALSE,              FALSE },
       
   260   { "wistream",             "basic_istream<wchar_t>",       0,                     0,             0,             0,            0,             FALSE,              FALSE },
       
   261   { "ostream",              "basic_ostream<char>",          0,                     0,             0,             0,            0,             FALSE,              FALSE },
       
   262   { "wostream",             "basic_ostream<wchar_t>",       0,                     0,             0,             0,            0,             FALSE,              FALSE },
       
   263   { "ifstream",             "basic_ifstream<char>",         0,                     0,             0,             0,            0,             FALSE,              FALSE },
       
   264   { "wifstream",            "basic_ifstream<wchar_t>",      0,                     0,             0,             0,            0,             FALSE,              FALSE },
       
   265   { "ofstream",             "basic_ofstream<char>",         0,                     0,             0,             0,            0,             FALSE,              FALSE },
       
   266   { "wofstream",            "basic_ofstream<wchar_t>",      0,                     0,             0,             0,            0,             FALSE,              FALSE },
       
   267   { "fstream",              "basic_fstream<char>",          0,                     0,             0,             0,            0,             FALSE,              FALSE },
       
   268   { "wfstream",             "basic_fstream<wchar_t>",       0,                     0,             0,             0,            0,             FALSE,              FALSE },
       
   269   { "istringstream",        "basic_istringstream<char>",    0,                     0,             0,             0,            0,             FALSE,              FALSE },
       
   270   { "wistringstream",       "basic_istringstream<wchar_t>", 0,                     0,             0,             0,            0,             FALSE,              FALSE },
       
   271   { "ostringstream",        "basic_ostringstream<char>",    0,                     0,             0,             0,            0,             FALSE,              FALSE },
       
   272   { "wostringstream",       "basic_ostringstream<wchar_t>", 0,                     0,             0,             0,            0,             FALSE,              FALSE },
       
   273   { "stringstream",         "basic_stringstream<char>",     0,                     0,             0,             0,            0,             FALSE,              FALSE },
       
   274   { "wstringstream",        "basic_stringstream<wchar_t>",  0,                     0,             0,             0,            0,             FALSE,              FALSE },
       
   275   { "basic_string",         0,                              0,                     "Char",        0,             0,            0,             FALSE,              TRUE  },
       
   276   { "string",               "basic_string<char>",           0,                     0,             0,             0,            0,             FALSE,              TRUE  },
       
   277   { "wstring",              "basic_string<wchar_t>",        0,                     0,             0,             0,            0,             FALSE,              TRUE  },
       
   278   { "complex",              0,                              0,                     0,             0,             0,            0,             FALSE,              FALSE },
       
   279   { "bitset",               0,                              0,                     "Bits",        0,             0,            0,             FALSE,              FALSE },
       
   280   { "deque",                0,                              0,                     "T",           "elements",    0,            0,             FALSE,              TRUE  },
       
   281   { "list",                 0,                              0,                     "T",           "elements",    0,            0,             FALSE,              TRUE  },
       
   282   { "map",                  0,                              0,                     "K",           "keys",        "T",          "elements",    FALSE,              TRUE  },
       
   283   { "multimap",             0,                              0,                     "K",           "keys",        "T",          "elements",    FALSE,              TRUE  },
       
   284   { "set",                  0,                              0,                     "K",           "keys",        0,            0,             FALSE,              TRUE  },
       
   285   { "multiset",             0,                              0,                     "K",           "keys",        0,            0,             FALSE,              TRUE  },
       
   286   { "vector",               0,                              0,                     "T",           "elements",    0,            0,             FALSE,              TRUE  },
       
   287   { "queue",                0,                              0,                     "T",           "elements",    0,            0,             FALSE,              FALSE },
       
   288   { "priority_queue",       0,                              0,                     "T",           "elements",    0,            0,             FALSE,              FALSE },
       
   289   { "stack",                0,                              0,                     "T",           "elements",    0,            0,             FALSE,              FALSE },
       
   290   { "valarray",             0,                              0,                     "T",           "elements",    0,            0,             FALSE,              FALSE },
       
   291   { "exception",            0,                              0,                     0,             0,             0,            0,             FALSE,              FALSE },
       
   292   { "bad_alloc",            "exception",                    0,                     0,             0,             0,            0,             FALSE,              FALSE },
       
   293   { "bad_cast",             "exception",                    0,                     0,             0,             0,            0,             FALSE,              FALSE },
       
   294   { "bad_typeid",           "exception",                    0,                     0,             0,             0,            0,             FALSE,              FALSE },
       
   295   { "logic_error",          "exception",                    0,                     0,             0,             0,            0,             FALSE,              FALSE },
       
   296   { "ios_base::failure",    "exception",                    0,                     0,             0,             0,            0,             FALSE,              FALSE },
       
   297   { "runtime_error",        "exception",                    0,                     0,             0,             0,            0,             FALSE,              FALSE },
       
   298   { "bad_exception",        "exception",                    0,                     0,             0,             0,            0,             FALSE,              FALSE },
       
   299   { "domain_error",         "logic_error",                  0,                     0,             0,             0,            0,             FALSE,              FALSE },
       
   300   { "invalid_argument",     "logic_error",                  0,                     0,             0,             0,            0,             FALSE,              FALSE },
       
   301   { "length_error",         "logic_error",                  0,                     0,             0,             0,            0,             FALSE,              FALSE },
       
   302   { "out_of_range",         "logic_error",                  0,                     0,             0,             0,            0,             FALSE,              FALSE },
       
   303   { "range_error",          "runtime_error",                0,                     0,             0,             0,            0,             FALSE,              FALSE },
       
   304   { "overflow_error",       "runtime_error",                0,                     0,             0,             0,            0,             FALSE,              FALSE },
       
   305   { "underflow_error",      "runtime_error",                0,                     0,             0,             0,            0,             FALSE,              FALSE },
       
   306   { 0,                      0,                              0,                     0,             0,             0,            0,             FALSE,              FALSE }
       
   307 };
       
   308 
       
   309 static void addSTLMember(EntryNav *rootNav,const char *type,const char *name)
       
   310 {
       
   311   Entry *memEntry = new Entry;
       
   312   memEntry->name       = name;
       
   313   memEntry->type       = type;
       
   314   memEntry->protection = Private;
       
   315   memEntry->section    = Entry::VARIABLE_SEC;
       
   316   memEntry->brief      = "STL member";
       
   317   memEntry->hidden     = FALSE; 
       
   318   memEntry->artificial = TRUE;
       
   319   //memEntry->parent     = root;
       
   320   //root->addSubEntry(memEntry);
       
   321   EntryNav *memEntryNav = new EntryNav(rootNav,memEntry);
       
   322   memEntryNav->setEntry(memEntry);
       
   323   rootNav->addChild(memEntryNav);
       
   324 }
       
   325 
       
   326 static void addSTLIterator(EntryNav *classEntryNav,const char *name)
       
   327 {
       
   328   Entry *iteratorClassEntry = new Entry;
       
   329   iteratorClassEntry->fileName  = "[STL]";
       
   330   iteratorClassEntry->startLine = 1;
       
   331   iteratorClassEntry->name      = name;
       
   332   iteratorClassEntry->section   = Entry::CLASS_SEC;
       
   333   iteratorClassEntry->brief     = "STL iterator class";
       
   334   iteratorClassEntry->hidden    = FALSE;
       
   335   iteratorClassEntry->artificial= TRUE;
       
   336   EntryNav *iteratorClassEntryNav = new EntryNav(classEntryNav,iteratorClassEntry);
       
   337   iteratorClassEntryNav->setEntry(iteratorClassEntry);
       
   338   classEntryNav->addChild(iteratorClassEntryNav);
       
   339 }
       
   340 
       
   341 
       
   342 static void addSTLClasses(EntryNav *rootNav)
       
   343 {
       
   344   Entry *namespaceEntry = new Entry;
       
   345   namespaceEntry->fileName  = "[STL]";
       
   346   namespaceEntry->startLine = 1;
       
   347   //namespaceEntry->parent    = rootNav->entry();
       
   348   namespaceEntry->name      = "std";
       
   349   namespaceEntry->section   = Entry::NAMESPACE_SEC;
       
   350   namespaceEntry->brief     = "STL namespace";
       
   351   namespaceEntry->hidden    = FALSE;
       
   352   namespaceEntry->artificial= TRUE;
       
   353   //root->addSubEntry(namespaceEntry);
       
   354   EntryNav *namespaceEntryNav = new EntryNav(rootNav,namespaceEntry);
       
   355   namespaceEntryNav->setEntry(namespaceEntry);
       
   356   rootNav->addChild(namespaceEntryNav);
       
   357   
       
   358   STLInfo *info = g_stlinfo;
       
   359   while (info->className)
       
   360   {
       
   361     //printf("Adding STL class %s\n",info->className);
       
   362     QCString fullName = info->className;
       
   363     fullName.prepend("std::");
       
   364 
       
   365     // add fake Entry for the class
       
   366     Entry *classEntry = new Entry;
       
   367     classEntry->fileName  = "[STL]";
       
   368     classEntry->startLine = 1;
       
   369     classEntry->name      = fullName;
       
   370     //classEntry->parent    = namespaceEntry;
       
   371     classEntry->section   = Entry::CLASS_SEC;
       
   372     classEntry->brief     = "STL class";
       
   373     classEntry->hidden    = FALSE;
       
   374     classEntry->artificial= TRUE;
       
   375     //namespaceEntry->addSubEntry(classEntry);
       
   376     EntryNav *classEntryNav = new EntryNav(namespaceEntryNav,classEntry);
       
   377     classEntryNav->setEntry(classEntry);
       
   378     namespaceEntryNav->addChild(classEntryNav);
       
   379 
       
   380     // add template arguments to class
       
   381     if (info->templType1)
       
   382     {
       
   383       ArgumentList *al = new ArgumentList;
       
   384       Argument *a=new Argument;
       
   385       a->type="typename";
       
   386       a->name=info->templType1;
       
   387       al->append(a);
       
   388       if (info->templType2) // another template argument
       
   389       {
       
   390         a=new Argument;
       
   391         a->type="typename";
       
   392         a->name=info->templType2;
       
   393         al->append(a);
       
   394       }
       
   395       classEntry->tArgLists = new QList<ArgumentList>;
       
   396       classEntry->tArgLists->setAutoDelete(TRUE);
       
   397       classEntry->tArgLists->append(al);
       
   398     }
       
   399     // add member variables
       
   400     if (info->templName1)
       
   401     {
       
   402       addSTLMember(classEntryNav,info->templType1,info->templName1);
       
   403     }
       
   404     if (info->templName2)
       
   405     {
       
   406       addSTLMember(classEntryNav,info->templType2,info->templName2);
       
   407     }
       
   408     if (info->baseClass1)
       
   409     {
       
   410       classEntry->extends->append(new BaseInfo(info->baseClass1,Public,info->virtualInheritance?Virtual:Normal));
       
   411     }
       
   412     if (info->baseClass2)
       
   413     {
       
   414       classEntry->extends->append(new BaseInfo(info->baseClass2,Public,info->virtualInheritance?Virtual:Normal));
       
   415     }
       
   416     if (info->iterators)
       
   417     {
       
   418       // add iterator class
       
   419       addSTLIterator(classEntryNav,fullName+"::iterator");
       
   420       addSTLIterator(classEntryNav,fullName+"::const_iterator");
       
   421       addSTLIterator(classEntryNav,fullName+"::reverse_iterator");
       
   422       addSTLIterator(classEntryNav,fullName+"::const_reverse_iterator");
       
   423     }
       
   424     info++;
       
   425   }
       
   426 }
       
   427 
       
   428 //----------------------------------------------------------------------------
       
   429 
       
   430 static Definition *findScopeFromQualifiedName(Definition *startScope,const QCString &n,
       
   431                                               FileDef *fileScope=0);
       
   432 
       
   433 static void addPageToContext(PageDef *pd,EntryNav *rootNav)
       
   434 {
       
   435   if (rootNav->parent()) // add the page to it's scope
       
   436   {
       
   437     QCString scope = rootNav->parent()->name();
       
   438     if (rootNav->parent()->section()==Entry::PACKAGEDOC_SEC)
       
   439     {
       
   440       scope=substitute(scope,".","::");
       
   441     }
       
   442     scope = stripAnonymousNamespaceScope(scope);
       
   443     scope+="::"+pd->name();
       
   444     Definition *d = findScopeFromQualifiedName(Doxygen::globalScope,scope);
       
   445     if (d) 
       
   446     {
       
   447       pd->setPageScope(d);
       
   448     }
       
   449   }
       
   450 }
       
   451 
       
   452 static void addRelatedPage(EntryNav *rootNav)
       
   453 {
       
   454   Entry *root = rootNav->entry();
       
   455   GroupDef *gd=0;
       
   456   QListIterator<Grouping> gli(*root->groups);
       
   457   Grouping *g;
       
   458   for (;(g=gli.current());++gli)
       
   459   {
       
   460     if (!g->groupname.isEmpty() && (gd=Doxygen::groupSDict->find(g->groupname))) break;
       
   461   }
       
   462   //printf("---> addRelatedPage() %s gd=%p\n",root->name.data(),gd);
       
   463   QCString doc;
       
   464   if (root->brief.isEmpty())
       
   465   {
       
   466     doc=root->doc+root->inbodyDocs;
       
   467   }
       
   468   else
       
   469   {
       
   470     doc=root->brief+"\n\n"+root->doc+root->inbodyDocs;
       
   471   }
       
   472   PageDef *pd = addRelatedPage(root->name,root->args,doc,root->anchors,
       
   473       root->fileName,root->startLine,
       
   474       root->sli,
       
   475       gd,rootNav->tagInfo()
       
   476      );
       
   477   if (pd)
       
   478   {
       
   479     pd->addSectionsToDefinition(root->anchors);
       
   480     addPageToContext(pd,rootNav);
       
   481   }
       
   482 }
       
   483 
       
   484 static void buildGroupListFiltered(EntryNav *rootNav,bool additional)
       
   485 {
       
   486   if (rootNav->section()==Entry::GROUPDOC_SEC && !rootNav->name().isEmpty())
       
   487   {
       
   488     //printf("Found group %s title=`%s type=%d'\n",
       
   489     //    root->name.data(),root->type.data(),root->groupDocType);
       
   490 
       
   491     rootNav->loadEntry(g_storage);
       
   492     Entry *root = rootNav->entry();
       
   493     
       
   494     if ((root->groupDocType==Entry::GROUPDOC_NORMAL && !additional) ||
       
   495         (root->groupDocType!=Entry::GROUPDOC_NORMAL && additional))
       
   496     {
       
   497       GroupDef *gd;
       
   498 
       
   499       if ((gd=Doxygen::groupSDict->find(root->name)))
       
   500       {
       
   501         if ( !gd->hasGroupTitle() )
       
   502         {
       
   503           gd->setGroupTitle( root->type );
       
   504         }
       
   505         else if ( root->type.length() > 0 && root->name != root->type && gd->groupTitle() != root->type )
       
   506         {
       
   507           warn( root->fileName,root->startLine,
       
   508               "group %s: ignoring title \"%s\" that does not match old title \"%s\"\n",
       
   509               root->name.data(), root->type.data(), gd->groupTitle() );
       
   510         }
       
   511         gd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
       
   512         gd->setDocumentation( root->doc, root->docFile, root->docLine );
       
   513         gd->setInbodyDocumentation( root->inbodyDocs, root->inbodyFile, root->inbodyLine );
       
   514         gd->addSectionsToDefinition(root->anchors);
       
   515         gd->setRefItems(root->sli);
       
   516       }
       
   517       else
       
   518       {
       
   519         if (rootNav->tagInfo())
       
   520         {
       
   521           gd = new GroupDef(root->fileName,root->startLine,root->name,root->type,rootNav->tagInfo()->fileName);
       
   522           gd->setReference(rootNav->tagInfo()->tagName);
       
   523         }
       
   524         else
       
   525         {
       
   526           gd = new GroupDef(root->fileName,root->startLine,root->name,root->type);
       
   527         }
       
   528         gd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
       
   529         gd->setDocumentation(root->doc,root->docFile,root->docLine);
       
   530         gd->setInbodyDocumentation( root->inbodyDocs, root->inbodyFile, root->inbodyLine );
       
   531         gd->addSectionsToDefinition(root->anchors);
       
   532         Doxygen::groupSDict->append(root->name,gd);
       
   533         gd->setRefItems(root->sli);
       
   534       }
       
   535     }
       
   536 
       
   537     rootNav->releaseEntry();
       
   538   }
       
   539   if (rootNav->children())
       
   540   {
       
   541     EntryNavListIterator eli(*rootNav->children());
       
   542     EntryNav *e;
       
   543     for (;(e=eli.current());++eli)
       
   544     {
       
   545       buildGroupListFiltered(e,additional);
       
   546     }
       
   547   }
       
   548 }
       
   549 
       
   550 static void buildGroupList(EntryNav *rootNav)
       
   551 {
       
   552   // first process the @defgroups blocks
       
   553   buildGroupListFiltered(rootNav,FALSE);
       
   554   // then process the @addtogroup, @weakgroup blocks
       
   555   buildGroupListFiltered(rootNav,TRUE);
       
   556 }
       
   557 
       
   558 static void findGroupScope(EntryNav *rootNav)
       
   559 {
       
   560   if (rootNav->section()==Entry::GROUPDOC_SEC && !rootNav->name().isEmpty() && 
       
   561       rootNav->parent() && !rootNav->parent()->name().isEmpty())
       
   562   {
       
   563     GroupDef *gd;
       
   564     if ((gd=Doxygen::groupSDict->find(rootNav->name())))
       
   565     {
       
   566       QCString scope = rootNav->parent()->name();
       
   567       if (rootNav->parent()->section()==Entry::PACKAGEDOC_SEC)
       
   568       {
       
   569         scope=substitute(scope,".","::");
       
   570       }
       
   571       scope = stripAnonymousNamespaceScope(scope);
       
   572       scope+="::"+gd->name();
       
   573       Definition *d = findScopeFromQualifiedName(Doxygen::globalScope,scope);
       
   574       if (d) 
       
   575       {
       
   576         gd->setGroupScope(d);
       
   577       }
       
   578     }
       
   579   }
       
   580   RECURSE_ENTRYTREE(findGroupScope,rootNav);
       
   581 }
       
   582 
       
   583 static void organizeSubGroupsFiltered(EntryNav *rootNav,bool additional)
       
   584 {
       
   585   if (rootNav->section()==Entry::GROUPDOC_SEC && !rootNav->name().isEmpty())
       
   586   {
       
   587     rootNav->loadEntry(g_storage);
       
   588     Entry *root = rootNav->entry();
       
   589 
       
   590     if ((root->groupDocType==Entry::GROUPDOC_NORMAL && !additional) ||
       
   591         (root->groupDocType!=Entry::GROUPDOC_NORMAL && additional))
       
   592     {
       
   593       GroupDef *gd;
       
   594       if ((gd=Doxygen::groupSDict->find(root->name)))
       
   595       {
       
   596         //printf("adding %s to group %s\n",root->name.data(),gd->name().data());
       
   597         addGroupToGroups(root,gd);
       
   598       }
       
   599     }
       
   600 
       
   601     rootNav->releaseEntry();
       
   602   }
       
   603   if (rootNav->children())
       
   604   {
       
   605     EntryNavListIterator eli(*rootNav->children());
       
   606     EntryNav *e;
       
   607     for (;(e=eli.current());++eli)
       
   608     {
       
   609       organizeSubGroupsFiltered(e,additional);
       
   610     }
       
   611   }
       
   612 }
       
   613 
       
   614 static void organizeSubGroups(EntryNav *rootNav)
       
   615 {
       
   616   //printf("Defining groups\n");
       
   617   // first process the @defgroups blocks
       
   618   organizeSubGroupsFiltered(rootNav,FALSE);
       
   619   //printf("Additional groups\n");
       
   620   // then process the @addtogroup, @weakgroup blocks
       
   621   organizeSubGroupsFiltered(rootNav,TRUE);
       
   622 }
       
   623 
       
   624 //----------------------------------------------------------------------
       
   625 
       
   626 static void buildFileList(EntryNav *rootNav)
       
   627 {
       
   628   if (((rootNav->section()==Entry::FILEDOC_SEC) ||
       
   629         ((rootNav->section() & Entry::FILE_MASK) && Config_getBool("EXTRACT_ALL"))) &&
       
   630       !rootNav->name().isEmpty() && !rootNav->tagInfo() // skip any file coming from tag files
       
   631      )
       
   632   {
       
   633     rootNav->loadEntry(g_storage);
       
   634     Entry *root = rootNav->entry();
       
   635 
       
   636     bool ambig;
       
   637     FileDef *fd=findFileDef(Doxygen::inputNameDict,root->name,ambig);
       
   638     //printf("**************** root->name=%s fd=%p\n",root->name.data(),fd);
       
   639     if (fd && !ambig)
       
   640     {
       
   641 #if 0
       
   642       if ((!root->doc.isEmpty() && !fd->documentation().isEmpty()) ||
       
   643           (!root->brief.isEmpty() && !fd->briefDescription().isEmpty()))
       
   644       {
       
   645         warn(
       
   646             root->fileName,root->startLine,
       
   647             "Warning: file %s already documented. "
       
   648             "Skipping documentation.",
       
   649             root->name.data()
       
   650             );
       
   651       }
       
   652       else
       
   653 #endif
       
   654       {
       
   655         //printf("Adding documentation!\n");
       
   656         // using FALSE in setDocumentation is small hack to make sure a file 
       
   657         // is documented even if a \file command is used without further 
       
   658         // documentation
       
   659         fd->setDocumentation(root->doc,root->docFile,root->docLine,FALSE);
       
   660         fd->setBriefDescription(root->brief,root->briefFile,root->briefLine); 
       
   661         fd->addSectionsToDefinition(root->anchors);
       
   662         fd->setRefItems(root->sli);
       
   663         QListIterator<Grouping> gli(*root->groups);
       
   664         Grouping *g;
       
   665         for (;(g=gli.current());++gli)
       
   666         {
       
   667           GroupDef *gd=0;
       
   668           if (!g->groupname.isEmpty() && (gd=Doxygen::groupSDict->find(g->groupname)))
       
   669           {
       
   670             gd->addFile(fd);
       
   671             //printf("File %s: in group %s\n",fd->name().data(),s->data());
       
   672           }
       
   673         }
       
   674       }
       
   675     }
       
   676     else
       
   677     {
       
   678       const char *fn = root->fileName.data();
       
   679       QCString text;
       
   680       text.sprintf("Warning: the name `%s' supplied as "
       
   681           "the second argument in the \\file statement ",
       
   682           root->name.data()
       
   683                   );
       
   684       if (ambig) // name is ambigious
       
   685       {
       
   686         text+="matches the following input files:\n";
       
   687         text+=showFileDefMatches(Doxygen::inputNameDict,root->name);
       
   688         text+="Please use a more specific name by "
       
   689           "including a (larger) part of the path!";
       
   690       }
       
   691       else // name is not an input file
       
   692       {
       
   693         text+="is not an input file";
       
   694       }
       
   695       warn(fn,root->startLine,text);
       
   696     }
       
   697 
       
   698     rootNav->releaseEntry();
       
   699   }
       
   700   RECURSE_ENTRYTREE(buildFileList,rootNav);
       
   701 }
       
   702 
       
   703 static void addIncludeFile(ClassDef *cd,FileDef *ifd,Entry *root)
       
   704 {
       
   705   if ( 
       
   706       (!root->doc.stripWhiteSpace().isEmpty() || 
       
   707        !root->brief.stripWhiteSpace().isEmpty() || 
       
   708        Config_getBool("EXTRACT_ALL")
       
   709       ) && root->protection!=Private
       
   710      )
       
   711   { 
       
   712     //printf(">>>>>> includeFile=%s\n",root->includeFile.data());
       
   713 
       
   714     bool local=Config_getBool("FORCE_LOCAL_INCLUDES");
       
   715     QCString includeFile = root->includeFile;
       
   716     if (!includeFile.isEmpty() && includeFile.at(0)=='"')
       
   717     {
       
   718       local = TRUE;
       
   719       includeFile=includeFile.mid(1,includeFile.length()-2);
       
   720     }
       
   721     else if (!includeFile.isEmpty() && includeFile.at(0)=='<')
       
   722     {
       
   723       local = FALSE;
       
   724       includeFile=includeFile.mid(1,includeFile.length()-2);
       
   725     }
       
   726 
       
   727     bool ambig;
       
   728     FileDef *fd=0;
       
   729     // see if we need to include a verbatim copy of the header file
       
   730     //printf("root->includeFile=%s\n",root->includeFile.data());
       
   731     if (!includeFile.isEmpty() && 
       
   732         (fd=findFileDef(Doxygen::inputNameDict,includeFile,ambig))==0
       
   733        )
       
   734     { // explicit request
       
   735       QCString text;
       
   736       text.sprintf("Warning: the name `%s' supplied as "
       
   737                   "the argument of the \\class, \\struct, \\union, or \\include command ",
       
   738                   includeFile.data()
       
   739                  );
       
   740       if (ambig) // name is ambigious
       
   741       {
       
   742         text+="matches the following input files:\n";
       
   743         text+=showFileDefMatches(Doxygen::inputNameDict,root->includeFile);
       
   744         text+="Please use a more specific name by "
       
   745             "including a (larger) part of the path!";
       
   746       }
       
   747       else // name is not an input file
       
   748       {
       
   749         text+="is not an input file";
       
   750       }
       
   751       warn(root->fileName,root->startLine,text);
       
   752     }
       
   753     else if (includeFile.isEmpty() && ifd &&
       
   754         // see if the file extension makes sense
       
   755         guessSection(ifd->name())==Entry::HEADER_SEC)
       
   756     { // implicit assumption
       
   757       fd=ifd;
       
   758     }
       
   759 
       
   760     // if a file is found, we mark it as a source file.
       
   761     if (fd)
       
   762     {
       
   763       QCString iName = !root->includeName.isEmpty() ? 
       
   764                        root->includeName : includeFile;
       
   765       if (!iName.isEmpty()) // user specified include file
       
   766       {
       
   767         if (iName.at(0)=='<') local=FALSE; // explicit override
       
   768         if (iName.at(0)=='"' || iName.at(0)=='<')
       
   769         {
       
   770           iName=iName.mid(1,iName.length()-2); // strip quotes or brackets
       
   771         }
       
   772         if (iName.isEmpty())
       
   773         {
       
   774           iName=fd->name();
       
   775         }
       
   776       }
       
   777       else if (!Config_getList("STRIP_FROM_INC_PATH").isEmpty()) 
       
   778       {
       
   779         iName=stripFromIncludePath(fd->absFilePath());
       
   780       }
       
   781       else // use name of the file containing the class definition
       
   782       {
       
   783         iName=fd->name();
       
   784       }
       
   785       if (fd->generateSourceFile()) // generate code for header
       
   786       {
       
   787         cd->setIncludeFile(fd,iName,local,!root->includeName.isEmpty());
       
   788       }
       
   789       else // put #include in the class documentation without link
       
   790       {
       
   791         cd->setIncludeFile(0,iName,local,TRUE);
       
   792       }
       
   793     }
       
   794   }
       
   795 }
       
   796 
       
   797 #if 0
       
   798 static bool addNamespace(Entry *root,ClassDef *cd)
       
   799 {
       
   800   // see if this class is defined inside a namespace
       
   801   if (root->section & Entry::COMPOUND_MASK)
       
   802   {
       
   803     Entry *e = root->parent;
       
   804     while (e)
       
   805     {
       
   806       if (e->section==Entry::NAMESPACE_SEC)
       
   807       {
       
   808         NamespaceDef *nd=0;
       
   809         QCString nsName = stripAnonymousNamespaceScope(e->name);
       
   810         //printf("addNameSpace() trying: %s\n",nsName.data());
       
   811         if (!nsName.isEmpty() && nsName.at(0)!='@' &&
       
   812             (nd=getResolvedNamespace(nsName))
       
   813            )
       
   814         {
       
   815           cd->setNamespace(nd);
       
   816           cd->setOuterScope(nd);
       
   817           nd->insertClass(cd);
       
   818           return TRUE;
       
   819         }
       
   820       }
       
   821       e=e->parent;
       
   822     } 
       
   823   }
       
   824   return FALSE;
       
   825 }
       
   826 #endif
       
   827 
       
   828 #if 0
       
   829 static Definition *findScope(Entry *root,int level=0)
       
   830 {
       
   831   if (root==0) return 0;
       
   832   //printf("start findScope name=%s\n",root->name.data());
       
   833   Definition *result=0;
       
   834   if (root->section&Entry::SCOPE_MASK)
       
   835   {
       
   836     result = findScope(root->parent,level+1); // traverse to the root of the tree
       
   837     if (result)
       
   838     {
       
   839       //printf("Found %s inside %s at level %d\n",root->name.data(),result->name().data(),level);
       
   840       // TODO: look at template arguments
       
   841       result = result->findInnerCompound(root->name);
       
   842     }
       
   843     else // reached the global scope
       
   844     {
       
   845       // TODO: look at template arguments
       
   846       result = Doxygen::globalScope->findInnerCompound(root->name);
       
   847       //printf("Found in globalScope %s at level %d\n",result->name().data(),level);
       
   848     }
       
   849   }
       
   850   //printf("end findScope(%s,%d)=%s\n",root->name.data(),
       
   851   //       level,result==0 ? "<none>" : result->name().data());
       
   852   return result;
       
   853 }
       
   854 #endif
       
   855 
       
   856 /*! returns the Definition object belonging to the first \a level levels of 
       
   857  *  full qualified name \a name. Creates an artificial scope if the scope is
       
   858  *  not found and set the parent/child scope relation if the scope is found.
       
   859  */
       
   860 static Definition *buildScopeFromQualifiedName(const QCString name,int level)
       
   861 {
       
   862   int i=0;
       
   863   int p=0,l;
       
   864   Definition *prevScope=Doxygen::globalScope;
       
   865   QCString fullScope;
       
   866   while (i<level)
       
   867   {
       
   868     int idx=getScopeFragment(name,p,&l);
       
   869     QCString nsName = name.mid(idx,l);
       
   870     if (nsName.isEmpty()) return prevScope;
       
   871     if (!fullScope.isEmpty()) fullScope+="::";
       
   872     fullScope+=nsName;
       
   873     NamespaceDef *nd=Doxygen::namespaceSDict->find(fullScope);
       
   874     Definition *innerScope = nd;
       
   875     ClassDef *cd=0; 
       
   876     if (nd==0) cd = getClass(fullScope);
       
   877     if (nd==0 && cd) // scope is a class
       
   878     {
       
   879       innerScope = cd;
       
   880     }
       
   881     else if (nd==0 && cd==0) // scope is not known!
       
   882     {
       
   883       // introduce bogus namespace
       
   884       //printf("++ adding dummy namespace %s to %s\n",nsName.data(),prevScope->name().data());
       
   885       nd=new NamespaceDef(
       
   886         "[generated]",1,fullScope);
       
   887 
       
   888       // add namespace to the list
       
   889       Doxygen::namespaceSDict->inSort(fullScope,nd);
       
   890       innerScope = nd;
       
   891     }
       
   892     else // scope is a namespace
       
   893     {
       
   894     }
       
   895     // make the parent/child scope relation
       
   896     prevScope->addInnerCompound(innerScope);
       
   897     innerScope->setOuterScope(prevScope);
       
   898     // proceed to the next scope fragment
       
   899     p=idx+l+2;
       
   900     prevScope=innerScope;
       
   901     i++;
       
   902   }
       
   903   return prevScope;
       
   904 }
       
   905 
       
   906 static Definition *findScopeFromQualifiedName(Definition *startScope,const QCString &n,
       
   907                                               FileDef *fileScope)
       
   908 {
       
   909   //printf("<findScopeFromQualifiedName(%s,%s)\n",startScope ? startScope->name().data() : 0, n.data());
       
   910   Definition *resultScope=startScope;
       
   911   if (resultScope==0) resultScope=Doxygen::globalScope;
       
   912   QCString scope=stripTemplateSpecifiersFromScope(n,FALSE);
       
   913   int l1=0,i1;
       
   914   i1=getScopeFragment(scope,0,&l1);
       
   915   if (i1==-1) 
       
   916   {
       
   917     //printf(">no fragments!\n");
       
   918     return resultScope;
       
   919   }
       
   920   int p=i1+l1,l2=0,i2;
       
   921   while ((i2=getScopeFragment(scope,p,&l2))!=-1)
       
   922   {
       
   923     QCString nestedNameSpecifier = scope.mid(i1,l1);
       
   924     Definition *orgScope = resultScope;
       
   925     //printf("  nestedNameSpecifier=%s\n",nestedNameSpecifier.data());
       
   926     resultScope = resultScope->findInnerCompound(nestedNameSpecifier);
       
   927     //printf("  resultScope=%p\n",resultScope);
       
   928     if (resultScope==0) 
       
   929     {
       
   930       NamespaceSDict *usedNamespaces;
       
   931       if (orgScope==Doxygen::globalScope && fileScope &&
       
   932           (usedNamespaces = fileScope->getUsedNamespaces())) 
       
   933         // also search for used namespaces 
       
   934       {
       
   935         NamespaceSDict::Iterator ni(*usedNamespaces);
       
   936         NamespaceDef *nd;
       
   937         for (ni.toFirst();((nd=ni.current()) && resultScope==0);++ni)
       
   938         {
       
   939           // restart search within the used namespace
       
   940           resultScope = findScopeFromQualifiedName(nd,n,fileScope);
       
   941         }
       
   942         if (resultScope) 
       
   943         {
       
   944           // for a nested class A::I in used namespace N, we get
       
   945           // N::A::I while looking for A, so we should compare
       
   946           // resultScope->name() against scope.left(i2+l2)
       
   947           //printf("  -> result=%s scope=%s\n",resultScope->name().data(),scope.data());
       
   948           if (rightScopeMatch(resultScope->name(),scope.left(i2+l2)))
       
   949           {
       
   950             break;
       
   951           }
       
   952           goto nextFragment;
       
   953         }
       
   954       }
       
   955 
       
   956       // also search for used classes. Complication: we haven't been able 
       
   957       // to put them in the right scope yet, because we are still resolving
       
   958       // the scope relations!
       
   959       // Therefore loop through all used classes and see if there is a right 
       
   960       // scope match between the used class and nestedNameSpecifier.
       
   961       QDictIterator<FileDef> ui(g_usingDeclarations);
       
   962       FileDef *usedFd;
       
   963       for (ui.toFirst();(usedFd=ui.current());++ui)
       
   964       {
       
   965         //printf("Checking using class %s\n",ui.currentKey());
       
   966         if (rightScopeMatch(ui.currentKey(),nestedNameSpecifier))
       
   967         {
       
   968           // ui.currentKey() is the fully qualified name of nestedNameSpecifier
       
   969           // so use this instead.
       
   970           QCString fqn = QCString(ui.currentKey())+
       
   971                          scope.right(scope.length()-p);
       
   972           resultScope = buildScopeFromQualifiedName(fqn,fqn.contains("::"));
       
   973           //printf("Creating scope from fqn=%s result %p\n",fqn.data(),resultScope);
       
   974           if (resultScope) 
       
   975           {
       
   976             //printf("> Match! resultScope=%s\n",resultScope->name().data());
       
   977             return resultScope;
       
   978           }
       
   979         }
       
   980       }
       
   981       
       
   982       //printf("> name %s not found in scope %s\n",nestedNameSpecifier.data(),orgScope->name().data());
       
   983       return 0;
       
   984     }
       
   985  nextFragment:
       
   986     i1=i2;
       
   987     l1=l2;
       
   988     p=i2+l2;
       
   989   }
       
   990   //printf(">findScopeFromQualifiedName scope %s\n",resultScope->name().data());
       
   991   return resultScope;
       
   992 }
       
   993 
       
   994 ArgumentList *getTemplateArgumentsFromName(
       
   995                   const QCString &name,
       
   996                   const QList<ArgumentList> *tArgLists)
       
   997 {
       
   998   if (tArgLists==0) return 0;
       
   999   
       
  1000   QListIterator<ArgumentList> ali(*tArgLists);
       
  1001   // for each scope fragment, check if it is a template and advance through
       
  1002   // the list if so.
       
  1003   int i,p=0;
       
  1004   while ((i=name.find("::",p))!=-1)
       
  1005   {
       
  1006     NamespaceDef *nd = Doxygen::namespaceSDict->find(name.left(i));
       
  1007     if (nd==0)
       
  1008     {
       
  1009       ClassDef *cd = getClass(name.left(i));
       
  1010       if (cd)
       
  1011       {
       
  1012         if (cd->templateArguments())
       
  1013         {
       
  1014           ++ali;
       
  1015         }
       
  1016       }
       
  1017     }
       
  1018     p=i+2;
       
  1019   }
       
  1020   return ali.current();
       
  1021 }
       
  1022 
       
  1023 static ClassDef::CompoundType convertToCompoundType(int section,int specifier)
       
  1024 {
       
  1025     ClassDef::CompoundType sec=ClassDef::Class; 
       
  1026     if (specifier&Entry::Struct) 
       
  1027       sec=ClassDef::Struct;
       
  1028     else if (specifier&Entry::Union) 
       
  1029       sec=ClassDef::Union;
       
  1030     else if (specifier&Entry::Interface) 
       
  1031       sec=ClassDef::Interface;
       
  1032     else if (specifier&Entry::Protocol) 
       
  1033       sec=ClassDef::Protocol;
       
  1034     else if (specifier&Entry::Category) 
       
  1035       sec=ClassDef::Category;
       
  1036     else if (specifier&Entry::Exception) 
       
  1037       sec=ClassDef::Exception;
       
  1038 
       
  1039     switch(section)
       
  1040     {
       
  1041       //case Entry::UNION_SEC: 
       
  1042       case Entry::UNIONDOC_SEC: 
       
  1043         sec=ClassDef::Union; 
       
  1044         break;
       
  1045       //case Entry::STRUCT_SEC:
       
  1046       case Entry::STRUCTDOC_SEC: 
       
  1047         sec=ClassDef::Struct; 
       
  1048         break;
       
  1049       //case Entry::INTERFACE_SEC:
       
  1050       case Entry::INTERFACEDOC_SEC:
       
  1051         sec=ClassDef::Interface; 
       
  1052         break;
       
  1053       //case Entry::PROTOCOL_SEC:
       
  1054       case Entry::PROTOCOLDOC_SEC:
       
  1055         sec=ClassDef::Protocol; 
       
  1056         break;
       
  1057       //case Entry::CATEGORY_SEC:
       
  1058       case Entry::CATEGORYDOC_SEC:
       
  1059         sec=ClassDef::Category; 
       
  1060         break;
       
  1061       //case Entry::EXCEPTION_SEC:
       
  1062       case Entry::EXCEPTIONDOC_SEC:
       
  1063         sec=ClassDef::Exception; 
       
  1064         break;
       
  1065     }
       
  1066     return sec;
       
  1067 }
       
  1068 
       
  1069 
       
  1070 static void addClassToContext(EntryNav *rootNav)
       
  1071 {
       
  1072   //printf("Loading entry for rootNav=%p name=%s\n",rootNav,rootNav->name().data());
       
  1073   rootNav->loadEntry(g_storage);
       
  1074   Entry *root = rootNav->entry();
       
  1075 
       
  1076   //NamespaceDef *nd = 0;
       
  1077   FileDef *fd = rootNav->fileDef();
       
  1078 
       
  1079   QCString scName;
       
  1080   if (rootNav->parent()->section()&Entry::SCOPE_MASK)
       
  1081   {
       
  1082      scName=rootNav->parent()->name();
       
  1083   }
       
  1084   // name without parent's scope
       
  1085   QCString fullName = root->name;
       
  1086 
       
  1087   // strip off any template parameters (but not those for specializations)
       
  1088   fullName=stripTemplateSpecifiersFromScope(fullName);
       
  1089 
       
  1090   // name with scope (if not present already)
       
  1091   QCString qualifiedName = fullName;
       
  1092   if (!scName.isEmpty() && !leftScopeMatch(fullName,scName))
       
  1093   {
       
  1094     qualifiedName.prepend(scName+"::");
       
  1095   }
       
  1096 
       
  1097   // see if we already found the class before
       
  1098   ClassDef *cd = getClass(qualifiedName);
       
  1099 
       
  1100   Debug::print(Debug::Classes,0, "  Found class with name %s (qualifiedName=%s -> cd=%p)\n",
       
  1101       cd ? cd->name().data() : root->name.data(), qualifiedName.data(),cd);
       
  1102   
       
  1103   if (cd) 
       
  1104   {
       
  1105     fullName=cd->name();
       
  1106     Debug::print(Debug::Classes,0,"  Existing class %s!\n",cd->name().data());
       
  1107     //if (cd->templateArguments()==0)
       
  1108     //{
       
  1109     //  //printf("existing ClassDef tempArgList=%p specScope=%s\n",root->tArgList,root->scopeSpec.data());
       
  1110     //  cd->setTemplateArguments(tArgList);
       
  1111     //}
       
  1112 
       
  1113     cd->setDocumentation(root->doc,root->docFile,root->docLine);
       
  1114     cd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
       
  1115 
       
  1116     if (root->bodyLine!=-1 && cd->getStartBodyLine()==-1)
       
  1117     {
       
  1118       cd->setBodySegment(root->bodyLine,root->endBodyLine);
       
  1119       cd->setBodyDef(fd);
       
  1120     }
       
  1121     //cd->setName(fullName); // change name to match docs
       
  1122 
       
  1123     if (cd->templateArguments()==0) 
       
  1124     {
       
  1125       // this happens if a template class declared with @class is found
       
  1126       // before the actual definition.
       
  1127       ArgumentList *tArgList = 
       
  1128         getTemplateArgumentsFromName(cd->name(),root->tArgLists);
       
  1129       cd->setTemplateArguments(tArgList);
       
  1130     }
       
  1131 
       
  1132     cd->setCompoundType(convertToCompoundType(root->section,root->spec));
       
  1133   }
       
  1134   else // new class
       
  1135   {
       
  1136     ClassDef::CompoundType sec = convertToCompoundType(root->section,root->spec);
       
  1137 
       
  1138     QCString className;
       
  1139     QCString namespaceName;
       
  1140     extractNamespaceName(fullName,className,namespaceName);
       
  1141 
       
  1142     //printf("New class: fullname %s namespace `%s' name=`%s' brief=`%s' docs=`%s'\n",
       
  1143     //    fullName.data(),namespaceName.data(),className.data(),root->brief.data(),root->doc.data());
       
  1144 
       
  1145     QCString tagName;
       
  1146     QCString refFileName;
       
  1147     if (rootNav->tagInfo())
       
  1148     {
       
  1149       tagName     = rootNav->tagInfo()->tagName;
       
  1150       refFileName = rootNav->tagInfo()->fileName;
       
  1151     }
       
  1152     cd=new ClassDef(root->fileName,root->startLine,fullName,sec,
       
  1153         tagName,refFileName);
       
  1154     Debug::print(Debug::Classes,0,"  New class `%s' (sec=0x%08x)! #tArgLists=%d\n",
       
  1155         fullName.data(),root->section,root->tArgLists ? (int)root->tArgLists->count() : -1);
       
  1156     cd->setDocumentation(root->doc,root->docFile,root->docLine); // copy docs to definition
       
  1157     cd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
       
  1158     cd->setIsObjectiveC(root->objc);
       
  1159     cd->setHidden(root->hidden);
       
  1160     cd->setArtificial(root->artificial);
       
  1161     cd->setTypeConstraints(root->typeConstr);
       
  1162     //printf("new ClassDef %s tempArgList=%p specScope=%s\n",fullName.data(),root->tArgList,root->scopeSpec.data());
       
  1163 
       
  1164     ArgumentList *tArgList = 
       
  1165       getTemplateArgumentsFromName(fullName,root->tArgLists);
       
  1166     //printf("class %s template args=%s\n",fullName.data(),
       
  1167     //    tArgList ? tempArgListToString(tArgList).data() : "<none>");
       
  1168     cd->setTemplateArguments(tArgList);
       
  1169     cd->setProtection(root->protection);
       
  1170     cd->setIsStatic(root->stat);
       
  1171 
       
  1172     // file definition containing the class cd
       
  1173     cd->setBodySegment(root->bodyLine,root->endBodyLine);
       
  1174     cd->setBodyDef(fd);
       
  1175 
       
  1176     // see if the class is found inside a namespace 
       
  1177     //bool found=addNamespace(root,cd);
       
  1178 
       
  1179 
       
  1180     // the empty string test is needed for extract all case
       
  1181     cd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
       
  1182     cd->insertUsedFile(root->fileName);
       
  1183 
       
  1184     // add class to the list
       
  1185     //printf("ClassDict.insert(%s)\n",resolveDefines(fullName).data());
       
  1186     Doxygen::classSDict->append(fullName,cd);
       
  1187 
       
  1188   }
       
  1189 
       
  1190   cd->addSectionsToDefinition(root->anchors);
       
  1191   if (!root->subGrouping) cd->setSubGrouping(FALSE);
       
  1192   if (cd->hasDocumentation())
       
  1193   {
       
  1194     addIncludeFile(cd,fd,root);
       
  1195   }
       
  1196   if (fd && (root->section & Entry::COMPOUND_MASK)) 
       
  1197   {
       
  1198     //printf(">> Inserting class `%s' in file `%s' (root->fileName=`%s')\n",
       
  1199     //    cd->name().data(),
       
  1200     //    fd->name().data(),
       
  1201     //    root->fileName.data()
       
  1202     //   );
       
  1203     cd->setFileDef(fd);
       
  1204     fd->insertClass(cd);
       
  1205   }
       
  1206   addClassToGroups(root,cd);
       
  1207   cd->setRefItems(root->sli);
       
  1208 
       
  1209   rootNav->releaseEntry();
       
  1210 }
       
  1211             
       
  1212 //----------------------------------------------------------------------
       
  1213 // build a list of all classes mentioned in the documentation
       
  1214 // and all classes that have a documentation block before their definition.
       
  1215 static void buildClassList(EntryNav *rootNav)
       
  1216 {
       
  1217   if (
       
  1218         ((rootNav->section() & Entry::COMPOUND_MASK) || 
       
  1219          rootNav->section()==Entry::OBJCIMPL_SEC) && !rootNav->name().isEmpty()
       
  1220      )
       
  1221   {
       
  1222     addClassToContext(rootNav);
       
  1223   }
       
  1224   RECURSE_ENTRYTREE(buildClassList,rootNav);
       
  1225 }
       
  1226 
       
  1227 static void buildClassDocList(EntryNav *rootNav)
       
  1228 {
       
  1229   if (
       
  1230        (rootNav->section() & Entry::COMPOUNDDOC_MASK) && !rootNav->name().isEmpty()
       
  1231      )
       
  1232   {
       
  1233     addClassToContext(rootNav);
       
  1234   }
       
  1235   RECURSE_ENTRYTREE(buildClassDocList,rootNav);
       
  1236 }
       
  1237 
       
  1238 static void resolveClassNestingRelations()
       
  1239 {
       
  1240   ClassSDict::Iterator cli(*Doxygen::classSDict);
       
  1241   for (cli.toFirst();cli.current();++cli) cli.current()->visited=FALSE;
       
  1242 
       
  1243   bool done=FALSE;
       
  1244   int iteration=0;
       
  1245   while (!done)
       
  1246   {
       
  1247     done=TRUE;
       
  1248     ++iteration;
       
  1249     ClassDef *cd=0;
       
  1250     for (cli.toFirst();(cd=cli.current());++cli)
       
  1251     {
       
  1252       if (!cd->visited)
       
  1253       {
       
  1254         QCString name = stripAnonymousNamespaceScope(cd->name());
       
  1255         //printf("processing=%s, iteration=%d\n",cd->name().data(),iteration);
       
  1256         // also add class to the correct structural context 
       
  1257         Definition *d = findScopeFromQualifiedName(Doxygen::globalScope,
       
  1258                                                  name,cd->getFileDef());
       
  1259         if (d)
       
  1260         {
       
  1261           //printf("****** adding %s to scope %s in iteration %d\n",cd->name().data(),d->name().data(),iteration);
       
  1262           d->addInnerCompound(cd);
       
  1263           cd->setOuterScope(d);
       
  1264           cd->visited=TRUE;
       
  1265           done=FALSE;
       
  1266         }
       
  1267         //else
       
  1268         //{
       
  1269         //  printf("****** ignoring %s: scope not (yet) found in iteration %d\n",cd->name().data(),iteration);
       
  1270         //}
       
  1271       }
       
  1272     }
       
  1273   }
       
  1274 
       
  1275   //give warnings for unresolved compounds
       
  1276   ClassDef *cd=0;
       
  1277   for (cli.toFirst();(cd=cli.current());++cli)
       
  1278   {
       
  1279     if (!cd->visited)
       
  1280     {
       
  1281       QCString name = stripAnonymousNamespaceScope(cd->name());
       
  1282       //printf("processing unresolved=%s, iteration=%d\n",cd->name().data(),iteration);
       
  1283       /// create the scope artificially
       
  1284       // anyway, so we can at least relate scopes properly.
       
  1285       Definition *d = buildScopeFromQualifiedName(name,name.contains("::"));
       
  1286       if (d!=cd && !cd->getDefFileName().isEmpty()) 
       
  1287                  // avoid recursion in case of redundant scopes, i.e: namespace N { class N::C {}; }
       
  1288                  // for this case doxygen assumes the exitance of a namespace N::N in which C is to be found!
       
  1289                  // also avoid warning for stuff imported via a tagfile.
       
  1290       {
       
  1291         d->addInnerCompound(cd);
       
  1292         cd->setOuterScope(d);
       
  1293         warn(cd->getDefFileName(),cd->getDefLine(),
       
  1294             "Warning: Internal inconsistency: scope for class %s not "
       
  1295             "found!",name.data()
       
  1296             );
       
  1297       }
       
  1298     }
       
  1299   }
       
  1300 }
       
  1301 
       
  1302 
       
  1303 //----------------------------------------------------------------------
       
  1304 // build a list of all namespaces mentioned in the documentation
       
  1305 // and all namespaces that have a documentation block before their definition.
       
  1306 static void buildNamespaceList(EntryNav *rootNav)
       
  1307 {
       
  1308   if (
       
  1309        (rootNav->section()==Entry::NAMESPACE_SEC ||
       
  1310         rootNav->section()==Entry::NAMESPACEDOC_SEC ||
       
  1311         rootNav->section()==Entry::PACKAGEDOC_SEC
       
  1312        ) && 
       
  1313        !rootNav->name().isEmpty()
       
  1314      )
       
  1315   {
       
  1316     rootNav->loadEntry(g_storage);
       
  1317     Entry *root = rootNav->entry();
       
  1318 
       
  1319     //printf("** buildNamespaceList(%s)\n",root->name.data());
       
  1320 
       
  1321     QCString fName = root->name;
       
  1322     if (root->section==Entry::PACKAGEDOC_SEC)
       
  1323     {
       
  1324       fName=substitute(fName,".","::");
       
  1325     }
       
  1326 
       
  1327     QCString fullName = stripAnonymousNamespaceScope(fName);
       
  1328     if (!fullName.isEmpty())
       
  1329     {
       
  1330       //printf("Found namespace %s in %s at line %d\n",root->name.data(),
       
  1331       //        root->fileName.data(), root->startLine);
       
  1332       NamespaceDef *nd;
       
  1333       if ((nd=Doxygen::namespaceSDict->find(fullName))) // existing namespace
       
  1334       {
       
  1335 #if 0
       
  1336         if (!root->doc.isEmpty() || !root->brief.isEmpty()) // block contains docs
       
  1337         { 
       
  1338           if (nd->documentation().isEmpty() && !root->doc.isEmpty())
       
  1339           {
       
  1340 #endif
       
  1341             nd->setDocumentation(root->doc,root->docFile,root->docLine);
       
  1342             nd->setName(fullName); // change name to match docs
       
  1343             nd->addSectionsToDefinition(root->anchors);
       
  1344 #if 0
       
  1345           }
       
  1346           else if (!nd->documentation().isEmpty() && !root->doc.isEmpty())
       
  1347           {
       
  1348             warn(
       
  1349                  root->fileName,root->startLine,
       
  1350                  "Warning: namespace %s already has a detailed description found in file %s at line %d. "
       
  1351                  "Skipping the documentation found here.",
       
  1352                  fullName.data(),nd->docFile().data(),nd->docLine());
       
  1353           }
       
  1354           if (nd->briefDescription().isEmpty() && !root->brief.isEmpty())
       
  1355           {
       
  1356 #endif
       
  1357             nd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
       
  1358 #if 0
       
  1359             nd->setName(fullName); // change name to match docs
       
  1360           }
       
  1361           else if (!nd->briefDescription().isEmpty() && !root->brief.isEmpty())
       
  1362           {
       
  1363             warn(root->fileName,root->startLine,
       
  1364                  "Warning: namespace %s already has a brief description found in file %s at line %d. "
       
  1365                  "Skipping the documentation found here.",
       
  1366                  fullName.data(),nd->docFile().data(),nd->docLine()
       
  1367                 );
       
  1368           }
       
  1369         }
       
  1370 #endif
       
  1371 
       
  1372         // file definition containing the namespace nd
       
  1373         FileDef *fd=rootNav->fileDef();
       
  1374         // insert the namespace in the file definition
       
  1375         if (fd) fd->insertNamespace(nd);
       
  1376         addNamespaceToGroups(root,nd);
       
  1377         nd->setRefItems(root->sli);
       
  1378       }
       
  1379       else // fresh namespace
       
  1380       {
       
  1381         QCString tagName;
       
  1382         QCString tagFileName;
       
  1383         if (rootNav->tagInfo())
       
  1384         {
       
  1385           tagName=rootNav->tagInfo()->tagName;
       
  1386           tagFileName=rootNav->tagInfo()->fileName;
       
  1387         }
       
  1388         //printf("++ new namespace %d\n",fullName.data());
       
  1389         NamespaceDef *nd=new NamespaceDef(root->fileName,root->startLine,fullName,tagName,tagFileName);
       
  1390         nd->setDocumentation(root->doc,root->docFile,root->docLine); // copy docs to definition
       
  1391         nd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
       
  1392         nd->addSectionsToDefinition(root->anchors);
       
  1393         nd->setHidden(root->hidden);
       
  1394         nd->setArtificial(root->artificial);
       
  1395 
       
  1396         //printf("Adding namespace to group\n");
       
  1397         addNamespaceToGroups(root,nd);
       
  1398         nd->setRefItems(root->sli);
       
  1399 
       
  1400         // file definition containing the namespace nd
       
  1401         FileDef *fd=rootNav->fileDef();
       
  1402         // insert the namespace in the file definition
       
  1403         if (fd) fd->insertNamespace(nd);
       
  1404 
       
  1405         // the empty string test is needed for extract all case
       
  1406         nd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
       
  1407         nd->insertUsedFile(root->fileName);
       
  1408         nd->setBodySegment(root->bodyLine,root->endBodyLine);
       
  1409         nd->setBodyDef(fd);
       
  1410         // add class to the list
       
  1411         Doxygen::namespaceSDict->inSort(fullName,nd);
       
  1412 
       
  1413         // also add namespace to the correct structural context 
       
  1414         Definition *d = findScopeFromQualifiedName(Doxygen::globalScope,fullName);
       
  1415         //printf("adding namespace %s to context %s\n",nd->name().data(),d?d->name().data():"<none>");
       
  1416         if (d==0) // we didn't find anything, create the scope artificially
       
  1417                   // anyway, so we can at least relate scopes properly.
       
  1418         {
       
  1419           Definition *d = buildScopeFromQualifiedName(fullName,fullName.contains("::"));
       
  1420           d->addInnerCompound(nd);
       
  1421           nd->setOuterScope(d);
       
  1422           // TODO: Due to the order in which the tag file is written
       
  1423           // a nested class can be found before its parent!
       
  1424         }
       
  1425         else
       
  1426         {
       
  1427           d->addInnerCompound(nd);
       
  1428           nd->setOuterScope(d);
       
  1429         }
       
  1430       }
       
  1431     }
       
  1432 
       
  1433     rootNav->releaseEntry();
       
  1434   }
       
  1435   RECURSE_ENTRYTREE(buildNamespaceList,rootNav);
       
  1436 }
       
  1437 
       
  1438 //----------------------------------------------------------------------
       
  1439 
       
  1440 static NamespaceDef *findUsedNamespace(NamespaceSDict *unl,
       
  1441                               const QCString &name)
       
  1442 {
       
  1443   NamespaceDef *usingNd =0;
       
  1444   if (unl)
       
  1445   {
       
  1446     //printf("Found namespace dict %d\n",unl->count());
       
  1447     NamespaceSDict::Iterator unli(*unl);
       
  1448     NamespaceDef *und;
       
  1449     for (unli.toFirst();(und=unli.current());++unli)
       
  1450     {
       
  1451       QCString uScope=und->name()+"::";
       
  1452       usingNd = getResolvedNamespace(uScope+name);
       
  1453       //printf("Also trying with scope=`%s' usingNd=%p\n",(uScope+name).data(),usingNd);
       
  1454     }
       
  1455   }
       
  1456   return usingNd;
       
  1457 }
       
  1458 
       
  1459 static void findUsingDirectives(EntryNav *rootNav)
       
  1460 {
       
  1461   if (rootNav->section()==Entry::USINGDIR_SEC)
       
  1462   {
       
  1463     rootNav->loadEntry(g_storage);
       
  1464     Entry *root = rootNav->entry();
       
  1465 
       
  1466     //printf("Found using directive %s at line %d of %s\n",
       
  1467     //    root->name.data(),root->startLine,root->fileName.data());
       
  1468     QCString name=substitute(root->name,".","::");
       
  1469     if (!name.isEmpty())
       
  1470     {
       
  1471       NamespaceDef *usingNd = 0;
       
  1472       NamespaceDef *nd = 0;
       
  1473       FileDef      *fd = rootNav->fileDef();
       
  1474       QCString nsName;
       
  1475 
       
  1476       // see if the using statement was found inside a namespace or inside
       
  1477       // the global file scope.
       
  1478       if (rootNav->parent() && rootNav->parent()->section()==Entry::NAMESPACE_SEC &&
       
  1479           (fd==0 || !fd->isJava()) // not a .java file
       
  1480          )
       
  1481       {
       
  1482         nsName=stripAnonymousNamespaceScope(rootNav->parent()->name());
       
  1483         if (!nsName.isEmpty())
       
  1484         {
       
  1485           nd = getResolvedNamespace(nsName);
       
  1486         }
       
  1487       }
       
  1488 
       
  1489       // find the scope in which the `using' namespace is defined by prepending
       
  1490       // the possible scopes in which the using statement was found, starting
       
  1491       // with the most inner scope and going to the most outer scope (i.e. 
       
  1492       // file scope). 
       
  1493       int scopeOffset = nsName.length();
       
  1494       do
       
  1495       {
       
  1496         QCString scope=scopeOffset>0 ? 
       
  1497                       nsName.left(scopeOffset)+"::" : QCString();
       
  1498         usingNd = getResolvedNamespace(scope+name);
       
  1499         //printf("Trying with scope=`%s' usingNd=%p\n",(scope+name).data(),usingNd);
       
  1500         if (scopeOffset==0)
       
  1501         {
       
  1502           scopeOffset=-1;
       
  1503         }
       
  1504         else if ((scopeOffset=nsName.findRev("::",scopeOffset-1))==-1)
       
  1505         {
       
  1506           scopeOffset=0;
       
  1507         }
       
  1508       } while (scopeOffset>=0 && usingNd==0);
       
  1509 
       
  1510       if (usingNd==0 && nd) // not found, try used namespaces in this scope
       
  1511                             // or in one of the parent namespace scopes
       
  1512       {
       
  1513         NamespaceDef *pnd = nd;
       
  1514         while (pnd && usingNd==0)
       
  1515         {
       
  1516           // also try with one of the used namespaces found earlier
       
  1517           usingNd = findUsedNamespace(pnd->getUsedNamespaces(),name);
       
  1518 
       
  1519           // goto the parent
       
  1520           Definition *s = pnd->getOuterScope();
       
  1521           if (s && s->definitionType()==Definition::TypeNamespace)
       
  1522           {
       
  1523             pnd = (NamespaceDef*)s;
       
  1524           }
       
  1525           else
       
  1526           {
       
  1527             pnd = 0;
       
  1528           }
       
  1529         }
       
  1530       }
       
  1531       if (usingNd==0 && fd) // still nothing, also try used namespace in the
       
  1532                             // global scope
       
  1533       {
       
  1534         usingNd = findUsedNamespace(fd->getUsedNamespaces(),name);
       
  1535       }
       
  1536 
       
  1537       //printf("%s -> %s\n",name.data(),usingNd?usingNd->name().data():"<none>");
       
  1538 
       
  1539       // add the namespace the correct scope
       
  1540       if (usingNd)
       
  1541       {
       
  1542         //printf("using fd=%p nd=%p\n",fd,nd);
       
  1543         if (nd)
       
  1544         {
       
  1545           //printf("Inside namespace %s\n",nd->name().data());
       
  1546           nd->addUsingDirective(usingNd);
       
  1547         }
       
  1548         else if (fd)
       
  1549         {
       
  1550           //printf("Inside file %s\n",fd->name().data());
       
  1551           fd->addUsingDirective(usingNd);
       
  1552         }
       
  1553       }
       
  1554       else // unknown namespace, but add it anyway.
       
  1555       {
       
  1556         //printf("++ new unknown namespace %s\n",name.data());
       
  1557         NamespaceDef *nd=new NamespaceDef(root->fileName,root->startLine,name);
       
  1558         nd->setDocumentation(root->doc,root->docFile,root->docLine); // copy docs to definition
       
  1559         nd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
       
  1560         nd->addSectionsToDefinition(root->anchors);
       
  1561         //printf("** Adding namespace %s hidden=%d\n",name.data(),root->hidden);
       
  1562         nd->setHidden(root->hidden);
       
  1563         nd->setArtificial(TRUE);
       
  1564 
       
  1565         QListIterator<Grouping> gli(*root->groups);
       
  1566         Grouping *g;
       
  1567         for (;(g=gli.current());++gli)
       
  1568         {
       
  1569           GroupDef *gd=0;
       
  1570           if (!g->groupname.isEmpty() && (gd=Doxygen::groupSDict->find(g->groupname)))
       
  1571             gd->addNamespace(nd);
       
  1572         }
       
  1573 
       
  1574         // insert the namespace in the file definition
       
  1575         if (fd) 
       
  1576         {
       
  1577           fd->insertNamespace(nd);
       
  1578           fd->addUsingDirective(nd);
       
  1579         }
       
  1580 
       
  1581         // the empty string test is needed for extract all case
       
  1582         nd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
       
  1583         nd->insertUsedFile(root->fileName);
       
  1584         // add class to the list
       
  1585         Doxygen::namespaceSDict->inSort(name,nd);
       
  1586         nd->setRefItems(root->sli);
       
  1587       }
       
  1588     }
       
  1589 
       
  1590     rootNav->releaseEntry();
       
  1591   }
       
  1592   RECURSE_ENTRYTREE(findUsingDirectives,rootNav);
       
  1593 }
       
  1594 
       
  1595 //----------------------------------------------------------------------
       
  1596 
       
  1597 static void buildListOfUsingDecls(EntryNav *rootNav)
       
  1598 {
       
  1599   if (rootNav->section()==Entry::USINGDECL_SEC &&
       
  1600       !(rootNav->parent()->section()&Entry::COMPOUND_MASK) // not a class/struct member
       
  1601      )
       
  1602   {
       
  1603     rootNav->loadEntry(g_storage);
       
  1604     Entry *root = rootNav->entry();
       
  1605 
       
  1606     QCString name = substitute(root->name,".","::");
       
  1607     if (g_usingDeclarations.find(name)==0)
       
  1608     {
       
  1609       FileDef *fd = rootNav->fileDef();
       
  1610       if (fd)
       
  1611       {
       
  1612         g_usingDeclarations.insert(name,fd);
       
  1613       }
       
  1614     }
       
  1615 
       
  1616     rootNav->releaseEntry();
       
  1617   }
       
  1618   RECURSE_ENTRYTREE(buildListOfUsingDecls,rootNav);
       
  1619 }
       
  1620 
       
  1621   
       
  1622 static void findUsingDeclarations(EntryNav *rootNav)
       
  1623 {
       
  1624   if (rootNav->section()==Entry::USINGDECL_SEC &&
       
  1625       !(rootNav->parent()->section()&Entry::COMPOUND_MASK) // not a class/struct member
       
  1626      )
       
  1627   {
       
  1628     rootNav->loadEntry(g_storage);
       
  1629     Entry *root = rootNav->entry();
       
  1630 
       
  1631     //printf("Found using declaration %s at line %d of %s inside section %x\n",
       
  1632     //   root->name.data(),root->startLine,root->fileName.data(),
       
  1633     //   rootNav->parent()->section());
       
  1634     if (!root->name.isEmpty())
       
  1635     {
       
  1636       ClassDef *usingCd = 0;
       
  1637       NamespaceDef *nd = 0;
       
  1638       FileDef      *fd = rootNav->fileDef();
       
  1639       QCString scName;
       
  1640 
       
  1641       // see if the using statement was found inside a namespace or inside
       
  1642       // the global file scope.
       
  1643       if (rootNav->parent()->section() == Entry::NAMESPACE_SEC)
       
  1644       {
       
  1645         scName=rootNav->parent()->name();
       
  1646         if (!scName.isEmpty())
       
  1647         {
       
  1648           nd = getResolvedNamespace(scName);
       
  1649         }
       
  1650       }
       
  1651 
       
  1652       // Assume the using statement was used to import a class.
       
  1653       // Find the scope in which the `using' namespace is defined by prepending
       
  1654       // the possible scopes in which the using statement was found, starting
       
  1655       // with the most inner scope and going to the most outer scope (i.e. 
       
  1656       // file scope).
       
  1657 
       
  1658       QCString name = substitute(root->name,".","::"); //Java/C# scope->internal
       
  1659       usingCd = getClass(name);
       
  1660       if (usingCd==0)
       
  1661       {
       
  1662         usingCd = Doxygen::hiddenClasses->find(name);
       
  1663       }
       
  1664 
       
  1665       //printf("%s -> %p\n",root->name.data(),usingCd);
       
  1666       if (usingCd==0) // definition not in the input => add an artificial class
       
  1667       {
       
  1668         Debug::print(Debug::Classes,0,"  New using class `%s' (sec=0x%08x)! #tArgLists=%d\n",
       
  1669              name.data(),root->section,root->tArgLists ? (int)root->tArgLists->count() : -1);
       
  1670         usingCd = new ClassDef(
       
  1671                      "<using>",1,
       
  1672                      name,ClassDef::Class);
       
  1673         Doxygen::hiddenClasses->append(root->name,usingCd);
       
  1674         usingCd->setArtificial(TRUE);
       
  1675       }
       
  1676       else
       
  1677       {
       
  1678         Debug::print(Debug::Classes,0,"  Found used class %s in scope=%s\n",
       
  1679             usingCd->name().data(),nd?nd->name().data():fd->name().data());
       
  1680       }
       
  1681 
       
  1682       if (usingCd) // add the class to the correct scope
       
  1683       {
       
  1684         if (nd)
       
  1685         {
       
  1686           //printf("Inside namespace %s\n",nd->name().data());
       
  1687           nd->addUsingDeclaration(usingCd);
       
  1688         }
       
  1689         else if (fd)
       
  1690         {
       
  1691           //printf("Inside file %s\n",fd->name().data());
       
  1692           fd->addUsingDeclaration(usingCd);
       
  1693         }
       
  1694       }
       
  1695     }
       
  1696 
       
  1697     rootNav->releaseEntry();
       
  1698   }
       
  1699   RECURSE_ENTRYTREE(findUsingDeclarations,rootNav);
       
  1700 }
       
  1701 
       
  1702 //----------------------------------------------------------------------
       
  1703 
       
  1704 static void findUsingDeclImports(EntryNav *rootNav)
       
  1705 {
       
  1706   if (rootNav->section()==Entry::USINGDECL_SEC &&
       
  1707       (rootNav->parent()->section()&Entry::COMPOUND_MASK) // in a class/struct member
       
  1708      )
       
  1709   {
       
  1710     //printf("Found using declaration %s at line %d of %s inside section %x\n",
       
  1711     //    root->name.data(),root->startLine,root->fileName.data(),
       
  1712     //    root->parent->section);
       
  1713     QCString fullName=removeRedundantWhiteSpace(rootNav->parent()->name());
       
  1714     fullName=stripAnonymousNamespaceScope(fullName);
       
  1715     fullName=stripTemplateSpecifiersFromScope(fullName);
       
  1716     ClassDef *cd = getClass(fullName);
       
  1717     if (cd)
       
  1718     {
       
  1719       //printf("found class %s\n",cd->name().data());
       
  1720       int i=rootNav->name().find("::");
       
  1721       if (i!=-1)
       
  1722       {
       
  1723         QCString scope=rootNav->name().left(i);
       
  1724         QCString memName=rootNav->name().right(rootNav->name().length()-i-2);
       
  1725         ClassDef *bcd = getResolvedClass(cd,0,scope); // todo: file in fileScope parameter
       
  1726         if (bcd)
       
  1727         {
       
  1728           //printf("found class %s\n",bcd->name().data());
       
  1729           MemberNameInfoSDict *mndict=bcd->memberNameInfoSDict();
       
  1730           if (mndict)
       
  1731           {
       
  1732             MemberNameInfo *mni = mndict->find(memName);
       
  1733             if (mni)
       
  1734             {
       
  1735               MemberNameInfoIterator mnii(*mni); 
       
  1736               MemberInfo *mi;
       
  1737               for ( ; (mi=mnii.current()) ; ++mnii )
       
  1738               {
       
  1739                 MemberDef *md = mi->memberDef;
       
  1740                 if (md && md->protection()!=Private)
       
  1741                 {
       
  1742 
       
  1743                   rootNav->loadEntry(g_storage);
       
  1744                   Entry *root = rootNav->entry();
       
  1745 
       
  1746                   //printf("found member %s\n",mni->memberName());
       
  1747                   MemberDef *newMd = 0;
       
  1748                   {
       
  1749                     LockingPtr<ArgumentList> templAl = md->templateArguments();
       
  1750                     LockingPtr<ArgumentList> al = md->templateArguments();
       
  1751                     newMd = new MemberDef(
       
  1752                       root->fileName,root->startLine,
       
  1753                       md->typeString(),memName,md->argsString(),
       
  1754                       md->excpString(),root->protection,root->virt,
       
  1755                       md->isStatic(),Member,md->memberType(),
       
  1756                       templAl.pointer(),al.pointer()
       
  1757                       );
       
  1758                   }
       
  1759                   newMd->setMemberClass(cd);
       
  1760                   cd->insertMember(newMd);
       
  1761                   if (!root->doc.isEmpty() || !root->brief.isEmpty())
       
  1762                   {
       
  1763                     newMd->setDocumentation(root->doc,root->docFile,root->docLine);
       
  1764                     newMd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
       
  1765                     newMd->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
       
  1766                   }
       
  1767                   else
       
  1768                   {
       
  1769                     newMd->setDocumentation(md->documentation(),md->docFile(),md->docLine());
       
  1770                     newMd->setBriefDescription(md->briefDescription(),md->briefFile(),md->briefLine());
       
  1771                     newMd->setInbodyDocumentation(md->inbodyDocumentation(),md->inbodyFile(),md->inbodyLine());
       
  1772                   }
       
  1773                   newMd->setDefinition(md->definition());
       
  1774                   newMd->enableCallGraph(root->callGraph);
       
  1775                   newMd->enableCallerGraph(root->callerGraph);
       
  1776                   newMd->setBitfields(md->bitfieldString());
       
  1777                   newMd->addSectionsToDefinition(root->anchors);
       
  1778                   newMd->setBodySegment(md->getStartBodyLine(),md->getEndBodyLine());
       
  1779                   newMd->setBodyDef(md->getBodyDef());
       
  1780                   newMd->setInitializer(md->initializer());
       
  1781                   newMd->setMaxInitLines(md->initializerLines());
       
  1782                   newMd->setMemberGroupId(root->mGrpId);
       
  1783                   newMd->setMemberSpecifiers(md->getMemberSpecifiers());
       
  1784 
       
  1785                   rootNav->releaseEntry();
       
  1786                 }
       
  1787               }
       
  1788             }
       
  1789           }
       
  1790         }
       
  1791       }
       
  1792     }
       
  1793 
       
  1794   }
       
  1795   RECURSE_ENTRYTREE(findUsingDeclImports,rootNav);
       
  1796 }
       
  1797 
       
  1798 //----------------------------------------------------------------------
       
  1799 
       
  1800 static void findIncludedUsingDirectives()
       
  1801 {
       
  1802   // first mark all files as not visited
       
  1803   FileNameListIterator fnli(*Doxygen::inputNameList); 
       
  1804   FileName *fn;
       
  1805   for (fnli.toFirst();(fn=fnli.current());++fnli)
       
  1806   {
       
  1807     FileNameIterator fni(*fn);
       
  1808     FileDef *fd;
       
  1809     for (;(fd=fni.current());++fni)
       
  1810     {
       
  1811       fd->visited=FALSE;
       
  1812     }
       
  1813   }
       
  1814   // then recursively add using directives found in #include files
       
  1815   // to files that have not been visited.
       
  1816   for (fnli.toFirst();(fn=fnli.current());++fnli)
       
  1817   {
       
  1818     FileNameIterator fni(*fn);
       
  1819     FileDef *fd;
       
  1820     for (fni.toFirst();(fd=fni.current());++fni)
       
  1821     {
       
  1822       if (!fd->visited) 
       
  1823       {
       
  1824         //printf("----- adding using directives for file %s\n",fd->name().data());
       
  1825         fd->addIncludedUsingDirectives();
       
  1826       }
       
  1827     }
       
  1828   }
       
  1829 }
       
  1830 
       
  1831 //----------------------------------------------------------------------
       
  1832 
       
  1833 static MemberDef *addVariableToClass(
       
  1834     EntryNav *rootNav,
       
  1835     ClassDef *cd,
       
  1836     MemberDef::MemberType mtype,
       
  1837     const QCString &name,
       
  1838     bool fromAnnScope,
       
  1839     MemberDef *fromAnnMemb,
       
  1840     Protection prot,
       
  1841     Relationship related)
       
  1842 {
       
  1843   Entry *root = rootNav->entry();
       
  1844 
       
  1845   QCString qualScope = cd->qualifiedNameWithTemplateParameters();
       
  1846   QCString scopeSeparator="::";
       
  1847   if (Config_getBool("OPTIMIZE_OUTPUT_JAVA"))
       
  1848   {
       
  1849     qualScope = substitute(qualScope,"::",".");
       
  1850     scopeSeparator=".";
       
  1851   }
       
  1852   Debug::print(Debug::Variables,0,
       
  1853       "  class variable:\n"
       
  1854       "    `%s' `%s'::`%s' `%s' prot=`%d ann=%d init=`%s'\n",
       
  1855       root->type.data(),
       
  1856       qualScope.data(), 
       
  1857       name.data(),
       
  1858       root->args.data(),
       
  1859       root->protection,
       
  1860       fromAnnScope,
       
  1861       root->initializer.data()
       
  1862               );
       
  1863 
       
  1864   QCString def;
       
  1865   if (!root->type.isEmpty())
       
  1866   {
       
  1867     if (related || mtype==MemberDef::Friend || Config_getBool("HIDE_SCOPE_NAMES"))
       
  1868     {
       
  1869       def=root->type+" "+name+root->args;
       
  1870     }
       
  1871     else
       
  1872     {
       
  1873       def=root->type+" "+qualScope+scopeSeparator+name+root->args;
       
  1874     }
       
  1875   }
       
  1876   else
       
  1877   {
       
  1878     if (Config_getBool("HIDE_SCOPE_NAMES"))
       
  1879     {
       
  1880       def=name+root->args;
       
  1881     }
       
  1882     else
       
  1883     {
       
  1884       def=qualScope+scopeSeparator+name+root->args;
       
  1885     }
       
  1886   }
       
  1887   def.stripPrefix("static ");
       
  1888 
       
  1889   // see if the member is already found in the same scope
       
  1890   // (this may be the case for a static member that is initialized
       
  1891   //  outside the class)
       
  1892   MemberName *mn=Doxygen::memberNameSDict->find(name);
       
  1893   if (mn)
       
  1894   {
       
  1895     MemberNameIterator mni(*mn);
       
  1896     MemberDef *md;
       
  1897     for (mni.toFirst();(md=mni.current());++mni)
       
  1898     {
       
  1899       //printf("md->getClassDef()=%p cd=%p type=[%s] md->typeString()=[%s]\n",
       
  1900       //    md->getClassDef(),cd,root->type.data(),md->typeString());
       
  1901       if (md->getClassDef()==cd && 
       
  1902           removeRedundantWhiteSpace(root->type)==md->typeString()) 
       
  1903         // member already in the scope
       
  1904       {
       
  1905 
       
  1906         if (root->objc && 
       
  1907             root->mtype==Property && 
       
  1908             md->memberType()==MemberDef::Variable)
       
  1909         { // Objective-C 2.0 property
       
  1910           // turn variable into a property
       
  1911           md->setProtection(root->protection);
       
  1912           cd->reclassifyMember(md,MemberDef::Property);
       
  1913         }
       
  1914         addMemberDocs(rootNav,md,def,0,FALSE);
       
  1915         //printf("    Member already found!\n");
       
  1916         return md;
       
  1917       }
       
  1918     } 
       
  1919   }
       
  1920 
       
  1921   // new member variable, typedef or enum value
       
  1922   MemberDef *md=new MemberDef(
       
  1923       root->fileName,root->startLine,
       
  1924       root->type,name,root->args,0,
       
  1925       prot,Normal,root->stat,related,
       
  1926       mtype,0,0);
       
  1927   md->setTagInfo(rootNav->tagInfo());
       
  1928   md->setMemberClass(cd); // also sets outer scope (i.e. getOuterScope())
       
  1929   //md->setDefFile(root->fileName);
       
  1930   //md->setDefLine(root->startLine);
       
  1931   md->setDocumentation(root->doc,root->docFile,root->docLine);
       
  1932   md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
       
  1933   md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
       
  1934   md->setDefinition(def);
       
  1935   md->setBitfields(root->bitfields);
       
  1936   md->addSectionsToDefinition(root->anchors);
       
  1937   md->setFromAnonymousScope(fromAnnScope);
       
  1938   md->setFromAnonymousMember(fromAnnMemb);
       
  1939   //md->setIndentDepth(indentDepth);
       
  1940   md->setBodySegment(root->bodyLine,root->endBodyLine);
       
  1941   md->setInitializer(root->initializer);
       
  1942   md->setMaxInitLines(root->initLines);
       
  1943   md->setMemberGroupId(root->mGrpId);
       
  1944   md->setMemberSpecifiers(root->spec);
       
  1945   md->setReadAccessor(root->read);
       
  1946   md->setWriteAccessor(root->write);
       
  1947   md->enableCallGraph(root->callGraph);
       
  1948   md->enableCallerGraph(root->callerGraph);
       
  1949   md->setHidden(root->hidden);
       
  1950   md->setArtificial(root->artificial);
       
  1951   addMemberToGroups(root,md);
       
  1952   //if (root->mGrpId!=-1) 
       
  1953   //{
       
  1954   //  printf("memberdef %s in memberGroup %d\n",name.data(),root->mGrpId);
       
  1955   //  md->setMemberGroup(memberGroupDict[root->mGrpId]);
       
  1956   //
       
  1957   md->setBodyDef(rootNav->fileDef());
       
  1958 
       
  1959   //printf("    Adding member=%s\n",md->name().data());
       
  1960   // add the member to the global list
       
  1961   if (mn)
       
  1962   {
       
  1963     mn->append(md);
       
  1964   }
       
  1965   else // new variable name
       
  1966   {
       
  1967     mn = new MemberName(name);
       
  1968     mn->append(md);
       
  1969     //printf("Adding memberName=%s\n",mn->memberName());
       
  1970     //Doxygen::memberNameDict.insert(name,mn);
       
  1971     //Doxygen::memberNameList.append(mn);
       
  1972     Doxygen::memberNameSDict->append(name,mn);
       
  1973     // add the member to the class
       
  1974   }
       
  1975   //printf("    New member adding to %s (%p)!\n",cd->name().data(),cd);
       
  1976   cd->insertMember(md);
       
  1977   md->setRefItems(root->sli);
       
  1978 
       
  1979   //TODO: insert FileDef instead of filename strings.
       
  1980   cd->insertUsedFile(root->fileName);
       
  1981   rootNav->changeSection(Entry::EMPTY_SEC);
       
  1982   return md;
       
  1983 }
       
  1984 
       
  1985 //----------------------------------------------------------------------
       
  1986 
       
  1987 static MemberDef *addVariableToFile(
       
  1988     EntryNav *rootNav,
       
  1989     MemberDef::MemberType mtype,
       
  1990     const QCString &scope,
       
  1991     const QCString &name,
       
  1992     bool fromAnnScope,
       
  1993     /*int indentDepth,*/
       
  1994     MemberDef *fromAnnMemb)
       
  1995 {
       
  1996   Entry *root = rootNav->entry();
       
  1997   Debug::print(Debug::Variables,0,
       
  1998       "  global variable:\n"
       
  1999       "    type=`%s' scope=`%s' name=`%s' args=`%s' prot=`%d mtype=%d\n",
       
  2000       root->type.data(),
       
  2001       scope.data(), 
       
  2002       name.data(),
       
  2003       root->args.data(),
       
  2004       root->protection,
       
  2005       mtype
       
  2006               );
       
  2007 
       
  2008   FileDef *fd = rootNav->fileDef();
       
  2009 
       
  2010   // see if we have a typedef that should hide a struct or union
       
  2011   if (mtype==MemberDef::Typedef && Config_getBool("TYPEDEF_HIDES_STRUCT"))
       
  2012   {
       
  2013     QCString type = root->type;
       
  2014     type.stripPrefix("typedef ");
       
  2015     if (type.left(7)=="struct " || type.left(6)=="union ")
       
  2016     {
       
  2017       type.stripPrefix("struct ");
       
  2018       type.stripPrefix("union ");
       
  2019       static QRegExp re("[a-z_A-Z][a-z_A-Z0-9]*");
       
  2020       int l,s;
       
  2021       s = re.match(type,0,&l);
       
  2022       if (s>=0)
       
  2023       {
       
  2024         QCString typeValue = type.mid(s,l);
       
  2025         ClassDef *cd = getClass(typeValue);
       
  2026         if (cd)
       
  2027         {
       
  2028           // this typedef should hide compound name cd, so we
       
  2029           // change the name that is displayed from cd.
       
  2030           cd->setClassName(name);
       
  2031           cd->setDocumentation(root->doc,root->docFile,root->docLine);
       
  2032           cd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
       
  2033           return 0;
       
  2034         }
       
  2035       }
       
  2036     }
       
  2037   }
       
  2038 
       
  2039   // see if the function is inside a namespace
       
  2040   NamespaceDef *nd = 0;
       
  2041   QCString nscope;
       
  2042   if (!scope.isEmpty())
       
  2043   {
       
  2044     if (scope.find('@')!=-1) return 0; // anonymous scope!
       
  2045     //nscope=removeAnonymousScopes(scope);
       
  2046     //if (!nscope.isEmpty())
       
  2047     //{
       
  2048     nd = getResolvedNamespace(scope);
       
  2049     //}
       
  2050   }
       
  2051   QCString def;
       
  2052 
       
  2053   // determine the definition of the global variable
       
  2054   if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@' && 
       
  2055       !Config_getBool("HIDE_SCOPE_NAMES")
       
  2056      )
       
  2057     // variable is inside a namespace, so put the scope before the name
       
  2058   {
       
  2059     static bool optimizeForJava = Config_getBool("OPTIMIZE_OUTPUT_JAVA");
       
  2060     QCString sep="::";
       
  2061     if (optimizeForJava) sep=".";
       
  2062     
       
  2063     if (!root->type.isEmpty())
       
  2064     {
       
  2065       def=root->type+" "+nd->name()+sep+name+root->args;
       
  2066     }
       
  2067     else
       
  2068     {
       
  2069       def=nd->name()+sep+name+root->args;
       
  2070     }
       
  2071   }
       
  2072   else
       
  2073   {
       
  2074     if (!root->type.isEmpty() && !root->name.isEmpty())
       
  2075     {
       
  2076       if (name.at(0)=='@') // dummy variable representing annonymous union
       
  2077         def=root->type;
       
  2078       else
       
  2079         def=root->type+" "+name+root->args;
       
  2080     }
       
  2081     else
       
  2082     {
       
  2083       def=name+root->args;
       
  2084     }
       
  2085   }
       
  2086   def.stripPrefix("static ");
       
  2087 
       
  2088   MemberName *mn=Doxygen::functionNameSDict->find(name);
       
  2089   if (mn)
       
  2090   {
       
  2091     //QCString nscope=removeAnonymousScopes(scope);
       
  2092     //NamespaceDef *nd=0;
       
  2093     //if (!nscope.isEmpty())
       
  2094     if (!scope.isEmpty())
       
  2095     {
       
  2096       nd = getResolvedNamespace(scope);
       
  2097     }
       
  2098     MemberNameIterator mni(*mn);
       
  2099     MemberDef *md;
       
  2100     for (mni.toFirst();(md=mni.current());++mni)
       
  2101     {
       
  2102       if (
       
  2103           ((nd==0 && md->getNamespaceDef()==0 && md->getFileDef() && 
       
  2104             root->fileName==md->getFileDef()->absFilePath()
       
  2105            ) // both variable names in the same file
       
  2106            || (nd!=0 && md->getNamespaceDef()==nd) // both in same namespace
       
  2107           )
       
  2108           && !md->isDefine() // function style #define's can be "overloaded" by typedefs or variables
       
  2109           && !md->isEnumerate() // in C# an enum value and enum can have the same name
       
  2110          )
       
  2111         // variable already in the scope
       
  2112       {
       
  2113         if (md->getFileDef() &&
       
  2114             ! // not a php array
       
  2115              (
       
  2116                (getLanguageFromFileName(md->getFileDef()->name())==SrcLangExt_PHP) &&
       
  2117                (md->argsString()!=root->args && root->args.find('[')!=-1)
       
  2118              )
       
  2119            ) 
       
  2120           // not a php array variable
       
  2121         {
       
  2122 
       
  2123           Debug::print(Debug::Variables,0,
       
  2124               "    variable already found: scope=%s\n",md->getOuterScope()->name().data());
       
  2125           addMemberDocs(rootNav,md,def,0,FALSE);
       
  2126           md->setRefItems(root->sli);
       
  2127           return md;
       
  2128         }
       
  2129       }
       
  2130     } 
       
  2131   }
       
  2132   Debug::print(Debug::Variables,0,
       
  2133     "    new variable, nd=%s!\n",nd?nd->name().data():"<global>");
       
  2134   // new global variable, enum value or typedef
       
  2135   MemberDef *md=new MemberDef(
       
  2136       root->fileName,root->startLine,
       
  2137       root->type,name,root->args,0,
       
  2138       Public, Normal,root->stat,Member,
       
  2139       mtype,0,0);
       
  2140   md->setTagInfo(rootNav->tagInfo());
       
  2141   md->setDocumentation(root->doc,root->docFile,root->docLine);
       
  2142   md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
       
  2143   md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
       
  2144   md->addSectionsToDefinition(root->anchors);
       
  2145   md->setFromAnonymousScope(fromAnnScope);
       
  2146   md->setFromAnonymousMember(fromAnnMemb);
       
  2147   md->setInitializer(root->initializer);
       
  2148   md->setMaxInitLines(root->initLines);
       
  2149   md->setMemberGroupId(root->mGrpId);
       
  2150   md->setDefinition(def);
       
  2151   md->enableCallGraph(root->callGraph);
       
  2152   md->enableCallerGraph(root->callerGraph);
       
  2153   md->setExplicitExternal(root->explicitExternal);
       
  2154   //md->setOuterScope(fd);
       
  2155   if (!root->explicitExternal)
       
  2156   {
       
  2157     md->setBodySegment(root->bodyLine,root->endBodyLine);
       
  2158     md->setBodyDef(fd);
       
  2159   }
       
  2160   addMemberToGroups(root,md);
       
  2161 
       
  2162   md->setRefItems(root->sli);
       
  2163   if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@')
       
  2164   {
       
  2165     md->setNamespace(nd);
       
  2166     nd->insertMember(md); 
       
  2167   }
       
  2168 
       
  2169   // add member to the file (we do this even if we have already inserted
       
  2170   // it into the namespace. 
       
  2171   if (fd)
       
  2172   {
       
  2173     md->setFileDef(fd); 
       
  2174     fd->insertMember(md);
       
  2175   }
       
  2176 
       
  2177   // add member definition to the list of globals 
       
  2178   if (mn)
       
  2179   {
       
  2180     mn->append(md);
       
  2181   }
       
  2182   else
       
  2183   {
       
  2184     mn = new MemberName(name);
       
  2185     mn->append(md);
       
  2186     Doxygen::functionNameSDict->append(name,mn);
       
  2187   }
       
  2188   rootNav->changeSection(Entry::EMPTY_SEC);
       
  2189   return md;
       
  2190 }
       
  2191 
       
  2192 /*! See if the return type string \a type is that of a function pointer 
       
  2193  *  \returns -1 if this is not a function pointer variable or
       
  2194  *           the index at which the brace of (...*name) was found.
       
  2195  */
       
  2196 static int findFunctionPtr(const QCString &type,int *pLength=0)
       
  2197 {
       
  2198   static const QRegExp re("([^)]*\\*[^)]*)");
       
  2199   int i=-1,l;
       
  2200   if (!type.isEmpty() &&             // return type is non-empty
       
  2201       (i=re.match(type,0,&l))!=-1 && // contains (...*...)
       
  2202       type.find("operator")==-1 &&   // not an operator
       
  2203       (type.find(")(")==-1 || type.find("typedef ")!=-1)
       
  2204                                     // not a function pointer return type
       
  2205      )
       
  2206   {
       
  2207     if (pLength) *pLength=l;
       
  2208     return i;
       
  2209   }
       
  2210   else
       
  2211   {
       
  2212     return -1;
       
  2213   }
       
  2214 }
       
  2215 
       
  2216 
       
  2217 /*! Returns TRUE iff \a type is a class within scope \a context.
       
  2218  *  Used to detect variable declarations that look like function prototypes.
       
  2219  */
       
  2220 static bool isVarWithConstructor(EntryNav *rootNav)
       
  2221 {
       
  2222   static QRegExp initChars("[0-9\"'&*!^]+");
       
  2223   static QRegExp idChars("[a-z_A-Z][a-z_A-Z0-9]*");
       
  2224   bool result=FALSE;
       
  2225   bool typeIsClass;
       
  2226   QCString type;
       
  2227   Definition *ctx = 0;
       
  2228   FileDef *fd = 0;
       
  2229   int ti;
       
  2230 
       
  2231   //printf("isVarWithConstructor(%s)\n",rootNav->name().data());
       
  2232   rootNav->loadEntry(g_storage);
       
  2233   Entry *root = rootNav->entry();
       
  2234 
       
  2235   if (rootNav->parent()->section() & Entry::COMPOUND_MASK)
       
  2236   { // inside a class
       
  2237     result=FALSE;
       
  2238     goto done;
       
  2239   }
       
  2240   else if ((fd = rootNav->fileDef()) &&
       
  2241             (fd->name().right(2)==".c" || fd->name().right(2)==".h")
       
  2242           )
       
  2243   { // inside a .c file
       
  2244     result=FALSE;
       
  2245     goto done;
       
  2246   }
       
  2247   if (root->type.isEmpty()) 
       
  2248   {
       
  2249     result=FALSE;
       
  2250     goto done;
       
  2251   }
       
  2252   if (!rootNav->parent()->name().isEmpty()) 
       
  2253   {
       
  2254     ctx=Doxygen::namespaceSDict->find(rootNav->parent()->name());
       
  2255   }
       
  2256   type = root->type;
       
  2257   // remove qualifiers
       
  2258   findAndRemoveWord(type,"const");
       
  2259   findAndRemoveWord(type,"static");
       
  2260   findAndRemoveWord(type,"volatile");
       
  2261   //if (type.left(6)=="const ") type=type.right(type.length()-6);
       
  2262   typeIsClass=getResolvedClass(ctx,fd,type)!=0;
       
  2263   if (!typeIsClass && (ti=type.find('<'))!=-1)
       
  2264   {
       
  2265     typeIsClass=getResolvedClass(ctx,fd,type.left(ti))!=0;
       
  2266   }
       
  2267   if (typeIsClass) // now we still have to check if the arguments are 
       
  2268                    // types or values. Since we do not have complete type info
       
  2269                    // we need to rely on heuristics :-(
       
  2270   {
       
  2271     //printf("typeIsClass\n");
       
  2272     ArgumentList *al = root->argList;
       
  2273     if (al==0 || al->isEmpty()) 
       
  2274     {
       
  2275       result=FALSE; // empty arg list -> function prototype.
       
  2276       goto done;
       
  2277     }
       
  2278     ArgumentListIterator ali(*al);
       
  2279     Argument *a;
       
  2280     for (ali.toFirst();(a=ali.current());++ali)
       
  2281     {
       
  2282       if (!a->name.isEmpty() || !a->defval.isEmpty()) 
       
  2283       {
       
  2284         if (a->name.find(initChars)==0)
       
  2285         {
       
  2286           result=TRUE;
       
  2287         }
       
  2288         else
       
  2289         {
       
  2290           result=FALSE; // arg has (type,name) pair -> function prototype
       
  2291         }
       
  2292         goto done;
       
  2293       }
       
  2294       if (a->type.isEmpty() || getResolvedClass(ctx,fd,a->type)!=0) 
       
  2295       {
       
  2296         result=FALSE; // arg type is a known type
       
  2297         goto done;
       
  2298       }
       
  2299       if (checkIfTypedef(ctx,fd,a->type))
       
  2300       {
       
  2301          //printf("%s:%d: false (arg is typedef)\n",__FILE__,__LINE__);
       
  2302          result=FALSE; // argument is a typedef
       
  2303          goto done;
       
  2304       }
       
  2305       if (a->type.at(a->type.length()-1)=='*' ||
       
  2306           a->type.at(a->type.length()-1)=='&')  
       
  2307                      // type ends with * or & => pointer or reference
       
  2308       {
       
  2309         result=FALSE;
       
  2310         goto done;
       
  2311       }
       
  2312       if (a->type.find(initChars)==0) 
       
  2313       {
       
  2314         result=TRUE; // argument type starts with typical initializer char
       
  2315         goto done;
       
  2316       }
       
  2317       QCString resType=resolveTypeDef(ctx,a->type);
       
  2318       if (resType.isEmpty()) resType=a->type;
       
  2319       int len;
       
  2320       if (idChars.match(resType,0,&len)==0) // resType starts with identifier
       
  2321       {
       
  2322         resType=resType.left(len);
       
  2323         //printf("resType=%s\n",resType.data());
       
  2324         if (resType=="int"    || resType=="long" || resType=="float" || 
       
  2325             resType=="double" || resType=="char" || resType=="signed" || 
       
  2326             resType=="const"  || resType=="unsigned" || resType=="void") 
       
  2327         {
       
  2328           result=FALSE; // type keyword -> function prototype
       
  2329           goto done;
       
  2330         }
       
  2331       }
       
  2332     }
       
  2333     result=TRUE;
       
  2334   }
       
  2335 
       
  2336 done:
       
  2337   //printf("isVarWithConstructor(%s,%s)=%d\n",rootNav->parent()->name().data(),
       
  2338   //                                          root->type.data(),result);
       
  2339   rootNav->releaseEntry();
       
  2340   return result;
       
  2341 }
       
  2342 
       
  2343 static void addVariable(EntryNav *rootNav,int isFuncPtr=-1)
       
  2344 {
       
  2345     rootNav->loadEntry(g_storage);
       
  2346     Entry *root = rootNav->entry();
       
  2347 
       
  2348     Debug::print(Debug::Variables,0,
       
  2349                   "VARIABLE_SEC: \n"
       
  2350                   "  type=`%s' name=`%s' args=`%s' bodyLine=`%d' mGrpId=%d\n",
       
  2351                    root->type.data(),
       
  2352                    root->name.data(),
       
  2353                    root->args.data(),
       
  2354                    root->bodyLine,
       
  2355                    root->mGrpId
       
  2356                 );
       
  2357     //printf("root->parent->name=%s\n",root->parent->name.data());
       
  2358 
       
  2359     if (root->type.isEmpty() && root->name.find("operator")==-1 &&
       
  2360         (root->name.find('*')!=-1 || root->name.find('&')!=-1))
       
  2361     {
       
  2362       // recover from parse error caused by redundant braces 
       
  2363       // like in "int *(var[10]);", which is parsed as
       
  2364       // type="" name="int *" args="(var[10])"
       
  2365 
       
  2366       root->type=root->name;
       
  2367       static const QRegExp reName("[a-z_A-Z][a-z_A-Z0-9]*");
       
  2368       int l;
       
  2369       int i=root->args.isEmpty() ? -1 : reName.match(root->args,0,&l);
       
  2370       root->name=root->args.mid(i,l);
       
  2371       root->args=root->args.mid(i+l,root->args.find(')',i+l)-i-l);
       
  2372       //printf("new: type=`%s' name=`%s' args=`%s'\n",
       
  2373       //    root->type.data(),root->name.data(),root->args.data());
       
  2374     }
       
  2375     else
       
  2376     {
       
  2377       int i=isFuncPtr;
       
  2378       if (i==-1) i=findFunctionPtr(root->type); // for typedefs isFuncPtr is not yet set
       
  2379       if (i!=-1) // function pointer
       
  2380       {
       
  2381         int ai = root->type.find('[',i);
       
  2382         if (ai>i) // function pointer array
       
  2383         {
       
  2384           root->args.prepend(root->type.right(root->type.length()-ai));
       
  2385           root->type=root->type.left(ai);
       
  2386         }
       
  2387         else if (root->type.find(')',i)!=-1) // function ptr, not variable like "int (*bla)[10]"
       
  2388         {
       
  2389           root->type=root->type.left(root->type.length()-1);
       
  2390           root->args.prepend(")");
       
  2391           //printf("root->type=%s root->args=%s\n",root->type.data(),root->args.data());
       
  2392         }
       
  2393       }
       
  2394       else if (root->type.find("typedef ")!=-1 && root->type.right(2)=="()") // typedef void (func)(int)
       
  2395       {
       
  2396         root->type=root->type.left(root->type.length()-1);
       
  2397         root->args.prepend(")");
       
  2398       }
       
  2399     }
       
  2400     
       
  2401     QCString scope,name=removeRedundantWhiteSpace(root->name);
       
  2402 
       
  2403     // find the scope of this variable 
       
  2404     EntryNav *p = rootNav->parent();
       
  2405     while ((p->section() & Entry::SCOPE_MASK))
       
  2406     {
       
  2407       QCString scopeName = p->name();
       
  2408       if (!scopeName.isEmpty())
       
  2409       {
       
  2410         scope.prepend(scopeName);
       
  2411         break;
       
  2412       }
       
  2413       p=p->parent();
       
  2414     }
       
  2415     
       
  2416     MemberDef::MemberType mtype;
       
  2417     QCString type=root->type.stripWhiteSpace();
       
  2418     ClassDef *cd=0;
       
  2419     bool isRelated=FALSE;
       
  2420     bool isMemberOf=FALSE;
       
  2421 
       
  2422     QCString classScope=stripAnonymousNamespaceScope(scope);
       
  2423     classScope=stripTemplateSpecifiersFromScope(classScope,FALSE);
       
  2424     QCString annScopePrefix=scope.left(scope.length()-classScope.length());
       
  2425 
       
  2426     if (root->name.findRev("::")!=-1) 
       
  2427     {
       
  2428       if (root->type=="friend class" || root->type=="friend struct" || 
       
  2429           root->type=="friend union")
       
  2430       {
       
  2431          cd=getClass(scope);
       
  2432          if (cd)
       
  2433          {
       
  2434            addVariableToClass(rootNav,  // entry
       
  2435                               cd,    // class to add member to
       
  2436                               MemberDef::Friend, // type of member
       
  2437                               name, // name of the member
       
  2438                               FALSE,  // from Anonymous scope
       
  2439                               0,      // anonymous member
       
  2440                               Public, // protection
       
  2441                               Member  // related to a class
       
  2442                              );
       
  2443          }
       
  2444       }
       
  2445       goto nextMember;
       
  2446                /* skip this member, because it is a 
       
  2447                 * static variable definition (always?), which will be
       
  2448                 * found in a class scope as well, but then we know the
       
  2449                 * correct protection level, so only then it will be
       
  2450                 * inserted in the correct list!
       
  2451                 */
       
  2452     }
       
  2453 
       
  2454     if (type=="@") 
       
  2455       mtype=MemberDef::EnumValue;
       
  2456     else if (type.left(8)=="typedef ") 
       
  2457       mtype=MemberDef::Typedef;
       
  2458     else if (type.left(7)=="friend ")
       
  2459       mtype=MemberDef::Friend;
       
  2460     else if (root->mtype==Property)
       
  2461       mtype=MemberDef::Property;
       
  2462     else if (root->mtype==Event)
       
  2463       mtype=MemberDef::Event;
       
  2464     else
       
  2465       mtype=MemberDef::Variable;
       
  2466 
       
  2467     if (!root->relates.isEmpty()) // related variable
       
  2468     {
       
  2469       isRelated=TRUE;
       
  2470       isMemberOf=(root->relatesType == MemberOf);
       
  2471       if (getClass(root->relates)==0 && !scope.isEmpty())
       
  2472         scope=mergeScopes(scope,root->relates);
       
  2473       else 
       
  2474         scope=root->relates;
       
  2475     }
       
  2476     
       
  2477     cd=getClass(scope);
       
  2478     if (cd==0 && classScope!=scope) cd=getClass(classScope);
       
  2479     if (cd)
       
  2480     {
       
  2481       MemberDef *md=0;
       
  2482 
       
  2483       // if cd is an annonymous scope we insert the member 
       
  2484       // into a non-annonymous scope as well. This is needed to
       
  2485       // be able to refer to it using \var or \fn
       
  2486 
       
  2487       //int indentDepth=0;
       
  2488       int si=scope.find('@');
       
  2489       //int anonyScopes = 0;
       
  2490       bool added=FALSE;
       
  2491       
       
  2492       if (si!=-1) // anonymous scope
       
  2493       {
       
  2494         QCString pScope;
       
  2495         ClassDef *pcd=0;
       
  2496         pScope = scope.left(QMAX(si-2,0));
       
  2497         if (!pScope.isEmpty())
       
  2498           pScope.prepend(annScopePrefix);
       
  2499         else if (annScopePrefix.length()>2)
       
  2500           pScope=annScopePrefix.left(annScopePrefix.length()-2);
       
  2501         if (name.at(0)!='@')
       
  2502         {
       
  2503           if (!pScope.isEmpty() && (pcd=getClass(pScope)))
       
  2504           {
       
  2505             md=addVariableToClass(rootNav,  // entry
       
  2506                                   pcd,   // class to add member to
       
  2507                                   mtype, // member type
       
  2508                                   name,  // member name
       
  2509                                   TRUE,  // from anonymous scope
       
  2510                                   0,     // from anonymous member
       
  2511                                   root->protection,
       
  2512                                   isMemberOf ? Foreign : isRelated ? Related : Member
       
  2513                                  );
       
  2514             added=TRUE;
       
  2515           }
       
  2516           else // anonymous scope inside namespace or file => put variable in the global scope
       
  2517           {
       
  2518             if (mtype==MemberDef::Variable)
       
  2519             {
       
  2520               md=addVariableToFile(rootNav,mtype,pScope,name,TRUE,0); 
       
  2521             }
       
  2522             added=TRUE;
       
  2523           }
       
  2524         }
       
  2525       }
       
  2526 
       
  2527       //printf("name=`%s' scope=%s scope.right=%s\n",
       
  2528       //                   name.data(),scope.data(),
       
  2529       //                   scope.right(scope.length()-si).data());
       
  2530       addVariableToClass(rootNav,   // entry
       
  2531                          cd,     // class to add member to
       
  2532                          mtype,  // member type
       
  2533                          name,   // name of the member
       
  2534                          FALSE,  // from anonymous scope
       
  2535                          md,     // from anonymous member
       
  2536                          root->protection, 
       
  2537                          isMemberOf ? Foreign : isRelated ? Related : Member);
       
  2538     }
       
  2539     else if (!name.isEmpty()) // global variable
       
  2540     {
       
  2541       //printf("Inserting member in global scope %s!\n",scope.data());
       
  2542       addVariableToFile(rootNav,mtype,scope,name,FALSE,/*0,*/0);
       
  2543     }
       
  2544 
       
  2545 nextMember:
       
  2546     rootNav->releaseEntry();
       
  2547 }
       
  2548 
       
  2549 //----------------------------------------------------------------------
       
  2550 // Searches the Entry tree for typedef documentation sections.
       
  2551 // If found they are stored in their class or in the global list.
       
  2552 static void buildTypedefList(EntryNav *rootNav)
       
  2553 {
       
  2554   //printf("buildVarList(%s)\n",rootNav->name().data());
       
  2555   if (!rootNav->name().isEmpty() &&
       
  2556       rootNav->section()==Entry::VARIABLE_SEC &&
       
  2557       rootNav->type().find("typedef ")!=-1 // its a typedef
       
  2558      ) 
       
  2559   {
       
  2560     addVariable(rootNav);
       
  2561   }
       
  2562   if (rootNav->children())
       
  2563   {
       
  2564     EntryNavListIterator eli(*rootNav->children());
       
  2565     EntryNav *e;
       
  2566     for (;(e=eli.current());++eli)
       
  2567     {
       
  2568       if (e->section()!=Entry::ENUM_SEC) 
       
  2569       {
       
  2570         buildTypedefList(e);
       
  2571       }
       
  2572     }
       
  2573   }
       
  2574 }
       
  2575 
       
  2576 //----------------------------------------------------------------------
       
  2577 // Searches the Entry tree for Variable documentation sections.
       
  2578 // If found they are stored in their class or in the global list.
       
  2579 
       
  2580 static void buildVarList(EntryNav *rootNav)
       
  2581 {
       
  2582   //printf("buildVarList(%s)\n",rootNav->name().data());
       
  2583   int isFuncPtr=-1;
       
  2584   if (!rootNav->name().isEmpty() &&
       
  2585       (rootNav->type().isEmpty() || g_compoundKeywordDict.find(rootNav->type())==0) &&
       
  2586       (
       
  2587        (rootNav->section()==Entry::VARIABLE_SEC    // it's a variable
       
  2588        ) ||
       
  2589        (rootNav->section()==Entry::FUNCTION_SEC && // or maybe a function pointer variable 
       
  2590         (isFuncPtr=findFunctionPtr(rootNav->type()))!=-1
       
  2591        ) ||
       
  2592        (rootNav->section()==Entry::FUNCTION_SEC && // class variable initialized by constructor
       
  2593         isVarWithConstructor(rootNav)
       
  2594        )
       
  2595       ) 
       
  2596      ) // documented variable
       
  2597   {
       
  2598     addVariable(rootNav,isFuncPtr);
       
  2599   }
       
  2600   if (rootNav->children())
       
  2601   {
       
  2602     EntryNavListIterator eli(*rootNav->children());
       
  2603     EntryNav *e;
       
  2604     for (;(e=eli.current());++eli)
       
  2605     {
       
  2606       if (e->section()!=Entry::ENUM_SEC) 
       
  2607       {
       
  2608         buildVarList(e);
       
  2609       }
       
  2610     }
       
  2611   }
       
  2612 }
       
  2613 
       
  2614 //----------------------------------------------------------------------
       
  2615 // Searches the Entry tree for Function sections.
       
  2616 // If found they are stored in their class or in the global list.
       
  2617 
       
  2618 static void addMethodToClass(EntryNav *rootNav,ClassDef *cd,
       
  2619                   const QCString &rname,bool isFriend)
       
  2620 {
       
  2621   Entry *root = rootNav->entry();
       
  2622   FileDef *fd=rootNav->fileDef();
       
  2623 
       
  2624   int l,i=-1;
       
  2625   static QRegExp re("([a-z_A-Z0-9: ]*[ &*]+[ ]*");
       
  2626 
       
  2627   if (!root->type.isEmpty() && (i=re.match(root->type,0,&l))!=-1) // function variable
       
  2628   {
       
  2629     root->args+=root->type.right(root->type.length()-i-l);
       
  2630     root->type=root->type.left(i+l);
       
  2631   }
       
  2632 
       
  2633   QCString name=removeRedundantWhiteSpace(rname);
       
  2634   if (name.left(2)=="::") name=name.right(name.length()-2);
       
  2635 
       
  2636   MemberDef::MemberType mtype;
       
  2637   if (isFriend)                 mtype=MemberDef::Friend;
       
  2638   else if (root->mtype==Signal) mtype=MemberDef::Signal;
       
  2639   else if (root->mtype==Slot)   mtype=MemberDef::Slot;
       
  2640   else if (root->mtype==DCOP)   mtype=MemberDef::DCOP;
       
  2641   else                          mtype=MemberDef::Function;
       
  2642 
       
  2643   // strip redundant template specifier for constructors
       
  2644   if ((fd==0 || getLanguageFromFileName(fd->name())==SrcLangExt_Cpp) &&
       
  2645      name.left(9)!="operator " && (i=name.find('<'))!=-1 && name.find('>')!=-1)
       
  2646   {
       
  2647     name=name.left(i); 
       
  2648   }
       
  2649 
       
  2650   //printf("root->name=`%s; root->args=`%s' root->argList=`%s'\n", 
       
  2651   //    root->name.data(),root->args.data(),argListToString(root->argList).data()
       
  2652   //   );
       
  2653 
       
  2654   // adding class member
       
  2655   MemberDef *md=new MemberDef(
       
  2656       root->fileName,root->startLine,
       
  2657       root->type,name,root->args,root->exception,
       
  2658       root->protection,root->virt,
       
  2659       root->stat && root->relatesType != MemberOf,
       
  2660       root->relates.isEmpty() ? Member :
       
  2661           root->relatesType == MemberOf ? Foreign : Related,
       
  2662       mtype,root->tArgLists ? root->tArgLists->last() : 0,root->argList);
       
  2663   md->setTagInfo(rootNav->tagInfo());
       
  2664   md->setMemberClass(cd);
       
  2665   md->setDocumentation(root->doc,root->docFile,root->docLine);
       
  2666   md->setDocsForDefinition(!root->proto);
       
  2667   md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
       
  2668   md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
       
  2669   md->setBodySegment(root->bodyLine,root->endBodyLine);
       
  2670   md->setMemberSpecifiers(root->spec);
       
  2671   md->setMemberGroupId(root->mGrpId);
       
  2672   md->setTypeConstraints(root->typeConstr);
       
  2673   md->setBodyDef(fd);
       
  2674   md->setFileDef(fd);
       
  2675   //md->setScopeTemplateArguments(root->tArgList);
       
  2676   md->addSectionsToDefinition(root->anchors);
       
  2677   QCString def;
       
  2678   QCString qualScope = cd->qualifiedNameWithTemplateParameters();
       
  2679   QCString scopeSeparator="::";
       
  2680   if (Config_getBool("OPTIMIZE_OUTPUT_JAVA"))
       
  2681   {
       
  2682     qualScope = substitute(qualScope,"::",".");
       
  2683     scopeSeparator=".";
       
  2684   }
       
  2685   if (!root->relates.isEmpty() || isFriend || Config_getBool("HIDE_SCOPE_NAMES"))
       
  2686   {
       
  2687     if (!root->type.isEmpty())
       
  2688     {
       
  2689       if (root->argList)
       
  2690       {
       
  2691         def=root->type+" "+name;
       
  2692       }
       
  2693       else
       
  2694       {
       
  2695         def=root->type+" "+name+root->args;
       
  2696       }
       
  2697     }
       
  2698     else
       
  2699     {
       
  2700       if (root->argList)
       
  2701       {
       
  2702         def=name;
       
  2703       }
       
  2704       else
       
  2705       {
       
  2706         def=name+root->args;
       
  2707       }
       
  2708     }
       
  2709   }
       
  2710   else
       
  2711   {
       
  2712     if (!root->type.isEmpty())
       
  2713     {
       
  2714       if (root->argList)
       
  2715       {
       
  2716         def=root->type+" "+qualScope+scopeSeparator+name;
       
  2717       }
       
  2718       else
       
  2719       {
       
  2720         def=root->type+" "+qualScope+scopeSeparator+name+root->args;
       
  2721       }
       
  2722     }
       
  2723     else
       
  2724     {
       
  2725       if (root->argList)
       
  2726       {
       
  2727         def=qualScope+scopeSeparator+name;
       
  2728       }
       
  2729       else
       
  2730       {
       
  2731         def=qualScope+scopeSeparator+name+root->args;
       
  2732       }
       
  2733     }
       
  2734   }
       
  2735   if (def.left(7)=="friend ") def=def.right(def.length()-7);
       
  2736   md->setDefinition(def);
       
  2737   md->enableCallGraph(root->callGraph);
       
  2738   md->enableCallerGraph(root->callerGraph);
       
  2739 
       
  2740   Debug::print(Debug::Functions,0,
       
  2741       "  Func Member:\n"
       
  2742       "    `%s' `%s'::`%s' `%s' proto=%d\n"
       
  2743       "    def=`%s'\n",
       
  2744       root->type.data(),
       
  2745       qualScope.data(),
       
  2746       rname.data(),
       
  2747       root->args.data(),
       
  2748       root->proto,
       
  2749       def.data()
       
  2750               );
       
  2751 
       
  2752   // add member to the global list of all members
       
  2753   //printf("Adding member=%s class=%s\n",md->name().data(),cd->name().data());
       
  2754   MemberName *mn;
       
  2755   if ((mn=Doxygen::memberNameSDict->find(name)))
       
  2756   {
       
  2757     mn->append(md);
       
  2758   }
       
  2759   else
       
  2760   {
       
  2761     mn = new MemberName(name);
       
  2762     mn->append(md);
       
  2763     Doxygen::memberNameSDict->append(name,mn);
       
  2764   }
       
  2765 
       
  2766   // add member to the class cd
       
  2767   cd->insertMember(md);
       
  2768   // add file to list of used files
       
  2769   cd->insertUsedFile(root->fileName);
       
  2770 
       
  2771   addMemberToGroups(root,md);
       
  2772   rootNav->changeSection(Entry::EMPTY_SEC);
       
  2773   md->setRefItems(root->sli);
       
  2774 }
       
  2775 
       
  2776 
       
  2777 static void buildFunctionList(EntryNav *rootNav)
       
  2778 {
       
  2779   if (rootNav->section()==Entry::FUNCTION_SEC)
       
  2780   {
       
  2781     rootNav->loadEntry(g_storage);
       
  2782     Entry *root = rootNav->entry();
       
  2783 
       
  2784     Debug::print(Debug::Functions,0,
       
  2785                  "FUNCTION_SEC:\n"
       
  2786                  "  `%s' `%s'::`%s' `%s' relates=`%s' relatesType=`%d' file=`%s' line=`%d' bodyLine=`%d' #tArgLists=%d mGrpId=%d spec=%d proto=%d docFile=%s\n",
       
  2787                  root->type.data(),
       
  2788                  rootNav->parent()->name().data(),
       
  2789                  root->name.data(),
       
  2790                  root->args.data(),
       
  2791                  root->relates.data(),
       
  2792                  root->relatesType,
       
  2793                  root->fileName.data(),
       
  2794                  root->startLine,
       
  2795                  root->bodyLine,
       
  2796                  root->tArgLists ? (int)root->tArgLists->count() : -1,
       
  2797                  root->mGrpId,
       
  2798                  root->spec,
       
  2799                  root->proto,
       
  2800                  root->docFile.data()
       
  2801                 );
       
  2802 
       
  2803     bool isFriend=root->type.find("friend ")!=-1;
       
  2804     QCString rname = removeRedundantWhiteSpace(root->name);
       
  2805     //printf("rname=%s\n",rname.data());
       
  2806 
       
  2807     QCString scope=rootNav->parent()->name(); //stripAnonymousNamespaceScope(root->parent->name);
       
  2808     if (!rname.isEmpty() && scope.find('@')==-1)
       
  2809     {
       
  2810       ClassDef *cd=0;
       
  2811       // check if this function's parent is a class
       
  2812       scope=stripTemplateSpecifiersFromScope(scope,FALSE);
       
  2813 
       
  2814       FileDef *rfd=rootNav->fileDef();
       
  2815 
       
  2816       int memIndex=rname.findRev("::");
       
  2817 
       
  2818       cd=getClass(scope);
       
  2819       if (cd && scope+"::"==rname.left(scope.length()+2)) // found A::f inside A
       
  2820       {
       
  2821         // strip scope from name
       
  2822         rname=rname.right(rname.length()-rootNav->parent()->name().length()-2); 
       
  2823       }
       
  2824 
       
  2825       NamespaceDef *nd = 0;
       
  2826       bool isMember=FALSE;
       
  2827       if (memIndex!=-1)
       
  2828       {
       
  2829         int ts=rname.find('<');
       
  2830         int te=rname.find('>');
       
  2831         if (memIndex>0 && (ts==-1 || te==-1))
       
  2832         {
       
  2833           // note: the following code was replaced by inMember=TRUE to deal with a 
       
  2834           // function rname='X::foo' of class X inside a namespace also called X...
       
  2835           // bug id 548175
       
  2836           //nd = Doxygen::namespaceSDict->find(rname.left(memIndex));
       
  2837           //isMember = nd==0;
       
  2838           //if (nd)
       
  2839           //{
       
  2840           //  // strip namespace scope from name
       
  2841           //  scope=rname.left(memIndex);
       
  2842           //  rname=rname.right(rname.length()-memIndex-2);
       
  2843           //}
       
  2844           isMember = TRUE;
       
  2845         }
       
  2846         else
       
  2847         {
       
  2848           isMember=memIndex<ts || memIndex>te;
       
  2849         }
       
  2850       }
       
  2851 
       
  2852       static QRegExp re("([a-z_A-Z0-9: ]*[ &*]+[ ]*");
       
  2853       if (!rootNav->parent()->name().isEmpty() &&
       
  2854           (rootNav->parent()->section() & Entry::COMPOUND_MASK) && 
       
  2855           cd &&
       
  2856           // do some fuzzy things to exclude function pointers 
       
  2857           (root->type.isEmpty() || 
       
  2858            (root->type.find(re,0)==-1 || root->args.find(")[")!=-1) ||  // type contains ..(..* and args not )[.. -> function pointer
       
  2859            root->type.find(")(")!=-1 || root->type.find("operator")!=-1 // type contains ..)(.. and not "operator"
       
  2860           )
       
  2861          )
       
  2862       {
       
  2863         Debug::print(Debug::Functions,0,"  --> member %s of class %s!\n",
       
  2864             rname.data(),cd->name().data());
       
  2865         addMethodToClass(rootNav,cd,rname,isFriend);
       
  2866       }
       
  2867       else if (!((rootNav->parent()->section() & Entry::COMPOUND_MASK) 
       
  2868                  || rootNav->parent()->section()==Entry::OBJCIMPL_SEC
       
  2869                 ) &&
       
  2870                !isMember &&
       
  2871                (root->relates.isEmpty() || root->relatesType == Duplicate) &&
       
  2872                root->type.left(7)!="extern " && root->type.left(8)!="typedef " 
       
  2873               )
       
  2874       // no member => unrelated function 
       
  2875       {
       
  2876         /* check the uniqueness of the function name in the file.
       
  2877          * A file could contain a function prototype and a function definition
       
  2878          * or even multiple function prototypes.
       
  2879          */
       
  2880         bool found=FALSE;
       
  2881         MemberName *mn;
       
  2882         MemberDef *md=0;
       
  2883         if ((mn=Doxygen::functionNameSDict->find(rname)))
       
  2884         {
       
  2885           Debug::print(Debug::Functions,0,"  --> function %s already found!\n",rname.data());
       
  2886           MemberNameIterator mni(*mn);
       
  2887           for (mni.toFirst();(!found && (md=mni.current()));++mni)
       
  2888           {
       
  2889             NamespaceDef *mnd = md->getNamespaceDef();
       
  2890             NamespaceDef *rnd = 0;
       
  2891             //printf("root namespace=%s\n",rootNav->parent()->name().data());
       
  2892             QCString fullScope = scope;
       
  2893             QCString parentScope = rootNav->parent()->name();
       
  2894             if (!parentScope.isEmpty() && !leftScopeMatch(parentScope,scope))
       
  2895             {
       
  2896               if (!scope.isEmpty()) fullScope.prepend("::");
       
  2897               fullScope.prepend(parentScope);
       
  2898             }
       
  2899             //printf("fullScope=%s\n",fullScope.data());
       
  2900             rnd = getResolvedNamespace(fullScope);
       
  2901             FileDef *mfd = md->getFileDef();
       
  2902             QCString nsName,rnsName;
       
  2903             if (mnd)  nsName = mnd->name().copy();
       
  2904             if (rnd) rnsName = rnd->name().copy();
       
  2905             //printf("matching arguments for %s%s %s%s\n",
       
  2906             //    md->name().data(),md->argsString(),rname.data(),argListToString(root->argList).data());
       
  2907             LockingPtr<ArgumentList> mdAl = md->argumentList();
       
  2908             LockingPtr<ArgumentList> mdTempl = md->templateArguments();
       
  2909 
       
  2910             // in case of template functions, we need to check if the
       
  2911             // functions have the same number of template parameters
       
  2912             bool sameNumTemplateArgs = TRUE;
       
  2913             if (mdTempl!=0 && root->tArgLists)
       
  2914             {
       
  2915               if (mdTempl->count()!=root->tArgLists->getLast()->count())
       
  2916               {
       
  2917                 sameNumTemplateArgs = FALSE;
       
  2918               }
       
  2919             }
       
  2920             if (
       
  2921                 matchArguments2(md->getOuterScope(),mfd,mdAl.pointer(),
       
  2922                                 rnd ? rnd : Doxygen::globalScope,rfd,root->argList,
       
  2923                                 FALSE) &&
       
  2924                 sameNumTemplateArgs
       
  2925                )
       
  2926             {
       
  2927               GroupDef *gd=0;
       
  2928               if (root->groups->first()!=0)
       
  2929               {
       
  2930                 gd = Doxygen::groupSDict->find(root->groups->first()->groupname.data());
       
  2931               }
       
  2932               //printf("match!\n");
       
  2933               //printf("mnd=%p rnd=%p nsName=%s rnsName=%s\n",mnd,rnd,nsName.data(),rnsName.data());
       
  2934               // see if we need to create a new member
       
  2935               found=(mnd && rnd && nsName==rnsName) ||   // members are in the same namespace
       
  2936                     ((mnd==0 && rnd==0 && mfd!=0 &&       // no external reference and
       
  2937                       mfd->absFilePath()==root->fileName // prototype in the same file
       
  2938                      )
       
  2939                     );
       
  2940               // otherwise, allow a duplicate global member with the same argument list
       
  2941               if (!found && gd && gd==md->getGroupDef())
       
  2942               {
       
  2943                 // member is already in the group, so we don't want to add it again.
       
  2944                 found=TRUE;
       
  2945               }
       
  2946 
       
  2947               //printf("combining function with prototype found=%d in namespace %s\n",
       
  2948               //    found,nsName.data());
       
  2949 
       
  2950               if (found)
       
  2951               {
       
  2952                 // merge argument lists
       
  2953                 mergeArguments(mdAl.pointer(),root->argList,!root->doc.isEmpty());
       
  2954                 // merge documentation
       
  2955                 if (md->documentation().isEmpty() && !root->doc.isEmpty())
       
  2956                 {
       
  2957                   ArgumentList *argList = new ArgumentList;
       
  2958                   stringToArgumentList(root->args,argList);
       
  2959                   if (root->proto)
       
  2960                   {
       
  2961                     //printf("setDeclArgumentList to %p\n",argList);
       
  2962                     md->setDeclArgumentList(argList);
       
  2963                   }
       
  2964                   else
       
  2965                   {
       
  2966                     md->setArgumentList(argList);
       
  2967                   }
       
  2968                 }
       
  2969 
       
  2970                 md->setDocumentation(root->doc,root->docFile,root->docLine);
       
  2971                 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
       
  2972                 md->setDocsForDefinition(!root->proto);
       
  2973                 md->setBodySegment(root->bodyLine,root->endBodyLine);
       
  2974                 md->setBodyDef(rfd);
       
  2975 
       
  2976                 if (md->briefDescription().isEmpty() && !root->brief.isEmpty())
       
  2977                 {
       
  2978                   md->setArgsString(root->args);
       
  2979                 }
       
  2980                 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
       
  2981 
       
  2982                 md->addSectionsToDefinition(root->anchors);
       
  2983 
       
  2984                 md->enableCallGraph(md->hasCallGraph() || root->callGraph);
       
  2985                 md->enableCallerGraph(md->hasCallerGraph() || root->callerGraph);
       
  2986 
       
  2987                 // merge ingroup specifiers
       
  2988                 if (md->getGroupDef()==0 && root->groups->first()!=0)
       
  2989                 {
       
  2990                   addMemberToGroups(root,md);
       
  2991                 }
       
  2992                 else if (md->getGroupDef()!=0 && root->groups->count()==0)
       
  2993                 {
       
  2994                   //printf("existing member is grouped, new member not\n");
       
  2995                   root->groups->append(new Grouping(md->getGroupDef()->name(), md->getGroupPri()));
       
  2996                 }
       
  2997                 else if (md->getGroupDef()!=0 && root->groups->first()!=0)
       
  2998                 {
       
  2999                   //printf("both members are grouped\n");
       
  3000                 }
       
  3001 
       
  3002                 // if md is a declaration and root is the corresponding
       
  3003                 // definition, then turn md into a definition.
       
  3004                 if (md->isPrototype() && !root->proto)
       
  3005                 {
       
  3006                   md->setPrototype(FALSE);
       
  3007                 }
       
  3008               }
       
  3009             }
       
  3010           }
       
  3011         }
       
  3012         if (!found) /* global function is unique with respect to the file */
       
  3013         {
       
  3014           Debug::print(Debug::Functions,0,"  --> new function %s found!\n",rname.data());
       
  3015           //printf("New function type=`%s' name=`%s' args=`%s' bodyLine=%d\n",
       
  3016           //       root->type.data(),rname.data(),root->args.data(),root->bodyLine);
       
  3017 
       
  3018           // new global function
       
  3019           ArgumentList *tArgList = root->tArgLists ? root->tArgLists->last() : 0;
       
  3020           QCString name=removeRedundantWhiteSpace(rname);
       
  3021           md=new MemberDef(
       
  3022               root->fileName,root->startLine,
       
  3023               root->type,name,root->args,root->exception,
       
  3024               root->protection,root->virt,root->stat,Member,
       
  3025               MemberDef::Function,tArgList,root->argList);
       
  3026 
       
  3027           md->setTagInfo(rootNav->tagInfo());
       
  3028           //md->setDefFile(root->fileName);
       
  3029           //md->setDefLine(root->startLine);
       
  3030           md->setDocumentation(root->doc,root->docFile,root->docLine);
       
  3031           md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
       
  3032           md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
       
  3033           md->setPrototype(root->proto);
       
  3034           md->setDocsForDefinition(!root->proto);
       
  3035           md->setTypeConstraints(root->typeConstr);
       
  3036           //md->setBody(root->body);
       
  3037           md->setBodySegment(root->bodyLine,root->endBodyLine);
       
  3038           FileDef *fd=rootNav->fileDef();
       
  3039           md->setBodyDef(fd);
       
  3040           md->addSectionsToDefinition(root->anchors);
       
  3041           md->setMemberSpecifiers(root->spec);
       
  3042           md->setMemberGroupId(root->mGrpId);
       
  3043 
       
  3044           // see if the function is inside a namespace that was not part of
       
  3045           // the name already (in that case nd should be non-zero already)
       
  3046           if (nd==0 && rootNav->parent()->section() == Entry::NAMESPACE_SEC )
       
  3047           {
       
  3048             //QCString nscope=removeAnonymousScopes(rootNav->parent()->name());
       
  3049             QCString nscope=rootNav->parent()->name();
       
  3050             if (!nscope.isEmpty())
       
  3051             {
       
  3052               nd = getResolvedNamespace(nscope);
       
  3053             }
       
  3054           }
       
  3055 
       
  3056           if (!scope.isEmpty())
       
  3057           {
       
  3058             if (Config_getBool("OPTIMIZE_OUTPUT_JAVA"))
       
  3059             {
       
  3060               scope = substitute(scope,"::",".")+".";
       
  3061             }
       
  3062             else
       
  3063             {
       
  3064               scope+="::";
       
  3065             }
       
  3066           }
       
  3067 
       
  3068           QCString def;
       
  3069           if (!root->type.isEmpty())
       
  3070           {
       
  3071             if (root->argList)
       
  3072             {
       
  3073               def=root->type+" "+scope+name;
       
  3074             }
       
  3075             else
       
  3076             {
       
  3077               def=root->type+" "+scope+name+root->args;
       
  3078             }
       
  3079           }
       
  3080           else
       
  3081           {
       
  3082             if (root->argList)
       
  3083             {
       
  3084               def=scope+name.copy();
       
  3085             }
       
  3086             else
       
  3087             {
       
  3088               def=scope+name+root->args;
       
  3089             }
       
  3090           }
       
  3091           Debug::print(Debug::Functions,0,
       
  3092                      "  Global Function:\n"
       
  3093                      "    `%s' `%s'::`%s' `%s' proto=%d\n"
       
  3094                      "    def=`%s'\n",
       
  3095                      root->type.data(),
       
  3096                      rootNav->parent()->name().data(),
       
  3097                      rname.data(),
       
  3098                      root->args.data(),
       
  3099                      root->proto,
       
  3100                      def.data()
       
  3101                     );
       
  3102           md->setDefinition(def);
       
  3103           md->enableCallGraph(root->callGraph);
       
  3104           md->enableCallerGraph(root->callerGraph);
       
  3105           //if (root->mGrpId!=-1) 
       
  3106           //{
       
  3107           //  md->setMemberGroup(memberGroupDict[root->mGrpId]);
       
  3108           //}
       
  3109 
       
  3110           md->setRefItems(root->sli);
       
  3111           if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@')
       
  3112           {
       
  3113             // add member to namespace
       
  3114             md->setNamespace(nd);
       
  3115             nd->insertMember(md); 
       
  3116           }
       
  3117           if (fd)
       
  3118           {
       
  3119             // add member to the file (we do this even if we have already
       
  3120             // inserted it into the namespace)
       
  3121             md->setFileDef(fd); 
       
  3122             fd->insertMember(md);
       
  3123           }
       
  3124 
       
  3125           // add member to the list of file members
       
  3126           //printf("Adding member=%s\n",md->name().data());
       
  3127           MemberName *mn;
       
  3128           if ((mn=Doxygen::functionNameSDict->find(name)))
       
  3129           {
       
  3130             mn->append(md);
       
  3131           }
       
  3132           else 
       
  3133           {
       
  3134             mn = new MemberName(name);
       
  3135             mn->append(md);
       
  3136             Doxygen::functionNameSDict->append(name,mn);
       
  3137           }
       
  3138           addMemberToGroups(root,md);
       
  3139           if (root->relatesType == Simple) // if this is a relatesalso command,
       
  3140                                            // allow find Member to pick it up
       
  3141           {
       
  3142             rootNav->changeSection(Entry::EMPTY_SEC); // Otherwise we have finished 
       
  3143                                                       // with this entry.
       
  3144 
       
  3145           }
       
  3146         }
       
  3147         else
       
  3148         {
       
  3149           FileDef *fd=rootNav->fileDef();
       
  3150           if (fd)
       
  3151           {
       
  3152             // add member to the file (we do this even if we have already
       
  3153             // inserted it into the namespace)
       
  3154             fd->insertMember(md);
       
  3155           }
       
  3156         }
       
  3157 
       
  3158         //printf("unrelated function %d `%s' `%s' `%s'\n",
       
  3159         //    root->parent->section,root->type.data(),rname.data(),root->args.data());
       
  3160       }
       
  3161       else
       
  3162       {
       
  3163           Debug::print(Debug::Functions,0,"  --> %s not processed!\n",rname.data());
       
  3164       }
       
  3165     }
       
  3166     else if (rname.isEmpty())
       
  3167     {
       
  3168         warn(root->fileName,root->startLine,
       
  3169              "Warning: Illegal member name found."
       
  3170             );
       
  3171     }
       
  3172 
       
  3173     rootNav->releaseEntry();
       
  3174   }
       
  3175   RECURSE_ENTRYTREE(buildFunctionList,rootNav);
       
  3176 }
       
  3177 
       
  3178 //----------------------------------------------------------------------
       
  3179 
       
  3180 static void findFriends()
       
  3181 {
       
  3182   //printf("findFriends()\n");
       
  3183   MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict);
       
  3184   MemberName *fn;
       
  3185   for (;(fn=fnli.current());++fnli) // for each global function name
       
  3186   {
       
  3187     //printf("Function name=`%s'\n",fn->memberName());
       
  3188     MemberName *mn;
       
  3189     if ((mn=Doxygen::memberNameSDict->find(fn->memberName())))
       
  3190     { // there are members with the same name
       
  3191       //printf("Function name is also a member name\n");
       
  3192       MemberNameIterator fni(*fn);
       
  3193       MemberDef *fmd;
       
  3194       for (;(fmd=fni.current());++fni) // for each function with that name
       
  3195       {
       
  3196         MemberNameIterator mni(*mn);
       
  3197         MemberDef *mmd;
       
  3198         for (;(mmd=mni.current());++mni) // for each member with that name
       
  3199         {
       
  3200           //printf("Checking for matching arguments 
       
  3201           //        mmd->isRelated()=%d mmd->isFriend()=%d mmd->isFunction()=%d\n",
       
  3202           //    mmd->isRelated(),mmd->isFriend(),mmd->isFunction());
       
  3203           LockingPtr<ArgumentList> mmdAl = mmd->argumentList();
       
  3204           LockingPtr<ArgumentList> fmdAl = fmd->argumentList();
       
  3205           if ((mmd->isFriend() || (mmd->isRelated() && mmd->isFunction())) &&
       
  3206               matchArguments2(mmd->getOuterScope(), mmd->getFileDef(), mmdAl.pointer(),
       
  3207                               fmd->getOuterScope(), fmd->getFileDef(), fmdAl.pointer(),
       
  3208                               TRUE
       
  3209                              )
       
  3210                              
       
  3211              ) // if the member is related and the arguments match then the 
       
  3212                // function is actually a friend.
       
  3213           {
       
  3214             mergeArguments(mmdAl.pointer(),fmdAl.pointer());
       
  3215             if (!fmd->documentation().isEmpty())
       
  3216             {
       
  3217               mmd->setDocumentation(fmd->documentation(),fmd->docFile(),fmd->docLine());
       
  3218             }
       
  3219             else if (!mmd->documentation().isEmpty())
       
  3220             {
       
  3221               fmd->setDocumentation(mmd->documentation(),mmd->docFile(),mmd->docLine());
       
  3222             }
       
  3223             if (mmd->briefDescription().isEmpty() && !fmd->briefDescription().isEmpty())
       
  3224             {
       
  3225               mmd->setBriefDescription(fmd->briefDescription(),fmd->briefFile(),fmd->briefLine());
       
  3226             }
       
  3227             else if (!mmd->briefDescription().isEmpty() && !fmd->briefDescription().isEmpty())
       
  3228             {
       
  3229               fmd->setBriefDescription(mmd->briefDescription(),mmd->briefFile(),mmd->briefLine());
       
  3230             }
       
  3231             if (!fmd->inbodyDocumentation().isEmpty())
       
  3232             {
       
  3233               mmd->setInbodyDocumentation(fmd->inbodyDocumentation(),fmd->inbodyFile(),fmd->inbodyLine());
       
  3234             }
       
  3235             else if (!mmd->inbodyDocumentation().isEmpty())
       
  3236             {
       
  3237               fmd->setInbodyDocumentation(mmd->inbodyDocumentation(),mmd->inbodyFile(),mmd->inbodyLine());
       
  3238             }
       
  3239             //printf("body mmd %d fmd %d\n",mmd->getStartBodyLine(),fmd->getStartBodyLine());
       
  3240             if (mmd->getStartBodyLine()==-1 && fmd->getStartBodyLine()!=-1)
       
  3241             {
       
  3242               mmd->setBodySegment(fmd->getStartBodyLine(),fmd->getEndBodyLine());
       
  3243               mmd->setBodyDef(fmd->getBodyDef());
       
  3244               //mmd->setBodyMember(fmd);
       
  3245             }
       
  3246             else if (mmd->getStartBodyLine()!=-1 && fmd->getStartBodyLine()==-1)
       
  3247             {
       
  3248               fmd->setBodySegment(mmd->getStartBodyLine(),mmd->getEndBodyLine());
       
  3249               fmd->setBodyDef(mmd->getBodyDef());
       
  3250               //fmd->setBodyMember(mmd);
       
  3251             }
       
  3252             mmd->setDocsForDefinition(fmd->isDocsForDefinition());
       
  3253 
       
  3254             mmd->enableCallGraph(mmd->hasCallGraph() || fmd->hasCallGraph());
       
  3255             mmd->enableCallerGraph(mmd->hasCallerGraph() || fmd->hasCallerGraph());
       
  3256             fmd->enableCallGraph(mmd->hasCallGraph() || fmd->hasCallGraph());
       
  3257             fmd->enableCallerGraph(mmd->hasCallerGraph() || fmd->hasCallerGraph());
       
  3258           }
       
  3259         }
       
  3260       }
       
  3261     }
       
  3262   }
       
  3263 }
       
  3264 
       
  3265 //----------------------------------------------------------------------
       
  3266 
       
  3267 static void transferArgumentDocumentation(ArgumentList *decAl,ArgumentList *defAl)
       
  3268 {
       
  3269   if (decAl && defAl)
       
  3270   {
       
  3271     ArgumentListIterator decAli(*decAl);
       
  3272     ArgumentListIterator defAli(*defAl);
       
  3273     Argument *decA,*defA;
       
  3274     for (decAli.toFirst(),defAli.toFirst();
       
  3275         (decA=decAli.current()) && (defA=defAli.current());
       
  3276         ++decAli,++defAli)
       
  3277     {
       
  3278       //printf("Argument decA->name=%s (doc=%s) defA->name=%s (doc=%s)\n",
       
  3279       //    decA->name.data(),decA->docs.data(),
       
  3280       //    defA->name.data(),defA->docs.data()
       
  3281       //      );
       
  3282       if (decA->docs.isEmpty() && !defA->docs.isEmpty())
       
  3283       {
       
  3284         decA->docs = defA->docs.copy();
       
  3285       }
       
  3286       else if (defA->docs.isEmpty() && !decA->docs.isEmpty())
       
  3287       {
       
  3288         defA->docs = decA->docs.copy();
       
  3289       }
       
  3290     }
       
  3291   }
       
  3292 }
       
  3293 
       
  3294 static void transferFunctionDocumentation()
       
  3295 {
       
  3296   //printf("---- transferFunctionDocumentation()\n");
       
  3297 
       
  3298   // find matching function declaration and definitions.
       
  3299   MemberNameSDict::Iterator mnli(*Doxygen::functionNameSDict);
       
  3300   MemberName *mn;
       
  3301   for (;(mn=mnli.current());++mnli)
       
  3302   {
       
  3303     //printf("memberName=%s count=%d\n",mn->memberName(),mn->count());
       
  3304     MemberDef *mdef=0,*mdec=0;
       
  3305     MemberNameIterator mni1(*mn);
       
  3306     /* find a matching function declaration and definition for this function */
       
  3307     for (;(mdec=mni1.current());++mni1)
       
  3308     {
       
  3309       //printf("mdec=%s isPrototype()=%d\n",mdec->name().data(),mdec->isPrototype());
       
  3310       if (mdec->isPrototype() ||
       
  3311           (mdec->isVariable() && mdec->isExternal()) 
       
  3312          )
       
  3313       {
       
  3314         MemberNameIterator mni2(*mn);
       
  3315         for (;(mdef=mni2.current());++mni2)
       
  3316         {
       
  3317           if (
       
  3318               (mdef->isFunction() && !mdef->isStatic() && !mdef->isPrototype()) ||
       
  3319               (mdef->isVariable() && !mdef->isExternal() && !mdef->isStatic())
       
  3320              )
       
  3321           {
       
  3322             //printf("mdef=(%p,%s) mdec=(%p,%s)\n",
       
  3323             //    mdef, mdef ? mdef->name().data() : "",
       
  3324             //    mdec, mdec ? mdec->name().data() : "");
       
  3325 
       
  3326             LockingPtr<ArgumentList> mdefAl = mdef->argumentList();
       
  3327             LockingPtr<ArgumentList> mdecAl = mdec->argumentList();
       
  3328             if (matchArguments2(mdef->getOuterScope(),mdef->getFileDef(),mdefAl.pointer(),
       
  3329                                 mdec->getOuterScope(),mdec->getFileDef(),mdecAl.pointer(),
       
  3330                                 TRUE
       
  3331                                )
       
  3332                ) /* match found */
       
  3333             {
       
  3334               //printf("Found member %s: definition in %s (doc=`%s') and declaration in %s (doc=`%s')\n",
       
  3335               //    mn->memberName(),
       
  3336               //    mdef->getFileDef()->name().data(),mdef->documentation().data(),
       
  3337               //    mdec->getFileDef()->name().data(),mdec->documentation().data()
       
  3338               //    );
       
  3339 
       
  3340               // first merge argument documentation
       
  3341               transferArgumentDocumentation(mdecAl.pointer(),mdefAl.pointer());
       
  3342 
       
  3343               /* copy documentation between function definition and declaration */
       
  3344               if (!mdec->briefDescription().isEmpty())
       
  3345               {
       
  3346                 mdef->setBriefDescription(mdec->briefDescription(),mdec->briefFile(),mdec->briefLine());
       
  3347               }
       
  3348               else if (!mdef->briefDescription().isEmpty())
       
  3349               {
       
  3350                 mdec->setBriefDescription(mdef->briefDescription(),mdef->briefFile(),mdef->briefLine());
       
  3351               }
       
  3352               if (!mdef->documentation().isEmpty())
       
  3353               {
       
  3354                 //printf("transfering docs mdef->mdec (%s->%s)\n",mdef->argsString(),mdec->argsString());
       
  3355                 mdec->setDocumentation(mdef->documentation(),mdef->docFile(),mdef->docLine());
       
  3356                 mdec->setDocsForDefinition(mdef->isDocsForDefinition());
       
  3357                 if (mdefAl!=0)
       
  3358                 {
       
  3359                   ArgumentList *mdefAlComb = new ArgumentList;
       
  3360                   stringToArgumentList(mdef->argsString(),mdefAlComb);
       
  3361                   transferArgumentDocumentation(mdefAl.pointer(),mdefAlComb);
       
  3362                   mdec->setArgumentList(mdefAlComb);
       
  3363                 }
       
  3364               }
       
  3365               else if (!mdec->documentation().isEmpty())
       
  3366               {
       
  3367                 //printf("transfering docs mdec->mdef (%s->%s)\n",mdec->argsString(),mdef->argsString());
       
  3368                 mdef->setDocumentation(mdec->documentation(),mdec->docFile(),mdec->docLine());
       
  3369                 mdef->setDocsForDefinition(mdec->isDocsForDefinition());
       
  3370                 if (mdecAl!=0)
       
  3371                 {
       
  3372                   ArgumentList *mdecAlComb = new ArgumentList;
       
  3373                   stringToArgumentList(mdec->argsString(),mdecAlComb);
       
  3374                   transferArgumentDocumentation(mdecAl.pointer(),mdecAlComb);
       
  3375                   mdef->setDeclArgumentList(mdecAlComb);
       
  3376                 }
       
  3377               }
       
  3378               if (!mdef->inbodyDocumentation().isEmpty())
       
  3379               {
       
  3380                 mdec->setInbodyDocumentation(mdef->inbodyDocumentation(),mdef->inbodyFile(),mdef->inbodyLine());
       
  3381               }
       
  3382               else if (!mdec->inbodyDocumentation().isEmpty())
       
  3383               {
       
  3384                 mdef->setInbodyDocumentation(mdec->inbodyDocumentation(),mdec->inbodyFile(),mdec->inbodyLine());
       
  3385               }
       
  3386               if (mdec->getStartBodyLine()!=-1 && mdef->getStartBodyLine()==-1)
       
  3387               {
       
  3388                 //printf("body mdec->mdef %d-%d\n",mdec->getStartBodyLine(),mdef->getEndBodyLine());
       
  3389                 mdef->setBodySegment(mdec->getStartBodyLine(),mdec->getEndBodyLine());
       
  3390                 mdef->setBodyDef(mdec->getBodyDef());
       
  3391                 //mdef->setBodyMember(mdec);
       
  3392               }
       
  3393               else if (mdef->getStartBodyLine()!=-1 && mdec->getStartBodyLine()==-1)
       
  3394               {
       
  3395                 //printf("body mdef->mdec %d-%d\n",mdef->getStartBodyLine(),mdec->getEndBodyLine());
       
  3396                 mdec->setBodySegment(mdef->getStartBodyLine(),mdef->getEndBodyLine());
       
  3397                 mdec->setBodyDef(mdef->getBodyDef());
       
  3398                 //mdec->setBodyMember(mdef);
       
  3399               }
       
  3400               mdec->mergeMemberSpecifiers(mdef->getMemberSpecifiers());
       
  3401               mdef->mergeMemberSpecifiers(mdec->getMemberSpecifiers());
       
  3402 
       
  3403 
       
  3404               // copy group info.
       
  3405               if (mdec->getGroupDef()==0 && mdef->getGroupDef()!=0)
       
  3406               {
       
  3407                 mdec->setGroupDef(mdef->getGroupDef(),
       
  3408                                   mdef->getGroupPri(),
       
  3409                                   mdef->docFile(),
       
  3410                                   mdef->docLine(),
       
  3411                                   mdef->hasDocumentation(),
       
  3412                                   mdef
       
  3413                                  );
       
  3414               }
       
  3415               else if (mdef->getGroupDef()==0 && mdec->getGroupDef()!=0)
       
  3416               {
       
  3417                 mdef->setGroupDef(mdec->getGroupDef(),
       
  3418                                   mdec->getGroupPri(),
       
  3419                                   mdec->docFile(),
       
  3420                                   mdec->docLine(),
       
  3421                                   mdec->hasDocumentation(),
       
  3422                                   mdec
       
  3423                                  );
       
  3424               }
       
  3425 
       
  3426 
       
  3427               mdec->mergeRefItems(mdef);
       
  3428               mdef->mergeRefItems(mdec);
       
  3429 
       
  3430               mdef->setMemberDeclaration(mdec);
       
  3431               mdec->setMemberDefinition(mdef);
       
  3432 
       
  3433               mdef->enableCallGraph(mdec->hasCallGraph() || mdef->hasCallGraph());
       
  3434               mdef->enableCallerGraph(mdec->hasCallerGraph() || mdef->hasCallerGraph());
       
  3435               mdec->enableCallGraph(mdec->hasCallGraph() || mdef->hasCallGraph());
       
  3436               mdec->enableCallerGraph(mdec->hasCallerGraph() || mdef->hasCallerGraph());
       
  3437             }
       
  3438           }
       
  3439         }
       
  3440       }
       
  3441     }
       
  3442   }
       
  3443 }
       
  3444 
       
  3445 //----------------------------------------------------------------------
       
  3446 
       
  3447 static void transferFunctionReferences()
       
  3448 {
       
  3449   MemberNameSDict::Iterator mnli(*Doxygen::functionNameSDict);
       
  3450   MemberName *mn;
       
  3451   for (;(mn=mnli.current());++mnli)
       
  3452   {
       
  3453     MemberDef *md,*mdef=0,*mdec=0;
       
  3454     MemberNameIterator mni(*mn);
       
  3455     /* find a matching function declaration and definition for this function */
       
  3456     for (;(md=mni.current());++mni)
       
  3457     {
       
  3458       if (md->isPrototype()) 
       
  3459         mdec=md;
       
  3460       else if (md->isVariable() && md->isExternal()) 
       
  3461         mdec=md;
       
  3462       
       
  3463       if (md->isFunction() && !md->isStatic() && !md->isPrototype()) 
       
  3464         mdef=md;
       
  3465       else if (md->isVariable() && !md->isExternal() && !md->isStatic())
       
  3466         mdef=md;
       
  3467     }
       
  3468     if (mdef && mdec)
       
  3469     {
       
  3470       LockingPtr<ArgumentList> mdefAl = mdef->argumentList();
       
  3471       LockingPtr<ArgumentList> mdecAl = mdec->argumentList();
       
  3472       if (
       
  3473           matchArguments2(mdef->getOuterScope(),mdef->getFileDef(),mdefAl.pointer(),
       
  3474                           mdec->getOuterScope(),mdec->getFileDef(),mdecAl.pointer(),
       
  3475                           TRUE
       
  3476             )
       
  3477          ) /* match found */
       
  3478       {
       
  3479         LockingPtr<MemberSDict> defDict = mdef->getReferencesMembers();
       
  3480         LockingPtr<MemberSDict> decDict = mdec->getReferencesMembers();
       
  3481         if (defDict!=0)
       
  3482         {
       
  3483           MemberSDict::Iterator msdi(*defDict);
       
  3484           MemberDef *rmd;
       
  3485           for (msdi.toFirst();(rmd=msdi.current());++msdi)
       
  3486           {
       
  3487             if (decDict==0 || decDict->find(rmd->name())==0)
       
  3488             {
       
  3489               mdec->addSourceReferences(rmd);
       
  3490             }
       
  3491           }
       
  3492         }
       
  3493         if (decDict!=0)
       
  3494         {
       
  3495           MemberSDict::Iterator msdi(*decDict);
       
  3496           MemberDef *rmd;
       
  3497           for (msdi.toFirst();(rmd=msdi.current());++msdi)
       
  3498           {
       
  3499             if (defDict==0 || defDict->find(rmd->name())==0)
       
  3500             {
       
  3501               mdef->addSourceReferences(rmd);
       
  3502             }
       
  3503           }
       
  3504         }
       
  3505 
       
  3506         defDict = mdef->getReferencedByMembers();
       
  3507         decDict = mdec->getReferencedByMembers();
       
  3508         if (defDict!=0)
       
  3509         {
       
  3510           MemberSDict::Iterator msdi(*defDict);
       
  3511           MemberDef *rmd;
       
  3512           for (msdi.toFirst();(rmd=msdi.current());++msdi)
       
  3513           {
       
  3514             if (decDict==0 || decDict->find(rmd->name())==0)
       
  3515             {
       
  3516               mdec->addSourceReferencedBy(rmd);
       
  3517             }
       
  3518           }
       
  3519         }
       
  3520         if (decDict!=0)
       
  3521         {
       
  3522           MemberSDict::Iterator msdi(*decDict);
       
  3523           MemberDef *rmd;
       
  3524           for (msdi.toFirst();(rmd=msdi.current());++msdi)
       
  3525           {
       
  3526             if (defDict==0 || defDict->find(rmd->name())==0)
       
  3527             {
       
  3528               mdef->addSourceReferencedBy(rmd);
       
  3529             }
       
  3530           }
       
  3531         }
       
  3532       }
       
  3533     }
       
  3534   }
       
  3535 }
       
  3536 
       
  3537 //----------------------------------------------------------------------
       
  3538 
       
  3539 static void transferRelatedFunctionDocumentation()
       
  3540 {
       
  3541   // find match between function declaration and definition for 
       
  3542   // related functions
       
  3543   MemberNameSDict::Iterator mnli(*Doxygen::functionNameSDict);
       
  3544   MemberName *mn;
       
  3545   for (mnli.toFirst();(mn=mnli.current());++mnli)
       
  3546   {
       
  3547     MemberDef *md;
       
  3548     MemberNameIterator mni(*mn);
       
  3549     /* find a matching function declaration and definition for this function */
       
  3550     for (mni.toFirst();(md=mni.current());++mni) // for each global function
       
  3551     {
       
  3552       //printf("  Function `%s'\n",md->name().data());
       
  3553       MemberName *rmn;
       
  3554       if ((rmn=Doxygen::memberNameSDict->find(md->name()))) // check if there is a member with the same name
       
  3555       {
       
  3556         //printf("  Member name found\n");
       
  3557         MemberDef *rmd;
       
  3558         MemberNameIterator rmni(*rmn);
       
  3559         for (rmni.toFirst();(rmd=rmni.current());++rmni) // for each member with the same name
       
  3560         {
       
  3561           LockingPtr<ArgumentList>  mdAl = md->argumentList();
       
  3562           LockingPtr<ArgumentList> rmdAl = rmd->argumentList();
       
  3563           //printf("  Member found: related=`%d'\n",rmd->isRelated());
       
  3564           if ((rmd->isRelated() || rmd->isForeign()) && // related function
       
  3565               matchArguments2( md->getOuterScope(), md->getFileDef(), mdAl.pointer(),
       
  3566                               rmd->getOuterScope(),rmd->getFileDef(),rmdAl.pointer(),
       
  3567                               TRUE
       
  3568                              )
       
  3569              )
       
  3570           {
       
  3571             //printf("  Found related member `%s'\n",md->name().data());
       
  3572             if (rmd->relatedAlso())
       
  3573               md->setRelatedAlso(rmd->relatedAlso());
       
  3574             else if (rmd->isForeign())
       
  3575               md->makeForeign();
       
  3576             else
       
  3577               md->makeRelated();
       
  3578           } 
       
  3579         }
       
  3580       } 
       
  3581     }
       
  3582   }
       
  3583 }
       
  3584 
       
  3585 //----------------------------------------------------------------------
       
  3586 
       
  3587 /*! make a dictionary of all template arguments of class cd
       
  3588  * that are part of the base class name. 
       
  3589  * Example: A template class A with template arguments <R,S,T> 
       
  3590  * that inherits from B<T,T,S> will have T and S in the dictionary.
       
  3591  */
       
  3592 static QDict<int> *getTemplateArgumentsInName(ArgumentList *templateArguments,const QCString &name)
       
  3593 {
       
  3594   QDict<int> *templateNames = new QDict<int>(17);
       
  3595   templateNames->setAutoDelete(TRUE);
       
  3596   static QRegExp re("[a-z_A-Z][a-z_A-Z0-9:]*");
       
  3597   if (templateArguments)
       
  3598   {
       
  3599     ArgumentListIterator ali(*templateArguments);
       
  3600     Argument *arg;
       
  3601     int count=0;
       
  3602     for (ali.toFirst();(arg=ali.current());++ali,count++)
       
  3603     {
       
  3604       int i,p=0,l;
       
  3605       while ((i=re.match(name,p,&l))!=-1)
       
  3606       {
       
  3607         QCString n = name.mid(i,l);
       
  3608         if (n==arg->name)
       
  3609         {
       
  3610           if (templateNames->find(n)==0)
       
  3611           {
       
  3612             templateNames->insert(n,new int(count));
       
  3613           }
       
  3614         }
       
  3615         p=i+l;
       
  3616       }
       
  3617     }
       
  3618   }
       
  3619   return templateNames;
       
  3620 }
       
  3621 
       
  3622 /*! Searches a class from within \a context and \a cd and returns its
       
  3623  *  definition if found (otherwise 0 is returned).
       
  3624  */
       
  3625 static ClassDef *findClassWithinClassContext(Definition *context,ClassDef *cd,const QCString &name)
       
  3626 {
       
  3627   FileDef *fd=cd->getFileDef();
       
  3628   ClassDef *result=0;
       
  3629   if (context && cd!=context)
       
  3630   {
       
  3631     result = getResolvedClass(context,0,name,0,0,TRUE,TRUE);
       
  3632   }
       
  3633   if (result==0)
       
  3634   {
       
  3635     result = getResolvedClass(cd,fd,name,0,0,TRUE,TRUE);
       
  3636   }
       
  3637   //printf("** Trying to find %s within context %s class %s result=%s lookup=%p\n",
       
  3638   //       name.data(),
       
  3639   //       context ? context->name().data() : "<none>",
       
  3640   //       cd      ? cd->name().data()      : "<none>",
       
  3641   //       result  ? result->name().data()  : "<none>",
       
  3642   //       Doxygen::classSDict.find(name)
       
  3643   //      );
       
  3644   return result;
       
  3645 }
       
  3646 
       
  3647 enum FindBaseClassRelation_Mode 
       
  3648 { 
       
  3649   TemplateInstances, 
       
  3650   DocumentedOnly, 
       
  3651   Undocumented 
       
  3652 };
       
  3653 
       
  3654 static bool findClassRelation(
       
  3655                            EntryNav *rootNav,
       
  3656                            Definition *context,
       
  3657                            ClassDef *cd,
       
  3658                            BaseInfo *bi,
       
  3659                            QDict<int> *templateNames,
       
  3660                            /*bool insertUndocumented*/
       
  3661                            FindBaseClassRelation_Mode mode,
       
  3662                            bool isArtificial
       
  3663                           );
       
  3664 
       
  3665 
       
  3666 static void findUsedClassesForClass(EntryNav *rootNav,
       
  3667                            Definition *context,
       
  3668                            ClassDef *masterCd,
       
  3669                            ClassDef *instanceCd,
       
  3670                            bool isArtificial,
       
  3671                            ArgumentList *actualArgs=0,
       
  3672                            QDict<int> *templateNames=0
       
  3673                            )
       
  3674 {
       
  3675   masterCd->visited=TRUE;
       
  3676   ArgumentList *formalArgs = masterCd->templateArguments();
       
  3677   if (masterCd->memberNameInfoSDict())
       
  3678   {
       
  3679     MemberNameInfoSDict::Iterator mnili(*masterCd->memberNameInfoSDict());
       
  3680     MemberNameInfo *mni;
       
  3681     for (;(mni=mnili.current());++mnili)
       
  3682     {
       
  3683       MemberNameInfoIterator mnii(*mni);
       
  3684       MemberInfo *mi;
       
  3685       for (mnii.toFirst();(mi=mnii.current());++mnii)
       
  3686       {
       
  3687         MemberDef *md=mi->memberDef;
       
  3688         if (md->isVariable()) // for each member variable in this class
       
  3689         {
       
  3690           //printf("    Found variable %s in class %s\n",md->name().data(),masterCd->name().data());
       
  3691           QCString type=removeRedundantWhiteSpace(md->typeString());
       
  3692           QCString typedefValue = resolveTypeDef(masterCd,type);
       
  3693           if (!typedefValue.isEmpty())
       
  3694           {
       
  3695             type = typedefValue;
       
  3696           }
       
  3697           int pos=0;
       
  3698           QCString usedClassName;
       
  3699           QCString templSpec;
       
  3700           bool found=FALSE;
       
  3701           // the type can contain template variables, replace them if present
       
  3702           if (actualArgs)
       
  3703           {
       
  3704             type = substituteTemplateArgumentsInString(type,formalArgs,actualArgs);
       
  3705           }
       
  3706 
       
  3707           //printf("      template substitution gives=%s\n",type.data());
       
  3708           while (!found && extractClassNameFromType(type,pos,usedClassName,templSpec)!=-1)
       
  3709           {
       
  3710             // find the type (if any) that matches usedClassName
       
  3711             ClassDef *typeCd = getResolvedClass(masterCd,
       
  3712                 masterCd->getFileDef(),
       
  3713                 usedClassName,
       
  3714                 0,0,
       
  3715                 FALSE,TRUE
       
  3716                 );
       
  3717             //printf("====>  usedClassName=%s -> typeCd=%s\n",
       
  3718             //     usedClassName.data(),typeCd?typeCd->name().data():"<none>");
       
  3719             if (typeCd)
       
  3720             {
       
  3721               usedClassName = typeCd->name();
       
  3722             }
       
  3723 
       
  3724             int sp=usedClassName.find('<');
       
  3725             if (sp==-1) sp=0;
       
  3726             int si=usedClassName.findRev("::",sp);
       
  3727             if (si!=-1)
       
  3728             {
       
  3729               // replace any namespace aliases
       
  3730               replaceNamespaceAliases(usedClassName,si);
       
  3731             }
       
  3732             // add any template arguments to the class
       
  3733             QCString usedName = removeRedundantWhiteSpace(usedClassName+templSpec);
       
  3734             //printf("    usedName=%s\n",usedName.data());
       
  3735 
       
  3736             bool delTempNames=FALSE;
       
  3737             if (templateNames==0)
       
  3738             {
       
  3739               templateNames = getTemplateArgumentsInName(formalArgs,usedName);
       
  3740               delTempNames=TRUE;
       
  3741             }
       
  3742             BaseInfo bi(usedName,Public,Normal);
       
  3743             findClassRelation(rootNav,context,instanceCd,&bi,templateNames,TemplateInstances,isArtificial);
       
  3744 
       
  3745             if (masterCd->templateArguments())
       
  3746             {
       
  3747               ArgumentListIterator ali(*masterCd->templateArguments());
       
  3748               Argument *arg;
       
  3749               int count=0;
       
  3750               for (ali.toFirst();(arg=ali.current());++ali,++count)
       
  3751               {
       
  3752                 if (arg->name==usedName) // type is a template argument
       
  3753                 {
       
  3754                   found=TRUE;
       
  3755                   Debug::print(Debug::Classes,0,"    New used class `%s'\n", usedName.data());
       
  3756 
       
  3757                   ClassDef *usedCd = Doxygen::hiddenClasses->find(usedName);
       
  3758                   if (usedCd==0)
       
  3759                   {
       
  3760                     usedCd = new ClassDef(
       
  3761                         masterCd->getDefFileName(),masterCd->getDefLine(),
       
  3762                         usedName,ClassDef::Class);
       
  3763                     //printf("making %s a template argument!!!\n",usedCd->name().data());
       
  3764                     usedCd->makeTemplateArgument();
       
  3765                     usedCd->setUsedOnly(TRUE);
       
  3766                     Doxygen::hiddenClasses->append(usedName,usedCd);
       
  3767                   }
       
  3768                   if (usedCd)
       
  3769                   {
       
  3770                     if (isArtificial) usedCd->setArtificial(TRUE);
       
  3771                     Debug::print(Debug::Classes,0,"      Adding used class `%s' (1)\n", usedCd->name().data());
       
  3772                     instanceCd->addUsedClass(usedCd,md->name());
       
  3773                     usedCd->addUsedByClass(instanceCd,md->name());
       
  3774                   }
       
  3775                 }
       
  3776               }
       
  3777             }
       
  3778 
       
  3779             if (!found)
       
  3780             {
       
  3781               ClassDef *usedCd=findClassWithinClassContext(context,masterCd,usedName);
       
  3782               //printf("Looking for used class %s: result=%s master=%s\n",
       
  3783               //    usedName.data(),usedCd?usedCd->name().data():"<none>",masterCd?masterCd->name().data():"<none>");
       
  3784 
       
  3785               if (usedCd) 
       
  3786               {
       
  3787                 found=TRUE;
       
  3788                 Debug::print(Debug::Classes,0,"    Adding used class `%s' (2)\n", usedCd->name().data());
       
  3789                 instanceCd->addUsedClass(usedCd,md->name()); // class exists 
       
  3790                 usedCd->addUsedByClass(instanceCd,md->name());
       
  3791               }
       
  3792             }
       
  3793             if (delTempNames)
       
  3794             {
       
  3795               delete templateNames;
       
  3796               templateNames=0;
       
  3797             }
       
  3798           }
       
  3799           if (!found && !type.isEmpty()) // used class is not documented in any scope
       
  3800           {
       
  3801             ClassDef *usedCd = Doxygen::hiddenClasses->find(type);
       
  3802             if (usedCd==0 && !Config_getBool("HIDE_UNDOC_RELATIONS"))
       
  3803             {
       
  3804               if (type.right(2)=="(*") // type is a function pointer
       
  3805               {
       
  3806                 type+=md->argsString();
       
  3807               }
       
  3808               Debug::print(Debug::Classes,0,"  New undocumented used class `%s'\n", type.data());
       
  3809               usedCd = new ClassDef(
       
  3810                   masterCd->getDefFileName(),masterCd->getDefLine(),
       
  3811                   type,ClassDef::Class);
       
  3812               usedCd->setUsedOnly(TRUE);
       
  3813               Doxygen::hiddenClasses->append(type,usedCd);
       
  3814             }
       
  3815             if (usedCd)
       
  3816             {
       
  3817               if (isArtificial) usedCd->setArtificial(TRUE);
       
  3818               Debug::print(Debug::Classes,0,"    Adding used class `%s' (3)\n", usedCd->name().data());
       
  3819               instanceCd->addUsedClass(usedCd,md->name()); 
       
  3820               usedCd->addUsedByClass(instanceCd,md->name());
       
  3821             }
       
  3822           }
       
  3823         }
       
  3824       }
       
  3825     }
       
  3826   }
       
  3827   else
       
  3828   {
       
  3829     //printf("no members for class %s (%p)\n",masterCd->name().data(),masterCd);
       
  3830   }
       
  3831 }
       
  3832 
       
  3833 static void findBaseClassesForClass(
       
  3834       EntryNav *rootNav,
       
  3835       Definition *context,
       
  3836       ClassDef *masterCd,
       
  3837       ClassDef *instanceCd,
       
  3838       FindBaseClassRelation_Mode mode,
       
  3839       bool isArtificial,
       
  3840       ArgumentList *actualArgs=0,
       
  3841       QDict<int> *templateNames=0
       
  3842     )
       
  3843 {
       
  3844   Entry *root = rootNav->entry();
       
  3845   //if (masterCd->visited) return;
       
  3846   masterCd->visited=TRUE;
       
  3847   // The base class could ofcouse also be a non-nested class
       
  3848   ArgumentList *formalArgs = masterCd->templateArguments();
       
  3849   QListIterator<BaseInfo> bii(*root->extends);
       
  3850   BaseInfo *bi=0;
       
  3851   for (bii.toFirst();(bi=bii.current());++bii)
       
  3852   {
       
  3853     //printf("masterCd=%s bi->name='%s' #actualArgs=%d\n",
       
  3854     //    masterCd->localName().data(),bi->name.data(),actualArgs?(int)actualArgs->count():-1);
       
  3855     bool delTempNames=FALSE;
       
  3856     if (templateNames==0)
       
  3857     {
       
  3858       templateNames = getTemplateArgumentsInName(formalArgs,bi->name);
       
  3859       delTempNames=TRUE;
       
  3860     }
       
  3861     BaseInfo tbi(bi->name,bi->prot,bi->virt);
       
  3862     if (actualArgs) // substitute the formal template arguments of the base class
       
  3863     {
       
  3864       tbi.name = substituteTemplateArgumentsInString(bi->name,formalArgs,actualArgs);
       
  3865     }
       
  3866     //printf("bi->name=%s tbi.name=%s\n",bi->name.data(),tbi.name.data());
       
  3867 
       
  3868     if (mode==DocumentedOnly)
       
  3869     {
       
  3870       // find a documented base class in the correct scope
       
  3871       if (!findClassRelation(rootNav,context,instanceCd,&tbi,templateNames,DocumentedOnly,isArtificial))
       
  3872       {
       
  3873         if (!Config_getBool("HIDE_UNDOC_RELATIONS"))
       
  3874         {
       
  3875           // no documented base class -> try to find an undocumented one
       
  3876           findClassRelation(rootNav,context,instanceCd,&tbi,templateNames,Undocumented,isArtificial);
       
  3877         }
       
  3878       }
       
  3879     }
       
  3880     else if (mode==TemplateInstances)
       
  3881     {
       
  3882       findClassRelation(rootNav,context,instanceCd,&tbi,templateNames,TemplateInstances,isArtificial);
       
  3883     }
       
  3884     if (delTempNames)
       
  3885     {
       
  3886       delete templateNames;
       
  3887       templateNames=0;
       
  3888     }  
       
  3889   }
       
  3890 }
       
  3891 
       
  3892 //----------------------------------------------------------------------
       
  3893 
       
  3894 static bool findTemplateInstanceRelation(Entry *root,
       
  3895             Definition *context,
       
  3896             ClassDef *templateClass,const QCString &templSpec,
       
  3897             QDict<int> *templateNames,
       
  3898             bool isArtificial)
       
  3899 {
       
  3900   Debug::print(Debug::Classes,0,"    derived from template %s with parameters %s\n",
       
  3901          templateClass->name().data(),templSpec.data());
       
  3902   //printf("findTemplateInstanceRelation(base=%s templSpec=%s templateNames=",
       
  3903   //    templateClass->name().data(),templSpec.data());
       
  3904   //if (templateNames)
       
  3905   //{
       
  3906   //  QDictIterator<int> qdi(*templateNames);
       
  3907   //  int *tempArgIndex;
       
  3908   //  for (;(tempArgIndex=qdi.current());++qdi)
       
  3909   //  {
       
  3910   //    printf("(%s->%d) ",qdi.currentKey().data(),*tempArgIndex);
       
  3911   //  }
       
  3912   //}
       
  3913   //printf("\n");
       
  3914   
       
  3915   bool existingClass = (templSpec ==
       
  3916                         tempArgListToString(templateClass->templateArguments())
       
  3917                        );
       
  3918   if (existingClass) return TRUE;
       
  3919 
       
  3920   bool freshInstance=FALSE;
       
  3921   ClassDef *instanceClass = templateClass->insertTemplateInstance(
       
  3922                      root->fileName,root->startLine,templSpec,freshInstance);
       
  3923   if (isArtificial) instanceClass->setArtificial(TRUE);
       
  3924   instanceClass->setIsObjectiveC(root->objc);
       
  3925 
       
  3926   if (freshInstance)
       
  3927   {
       
  3928     Debug::print(Debug::Classes,0,"      found fresh instance '%s'!\n",instanceClass->name().data());
       
  3929     Doxygen::classSDict->append(instanceClass->name(),instanceClass);
       
  3930     instanceClass->setTemplateBaseClassNames(templateNames);
       
  3931 
       
  3932     // search for new template instances caused by base classes of 
       
  3933     // instanceClass 
       
  3934     EntryNav *templateRootNav = g_classEntries.find(templateClass->name());
       
  3935     if (templateRootNav)
       
  3936     {
       
  3937       bool unloadNeeded=FALSE;
       
  3938       Entry *templateRoot = templateRootNav->entry();
       
  3939       if (templateRoot==0) // not yet loaded
       
  3940       {
       
  3941         templateRootNav->loadEntry(g_storage);
       
  3942         templateRoot = templateRootNav->entry();
       
  3943         ASSERT(templateRoot!=0); // now it should really be loaded
       
  3944         unloadNeeded=TRUE;
       
  3945       }
       
  3946 
       
  3947       Debug::print(Debug::Classes,0,"        template root found %s templSpec=%s!\n",
       
  3948           templateRoot->name.data(),templSpec.data());
       
  3949       ArgumentList *templArgs = new ArgumentList;
       
  3950       stringToArgumentList(templSpec,templArgs);
       
  3951       findBaseClassesForClass(templateRootNav,context,templateClass,instanceClass,
       
  3952           TemplateInstances,isArtificial,templArgs,templateNames);
       
  3953 
       
  3954       findUsedClassesForClass(templateRootNav,context,templateClass,instanceClass,
       
  3955           isArtificial,templArgs,templateNames);
       
  3956       delete templArgs;
       
  3957 
       
  3958       if (unloadNeeded) // still cleanup to do
       
  3959       {
       
  3960         templateRootNav->releaseEntry();
       
  3961       }
       
  3962     }
       
  3963     else
       
  3964     {
       
  3965       Debug::print(Debug::Classes,0,"        no template root entry found!\n");
       
  3966       // TODO: what happened if we get here?
       
  3967     }
       
  3968 
       
  3969     //Debug::print(Debug::Classes,0,"    Template instance %s : \n",instanceClass->name().data());
       
  3970     //ArgumentList *tl = templateClass->templateArguments();
       
  3971   }
       
  3972   else
       
  3973   {
       
  3974     Debug::print(Debug::Classes,0,"      instance already exists!\n");
       
  3975   }
       
  3976   return TRUE;
       
  3977 }
       
  3978 
       
  3979 static bool isRecursiveBaseClass(const QCString &scope,const QCString &name)
       
  3980 {
       
  3981   QCString n=name;
       
  3982   int index=n.find('<');
       
  3983   if (index!=-1)
       
  3984   {
       
  3985     n=n.left(index);
       
  3986   }
       
  3987   bool result = rightScopeMatch(scope,n);
       
  3988   return result;
       
  3989 }
       
  3990 
       
  3991 /*! Searches for the end of a template in prototype \a s starting from
       
  3992  *  character position \a startPos. If the end was found the position
       
  3993  *  of the closing \> is returned, otherwise -1 is returned.
       
  3994  *
       
  3995  *  Handles exotic cases such as 
       
  3996  *  \code
       
  3997  *    Class<(id<0)>
       
  3998  *    Class<bits<<2>
       
  3999  *    Class<"<">
       
  4000  *    Class<'<'>
       
  4001  *    Class<(")<")>
       
  4002  *  \endcode
       
  4003  */
       
  4004 static int findEndOfTemplate(const QCString &s,int startPos)
       
  4005 {
       
  4006   // locate end of template
       
  4007   int e=startPos;
       
  4008   int brCount=1;
       
  4009   int roundCount=0;
       
  4010   int len = s.length();
       
  4011   bool insideString=FALSE;
       
  4012   bool insideChar=FALSE;
       
  4013   char pc = 0;
       
  4014   while (e<len && brCount!=0)
       
  4015   {
       
  4016     char c=s.at(e);
       
  4017     switch(c)
       
  4018     {
       
  4019       case '<': 
       
  4020         if (!insideString && !insideChar)
       
  4021         {
       
  4022           if (e<len-1 && s.at(e+1)=='<') 
       
  4023             e++; 
       
  4024           else if (roundCount==0)
       
  4025             brCount++;
       
  4026         }
       
  4027         break;
       
  4028       case '>':
       
  4029         if (!insideString && !insideChar)
       
  4030         {
       
  4031           if (e<len-1 && s.at(e+1)=='>') 
       
  4032             e++; 
       
  4033           else if (roundCount==0)
       
  4034             brCount--;
       
  4035         }
       
  4036         break;
       
  4037       case '(':
       
  4038         if (!insideString && !insideChar) 
       
  4039           roundCount++;
       
  4040         break;
       
  4041       case ')':
       
  4042         if (!insideString && !insideChar) 
       
  4043           roundCount--;
       
  4044         break;
       
  4045       case '"':
       
  4046         if (!insideChar)
       
  4047         {
       
  4048           if (insideString && pc!='\\') 
       
  4049             insideString=FALSE;
       
  4050           else
       
  4051             insideString=TRUE;
       
  4052         }
       
  4053         break;
       
  4054       case '\'':
       
  4055         if (!insideString)
       
  4056         {
       
  4057           if (insideChar && pc!='\\')
       
  4058             insideChar=FALSE;
       
  4059           else
       
  4060             insideChar=TRUE;
       
  4061         }
       
  4062         break;
       
  4063     }
       
  4064     pc = c;
       
  4065     e++;
       
  4066   }
       
  4067   return brCount==0 ? e : -1;
       
  4068 }
       
  4069 
       
  4070 static bool findClassRelation(
       
  4071                            EntryNav *rootNav,
       
  4072                            Definition *context,
       
  4073                            ClassDef *cd,
       
  4074                            BaseInfo *bi,
       
  4075                            QDict<int> *templateNames,
       
  4076                            FindBaseClassRelation_Mode mode,
       
  4077                            bool isArtificial
       
  4078                           )
       
  4079 {
       
  4080   //printf("findClassRelation(class=%s base=%s templateNames=",
       
  4081   //    cd->name().data(),bi->name.data());
       
  4082   //if (templateNames)
       
  4083   //{
       
  4084   //  QDictIterator<int> qdi(*templateNames);
       
  4085   //  int *tempArgIndex;
       
  4086   //  for (;(tempArgIndex=qdi.current());++qdi)
       
  4087   //  {
       
  4088   //    printf("(%s->%d) ",qdi.currentKey(),*tempArgIndex);
       
  4089   //  }
       
  4090   //}
       
  4091   //printf("\n");
       
  4092 
       
  4093   Entry *root = rootNav->entry();
       
  4094 
       
  4095   QCString biName=bi->name;
       
  4096   bool explicitGlobalScope=FALSE;
       
  4097   //printf("findClassRelation: biName=`%s'\n",biName.data());
       
  4098   if (biName.left(2)=="::") // explicit global scope
       
  4099   {
       
  4100      biName=biName.right(biName.length()-2);
       
  4101      explicitGlobalScope=TRUE;
       
  4102   }
       
  4103 
       
  4104   EntryNav *parentNode=rootNav->parent();
       
  4105   bool lastParent=FALSE;
       
  4106   do // for each parent scope, starting with the largest scope 
       
  4107      // (in case of nested classes)
       
  4108   {
       
  4109     QCString scopeName= parentNode ? parentNode->name().data() : "";
       
  4110     int scopeOffset=explicitGlobalScope ? 0 : scopeName.length();
       
  4111     do // try all parent scope prefixes, starting with the largest scope
       
  4112     {
       
  4113       //printf("scopePrefix=`%s' biName=`%s'\n",
       
  4114       //    scopeName.left(scopeOffset).data(),biName.data());
       
  4115 
       
  4116       QCString baseClassName=biName;
       
  4117       if (scopeOffset>0)
       
  4118       {
       
  4119         baseClassName.prepend(scopeName.left(scopeOffset)+"::");
       
  4120       }
       
  4121       //QCString stripped;
       
  4122       //baseClassName=stripTemplateSpecifiersFromScope
       
  4123       //                    (removeRedundantWhiteSpace(baseClassName),TRUE,
       
  4124       //                    &stripped);
       
  4125       MemberDef *baseClassTypeDef=0;
       
  4126       QCString templSpec;
       
  4127       ClassDef *baseClass=getResolvedClass(explicitGlobalScope ? Doxygen::globalScope : context,
       
  4128                                            cd->getFileDef(), 
       
  4129                                            baseClassName,
       
  4130                                            &baseClassTypeDef,
       
  4131                                            &templSpec,
       
  4132                                            mode==Undocumented,
       
  4133                                            TRUE
       
  4134                                           );
       
  4135       //printf("baseClassName=%s baseClass=%p cd=%p explicitGlobalScope=%d\n",
       
  4136       //    baseClassName.data(),baseClass,cd,explicitGlobalScope);
       
  4137       //printf("    scope=`%s' baseClassName=`%s' baseClass=%s templSpec=%s\n",
       
  4138       //                    cd ? cd->name().data():"<none>",
       
  4139       //                    baseClassName.data(),
       
  4140       //                    baseClass?baseClass->name().data():"<none>",
       
  4141       //                    templSpec.data()
       
  4142       //      );
       
  4143       //if (baseClassName.left(root->name.length())!=root->name ||
       
  4144       //    baseClassName.at(root->name.length())!='<'
       
  4145       //   ) // Check for base class with the same name.
       
  4146       //     // If found then look in the outer scope for a match
       
  4147       //     // and prevent recursion.
       
  4148       if (!isRecursiveBaseClass(rootNav->name(),baseClassName) || explicitGlobalScope)
       
  4149       {
       
  4150         Debug::print(
       
  4151             Debug::Classes,0,"    class relation %s inherited/used by %s found (%s and %s) templSpec='%s'\n",
       
  4152             baseClassName.data(),
       
  4153             rootNav->name().data(),
       
  4154             (bi->prot==Private)?"private":((bi->prot==Protected)?"protected":"public"),
       
  4155             (bi->virt==Normal)?"normal":"virtual",
       
  4156             templSpec.data()
       
  4157            );
       
  4158 
       
  4159         int i=baseClassName.find('<');
       
  4160         int si=baseClassName.findRev("::",i==-1 ? baseClassName.length() : i);
       
  4161         if (si==-1) si=0;
       
  4162         if (baseClass==0 && i!=-1) 
       
  4163           // base class has template specifiers
       
  4164         {
       
  4165           // TODO: here we should try to find the correct template specialization
       
  4166           // but for now, we only look for the unspecializated base class.
       
  4167           int e=findEndOfTemplate(baseClassName,i+1);
       
  4168           //printf("baseClass==0 i=%d e=%d\n",i,e);
       
  4169           if (e!=-1) // end of template was found at e
       
  4170           {
       
  4171             templSpec=removeRedundantWhiteSpace(baseClassName.mid(i,e-i));
       
  4172             baseClassName=baseClassName.left(i)+baseClassName.right(baseClassName.length()-e);
       
  4173             baseClass=getResolvedClass(explicitGlobalScope ? Doxygen::globalScope : context,
       
  4174                                        cd->getFileDef(),
       
  4175                                        baseClassName,
       
  4176                                        &baseClassTypeDef,
       
  4177                                        0, //&templSpec,
       
  4178                                        mode==Undocumented,
       
  4179                                        TRUE
       
  4180                                       );
       
  4181             //printf("baseClass=%p -> baseClass=%s templSpec=%s\n",
       
  4182             //      baseClass,baseClassName.data(),templSpec.data());
       
  4183           }
       
  4184         }
       
  4185         else if (baseClass && !templSpec.isEmpty()) // we have a known class, but also
       
  4186                                                     // know it is a template, so see if
       
  4187                                                     // we can also link to the explicit
       
  4188                                                     // instance (for instance if a class
       
  4189                                                     // derived from a template argument)
       
  4190         {
       
  4191           //printf("baseClass=%p templSpec=%s\n",baseClass,templSpec.data());
       
  4192           ClassDef *templClass=getClass(baseClass->name()+templSpec);
       
  4193           if (templClass)
       
  4194           {
       
  4195             // use the template instance instead of the template base.
       
  4196             baseClass = templClass;
       
  4197             templSpec.resize(0);
       
  4198           }
       
  4199         }
       
  4200 
       
  4201         //printf("cd=%p baseClass=%p\n",cd,baseClass);
       
  4202         bool found=baseClass!=0 && (baseClass!=cd || mode==TemplateInstances);
       
  4203         //printf("1. found=%d\n",found);
       
  4204         if (!found && si!=-1)
       
  4205         {
       
  4206           QCString tmpTemplSpec;
       
  4207           // replace any namespace aliases
       
  4208           replaceNamespaceAliases(baseClassName,si);
       
  4209           baseClass=getResolvedClass(explicitGlobalScope ? Doxygen::globalScope : context,
       
  4210                                      cd->getFileDef(),
       
  4211                                      baseClassName,
       
  4212                                      &baseClassTypeDef,
       
  4213                                      &tmpTemplSpec,
       
  4214                                      mode==Undocumented,
       
  4215                                      TRUE
       
  4216                                     );
       
  4217           found=baseClass!=0 && baseClass!=cd;
       
  4218           if (found) templSpec = tmpTemplSpec;
       
  4219         }
       
  4220         //printf("2. found=%d\n",found);
       
  4221         
       
  4222         //printf("root->name=%s biName=%s baseClassName=%s\n",
       
  4223         //        root->name.data(),biName.data(),baseClassName.data());
       
  4224 
       
  4225         if (!found)
       
  4226         {
       
  4227           baseClass=findClassWithinClassContext(context,cd,baseClassName);
       
  4228           //printf("findClassWithinClassContext(%s,%s)=%p\n",
       
  4229           //    cd->name().data(),baseClassName.data(),baseClass);
       
  4230           found = baseClass!=0 && baseClass!=cd;
       
  4231 
       
  4232         }
       
  4233         bool isATemplateArgument = templateNames!=0 && templateNames->find(biName)!=0;
       
  4234         // make templSpec canonical
       
  4235         // Warning: the following line doesn't work for Mixin classes (see bug 560623)
       
  4236         // templSpec = getCanonicalTemplateSpec(cd, cd->getFileDef(), templSpec);
       
  4237 
       
  4238         //printf("3. found=%d\n",found);
       
  4239         if (found)
       
  4240         {
       
  4241           Debug::print(Debug::Classes,0,"    Documented base class `%s' templSpec=%s\n",biName.data(),templSpec.isEmpty()?"":templSpec.data());
       
  4242           // add base class to this class
       
  4243 
       
  4244           // if templSpec is not empty then we should "instantiate"
       
  4245           // the template baseClass. A new ClassDef should be created
       
  4246           // to represent the instance. To be able to add the (instantiated)
       
  4247           // members and documentation of a template class 
       
  4248           // (inserted in that template class at a later stage), 
       
  4249           // the template should know about its instances. 
       
  4250           // the instantiation process, should be done in a recursive way, 
       
  4251           // since instantiating a template may introduce new inheritance 
       
  4252           // relations.
       
  4253           if (!templSpec.isEmpty() && mode==TemplateInstances)
       
  4254           {
       
  4255             // if baseClass is actually a typedef then we should not
       
  4256             // instantiate it, since typedefs are in a different namespace
       
  4257             // see bug531637 for an example where this would otherwise hang
       
  4258             // doxygen
       
  4259             if (baseClassTypeDef==0)
       
  4260             {
       
  4261               //printf("       => findTemplateInstanceRelation: %p\n",baseClassTypeDef);
       
  4262               findTemplateInstanceRelation(root,context,baseClass,templSpec,templateNames,isArtificial);
       
  4263             }
       
  4264           }
       
  4265           else if (mode==DocumentedOnly || mode==Undocumented)
       
  4266           {
       
  4267             //printf("       => insert base class\n");
       
  4268             QCString usedName;
       
  4269             if (baseClassTypeDef) 
       
  4270             {
       
  4271               usedName=biName;
       
  4272               //printf("***** usedName=%s templSpec=%s\n",usedName.data(),templSpec.data());
       
  4273             }
       
  4274             if (Config_getBool("SIP_SUPPORT")) bi->prot=Public;
       
  4275             cd->insertBaseClass(baseClass,usedName,bi->prot,bi->virt,templSpec);
       
  4276             // add this class as super class to the base class
       
  4277             baseClass->insertSubClass(cd,bi->prot,bi->virt,templSpec);
       
  4278           }
       
  4279           return TRUE;
       
  4280         }
       
  4281         else if (mode==Undocumented && (scopeOffset==0 || isATemplateArgument))
       
  4282         {
       
  4283           Debug::print(Debug::Classes,0,
       
  4284                        "    New undocumented base class `%s' baseClassName=%s\n",
       
  4285                        biName.data(),baseClassName.data()
       
  4286                       );
       
  4287           baseClass=0;
       
  4288           if (isATemplateArgument)
       
  4289           {
       
  4290             baseClass=Doxygen::hiddenClasses->find(baseClassName);
       
  4291             if (baseClass==0)
       
  4292             {
       
  4293               baseClass=new ClassDef(root->fileName,root->startLine,
       
  4294                                  baseClassName,ClassDef::Class);
       
  4295               Doxygen::hiddenClasses->append(baseClassName,baseClass);
       
  4296               if (isArtificial) baseClass->setArtificial(TRUE);
       
  4297             }
       
  4298           }
       
  4299           else
       
  4300           {
       
  4301             baseClass=Doxygen::classSDict->find(baseClassName);
       
  4302             //printf("*** classDDict->find(%s)=%p biName=%s templSpec=%s\n",
       
  4303             //    baseClassName.data(),baseClass,biName.data(),templSpec.data());
       
  4304             if (baseClass==0)
       
  4305             {
       
  4306               baseClass=new ClassDef(root->fileName,root->startLine,
       
  4307                   baseClassName,ClassDef::Class);
       
  4308               Doxygen::classSDict->append(baseClassName,baseClass);
       
  4309               if (isArtificial) baseClass->setArtificial(TRUE);
       
  4310             }
       
  4311           }
       
  4312           // add base class to this class
       
  4313           cd->insertBaseClass(baseClass,biName,bi->prot,bi->virt,templSpec);
       
  4314           // add this class as super class to the base class
       
  4315           baseClass->insertSubClass(cd,bi->prot,bi->virt,templSpec);
       
  4316           // the undocumented base was found in this file
       
  4317           baseClass->insertUsedFile(root->fileName);
       
  4318           baseClass->setOuterScope(Doxygen::globalScope);
       
  4319           return TRUE;
       
  4320         }
       
  4321         else
       
  4322         {
       
  4323           Debug::print(Debug::Classes,0,"    Base class `%s' not found\n",biName.data());
       
  4324         }
       
  4325       }
       
  4326       else
       
  4327       {
       
  4328         if (mode!=TemplateInstances)
       
  4329         {
       
  4330           warn(root->fileName,root->startLine,
       
  4331               "Detected potential recursive class relation "
       
  4332               "between class %s and base class %s!\n",
       
  4333               root->name.data(),baseClassName.data()
       
  4334               );
       
  4335         }
       
  4336         // for mode==TemplateInstance this case is quite common and
       
  4337         // indicates a relation between a template class and a template 
       
  4338         // instance with the same name.
       
  4339       }
       
  4340       if (scopeOffset==0)
       
  4341       {
       
  4342         scopeOffset=-1;
       
  4343       }
       
  4344       else if ((scopeOffset=scopeName.findRev("::",scopeOffset-1))==-1)
       
  4345       {
       
  4346         scopeOffset=0;
       
  4347       }
       
  4348       //printf("new scopeOffset=`%d'",scopeOffset);
       
  4349     } while (scopeOffset>=0);
       
  4350 
       
  4351     if (parentNode==0)
       
  4352     {
       
  4353       lastParent=TRUE;
       
  4354     }
       
  4355     else
       
  4356     {
       
  4357       parentNode=parentNode->parent();
       
  4358     }
       
  4359   } while (lastParent);
       
  4360 
       
  4361   return FALSE;
       
  4362 }
       
  4363 
       
  4364 //----------------------------------------------------------------------
       
  4365 // Computes the base and super classes for each class in the tree
       
  4366 
       
  4367 static bool isClassSection(EntryNav *rootNav)
       
  4368 {
       
  4369   if ( !rootNav->name().isEmpty() )
       
  4370   {
       
  4371     if (rootNav->section() & Entry::COMPOUND_MASK)
       
  4372          // is it a compound (class, struct, union, interface ...)
       
  4373     {
       
  4374       return TRUE;
       
  4375     }
       
  4376     else if (rootNav->section() & Entry::COMPOUNDDOC_MASK) 
       
  4377          // is it a documentation block with inheritance info.
       
  4378     {
       
  4379       rootNav->loadEntry(g_storage);
       
  4380       Entry *root = rootNav->entry();
       
  4381       bool extends = root->extends->count()>0;
       
  4382       rootNav->releaseEntry(); 
       
  4383       if (extends) return TRUE;
       
  4384     }
       
  4385   }
       
  4386   return FALSE;
       
  4387 }
       
  4388 
       
  4389 
       
  4390 /*! Builds a dictionary of all entry nodes in the tree starting with \a root
       
  4391  */
       
  4392 static void findClassEntries(EntryNav *rootNav)
       
  4393 {
       
  4394   if (isClassSection(rootNav))
       
  4395   {
       
  4396     g_classEntries.insert(rootNav->name(),rootNav);
       
  4397   }
       
  4398   RECURSE_ENTRYTREE(findClassEntries,rootNav);
       
  4399 }
       
  4400 
       
  4401 /*! Using the dictionary build by findClassEntries(), this 
       
  4402  *  function will look for additional template specialization that
       
  4403  *  exists as inheritance relations only. These instances will be
       
  4404  *  added to the template they are derived from.
       
  4405  */
       
  4406 static void findInheritedTemplateInstances()
       
  4407 {
       
  4408   ClassSDict::Iterator cli(*Doxygen::classSDict);
       
  4409   for (cli.toFirst();cli.current();++cli) cli.current()->visited=FALSE;
       
  4410   QDictIterator<EntryNav> edi(g_classEntries);
       
  4411   EntryNav *rootNav;
       
  4412   for (;(rootNav=edi.current());++edi)
       
  4413   {
       
  4414     ClassDef *cd;
       
  4415     // strip any annonymous scopes first 
       
  4416     QCString bName=stripAnonymousNamespaceScope(rootNav->name());
       
  4417     bName=stripTemplateSpecifiersFromScope(bName);
       
  4418     Debug::print(Debug::Classes,0,"  Inheritance: Class %s : \n",bName.data());
       
  4419     if ((cd=getClass(bName)))
       
  4420     {
       
  4421       rootNav->loadEntry(g_storage);
       
  4422       //printf("Class %s %d\n",cd->name().data(),root->extends->count());
       
  4423       findBaseClassesForClass(rootNav,cd,cd,cd,TemplateInstances,FALSE);
       
  4424       rootNav->releaseEntry();
       
  4425     }
       
  4426   }
       
  4427 }
       
  4428 
       
  4429 static void findUsedTemplateInstances()
       
  4430 {
       
  4431   ClassSDict::Iterator cli(*Doxygen::classSDict);
       
  4432   for (cli.toFirst();cli.current();++cli) cli.current()->visited=FALSE;
       
  4433   QDictIterator<EntryNav> edi(g_classEntries);
       
  4434   EntryNav *rootNav;
       
  4435   for (;(rootNav=edi.current());++edi)
       
  4436   {
       
  4437     ClassDef *cd;
       
  4438     // strip any annonymous scopes first 
       
  4439     QCString bName=stripAnonymousNamespaceScope(rootNav->name());
       
  4440     bName=stripTemplateSpecifiersFromScope(bName);
       
  4441     Debug::print(Debug::Classes,0,"  Usage: Class %s : \n",bName.data());
       
  4442     if ((cd=getClass(bName)))
       
  4443     {
       
  4444       rootNav->loadEntry(g_storage);
       
  4445       findUsedClassesForClass(rootNav,cd,cd,cd,TRUE);
       
  4446       rootNav->releaseEntry();
       
  4447     }
       
  4448   }
       
  4449 }
       
  4450 
       
  4451 static void computeClassRelations()
       
  4452 {
       
  4453   ClassSDict::Iterator cli(*Doxygen::classSDict);
       
  4454   for (cli.toFirst();cli.current();++cli) cli.current()->visited=FALSE;
       
  4455   QDictIterator<EntryNav> edi(g_classEntries);
       
  4456   EntryNav *rootNav;
       
  4457   for (;(rootNav=edi.current());++edi)
       
  4458   {
       
  4459     ClassDef *cd;
       
  4460 
       
  4461     rootNav->loadEntry(g_storage);
       
  4462     Entry *root = rootNav->entry();
       
  4463 
       
  4464     // strip any annonymous scopes first 
       
  4465     QCString bName=stripAnonymousNamespaceScope(rootNav->name());
       
  4466     bName=stripTemplateSpecifiersFromScope(bName);
       
  4467     Debug::print(Debug::Classes,0,"  Relations: Class %s : \n",bName.data());
       
  4468     if ((cd=getClass(bName)))
       
  4469     {
       
  4470       findBaseClassesForClass(rootNav,cd,cd,cd,DocumentedOnly,FALSE);
       
  4471     }
       
  4472     if ((cd==0 || (!cd->hasDocumentation() && !cd->isReference())) && 
       
  4473         bName.right(2)!="::")
       
  4474     {
       
  4475       if (!root->name.isEmpty() && root->name.find('@')==-1 && // normal name
       
  4476           (guessSection(root->fileName)==Entry::HEADER_SEC || 
       
  4477            Config_getBool("EXTRACT_LOCAL_CLASSES")) && // not defined in source file
       
  4478           (root->protection!=Private || Config_getBool("EXTRACT_PRIVATE")) && // hidden by protection
       
  4479           !Config_getBool("HIDE_UNDOC_CLASSES") // undocumented class are visible
       
  4480          )
       
  4481         warn_undoc(
       
  4482                    root->fileName,root->startLine,
       
  4483                    "Warning: Compound %s is not documented.",
       
  4484                    root->name.data()
       
  4485              );
       
  4486     }
       
  4487 
       
  4488     rootNav->releaseEntry();
       
  4489   }
       
  4490 }
       
  4491 
       
  4492 static void computeTemplateClassRelations()
       
  4493 {
       
  4494   QDictIterator<EntryNav> edi(g_classEntries);
       
  4495   EntryNav *rootNav;
       
  4496   for (;(rootNav=edi.current());++edi)
       
  4497   {
       
  4498     rootNav->loadEntry(g_storage);
       
  4499     Entry *root = rootNav->entry();
       
  4500 
       
  4501     QCString bName=stripAnonymousNamespaceScope(root->name);
       
  4502     bName=stripTemplateSpecifiersFromScope(bName);
       
  4503     ClassDef *cd=getClass(bName);
       
  4504     // strip any annonymous scopes first 
       
  4505     QDict<ClassDef> *templInstances = 0;
       
  4506     if (cd && (templInstances=cd->getTemplateInstances()))
       
  4507     {
       
  4508       Debug::print(Debug::Classes,0,"  Template class %s : \n",cd->name().data());
       
  4509       QDictIterator<ClassDef> tdi(*templInstances);
       
  4510       ClassDef *tcd;
       
  4511       for (tdi.toFirst();(tcd=tdi.current());++tdi) // for each template instance
       
  4512       {
       
  4513         Debug::print(Debug::Classes,0,"    Template instance %s : \n",tcd->name().data());
       
  4514         QCString templSpec = tdi.currentKey();
       
  4515         ArgumentList *templArgs = new ArgumentList;
       
  4516         stringToArgumentList(templSpec,templArgs);
       
  4517         QList<BaseInfo> *baseList=root->extends;
       
  4518         BaseInfo *bi=baseList->first();
       
  4519         while (bi) // for each base class of the template
       
  4520         {
       
  4521           // check if the base class is a template argument
       
  4522           BaseInfo tbi(bi->name,bi->prot,bi->virt);
       
  4523           ArgumentList *tl = cd->templateArguments();
       
  4524           if (tl)
       
  4525           {
       
  4526             QDict<int> *baseClassNames = tcd->getTemplateBaseClassNames();
       
  4527             QDict<int> *templateNames = getTemplateArgumentsInName(tl,bi->name);
       
  4528             // for each template name that we inherit from we need to
       
  4529             // substitute the formal with the actual arguments
       
  4530             QDict<int> *actualTemplateNames = new QDict<int>(17);
       
  4531             actualTemplateNames->setAutoDelete(TRUE);
       
  4532             QDictIterator<int> qdi(*templateNames);
       
  4533             for (qdi.toFirst();qdi.current();++qdi)
       
  4534             {
       
  4535               int templIndex = *qdi.current();
       
  4536               Argument *actArg = 0;
       
  4537               if (templIndex<(int)templArgs->count()) 
       
  4538               {
       
  4539                 actArg=templArgs->at(templIndex);
       
  4540               }
       
  4541               if (actArg!=0 &&
       
  4542                   baseClassNames!=0 &&
       
  4543                   baseClassNames->find(actArg->type)!=0 &&
       
  4544                   actualTemplateNames->find(actArg->type)==0
       
  4545                  )
       
  4546               {
       
  4547                 actualTemplateNames->insert(actArg->type,new int(templIndex));
       
  4548               }
       
  4549             }
       
  4550             delete templateNames;
       
  4551             
       
  4552             tbi.name = substituteTemplateArgumentsInString(bi->name,tl,templArgs);
       
  4553             // find a documented base class in the correct scope
       
  4554             if (!findClassRelation(rootNav,cd,tcd,&tbi,actualTemplateNames,DocumentedOnly,FALSE))
       
  4555             {
       
  4556               // no documented base class -> try to find an undocumented one
       
  4557               findClassRelation(rootNav,cd,tcd,&tbi,actualTemplateNames,Undocumented,FALSE);
       
  4558             }
       
  4559             delete actualTemplateNames;
       
  4560           }
       
  4561           bi=baseList->next();
       
  4562         }
       
  4563         delete templArgs;
       
  4564       } // class has no base classes
       
  4565     }
       
  4566 
       
  4567     rootNav->releaseEntry();
       
  4568   }
       
  4569 }
       
  4570 
       
  4571 //-----------------------------------------------------------------------
       
  4572 // compute the references (anchors in HTML) for each function in the file
       
  4573 
       
  4574 static void computeMemberReferences()
       
  4575 {
       
  4576   ClassSDict::Iterator cli(*Doxygen::classSDict);
       
  4577   ClassDef *cd=0;
       
  4578   for (cli.toFirst();(cd=cli.current());++cli)
       
  4579   {
       
  4580     cd->computeAnchors();
       
  4581   } 
       
  4582   FileName *fn=Doxygen::inputNameList->first();
       
  4583   while (fn)
       
  4584   {
       
  4585     FileDef *fd=fn->first();
       
  4586     while (fd)
       
  4587     {
       
  4588       fd->computeAnchors();
       
  4589       fd=fn->next();
       
  4590     }
       
  4591     fn=Doxygen::inputNameList->next();
       
  4592   }
       
  4593   NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
       
  4594   NamespaceDef *nd=0;
       
  4595   for (nli.toFirst();(nd=nli.current());++nli)
       
  4596   {
       
  4597     nd->computeAnchors();
       
  4598   }
       
  4599   GroupSDict::Iterator gli(*Doxygen::groupSDict);
       
  4600   GroupDef *gd;
       
  4601   for (gli.toFirst();(gd=gli.current());++gli)
       
  4602   {
       
  4603     gd->computeAnchors();
       
  4604   }
       
  4605 }
       
  4606 
       
  4607 //----------------------------------------------------------------------
       
  4608 
       
  4609 static void addListReferences()
       
  4610 {
       
  4611   MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
       
  4612   MemberName *mn=0;
       
  4613   for (mnli.toFirst();(mn=mnli.current());++mnli)
       
  4614   {
       
  4615     MemberNameIterator mni(*mn);
       
  4616     MemberDef *md=0;
       
  4617     for (mni.toFirst();(md=mni.current());++mni)
       
  4618     {
       
  4619       md->visited=FALSE;
       
  4620     }
       
  4621   }
       
  4622   MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict);
       
  4623   for (fnli.toFirst();(mn=fnli.current());++fnli)
       
  4624   {
       
  4625     MemberNameIterator mni(*mn);
       
  4626     MemberDef *md=0;
       
  4627     for (mni.toFirst();(md=mni.current());++mni)
       
  4628     {
       
  4629       md->visited=FALSE;
       
  4630     }
       
  4631   }
       
  4632 
       
  4633   ClassSDict::Iterator cli(*Doxygen::classSDict);
       
  4634   ClassDef *cd=0;
       
  4635   for (cli.toFirst();(cd=cli.current());++cli)
       
  4636   {
       
  4637     cd->addListReferences();
       
  4638   } 
       
  4639   FileName *fn=Doxygen::inputNameList->first();
       
  4640   while (fn)
       
  4641   {
       
  4642     FileDef *fd=fn->first();
       
  4643     while (fd)
       
  4644     {
       
  4645       fd->addListReferences();
       
  4646       fd=fn->next();
       
  4647     }
       
  4648     fn=Doxygen::inputNameList->next();
       
  4649   }
       
  4650   NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
       
  4651   NamespaceDef *nd=0;
       
  4652   for (nli.toFirst();(nd=nli.current());++nli)
       
  4653   {
       
  4654     nd->addListReferences();
       
  4655   }
       
  4656   GroupSDict::Iterator gli(*Doxygen::groupSDict);
       
  4657   GroupDef *gd;
       
  4658   for (gli.toFirst();(gd=gli.current());++gli)
       
  4659   {
       
  4660     gd->addListReferences();
       
  4661   }
       
  4662   PageSDict::Iterator pdi(*Doxygen::pageSDict);
       
  4663   PageDef *pd=0;
       
  4664   for (pdi.toFirst();(pd=pdi.current());++pdi)
       
  4665   {
       
  4666     QCString name = pd->name();
       
  4667     if (pd->getGroupDef())
       
  4668     {
       
  4669       name = pd->getGroupDef()->getOutputFileBase();
       
  4670     }
       
  4671     {
       
  4672       LockingPtr< QList<ListItemInfo> > xrefItems = pd->xrefListItems();
       
  4673       addRefItem(xrefItems.pointer(),
       
  4674           name,
       
  4675           theTranslator->trPage(TRUE,TRUE),
       
  4676           name,pd->title(),0);
       
  4677     }
       
  4678   }
       
  4679   DirSDict::Iterator ddi(*Doxygen::directories);
       
  4680   DirDef *dd = 0;
       
  4681   for (ddi.toFirst();(dd=ddi.current());++ddi)
       
  4682   {
       
  4683     QCString name = dd->getOutputFileBase();
       
  4684     //if (dd->getGroupDef())
       
  4685     //{
       
  4686     //  name = dd->getGroupDef()->getOutputFileBase();
       
  4687     //}
       
  4688     LockingPtr< QList<ListItemInfo> > xrefItems = dd->xrefListItems();
       
  4689     addRefItem(xrefItems.pointer(),
       
  4690         name,
       
  4691         theTranslator->trDir(TRUE,TRUE),
       
  4692         name,dd->displayName(),0);
       
  4693   }
       
  4694 }
       
  4695 
       
  4696 //----------------------------------------------------------------------
       
  4697 
       
  4698 static void generateXRefPages()
       
  4699 {
       
  4700   QDictIterator<RefList> di(*Doxygen::xrefLists);
       
  4701   RefList *rl;
       
  4702   for (di.toFirst();(rl=di.current());++di)
       
  4703   {
       
  4704     rl->generatePage();
       
  4705   }
       
  4706 }
       
  4707 
       
  4708 //----------------------------------------------------------------------
       
  4709 // Copy the documentation in entry `root' to member definition `md' and
       
  4710 // set the function declaration of the member to `funcDecl'. If the boolean 
       
  4711 // over_load is set the standard overload text is added. 
       
  4712 
       
  4713 static void addMemberDocs(EntryNav *rootNav,
       
  4714                    MemberDef *md, const char *funcDecl,
       
  4715                    ArgumentList *al,
       
  4716                    bool over_load,
       
  4717                    NamespaceSDict *
       
  4718                   )
       
  4719 {
       
  4720   Entry *root = rootNav->entry();
       
  4721   //printf("addMemberDocs: `%s'::`%s' `%s' funcDecl=`%s' mSpec=%d\n",
       
  4722   //     root->parent->name.data(),md->name().data(),md->argsString(),funcDecl,root->spec);
       
  4723   QCString fDecl=funcDecl;
       
  4724   // strip extern specifier
       
  4725   fDecl.stripPrefix("extern ");
       
  4726   md->setDefinition(fDecl);
       
  4727   md->enableCallGraph(root->callGraph);
       
  4728   md->enableCallerGraph(root->callerGraph);
       
  4729   ClassDef     *cd=md->getClassDef();
       
  4730   NamespaceDef *nd=md->getNamespaceDef();
       
  4731   QCString fullName;
       
  4732   if (cd) 
       
  4733     fullName = cd->name();
       
  4734   else if (nd) 
       
  4735     fullName = nd->name();
       
  4736 
       
  4737   if (!fullName.isEmpty()) fullName+="::";
       
  4738   fullName+=md->name();
       
  4739   FileDef *rfd=rootNav->fileDef();
       
  4740 
       
  4741   // TODO determine scope based on root not md
       
  4742   Definition *rscope = md->getOuterScope();
       
  4743 
       
  4744   LockingPtr<ArgumentList> mdAl = md->argumentList();
       
  4745   if (al)
       
  4746   {
       
  4747     //printf("merging arguments (1) docs=%d\n",root->doc.isEmpty());
       
  4748     mergeArguments(mdAl.pointer(),al,!root->doc.isEmpty());
       
  4749   }
       
  4750   else
       
  4751   {
       
  4752     if ( 
       
  4753           matchArguments2( md->getOuterScope(), md->getFileDef(), mdAl.pointer(),
       
  4754                            rscope,rfd,root->argList,
       
  4755                            TRUE
       
  4756                          )
       
  4757        ) 
       
  4758     {
       
  4759       //printf("merging arguments (2)\n");
       
  4760       mergeArguments(mdAl.pointer(),root->argList,!root->doc.isEmpty());
       
  4761     }
       
  4762   }
       
  4763   if (over_load)  // the \overload keyword was used
       
  4764   {
       
  4765     QCString doc=getOverloadDocs();
       
  4766     if (!root->doc.isEmpty())
       
  4767     {
       
  4768       doc+="<p>";
       
  4769       doc+=root->doc;
       
  4770     }
       
  4771     md->setDocumentation(doc,root->docFile,root->docLine); 
       
  4772     md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
       
  4773     md->setDocsForDefinition(!root->proto);
       
  4774   }
       
  4775   else  
       
  4776   {
       
  4777     //printf("overwrite!\n");
       
  4778     md->setDocumentation(root->doc,root->docFile,root->docLine);
       
  4779     md->setDocsForDefinition(!root->proto);
       
  4780 
       
  4781     //printf("overwrite!\n");
       
  4782     md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
       
  4783 
       
  4784     if (
       
  4785         (md->inbodyDocumentation().isEmpty() ||
       
  4786          !rootNav->parent()->name().isEmpty()
       
  4787         ) && !root->inbodyDocs.isEmpty()
       
  4788        )
       
  4789     {
       
  4790       md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
       
  4791     }
       
  4792   }
       
  4793 
       
  4794   //printf("initializer: '%s'(isEmpty=%d) '%s'(isEmpty=%d)\n",
       
  4795   //    md->initializer().data(),md->initializer().isEmpty(),
       
  4796   //    root->initializer.data(),root->initializer.isEmpty()
       
  4797   //   );
       
  4798   if (md->initializer().isEmpty() && !root->initializer.isEmpty())
       
  4799   {
       
  4800     //printf("setInitializer\n");
       
  4801     md->setInitializer(root->initializer);
       
  4802   }
       
  4803 
       
  4804   md->setMaxInitLines(root->initLines);
       
  4805 
       
  4806   if (rfd)
       
  4807   {
       
  4808     if ((md->getStartBodyLine()==-1 && root->bodyLine!=-1) 
       
  4809        )
       
  4810     {
       
  4811       //printf("Setting new body segment [%d,%d]\n",root->bodyLine,root->endBodyLine);
       
  4812       md->setBodySegment(root->bodyLine,root->endBodyLine);
       
  4813       md->setBodyDef(rfd);
       
  4814     }
       
  4815 
       
  4816     md->setRefItems(root->sli);
       
  4817   }
       
  4818 
       
  4819   md->enableCallGraph(md->hasCallGraph() || root->callGraph);
       
  4820   md->enableCallerGraph(md->hasCallerGraph() || root->callerGraph);
       
  4821 
       
  4822   md->mergeMemberSpecifiers(root->spec);
       
  4823   md->addSectionsToDefinition(root->anchors);
       
  4824   addMemberToGroups(root,md);
       
  4825   if (cd) cd->insertUsedFile(root->fileName);
       
  4826   //printf("root->mGrpId=%d\n",root->mGrpId);
       
  4827   if (root->mGrpId!=-1)
       
  4828   {
       
  4829     if (md->getMemberGroupId()!=-1)
       
  4830     {
       
  4831       if (md->getMemberGroupId()!=root->mGrpId)
       
  4832       {
       
  4833         warn(
       
  4834              root->fileName,root->startLine,
       
  4835              "Warning: member %s belongs to two different groups. The second "
       
  4836              "one found here will be ignored.",
       
  4837              md->name().data()
       
  4838             );
       
  4839       }
       
  4840     }
       
  4841     else // set group id
       
  4842     {
       
  4843       //printf("setMemberGroupId=%d md=%s\n",root->mGrpId,md->name().data());
       
  4844       md->setMemberGroupId(root->mGrpId);
       
  4845     }
       
  4846   }
       
  4847 }
       
  4848 
       
  4849 //----------------------------------------------------------------------
       
  4850 // find a class definition given the scope name and (optionally) a 
       
  4851 // template list specifier
       
  4852 
       
  4853 static ClassDef *findClassDefinition(FileDef *fd,NamespaceDef *nd,
       
  4854                          const char *scopeName)
       
  4855 {
       
  4856   ClassDef *tcd = getResolvedClass(nd,fd,scopeName,0,0,TRUE,TRUE);
       
  4857   return tcd;
       
  4858 }
       
  4859 
       
  4860 
       
  4861 //----------------------------------------------------------------------
       
  4862 // Adds the documentation contained in `root' to a global function
       
  4863 // with name `name' and argument list `args' (for overloading) and
       
  4864 // function declaration `decl' to the corresponding member definition.
       
  4865 
       
  4866 static bool findGlobalMember(EntryNav *rootNav, 
       
  4867                            const QCString &namespaceName,
       
  4868                            const char *name, 
       
  4869                            const char *tempArg,
       
  4870                            const char *, 
       
  4871                            const char *decl)
       
  4872 {
       
  4873   Entry *root = rootNav->entry();
       
  4874   Debug::print(Debug::FindMembers,0,
       
  4875        "2. findGlobalMember(namespace=%s,name=%s,tempArg=%s,decl=%s)\n",
       
  4876           namespaceName.data(),name,tempArg,decl);
       
  4877   QCString n=name;
       
  4878   if (n.isEmpty()) return FALSE;
       
  4879   if (n.find("::")!=-1) return FALSE; // skip undefined class members
       
  4880   MemberName *mn=Doxygen::functionNameSDict->find(n+tempArg); // look in function dictionary
       
  4881   if (mn==0)
       
  4882   {
       
  4883     mn=Doxygen::functionNameSDict->find(n); // try without template arguments
       
  4884   }
       
  4885   if (mn) // function name defined
       
  4886   {
       
  4887     Debug::print(Debug::FindMembers,0,"3. Found function scope\n");
       
  4888     //int count=0;
       
  4889     MemberNameIterator mni(*mn);
       
  4890     MemberDef *md;
       
  4891     bool found=FALSE;
       
  4892     for (mni.toFirst();(md=mni.current()) && !found;++mni)
       
  4893     {
       
  4894       NamespaceDef *nd=md->getNamespaceDef();
       
  4895 
       
  4896       //printf("Namespace namespaceName=%s nd=%s\n",
       
  4897       //    namespaceName.data(),nd ? nd->name().data() : "<none>");
       
  4898 
       
  4899       FileDef *fd=rootNav->fileDef();
       
  4900       //printf("File %s\n",fd ? fd->name().data() : "<none>");
       
  4901       NamespaceSDict *nl = fd ? fd->getUsedNamespaces() : 0;
       
  4902       //SDict<Definition> *cl = fd ? fd->getUsedClasses()    : 0;
       
  4903       //printf("NamespaceList %p\n",nl);
       
  4904 
       
  4905       // search in the list of namespaces that are imported via a 
       
  4906       // using declaration
       
  4907       bool viaUsingDirective = nl && nd && nl->find(nd->qualifiedName())!=0;
       
  4908 
       
  4909       if ((namespaceName.isEmpty() && nd==0) ||  // not in a namespace
       
  4910           (nd && nd->name()==namespaceName) ||   // or in the same namespace 
       
  4911           viaUsingDirective                      // member in `using' namespace
       
  4912          )     
       
  4913       {
       
  4914         Debug::print(Debug::FindMembers,0,"4. Try to add member `%s' to scope `%s'\n",
       
  4915             md->name().data(),namespaceName.data());
       
  4916         QCString nsName = nd ? nd->name().data() : "";
       
  4917 
       
  4918         NamespaceDef *rnd = 0;
       
  4919         if (!namespaceName.isEmpty()) rnd = Doxygen::namespaceSDict->find(namespaceName);
       
  4920 
       
  4921         LockingPtr<ArgumentList> mdAl = md->argumentList();
       
  4922         bool matching=
       
  4923           (mdAl==0 && root->argList->count()==0) ||
       
  4924           md->isVariable() || md->isTypedef() || /* in case of function pointers */
       
  4925           matchArguments2(md->getOuterScope(),md->getFileDef(),mdAl.pointer(),
       
  4926                           rnd ? rnd : Doxygen::globalScope,fd,root->argList,
       
  4927                           FALSE);
       
  4928 
       
  4929         // for template members we need to check if the number of
       
  4930         // template arguments is the same, otherwise we are dealing with
       
  4931         // different functions.
       
  4932         if (matching && root->tArgLists)
       
  4933         {
       
  4934           LockingPtr<ArgumentList> mdTempl = md->templateArguments();
       
  4935           if (mdTempl!=0)
       
  4936           {
       
  4937             if (root->tArgLists->getLast()->count()!=mdTempl->count())
       
  4938             {
       
  4939               matching=FALSE;
       
  4940             }
       
  4941           }
       
  4942         }
       
  4943 
       
  4944 
       
  4945         //printf("%s<->%s\n",
       
  4946         //    argListToString(md->argumentList()).data(),
       
  4947         //    argListToString(root->argList).data());
       
  4948 
       
  4949         // for static members we also check if the comment block was found in 
       
  4950         // the same file. This is needed because static members with the same
       
  4951         // name can be in different files. Thus it would be wrong to just
       
  4952         // put the comment block at the first syntactically matching member.
       
  4953         if (matching && md->isStatic() && 
       
  4954             md->getDefFileName()!=root->fileName && 
       
  4955             mn->count()>1)
       
  4956         {
       
  4957           matching = FALSE;
       
  4958         }
       
  4959 
       
  4960         if (matching) // add docs to the member
       
  4961         {
       
  4962           Debug::print(Debug::FindMembers,0,"5. Match found\n");
       
  4963           addMemberDocs(rootNav,md,decl,root->argList,FALSE);
       
  4964           found=TRUE;
       
  4965         }
       
  4966       }
       
  4967     } 
       
  4968     if (!found && root->relatesType != Duplicate) // no match
       
  4969     {
       
  4970       QCString fullFuncDecl=decl;
       
  4971       if (root->argList) fullFuncDecl+=argListToString(root->argList,TRUE);
       
  4972       warn(root->fileName,root->startLine,
       
  4973            "Warning: no matching file member found for \n%s",fullFuncDecl.data());   
       
  4974       if (mn->count()>0)
       
  4975       {
       
  4976         warn_cont("Possible candidates:\n");
       
  4977         for (mni.toFirst();(md=mni.current());++mni)
       
  4978         {
       
  4979           warn_cont("  %s\n",md->declaration());
       
  4980         }
       
  4981       }
       
  4982     }
       
  4983   }
       
  4984   else // got docs for an undefined member!
       
  4985   {
       
  4986     if (root->type!="friend class" && 
       
  4987         root->type!="friend struct" &&
       
  4988         root->type!="friend union" &&
       
  4989         (!Config_getBool("TYPEDEF_HIDES_STRUCT") || 
       
  4990          root->type.find("typedef ")==-1)
       
  4991        )
       
  4992     {
       
  4993       warn(root->fileName,root->startLine,
       
  4994            "Warning: documented function `%s' was not declared or defined.",decl
       
  4995           );
       
  4996     }
       
  4997   }
       
  4998   return TRUE;
       
  4999 }
       
  5000 
       
  5001 static bool isSpecialization(
       
  5002                   const QList<ArgumentList> &srcTempArgLists,
       
  5003                   const QList<ArgumentList> &dstTempArgLists
       
  5004     )
       
  5005 {
       
  5006     QListIterator<ArgumentList> srclali(srcTempArgLists);
       
  5007     QListIterator<ArgumentList> dstlali(dstTempArgLists);
       
  5008     for (;srclali.current();++srclali,++dstlali)
       
  5009     {
       
  5010       ArgumentList *sal = srclali.current();
       
  5011       ArgumentList *dal = dstlali.current();
       
  5012       if (!(sal && dal && sal->count()==dal->count())) return TRUE;
       
  5013     }
       
  5014     return FALSE;
       
  5015 }
       
  5016 
       
  5017 
       
  5018 static QCString substituteTemplatesInString(
       
  5019     const QList<ArgumentList> &srcTempArgLists,
       
  5020     const QList<ArgumentList> &dstTempArgLists,
       
  5021     ArgumentList *funcTempArgList, // can be used to match template specializations
       
  5022     const QCString &src
       
  5023     )
       
  5024 {
       
  5025   QCString dst;
       
  5026   QRegExp re( "[A-Za-z_][A-Za-z_0-9]*");
       
  5027   //printf("type=%s\n",sa->type.data());
       
  5028   int i,p=0,l; 
       
  5029   while ((i=re.match(src,p,&l))!=-1) // for each word in srcType
       
  5030   {
       
  5031     bool found=FALSE;
       
  5032     dst+=src.mid(p,i-p);
       
  5033     QCString name=src.mid(i,l);
       
  5034 
       
  5035     QListIterator<ArgumentList> srclali(srcTempArgLists);
       
  5036     QListIterator<ArgumentList> dstlali(dstTempArgLists);
       
  5037     for (;srclali.current() && !found;++srclali,++dstlali)
       
  5038     {
       
  5039       ArgumentListIterator tsali(*srclali.current());
       
  5040       ArgumentListIterator tdali(*dstlali.current());
       
  5041       Argument *tsa =0,*tda=0, *fa=0;
       
  5042       if (funcTempArgList)
       
  5043       {
       
  5044         fa=funcTempArgList->first();
       
  5045       }
       
  5046 
       
  5047       for (tsali.toFirst();(tsa=tsali.current()) && !found;++tsali)
       
  5048       {
       
  5049         tda = tdali.current();
       
  5050         //if (tda) printf("tsa=%s|%s tda=%s|%s\n",
       
  5051         //    tsa->type.data(),tsa->name.data(),
       
  5052         //    tda->type.data(),tda->name.data());
       
  5053         if (name==tsa->name)
       
  5054         {
       
  5055           if (tda && tda->name.isEmpty())
       
  5056           {
       
  5057             int vc=0;
       
  5058             if (tda->type.left(6)=="class ") vc=6;
       
  5059             else if (tda->type.left(9)=="typename ") vc=9;
       
  5060             if (vc>0) // convert type=="class T" to type=="class" name=="T"
       
  5061             {
       
  5062               tda->name = tda->type.mid(vc);
       
  5063               tda->type = tda->type.left(vc-1);
       
  5064             }
       
  5065           }
       
  5066           if (tda && !tda->name.isEmpty())
       
  5067           {
       
  5068             name=tda->name; // substitute
       
  5069             found=TRUE;
       
  5070           }
       
  5071           else if (fa)
       
  5072           {
       
  5073             name=fa->type;
       
  5074             found=TRUE;
       
  5075           }
       
  5076         }
       
  5077         if (tda) 
       
  5078           ++tdali; 
       
  5079         else if (fa) 
       
  5080           fa=funcTempArgList->next();
       
  5081       }
       
  5082       //printf("   srcList='%s' dstList='%s faList='%s'\n",
       
  5083       //  argListToString(srclali.current()).data(),
       
  5084       //  argListToString(dstlali.current()).data(),
       
  5085       //  funcTempArgList ? argListToString(funcTempArgList).data() : "<none>");
       
  5086     }
       
  5087     dst+=name; 
       
  5088     p=i+l;
       
  5089   }
       
  5090   dst+=src.right(src.length()-p);
       
  5091   //printf("  substituteTemplatesInString(%s)=%s\n",
       
  5092   //    src.data(),dst.data());
       
  5093   return dst;
       
  5094 }
       
  5095 
       
  5096 static void substituteTemplatesInArgList(
       
  5097                   const QList<ArgumentList> &srcTempArgLists,
       
  5098                   const QList<ArgumentList> &dstTempArgLists,
       
  5099                   ArgumentList *src,
       
  5100                   ArgumentList *dst,
       
  5101                   ArgumentList *funcTempArgs = 0
       
  5102                  )
       
  5103 {
       
  5104   ArgumentListIterator sali(*src);
       
  5105   Argument *sa=0;
       
  5106   Argument *da=dst->first();
       
  5107 
       
  5108   for (sali.toFirst();(sa=sali.current());++sali) // for each member argument
       
  5109   {
       
  5110     QCString dstType = substituteTemplatesInString(
       
  5111                                   srcTempArgLists,dstTempArgLists,funcTempArgs,
       
  5112                                   sa->type);
       
  5113     QCString dstArray = substituteTemplatesInString(
       
  5114                                   srcTempArgLists,dstTempArgLists,funcTempArgs,
       
  5115                                   sa->array);
       
  5116     if (da==0)
       
  5117     {
       
  5118       da=new Argument(*sa);
       
  5119       dst->append(da);
       
  5120       da->type=dstType;
       
  5121       da->array=dstArray;
       
  5122       da=0;
       
  5123     }
       
  5124     else
       
  5125     {
       
  5126       da->type=dstType;
       
  5127       da->type=dstArray;
       
  5128       da=dst->next();
       
  5129     }
       
  5130   }
       
  5131   dst->constSpecifier    = src->constSpecifier;
       
  5132   dst->volatileSpecifier = src->volatileSpecifier;
       
  5133   dst->pureSpecifier     = src->pureSpecifier;
       
  5134   //printf("substituteTemplatesInArgList: replacing %s with %s\n",
       
  5135   //    argListToString(src).data(),argListToString(dst).data()
       
  5136   //    );
       
  5137 }
       
  5138 
       
  5139 
       
  5140 
       
  5141 /*! This function tries to find a member (in a documented class/file/namespace) 
       
  5142  * that corresponds to the function/variable declaration given in \a funcDecl.
       
  5143  *
       
  5144  * The boolean \a overloaded is used to specify whether or not a standard
       
  5145  * overload documentation line should be generated.
       
  5146  *
       
  5147  * The boolean \a isFunc is a hint that indicates that this is a function
       
  5148  * instead of a variable or typedef.
       
  5149  */
       
  5150 static void findMember(EntryNav *rootNav,
       
  5151                        QCString funcDecl,
       
  5152                        bool overloaded,
       
  5153                        bool isFunc
       
  5154                       )
       
  5155 {
       
  5156   Entry *root = rootNav->entry();
       
  5157 
       
  5158   Debug::print(Debug::FindMembers,0,
       
  5159                "findMember(root=%p,funcDecl=`%s',related=`%s',overload=%d,"
       
  5160                "isFunc=%d mGrpId=%d tArgList=%p (#=%d) "
       
  5161                "spec=%d isObjC=%d\n",
       
  5162                root,funcDecl.data(),root->relates.data(),overloaded,isFunc,root->mGrpId,
       
  5163                root->tArgLists,root->tArgLists ? root->tArgLists->count() : 0,
       
  5164                root->spec,root->objc
       
  5165               );
       
  5166 
       
  5167   QCString scopeName;
       
  5168   QCString className;
       
  5169   QCString namespaceName;
       
  5170   QCString funcType;
       
  5171   QCString funcName;
       
  5172   QCString funcArgs;
       
  5173   QCString funcTempList;
       
  5174   QCString exceptions;
       
  5175   QCString funcSpec;
       
  5176   bool isRelated=FALSE;
       
  5177   bool isMemberOf=FALSE;
       
  5178   bool isFriend=FALSE;
       
  5179   bool done;
       
  5180   do
       
  5181   {
       
  5182     done=TRUE;
       
  5183     if (funcDecl.stripPrefix("friend ")) // treat friends as related members
       
  5184     {
       
  5185       isFriend=TRUE;
       
  5186       done=FALSE;
       
  5187     }
       
  5188     if (funcDecl.stripPrefix("inline "))
       
  5189     {
       
  5190       root->spec|=Entry::Inline;
       
  5191       done=FALSE;
       
  5192     }
       
  5193     if (funcDecl.stripPrefix("explicit "))
       
  5194     {
       
  5195       root->spec|=Entry::Explicit;
       
  5196       done=FALSE;
       
  5197     }
       
  5198     if (funcDecl.stripPrefix("mutable "))
       
  5199     {
       
  5200       root->spec|=Entry::Mutable;
       
  5201       done=FALSE;
       
  5202     }
       
  5203     if (funcDecl.stripPrefix("virtual "))
       
  5204     {
       
  5205       done=FALSE;
       
  5206     }
       
  5207   } while (!done);
       
  5208 
       
  5209   // delete any ; from the function declaration
       
  5210   int sep;
       
  5211   while ((sep=funcDecl.find(';'))!=-1)
       
  5212   {
       
  5213     funcDecl=(funcDecl.left(sep)+funcDecl.right(funcDecl.length()-sep-1)).stripWhiteSpace();
       
  5214   }
       
  5215   
       
  5216   // make sure the first character is a space to simplify searching.
       
  5217   if (!funcDecl.isEmpty() && funcDecl[0]!=' ') funcDecl.prepend(" ");
       
  5218   
       
  5219   // remove some superfluous spaces
       
  5220   funcDecl= substitute(
       
  5221               substitute(
       
  5222                 substitute(funcDecl,"~ ","~"),
       
  5223                 ":: ","::"
       
  5224               ),
       
  5225               " ::","::"
       
  5226             ).stripWhiteSpace();
       
  5227   
       
  5228   //printf("funcDecl=`%s'\n",funcDecl.data());
       
  5229   if (isFriend && funcDecl.left(6)=="class ")
       
  5230   {
       
  5231     //printf("friend class\n");
       
  5232     funcDecl=funcDecl.right(funcDecl.length()-6);
       
  5233     funcName = funcDecl.copy();
       
  5234   }
       
  5235   else if (isFriend && funcDecl.left(7)=="struct ")
       
  5236   {
       
  5237     funcDecl=funcDecl.right(funcDecl.length()-7);
       
  5238     funcName = funcDecl.copy();
       
  5239   }
       
  5240   else
       
  5241   {
       
  5242     // extract information from the declarations
       
  5243     parseFuncDecl(funcDecl,root->objc,scopeName,funcType,funcName,
       
  5244                 funcArgs,funcTempList,exceptions
       
  5245                );
       
  5246   }
       
  5247   //printf("scopeName=`%s' funcType=`%s' funcName=`%s' funcArgs=`%s'\n",
       
  5248   //    scopeName.data(),funcType.data(),funcName.data(),funcArgs.data());
       
  5249 
       
  5250   // the class name can also be a namespace name, we decide this later.
       
  5251   // if a related class name is specified and the class name could
       
  5252   // not be derived from the function declaration, then use the
       
  5253   // related field.
       
  5254   //printf("scopeName=`%s' className=`%s' namespaceName=`%s'\n",
       
  5255   //    scopeName.data(),className.data(),namespaceName.data());
       
  5256   if (!root->relates.isEmpty()) 
       
  5257   {                             // related member, prefix user specified scope
       
  5258     isRelated=TRUE;
       
  5259     isMemberOf=(root->relatesType == MemberOf);
       
  5260     if (getClass(root->relates)==0 && !scopeName.isEmpty())
       
  5261     {
       
  5262       scopeName= mergeScopes(scopeName,root->relates);
       
  5263     }
       
  5264     else 
       
  5265     {
       
  5266       scopeName = root->relates;
       
  5267     }
       
  5268   }
       
  5269 
       
  5270   if (root->relates.isEmpty() && rootNav->parent() && 
       
  5271       ((rootNav->parent()->section()&Entry::SCOPE_MASK) ||
       
  5272        (rootNav->parent()->section()==Entry::OBJCIMPL_SEC)
       
  5273       ) &&
       
  5274       !rootNav->parent()->name().isEmpty()) // see if we can combine scopeName 
       
  5275                                      // with the scope in which it was found
       
  5276   {
       
  5277     QCString joinedName = rootNav->parent()->name()+"::"+scopeName;
       
  5278     if (!scopeName.isEmpty() && 
       
  5279         (getClass(joinedName) || Doxygen::namespaceSDict->find(joinedName)))
       
  5280     {
       
  5281       scopeName = joinedName;
       
  5282     }
       
  5283     else
       
  5284     {
       
  5285       scopeName = mergeScopes(rootNav->parent()->name(),scopeName);
       
  5286     }
       
  5287   }
       
  5288   else // see if we can prefix a namespace or class that is used from the file
       
  5289   {
       
  5290      FileDef *fd=rootNav->fileDef();
       
  5291      if (fd)
       
  5292      {
       
  5293        NamespaceSDict *fnl = fd->getUsedNamespaces();
       
  5294        if (fnl)
       
  5295        {
       
  5296          QCString joinedName;
       
  5297          NamespaceDef *fnd;
       
  5298          NamespaceSDict::Iterator nsdi(*fnl);
       
  5299          for (nsdi.toFirst();(fnd=nsdi.current());++nsdi)
       
  5300          {
       
  5301            joinedName = fnd->name()+"::"+scopeName;
       
  5302            if (Doxygen::namespaceSDict->find(joinedName))
       
  5303            {
       
  5304              scopeName=joinedName;
       
  5305              break;
       
  5306            }
       
  5307          }
       
  5308        }
       
  5309      }
       
  5310   }
       
  5311   scopeName=stripTemplateSpecifiersFromScope(
       
  5312       removeRedundantWhiteSpace(scopeName),FALSE,&funcSpec); 
       
  5313 
       
  5314   // funcSpec contains the last template specifiers of the given scope.
       
  5315   // If this method does not have any template arguments or they are 
       
  5316   // empty while funcSpec is not empty we assume this is a 
       
  5317   // specialization of a method. If not, we clear the funcSpec and treat
       
  5318   // this as a normal method of a template class.
       
  5319   if (!(root->tArgLists && 
       
  5320         root->tArgLists->count()>0 &&
       
  5321         root->tArgLists->first()->count()==0
       
  5322        )
       
  5323      ) 
       
  5324   {
       
  5325     funcSpec.resize(0);
       
  5326   }
       
  5327   
       
  5328   // split scope into a namespace and a class part
       
  5329   extractNamespaceName(scopeName,className,namespaceName,TRUE);
       
  5330   //printf("scopeName=`%s' className=`%s' namespaceName=`%s'\n",
       
  5331   //       scopeName.data(),className.data(),namespaceName.data());
       
  5332   
       
  5333   //namespaceName=removeAnonymousScopes(namespaceName);
       
  5334   if (namespaceName.find('@')!=-1) return; // skip stuff in anonymous namespace...
       
  5335 
       
  5336   //printf("namespaceName=`%s' className=`%s'\n",namespaceName.data(),className.data());
       
  5337   // merge class and namespace scopes again
       
  5338   scopeName.resize(0);
       
  5339   if (!namespaceName.isEmpty())
       
  5340   {
       
  5341     if (className.isEmpty())
       
  5342     {
       
  5343       scopeName=namespaceName;
       
  5344     }
       
  5345     else if (!root->relates.isEmpty() || // relates command with explicit scope
       
  5346              !getClass(className)) // class name only exists in a namespace
       
  5347     {
       
  5348       scopeName=namespaceName+"::"+className;
       
  5349     }
       
  5350     else
       
  5351     {
       
  5352       scopeName=className;
       
  5353     }
       
  5354   }
       
  5355   else if (!className.isEmpty())
       
  5356   {
       
  5357     scopeName=className;
       
  5358   }
       
  5359   //printf("new scope=`%s'\n",scopeName.data());
       
  5360 
       
  5361   QCString tempScopeName=scopeName;
       
  5362   ClassDef *cd=getClass(scopeName);
       
  5363   if (cd)
       
  5364   {
       
  5365     if (root->tArgLists) root->tArgLists->first();
       
  5366     if (funcSpec.isEmpty())
       
  5367     {
       
  5368       tempScopeName=cd->qualifiedNameWithTemplateParameters(root->tArgLists);
       
  5369     }
       
  5370     else
       
  5371     {
       
  5372       tempScopeName=scopeName+funcSpec;
       
  5373     }
       
  5374   }
       
  5375   //printf("scopeName=%s cd=%p root->tArgLists=%p result=%s\n",
       
  5376   //    scopeName.data(),cd,root->tArgLists,tempScopeName.data());
       
  5377   
       
  5378   //printf("scopeName=`%s' className=`%s'\n",scopeName.data(),className.data());
       
  5379   // rebuild the function declaration (needed to get the scope right).
       
  5380   if (!scopeName.isEmpty() && !isRelated && !isFriend && !Config_getBool("HIDE_SCOPE_NAMES"))
       
  5381   {
       
  5382     if (!funcType.isEmpty())
       
  5383     {
       
  5384       if (isFunc) // a function -> we use argList for the arguments
       
  5385       {
       
  5386         funcDecl=funcType+" "+tempScopeName+"::"+funcName+funcTempList;
       
  5387       }
       
  5388       else
       
  5389       {
       
  5390         funcDecl=funcType+" "+tempScopeName+"::"+funcName+funcArgs;
       
  5391       }
       
  5392     }
       
  5393     else
       
  5394     {
       
  5395       if (isFunc) // a function => we use argList for the arguments
       
  5396       {
       
  5397         funcDecl=tempScopeName+"::"+funcName+funcTempList;
       
  5398       }
       
  5399       else // variable => add `argument' list
       
  5400       {
       
  5401         funcDecl=tempScopeName+"::"+funcName+funcArgs;
       
  5402       }
       
  5403     }
       
  5404   }
       
  5405   else // build declaration without scope
       
  5406   {
       
  5407     if (!funcType.isEmpty()) // but with a type
       
  5408     {
       
  5409       if (isFunc) // function => omit argument list
       
  5410       {
       
  5411         funcDecl=funcType+" "+funcName+funcTempList;
       
  5412       }
       
  5413       else // variable => add `argument' list
       
  5414       {
       
  5415         funcDecl=funcType+" "+funcName+funcArgs;
       
  5416       }
       
  5417     }
       
  5418     else // no type
       
  5419     {
       
  5420       if (isFunc)
       
  5421       {
       
  5422         funcDecl=funcName+funcTempList;
       
  5423       }
       
  5424       else
       
  5425       {
       
  5426         funcDecl=funcName+funcArgs;
       
  5427       }
       
  5428     }
       
  5429   }
       
  5430   
       
  5431   if (funcType=="template class" && !funcTempList.isEmpty())
       
  5432     return;   // ignore explicit template instantiations
       
  5433   
       
  5434   Debug::print(Debug::FindMembers,0,
       
  5435            "findMember() Parse results:\n"
       
  5436            "  namespaceName=`%s'\n"
       
  5437            "  className=`%s`\n"
       
  5438            "  funcType=`%s'\n"
       
  5439            "  funcSpec=`%s'\n"
       
  5440            "  funcName=`%s'\n"
       
  5441            "  funcArgs=`%s'\n"
       
  5442            "  funcTempList=`%s'\n"
       
  5443            "  funcDecl=`%s'\n"
       
  5444            "  related=`%s'\n" 
       
  5445            "  exceptions=`%s'\n"
       
  5446            "  isRelated=%d\n"
       
  5447            "  isMemberOf=%d\n"
       
  5448            "  isFriend=%d\n"
       
  5449            "  isFunc=%d\n\n",
       
  5450            namespaceName.data(),className.data(),
       
  5451            funcType.data(),funcSpec.data(),funcName.data(),funcArgs.data(),funcTempList.data(),
       
  5452            funcDecl.data(),root->relates.data(),exceptions.data(),isRelated,isMemberOf,isFriend,
       
  5453            isFunc
       
  5454           );
       
  5455 
       
  5456   MemberName *mn=0;
       
  5457   if (!funcName.isEmpty()) // function name is valid
       
  5458   { 
       
  5459     Debug::print(Debug::FindMembers,0,
       
  5460                  "1. funcName=`%s'\n",funcName.data());
       
  5461     if (funcName.left(9)=="operator ") // strip class scope from cast operator
       
  5462     {
       
  5463       funcName = substitute(funcName,className+"::","");
       
  5464     }
       
  5465     if (!funcTempList.isEmpty()) // try with member specialization
       
  5466     {
       
  5467       mn=Doxygen::memberNameSDict->find(funcName+funcTempList);
       
  5468     }
       
  5469     if (mn==0) // try without specialization
       
  5470     {
       
  5471       mn=Doxygen::memberNameSDict->find(funcName);
       
  5472     }
       
  5473     if (!isRelated && mn) // function name already found
       
  5474     {
       
  5475       Debug::print(Debug::FindMembers,0,
       
  5476                    "2. member name exists (%d members with this name)\n",mn->count());
       
  5477       if (!className.isEmpty()) // class name is valid
       
  5478       {
       
  5479         if (funcSpec.isEmpty()) // not a member specialization
       
  5480         {
       
  5481           int count=0;
       
  5482           int noMatchCount=0;
       
  5483           MemberNameIterator mni(*mn);
       
  5484           MemberDef *md;
       
  5485           bool memFound=FALSE;
       
  5486           for (mni.toFirst();!memFound && (md=mni.current());++mni)
       
  5487           {
       
  5488             ClassDef *cd=md->getClassDef();
       
  5489             Debug::print(Debug::FindMembers,0,
       
  5490                 "3. member definition found, "
       
  5491                 "scope needed=`%s' scope=`%s' args=`%s' fileName=%s\n",
       
  5492                 scopeName.data(),cd ? cd->name().data() : "<none>",
       
  5493                 md->argsString(),
       
  5494                 root->fileName.data());
       
  5495             //printf("Member %s (member scopeName=%s) (this scopeName=%s) classTempList=%s\n",md->name().data(),cd->name().data(),scopeName.data(),classTempList.data());
       
  5496             FileDef *fd=rootNav->fileDef();
       
  5497             NamespaceDef *nd=0;
       
  5498             if (!namespaceName.isEmpty()) nd=getResolvedNamespace(namespaceName);
       
  5499 
       
  5500             //printf("scopeName %s->%s\n",scopeName.data(),
       
  5501             //       stripTemplateSpecifiersFromScope(scopeName,FALSE).data());
       
  5502 
       
  5503             ClassDef *tcd=findClassDefinition(fd,nd,scopeName);
       
  5504             if (tcd==0 && stripAnonymousNamespaceScope(cd->name())==scopeName)
       
  5505             {
       
  5506               // don't be fooled by anonymous scopes
       
  5507               tcd=cd;
       
  5508             }
       
  5509             //printf("Looking for %s inside nd=%s result=%p (%s) cd=%p\n",
       
  5510             //    scopeName.data(),nd?nd->name().data():"<none>",tcd,tcd?tcd->name().data():"",cd);
       
  5511 
       
  5512             if (cd && tcd==cd) // member's classes match
       
  5513             {
       
  5514               Debug::print(Debug::FindMembers,0,
       
  5515                   "4. class definition %s found\n",cd->name().data());
       
  5516 
       
  5517               // get the template parameter lists found at the member declaration
       
  5518               QList<ArgumentList> declTemplArgs;
       
  5519               cd->getTemplateParameterLists(declTemplArgs);
       
  5520               LockingPtr<ArgumentList> templAl = md->templateArguments();
       
  5521               if (templAl!=0)
       
  5522               {
       
  5523                 declTemplArgs.append(templAl.pointer());
       
  5524               }
       
  5525 
       
  5526               // get the template parameter lists found at the member definition
       
  5527               QList<ArgumentList> *defTemplArgs = root->tArgLists;
       
  5528               //printf("defTemplArgs=%p\n",defTemplArgs);
       
  5529 
       
  5530               // do we replace the decl argument lists with the def argument lists?
       
  5531               bool substDone=FALSE;
       
  5532               ArgumentList *argList=0;
       
  5533 
       
  5534               /* substitute the occurrences of class template names in the 
       
  5535                * argument list before matching 
       
  5536                */
       
  5537               LockingPtr<ArgumentList> mdAl = md->argumentList();
       
  5538               if (declTemplArgs.count()>0 && defTemplArgs &&
       
  5539                   declTemplArgs.count()==defTemplArgs->count() &&
       
  5540                   mdAl.pointer()
       
  5541                  )
       
  5542               {
       
  5543                 /* the function definition has template arguments
       
  5544                  * and the class definition also has template arguments, so
       
  5545                  * we must substitute the template names of the class by that
       
  5546                  * of the function definition before matching.
       
  5547                  */
       
  5548                 argList = new ArgumentList;
       
  5549                 substituteTemplatesInArgList(declTemplArgs,*defTemplArgs,
       
  5550                     mdAl.pointer(),argList);
       
  5551 
       
  5552                 substDone=TRUE;
       
  5553               }
       
  5554               else /* no template arguments, compare argument lists directly */
       
  5555               {
       
  5556                 argList = mdAl.pointer();
       
  5557               }
       
  5558 
       
  5559               Debug::print(Debug::FindMembers,0,
       
  5560                   "5. matching `%s'<=>`%s' className=%s namespaceName=%s\n",
       
  5561                   argListToString(argList,TRUE).data(),argListToString(root->argList,TRUE).data(),
       
  5562                   className.data(),namespaceName.data()
       
  5563                   );
       
  5564 
       
  5565               bool matching=
       
  5566                 md->isVariable() || md->isTypedef() || // needed for function pointers
       
  5567                 (mdAl.pointer()==0 && root->argList->count()==0) || 
       
  5568                 matchArguments2(
       
  5569                     md->getClassDef(),md->getFileDef(),argList, 
       
  5570                     cd,fd,root->argList,
       
  5571                     TRUE);
       
  5572 
       
  5573               Debug::print(Debug::FindMembers,0,
       
  5574                   "6. match results of matchArguments2 = %d\n",matching);
       
  5575 
       
  5576               if (substDone) // found a new argument list
       
  5577               {
       
  5578                 if (matching) // replace member's argument list
       
  5579                 {
       
  5580                   md->setDefinitionTemplateParameterLists(root->tArgLists);
       
  5581                   md->setArgumentList(argList); // new owner of the list => no delete
       
  5582                 }
       
  5583                 else // no match 
       
  5584                 {
       
  5585                   if (!funcTempList.isEmpty() && 
       
  5586                       isSpecialization(declTemplArgs,*defTemplArgs))
       
  5587                   {
       
  5588                     // check if we are dealing with a partial template
       
  5589                     // specialization. In this case we add it to the class
       
  5590                     // even though the member arguments do not match.
       
  5591                     
       
  5592                     // TODO: copy other aspects?
       
  5593                     root->protection=md->protection(); // copy protection level
       
  5594                     addMethodToClass(rootNav,cd,md->name(),isFriend);
       
  5595                     return;
       
  5596                   }
       
  5597                   delete argList;
       
  5598                 }
       
  5599               }
       
  5600               if (matching) 
       
  5601               {
       
  5602                 addMemberDocs(rootNav,md,funcDecl,0,overloaded,0/* TODO */);
       
  5603                 count++;
       
  5604                 memFound=TRUE;
       
  5605               }
       
  5606             } 
       
  5607             else if (cd && cd!=tcd) // we did find a class with the same name as cd
       
  5608                                     // but in a different namespace
       
  5609             {
       
  5610               noMatchCount++;
       
  5611             }
       
  5612           } 
       
  5613           if (count==0 && rootNav->parent() && 
       
  5614               rootNav->parent()->section()==Entry::OBJCIMPL_SEC)
       
  5615           {
       
  5616             goto localObjCMethod;
       
  5617           }
       
  5618           if (count==0 && !(isFriend && funcType=="class"))
       
  5619           {
       
  5620             int candidates=0;
       
  5621             if (mn->count()>0)
       
  5622             {
       
  5623               //printf("Assume template class\n");
       
  5624               for (mni.toFirst();(md=mni.current());++mni)
       
  5625               {
       
  5626                 ClassDef *cd=md->getClassDef();
       
  5627                 //printf("cd->name()==%s className=%s\n",cd->name().data(),className.data());
       
  5628                 if (cd!=0 && rightScopeMatch(cd->name(),className)) 
       
  5629                 {
       
  5630                   LockingPtr<ArgumentList> templAl = md->templateArguments();
       
  5631                   if (root->tArgLists && templAl!=0 &&
       
  5632                       root->tArgLists->getLast()->count()<=templAl->count())
       
  5633                   { 
       
  5634                     addMethodToClass(rootNav,cd,md->name(),isFriend);
       
  5635                     return;
       
  5636                   }
       
  5637                   candidates++;
       
  5638                 }
       
  5639               }
       
  5640             }
       
  5641 
       
  5642             warn(root->fileName,root->startLine,
       
  5643                 "Warning: no %smatching class member found for",
       
  5644                 noMatchCount>1 ? "uniquely " : ""
       
  5645                 );   
       
  5646 
       
  5647             if (root->tArgLists)
       
  5648             {
       
  5649               QListIterator<ArgumentList> alli(*root->tArgLists);
       
  5650               ArgumentList *al;
       
  5651               for (;(al=alli.current());++alli)
       
  5652               {
       
  5653                 warn_cont("  template %s\n",tempArgListToString(al).data());
       
  5654               }
       
  5655             }
       
  5656             QCString fullFuncDecl=funcDecl.copy();
       
  5657             if (isFunc) fullFuncDecl+=argListToString(root->argList,TRUE);
       
  5658 
       
  5659             warn_cont("  %s\n",fullFuncDecl.data());
       
  5660 
       
  5661             if (candidates>0)
       
  5662             {
       
  5663               warn_cont("Possible candidates:\n");
       
  5664               for (mni.toFirst();(md=mni.current());++mni)
       
  5665               {
       
  5666                 ClassDef *cd=md->getClassDef();
       
  5667                 if (cd!=0 && rightScopeMatch(cd->name(),className))
       
  5668                 {
       
  5669                   LockingPtr<ArgumentList> templAl = md->templateArguments();
       
  5670                   if (templAl!=0)
       
  5671                   {
       
  5672                     warn_cont("  template %s\n",tempArgListToString(templAl.pointer()).data());
       
  5673                   }
       
  5674                   warn_cont("  ");
       
  5675                   if (md->typeString()) 
       
  5676                   {
       
  5677                     warn_cont("%s ",md->typeString());
       
  5678                   }
       
  5679                   QCString qScope = cd->qualifiedNameWithTemplateParameters();
       
  5680                   if (!qScope.isEmpty()) warn_cont("%s::%s",qScope.data(),md->name().data());
       
  5681                   if (md->argsString()) warn_cont("%s",md->argsString());
       
  5682                   if (noMatchCount>1) warn_cont(" at line %d of file %s",md->getDefLine(),md->getDefFileName().data());
       
  5683                   warn_cont("\n");
       
  5684                 }
       
  5685               }
       
  5686             }
       
  5687           }
       
  5688         }
       
  5689         else if (cd) // member specialization
       
  5690         {
       
  5691           MemberDef::MemberType mtype=MemberDef::Function;
       
  5692           ArgumentList *tArgList = new ArgumentList;
       
  5693           //  getTemplateArgumentsFromName(cd->name()+"::"+funcName,root->tArgLists);
       
  5694           MemberDef *md=new MemberDef(
       
  5695               root->fileName,root->startLine,
       
  5696               funcType,funcName,funcArgs,exceptions,
       
  5697               root->protection,root->virt,root->stat,Member,
       
  5698               mtype,tArgList,root->argList);
       
  5699           //printf("new specialized member %s args=`%s'\n",md->name().data(),funcArgs.data());
       
  5700           md->setTagInfo(rootNav->tagInfo());
       
  5701           md->setMemberClass(cd);
       
  5702           md->setTemplateSpecialization(TRUE);
       
  5703           md->setTypeConstraints(root->typeConstr);
       
  5704           md->setDefinition(funcDecl);
       
  5705           md->enableCallGraph(root->callGraph);
       
  5706           md->enableCallerGraph(root->callerGraph);
       
  5707           md->setDocumentation(root->doc,root->docFile,root->docLine);
       
  5708           md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
       
  5709           md->setDocsForDefinition(!root->proto);
       
  5710           md->setPrototype(root->proto);
       
  5711           md->addSectionsToDefinition(root->anchors);
       
  5712           md->setBodySegment(root->bodyLine,root->endBodyLine);
       
  5713           FileDef *fd=rootNav->fileDef();
       
  5714           md->setBodyDef(fd);
       
  5715           md->setMemberSpecifiers(root->spec);
       
  5716           md->setMemberGroupId(root->mGrpId);
       
  5717           mn->append(md);
       
  5718           cd->insertMember(md);
       
  5719           md->setRefItems(root->sli);
       
  5720           delete tArgList;
       
  5721         }
       
  5722         else
       
  5723         {
       
  5724           //printf("*** Specialized member %s of unknown scope %s%s found!\n",
       
  5725           //        scopeName.data(),funcName.data(),funcArgs.data());
       
  5726         }
       
  5727       }
       
  5728       else if (overloaded) // check if the function belongs to only one class 
       
  5729       {
       
  5730         // for unique overloaded member we allow the class to be
       
  5731         // omitted, this is to be Qt compatable. Using this should 
       
  5732         // however be avoided, because it is error prone
       
  5733         MemberNameIterator mni(*mn);
       
  5734         MemberDef *md=mni.toFirst();
       
  5735         ASSERT(md);
       
  5736         ClassDef *cd=md->getClassDef();
       
  5737         ASSERT(cd);
       
  5738         QCString className=cd->name().copy();
       
  5739         ++mni;
       
  5740         bool unique=TRUE;
       
  5741         for (;(md=mni.current());++mni)
       
  5742         {
       
  5743           ClassDef *cd=md->getClassDef();
       
  5744           if (className!=cd->name()) unique=FALSE; 
       
  5745         } 
       
  5746         if (unique)
       
  5747         {
       
  5748           MemberDef::MemberType mtype;
       
  5749           if      (root->mtype==Signal)  mtype=MemberDef::Signal;
       
  5750           else if (root->mtype==Slot)    mtype=MemberDef::Slot;
       
  5751           else if (root->mtype==DCOP)    mtype=MemberDef::DCOP;
       
  5752           else                 mtype=MemberDef::Function;
       
  5753           
       
  5754           // new overloaded member function
       
  5755           ArgumentList *tArgList = 
       
  5756             getTemplateArgumentsFromName(cd->name()+"::"+funcName,root->tArgLists);
       
  5757           //printf("new related member %s args=`%s'\n",md->name().data(),funcArgs.data());
       
  5758           MemberDef *md=new MemberDef(
       
  5759               root->fileName,root->startLine,
       
  5760               funcType,funcName,funcArgs,exceptions,
       
  5761               root->protection,root->virt,root->stat,Related,
       
  5762               mtype,tArgList,root->argList);
       
  5763           md->setTagInfo(rootNav->tagInfo());
       
  5764           md->setTypeConstraints(root->typeConstr);
       
  5765           md->setMemberClass(cd);
       
  5766           md->setDefinition(funcDecl);
       
  5767           md->enableCallGraph(root->callGraph);
       
  5768           md->enableCallerGraph(root->callerGraph);
       
  5769           QCString doc=getOverloadDocs();
       
  5770           doc+="<p>";
       
  5771           doc+=root->doc;
       
  5772           md->setDocumentation(doc,root->docFile,root->docLine);
       
  5773           md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
       
  5774           md->setDocsForDefinition(!root->proto);
       
  5775           md->setPrototype(root->proto);
       
  5776           md->addSectionsToDefinition(root->anchors);
       
  5777           md->setBodySegment(root->bodyLine,root->endBodyLine);
       
  5778           FileDef *fd=rootNav->fileDef();
       
  5779           md->setBodyDef(fd);
       
  5780           md->setMemberSpecifiers(root->spec);
       
  5781           md->setMemberGroupId(root->mGrpId);
       
  5782           mn->append(md);
       
  5783           cd->insertMember(md);
       
  5784           cd->insertUsedFile(root->fileName);
       
  5785           md->setRefItems(root->sli);
       
  5786         }
       
  5787       }
       
  5788       else // unrelated function with the same name as a member
       
  5789       {
       
  5790         if (!findGlobalMember(rootNav,namespaceName,funcName,funcTempList,funcArgs,funcDecl))
       
  5791         {
       
  5792           QCString fullFuncDecl=funcDecl.copy();
       
  5793           if (isFunc) fullFuncDecl+=argListToString(root->argList,TRUE);
       
  5794           warn(root->fileName,root->startLine,
       
  5795                "Warning: Cannot determine class for function\n%s",
       
  5796                fullFuncDecl.data()
       
  5797               );   
       
  5798         }
       
  5799       }
       
  5800     }
       
  5801     else if (isRelated && !root->relates.isEmpty())
       
  5802     {
       
  5803       Debug::print(Debug::FindMembers,0,"2. related function\n"
       
  5804               "  scopeName=%s className=%s\n",scopeName.data(),className.data());
       
  5805       if (className.isEmpty()) className=root->relates;
       
  5806       ClassDef *cd;
       
  5807       //printf("scopeName=`%s' className=`%s'\n",scopeName.data(),className.data());
       
  5808       if ((cd=getClass(scopeName)))
       
  5809       {
       
  5810         bool newMember=TRUE; // assume we have a new member
       
  5811         bool newMemberName=FALSE; 
       
  5812         bool isDefine=FALSE;
       
  5813         {
       
  5814           MemberName *mn = Doxygen::functionNameSDict->find(funcName);
       
  5815           if (mn)
       
  5816           {
       
  5817             MemberDef *md = mn->first();
       
  5818             while (md && !isDefine)
       
  5819             {
       
  5820               isDefine = isDefine || md->isDefine();
       
  5821               md = mn->next();
       
  5822             }
       
  5823           }
       
  5824         }
       
  5825 
       
  5826         FileDef *fd=rootNav->fileDef();
       
  5827 
       
  5828         if ((mn=Doxygen::memberNameSDict->find(funcName))==0)
       
  5829         {
       
  5830           mn=new MemberName(funcName);
       
  5831           newMemberName=TRUE; // we create a new member name
       
  5832         }
       
  5833         else
       
  5834         {
       
  5835           MemberDef *rmd=mn->first();
       
  5836           while (rmd && newMember) // see if we got another member with matching arguments
       
  5837           {
       
  5838             LockingPtr<ArgumentList> rmdAl = rmd->argumentList();
       
  5839 
       
  5840             newMember=newMember && 
       
  5841               !matchArguments2(rmd->getOuterScope(),rmd->getFileDef(),rmdAl.pointer(),
       
  5842                                cd,fd,root->argList,
       
  5843                                TRUE);
       
  5844             if (newMember) rmd=mn->next();
       
  5845           }
       
  5846           if (!newMember && rmd) // member already exists as rmd -> add docs
       
  5847           {
       
  5848             //printf("addMemberDocs for related member %s\n",root->name.data());
       
  5849             //rmd->setMemberDefTemplateArguments(root->mtArgList);
       
  5850             addMemberDocs(rootNav,rmd,funcDecl,0,overloaded);
       
  5851           }
       
  5852         }
       
  5853 
       
  5854         if (newMember) // need to create a new member
       
  5855         {
       
  5856           MemberDef::MemberType mtype;
       
  5857           if (isDefine)
       
  5858             mtype=MemberDef::Define;
       
  5859           else if (root->mtype==Signal)  
       
  5860             mtype=MemberDef::Signal;
       
  5861           else if (root->mtype==Slot) 
       
  5862             mtype=MemberDef::Slot;
       
  5863           else if (root->mtype==DCOP)
       
  5864             mtype=MemberDef::DCOP;
       
  5865           else
       
  5866             mtype=MemberDef::Function;
       
  5867 
       
  5868           //printf("New related name `%s' `%d'\n",funcName.data(),
       
  5869           //    root->argList ? (int)root->argList->count() : -1);
       
  5870 
       
  5871           // new related (member) function
       
  5872 #if 0 // removed as it doesn't handle related template functions correctly
       
  5873           ArgumentList *tArgList = 
       
  5874             getTemplateArgumentsFromName(scopeName+"::"+funcName,root->tArgLists);
       
  5875           MemberDef *md=new MemberDef(
       
  5876               root->fileName,root->startLine,
       
  5877               funcType,funcName,funcArgs,exceptions,
       
  5878               root->protection,root->virt,root->stat,TRUE,
       
  5879               mtype,tArgList,funcArgs.isEmpty() ? 0 : root->argList);
       
  5880 #endif
       
  5881           // first note that we pass:
       
  5882           //   (root->tArgLists ? root->tArgLists->last() : 0)
       
  5883           // for the template arguments fo the new "member."
       
  5884           // this accurately reflects the template arguments of
       
  5885           // the related function, which don't have to do with
       
  5886           // those of the related class.
       
  5887           MemberDef *md=new MemberDef(
       
  5888               root->fileName,root->startLine,
       
  5889               funcType,funcName,funcArgs,exceptions,
       
  5890               root->protection,root->virt,
       
  5891               root->stat && !isMemberOf,
       
  5892               isMemberOf ? Foreign : isRelated ? Related : Member,
       
  5893               mtype,
       
  5894               (root->tArgLists ? root->tArgLists->last() : 0),
       
  5895               funcArgs.isEmpty() ? 0 : root->argList);
       
  5896           // 
       
  5897           // we still have the problem that
       
  5898           // MemberDef::writeDocumentation() in memberdef.cpp
       
  5899           // writes the template argument list for the class,
       
  5900           // as if this member is a member of the class.
       
  5901           // fortunately, MemberDef::writeDocumentation() has
       
  5902           // a special mechanism that allows us to totally
       
  5903           // override the set of template argument lists that
       
  5904           // are printed.  We use that and set it to the
       
  5905           // template argument lists of the related function.
       
  5906           //
       
  5907           md->setDefinitionTemplateParameterLists(root->tArgLists);
       
  5908 
       
  5909           md->setTagInfo(rootNav->tagInfo());
       
  5910 
       
  5911 
       
  5912 
       
  5913           //printf("Related member name=`%s' decl=`%s' bodyLine=`%d'\n",
       
  5914           //       funcName.data(),funcDecl.data(),root->bodyLine);
       
  5915 
       
  5916           // try to find the matching line number of the body from the
       
  5917           // global function list 
       
  5918           bool found=FALSE;
       
  5919           if (root->bodyLine==-1)
       
  5920           {
       
  5921             MemberName *rmn=Doxygen::functionNameSDict->find(funcName);
       
  5922             if (rmn)
       
  5923             {
       
  5924               MemberDef *rmd=rmn->first();
       
  5925               while (rmd && !found) // see if we got another member with matching arguments
       
  5926               {
       
  5927                 LockingPtr<ArgumentList> rmdAl = rmd->argumentList();
       
  5928                 // check for matching argument lists
       
  5929                 if (
       
  5930                     matchArguments2(rmd->getOuterScope(),rmd->getFileDef(),rmdAl.pointer(),
       
  5931                                     cd,fd,root->argList,
       
  5932                                     TRUE)
       
  5933                    )
       
  5934                 {
       
  5935                   found=TRUE;
       
  5936                 }
       
  5937                 if (!found) rmd=rmn->next();
       
  5938               }
       
  5939               if (rmd) // member found -> copy line number info
       
  5940               {
       
  5941                 md->setBodySegment(rmd->getStartBodyLine(),rmd->getEndBodyLine());
       
  5942                 md->setBodyDef(rmd->getBodyDef());
       
  5943                 //md->setBodyMember(rmd);
       
  5944               }
       
  5945             }
       
  5946           }
       
  5947           if (!found) // line number could not be found or is available in this
       
  5948                       // entry
       
  5949           {
       
  5950             md->setBodySegment(root->bodyLine,root->endBodyLine);
       
  5951             md->setBodyDef(fd);
       
  5952           }
       
  5953 
       
  5954           //if (root->mGrpId!=-1) 
       
  5955           //{
       
  5956           //  md->setMemberGroup(memberGroupDict[root->mGrpId]);
       
  5957           //}
       
  5958           md->setMemberClass(cd);
       
  5959           md->setMemberSpecifiers(root->spec);
       
  5960           md->setDefinition(funcDecl);
       
  5961           md->enableCallGraph(root->callGraph);
       
  5962           md->enableCallerGraph(root->callerGraph);
       
  5963           md->setDocumentation(root->doc,root->docFile,root->docLine);
       
  5964           md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
       
  5965           md->setDocsForDefinition(!root->proto);
       
  5966           md->setPrototype(root->proto);
       
  5967           md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
       
  5968           md->addSectionsToDefinition(root->anchors);
       
  5969           md->setMemberGroupId(root->mGrpId);
       
  5970           //md->setMemberDefTemplateArguments(root->mtArgList);
       
  5971           mn->append(md);
       
  5972           cd->insertMember(md);
       
  5973           cd->insertUsedFile(root->fileName);
       
  5974           md->setRefItems(root->sli);
       
  5975           if (root->relatesType == Duplicate) md->setRelatedAlso(cd);
       
  5976           addMemberToGroups(root,md);
       
  5977           //printf("Adding member=%s\n",md->name().data());
       
  5978           if (newMemberName)
       
  5979           {
       
  5980             //Doxygen::memberNameList.append(mn);
       
  5981             //Doxygen::memberNameDict.insert(funcName,mn);
       
  5982             Doxygen::memberNameSDict->append(funcName,mn);
       
  5983           }
       
  5984         }
       
  5985         if (root->relatesType == Duplicate)
       
  5986         {
       
  5987           if (!findGlobalMember(rootNav,namespaceName,funcName,funcTempList,funcArgs,funcDecl))
       
  5988           {
       
  5989             QCString fullFuncDecl=funcDecl.copy();
       
  5990             if (isFunc) fullFuncDecl+=argListToString(root->argList,TRUE);
       
  5991             warn(root->fileName,root->startLine,
       
  5992                "Warning: Cannot determine file/namespace for relatedalso function\n%s",
       
  5993                fullFuncDecl.data()
       
  5994               );   
       
  5995           }
       
  5996         }
       
  5997       }
       
  5998       else
       
  5999       {
       
  6000         warn_undoc(root->fileName,root->startLine,
       
  6001                    "Warning: class `%s' for related function `%s' is not "
       
  6002                    "documented.", 
       
  6003                    className.data(),funcName.data()
       
  6004                   );
       
  6005       }
       
  6006     }
       
  6007     else if (rootNav->parent() && rootNav->parent()->section()==Entry::OBJCIMPL_SEC)
       
  6008     {
       
  6009 localObjCMethod:
       
  6010       ClassDef *cd;
       
  6011       //printf("scopeName=`%s' className=`%s'\n",scopeName.data(),className.data());
       
  6012       if (Config_getBool("EXTRACT_LOCAL_METHODS") && (cd=getClass(scopeName)))
       
  6013       {
       
  6014         //printf("Local objective C method `%s' of class `%s' found\n",root->name.data(),cd->name().data());
       
  6015         MemberDef *md=new MemberDef(
       
  6016             root->fileName,root->startLine,
       
  6017             funcType,funcName,funcArgs,exceptions,
       
  6018             root->protection,root->virt,root->stat,Member,
       
  6019             MemberDef::Function,0,root->argList);
       
  6020         md->setTagInfo(rootNav->tagInfo());
       
  6021         md->makeImplementationDetail();
       
  6022         md->setMemberClass(cd);
       
  6023         md->setDefinition(funcDecl);
       
  6024         md->enableCallGraph(root->callGraph);
       
  6025         md->enableCallerGraph(root->callerGraph);
       
  6026         md->setDocumentation(root->doc,root->docFile,root->docLine);
       
  6027         md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
       
  6028         md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
       
  6029         md->setDocsForDefinition(!root->proto);
       
  6030         md->setPrototype(root->proto);
       
  6031         md->addSectionsToDefinition(root->anchors);
       
  6032         md->setBodySegment(root->bodyLine,root->endBodyLine);
       
  6033         FileDef *fd=rootNav->fileDef();
       
  6034         md->setBodyDef(fd);
       
  6035         md->setMemberSpecifiers(root->spec);
       
  6036         md->setMemberGroupId(root->mGrpId);
       
  6037         cd->insertMember(md);
       
  6038         cd->insertUsedFile(root->fileName);
       
  6039         md->setRefItems(root->sli);
       
  6040         if ((mn=Doxygen::memberNameSDict->find(root->name)))
       
  6041         {
       
  6042           mn->append(md);
       
  6043         }
       
  6044         else 
       
  6045         {
       
  6046           mn = new MemberName(root->name);
       
  6047           mn->append(md);
       
  6048           Doxygen::memberNameSDict->append(root->name,mn);
       
  6049         }
       
  6050       }
       
  6051       else
       
  6052       {
       
  6053         // local objective C method found for class without interface
       
  6054       }
       
  6055     }
       
  6056     else // unrelated not overloaded member found
       
  6057     {
       
  6058       bool globMem = findGlobalMember(rootNav,namespaceName,funcName,funcTempList,funcArgs,funcDecl);
       
  6059       if (className.isEmpty() && !globMem)
       
  6060       {
       
  6061         warn(root->fileName,root->startLine,
       
  6062              "Warning: class for member `%s' cannot "
       
  6063              "be found.", funcName.data()
       
  6064             ); 
       
  6065       }
       
  6066       else if (!className.isEmpty() && !globMem)
       
  6067       {
       
  6068         warn(root->fileName,root->startLine,
       
  6069              "Warning: member `%s' of class `%s' cannot be found",
       
  6070              funcName.data(),className.data());
       
  6071       }
       
  6072     }
       
  6073   }
       
  6074   else
       
  6075   {
       
  6076     // this should not be called
       
  6077     warn(root->fileName,root->startLine,
       
  6078          "Warning: member with no name found.");
       
  6079   }
       
  6080   return;
       
  6081 } 
       
  6082 
       
  6083 //----------------------------------------------------------------------
       
  6084 // find the members corresponding to the different documentation blocks
       
  6085 // that are extracted from the sources.
       
  6086 
       
  6087 static void filterMemberDocumentation(EntryNav *rootNav)
       
  6088 {
       
  6089   Entry *root = rootNav->entry();
       
  6090   int i=-1,l;
       
  6091   Debug::print(Debug::FindMembers,0,
       
  6092       "findMemberDocumentation(): root->type=`%s' root->inside=`%s' root->name=`%s' root->args=`%s' section=%x root->spec=%d root->mGrpId=%d\n",
       
  6093       root->type.data(),root->inside.data(),root->name.data(),root->args.data(),root->section,root->spec,root->mGrpId
       
  6094       );
       
  6095   //printf("rootNav->parent()->name()=%s\n",rootNav->parent()->name().data());
       
  6096   bool isFunc=TRUE;
       
  6097 
       
  6098   if (root->relatesType == Duplicate && !root->relates.isEmpty())
       
  6099   {
       
  6100     QCString tmp = root->relates;
       
  6101     root->relates.resize(0);
       
  6102     filterMemberDocumentation(rootNav);
       
  6103     root->relates = tmp;
       
  6104   }
       
  6105 
       
  6106   if ( // detect func variable/typedef to func ptr
       
  6107       (i=findFunctionPtr(root->type,&l))!=-1 
       
  6108      )
       
  6109   {
       
  6110     //printf("Fixing function pointer!\n");
       
  6111     // fix type and argument
       
  6112     root->args.prepend(root->type.right(root->type.length()-i-l));
       
  6113     root->type=root->type.left(i+l);
       
  6114     //printf("Results type=%s,name=%s,args=%s\n",root->type.data(),root->name.data(),root->args.data());
       
  6115     isFunc=FALSE;
       
  6116   }
       
  6117   else if ((root->type.left(8)=="typedef " && root->args.find('(')!=-1)) 
       
  6118     // detect function types marked as functions
       
  6119   {
       
  6120     isFunc=FALSE;
       
  6121   }
       
  6122 
       
  6123   //printf("Member %s isFunc=%d\n",root->name.data(),isFunc);
       
  6124   if (root->section==Entry::MEMBERDOC_SEC)
       
  6125   {
       
  6126     //printf("Documentation for inline member `%s' found args=`%s'\n",
       
  6127     //    root->name.data(),root->args.data());
       
  6128     //if (root->relates.length()) printf("  Relates %s\n",root->relates.data());
       
  6129     if (root->type.isEmpty())
       
  6130     {
       
  6131       findMember(rootNav,root->name+root->args+root->exception,FALSE,isFunc);
       
  6132     }
       
  6133     else
       
  6134     {
       
  6135       findMember(rootNav,root->type+" "+root->name+root->args+root->exception,FALSE,isFunc);
       
  6136     }
       
  6137   }
       
  6138   else if (root->section==Entry::OVERLOADDOC_SEC) 
       
  6139   {
       
  6140     //printf("Overloaded member %s found\n",root->name.data());
       
  6141     findMember(rootNav,root->name,TRUE,isFunc);
       
  6142   }
       
  6143   else if 
       
  6144     ((root->section==Entry::FUNCTION_SEC      // function
       
  6145       ||   
       
  6146       (root->section==Entry::VARIABLE_SEC &&  // variable
       
  6147        !root->type.isEmpty() &&                // with a type
       
  6148        g_compoundKeywordDict.find(root->type)==0 // that is not a keyword 
       
  6149        // (to skip forward declaration of class etc.)
       
  6150       )
       
  6151      ) 
       
  6152     )
       
  6153     {
       
  6154       //printf("Documentation for member `%s' found args=`%s' excp=`%s'\n",
       
  6155       //    root->name.data(),root->args.data(),root->exception.data());
       
  6156       //if (root->relates.length()) printf("  Relates %s\n",root->relates.data());
       
  6157       //printf("Inside=%s\n Relates=%s\n",root->inside.data(),root->relates.data());
       
  6158       if (root->type=="friend class" || root->type=="friend struct" || 
       
  6159           root->type=="friend union")
       
  6160       {
       
  6161         findMember(rootNav,
       
  6162             root->type+" "+
       
  6163             root->name,
       
  6164             FALSE,FALSE);
       
  6165 
       
  6166       }
       
  6167       else if (!root->type.isEmpty())
       
  6168       {
       
  6169         findMember(rootNav,
       
  6170             root->type+" "+
       
  6171             root->inside+
       
  6172             root->name+
       
  6173             root->args+
       
  6174             root->exception,
       
  6175             FALSE,isFunc);
       
  6176       }
       
  6177       else
       
  6178       {
       
  6179         findMember(rootNav,
       
  6180             root->inside+
       
  6181             root->name+
       
  6182             root->args+
       
  6183             root->exception,
       
  6184             FALSE,isFunc);
       
  6185       }
       
  6186     }
       
  6187   else if (root->section==Entry::DEFINE_SEC && !root->relates.isEmpty())
       
  6188   {
       
  6189     findMember(rootNav,root->name+root->args,FALSE,!root->args.isEmpty());
       
  6190   }
       
  6191   else if (root->section==Entry::VARIABLEDOC_SEC)
       
  6192   {
       
  6193     //printf("Documentation for variable %s found\n",root->name.data());
       
  6194     //if (!root->relates.isEmpty()) printf("  Relates %s\n",root->relates.data());
       
  6195     findMember(rootNav,root->name,FALSE,FALSE);
       
  6196   }
       
  6197   else
       
  6198   {
       
  6199     // skip section 
       
  6200     //printf("skip section\n");
       
  6201   }
       
  6202 }
       
  6203 
       
  6204 static void findMemberDocumentation(EntryNav *rootNav)
       
  6205 {
       
  6206   if (rootNav->section()==Entry::MEMBERDOC_SEC ||
       
  6207       rootNav->section()==Entry::OVERLOADDOC_SEC ||
       
  6208       rootNav->section()==Entry::FUNCTION_SEC ||
       
  6209       rootNav->section()==Entry::VARIABLE_SEC ||
       
  6210       rootNav->section()==Entry::VARIABLEDOC_SEC ||
       
  6211       rootNav->section()==Entry::DEFINE_SEC
       
  6212      )
       
  6213   {
       
  6214     rootNav->loadEntry(g_storage);
       
  6215 
       
  6216     filterMemberDocumentation(rootNav);
       
  6217 
       
  6218     rootNav->releaseEntry();
       
  6219   }
       
  6220   if (rootNav->children())
       
  6221   {
       
  6222     EntryNavListIterator eli(*rootNav->children());
       
  6223     EntryNav *e;
       
  6224     for (;(e=eli.current());++eli)
       
  6225     {
       
  6226       if (e->section()!=Entry::ENUM_SEC) findMemberDocumentation(e);
       
  6227     }
       
  6228   }
       
  6229 }
       
  6230 
       
  6231 //----------------------------------------------------------------------
       
  6232 
       
  6233 static void findObjCMethodDefinitions(EntryNav *rootNav)
       
  6234 {
       
  6235   if (rootNav->children())
       
  6236   {
       
  6237     EntryNavListIterator eli(*rootNav->children());
       
  6238     EntryNav *objCImplNav;
       
  6239     for (;(objCImplNav=eli.current());++eli)
       
  6240     {
       
  6241       if (objCImplNav->section()==Entry::OBJCIMPL_SEC && objCImplNav->children())
       
  6242       {
       
  6243         EntryNavListIterator seli(*objCImplNav->children());
       
  6244         EntryNav *objCMethodNav;
       
  6245         for (;(objCMethodNav=seli.current());++seli)
       
  6246         {
       
  6247           if (objCMethodNav->section()==Entry::FUNCTION_SEC)
       
  6248           {
       
  6249             objCMethodNav->loadEntry(g_storage);
       
  6250             Entry *objCMethod = objCMethodNav->entry();
       
  6251 
       
  6252             //Printf("  Found ObjC method definition %s\n",objCMethod->name.data());
       
  6253             findMember(objCMethodNav, objCMethod->type+" "+objCImplNav->name()+"::"+
       
  6254                        objCMethod->name+" "+objCMethod->args, FALSE,TRUE);
       
  6255             objCMethod->section=Entry::EMPTY_SEC;
       
  6256 
       
  6257             objCMethodNav->releaseEntry();
       
  6258           }
       
  6259         }
       
  6260       }
       
  6261     }
       
  6262   }
       
  6263 }
       
  6264 
       
  6265 //----------------------------------------------------------------------
       
  6266 // find and add the enumeration to their classes, namespaces or files
       
  6267 
       
  6268 static void findEnums(EntryNav *rootNav)
       
  6269 {
       
  6270   if (rootNav->section()==Entry::ENUM_SEC)
       
  6271     // non anonymous enumeration
       
  6272   {
       
  6273     rootNav->loadEntry(g_storage);
       
  6274     Entry *root = rootNav->entry();
       
  6275 
       
  6276     MemberDef      *md=0;
       
  6277     ClassDef       *cd=0;
       
  6278     FileDef        *fd=0;
       
  6279     NamespaceDef   *nd=0;
       
  6280     MemberNameSDict *mnsd=0;
       
  6281     bool isGlobal;
       
  6282     bool isRelated=FALSE;
       
  6283     bool isMemberOf=FALSE;
       
  6284     //printf("Found enum with name `%s' relates=%s\n",root->name.data(),root->relates.data());
       
  6285     int i;
       
  6286 
       
  6287     QCString name;
       
  6288     QCString scope;
       
  6289 
       
  6290     if ((i=root->name.findRev("::"))!=-1) // scope is specified
       
  6291     {
       
  6292       scope=root->name.left(i); // extract scope
       
  6293       name=root->name.right(root->name.length()-i-2); // extract name
       
  6294       if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope);
       
  6295     }
       
  6296     else // no scope, check the scope in which the docs where found
       
  6297     {
       
  6298       if (( rootNav->parent()->section() & Entry::SCOPE_MASK )
       
  6299           && !rootNav->parent()->name().isEmpty()
       
  6300          ) // found enum docs inside a compound
       
  6301       {
       
  6302         scope=rootNav->parent()->name();
       
  6303         if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope);
       
  6304       }
       
  6305       name=root->name;
       
  6306     }
       
  6307 
       
  6308     if (!root->relates.isEmpty()) 
       
  6309     {   // related member, prefix user specified scope
       
  6310       isRelated=TRUE;
       
  6311       isMemberOf=(root->relatesType == MemberOf);
       
  6312       if (getClass(root->relates)==0 && !scope.isEmpty())
       
  6313         scope=mergeScopes(scope,root->relates);
       
  6314       else 
       
  6315         scope=root->relates.copy();
       
  6316       if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope);
       
  6317     }
       
  6318 
       
  6319     if (cd && !name.isEmpty()) // found a enum inside a compound
       
  6320     {
       
  6321       //printf("Enum `%s'::`%s'\n",cd->name(),name.data());
       
  6322       fd=0;
       
  6323       mnsd=Doxygen::memberNameSDict;
       
  6324       isGlobal=FALSE;
       
  6325     }
       
  6326     else if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@') // found enum inside namespace
       
  6327     {
       
  6328       mnsd=Doxygen::functionNameSDict;
       
  6329       isGlobal=TRUE;
       
  6330     }
       
  6331     else // found a global enum
       
  6332     {
       
  6333       fd=rootNav->fileDef();
       
  6334       mnsd=Doxygen::functionNameSDict;
       
  6335       isGlobal=TRUE;
       
  6336     }
       
  6337 
       
  6338     if (!name.isEmpty())
       
  6339     {
       
  6340       // new enum type
       
  6341       md = new MemberDef(
       
  6342           root->fileName,root->startLine,
       
  6343           0,name,0,0,
       
  6344           root->protection,Normal,FALSE,
       
  6345           isMemberOf ? Foreign : isRelated ? Related : Member,
       
  6346           MemberDef::Enumeration,
       
  6347           0,0);
       
  6348       md->setTagInfo(rootNav->tagInfo());
       
  6349       if (!isGlobal) md->setMemberClass(cd); else md->setFileDef(fd);
       
  6350       md->setBodySegment(root->bodyLine,root->endBodyLine);
       
  6351       md->setBodyDef(rootNav->fileDef());
       
  6352       //printf("Enum %s definition at line %d of %s: protection=%d\n",
       
  6353       //    root->name.data(),root->bodyLine,root->fileName.data(),root->protection);
       
  6354       md->addSectionsToDefinition(root->anchors);
       
  6355       md->setMemberGroupId(root->mGrpId);
       
  6356       md->enableCallGraph(root->callGraph);
       
  6357       md->enableCallerGraph(root->callerGraph);
       
  6358       //printf("%s::setRefItems(%d)\n",md->name().data(),root->sli?root->sli->count():-1);
       
  6359       md->setRefItems(root->sli);
       
  6360       //printf("found enum %s nd=%p\n",name.data(),nd);
       
  6361       bool defSet=FALSE;
       
  6362       if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@')
       
  6363       {
       
  6364         if (isRelated || Config_getBool("HIDE_SCOPE_NAMES"))
       
  6365         {
       
  6366           md->setDefinition(name);  
       
  6367         }
       
  6368         else
       
  6369         {
       
  6370           md->setDefinition(nd->name()+"::"+name);  
       
  6371         }
       
  6372         //printf("definition=%s\n",md->definition());
       
  6373         defSet=TRUE;
       
  6374         md->setNamespace(nd);
       
  6375         nd->insertMember(md);
       
  6376       }
       
  6377 
       
  6378       // even if we have already added the enum to a namespace, we still
       
  6379       // also want to add it to other appropriate places such as file
       
  6380       // or class.
       
  6381       if (isGlobal)
       
  6382       {
       
  6383         if (!defSet) md->setDefinition(name);
       
  6384         if (fd==0 && rootNav->parent())
       
  6385         {
       
  6386           fd=rootNav->parent()->fileDef();
       
  6387         }
       
  6388         if (fd) 
       
  6389         {
       
  6390           md->setFileDef(fd);
       
  6391           fd->insertMember(md);
       
  6392         }
       
  6393       }
       
  6394       else if (cd)
       
  6395       {
       
  6396         if (isRelated || Config_getBool("HIDE_SCOPE_NAMES"))
       
  6397         {
       
  6398           md->setDefinition(name);  
       
  6399         }
       
  6400         else
       
  6401         {
       
  6402           md->setDefinition(cd->name()+"::"+name);  
       
  6403         }
       
  6404         cd->insertMember(md);
       
  6405         cd->insertUsedFile(root->fileName);
       
  6406       }
       
  6407       md->setDocumentation(root->doc,root->docFile,root->docLine);
       
  6408       md->setDocsForDefinition(!root->proto);
       
  6409       md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
       
  6410       md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
       
  6411 
       
  6412       //printf("Adding member=%s\n",md->name().data());
       
  6413       MemberName *mn;
       
  6414       if ((mn=(*mnsd)[name]))
       
  6415       {
       
  6416         // this is used if the same enum is in multiple namespaces/classes
       
  6417         mn->append(md);
       
  6418       }
       
  6419       else // new enum name
       
  6420       {
       
  6421         mn = new MemberName(name);
       
  6422         mn->append(md);
       
  6423         mnsd->append(name,mn);
       
  6424         //printf("add %s to new memberName. Now %d members\n",
       
  6425         //       name.data(),mn->count());
       
  6426       }
       
  6427       addMemberToGroups(root,md);
       
  6428 
       
  6429 #if 0
       
  6430       if (rootNav->children())
       
  6431       {
       
  6432         EntryNavListIterator eli(*rootNav->children());
       
  6433         EntryNav *e;
       
  6434         for (;(e=eli.current());++eli)
       
  6435         {
       
  6436           //printf("e->name=%s isRelated=%d\n",e->name.data(),isRelated);
       
  6437           MemberName *fmn=0;
       
  6438           MemberNameSDict *emnsd = isRelated ? Doxygen::functionNameSDict : mnsd;
       
  6439           if (!e->name().isEmpty() && (fmn=(*emnsd)[e->name()])) 
       
  6440             // get list of members with the same name as the field
       
  6441           {
       
  6442             MemberNameIterator fmni(*fmn);
       
  6443             MemberDef *fmd;
       
  6444             for (fmni.toFirst(); (fmd=fmni.current()) ; ++fmni) 
       
  6445             {
       
  6446               if (fmd->isEnumValue())
       
  6447               {
       
  6448                 //printf("found enum value with same name\n");
       
  6449                 if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@')
       
  6450                 {
       
  6451                   NamespaceDef *fnd=fmd->getNamespaceDef();
       
  6452                   if (fnd==nd) // enum value is inside a namespace
       
  6453                   {
       
  6454                     md->insertEnumField(fmd);
       
  6455                     fmd->setEnumScope(md);
       
  6456                   }
       
  6457                 }
       
  6458                 else if (isGlobal)
       
  6459                 {
       
  6460                   FileDef *ffd=fmd->getFileDef();
       
  6461                   if (ffd==fd) // enum value has file scope
       
  6462                   {
       
  6463                     md->insertEnumField(fmd);
       
  6464                     fmd->setEnumScope(md);
       
  6465                   }
       
  6466                 }
       
  6467                 else if (isRelated && cd) // reparent enum value to
       
  6468                   // match the enum's scope
       
  6469                 {
       
  6470                   md->insertEnumField(fmd);   // add field def to list
       
  6471                   fmd->setEnumScope(md);      // cross ref with enum name
       
  6472                   fmd->setEnumClassScope(cd); // cross ref with enum name
       
  6473                   fmd->setOuterScope(cd);
       
  6474                   fmd->makeRelated();
       
  6475                   cd->insertMember(fmd);
       
  6476                 }
       
  6477                 else
       
  6478                 {
       
  6479                   ClassDef *fcd=fmd->getClassDef();
       
  6480                   if (fcd==cd) // enum value is inside a class
       
  6481                   {
       
  6482                     //printf("Inserting enum field %s in enum scope %s\n",
       
  6483                     //    fmd->name().data(),md->name().data());
       
  6484                     md->insertEnumField(fmd); // add field def to list
       
  6485                     fmd->setEnumScope(md);    // cross ref with enum name
       
  6486                   }
       
  6487                 }
       
  6488               } 
       
  6489             }
       
  6490           }
       
  6491         }
       
  6492       }
       
  6493 #endif
       
  6494     }
       
  6495 
       
  6496     rootNav->releaseEntry();
       
  6497   }
       
  6498   else
       
  6499   {
       
  6500     RECURSE_ENTRYTREE(findEnums,rootNav);
       
  6501   }
       
  6502 }
       
  6503 
       
  6504 //----------------------------------------------------------------------
       
  6505 
       
  6506 static void addEnumValuesToEnums(EntryNav *rootNav)
       
  6507 {
       
  6508   if (rootNav->section()==Entry::ENUM_SEC)
       
  6509     // non anonymous enumeration
       
  6510   {
       
  6511     rootNav->loadEntry(g_storage);
       
  6512     Entry *root = rootNav->entry();
       
  6513 
       
  6514     ClassDef       *cd=0;
       
  6515     FileDef        *fd=0;
       
  6516     NamespaceDef   *nd=0;
       
  6517     MemberNameSDict *mnsd=0;
       
  6518     bool isGlobal;
       
  6519     bool isRelated=FALSE;
       
  6520     //printf("Found enum with name `%s' relates=%s\n",root->name.data(),root->relates.data());
       
  6521     int i;
       
  6522 
       
  6523     QCString name;
       
  6524     QCString scope;
       
  6525 
       
  6526     if ((i=root->name.findRev("::"))!=-1) // scope is specified
       
  6527     {
       
  6528       scope=root->name.left(i); // extract scope
       
  6529       name=root->name.right(root->name.length()-i-2); // extract name
       
  6530       if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope);
       
  6531     }
       
  6532     else // no scope, check the scope in which the docs where found
       
  6533     {
       
  6534       if (( rootNav->parent()->section() & Entry::SCOPE_MASK )
       
  6535           && !rootNav->parent()->name().isEmpty()
       
  6536          ) // found enum docs inside a compound
       
  6537       {
       
  6538         scope=rootNav->parent()->name();
       
  6539         if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope);
       
  6540       }
       
  6541       name=root->name;
       
  6542     }
       
  6543 
       
  6544     if (!root->relates.isEmpty()) 
       
  6545     {   // related member, prefix user specified scope
       
  6546       isRelated=TRUE;
       
  6547       if (getClass(root->relates)==0 && !scope.isEmpty())
       
  6548         scope=mergeScopes(scope,root->relates);
       
  6549       else 
       
  6550         scope=root->relates.copy();
       
  6551       if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope);
       
  6552     }
       
  6553 
       
  6554     if (cd && !name.isEmpty()) // found a enum inside a compound
       
  6555     {
       
  6556       //printf("Enum in class `%s'::`%s'\n",cd->name().data(),name.data());
       
  6557       fd=0;
       
  6558       mnsd=Doxygen::memberNameSDict;
       
  6559       isGlobal=FALSE;
       
  6560     }
       
  6561     else if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@') // found enum inside namespace
       
  6562     {
       
  6563       //printf("Enum in namespace `%s'::`%s'\n",nd->name().data(),name.data());
       
  6564       mnsd=Doxygen::functionNameSDict;
       
  6565       isGlobal=TRUE;
       
  6566     }
       
  6567     else // found a global enum
       
  6568     {
       
  6569       fd=rootNav->fileDef();
       
  6570       //printf("Enum in file `%s': `%s'\n",fd->name().data(),name.data());
       
  6571       mnsd=Doxygen::functionNameSDict;
       
  6572       isGlobal=TRUE;
       
  6573     }
       
  6574 
       
  6575     if (!name.isEmpty())
       
  6576     {
       
  6577       MemberName *mn = mnsd->find(name); // for all members with this name
       
  6578       if (mn)
       
  6579       {
       
  6580         MemberNameIterator mni(*mn);
       
  6581         MemberDef *md;
       
  6582         for (mni.toFirst(); (md=mni.current()) ; ++mni)  // for each enum in this list
       
  6583         {
       
  6584           if (md->isEnumerate() && rootNav->children())
       
  6585           {
       
  6586             EntryNavListIterator eli(*rootNav->children()); // for each enum value
       
  6587             EntryNav *e;
       
  6588             for (;(e=eli.current());++eli)
       
  6589             {
       
  6590               SrcLangExt sle;
       
  6591               if (rootNav->fileDef() &&
       
  6592                   ( (sle=getLanguageFromFileName(rootNav->fileDef()->name()))==SrcLangExt_CSharp
       
  6593                   || sle==SrcLangExt_Java || sle==SrcLangExt_XML
       
  6594                   )
       
  6595                  )
       
  6596               {
       
  6597                 // Unlike C++, for C# enum value are only inside the enum 
       
  6598                 // scope, so we must create them here and only add them to the
       
  6599                 // enum
       
  6600                 e->loadEntry(g_storage);
       
  6601                 Entry *root = e->entry();
       
  6602                 if (md->qualifiedName()==rootNav->name()) // enum value scope matches that of the enum
       
  6603                 {
       
  6604                   MemberDef *fmd=new MemberDef(
       
  6605                       root->fileName,root->startLine,
       
  6606                       root->type,root->name,root->args,0,
       
  6607                       Public, Normal,root->stat,Member,
       
  6608                       MemberDef::EnumValue,0,0);
       
  6609                   if (md->getClassDef()) fmd->setMemberClass(md->getClassDef());
       
  6610                   else if (md->getNamespaceDef()) fmd->setNamespace(md->getNamespaceDef());
       
  6611                   else if (md->getFileDef()) fmd->setFileDef(md->getFileDef());
       
  6612                   fmd->setOuterScope(md->getOuterScope());
       
  6613                   fmd->setTagInfo(e->tagInfo());
       
  6614                   fmd->setDocumentation(root->doc,root->docFile,root->docLine);
       
  6615                   fmd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
       
  6616                   fmd->addSectionsToDefinition(root->anchors);
       
  6617                   fmd->setInitializer(root->initializer);
       
  6618                   fmd->setMaxInitLines(root->initLines);
       
  6619                   fmd->setMemberGroupId(root->mGrpId);
       
  6620                   fmd->setExplicitExternal(root->explicitExternal);
       
  6621                   if (fmd)
       
  6622                   {
       
  6623                     md->insertEnumField(fmd);
       
  6624                     fmd->setEnumScope(md);
       
  6625                   }
       
  6626                 }
       
  6627                 e->releaseEntry();
       
  6628               }
       
  6629               else
       
  6630               {
       
  6631                 //printf("e->name=%s isRelated=%d\n",e->name().data(),isRelated);
       
  6632                 MemberName *fmn=0;
       
  6633                 MemberNameSDict *emnsd = isRelated ? Doxygen::functionNameSDict : mnsd;
       
  6634                 if (!e->name().isEmpty() && (fmn=(*emnsd)[e->name()])) 
       
  6635                   // get list of members with the same name as the field
       
  6636                 {
       
  6637                   MemberNameIterator fmni(*fmn);
       
  6638                   MemberDef *fmd;
       
  6639                   for (fmni.toFirst(); (fmd=fmni.current()) ; ++fmni) 
       
  6640                   {
       
  6641                     if (fmd->isEnumValue() && fmd->getOuterScope()==md->getOuterScope()) // in same scope
       
  6642                     {
       
  6643                       //printf("found enum value with same name %s in scope %s\n",
       
  6644                       //    fmd->name().data(),fmd->getOuterScope()->name().data());
       
  6645                       if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@')
       
  6646                       {
       
  6647                         NamespaceDef *fnd=fmd->getNamespaceDef();
       
  6648                         if (fnd==nd) // enum value is inside a namespace
       
  6649                         {
       
  6650                           md->insertEnumField(fmd);
       
  6651                           fmd->setEnumScope(md);
       
  6652                         }
       
  6653                       }
       
  6654                       else if (isGlobal)
       
  6655                       {
       
  6656                         FileDef *ffd=fmd->getFileDef();
       
  6657                         if (ffd==fd) // enum value has file scope
       
  6658                         {
       
  6659                           md->insertEnumField(fmd);
       
  6660                           fmd->setEnumScope(md);
       
  6661                         }
       
  6662                       }
       
  6663                       else if (isRelated && cd) // reparent enum value to
       
  6664                                                 // match the enum's scope
       
  6665                       {
       
  6666                         md->insertEnumField(fmd);   // add field def to list
       
  6667                         fmd->setEnumScope(md);      // cross ref with enum name
       
  6668                         fmd->setEnumClassScope(cd); // cross ref with enum name
       
  6669                         fmd->setOuterScope(cd);
       
  6670                         fmd->makeRelated();
       
  6671                         cd->insertMember(fmd);
       
  6672                       }
       
  6673                       else
       
  6674                       {
       
  6675                         ClassDef *fcd=fmd->getClassDef();
       
  6676                         if (fcd==cd) // enum value is inside a class
       
  6677                         {
       
  6678                           //printf("Inserting enum field %s in enum scope %s\n",
       
  6679                           //    fmd->name().data(),md->name().data());
       
  6680                           md->insertEnumField(fmd); // add field def to list
       
  6681                           fmd->setEnumScope(md);    // cross ref with enum name
       
  6682                         }
       
  6683                       }
       
  6684                     } 
       
  6685                   }
       
  6686                 }
       
  6687               }
       
  6688             }
       
  6689           }
       
  6690         }
       
  6691       }
       
  6692     }
       
  6693 
       
  6694     rootNav->releaseEntry();
       
  6695   }
       
  6696   else
       
  6697   {
       
  6698     RECURSE_ENTRYTREE(addEnumValuesToEnums,rootNav);
       
  6699   }
       
  6700 }
       
  6701 
       
  6702 
       
  6703 //----------------------------------------------------------------------
       
  6704 // find the documentation blocks for the enumerations
       
  6705 
       
  6706 static void findEnumDocumentation(EntryNav *rootNav)
       
  6707 {
       
  6708   if (rootNav->section()==Entry::ENUMDOC_SEC
       
  6709       && !rootNav->name().isEmpty()
       
  6710       && rootNav->name().at(0)!='@'        // skip anonymous enums
       
  6711      )
       
  6712   {
       
  6713     rootNav->loadEntry(g_storage);
       
  6714     Entry *root = rootNav->entry();
       
  6715 
       
  6716     //printf("Found docs for enum with name `%s' in context %s\n",
       
  6717     //    root->name.data(),root->parent->name.data());
       
  6718     int i;
       
  6719     QCString name;
       
  6720     QCString scope;
       
  6721     if ((i=root->name.findRev("::"))!=-1) // scope is specified as part of the name
       
  6722     {
       
  6723       name=root->name.right(root->name.length()-i-2); // extract name
       
  6724       scope=root->name.left(i); // extract scope
       
  6725       //printf("Scope=`%s' Name=`%s'\n",scope.data(),name.data());
       
  6726     }
       
  6727     else // just the name
       
  6728     {
       
  6729       name=root->name;
       
  6730     }
       
  6731     if (( rootNav->parent()->section() & Entry::SCOPE_MASK )
       
  6732         && !rootNav->parent()->name().isEmpty()
       
  6733        ) // found enum docs inside a compound
       
  6734     {
       
  6735       if (!scope.isEmpty()) scope.prepend("::");
       
  6736       scope.prepend(rootNav->parent()->name());
       
  6737     }
       
  6738     ClassDef *cd=getClass(scope);
       
  6739 
       
  6740     if (!name.isEmpty())
       
  6741     {
       
  6742       bool found=FALSE;
       
  6743       if (cd)
       
  6744       {
       
  6745         //printf("Enum: scope=`%s' name=`%s'\n",cd->name(),name.data());
       
  6746         QCString className=cd->name().copy();
       
  6747         MemberName *mn=Doxygen::memberNameSDict->find(name);
       
  6748         if (mn)
       
  6749         {
       
  6750           MemberNameIterator mni(*mn);
       
  6751           MemberDef *md;
       
  6752           for (mni.toFirst();(md=mni.current()) && !found;++mni)
       
  6753           {
       
  6754             ClassDef *cd=md->getClassDef();
       
  6755             if (cd && cd->name()==className && md->isEnumerate())
       
  6756             {
       
  6757               // documentation outside a compound overrides the documentation inside it
       
  6758 #if 0
       
  6759               if (!md->documentation() || rootNav->parent()->name().isEmpty()) 
       
  6760 #endif
       
  6761               {
       
  6762                 md->setDocumentation(root->doc,root->docFile,root->docLine);
       
  6763                 md->setDocsForDefinition(!root->proto);
       
  6764               }
       
  6765 
       
  6766               // brief descriptions inside a compound override the documentation 
       
  6767               // outside it
       
  6768 #if 0
       
  6769               if (!md->briefDescription() || !rootNav->parent()->name().isEmpty())
       
  6770 #endif
       
  6771               {
       
  6772                 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
       
  6773               }
       
  6774 
       
  6775               if (!md->inbodyDocumentation() || !rootNav->parent()->name().isEmpty())
       
  6776               {
       
  6777                 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
       
  6778               }
       
  6779 
       
  6780               if (root->mGrpId!=-1 && md->getMemberGroupId()==-1)
       
  6781               {
       
  6782                 md->setMemberGroupId(root->mGrpId);
       
  6783               }
       
  6784 
       
  6785               md->addSectionsToDefinition(root->anchors);
       
  6786               md->setRefItems(root->sli);
       
  6787 
       
  6788               GroupDef *gd=md->getGroupDef();
       
  6789               if (gd==0 &&root->groups->first()!=0) // member not grouped but out-of-line documentation is
       
  6790               {
       
  6791                 addMemberToGroups(root,md);
       
  6792               }
       
  6793 
       
  6794               found=TRUE;
       
  6795             }
       
  6796           }
       
  6797         }
       
  6798         else
       
  6799         {
       
  6800           //printf("MemberName %s not found!\n",name.data());
       
  6801         }
       
  6802       }
       
  6803       else // enum outside class 
       
  6804       {
       
  6805         //printf("Enum outside class: %s grpId=%d\n",name.data(),root->mGrpId);
       
  6806         MemberName *mn=Doxygen::functionNameSDict->find(name);
       
  6807         if (mn)
       
  6808         {
       
  6809           MemberNameIterator mni(*mn);
       
  6810           MemberDef *md;
       
  6811           for (mni.toFirst();(md=mni.current()) && !found;++mni)
       
  6812           {
       
  6813             if (md->isEnumerate())
       
  6814             {
       
  6815               md->setDocumentation(root->doc,root->docFile,root->docLine);
       
  6816               md->setDocsForDefinition(!root->proto);
       
  6817               md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
       
  6818               md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
       
  6819               md->addSectionsToDefinition(root->anchors);
       
  6820               md->setMemberGroupId(root->mGrpId);
       
  6821 
       
  6822               GroupDef *gd=md->getGroupDef();
       
  6823               if (gd==0 && root->groups->first()!=0) // member not grouped but out-of-line documentation is
       
  6824               {
       
  6825                 addMemberToGroups(root,md);
       
  6826               }
       
  6827 
       
  6828               found=TRUE;
       
  6829             }
       
  6830           }
       
  6831         }
       
  6832       } 
       
  6833       if (!found)
       
  6834       {
       
  6835         warn(root->fileName,root->startLine,
       
  6836              "Warning: Documentation for undefined enum `%s' found.",
       
  6837              name.data()
       
  6838             );
       
  6839       }
       
  6840     }
       
  6841 
       
  6842     rootNav->releaseEntry();
       
  6843   }
       
  6844   RECURSE_ENTRYTREE(findEnumDocumentation,rootNav);
       
  6845 }
       
  6846 
       
  6847 // seach for each enum (member or function) in mnl if it has documented 
       
  6848 // enum values.
       
  6849 static void findDEV(const MemberNameSDict &mnsd)
       
  6850 {
       
  6851   MemberName *mn;
       
  6852   MemberNameSDict::Iterator mnli(mnsd);
       
  6853   // for each member name
       
  6854   for (mnli.toFirst();(mn=mnli.current());++mnli)
       
  6855   {
       
  6856     MemberDef *md;
       
  6857     MemberNameIterator mni(*mn);
       
  6858     // for each member definition
       
  6859     for (mni.toFirst();(md=mni.current());++mni)
       
  6860     {
       
  6861       if (md->isEnumerate()) // member is an enum
       
  6862       {
       
  6863         LockingPtr<MemberList> fmdl = md->enumFieldList();
       
  6864         int documentedEnumValues=0;
       
  6865         if (fmdl!=0) // enum has values
       
  6866         {
       
  6867           MemberListIterator fmni(*fmdl);
       
  6868           MemberDef *fmd;
       
  6869           // for each enum value
       
  6870           for (fmni.toFirst();(fmd=fmni.current());++fmni)
       
  6871           {
       
  6872             if (fmd->isLinkableInProject()) documentedEnumValues++;
       
  6873           }
       
  6874         }
       
  6875         // at least one enum value is documented
       
  6876         if (documentedEnumValues>0) md->setDocumentedEnumValues(TRUE);
       
  6877       }
       
  6878     }
       
  6879   }
       
  6880 }
       
  6881 
       
  6882 // seach for each enum (member or function) if it has documented enum 
       
  6883 // values.
       
  6884 static void findDocumentedEnumValues()
       
  6885 {
       
  6886   findDEV(*Doxygen::memberNameSDict);
       
  6887   findDEV(*Doxygen::functionNameSDict); 
       
  6888 }
       
  6889 
       
  6890 //----------------------------------------------------------------------
       
  6891 
       
  6892 static void addMembersToIndex()
       
  6893 {
       
  6894   MemberName *mn;
       
  6895   MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
       
  6896   // for each member name
       
  6897   for (mnli.toFirst();(mn=mnli.current());++mnli)
       
  6898   {
       
  6899     MemberDef *md;
       
  6900     MemberNameIterator mni(*mn);
       
  6901     // for each member definition
       
  6902     for (mni.toFirst();(md=mni.current());++mni)
       
  6903     {
       
  6904       addClassMemberNameToIndex(md);
       
  6905     }
       
  6906   }
       
  6907   MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict);
       
  6908   // for each member name
       
  6909   for (fnli.toFirst();(mn=fnli.current());++fnli)
       
  6910   {
       
  6911     MemberDef *md;
       
  6912     MemberNameIterator mni(*mn);
       
  6913     // for each member definition
       
  6914     for (mni.toFirst();(md=mni.current());++mni)
       
  6915     {
       
  6916       if (md->getNamespaceDef())
       
  6917       {
       
  6918         addNamespaceMemberNameToIndex(md);
       
  6919       }
       
  6920       else
       
  6921       {
       
  6922         addFileMemberNameToIndex(md);
       
  6923       }
       
  6924     }
       
  6925   }
       
  6926 }
       
  6927 
       
  6928 //----------------------------------------------------------------------
       
  6929 // computes the relation between all members. For each member `m'
       
  6930 // the members that override the implementation of `m' are searched and
       
  6931 // the member that `m' overrides is searched.
       
  6932 
       
  6933 static void computeMemberRelations()
       
  6934 {
       
  6935   MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
       
  6936   MemberName *mn;
       
  6937   for ( ; (mn=mnli.current()) ; ++mnli ) // for each member name
       
  6938   {
       
  6939     MemberNameIterator mdi(*mn);
       
  6940     MemberDef *md;
       
  6941     for ( ; (md=mdi.current()) ; ++mdi ) // for each member with a specific name
       
  6942     {
       
  6943       MemberDef *bmd = mn->first(); // for each other member with the same name
       
  6944       while (bmd)
       
  6945       {
       
  6946         ClassDef *mcd  = md->getClassDef();
       
  6947         if (mcd && mcd->baseClasses())
       
  6948         {
       
  6949           ClassDef *bmcd = bmd->getClassDef();
       
  6950           //printf("Check relation between `%s'::`%s' (%p) and `%s'::`%s' (%p)\n",
       
  6951           //      mcd->name().data(),md->name().data(),md,
       
  6952           //       bmcd->name().data(),bmd->name().data(),bmd
       
  6953           //      );
       
  6954           if (md!=bmd && bmcd && mcd && bmcd!=mcd && mcd->isBaseClass(bmcd,TRUE))
       
  6955           {
       
  6956             LockingPtr<ArgumentList> bmdAl = bmd->argumentList();
       
  6957             LockingPtr<ArgumentList>  mdAl =  md->argumentList();
       
  6958             //printf(" Base argList=`%s'\n Super argList=`%s'\n",
       
  6959             //        argListToString(bmdAl.pointer()).data(),
       
  6960             //        argListToString(mdAl.pointer()).data()
       
  6961             //      );
       
  6962             if ( 
       
  6963                 matchArguments2(bmd->getOuterScope(),bmd->getFileDef(),bmdAl.pointer(),
       
  6964                   md->getOuterScope(), md->getFileDef(), mdAl.pointer(),
       
  6965                   TRUE
       
  6966                   ) 
       
  6967                )
       
  6968             {
       
  6969               //printf("  match found!\n");
       
  6970               if (mcd && bmcd && 
       
  6971                   mcd->isLinkable() && bmcd->isLinkable()
       
  6972                  )
       
  6973               {
       
  6974                 MemberDef *rmd;
       
  6975                 if ((rmd=md->reimplements())==0 ||
       
  6976                     minClassDistance(mcd,bmcd)<minClassDistance(mcd,rmd->getClassDef())
       
  6977                    )
       
  6978                 {
       
  6979                   //printf("setting (new) reimplements member\n");
       
  6980                   md->setReimplements(bmd);
       
  6981                 }
       
  6982                 //printf("%s: add reimplements member %s\n",mcd->name().data(),bmcd->name().data());
       
  6983                 //md->setImplements(bmd);
       
  6984                 //printf("%s: add reimplementedBy member %s\n",bmcd->name().data(),mcd->name().data());
       
  6985                 bmd->insertReimplementedBy(md);
       
  6986               }
       
  6987             }  
       
  6988           }
       
  6989         }
       
  6990         bmd = mn->next();
       
  6991       }
       
  6992     }
       
  6993   }  
       
  6994 }
       
  6995 
       
  6996 
       
  6997 //----------------------------------------------------------------------------
       
  6998 //static void computeClassImplUsageRelations()
       
  6999 //{
       
  7000 //  ClassDef *cd;
       
  7001 //  ClassSDict::Iterator cli(*Doxygen::classSDict);
       
  7002 //  for (;(cd=cli.current());++cli)
       
  7003 //  {
       
  7004 //    cd->determineImplUsageRelation();
       
  7005 //  }
       
  7006 //}
       
  7007 
       
  7008 //----------------------------------------------------------------------------
       
  7009 
       
  7010 static void createTemplateInstanceMembers()
       
  7011 {
       
  7012   ClassSDict::Iterator cli(*Doxygen::classSDict);
       
  7013   ClassDef *cd;
       
  7014   // for each class
       
  7015   for (cli.toFirst();(cd=cli.current());++cli)
       
  7016   {
       
  7017     // that is a template
       
  7018     QDict<ClassDef> *templInstances = cd->getTemplateInstances();
       
  7019     if (templInstances)
       
  7020     {
       
  7021       QDictIterator<ClassDef> qdi(*templInstances);
       
  7022       ClassDef *tcd=0;
       
  7023       // for each instance of the template
       
  7024       for (qdi.toFirst();(tcd=qdi.current());++qdi)
       
  7025       {
       
  7026         tcd->addMembersToTemplateInstance(cd,qdi.currentKey());
       
  7027       }
       
  7028     }
       
  7029   }
       
  7030 }
       
  7031 
       
  7032 //----------------------------------------------------------------------------
       
  7033 
       
  7034 // builds the list of all members for each class
       
  7035 
       
  7036 static void buildCompleteMemberLists()
       
  7037 {
       
  7038   ClassDef *cd;
       
  7039   // merge members of categories into the class they extend
       
  7040   ClassSDict::Iterator cli(*Doxygen::classSDict);
       
  7041   for (cli.toFirst();(cd=cli.current());++cli)
       
  7042   {
       
  7043     int i=cd->name().find('(');
       
  7044     if (i!=-1) // it is an Objective-C category
       
  7045     {
       
  7046       QCString baseName=cd->name().left(i);
       
  7047       ClassDef *baseClass=Doxygen::classSDict->find(baseName);
       
  7048       if (baseClass)
       
  7049       {
       
  7050         //printf("*** merging members of category %s into %s\n",
       
  7051         //    cd->name().data(),baseClass->name().data());
       
  7052         baseClass->mergeCategory(cd);
       
  7053       }
       
  7054     }
       
  7055   }
       
  7056   // merge the member list of base classes into the inherited classes.
       
  7057   for (cli.toFirst();(cd=cli.current());++cli)
       
  7058   {
       
  7059     if (// !cd->isReference() && // not an external class
       
  7060          cd->subClasses()==0 && // is a root of the hierarchy
       
  7061          cd->baseClasses()) // and has at least one base class
       
  7062     {
       
  7063       //printf("*** merging members for %s\n",cd->name().data());
       
  7064       cd->mergeMembers();
       
  7065     }
       
  7066   }
       
  7067   // now sort the member list of all classes.
       
  7068   for (cli.toFirst();(cd=cli.current());++cli)
       
  7069   {
       
  7070     if (cd->memberNameInfoSDict()) cd->memberNameInfoSDict()->sort();
       
  7071   }
       
  7072 }
       
  7073 
       
  7074 //----------------------------------------------------------------------------
       
  7075 
       
  7076 static void generateFileSources()
       
  7077 {
       
  7078   if (documentedHtmlFiles==0) return;
       
  7079   if (Doxygen::inputNameList->count()>0)
       
  7080   {
       
  7081     FileNameListIterator fnli(*Doxygen::inputNameList); 
       
  7082     FileName *fn;
       
  7083     for (;(fn=fnli.current());++fnli)
       
  7084     {
       
  7085       FileNameIterator fni(*fn);
       
  7086       FileDef *fd;
       
  7087       for (;(fd=fni.current());++fni)
       
  7088       {
       
  7089         if (fd->generateSourceFile()) // sources need to be shown in the output
       
  7090         {
       
  7091           msg("Generating code for file %s...\n",fd->docName().data());
       
  7092           fd->writeSource(*g_outputList);
       
  7093         }
       
  7094         else if (!fd->isReference() && Doxygen::parseSourcesNeeded)
       
  7095           // we needed to parse the sources even if we do not show them
       
  7096         {
       
  7097           msg("Parsing code for file %s...\n",fd->docName().data());
       
  7098           fd->parseSource();
       
  7099         }
       
  7100       }
       
  7101     }
       
  7102   }
       
  7103 }
       
  7104 
       
  7105 //----------------------------------------------------------------------------
       
  7106 
       
  7107 static void generateFileDocs()
       
  7108 {
       
  7109   if (documentedHtmlFiles==0) return;
       
  7110   
       
  7111   if (Doxygen::inputNameList->count()>0)
       
  7112   {
       
  7113     FileNameListIterator fnli(*Doxygen::inputNameList);
       
  7114     FileName *fn;
       
  7115     for (fnli.toFirst();(fn=fnli.current());++fnli)
       
  7116     {
       
  7117       FileNameIterator fni(*fn);
       
  7118       FileDef *fd;
       
  7119       for (fni.toFirst();(fd=fni.current());++fni)
       
  7120       {
       
  7121         bool doc = fd->isLinkableInProject();
       
  7122         if (doc)
       
  7123         {
       
  7124           msg("Generating docs for file %s...\n",fd->docName().data());
       
  7125           fd->writeDocumentation(*g_outputList);
       
  7126         }
       
  7127       }
       
  7128     }
       
  7129   }
       
  7130 }
       
  7131 
       
  7132 //----------------------------------------------------------------------------
       
  7133 
       
  7134 static void addSourceReferences()
       
  7135 {
       
  7136   // add source references for class definitions
       
  7137   ClassSDict::Iterator cli(*Doxygen::classSDict);
       
  7138   ClassDef *cd=0;
       
  7139   for (cli.toFirst();(cd=cli.current());++cli)
       
  7140   {
       
  7141     FileDef *fd=cd->getBodyDef();
       
  7142     if (fd && cd->isLinkableInProject() && cd->getStartBodyLine()!=-1)
       
  7143     {
       
  7144       fd->addSourceRef(cd->getStartBodyLine(),cd,0);
       
  7145     }
       
  7146   }
       
  7147   // add source references for namespace definitions
       
  7148   NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
       
  7149   NamespaceDef *nd=0;
       
  7150   for (nli.toFirst();(nd=nli.current());++nli)
       
  7151   {
       
  7152     FileDef *fd=nd->getBodyDef();
       
  7153     if (fd && nd->isLinkableInProject() && nd->getStartBodyLine()!=-1)
       
  7154     {
       
  7155       fd->addSourceRef(nd->getStartBodyLine(),nd,0);
       
  7156     }
       
  7157   }
       
  7158   
       
  7159   // add source references for member names
       
  7160   MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
       
  7161   MemberName *mn=0;
       
  7162   for (mnli.toFirst();(mn=mnli.current());++mnli)
       
  7163   {
       
  7164     MemberNameIterator mni(*mn);
       
  7165     MemberDef *md=0;
       
  7166     for (mni.toFirst();(md=mni.current());++mni)
       
  7167     {
       
  7168       //printf("class member %s\n",md->name().data());
       
  7169       FileDef *fd=md->getBodyDef();
       
  7170       if (fd && 
       
  7171           md->getStartBodyLine()!=-1 &&
       
  7172           md->isLinkableInProject() &&
       
  7173           (fd->generateSourceFile() || Doxygen::parseSourcesNeeded)
       
  7174          )
       
  7175       {
       
  7176         //printf("Found member `%s' in file `%s' at line `%d' def=%s\n",
       
  7177         //    md->name().data(),fd->name().data(),md->getStartBodyLine(),md->getOuterScope()->name().data()); 
       
  7178         fd->addSourceRef(md->getStartBodyLine(),md->getOuterScope(),md);
       
  7179       }
       
  7180     }
       
  7181   }
       
  7182   MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict);
       
  7183   for (fnli.toFirst();(mn=fnli.current());++fnli)
       
  7184   {
       
  7185     MemberNameIterator mni(*mn);
       
  7186     MemberDef *md=0;
       
  7187     for (mni.toFirst();(md=mni.current());++mni)
       
  7188     {
       
  7189       FileDef *fd=md->getBodyDef();
       
  7190       //printf("member %s body=[%d,%d] fd=%p link=%d parseSources=%d\n",
       
  7191       //    md->name().data(),
       
  7192       //    md->getStartBodyLine(),md->getEndBodyLine(),fd,
       
  7193       //    md->isLinkableInProject(),
       
  7194       //    Doxygen::parseSourcesNeeded);
       
  7195       if (fd && 
       
  7196           md->getStartBodyLine()!=-1 && 
       
  7197           md->isLinkableInProject() && 
       
  7198           (fd->generateSourceFile() || Doxygen::parseSourcesNeeded)
       
  7199          )
       
  7200       {
       
  7201         //printf("Found member `%s' in file `%s' at line `%d' def=%s\n",
       
  7202         //    md->name().data(),fd->name().data(),md->getStartBodyLine(),md->getOuterScope()->name().data()); 
       
  7203         fd->addSourceRef(md->getStartBodyLine(),md->getOuterScope(),md);
       
  7204       }  
       
  7205     }
       
  7206   }
       
  7207 }
       
  7208 
       
  7209 //----------------------------------------------------------------------------
       
  7210 // generate the documentation of all classes
       
  7211   
       
  7212 static void generateClassList(ClassSDict &classSDict)
       
  7213 {
       
  7214   ClassSDict::Iterator cli(classSDict);
       
  7215   for ( ; cli.current() ; ++cli )
       
  7216   {
       
  7217     ClassDef *cd=cli.current();
       
  7218    
       
  7219     //printf("cd=%s getOuterScope=%p global=%p\n",cd->name().data(),cd->getOuterScope(),Doxygen::globalScope);
       
  7220     if ((cd->getOuterScope()==0 || // <-- should not happen, but can if we read an old tag file
       
  7221          cd->getOuterScope()==Doxygen::globalScope // only look at global classes
       
  7222         ) && !cd->isHidden()
       
  7223        ) 
       
  7224     {
       
  7225       // skip external references, anonymous compounds and 
       
  7226       // template instances 
       
  7227       if ( cd->isLinkableInProject() && cd->templateMaster()==0)
       
  7228       {
       
  7229         msg("Generating docs for compound %s...\n",cd->name().data());
       
  7230 
       
  7231         cd->writeDocumentation(*g_outputList);
       
  7232         cd->writeMemberList(*g_outputList);
       
  7233       }
       
  7234       // even for undocumented classes, the inner classes can be documented.
       
  7235       cd->writeDocumentationForInnerClasses(*g_outputList);
       
  7236     }
       
  7237   }
       
  7238 }
       
  7239 
       
  7240 static void generateClassDocs()
       
  7241 {
       
  7242   // write the installdox script if necessary
       
  7243   if (Config_getBool("GENERATE_HTML") && 
       
  7244       (Config_getList("TAGFILES").count()>0 || 
       
  7245        Config_getBool("SEARCHENGINE")
       
  7246       )
       
  7247      ) 
       
  7248   {
       
  7249     writeInstallScript();
       
  7250   }
       
  7251   
       
  7252   msg("Generating annotated compound index...\n");
       
  7253   writeAnnotatedIndex(*g_outputList);
       
  7254 
       
  7255   //if (Config_getBool("ALPHABETICAL_INDEX"))
       
  7256   //{
       
  7257     msg("Generating alphabetical compound index...\n");
       
  7258     writeAlphabeticalIndex(*g_outputList);
       
  7259   //}
       
  7260 
       
  7261   msg("Generating hierarchical class index...\n");
       
  7262   writeHierarchicalIndex(*g_outputList);
       
  7263 
       
  7264   msg("Generating member index...\n");
       
  7265   writeClassMemberIndex(*g_outputList);
       
  7266 
       
  7267   if (Doxygen::exampleSDict->count()>0)
       
  7268   {
       
  7269     msg("Generating example index...\n");
       
  7270   }
       
  7271 
       
  7272   generateClassList(*Doxygen::classSDict);
       
  7273   generateClassList(*Doxygen::hiddenClasses);
       
  7274 }
       
  7275 
       
  7276 //----------------------------------------------------------------------------
       
  7277 
       
  7278 static void inheritDocumentation()
       
  7279 {
       
  7280   MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
       
  7281   MemberName *mn;
       
  7282   //int count=0;
       
  7283   for (;(mn=mnli.current());++mnli)
       
  7284   {
       
  7285     MemberNameIterator mni(*mn);
       
  7286     MemberDef *md;
       
  7287     for (;(md=mni.current());++mni)
       
  7288     {
       
  7289       //printf("%04d Member `%s'\n",count++,md->name().data());
       
  7290       if (md->documentation().isEmpty() && md->briefDescription().isEmpty())
       
  7291       { // no documentation yet
       
  7292         MemberDef *bmd = md->reimplements();
       
  7293         while (bmd && bmd->documentation().isEmpty() && 
       
  7294                       bmd->briefDescription().isEmpty()
       
  7295               )
       
  7296         { // search up the inheritance tree for a documentation member
       
  7297           //printf("bmd=%s class=%s\n",bmd->name().data(),bmd->getClassDef()->name().data());
       
  7298           bmd = bmd->reimplements();
       
  7299         }
       
  7300         if (bmd) // copy the documentation from the reimplemented member
       
  7301         {
       
  7302           md->setInheritsDocsFrom(bmd);
       
  7303           md->setDocumentation(bmd->documentation(),bmd->docFile(),bmd->docLine());
       
  7304           md->setDocsForDefinition(bmd->isDocsForDefinition());
       
  7305           md->setBriefDescription(bmd->briefDescription(),bmd->briefFile(),bmd->briefLine());
       
  7306           md->copyArgumentNames(bmd);
       
  7307           md->setInbodyDocumentation(bmd->inbodyDocumentation(),bmd->inbodyFile(),bmd->inbodyLine());
       
  7308         }
       
  7309       }
       
  7310     }
       
  7311   }
       
  7312 }
       
  7313 
       
  7314 //----------------------------------------------------------------------------
       
  7315 
       
  7316 static void combineUsingRelations()
       
  7317 {
       
  7318   // for each file
       
  7319   FileNameListIterator fnli(*Doxygen::inputNameList);
       
  7320   FileName *fn;
       
  7321   for (fnli.toFirst();(fn=fnli.current());++fnli)
       
  7322   {
       
  7323     FileNameIterator fni(*fn);
       
  7324     FileDef *fd;
       
  7325     for (fni.toFirst();(fd=fni.current());++fni)
       
  7326     {
       
  7327       fd->visited=FALSE;
       
  7328     }
       
  7329   }
       
  7330   for (fnli.toFirst();(fn=fnli.current());++fnli)
       
  7331   {
       
  7332     FileNameIterator fni(*fn);
       
  7333     FileDef *fd;
       
  7334     for (fni.toFirst();(fd=fni.current());++fni)
       
  7335     {
       
  7336       fd->combineUsingRelations();
       
  7337     }
       
  7338   }
       
  7339 
       
  7340   // for each namespace
       
  7341   NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
       
  7342   NamespaceDef *nd;
       
  7343   for (nli.toFirst() ; (nd=nli.current()) ; ++nli )
       
  7344   {
       
  7345     nd->visited=FALSE;
       
  7346   }
       
  7347   for (nli.toFirst() ; (nd=nli.current()) ; ++nli )
       
  7348   {
       
  7349     nd->combineUsingRelations();
       
  7350   }
       
  7351 }
       
  7352 
       
  7353 //----------------------------------------------------------------------------
       
  7354   
       
  7355 static void addMembersToMemberGroup()
       
  7356 {
       
  7357   // for each class
       
  7358   ClassSDict::Iterator cli(*Doxygen::classSDict);
       
  7359   ClassDef *cd;
       
  7360   for ( ; (cd=cli.current()) ; ++cli )
       
  7361   {
       
  7362     cd->addMembersToMemberGroup();
       
  7363   }
       
  7364   // for each file
       
  7365   FileName *fn=Doxygen::inputNameList->first();
       
  7366   while (fn)
       
  7367   {
       
  7368     FileDef *fd=fn->first();
       
  7369     while (fd)
       
  7370     {
       
  7371       fd->addMembersToMemberGroup();
       
  7372       fd=fn->next();
       
  7373     }
       
  7374     fn=Doxygen::inputNameList->next();
       
  7375   }
       
  7376   // for each namespace
       
  7377   NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
       
  7378   NamespaceDef *nd;
       
  7379   for ( ; (nd=nli.current()) ; ++nli )
       
  7380   {
       
  7381     nd->addMembersToMemberGroup();
       
  7382   }
       
  7383   // for each group
       
  7384   GroupSDict::Iterator gli(*Doxygen::groupSDict);
       
  7385   GroupDef *gd;
       
  7386   for (gli.toFirst();(gd=gli.current());++gli)
       
  7387   {
       
  7388     gd->addMembersToMemberGroup();
       
  7389   }
       
  7390 }
       
  7391 
       
  7392 //----------------------------------------------------------------------------
       
  7393 
       
  7394 static void distributeMemberGroupDocumentation()
       
  7395 {
       
  7396   // for each class
       
  7397   ClassSDict::Iterator cli(*Doxygen::classSDict);
       
  7398   ClassDef *cd;
       
  7399   for ( ; (cd=cli.current()) ; ++cli )
       
  7400   {
       
  7401     cd->distributeMemberGroupDocumentation();
       
  7402   }
       
  7403   // for each file
       
  7404   FileName *fn=Doxygen::inputNameList->first();
       
  7405   while (fn)
       
  7406   {
       
  7407     FileDef *fd=fn->first();
       
  7408     while (fd)
       
  7409     {
       
  7410       fd->distributeMemberGroupDocumentation();
       
  7411       fd=fn->next();
       
  7412     }
       
  7413     fn=Doxygen::inputNameList->next();
       
  7414   }
       
  7415   // for each namespace
       
  7416   NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
       
  7417   NamespaceDef *nd;
       
  7418   for ( ; (nd=nli.current()) ; ++nli )
       
  7419   {
       
  7420     nd->distributeMemberGroupDocumentation();
       
  7421   }
       
  7422   // for each group
       
  7423   GroupSDict::Iterator gli(*Doxygen::groupSDict);
       
  7424   GroupDef *gd;
       
  7425   for (gli.toFirst();(gd=gli.current());++gli)
       
  7426   {
       
  7427     gd->distributeMemberGroupDocumentation();
       
  7428   }
       
  7429 }
       
  7430 
       
  7431 //----------------------------------------------------------------------------
       
  7432 
       
  7433 static void findSectionsInDocumentation()
       
  7434 {
       
  7435   // for each class
       
  7436   ClassSDict::Iterator cli(*Doxygen::classSDict);
       
  7437   ClassDef *cd;
       
  7438   for ( ; (cd=cli.current()) ; ++cli )
       
  7439   {
       
  7440     cd->findSectionsInDocumentation();
       
  7441   }
       
  7442   // for each file
       
  7443   FileName *fn=Doxygen::inputNameList->first();
       
  7444   while (fn)
       
  7445   {
       
  7446     FileDef *fd=fn->first();
       
  7447     while (fd)
       
  7448     {
       
  7449       fd->findSectionsInDocumentation();
       
  7450       fd=fn->next();
       
  7451     }
       
  7452     fn=Doxygen::inputNameList->next();
       
  7453   }
       
  7454   // for each namespace
       
  7455   NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
       
  7456   NamespaceDef *nd;
       
  7457   for ( ; (nd=nli.current()) ; ++nli )
       
  7458   {
       
  7459     nd->findSectionsInDocumentation();
       
  7460   }
       
  7461   // for each group
       
  7462   GroupSDict::Iterator gli(*Doxygen::groupSDict);
       
  7463   GroupDef *gd;
       
  7464   for (gli.toFirst();(gd=gli.current());++gli)
       
  7465   {
       
  7466     gd->findSectionsInDocumentation();
       
  7467   }
       
  7468   // for each page
       
  7469   PageSDict::Iterator pdi(*Doxygen::pageSDict);
       
  7470   PageDef *pd=0;
       
  7471   for (pdi.toFirst();(pd=pdi.current());++pdi)
       
  7472   {
       
  7473     pd->findSectionsInDocumentation();
       
  7474   }
       
  7475   if (Doxygen::mainPage) Doxygen::mainPage->findSectionsInDocumentation();
       
  7476 }
       
  7477 
       
  7478 static void flushCachedTemplateRelations()
       
  7479 {
       
  7480   // remove all references to classes from the cache
       
  7481   // as there can be new template instances in the inheritance path
       
  7482   // to this class. Optimization: only remove those classes that
       
  7483   // have inheritance instances as direct or indirect sub classes.
       
  7484   QCacheIterator<LookupInfo> ci(Doxygen::lookupCache);
       
  7485   LookupInfo *li=0;
       
  7486   for (ci.toFirst();(li=ci.current());++ci)
       
  7487   {
       
  7488     if (li->classDef)
       
  7489     {
       
  7490       Doxygen::lookupCache.remove(ci.currentKey());
       
  7491     }
       
  7492   }
       
  7493   // remove all cached typedef resolutions whose target is a
       
  7494   // template class as this may now be a template instance
       
  7495   MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict);
       
  7496   MemberName *fn;
       
  7497   for (;(fn=fnli.current());++fnli) // for each global function name
       
  7498   {
       
  7499     MemberNameIterator fni(*fn);
       
  7500     MemberDef *fmd;
       
  7501     for (;(fmd=fni.current());++fni) // for each function with that name
       
  7502     {
       
  7503       if (fmd->isTypedefValCached())
       
  7504       {
       
  7505         ClassDef *cd = fmd->getCachedTypedefVal();
       
  7506         if (cd->isTemplate()) fmd->invalidateTypedefValCache();
       
  7507       }
       
  7508     }
       
  7509   }
       
  7510   MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
       
  7511   for (;(fn=mnli.current());++mnli) // for each class method name
       
  7512   {
       
  7513     MemberNameIterator mni(*fn);
       
  7514     MemberDef *fmd;
       
  7515     for (;(fmd=mni.current());++mni) // for each function with that name
       
  7516     {
       
  7517       if (fmd->isTypedefValCached())
       
  7518       {
       
  7519         ClassDef *cd = fmd->getCachedTypedefVal();
       
  7520         if (cd->isTemplate()) fmd->invalidateTypedefValCache();
       
  7521       }
       
  7522     }
       
  7523   }
       
  7524 }
       
  7525 
       
  7526 //----------------------------------------------------------------------------
       
  7527 
       
  7528 static void flushUnresolvedRelations()
       
  7529 {
       
  7530   // Remove all unresolved references to classes from the cache.
       
  7531   // This is needed before resolving the inheritance relations, since
       
  7532   // it would otherwise not find the inheritance relation
       
  7533   // for C in the example below, as B::I was already found to be unresolvable 
       
  7534   // (which is correct if you igore the inheritance relation between A and B).
       
  7535   // 
       
  7536   // class A { class I {} };
       
  7537   // class B : public A {};
       
  7538   // class C : public B::I {};
       
  7539   //
       
  7540   QCacheIterator<LookupInfo> ci(Doxygen::lookupCache);
       
  7541   LookupInfo *li=0;
       
  7542   for (ci.toFirst();(li=ci.current());++ci)
       
  7543   {
       
  7544     if (li->classDef==0 && li->typeDef==0)
       
  7545     {
       
  7546       Doxygen::lookupCache.remove(ci.currentKey());
       
  7547     }
       
  7548   }
       
  7549 
       
  7550   MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict);
       
  7551   MemberName *fn;
       
  7552   for (;(fn=fnli.current());++fnli) // for each global function name
       
  7553   {
       
  7554     MemberNameIterator fni(*fn);
       
  7555     MemberDef *fmd;
       
  7556     for (;(fmd=fni.current());++fni) // for each function with that name
       
  7557     {
       
  7558       fmd->invalidateCachedArgumentTypes();
       
  7559     }
       
  7560   }
       
  7561   MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
       
  7562   for (;(fn=mnli.current());++mnli) // for each class method name
       
  7563   {
       
  7564     MemberNameIterator mni(*fn);
       
  7565     MemberDef *fmd;
       
  7566     for (;(fmd=mni.current());++mni) // for each function with that name
       
  7567     {
       
  7568       fmd->invalidateCachedArgumentTypes();
       
  7569     }
       
  7570   }
       
  7571 
       
  7572 }
       
  7573 
       
  7574 //----------------------------------------------------------------------------
       
  7575 
       
  7576 static void findDefineDocumentation(EntryNav *rootNav)
       
  7577 {
       
  7578   if ((rootNav->section()==Entry::DEFINEDOC_SEC ||
       
  7579        rootNav->section()==Entry::DEFINE_SEC) && !rootNav->name().isEmpty()
       
  7580      )
       
  7581   {
       
  7582     rootNav->loadEntry(g_storage);
       
  7583     Entry *root = rootNav->entry();
       
  7584     
       
  7585     //printf("found define `%s' `%s' brief=`%s' doc=`%s'\n",
       
  7586     //       root->name.data(),root->args.data(),root->brief.data(),root->doc.data());
       
  7587 
       
  7588     if (rootNav->tagInfo() && !root->name.isEmpty()) // define read from a tag file
       
  7589     {
       
  7590       MemberDef *md=new MemberDef("<tagfile>",1,
       
  7591                     "#define",root->name,root->args,0,
       
  7592                     Public,Normal,FALSE,Member,MemberDef::Define,0,0);
       
  7593       md->setTagInfo(rootNav->tagInfo());
       
  7594       //printf("Searching for `%s' fd=%p\n",filePathName.data(),fd);
       
  7595       md->setFileDef(rootNav->parent()->fileDef());
       
  7596       //printf("Adding member=%s\n",md->name().data());
       
  7597       MemberName *mn;
       
  7598       if ((mn=Doxygen::functionNameSDict->find(root->name)))
       
  7599       {
       
  7600         mn->append(md);
       
  7601       }
       
  7602       else 
       
  7603       {
       
  7604         mn = new MemberName(root->name);
       
  7605         mn->append(md);
       
  7606         Doxygen::functionNameSDict->append(root->name,mn);
       
  7607       }
       
  7608     }
       
  7609     MemberName *mn=Doxygen::functionNameSDict->find(root->name);
       
  7610     if (mn)
       
  7611     {
       
  7612       int count=0;
       
  7613       MemberDef *md=mn->first();
       
  7614       while (md)
       
  7615       {
       
  7616         if (md->memberType()==MemberDef::Define) count++;
       
  7617         md=mn->next();
       
  7618       }
       
  7619       if (count==1)
       
  7620       {
       
  7621         md=mn->first();
       
  7622         while (md)
       
  7623         {
       
  7624           if (md->memberType()==MemberDef::Define)
       
  7625           {
       
  7626 #if 0
       
  7627             if (md->documentation().isEmpty())
       
  7628 #endif
       
  7629             {
       
  7630               md->setDocumentation(root->doc,root->docFile,root->docLine);
       
  7631               md->setDocsForDefinition(!root->proto);
       
  7632             }
       
  7633 #if 0
       
  7634             if (md->briefDescription().isEmpty())
       
  7635 #endif
       
  7636             {
       
  7637               md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
       
  7638             }
       
  7639             if (md->inbodyDocumentation().isEmpty())
       
  7640             {
       
  7641               md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
       
  7642             }
       
  7643             md->setBodySegment(root->bodyLine,root->endBodyLine);
       
  7644             md->setBodyDef(rootNav->fileDef());
       
  7645             md->addSectionsToDefinition(root->anchors);
       
  7646             md->setMaxInitLines(root->initLines);
       
  7647             md->setRefItems(root->sli);
       
  7648             if (root->mGrpId!=-1) md->setMemberGroupId(root->mGrpId);
       
  7649             addMemberToGroups(root,md);
       
  7650           }
       
  7651           md=mn->next();
       
  7652         }
       
  7653       }
       
  7654       else if (count>1 && 
       
  7655                (!root->doc.isEmpty() || 
       
  7656                 !root->brief.isEmpty() || 
       
  7657                 root->bodyLine!=-1
       
  7658                )
       
  7659               ) 
       
  7660         // multiple defines don't know where to add docs
       
  7661         // but maybe they are in different files together with their documentation
       
  7662       {
       
  7663         md=mn->first();
       
  7664         while (md)
       
  7665         {
       
  7666           if (md->memberType()==MemberDef::Define)
       
  7667           {
       
  7668             FileDef *fd=md->getFileDef();
       
  7669             if (fd && fd->absFilePath()==root->fileName) 
       
  7670               // doc and define in the same file assume they belong together.
       
  7671             {
       
  7672 #if 0
       
  7673               if (md->documentation().isEmpty())
       
  7674 #endif
       
  7675               {
       
  7676                 md->setDocumentation(root->doc,root->docFile,root->docLine);
       
  7677                 md->setDocsForDefinition(!root->proto);
       
  7678               }
       
  7679 #if 0
       
  7680               if (md->briefDescription().isEmpty())
       
  7681 #endif
       
  7682               {
       
  7683                 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
       
  7684               }
       
  7685               if (md->inbodyDocumentation().isEmpty())
       
  7686               {
       
  7687                 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
       
  7688               }
       
  7689               md->setBodySegment(root->bodyLine,root->endBodyLine);
       
  7690               md->setBodyDef(rootNav->fileDef());
       
  7691               md->addSectionsToDefinition(root->anchors);
       
  7692               md->setRefItems(root->sli);
       
  7693               if (root->mGrpId!=-1) md->setMemberGroupId(root->mGrpId);
       
  7694               addMemberToGroups(root,md);
       
  7695             }
       
  7696           }
       
  7697           md=mn->next();
       
  7698         }
       
  7699         //warn("Warning: define %s found in the following files:\n",root->name.data());
       
  7700         //warn("Cannot determine where to add the documentation found "
       
  7701         //     "at line %d of file %s. \n",
       
  7702         //     root->startLine,root->fileName.data());
       
  7703       }
       
  7704     }
       
  7705     else if (!root->doc.isEmpty() || !root->brief.isEmpty()) // define not found
       
  7706     {
       
  7707       static bool preEnabled = Config_getBool("ENABLE_PREPROCESSING");
       
  7708       if (preEnabled)
       
  7709       {
       
  7710         warn(root->fileName,root->startLine,
       
  7711              "Warning: documentation for unknown define %s found.\n",
       
  7712              root->name.data()
       
  7713             );
       
  7714       }
       
  7715       else
       
  7716       {
       
  7717         warn(root->fileName,root->startLine,
       
  7718              "Warning: found documented #define but ignoring it because "
       
  7719              "ENABLE_PREPROCESSING is NO.\n",
       
  7720              root->name.data()
       
  7721             );
       
  7722       }
       
  7723     }
       
  7724 
       
  7725     rootNav->releaseEntry();
       
  7726   }
       
  7727   RECURSE_ENTRYTREE(findDefineDocumentation,rootNav);
       
  7728 }
       
  7729 
       
  7730 //----------------------------------------------------------------------------
       
  7731 
       
  7732 static void findDirDocumentation(EntryNav *rootNav)
       
  7733 {
       
  7734   if (rootNav->section() == Entry::DIRDOC_SEC)
       
  7735   {
       
  7736     rootNav->loadEntry(g_storage);
       
  7737     Entry *root = rootNav->entry();
       
  7738 
       
  7739     QCString normalizedName = root->name;
       
  7740     normalizedName = substitute(normalizedName,"\\","/");
       
  7741     if (normalizedName.at(normalizedName.length()-1)!='/')
       
  7742     {
       
  7743       normalizedName+='/';
       
  7744     }
       
  7745     DirDef *dir,*matchingDir=0;
       
  7746     SDict<DirDef>::Iterator sdi(*Doxygen::directories);
       
  7747     for (sdi.toFirst();(dir=sdi.current());++sdi)
       
  7748     {
       
  7749       //printf("Dir: %s<->%s\n",dir->name().data(),normalizedName.data());
       
  7750       if (dir->name().right(normalizedName.length())==normalizedName)
       
  7751       {
       
  7752         if (matchingDir)
       
  7753         {
       
  7754            warn(root->fileName,root->startLine,
       
  7755              "Warning: \\dir command matches multiple directories.\n"
       
  7756              "  Applying the command for directory %s\n"
       
  7757              "  Ignoring the command for directory %s\n",
       
  7758              matchingDir->name().data(),dir->name().data()
       
  7759            );
       
  7760         }
       
  7761         else
       
  7762         {
       
  7763           matchingDir=dir;
       
  7764         }
       
  7765       }
       
  7766     }
       
  7767     if (matchingDir)
       
  7768     {
       
  7769       //printf("Match for with dir %s\n",matchingDir->name().data());
       
  7770       matchingDir->setBriefDescription(root->brief,root->briefFile,root->briefLine);
       
  7771       matchingDir->setDocumentation(root->doc,root->docFile,root->docLine);
       
  7772       matchingDir->setRefItems(root->sli);
       
  7773       addDirToGroups(root,matchingDir);
       
  7774     }
       
  7775     else
       
  7776     {
       
  7777       warn(root->fileName,root->startLine,"Warning: No matching "
       
  7778           "directory found for command \\dir %s\n",root->name.data());
       
  7779     }
       
  7780     rootNav->releaseEntry();
       
  7781   }
       
  7782   RECURSE_ENTRYTREE(findDirDocumentation,rootNav);
       
  7783 }
       
  7784 
       
  7785 
       
  7786 //----------------------------------------------------------------------------
       
  7787 // create a (sorted) list of separate documentation pages
       
  7788 
       
  7789 static void buildPageList(EntryNav *rootNav)
       
  7790 {
       
  7791   if (rootNav->section() == Entry::PAGEDOC_SEC)
       
  7792   {
       
  7793     rootNav->loadEntry(g_storage);
       
  7794     Entry *root = rootNav->entry();
       
  7795 
       
  7796     if (!root->name.isEmpty())
       
  7797     {
       
  7798       addRelatedPage(rootNav);
       
  7799     }
       
  7800 
       
  7801     rootNav->releaseEntry();
       
  7802   }
       
  7803   else if (rootNav->section() == Entry::MAINPAGEDOC_SEC)
       
  7804   {
       
  7805     rootNav->loadEntry(g_storage);
       
  7806     Entry *root = rootNav->entry();
       
  7807 
       
  7808     QCString title=root->args.stripWhiteSpace();
       
  7809     if (title.isEmpty()) title=theTranslator->trMainPage();
       
  7810     QCString name = Config_getBool("GENERATE_TREEVIEW")?"main":"index";
       
  7811     addRefItem(root->sli,
       
  7812                name,
       
  7813                "page",
       
  7814                name,
       
  7815                title,
       
  7816                0
       
  7817                );
       
  7818 
       
  7819     rootNav->releaseEntry();
       
  7820   }
       
  7821   RECURSE_ENTRYTREE(buildPageList,rootNav);
       
  7822 }
       
  7823 
       
  7824 static void findMainPage(EntryNav *rootNav)
       
  7825 {
       
  7826   if (rootNav->section() == Entry::MAINPAGEDOC_SEC)
       
  7827   {
       
  7828     rootNav->loadEntry(g_storage);
       
  7829     Entry *root = rootNav->entry();
       
  7830 
       
  7831     if (Doxygen::mainPage==0)
       
  7832     {
       
  7833       //printf("Found main page! \n======\n%s\n=======\n",root->doc.data());
       
  7834       QCString title=root->args.stripWhiteSpace();
       
  7835       QCString indexName=Config_getBool("GENERATE_TREEVIEW")?"main":"index";
       
  7836       Doxygen::mainPage = new PageDef(root->fileName,root->startLine,
       
  7837                               indexName, root->brief+root->doc+root->inbodyDocs,title);
       
  7838       //setFileNameForSections(root->anchors,"index",Doxygen::mainPage);
       
  7839       Doxygen::mainPage->setFileName(indexName);
       
  7840       addPageToContext(Doxygen::mainPage,rootNav);
       
  7841           
       
  7842       // a page name is a label as well!
       
  7843       SectionInfo *si=new SectionInfo(
       
  7844           indexName,
       
  7845           Doxygen::mainPage->name(),
       
  7846           Doxygen::mainPage->title(),
       
  7847           SectionInfo::Page);
       
  7848       Doxygen::sectionDict.insert(indexName,si);
       
  7849       Doxygen::mainPage->addSectionsToDefinition(root->anchors);
       
  7850     }
       
  7851     else
       
  7852     {
       
  7853       warn(root->fileName,root->startLine,
       
  7854            "Warning: found more than one \\mainpage comment block! Skipping this "
       
  7855            "block."
       
  7856           );
       
  7857     }
       
  7858 
       
  7859     rootNav->releaseEntry();
       
  7860   }
       
  7861   RECURSE_ENTRYTREE(findMainPage,rootNav);
       
  7862 }
       
  7863 
       
  7864 static void computePageRelations(EntryNav *rootNav)
       
  7865 {
       
  7866   if ((rootNav->section()==Entry::PAGEDOC_SEC || 
       
  7867        rootNav->section()==Entry::MAINPAGEDOC_SEC
       
  7868       )
       
  7869       && !rootNav->name().isEmpty()
       
  7870      )
       
  7871   {
       
  7872     rootNav->loadEntry(g_storage);
       
  7873     Entry *root = rootNav->entry();
       
  7874 
       
  7875     PageDef *pd = root->section==Entry::PAGEDOC_SEC ?
       
  7876                     Doxygen::pageSDict->find(root->name) : 
       
  7877                     Doxygen::mainPage; 
       
  7878     if (pd)
       
  7879     {
       
  7880       QListIterator<BaseInfo> bii(*root->extends);
       
  7881       BaseInfo *bi;
       
  7882       for (bii.toFirst();(bi=bii.current());++bii)
       
  7883       {
       
  7884         PageDef *subPd = Doxygen::pageSDict->find(bi->name);
       
  7885         if (subPd)
       
  7886         {
       
  7887           pd->addInnerCompound(subPd);
       
  7888           //printf("*** Added subpage relation: %s->%s\n",
       
  7889           //    pd->name().data(),subPd->name().data());
       
  7890         }
       
  7891       }
       
  7892     }
       
  7893 
       
  7894     rootNav->releaseEntry();
       
  7895   }
       
  7896   RECURSE_ENTRYTREE(computePageRelations,rootNav);
       
  7897 }
       
  7898 
       
  7899 static void checkPageRelations()
       
  7900 {
       
  7901   PageSDict::Iterator pdi(*Doxygen::pageSDict);
       
  7902   PageDef *pd=0;
       
  7903   for (pdi.toFirst();(pd=pdi.current());++pdi)
       
  7904   {
       
  7905     Definition *ppd = pd->getOuterScope();
       
  7906     while (ppd)
       
  7907     {
       
  7908       if (ppd==pd)
       
  7909       {
       
  7910         err("Warning: page defined at line %d of file %s with label %s is a subpage "
       
  7911             "of itself! Please remove this cyclic dependency.\n",
       
  7912             pd->docLine(),pd->docFile().data(),pd->name().data());
       
  7913         exit(1);
       
  7914       }
       
  7915       ppd=ppd->getOuterScope();
       
  7916     }
       
  7917   }
       
  7918 }
       
  7919 
       
  7920 //----------------------------------------------------------------------------
       
  7921 
       
  7922 static void resolveUserReferences()
       
  7923 {
       
  7924   QDictIterator<SectionInfo> sdi(Doxygen::sectionDict);
       
  7925   SectionInfo *si;
       
  7926   for (;(si=sdi.current());++sdi)
       
  7927   {
       
  7928     //printf("si->label=`%s' si->definition=%s si->fileName=`%s'\n",
       
  7929     //        si->label.data(),si->definition?si->definition->name().data():"<none>",
       
  7930     //        si->fileName.data());
       
  7931     PageDef *pd=0;
       
  7932 
       
  7933     // hack: the items of a todo/test/bug/deprecated list are all fragments from 
       
  7934     // different files, so the resulting section's all have the wrong file 
       
  7935     // name (not from the todo/test/bug/deprecated list, but from the file in 
       
  7936     // which they are defined). We correct this here by looking at the 
       
  7937     // generated section labels!
       
  7938     QDictIterator<RefList> rli(*Doxygen::xrefLists);
       
  7939     RefList *rl;
       
  7940     for (rli.toFirst();(rl=rli.current());++rli)
       
  7941     {
       
  7942       QCString label="_"+rl->listName(); // "_todo", "_test", ...
       
  7943       if (si->label.left(label.length())==label)
       
  7944       {
       
  7945         si->fileName=rl->listName();
       
  7946         si->generated=TRUE;
       
  7947         break;
       
  7948       }
       
  7949     }
       
  7950 
       
  7951     //printf("start: si->label=%s si->fileName=%s\n",si->label.data(),si->fileName.data());
       
  7952     if (!si->generated)
       
  7953     {
       
  7954       // if this section is in a page and the page is in a group, then we
       
  7955       // have to adjust the link file name to point to the group.
       
  7956       if (!si->fileName.isEmpty() && 
       
  7957           (pd=Doxygen::pageSDict->find(si->fileName)) &&
       
  7958           pd->getGroupDef())
       
  7959       {
       
  7960         si->fileName=pd->getGroupDef()->getOutputFileBase().copy();
       
  7961       }
       
  7962 
       
  7963       if (si->definition)
       
  7964       {
       
  7965         // TODO: there should be one function in Definition that returns
       
  7966         // the file to link to, so we can avoid the following tests.
       
  7967         GroupDef *gd=0;
       
  7968         if (si->definition->definitionType()==Definition::TypeMember)
       
  7969         {
       
  7970           gd = ((MemberDef *)si->definition)->getGroupDef();
       
  7971         }
       
  7972 
       
  7973         if (gd)
       
  7974         {
       
  7975           si->fileName=gd->getOutputFileBase().copy();
       
  7976         }
       
  7977         else
       
  7978         {
       
  7979           //si->fileName=si->definition->getOutputFileBase().copy();
       
  7980           //printf("Setting si->fileName to %s\n",si->fileName.data());
       
  7981         }
       
  7982       }
       
  7983     }
       
  7984     //printf("end: si->label=%s si->fileName=%s\n",si->label.data(),si->fileName.data());
       
  7985   }
       
  7986 }
       
  7987 
       
  7988 
       
  7989 //----------------------------------------------------------------------------
       
  7990 // generate all separate documentation pages
       
  7991 
       
  7992 
       
  7993 static void generatePageDocs()
       
  7994 {
       
  7995   //printf("documentedPages=%d real=%d\n",documentedPages,Doxygen::pageSDict->count());
       
  7996   if (documentedPages==0) return;
       
  7997   PageSDict::Iterator pdi(*Doxygen::pageSDict);
       
  7998   PageDef *pd=0;
       
  7999   for (pdi.toFirst();(pd=pdi.current());++pdi)
       
  8000   {
       
  8001     if (!pd->getGroupDef() && !pd->isReference())
       
  8002     {
       
  8003       msg("Generating docs for page %s...\n",pd->name().data());
       
  8004       Doxygen::insideMainPage=TRUE;
       
  8005       pd->writeDocumentation(*g_outputList);
       
  8006       Doxygen::insideMainPage=FALSE;
       
  8007     }
       
  8008   }
       
  8009 }
       
  8010 
       
  8011 //----------------------------------------------------------------------------
       
  8012 // create a (sorted) list & dictionary of example pages
       
  8013 
       
  8014 static void buildExampleList(EntryNav *rootNav)
       
  8015 {
       
  8016   if (rootNav->section()==Entry::EXAMPLE_SEC && !rootNav->name().isEmpty()) 
       
  8017   {
       
  8018     rootNav->loadEntry(g_storage);
       
  8019     Entry *root = rootNav->entry();
       
  8020 
       
  8021     if (Doxygen::exampleSDict->find(root->name))
       
  8022     {
       
  8023       warn(root->fileName,root->startLine,
       
  8024           "Warning: Example %s was already documented. Ignoring "
       
  8025           "documentation found here.",
       
  8026           root->name.data()
       
  8027           );
       
  8028     }
       
  8029     else
       
  8030     {
       
  8031       PageDef *pd=new PageDef(root->fileName,root->startLine,
       
  8032           root->name,root->brief+root->doc+root->inbodyDocs,root->args);
       
  8033       pd->setFileName(convertNameToFile(pd->name()+"-example"));
       
  8034       pd->addSectionsToDefinition(root->anchors);
       
  8035       //pi->addSections(root->anchors);
       
  8036 
       
  8037       Doxygen::exampleSDict->inSort(root->name,pd);
       
  8038       //we don't add example to groups 
       
  8039       //addExampleToGroups(root,pd);
       
  8040     }
       
  8041 
       
  8042     rootNav->releaseEntry();
       
  8043   }
       
  8044   RECURSE_ENTRYTREE(buildExampleList,rootNav);
       
  8045 }
       
  8046 
       
  8047 //----------------------------------------------------------------------------
       
  8048 // prints the Entry tree (for debugging)
       
  8049 
       
  8050 void printNavTree(EntryNav *rootNav,int indent)
       
  8051 {
       
  8052   QCString indentStr;
       
  8053   indentStr.fill(' ',indent);
       
  8054   msg("%s%s (sec=0x%x)\n",
       
  8055       indentStr.isEmpty()?"":indentStr.data(),
       
  8056       rootNav->name().isEmpty()?"<empty>":rootNav->name().data(),
       
  8057       rootNav->section());
       
  8058   if (rootNav->children()) 
       
  8059   {
       
  8060     EntryNavListIterator eli(*rootNav->children());
       
  8061     for (;eli.current();++eli) printNavTree(eli.current(),indent+2);
       
  8062   }
       
  8063 }
       
  8064 
       
  8065 
       
  8066 //----------------------------------------------------------------------------
       
  8067 // generate the example documentation 
       
  8068 
       
  8069 static void generateExampleDocs()
       
  8070 {
       
  8071   g_outputList->disable(OutputGenerator::Man);
       
  8072   PageSDict::Iterator pdi(*Doxygen::exampleSDict);
       
  8073   PageDef *pd=0;
       
  8074   for (pdi.toFirst();(pd=pdi.current());++pdi)
       
  8075   {
       
  8076     msg("Generating docs for example %s...\n",pd->name().data());
       
  8077     resetCCodeParserState();
       
  8078     QCString n=pd->getOutputFileBase();
       
  8079     startFile(*g_outputList,n,n,pd->name());
       
  8080     startTitle(*g_outputList,n);
       
  8081     g_outputList->docify(pd->name());
       
  8082     endTitle(*g_outputList,n,0);
       
  8083     g_outputList->parseDoc(pd->docFile(),                            // file
       
  8084                          pd->docLine(),                            // startLine
       
  8085                          pd,                                       // context
       
  8086                          0,                                        // memberDef
       
  8087                          pd->documentation()+"\n\n\\include "+pd->name(),          // docs
       
  8088                          TRUE,                                     // index words
       
  8089                          TRUE,                                     // is example
       
  8090                          pd->name()
       
  8091                         );
       
  8092     endFile(*g_outputList);
       
  8093   }
       
  8094   g_outputList->enable(OutputGenerator::Man);
       
  8095 }
       
  8096 
       
  8097 //----------------------------------------------------------------------------
       
  8098 // generate module pages
       
  8099 
       
  8100 static void generateGroupDocs()
       
  8101 {
       
  8102   GroupSDict::Iterator gli(*Doxygen::groupSDict);
       
  8103   GroupDef *gd;
       
  8104   for (gli.toFirst();(gd=gli.current());++gli)
       
  8105   {
       
  8106     if (!gd->isReference())
       
  8107     {
       
  8108       gd->writeDocumentation(*g_outputList);
       
  8109     }
       
  8110   }
       
  8111 }
       
  8112 
       
  8113 //----------------------------------------------------------------------------
       
  8114 
       
  8115 //static void generatePackageDocs()
       
  8116 //{
       
  8117 //  writePackageIndex(*g_outputList);
       
  8118 //  
       
  8119 //  if (Doxygen::packageDict.count()>0)
       
  8120 //  {
       
  8121 //    PackageSDict::Iterator pdi(Doxygen::packageDict);
       
  8122 //    PackageDef *pd;
       
  8123 //    for (pdi.toFirst();(pd=pdi.current());++pdi)
       
  8124 //    {
       
  8125 //      pd->writeDocumentation(*g_outputList);
       
  8126 //    }
       
  8127 //  }
       
  8128 //}
       
  8129 
       
  8130 //----------------------------------------------------------------------------
       
  8131 // generate module pages
       
  8132 
       
  8133 static void generateNamespaceDocs()
       
  8134 {
       
  8135   writeNamespaceIndex(*g_outputList);
       
  8136   
       
  8137   NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
       
  8138   NamespaceDef *nd;
       
  8139   // for each namespace...
       
  8140   for (;(nd=nli.current());++nli)
       
  8141   {
       
  8142 
       
  8143     if (nd->isLinkableInProject())
       
  8144     {
       
  8145       msg("Generating docs for namespace %s\n",nd->name().data());
       
  8146       nd->writeDocumentation(*g_outputList);
       
  8147     }
       
  8148 
       
  8149     // for each class in the namespace...
       
  8150     ClassSDict::Iterator cli(*nd->getClassSDict());
       
  8151     for ( ; cli.current() ; ++cli )
       
  8152     {
       
  8153       ClassDef *cd=cli.current();
       
  8154       if ( ( cd->isLinkableInProject() && 
       
  8155              cd->templateMaster()==0
       
  8156            ) // skip external references, anonymous compounds and 
       
  8157              // template instances and nested classes
       
  8158            && !cd->isHidden()
       
  8159          )
       
  8160       {
       
  8161         msg("Generating docs for compound %s...\n",cd->name().data());
       
  8162 
       
  8163         cd->writeDocumentation(*g_outputList);
       
  8164         cd->writeMemberList(*g_outputList);
       
  8165       }
       
  8166       cd->writeDocumentationForInnerClasses(*g_outputList);
       
  8167     }
       
  8168   }
       
  8169 }
       
  8170 
       
  8171 #if defined(_WIN32)
       
  8172 static QCString fixSlashes(QCString &s)
       
  8173 {
       
  8174   QCString result;
       
  8175   uint i;
       
  8176   for (i=0;i<s.length();i++)
       
  8177   {
       
  8178     switch(s.at(i))
       
  8179     {
       
  8180       case '/': 
       
  8181       case '\\': 
       
  8182         result+="\\\\"; 
       
  8183         break;
       
  8184       default:
       
  8185         result+=s.at(i);
       
  8186     }
       
  8187   }
       
  8188   return result;
       
  8189 }
       
  8190 #endif
       
  8191 
       
  8192 
       
  8193 //----------------------------------------------------------------------------
       
  8194 // generate files for the search engine
       
  8195 
       
  8196 //static void generateSearchIndex()
       
  8197 //{
       
  8198 //  if (Config_getBool("SEARCHENGINE") && Config_getBool("GENERATE_HTML"))
       
  8199 //  {
       
  8200 //    // create search index
       
  8201 //    QCString fileName;
       
  8202 //    writeSearchButton(Config_getString("HTML_OUTPUT"));
       
  8203 //
       
  8204 //#if !defined(_WIN32)
       
  8205 //    // create cgi script
       
  8206 //    fileName = Config_getString("HTML_OUTPUT")+"/"+Config_getString("CGI_NAME");
       
  8207 //    QFile f(fileName);
       
  8208 //    if (f.open(IO_WriteOnly))
       
  8209 //    {
       
  8210 //      QTextStream t(&f);
       
  8211 //      t << "#!/bin/sh"   << endl
       
  8212 //        << "DOXYSEARCH=" << Config_getString("BIN_ABSPATH") << "/doxysearch" << endl
       
  8213 //        << "DOXYPATH=\"" << Config_getString("DOC_ABSPATH") << " ";
       
  8214 //
       
  8215 //      QStrList &extDocPaths=Config_getList("EXT_DOC_PATHS");
       
  8216 //      char *s= extDocPaths.first();
       
  8217 //      while (s)
       
  8218 //      {
       
  8219 //        t << s << " ";
       
  8220 //        s=extDocPaths.next();
       
  8221 //      }
       
  8222 //
       
  8223 //      t << "\"" << endl 
       
  8224 //        << "if [ -f $DOXYSEARCH ]" << endl
       
  8225 //        << "then" << endl
       
  8226 //        << "  $DOXYSEARCH $DOXYPATH" << endl 
       
  8227 //        << "else" << endl
       
  8228 //        << "  echo \"Content-Type: text/html\"" << endl
       
  8229 //        << "  echo \"\"" << endl
       
  8230 //        << "  echo \"<h2>Error: $DOXYSEARCH not found. Check cgi script!</h2>\"" << endl
       
  8231 //        << "fi" << endl;
       
  8232 //
       
  8233 //      f.close();
       
  8234 //      struct stat stat_struct;
       
  8235 //      stat(fileName,&stat_struct);
       
  8236 //      chmod(fileName,stat_struct.st_mode|S_IXUSR|S_IXGRP|S_IXOTH);
       
  8237 //    }
       
  8238 //    else
       
  8239 //    {
       
  8240 //      err("Error: Cannot open file %s for writing\n",fileName.data());
       
  8241 //    }
       
  8242 //#else /* Windows platform */
       
  8243 //    // create cgi program
       
  8244 //    fileName = Config_getString("CGI_NAME").copy();
       
  8245 //    if (fileName.right(4)==".cgi") 
       
  8246 //      fileName=fileName.left(fileName.length()-4);
       
  8247 //    fileName+=".c";
       
  8248 //    fileName.prepend(Config_getString("HTML_OUTPUT")+"/");
       
  8249 //    QFile f(fileName);
       
  8250 //    if (f.open(IO_WriteOnly))
       
  8251 //    {
       
  8252 //      QTextStream t(&f);
       
  8253 //      t << "#include <stdio.h>" << endl;
       
  8254 //      t << "#include <stdlib.h>" << endl;
       
  8255 //      t << "#include <process.h>" << endl;
       
  8256 //      t << endl;
       
  8257 //      t << "const char *DOXYSEARCH = \"" << 
       
  8258 //           fixSlashes(Config_getString("BIN_ABSPATH")) << "\\\\doxysearch.exe\";" << endl;
       
  8259 //      t << "const char *DOXYPATH = \"" << 
       
  8260 //           fixSlashes(Config_getString("DOC_ABSPATH")) << "\";" << endl;
       
  8261 //      t << endl;
       
  8262 //      t << "int main(void)" << endl;
       
  8263 //      t << "{" << endl;
       
  8264 //      t << "  char buf[1024];" << endl;
       
  8265 //      t << "  sprintf(buf,\"%s %s\",DOXYSEARCH,DOXYPATH);" << endl; 
       
  8266 //      t << "  if (system(buf))" << endl;
       
  8267 //      t << "  {" << endl;
       
  8268 //      t << "    printf(\"Content-Type: text/html\\n\\n\");" << endl;
       
  8269 //      t << "    printf(\"<h2>Error: failed to execute %s</h2>\\n\",DOXYSEARCH);" << endl;
       
  8270 //      t << "    exit(1);" << endl;
       
  8271 //      t << "  }" << endl;
       
  8272 //      t << "  return 0;" << endl;
       
  8273 //      t << "}" << endl;
       
  8274 //      f.close();
       
  8275 //    }
       
  8276 //    else
       
  8277 //    {
       
  8278 //      err("Error: Cannot open file %s for writing\n",fileName.data());
       
  8279 //    }
       
  8280 //#endif /* !defined(_WIN32) */
       
  8281 //    
       
  8282 //    // create config file
       
  8283 //    fileName = Config_getString("HTML_OUTPUT")+"/search.cfg";
       
  8284 //    f.setName(fileName);
       
  8285 //    if (f.open(IO_WriteOnly))
       
  8286 //    {
       
  8287 //      QTextStream t(&f);
       
  8288 //      t << Config_getString("DOC_URL") << "/" << endl 
       
  8289 //        << Config_getString("CGI_URL") << "/" << Config_getString("CGI_NAME") << endl;
       
  8290 //      f.close();
       
  8291 //    }
       
  8292 //    else
       
  8293 //    {
       
  8294 //      err("Error: Cannot open file %s for writing\n",fileName.data());
       
  8295 //    }
       
  8296 //    //g_outputList->generateExternalIndex();
       
  8297 //    g_outputList->pushGeneratorState();
       
  8298 //    g_outputList->disableAllBut(OutputGenerator::Html);
       
  8299 //    startFile(*g_outputList,"header"+Doxygen::htmlFileExtension,0,"Search Engine",TRUE);
       
  8300 //    g_outputList->endPlainFile();
       
  8301 //    g_outputList->startPlainFile("footer"+Doxygen::htmlFileExtension);
       
  8302 //    endFile(*g_outputList,TRUE);
       
  8303 //    g_outputList->popGeneratorState();
       
  8304 //  }
       
  8305 //}
       
  8306 
       
  8307 //----------------------------------------------------------------------------
       
  8308 
       
  8309 static bool openOutputFile(const char *outFile,QFile &f)
       
  8310 {
       
  8311   bool fileOpened=FALSE;
       
  8312   bool writeToStdout=(outFile[0]=='-' && outFile[1]=='\0');
       
  8313   if (writeToStdout) // write to stdout
       
  8314   {
       
  8315     fileOpened = f.open(IO_WriteOnly,stdout);
       
  8316   }
       
  8317   else // write to file
       
  8318   {
       
  8319     QFileInfo fi(outFile);
       
  8320     if (fi.exists()) // create a backup
       
  8321     {
       
  8322       QDir dir=fi.dir();
       
  8323       QFileInfo backup(fi.fileName()+".bak");
       
  8324       if (backup.exists()) // remove existing backup
       
  8325         dir.remove(backup.fileName());
       
  8326       dir.rename(fi.fileName(),fi.fileName()+".bak");
       
  8327     } 
       
  8328     f.setName(outFile);
       
  8329     fileOpened = f.open(IO_WriteOnly|IO_Translate);
       
  8330   }
       
  8331   return fileOpened;
       
  8332 }
       
  8333 
       
  8334 /*! Generate a template version of the configuration file.
       
  8335  *  If the \a shortList parameter is TRUE a configuration file without
       
  8336  *  comments will be generated.
       
  8337  */
       
  8338 static void generateConfigFile(const char *configFile,bool shortList,
       
  8339                                bool updateOnly=FALSE)
       
  8340 {
       
  8341   QFile f;
       
  8342   bool fileOpened=openOutputFile(configFile,f);
       
  8343   bool writeToStdout=(configFile[0]=='-' && configFile[1]=='\0');
       
  8344   if (fileOpened)
       
  8345   {
       
  8346     QTextStream t(&f);
       
  8347     t.setEncoding(QTextStream::UnicodeUTF8);
       
  8348     Config::instance()->writeTemplate(t,shortList,updateOnly);
       
  8349     if (!writeToStdout)
       
  8350     {
       
  8351       if (!updateOnly)
       
  8352       {
       
  8353         msg("\n\nConfiguration file `%s' created.\n\n",configFile);
       
  8354         msg("Now edit the configuration file and enter\n\n");
       
  8355         if (strcmp(configFile,"Doxyfile") || strcmp(configFile,"doxyfile"))
       
  8356           msg("  doxygen %s\n\n",configFile);
       
  8357         else
       
  8358           msg("  doxygen\n\n");
       
  8359         msg("to generate the documentation for your project\n\n");
       
  8360       }
       
  8361       else
       
  8362       {
       
  8363         msg("\n\nConfiguration file `%s' updated.\n\n",configFile);
       
  8364       }
       
  8365     }
       
  8366   }
       
  8367   else
       
  8368   {
       
  8369     err("Error: Cannot open file %s for writing\n",configFile);
       
  8370     exit(1);
       
  8371   }
       
  8372 }
       
  8373 
       
  8374 //----------------------------------------------------------------------------
       
  8375 // read and parse a tag file
       
  8376 
       
  8377 //static bool readLineFromFile(QFile &f,QCString &s)
       
  8378 //{
       
  8379 //  char c=0;
       
  8380 //  s.resize(0);
       
  8381 //  while (!f.atEnd() && (c=f.getch())!='\n') s+=c;
       
  8382 //  return f.atEnd();
       
  8383 //}
       
  8384 
       
  8385 //----------------------------------------------------------------------------
       
  8386 
       
  8387 static void readTagFile(Entry *root,const char *tl)
       
  8388 {
       
  8389   QCString tagLine = tl;
       
  8390   QCString fileName;
       
  8391   QCString destName;
       
  8392   int eqPos = tagLine.find('=');
       
  8393   if (eqPos!=-1) // tag command contains a destination
       
  8394   {
       
  8395     fileName = tagLine.left(eqPos).stripWhiteSpace();
       
  8396     destName = tagLine.right(tagLine.length()-eqPos-1).stripWhiteSpace();
       
  8397     QFileInfo fi(fileName);
       
  8398     Doxygen::tagDestinationDict.insert(fi.fileName(),new QCString(destName));
       
  8399     //printf("insert tagDestination %s->%s\n",fi.fileName().data(),destName.data());
       
  8400   }
       
  8401   else
       
  8402   {
       
  8403     fileName = tagLine;
       
  8404   }
       
  8405     
       
  8406   QFileInfo fi(fileName);
       
  8407   if (!fi.exists() || !fi.isFile())
       
  8408   {
       
  8409     err("Error: Tag file `%s' does not exist or is not a file. Skipping it...\n",
       
  8410         fileName.data());
       
  8411     return;
       
  8412   }
       
  8413 
       
  8414   if (!destName.isEmpty())
       
  8415     msg("Reading tag file `%s', location `%s'...\n",fileName.data(),destName.data());
       
  8416   else
       
  8417     msg("Reading tag file `%s'...\n",fileName.data());
       
  8418 
       
  8419   parseTagFile(root,fi.absFilePath(),fi.fileName());
       
  8420 
       
  8421 }
       
  8422 
       
  8423 //----------------------------------------------------------------------------
       
  8424 // returns TRUE if the name of the file represented by `fi' matches
       
  8425 // one of the file patterns in the `patList' list.
       
  8426 
       
  8427 static bool patternMatch(QFileInfo *fi,QStrList *patList)
       
  8428 {
       
  8429   bool found=FALSE;
       
  8430   if (patList)
       
  8431   { 
       
  8432     QCString pattern=patList->first();
       
  8433     while (!pattern.isEmpty() && !found)
       
  8434     {
       
  8435       int i=pattern.find('=');
       
  8436       if (i!=-1) pattern=pattern.left(i); // strip of the extension specific filter name
       
  8437 
       
  8438 #if defined(_WIN32) // windows
       
  8439       QRegExp re(pattern,FALSE,TRUE); // case insensitive match 
       
  8440 #else                // unix
       
  8441       QRegExp re(pattern,TRUE,TRUE);  // case sensitive match
       
  8442 #endif
       
  8443       found = found || re.match(fi->fileName())!=-1 || 
       
  8444                        re.match(fi->filePath())!=-1 ||
       
  8445                        re.match(fi->absFilePath())!=-1;
       
  8446       //printf("Matching `%s' against pattern `%s' found=%d\n",
       
  8447       //    fi->fileName().data(),pattern.data(),found);
       
  8448       pattern=patList->next();
       
  8449     }
       
  8450   }
       
  8451   return found;
       
  8452 }
       
  8453 
       
  8454 //----------------------------------------------------------------------------
       
  8455 static void copyStyleSheet()
       
  8456 {
       
  8457   QCString &htmlStyleSheet = Config_getString("HTML_STYLESHEET");
       
  8458   if (!htmlStyleSheet.isEmpty())
       
  8459   {
       
  8460     QFile cssf(htmlStyleSheet);
       
  8461     QFileInfo cssfi(htmlStyleSheet);
       
  8462     if (cssf.open(IO_ReadOnly))
       
  8463     {
       
  8464       QCString destFileName = Config_getString("HTML_OUTPUT")+"/"+cssfi.fileName().data();
       
  8465       QFile df(destFileName);
       
  8466       if (df.open(IO_WriteOnly))
       
  8467       {
       
  8468         char *buffer = new char[cssf.size()];
       
  8469         cssf.readBlock(buffer,cssf.size());
       
  8470         df.writeBlock(buffer,cssf.size());
       
  8471         df.flush();
       
  8472         delete[] buffer;
       
  8473       }
       
  8474       else
       
  8475       {
       
  8476         err("Error: could not write to style sheet %s\n",destFileName.data());
       
  8477       }
       
  8478     }
       
  8479     else
       
  8480     {
       
  8481       err("Error: could not open user specified style sheet %s\n",Config_getString("HTML_STYLESHEET").data());
       
  8482       htmlStyleSheet.resize(0); // revert to the default
       
  8483     }
       
  8484   }
       
  8485 }
       
  8486 
       
  8487 
       
  8488 //! parse the list of input files
       
  8489 static void parseFiles(Entry *root,EntryNav *rootNav)
       
  8490 {
       
  8491 #if 0
       
  8492   void *cd = 0;
       
  8493   QCString inpEncoding = Config_getString("INPUT_ENCODING");
       
  8494   bool needsTranscoding = !inpEncoding.isEmpty();
       
  8495   if (needsTranscoding)
       
  8496   {
       
  8497     if (!(cd = portable_iconv_open("UTF-8", inpEncoding)))
       
  8498     {
       
  8499        err("Error: unsupported character enconding: '%s'",inpEncoding.data());
       
  8500        exit(1);
       
  8501     }
       
  8502   }
       
  8503 #endif
       
  8504 
       
  8505   QCString *s=g_inputFiles.first();
       
  8506   while (s)
       
  8507   {
       
  8508     QCString fileName=*s;
       
  8509     QCString extension;
       
  8510     int ei = fileName.findRev('.');
       
  8511     if (ei!=-1) extension=fileName.right(fileName.length()-ei);
       
  8512     ParserInterface *parser = Doxygen::parserManager->getParser(extension);
       
  8513 
       
  8514     QFileInfo fi(fileName);
       
  8515     BufStr preBuf(fi.size()+4096);
       
  8516 
       
  8517     if (Config_getBool("ENABLE_PREPROCESSING") && 
       
  8518         parser->needsPreprocessing(extension))
       
  8519     {
       
  8520       BufStr inBuf(fi.size()+4096);
       
  8521       msg("Preprocessing %s...\n",s->data());
       
  8522       readInputFile(fileName,inBuf);
       
  8523       preprocessFile(fileName,inBuf,preBuf);
       
  8524     }
       
  8525     else // no preprocessing
       
  8526     {
       
  8527       msg("Reading %s...\n",s->data());
       
  8528       readInputFile(fileName,preBuf);
       
  8529     }
       
  8530 	msg("Have input for \"%s\", size=%d bytes.\n", s->data(), preBuf.size());
       
  8531     BufStr convBuf(preBuf.curPos()+1024);
       
  8532 
       
  8533     // convert multi-line C++ comments to C style comments
       
  8534     convertCppComments(&preBuf,&convBuf,fileName);
       
  8535 
       
  8536     convBuf.addChar('\0');
       
  8537 
       
  8538     // use language parse to parse the file
       
  8539     parser->parseInput(fileName,convBuf.data(),root);
       
  8540 
       
  8541     // store the Entry tree in a file and create an index to
       
  8542     // navigate/load entries
       
  8543     bool ambig;
       
  8544     FileDef *fd=findFileDef(Doxygen::inputNameDict,fileName,ambig);
       
  8545     ASSERT(fd!=0);
       
  8546     root->createNavigationIndex(rootNav,g_storage,fd);
       
  8547 
       
  8548     s=g_inputFiles.next();
       
  8549   }
       
  8550 }
       
  8551 
       
  8552 // resolves a path that may include symlinks, if a recursive symlink is
       
  8553 // found an empty string is returned.
       
  8554 static QCString resolveSymlink(QCString path)
       
  8555 {
       
  8556   int sepPos=0;
       
  8557   QFileInfo fi;
       
  8558   QDict<void> nonSymlinks;
       
  8559   QDict<void> known;
       
  8560   QCString result = path;
       
  8561   QCString oldPrefix = "/";
       
  8562   do
       
  8563   {
       
  8564 #ifdef WIN32
       
  8565     // UNC path, skip server and share name
       
  8566     if (sepPos==0 && (result.left(2)=="//" || result.left(2)=="\\\\")) 
       
  8567       sepPos = result.find('/',2);
       
  8568     if (sepPos!=-1) 
       
  8569       sepPos = result.find('/',sepPos+1);
       
  8570 #else
       
  8571     sepPos = result.find('/',sepPos+1);
       
  8572 #endif
       
  8573     QCString prefix = sepPos==-1 ? result : result.left(sepPos);
       
  8574     if (nonSymlinks.find(prefix)==0)
       
  8575     {
       
  8576       fi.setFile(prefix);
       
  8577       if (fi.isSymLink())
       
  8578       {
       
  8579         QString target = fi.readLink();
       
  8580         if (QFileInfo(target).isRelative())
       
  8581         {
       
  8582           target = QDir::cleanDirPath(oldPrefix+"/"+target.data());
       
  8583         }
       
  8584         if (sepPos!=-1)
       
  8585         {
       
  8586           if (fi.isDir() && target.length()>0 && target.at(target.length()-1)!='/')
       
  8587           {
       
  8588             target+='/';
       
  8589           }
       
  8590           target+=result.mid(sepPos);
       
  8591         }
       
  8592         result = QDir::cleanDirPath(target).data();
       
  8593         sepPos = 0;
       
  8594         if (known.find(result)) return QCString(); // recursive symlink!
       
  8595         known.insert(result,(void*)0x8);
       
  8596       }
       
  8597       else
       
  8598       {
       
  8599         nonSymlinks.insert(prefix,(void*)0x8);
       
  8600       }
       
  8601       oldPrefix = prefix;
       
  8602     }
       
  8603   }
       
  8604   while (sepPos!=-1);
       
  8605   return QDir::cleanDirPath(result).data();
       
  8606 }
       
  8607 
       
  8608 static QDict<void> g_pathsVisited(1009);
       
  8609 
       
  8610 //----------------------------------------------------------------------------
       
  8611 // Read all files matching at least one pattern in `patList' in the 
       
  8612 // directory represented by `fi'.
       
  8613 // The directory is read iff the recusiveFlag is set.
       
  8614 // The contents of all files is append to the input string
       
  8615 
       
  8616 int readDir(QFileInfo *fi,
       
  8617             FileNameList *fnList,
       
  8618             FileNameDict *fnDict,
       
  8619             StringDict  *exclDict,
       
  8620             QStrList *patList,
       
  8621             QStrList *exclPatList,
       
  8622             StringList *resultList,
       
  8623             StringDict *resultDict,
       
  8624             bool errorIfNotExist,
       
  8625             bool recursive,
       
  8626             QDict<void> *killDict
       
  8627            )
       
  8628 {
       
  8629   QString dirName = fi->absFilePath();
       
  8630   if (fi->isSymLink())
       
  8631   {
       
  8632     dirName = resolveSymlink(dirName.data());
       
  8633     if (dirName.isEmpty()) return 0;            // recusive symlink
       
  8634     if (g_pathsVisited.find(dirName)) return 0; // already visited path
       
  8635     g_pathsVisited.insert(dirName,(void*)0x8);
       
  8636   }
       
  8637   QDir dir(dirName);
       
  8638   dir.setFilter( QDir::Files | QDir::Dirs | QDir::Hidden );
       
  8639   int totalSize=0;
       
  8640   msg("Searching for files in directory %s\n", fi->absFilePath().data());
       
  8641   //printf("killDict=%p count=%d\n",killDict,killDict->count());
       
  8642   
       
  8643   const QFileInfoList *list = dir.entryInfoList();
       
  8644   if (list)
       
  8645   {
       
  8646     QFileInfoListIterator it( *list );
       
  8647     QFileInfo *cfi;
       
  8648 
       
  8649     while ((cfi=it.current()))
       
  8650     {
       
  8651       if (exclDict==0 || exclDict->find(cfi->absFilePath())==0) 
       
  8652       { // file should not be excluded
       
  8653         //printf("killDict->find(%s)\n",cfi->absFilePath().data());
       
  8654         if (!cfi->exists() || !cfi->isReadable())
       
  8655         {
       
  8656           if (errorIfNotExist)
       
  8657           {
       
  8658             err("Warning: source %s is not a readable file or directory... skipping.\n",cfi->absFilePath().data());
       
  8659           }
       
  8660         }
       
  8661         else if (cfi->isFile() && 
       
  8662             (!Config_getBool("EXCLUDE_SYMLINKS") || !cfi->isSymLink()) &&
       
  8663             (patList==0 || patternMatch(cfi,patList)) && 
       
  8664             !patternMatch(cfi,exclPatList) &&
       
  8665             (killDict==0 || killDict->find(cfi->absFilePath())==0)
       
  8666             )
       
  8667         {
       
  8668           totalSize+=cfi->size()+cfi->absFilePath().length()+4;
       
  8669           QCString name=convertToQCString(cfi->fileName());
       
  8670           //printf("New file %s\n",name.data());
       
  8671           if (fnDict)
       
  8672           {
       
  8673             FileDef  *fd=new FileDef(cfi->dirPath()+"/",name);
       
  8674             FileName *fn=0;
       
  8675             if (!name.isEmpty() && (fn=(*fnDict)[name]))
       
  8676             {
       
  8677               fn->append(fd);
       
  8678             }
       
  8679             else
       
  8680             {
       
  8681               fn = new FileName(cfi->absFilePath(),name);
       
  8682               fn->append(fd);
       
  8683               if (fnList) fnList->inSort(fn);
       
  8684               fnDict->insert(name,fn);
       
  8685             }
       
  8686           }
       
  8687           QCString *rs=0;
       
  8688           if (resultList || resultDict)
       
  8689           {
       
  8690             rs=new QCString(cfi->absFilePath());
       
  8691           }
       
  8692           if (resultList) resultList->append(rs);
       
  8693           if (resultDict) resultDict->insert(cfi->absFilePath(),rs);
       
  8694           if (killDict) killDict->insert(cfi->absFilePath(),(void *)0x8);
       
  8695         }
       
  8696         else if (recursive &&
       
  8697             (!Config_getBool("EXCLUDE_SYMLINKS") || !cfi->isSymLink()) &&
       
  8698             cfi->isDir() && cfi->fileName()!="." && 
       
  8699             !patternMatch(cfi,exclPatList) &&
       
  8700             cfi->fileName()!="..")
       
  8701         {
       
  8702           cfi->setFile(cfi->absFilePath());
       
  8703           totalSize+=readDir(cfi,fnList,fnDict,exclDict,
       
  8704               patList,exclPatList,resultList,resultDict,errorIfNotExist,
       
  8705               recursive,killDict);
       
  8706         }
       
  8707       }
       
  8708       ++it;
       
  8709     }
       
  8710   }
       
  8711   return totalSize;
       
  8712 }
       
  8713 
       
  8714 
       
  8715 //----------------------------------------------------------------------------
       
  8716 // read a file or all files in a directory and append their contents to the
       
  8717 // input string. The names of the files are appended to the `fiList' list.
       
  8718 
       
  8719 int readFileOrDirectory(const char *s,
       
  8720                         FileNameList *fnList,
       
  8721                         FileNameDict *fnDict,
       
  8722                         StringDict *exclDict,
       
  8723                         QStrList *patList,
       
  8724                         QStrList *exclPatList,
       
  8725                         StringList *resultList,
       
  8726                         StringDict *resultDict,
       
  8727                         bool recursive,
       
  8728                         bool errorIfNotExist,
       
  8729                         QDict<void> *killDict
       
  8730                        )
       
  8731 {
       
  8732   //printf("killDict=%p count=%d\n",killDict,killDict->count());
       
  8733   // strip trailing slashes
       
  8734   if (s==0) return 0;
       
  8735   QCString fs = s;
       
  8736   char lc = fs.at(fs.length()-1);
       
  8737   if (lc=='/' || lc=='\\') fs = fs.left(fs.length()-1);
       
  8738 
       
  8739   QFileInfo fi(fs);
       
  8740   //printf("readFileOrDirectory(%s)\n",s);
       
  8741   int totalSize=0;
       
  8742   {
       
  8743     if (exclDict==0 || exclDict->find(fi.absFilePath())==0)
       
  8744     {
       
  8745       if (!fi.exists() || !fi.isReadable())
       
  8746       {
       
  8747         if (errorIfNotExist)
       
  8748         {
       
  8749           err("Warning: source %s is not a readable file or directory... skipping.\n",s);
       
  8750         }
       
  8751       }
       
  8752       else if (!Config_getBool("EXCLUDE_SYMLINKS") || !fi.isSymLink())
       
  8753       {
       
  8754         if (fi.isFile())
       
  8755         {
       
  8756           //printf("killDict->find(%s)\n",fi.absFilePath().data());
       
  8757           if (killDict==0 || killDict->find(fi.absFilePath())==0)
       
  8758           {
       
  8759             totalSize+=fi.size()+fi.absFilePath().length()+4; //readFile(&fi,fiList,input); 
       
  8760             //fiList->inSort(new FileInfo(fi));
       
  8761             QCString name=convertToQCString(fi.fileName());
       
  8762             //printf("New file %s\n",name.data());
       
  8763             if (fnDict)
       
  8764             {
       
  8765               FileDef  *fd=new FileDef(fi.dirPath(TRUE)+"/",name);
       
  8766               FileName *fn=0;
       
  8767               if (!name.isEmpty() && (fn=(*fnDict)[name]))
       
  8768               {
       
  8769                 fn->append(fd);
       
  8770               }
       
  8771               else
       
  8772               {
       
  8773                 fn = new FileName(fi.absFilePath(),name);
       
  8774                 fn->append(fd);
       
  8775                 if (fnList) fnList->inSort(fn);
       
  8776                 fnDict->insert(name,fn);
       
  8777               }
       
  8778             }
       
  8779             QCString *rs=0;
       
  8780             if (resultList || resultDict)
       
  8781             {
       
  8782               rs=new QCString(fi.absFilePath());
       
  8783               if (resultList) resultList->append(rs);
       
  8784               if (resultDict) resultDict->insert(fi.absFilePath(),rs);
       
  8785             }
       
  8786 
       
  8787             if (killDict) killDict->insert(fi.absFilePath(),(void *)0x8);
       
  8788           }
       
  8789         }
       
  8790         else if (fi.isDir()) // readable dir
       
  8791         {
       
  8792           totalSize+=readDir(&fi,fnList,fnDict,exclDict,patList,
       
  8793               exclPatList,resultList,resultDict,errorIfNotExist,
       
  8794               recursive,killDict);
       
  8795         }
       
  8796       }
       
  8797     }
       
  8798   }
       
  8799   return totalSize;
       
  8800 }
       
  8801 
       
  8802 //----------------------------------------------------------------------------
       
  8803 
       
  8804 void readFormulaRepository()
       
  8805 {
       
  8806   QFile f(Config_getString("HTML_OUTPUT")+"/formula.repository");
       
  8807   if (f.open(IO_ReadOnly)) // open repository
       
  8808   {
       
  8809     msg("Reading formula repository...\n");
       
  8810     QTextStream t(&f);
       
  8811     QCString line;
       
  8812     while (!t.eof())
       
  8813     {
       
  8814       line=t.readLine();
       
  8815       int se=line.find(':'); // find name and text separator.
       
  8816       if (se==-1)
       
  8817       {
       
  8818         err("Warning: formula.repository is corrupted!\n");
       
  8819         break;
       
  8820       }
       
  8821       else
       
  8822       {
       
  8823         QCString formName = line.left(se);
       
  8824         QCString formText = line.right(line.length()-se-1); 
       
  8825         Formula *f=new Formula(formText);
       
  8826         Doxygen::formulaList.append(f);
       
  8827         Doxygen::formulaDict.insert(formText,f);
       
  8828         Doxygen::formulaNameDict.insert(formName,f);
       
  8829       }
       
  8830     }
       
  8831   }
       
  8832 }
       
  8833 
       
  8834 //----------------------------------------------------------------------------
       
  8835 
       
  8836 static void expandAliases()
       
  8837 {
       
  8838   QDictIterator<QCString> adi(Doxygen::aliasDict);
       
  8839   QCString *s;
       
  8840   for (adi.toFirst();(s=adi.current());++adi)
       
  8841   {
       
  8842     *s = expandAlias(adi.currentKey(),*s);
       
  8843   }
       
  8844 }
       
  8845 
       
  8846 //----------------------------------------------------------------------------
       
  8847 
       
  8848 static void escapeAliases()
       
  8849 {
       
  8850   QDictIterator<QCString> adi(Doxygen::aliasDict);
       
  8851   QCString *s;
       
  8852   for (adi.toFirst();(s=adi.current());++adi)
       
  8853   {
       
  8854     QCString value=*s,newValue;
       
  8855     int in,p=0;
       
  8856     // for each \n in the alias command value
       
  8857     while ((in=value.find("\\n",p))!=-1)
       
  8858     {
       
  8859       newValue+=value.mid(p,in-p);
       
  8860       // expand \n's except if \n is part of a built-in command.
       
  8861       if (value.mid(in,5)!="\\note" && 
       
  8862           value.mid(in,5)!="\\name" && 
       
  8863           value.mid(in,10)!="\\namespace" && 
       
  8864           value.mid(in,14)!="\\nosubgrouping"
       
  8865          ) 
       
  8866       {
       
  8867         newValue+="\\_linebr ";
       
  8868       }
       
  8869       else 
       
  8870       {
       
  8871         newValue+="\\n";
       
  8872       }
       
  8873       p=in+2;
       
  8874     }
       
  8875     newValue+=value.mid(p,value.length()-p);
       
  8876     *s=newValue;
       
  8877     //printf("Alias %s has value %s\n",adi.currentKey().data(),s->data());
       
  8878   }
       
  8879 }
       
  8880 
       
  8881 //----------------------------------------------------------------------------
       
  8882 
       
  8883 void readAliases()
       
  8884 { 
       
  8885   // add aliases to a dictionary
       
  8886   Doxygen::aliasDict.setAutoDelete(TRUE);
       
  8887   QStrList &aliasList = Config_getList("ALIASES");
       
  8888   const char *s=aliasList.first();
       
  8889   while (s)
       
  8890   {
       
  8891     if (Doxygen::aliasDict[s]==0)
       
  8892     {
       
  8893       QCString alias=s;
       
  8894       int i=alias.find('=');
       
  8895       if (i>0)
       
  8896       {
       
  8897         QCString name=alias.left(i).stripWhiteSpace();
       
  8898         QCString value=alias.right(alias.length()-i-1);
       
  8899         //printf("Alias: found name=`%s' value=`%s'\n",name.data(),value.data()); 
       
  8900         if (!name.isEmpty())
       
  8901         {
       
  8902           QCString *dn=Doxygen::aliasDict[name];
       
  8903           if (dn==0) // insert new alias
       
  8904           {
       
  8905             Doxygen::aliasDict.insert(name,new QCString(value));
       
  8906           }
       
  8907           else // overwrite previous alias
       
  8908           {
       
  8909             *dn=value;
       
  8910           }
       
  8911         }
       
  8912       }
       
  8913     }
       
  8914     s=aliasList.next();
       
  8915   }
       
  8916   expandAliases();
       
  8917   escapeAliases();
       
  8918 }
       
  8919 
       
  8920 //----------------------------------------------------------------------------
       
  8921 
       
  8922 static void dumpSymbol(QTextStream &t,Definition *d)
       
  8923 {
       
  8924   QCString anchor;
       
  8925   if (d->definitionType()==Definition::TypeMember)
       
  8926   {
       
  8927     MemberDef *md = (MemberDef *)d;
       
  8928     anchor=":"+md->anchor();
       
  8929   }
       
  8930   QCString scope;
       
  8931   if (d->getOuterScope() && d->getOuterScope()!=Doxygen::globalScope) 
       
  8932   {
       
  8933     scope = d->getOuterScope()->getOutputFileBase()+Doxygen::htmlFileExtension;
       
  8934   }
       
  8935   t << "REPLACE INTO symbols (symbol_id,scope_id,name,file,line) VALUES('"
       
  8936     << d->getOutputFileBase()+Doxygen::htmlFileExtension+anchor << "','"
       
  8937     << scope << "','"
       
  8938     << d->name() << "','"
       
  8939     << d->getDefFileName() << "','"
       
  8940     << d->getDefLine()
       
  8941     << "');" << endl;
       
  8942 }
       
  8943 
       
  8944 static void dumpSymbolMap()
       
  8945 { 
       
  8946   QFile f("symbols.sql");
       
  8947   if (f.open(IO_WriteOnly))
       
  8948   {
       
  8949     QTextStream t(&f);
       
  8950     QDictIterator<DefinitionIntf> di(*Doxygen::symbolMap);
       
  8951     DefinitionIntf *intf;
       
  8952     for (;(intf=di.current());++di)
       
  8953     {
       
  8954       if (intf->definitionType()==DefinitionIntf::TypeSymbolList) // list of symbols
       
  8955       {
       
  8956         DefinitionListIterator dli(*(DefinitionList*)intf);
       
  8957         Definition *d;
       
  8958         // for each symbol
       
  8959         for (dli.toFirst();(d=dli.current());++dli)
       
  8960         {
       
  8961           dumpSymbol(t,d);
       
  8962         }
       
  8963       }
       
  8964       else // single symbol
       
  8965       {
       
  8966         Definition *d = (Definition *)intf;
       
  8967         if (d!=Doxygen::globalScope) dumpSymbol(t,d);
       
  8968       }
       
  8969     }
       
  8970   }
       
  8971 }
       
  8972 
       
  8973 //----------------------------------------------------------------------------
       
  8974 
       
  8975 void dumpConfigAsXML()
       
  8976 {
       
  8977   QFile f("config.xml");
       
  8978   if (f.open(IO_WriteOnly))
       
  8979   {
       
  8980     QTextStream t(&f);
       
  8981     Config::instance()->writeXML(t);
       
  8982   }
       
  8983 }
       
  8984 
       
  8985 //----------------------------------------------------------------------------
       
  8986 // print the usage of doxygen
       
  8987 
       
  8988 static void usage(const char *name)
       
  8989 {
       
  8990   msg("Doxygen version %s\nCopyright Dimitri van Heesch 1997-2008\n\n",versionString);
       
  8991   msg("You can use doxygen in a number of ways:\n\n");
       
  8992   msg("1) Use doxygen to generate a template configuration file:\n");
       
  8993   msg("    %s [-s] -g [configName]\n\n",name);
       
  8994   msg("    If - is used for configName doxygen will write to standard output.\n\n");
       
  8995   msg("2) Use doxygen to update an old configuration file:\n");
       
  8996   msg("    %s [-s] -u [configName]\n\n",name);
       
  8997   msg("3) Use doxygen to generate documentation using an existing ");
       
  8998   msg("configuration file:\n");
       
  8999   msg("    %s [configName]\n\n",name);
       
  9000   msg("    If - is used for configName doxygen will read from standard input.\n\n");
       
  9001   msg("4) Use doxygen to generate a template file controlling the layout of the\n");
       
  9002   msg("   generated documentation:\n");
       
  9003   msg("    %s -l layoutFileName.xml\n\n",name);
       
  9004   msg("5) Use doxygen to generate a template style sheet file for RTF, HTML or Latex.\n");
       
  9005   msg("    RTF:   %s -w rtf styleSheetFile\n",name);
       
  9006   msg("    HTML:  %s -w html headerFile footerFile styleSheetFile [configFile]\n",name);
       
  9007   msg("    LaTeX: %s -w latex headerFile styleSheetFile [configFile]\n\n",name);
       
  9008   msg("6) Use doxygen to generate an rtf extensions file\n");
       
  9009   msg("    RTF:   %s -e rtf extensionsFile\n\n",name);
       
  9010   msg("If -s is specified the comments in the config file will be omitted.\n");
       
  9011   msg("If configName is omitted `Doxyfile' will be used as a default.\n\n");
       
  9012   exit(1);
       
  9013 }
       
  9014 
       
  9015 //----------------------------------------------------------------------------
       
  9016 // read the argument of option `c' from the comment argument list and
       
  9017 // update the option index `optind'.
       
  9018 
       
  9019 static const char *getArg(int argc,char **argv,int &optind)
       
  9020 {
       
  9021   char *s=0;
       
  9022   if (strlen(&argv[optind][2])>0)
       
  9023     s=&argv[optind][2];
       
  9024   else if (optind+1<argc && argv[optind+1][0]!='-')
       
  9025     s=argv[++optind];
       
  9026   return s;
       
  9027 }
       
  9028 
       
  9029 //----------------------------------------------------------------------------
       
  9030 
       
  9031 extern void commentScanTest();
       
  9032 
       
  9033 void initDoxygen()
       
  9034 {
       
  9035   setlocale(LC_ALL,"");
       
  9036   setlocale(LC_CTYPE,"C"); // to get isspace(0xA0)==0, needed for UTF-8
       
  9037   setlocale(LC_NUMERIC,"C");
       
  9038 
       
  9039   //Doxygen::symbolMap->setAutoDelete(TRUE);
       
  9040 
       
  9041   Doxygen::runningTime.start();
       
  9042   initPreprocessor();
       
  9043 
       
  9044   Doxygen::parserManager = new ParserManager;
       
  9045   Doxygen::parserManager->registerParser("c",       new CLanguageScanner, TRUE);
       
  9046   Doxygen::parserManager->registerParser("python",  new PythonLanguageScanner);
       
  9047   Doxygen::parserManager->registerParser("fortran", new FortranLanguageScanner);
       
  9048   Doxygen::parserManager->registerParser("vhdl",    new VHDLLanguageScanner);
       
  9049   Doxygen::parserManager->registerParser("dbusxml", new DBusXMLScanner);
       
  9050 
       
  9051   // register any additional parsers here...
       
  9052 
       
  9053   initDefaultExtensionMapping();
       
  9054   initClassMemberIndices();
       
  9055   initNamespaceMemberIndices();
       
  9056   initFileMemberIndices();
       
  9057 
       
  9058   Doxygen::symbolMap     = new QDict<DefinitionIntf>(1000);
       
  9059   Doxygen::inputNameList = new FileNameList;
       
  9060   Doxygen::inputNameList->setAutoDelete(TRUE);
       
  9061   Doxygen::memberNameSDict = new MemberNameSDict(10000);   
       
  9062   Doxygen::memberNameSDict->setAutoDelete(TRUE);
       
  9063   Doxygen::functionNameSDict = new MemberNameSDict(10000);   
       
  9064   Doxygen::functionNameSDict->setAutoDelete(TRUE);
       
  9065   Doxygen::groupSDict = new GroupSDict(17);          
       
  9066   Doxygen::groupSDict->setAutoDelete(TRUE);
       
  9067   Doxygen::globalScope = new NamespaceDef("<globalScope>",1,"<globalScope>");
       
  9068   Doxygen::namespaceSDict = new NamespaceSDict(20);      
       
  9069   Doxygen::namespaceSDict->setAutoDelete(TRUE);
       
  9070   Doxygen::classSDict = new ClassSDict(1009);         
       
  9071   Doxygen::classSDict->setAutoDelete(TRUE);
       
  9072   Doxygen::hiddenClasses = new ClassSDict(257);
       
  9073   Doxygen::hiddenClasses->setAutoDelete(TRUE);
       
  9074   Doxygen::directories = new DirSDict(17);
       
  9075   Doxygen::directories->setAutoDelete(TRUE);
       
  9076   Doxygen::pageSDict = new PageSDict(1009);          // all doc pages
       
  9077   Doxygen::pageSDict->setAutoDelete(TRUE);
       
  9078   Doxygen::exampleSDict = new PageSDict(1009);       // all examples
       
  9079   Doxygen::exampleSDict->setAutoDelete(TRUE);
       
  9080   Doxygen::inputNameDict = new FileNameDict(10007);
       
  9081   Doxygen::includeNameDict = new FileNameDict(10007);
       
  9082   Doxygen::exampleNameDict = new FileNameDict(1009);
       
  9083   Doxygen::exampleNameDict->setAutoDelete(TRUE);
       
  9084   Doxygen::imageNameDict = new FileNameDict(257);
       
  9085   Doxygen::dotFileNameDict = new FileNameDict(257);
       
  9086   Doxygen::sectionDict.setAutoDelete(TRUE);
       
  9087   Doxygen::memGrpInfoDict.setAutoDelete(TRUE);
       
  9088   Doxygen::tagDestinationDict.setAutoDelete(TRUE);
       
  9089   Doxygen::lookupCache.setAutoDelete(TRUE);
       
  9090   Doxygen::dirRelations.setAutoDelete(TRUE);
       
  9091 }
       
  9092 
       
  9093 void cleanUpDoxygen()
       
  9094 {
       
  9095   delete Doxygen::inputNameDict;
       
  9096   delete Doxygen::includeNameDict;
       
  9097   delete Doxygen::exampleNameDict;
       
  9098   delete Doxygen::imageNameDict;
       
  9099   delete Doxygen::dotFileNameDict;
       
  9100   delete Doxygen::mainPage;
       
  9101   delete Doxygen::pageSDict;  
       
  9102   delete Doxygen::exampleSDict;
       
  9103   delete Doxygen::globalScope;
       
  9104   delete Doxygen::xrefLists;
       
  9105   delete Doxygen::parserManager;
       
  9106   cleanUpPreprocessor();
       
  9107   delete theTranslator;
       
  9108   delete g_outputList;
       
  9109   Mappers::freeMappers();
       
  9110   codeFreeScanner();
       
  9111 
       
  9112   if (Doxygen::symbolMap)
       
  9113   {
       
  9114     // iterate through Doxygen::symbolMap and delete all
       
  9115     // DefinitionList objects, since they have no owner
       
  9116     QDictIterator<DefinitionIntf> dli(*Doxygen::symbolMap);
       
  9117     DefinitionIntf *di;
       
  9118     for (dli.toFirst();(di=dli.current());)
       
  9119     {
       
  9120       if (di->definitionType()==DefinitionIntf::TypeSymbolList)
       
  9121       {
       
  9122         DefinitionIntf *tmp = Doxygen::symbolMap->take(dli.currentKey());
       
  9123         delete (DefinitionList *)tmp;
       
  9124       }
       
  9125       else
       
  9126       {
       
  9127         ++dli;
       
  9128       }
       
  9129     } 
       
  9130   }
       
  9131 
       
  9132   delete Doxygen::inputNameList;
       
  9133   delete Doxygen::memberNameSDict;
       
  9134   delete Doxygen::functionNameSDict;
       
  9135   delete Doxygen::groupSDict;
       
  9136   delete Doxygen::classSDict;
       
  9137   delete Doxygen::hiddenClasses;
       
  9138   delete Doxygen::namespaceSDict;
       
  9139   delete Doxygen::directories;
       
  9140 
       
  9141   //delete Doxygen::symbolMap; <- we cannot do this unless all static lists 
       
  9142   //                              (such as Doxygen::namespaceSDict)
       
  9143   //                              with objects based on Definition are made
       
  9144   //                              dynamic first
       
  9145 }
       
  9146 
       
  9147 void readConfiguration(int argc, char **argv)
       
  9148 {
       
  9149   /**************************************************************************
       
  9150    *             Handle arguments                                           *
       
  9151    **************************************************************************/
       
  9152 
       
  9153   int optind=1;
       
  9154   const char *configName=0;
       
  9155   const char *layoutName=0;
       
  9156   const char *debugLabel;
       
  9157   const char *formatName;
       
  9158   bool genConfig=FALSE;
       
  9159   bool shortList=FALSE;
       
  9160   bool updateConfig=FALSE;
       
  9161   bool genLayout=FALSE;
       
  9162   while (optind<argc && argv[optind][0]=='-' && 
       
  9163                (isalpha(argv[optind][1]) || argv[optind][1]=='?' || 
       
  9164                 argv[optind][1]=='-')
       
  9165         )
       
  9166   {
       
  9167     switch(argv[optind][1])
       
  9168     {
       
  9169       case 'g':
       
  9170         genConfig=TRUE;
       
  9171         configName=getArg(argc,argv,optind);
       
  9172         if (strcmp(argv[optind+1],"-")==0)
       
  9173         { configName="-"; optind++; }
       
  9174         if (!configName) 
       
  9175         { configName="Doxyfile"; }
       
  9176         break;
       
  9177       case 'l':
       
  9178         genLayout=TRUE;
       
  9179         layoutName=getArg(argc,argv,optind);
       
  9180         if (!layoutName)
       
  9181         { layoutName="DoxygenLayout.xml"; }
       
  9182         break;
       
  9183       case 'd':
       
  9184         debugLabel=getArg(argc,argv,optind);
       
  9185         Debug::setFlag(debugLabel);
       
  9186         break;
       
  9187       case 's':
       
  9188         shortList=TRUE;
       
  9189         break;
       
  9190       case 'u':
       
  9191         updateConfig=TRUE;
       
  9192         break;
       
  9193       case 'e':
       
  9194         formatName=getArg(argc,argv,optind);
       
  9195         if (!formatName)
       
  9196         {
       
  9197           err("Error:option -e is missing format specifier rtf.\n");
       
  9198           cleanUpDoxygen();
       
  9199           exit(1);
       
  9200         }
       
  9201         if (stricmp(formatName,"rtf")==0)
       
  9202         {
       
  9203           if (optind+1>=argc)
       
  9204           {
       
  9205             err("Error: option \"-e rtf\" is missing an extensions file name\n");
       
  9206             cleanUpDoxygen();
       
  9207             exit(1);
       
  9208           }
       
  9209           QFile f;
       
  9210           if (openOutputFile(argv[optind+1],f))
       
  9211           {
       
  9212             RTFGenerator::writeExtensionsFile(f);
       
  9213           }
       
  9214           cleanUpDoxygen();
       
  9215           exit(1);
       
  9216         }
       
  9217         err("Error: option \"-e\" has invalid format specifier.\n");
       
  9218         cleanUpDoxygen();
       
  9219         exit(1);
       
  9220         break; 
       
  9221       case 'w':
       
  9222         formatName=getArg(argc,argv,optind);
       
  9223         if (!formatName)
       
  9224         {
       
  9225           err("Error: option -w is missing format specifier rtf, html or latex\n");
       
  9226           cleanUpDoxygen();
       
  9227           exit(1);
       
  9228         } 
       
  9229         if (stricmp(formatName,"rtf")==0)
       
  9230         {
       
  9231           if (optind+1>=argc)
       
  9232           {
       
  9233             err("Error: option \"-w rtf\" is missing a style sheet file name\n");
       
  9234             cleanUpDoxygen();
       
  9235             exit(1);
       
  9236           }
       
  9237           QFile f;
       
  9238           if (openOutputFile(argv[optind+1],f))
       
  9239           {
       
  9240             RTFGenerator::writeStyleSheetFile(f);
       
  9241           }
       
  9242           cleanUpDoxygen();
       
  9243           exit(1);
       
  9244         }
       
  9245         else if (stricmp(formatName,"html")==0)
       
  9246         {
       
  9247           if (optind+4<argc)
       
  9248           {
       
  9249             if (!Config::instance()->parse(argv[optind+4]))
       
  9250             {
       
  9251               err("Error opening or reading configuration file %s!\n",argv[optind+4]);
       
  9252               cleanUpDoxygen();
       
  9253               exit(1);
       
  9254             }
       
  9255             Config::instance()->substituteEnvironmentVars();
       
  9256             Config::instance()->convertStrToVal();
       
  9257             Config::instance()->check();
       
  9258           }
       
  9259           else
       
  9260           {
       
  9261             Config::instance()->init();
       
  9262           }
       
  9263           if (optind+3>=argc)
       
  9264           {
       
  9265             err("Error: option \"-w html\" does not have enough arguments\n");
       
  9266             cleanUpDoxygen();
       
  9267             exit(1);
       
  9268           }
       
  9269 
       
  9270           QCString outputLanguage=Config_getEnum("OUTPUT_LANGUAGE");
       
  9271           if (!setTranslator(outputLanguage))
       
  9272           {
       
  9273             err("Warning: Output language %s not supported! Using English instead.\n", outputLanguage.data());
       
  9274           }
       
  9275 
       
  9276           QFile f;
       
  9277           if (openOutputFile(argv[optind+1],f))
       
  9278           {
       
  9279             HtmlGenerator::writeHeaderFile(f);
       
  9280           }
       
  9281           f.close();
       
  9282           if (openOutputFile(argv[optind+2],f))
       
  9283           {
       
  9284             HtmlGenerator::writeFooterFile(f);
       
  9285           }
       
  9286           f.close();
       
  9287           if (openOutputFile(argv[optind+3],f))
       
  9288           {
       
  9289             HtmlGenerator::writeStyleSheetFile(f);
       
  9290           } 
       
  9291           cleanUpDoxygen();
       
  9292           exit(0);
       
  9293         }
       
  9294         else if (stricmp(formatName,"latex")==0)
       
  9295         {
       
  9296           if (optind+3<argc) // use config file to get settings
       
  9297           {
       
  9298             if (!Config::instance()->parse(argv[optind+3]))
       
  9299             {
       
  9300               err("Error opening or reading configuration file %s!\n",argv[optind+3]);
       
  9301               exit(1);
       
  9302             }
       
  9303             Config::instance()->substituteEnvironmentVars();
       
  9304             Config::instance()->convertStrToVal();
       
  9305             Config::instance()->check();
       
  9306           }
       
  9307           else // use default config
       
  9308           {
       
  9309             Config::instance()->init();
       
  9310           }
       
  9311           if (optind+2>=argc)
       
  9312           {
       
  9313             err("Error: option \"-w latex\" does not have enough arguments\n");
       
  9314             cleanUpDoxygen();
       
  9315             exit(1);
       
  9316           }
       
  9317 
       
  9318           QCString outputLanguage=Config_getEnum("OUTPUT_LANGUAGE");
       
  9319           if (!setTranslator(outputLanguage))
       
  9320           {
       
  9321             err("Warning: Output language %s not supported! Using English instead.\n", outputLanguage.data());
       
  9322           }
       
  9323 
       
  9324           QFile f;
       
  9325           if (openOutputFile(argv[optind+1],f))
       
  9326           {
       
  9327             LatexGenerator::writeHeaderFile(f);
       
  9328           }
       
  9329           f.close();
       
  9330           if (openOutputFile(argv[optind+2],f))
       
  9331           {
       
  9332             LatexGenerator::writeStyleSheetFile(f);
       
  9333           }
       
  9334           cleanUpDoxygen();
       
  9335           exit(0);
       
  9336         }
       
  9337         else 
       
  9338         {
       
  9339           err("Error: Illegal format specifier %s: should be one of rtf, html, or latex\n",formatName);
       
  9340           cleanUpDoxygen();
       
  9341           exit(1);
       
  9342         }
       
  9343         break;
       
  9344       case 'm':
       
  9345         g_dumpSymbolMap = TRUE;
       
  9346         break;
       
  9347       case 'x':
       
  9348         g_dumpConfigAsXML = TRUE;
       
  9349         break;
       
  9350       case '-':
       
  9351         if (strcmp(&argv[optind][2],"help")==0)
       
  9352         {
       
  9353           usage(argv[0]);
       
  9354         }
       
  9355         else if (strcmp(&argv[optind][2],"version")==0)
       
  9356         {
       
  9357           msg("%s\n",versionString); 
       
  9358           cleanUpDoxygen();
       
  9359           exit(0);
       
  9360         }
       
  9361         break;
       
  9362       case 'b':
       
  9363         setvbuf(stdout,NULL,_IONBF,0);
       
  9364         Doxygen::outputToWizard=TRUE;
       
  9365         break;
       
  9366       case 'h':
       
  9367       case '?':
       
  9368         usage(argv[0]);
       
  9369         break;
       
  9370       default:
       
  9371         err("Unknown option -%c\n",argv[optind][1]);
       
  9372         usage(argv[0]);
       
  9373     }
       
  9374     optind++;
       
  9375   }
       
  9376   
       
  9377   /**************************************************************************
       
  9378    *            Parse or generate the config file                           *
       
  9379    **************************************************************************/
       
  9380 
       
  9381   Config::instance()->init();
       
  9382 
       
  9383   if (genConfig)
       
  9384   {
       
  9385     if (g_dumpConfigAsXML)
       
  9386     {
       
  9387       checkConfiguration();
       
  9388       generateConfigFile(configName,shortList);
       
  9389       dumpConfigAsXML();
       
  9390       exit(0); 
       
  9391     }
       
  9392     else
       
  9393     {
       
  9394       generateConfigFile(configName,shortList);
       
  9395     }
       
  9396     cleanUpDoxygen();
       
  9397     exit(0);
       
  9398   }
       
  9399   if (genLayout)
       
  9400   {
       
  9401     writeDefaultLayoutFile(layoutName);
       
  9402     cleanUpDoxygen();
       
  9403     exit(0);
       
  9404   }
       
  9405 
       
  9406   QFileInfo configFileInfo1("Doxyfile"),configFileInfo2("doxyfile");
       
  9407   if (optind>=argc)
       
  9408   { 
       
  9409     if (configFileInfo1.exists()) 
       
  9410     {
       
  9411       configName="Doxyfile";
       
  9412     }
       
  9413     else if (configFileInfo2.exists())
       
  9414     {
       
  9415       configName="doxyfile";
       
  9416     }
       
  9417     else
       
  9418     {
       
  9419       err("Doxyfile not found and no input file specified!\n");
       
  9420       usage(argv[0]);
       
  9421     }
       
  9422   }
       
  9423   else
       
  9424   {
       
  9425     QFileInfo fi(argv[optind]);
       
  9426     if (fi.exists() || strcmp(argv[optind],"-")==0)
       
  9427     {
       
  9428       configName=argv[optind];
       
  9429     }
       
  9430     else
       
  9431     {
       
  9432       err("Error: configuration file %s not found!\n",argv[optind]);
       
  9433       usage(argv[0]);
       
  9434     }
       
  9435   }
       
  9436 
       
  9437 
       
  9438   if (!Config::instance()->parse(configName))
       
  9439   {
       
  9440     err("Error: could not open or read configuration file %s!\n",configName);
       
  9441     cleanUpDoxygen();
       
  9442     exit(1);
       
  9443   }
       
  9444 
       
  9445   if (updateConfig)
       
  9446   {
       
  9447     generateConfigFile(configName,shortList,TRUE);
       
  9448     cleanUpDoxygen();
       
  9449     exit(0);
       
  9450   }
       
  9451 
       
  9452   /* Perlmod wants to know the path to the config file.*/
       
  9453   QFileInfo configFileInfo(configName);
       
  9454   setPerlModDoxyfile(configFileInfo.absFilePath());
       
  9455 
       
  9456 }
       
  9457 
       
  9458 /** check and resolve config options */
       
  9459 void checkConfiguration()
       
  9460 {
       
  9461   
       
  9462   Config::instance()->substituteEnvironmentVars();
       
  9463   Config::instance()->convertStrToVal();
       
  9464   Config::instance()->check();
       
  9465   
       
  9466   initWarningFormat();
       
  9467 }
       
  9468 
       
  9469 /** adjust globals that depend on configuration settings. */
       
  9470 void adjustConfiguration()
       
  9471 {
       
  9472   QCString outputLanguage=Config_getEnum("OUTPUT_LANGUAGE");
       
  9473   if (!setTranslator(outputLanguage))
       
  9474   {
       
  9475     err("Warning: Output language %s not supported! Using English instead.\n",
       
  9476        outputLanguage.data());
       
  9477   }
       
  9478   QStrList &includePath = Config_getList("INCLUDE_PATH");
       
  9479   char *s=includePath.first();
       
  9480   while (s)
       
  9481   {
       
  9482     QFileInfo fi(s);
       
  9483     addSearchDir(fi.absFilePath());
       
  9484     s=includePath.next();
       
  9485   }
       
  9486 
       
  9487   /* Set the global html file extension. */ 
       
  9488   Doxygen::htmlFileExtension = Config_getString("HTML_FILE_EXTENSION");
       
  9489 
       
  9490 
       
  9491   Doxygen::xrefLists->setAutoDelete(TRUE);
       
  9492 
       
  9493   Doxygen::parseSourcesNeeded = Config_getBool("CALL_GRAPH") || 
       
  9494                                 Config_getBool("CALLER_GRAPH") ||
       
  9495                                 Config_getBool("REFERENCES_RELATION") ||
       
  9496                                 Config_getBool("REFERENCED_BY_RELATION");
       
  9497   
       
  9498   /**************************************************************************
       
  9499    *            Add custom extension mappings
       
  9500    **************************************************************************/
       
  9501 
       
  9502   QStrList &extMaps = Config_getList("EXTENSION_MAPPING");
       
  9503   char *mapping = extMaps.first();
       
  9504   while (mapping)
       
  9505   {
       
  9506     QCString mapStr = mapping;
       
  9507     int i;
       
  9508     if ((i=mapStr.find('='))!=-1)
       
  9509     {
       
  9510       QCString ext=mapStr.left(i).stripWhiteSpace().lower();
       
  9511       QCString language=mapStr.mid(i+1).stripWhiteSpace().lower();
       
  9512       if (!updateLanguageMapping(ext,language))
       
  9513       {
       
  9514         err("Failed to map file extension '%s' to unsupported language '%s'.\n"
       
  9515             "Check the EXTENSION_MAPPING setting in the config file.\n", 
       
  9516             ext.data(),language.data());
       
  9517       }
       
  9518       else
       
  9519       {
       
  9520         msg("Adding custom extension mapping: .%s will be treated as language %s\n",
       
  9521             ext.data(),language.data());
       
  9522       }
       
  9523     }
       
  9524     mapping = extMaps.next();
       
  9525   }
       
  9526 
       
  9527 
       
  9528   // add predefined macro name to a dictionary
       
  9529   QStrList &expandAsDefinedList =Config_getList("EXPAND_AS_DEFINED");
       
  9530   s=expandAsDefinedList.first();
       
  9531   while (s)
       
  9532   {
       
  9533     if (Doxygen::expandAsDefinedDict[s]==0)
       
  9534     {
       
  9535       Doxygen::expandAsDefinedDict.insert(s,(void *)666);
       
  9536     }
       
  9537     s=expandAsDefinedList.next();
       
  9538   }
       
  9539 
       
  9540   // read aliases and store them in a dictionary
       
  9541   readAliases();
       
  9542 
       
  9543   // store number of spaces in a tab into Doxygen::spaces
       
  9544   int &tabSize = Config_getInt("TAB_SIZE");
       
  9545   Doxygen::spaces.resize(tabSize+1);
       
  9546   int sp;for (sp=0;sp<tabSize;sp++) Doxygen::spaces.at(sp)=' ';
       
  9547   Doxygen::spaces.at(tabSize)='\0';
       
  9548 }
       
  9549 
       
  9550 #ifdef HAS_SIGNALS
       
  9551 static void stopDoxygen(int)
       
  9552 {
       
  9553   QDir thisDir;
       
  9554   msg("Cleaning up...\n");
       
  9555   if (!Doxygen::entryDBFileName.isEmpty())
       
  9556   {
       
  9557     thisDir.remove(Doxygen::entryDBFileName);
       
  9558   }
       
  9559   if (!Doxygen::objDBFileName.isEmpty())
       
  9560   {
       
  9561     thisDir.remove(Doxygen::objDBFileName);
       
  9562   }
       
  9563   exit(1);
       
  9564 }
       
  9565 #endif
       
  9566 
       
  9567 static void exitDoxygen()
       
  9568 {
       
  9569   if (!g_successfulRun)  // premature exit
       
  9570   {
       
  9571     QDir thisDir;
       
  9572     msg("Exiting...\n");
       
  9573     if (!Doxygen::entryDBFileName.isEmpty())
       
  9574     {
       
  9575       thisDir.remove(Doxygen::entryDBFileName);
       
  9576     }
       
  9577     if (!Doxygen::objDBFileName.isEmpty())
       
  9578     {
       
  9579       thisDir.remove(Doxygen::objDBFileName);
       
  9580     }
       
  9581   }
       
  9582 }
       
  9583 
       
  9584 static QCString createOutputDirectory(const QCString &baseDirName,
       
  9585                                   const char *formatDirOption,
       
  9586                                   const char *defaultDirName)
       
  9587 {
       
  9588   // Note the & on the next line, we modify the formatDirOption!
       
  9589   QCString &formatDirName = Config_getString(formatDirOption);
       
  9590   if (formatDirName.isEmpty())
       
  9591   {
       
  9592     formatDirName = baseDirName + defaultDirName;
       
  9593   }
       
  9594   else if (formatDirName[0]!='/' && (formatDirName.length()==1 || formatDirName[1]!=':'))
       
  9595   {
       
  9596     formatDirName.prepend(baseDirName+'/');
       
  9597   }
       
  9598   QDir formatDir(formatDirName);
       
  9599   if (!formatDir.exists() && !formatDir.mkdir(formatDirName))
       
  9600   {
       
  9601     err("Could not create output directory %s\n", formatDirName.data());
       
  9602     cleanUpDoxygen();
       
  9603     exit(1);
       
  9604   }
       
  9605   return formatDirName;
       
  9606 }
       
  9607 
       
  9608 static QCString getQchFileName()
       
  9609 {
       
  9610   QCString const & qchFile = Config_getString("QCH_FILE");
       
  9611   if (!qchFile.isEmpty())
       
  9612   {
       
  9613     return qchFile;
       
  9614   }
       
  9615 
       
  9616   QCString const & projectName = Config_getString("PROJECT_NAME");
       
  9617   QCString const & versionText = Config_getString("PROJECT_NUMBER");
       
  9618 
       
  9619   return QCString("../qch/")
       
  9620       + (projectName.isEmpty() ? QCString("index") : projectName)
       
  9621       + (versionText.isEmpty() ? QCString("") : QCString("-") + versionText)
       
  9622       + QCString(".qch");
       
  9623 }
       
  9624 
       
  9625 void searchInputFiles(StringList &inputFiles)
       
  9626 {
       
  9627   QStrList &exclPatterns = Config_getList("EXCLUDE_PATTERNS");
       
  9628   bool alwaysRecursive = Config_getBool("RECURSIVE");
       
  9629   StringDict excludeNameDict(1009);
       
  9630   excludeNameDict.setAutoDelete(TRUE);
       
  9631 
       
  9632   // gather names of all files in the include path
       
  9633   msg("Searching for include files...\n");
       
  9634   QStrList &includePathList = Config_getList("INCLUDE_PATH");
       
  9635   char *s=includePathList.first();
       
  9636   while (s)
       
  9637   {
       
  9638     QStrList &pl = Config_getList("INCLUDE_FILE_PATTERNS");
       
  9639     if (pl.count()==0) 
       
  9640     {
       
  9641       pl = Config_getList("FILE_PATTERNS");
       
  9642     }
       
  9643     readFileOrDirectory(s,0,Doxygen::includeNameDict,0,&pl,
       
  9644                         &exclPatterns,0,0,
       
  9645                         alwaysRecursive);
       
  9646     s=includePathList.next(); 
       
  9647   }
       
  9648   
       
  9649   msg("Searching for example files...\n");
       
  9650   QStrList &examplePathList = Config_getList("EXAMPLE_PATH");
       
  9651   s=examplePathList.first();
       
  9652   while (s)
       
  9653   {
       
  9654     readFileOrDirectory(s,0,Doxygen::exampleNameDict,0,
       
  9655                         &Config_getList("EXAMPLE_PATTERNS"),
       
  9656                         0,0,0,
       
  9657                         (alwaysRecursive || Config_getBool("EXAMPLE_RECURSIVE")));
       
  9658     s=examplePathList.next(); 
       
  9659   }
       
  9660 
       
  9661   msg("Searching for images...\n");
       
  9662   QStrList &imagePathList=Config_getList("IMAGE_PATH");
       
  9663   s=imagePathList.first();
       
  9664   while (s)
       
  9665   {
       
  9666     readFileOrDirectory(s,0,Doxygen::imageNameDict,0,0,
       
  9667                         0,0,0,
       
  9668                         alwaysRecursive);
       
  9669     s=imagePathList.next(); 
       
  9670   }
       
  9671 
       
  9672   msg("Searching for dot files...\n");
       
  9673   QStrList &dotFileList=Config_getList("DOTFILE_DIRS");
       
  9674   s=dotFileList.first();
       
  9675   while (s)
       
  9676   {
       
  9677     readFileOrDirectory(s,0,Doxygen::dotFileNameDict,0,0,
       
  9678                         0,0,0,
       
  9679                         alwaysRecursive);
       
  9680     s=dotFileList.next(); 
       
  9681   }
       
  9682 
       
  9683   msg("Searching for files to exclude\n");
       
  9684   QStrList &excludeList = Config_getList("EXCLUDE");
       
  9685   s=excludeList.first();
       
  9686   while (s)
       
  9687   {
       
  9688     readFileOrDirectory(s,0,0,0,&Config_getList("FILE_PATTERNS"),
       
  9689                         0,0,&excludeNameDict,
       
  9690                         alwaysRecursive,
       
  9691                         FALSE);
       
  9692     s=excludeList.next();
       
  9693   }
       
  9694 
       
  9695   /**************************************************************************
       
  9696    *             Determine Input Files                                      *
       
  9697    **************************************************************************/
       
  9698 
       
  9699   msg("Searching for files to process...\n");
       
  9700   QDict<void> *killDict = new QDict<void>(10007);
       
  9701   int inputSize=0;
       
  9702   QStrList &inputList=Config_getList("INPUT");
       
  9703   inputFiles.setAutoDelete(TRUE);
       
  9704   s=inputList.first();
       
  9705   while (s)
       
  9706   {
       
  9707     QCString path=s;
       
  9708     uint l = path.length();
       
  9709     // strip trailing slashes
       
  9710     if (path.at(l-1)=='\\' || path.at(l-1)=='/') path=path.left(l-1);
       
  9711 
       
  9712     inputSize+=readFileOrDirectory(
       
  9713         path,
       
  9714         Doxygen::inputNameList,
       
  9715         Doxygen::inputNameDict,
       
  9716         &excludeNameDict,
       
  9717         &Config_getList("FILE_PATTERNS"),
       
  9718         &exclPatterns,
       
  9719         &inputFiles,0,
       
  9720         alwaysRecursive,
       
  9721         TRUE,
       
  9722         killDict);
       
  9723     s=inputList.next();
       
  9724   }
       
  9725   delete killDict;
       
  9726 }
       
  9727 
       
  9728   
       
  9729 void parseInput()
       
  9730 {
       
  9731   atexit(exitDoxygen);
       
  9732 
       
  9733 
       
  9734   /**************************************************************************
       
  9735    *            Make sure the output directory exists
       
  9736    **************************************************************************/
       
  9737   QCString &outputDirectory = Config_getString("OUTPUT_DIRECTORY");
       
  9738   if (outputDirectory.isEmpty()) 
       
  9739   {
       
  9740     outputDirectory=QDir::currentDirPath();
       
  9741   }
       
  9742   else
       
  9743   {
       
  9744     QDir dir(outputDirectory);
       
  9745     if (!dir.exists())
       
  9746     {
       
  9747       dir.setPath(QDir::currentDirPath());
       
  9748       if (!dir.mkdir(outputDirectory))
       
  9749       {
       
  9750         err("Error: tag OUTPUT_DIRECTORY: Output directory `%s' does not "
       
  9751 	    "exist and cannot be created\n",outputDirectory.data());
       
  9752         cleanUpDoxygen();
       
  9753         exit(1);
       
  9754       }
       
  9755       else if (!Config_getBool("QUIET"))
       
  9756       {
       
  9757 	err("Notice: Output directory `%s' does not exist. "
       
  9758 	    "I have created it for you.\n", outputDirectory.data());
       
  9759       }
       
  9760       dir.cd(outputDirectory);
       
  9761     }
       
  9762     outputDirectory=dir.absPath();
       
  9763   }
       
  9764 
       
  9765   /**************************************************************************
       
  9766    *            Initialize global lists and dictionaries
       
  9767    **************************************************************************/
       
  9768 
       
  9769   int cacheSize = Config_getInt("SYMBOL_CACHE_SIZE");
       
  9770   if (cacheSize<0) cacheSize=0;
       
  9771   if (cacheSize>9) cacheSize=9;
       
  9772   Doxygen::symbolCache   = new ObjCache(16+cacheSize); // 16 -> room for 65536 elements, 
       
  9773                                                 //       ~2.0 MByte "overhead"
       
  9774   Doxygen::symbolStorage = new Store;
       
  9775 
       
  9776 #ifdef HAS_SIGNALS
       
  9777   signal(SIGINT, stopDoxygen);
       
  9778 #endif
       
  9779 
       
  9780   uint pid = portable_pid();
       
  9781   Doxygen::objDBFileName.sprintf("doxygen_objdb_%d.tmp",pid);
       
  9782   Doxygen::objDBFileName.prepend(outputDirectory+"/");
       
  9783   Doxygen::entryDBFileName.sprintf("doxygen_entrydb_%d.tmp",pid);
       
  9784   Doxygen::entryDBFileName.prepend(outputDirectory+"/");
       
  9785   
       
  9786   if (Doxygen::symbolStorage->open(Doxygen::objDBFileName)==-1)
       
  9787   {
       
  9788     err("Failed to open temporary file %s\n",Doxygen::objDBFileName.data());
       
  9789     exit(1);
       
  9790   }
       
  9791 
       
  9792 
       
  9793   /**************************************************************************
       
  9794    *            Initialize some global constants
       
  9795    **************************************************************************/
       
  9796   
       
  9797   g_compoundKeywordDict.insert("template class",(void *)8);
       
  9798   g_compoundKeywordDict.insert("template struct",(void *)8);
       
  9799   g_compoundKeywordDict.insert("class",(void *)8);
       
  9800   g_compoundKeywordDict.insert("struct",(void *)8);
       
  9801   g_compoundKeywordDict.insert("union",(void *)8);
       
  9802   g_compoundKeywordDict.insert("interface",(void *)8);
       
  9803   g_compoundKeywordDict.insert("exception",(void *)8);
       
  9804 
       
  9805 
       
  9806   /**************************************************************************
       
  9807    *            Check/create output directorties                            *
       
  9808    **************************************************************************/
       
  9809 
       
  9810   QCString htmlOutput;
       
  9811   bool &generateHtml = Config_getBool("GENERATE_HTML");
       
  9812   if (generateHtml)
       
  9813     htmlOutput = createOutputDirectory(outputDirectory,"HTML_OUTPUT","/html");
       
  9814 
       
  9815   QCString xmlOutput;
       
  9816   bool &generateXml = Config_getBool("GENERATE_XML");
       
  9817   if (generateXml)
       
  9818     xmlOutput = createOutputDirectory(outputDirectory,"XML_OUTPUT","/xml");
       
  9819     
       
  9820   QCString xmlDitaOutput;
       
  9821   bool &generateXmlDita = Config_getBool("GENERATE_XML_DITA");
       
  9822   if (generateXmlDita)
       
  9823     xmlDitaOutput = createOutputDirectory(outputDirectory,"XML_DITA_OUTPUT","/dita");
       
  9824 
       
  9825   QCString latexOutput;
       
  9826   bool &generateLatex = Config_getBool("GENERATE_LATEX");
       
  9827   if (generateLatex)
       
  9828     latexOutput = createOutputDirectory(outputDirectory,"LATEX_OUTPUT","/latex");
       
  9829 
       
  9830   QCString rtfOutput;
       
  9831   bool &generateRtf = Config_getBool("GENERATE_RTF");
       
  9832   if (generateRtf)
       
  9833     rtfOutput = createOutputDirectory(outputDirectory,"RTF_OUTPUT","/rtf");
       
  9834 
       
  9835   QCString manOutput;
       
  9836   bool &generateMan = Config_getBool("GENERATE_MAN");
       
  9837   if (generateMan)
       
  9838     manOutput = createOutputDirectory(outputDirectory,"MAN_OUTPUT","/man");
       
  9839 
       
  9840 
       
  9841   if (Config_getBool("HAVE_DOT"))
       
  9842   {
       
  9843     QCString curFontPath = Config_getString("DOT_FONTPATH");
       
  9844     if (curFontPath.isEmpty())
       
  9845     {
       
  9846       portable_getenv("DOTFONTPATH");
       
  9847       QCString newFontPath = ".";
       
  9848       if (!curFontPath.isEmpty())
       
  9849       {
       
  9850         newFontPath+=portable_pathListSeparator();
       
  9851         newFontPath+=curFontPath;
       
  9852       }
       
  9853       portable_setenv("DOTFONTPATH",newFontPath);
       
  9854     }
       
  9855     else
       
  9856     {
       
  9857       portable_setenv("DOTFONTPATH",curFontPath);
       
  9858     }
       
  9859   }
       
  9860 
       
  9861 
       
  9862 
       
  9863   /**************************************************************************
       
  9864    *             Handle layout file                                         *
       
  9865    **************************************************************************/
       
  9866 
       
  9867   LayoutDocManager::instance().init();
       
  9868   QCString layoutFileName = Config_getString("LAYOUT_FILE");
       
  9869   bool defaultLayoutUsed = FALSE;
       
  9870   if (layoutFileName.isEmpty())
       
  9871   {
       
  9872     layoutFileName = "DoxygenLayout.xml";
       
  9873     defaultLayoutUsed = TRUE;
       
  9874   }
       
  9875 
       
  9876   QFile layoutFile(layoutFileName);
       
  9877   if (layoutFile.open(IO_ReadOnly))
       
  9878   {
       
  9879     msg("Parsing layout file %s...\n",layoutFileName.data());
       
  9880     QTextStream t(&layoutFile); 
       
  9881     LayoutDocManager::instance().parse(t);
       
  9882   }
       
  9883   else if (!defaultLayoutUsed)
       
  9884   {
       
  9885     err("Warning: failed to open layout file '%s' for reading!\n",layoutFileName.data());
       
  9886   }
       
  9887 
       
  9888   /**************************************************************************
       
  9889    *             Read and preprocess input                                  *
       
  9890    **************************************************************************/
       
  9891  
       
  9892   // prevent search in the output directories
       
  9893   QStrList &exclPatterns = Config_getList("EXCLUDE_PATTERNS");
       
  9894   if (generateHtml)  exclPatterns.append(htmlOutput);
       
  9895   if (generateXml)   exclPatterns.append(xmlOutput);
       
  9896   if (generateXmlDita)   exclPatterns.append(xmlDitaOutput);
       
  9897   if (generateLatex) exclPatterns.append(latexOutput);
       
  9898   if (generateRtf)   exclPatterns.append(rtfOutput);
       
  9899   if (generateMan)   exclPatterns.append(manOutput);
       
  9900 
       
  9901 
       
  9902   searchInputFiles(g_inputFiles);
       
  9903 
       
  9904   // Notice: the order of the function calls below is very important!
       
  9905   
       
  9906   if (Config_getBool("GENERATE_HTML"))
       
  9907   {
       
  9908     readFormulaRepository();
       
  9909   }
       
  9910   
       
  9911   /**************************************************************************
       
  9912    *             Handle Tag Files                                           *
       
  9913    **************************************************************************/
       
  9914 
       
  9915   g_storage = new FileStorage;
       
  9916   g_storage->setName(Doxygen::entryDBFileName);
       
  9917   if (!g_storage->open(IO_WriteOnly))
       
  9918   {
       
  9919     err("Failed to create temporary storage file %s\n",
       
  9920         Doxygen::entryDBFileName.data());
       
  9921     exit(1);
       
  9922   }
       
  9923   Entry *root=new Entry;
       
  9924   EntryNav *rootNav = new EntryNav(0,root);
       
  9925   rootNav->setEntry(root);
       
  9926   msg("Reading and parsing tag files\n");
       
  9927   
       
  9928   QStrList &tagFileList = Config_getList("TAGFILES");
       
  9929   char *s=tagFileList.first();
       
  9930   while (s)
       
  9931   {
       
  9932     readTagFile(root,s);
       
  9933     root->createNavigationIndex(rootNav,g_storage,0);
       
  9934     s=tagFileList.next();
       
  9935   }
       
  9936   
       
  9937   /**************************************************************************
       
  9938    *             Parse source files                                         * 
       
  9939    **************************************************************************/
       
  9940 
       
  9941   parseFiles(root,rootNav);
       
  9942   g_storage->close();
       
  9943   if (!g_storage->open(IO_ReadOnly))
       
  9944   {
       
  9945     err("Failed to open temporary storage file %s for reading",
       
  9946         Doxygen::entryDBFileName.data());
       
  9947     exit(1);
       
  9948   }
       
  9949 
       
  9950   //printNavTree(rootNav,0);
       
  9951 
       
  9952   // we are done with input scanning now, so free up the buffers used by flex
       
  9953   // (can be around 4MB)
       
  9954   preFreeScanner();
       
  9955   scanFreeScanner();
       
  9956   pyscanFreeScanner();
       
  9957 
       
  9958   //delete rootNav;
       
  9959   //g_storage.close();
       
  9960   //exit(1);
       
  9961 
       
  9962   /**************************************************************************
       
  9963    *             Gather information                                         * 
       
  9964    **************************************************************************/
       
  9965   
       
  9966   msg("Building group list...\n");
       
  9967   buildGroupList(rootNav);
       
  9968   organizeSubGroups(rootNav);
       
  9969 
       
  9970   msg("Building directory list...\n");
       
  9971   buildDirectories();
       
  9972   findDirDocumentation(rootNav);
       
  9973 
       
  9974   if (Config_getBool("BUILTIN_STL_SUPPORT"))
       
  9975   {
       
  9976     addSTLClasses(rootNav);
       
  9977   }
       
  9978 
       
  9979   msg("Building namespace list...\n");
       
  9980   buildNamespaceList(rootNav);
       
  9981   findUsingDirectives(rootNav);
       
  9982 
       
  9983   msg("Building file list...\n");
       
  9984   buildFileList(rootNav);
       
  9985   //generateFileTree();
       
  9986   
       
  9987   msg("Building class list...\n");
       
  9988   buildClassList(rootNav);
       
  9989 
       
  9990   msg("Associating documentation with classes...\n");
       
  9991   buildClassDocList(rootNav);
       
  9992 
       
  9993   // build list of using declarations here (global list)
       
  9994   buildListOfUsingDecls(rootNav);
       
  9995   
       
  9996   msg("Computing nesting relations for classes...\n");
       
  9997   resolveClassNestingRelations();
       
  9998 
       
  9999   // calling buildClassList may result in cached relations that
       
 10000   // become invalid after resolveClassNestingRelations(), that's why
       
 10001   // we need to clear the cache here
       
 10002   Doxygen::lookupCache.clear();
       
 10003   // we don't need the list of using declaration anymore
       
 10004   g_usingDeclarations.clear();
       
 10005 
       
 10006   msg("Building example list...\n");
       
 10007   buildExampleList(rootNav);
       
 10008   
       
 10009   msg("Searching for enumerations...\n");
       
 10010   findEnums(rootNav);
       
 10011   
       
 10012   // Since buildVarList calls isVarWithConstructor
       
 10013   // and this calls getResolvedClass we need to process
       
 10014   // typedefs first so the relations between classes via typedefs
       
 10015   // are properly resolved. See bug 536385 for an example.
       
 10016   msg("Searching for documented typedefs...\n");
       
 10017   buildTypedefList(rootNav);
       
 10018 
       
 10019   msg("Searching for members imported via using declarations...\n");
       
 10020   findUsingDeclImports(rootNav);
       
 10021   // this should be after buildTypedefList in order to properly import
       
 10022   // used typedefs
       
 10023   findUsingDeclarations(rootNav);
       
 10024 
       
 10025   msg("Searching for included using directives...\n");
       
 10026   findIncludedUsingDirectives();
       
 10027 
       
 10028   msg("Searching for documented variables...\n");
       
 10029   buildVarList(rootNav);
       
 10030 
       
 10031   msg("Building member list...\n"); // using class info only !
       
 10032   buildFunctionList(rootNav);
       
 10033 
       
 10034   msg("Searching for friends...\n");
       
 10035   findFriends();
       
 10036   
       
 10037   msg("Searching for documented defines...\n");
       
 10038   findDefineDocumentation(rootNav); 
       
 10039   
       
 10040   findClassEntries(rootNav);         
       
 10041   msg("Computing class inheritance relations...\n");
       
 10042   findInheritedTemplateInstances();       
       
 10043   msg("Computing class usage relations...\n");
       
 10044   findUsedTemplateInstances();       
       
 10045 
       
 10046   msg("Flushing cached template relations that have become invalid...\n");
       
 10047   flushCachedTemplateRelations();
       
 10048   
       
 10049   msg("Creating members for template instances...\n");
       
 10050   createTemplateInstanceMembers();
       
 10051 
       
 10052   msg("Computing class relations...\n");
       
 10053   computeTemplateClassRelations(); 
       
 10054   flushUnresolvedRelations();
       
 10055   if (Config_getBool("OPTIMIZE_OUTPUT_VHDL"))
       
 10056   {
       
 10057     VhdlDocGen::computeVhdlComponentRelations();
       
 10058   }
       
 10059   else
       
 10060   {
       
 10061     computeClassRelations();        
       
 10062   }
       
 10063   g_classEntries.clear();          
       
 10064 
       
 10065   msg("Add enum values to enums...\n");
       
 10066   addEnumValuesToEnums(rootNav);
       
 10067   findEnumDocumentation(rootNav);
       
 10068 
       
 10069   msg("Searching for member function documentation...\n");
       
 10070   findObjCMethodDefinitions(rootNav);
       
 10071   findMemberDocumentation(rootNav); // may introduce new members !
       
 10072 
       
 10073   transferRelatedFunctionDocumentation();
       
 10074   transferFunctionDocumentation();
       
 10075   
       
 10076   msg("Building page list...\n");
       
 10077   buildPageList(rootNav);
       
 10078 
       
 10079   msg("Search for main page...\n");
       
 10080   findMainPage(rootNav);
       
 10081 
       
 10082   msg("Computing page relations...\n");
       
 10083   computePageRelations(rootNav);
       
 10084   checkPageRelations();
       
 10085 
       
 10086   msg("Determining the scope of groups...\n");
       
 10087   findGroupScope(rootNav);
       
 10088 
       
 10089   msg("Sorting lists...\n");
       
 10090   Doxygen::memberNameSDict->sort();
       
 10091   Doxygen::functionNameSDict->sort();
       
 10092   Doxygen::hiddenClasses->sort();
       
 10093   Doxygen::classSDict->sort();
       
 10094   
       
 10095   msg("Freeing entry tree\n");
       
 10096   delete rootNav;
       
 10097   g_storage->close();
       
 10098   delete g_storage;
       
 10099   g_storage=0;
       
 10100 
       
 10101   QDir thisDir;
       
 10102   thisDir.remove(Doxygen::entryDBFileName);
       
 10103   
       
 10104   msg("Determining which enums are documented\n");
       
 10105   findDocumentedEnumValues();
       
 10106 
       
 10107   msg("Computing member relations...\n");
       
 10108   computeMemberRelations();
       
 10109 
       
 10110   msg("Building full member lists recursively...\n");
       
 10111   buildCompleteMemberLists();
       
 10112   
       
 10113   msg("Adding members to member groups.\n");
       
 10114   addMembersToMemberGroup();
       
 10115 
       
 10116   if (Config_getBool("DISTRIBUTE_GROUP_DOC"))
       
 10117   {
       
 10118     msg("Distributing member group documentation.\n");
       
 10119     distributeMemberGroupDocumentation();
       
 10120   }
       
 10121   
       
 10122   msg("Computing member references...\n");
       
 10123   computeMemberReferences(); 
       
 10124 
       
 10125   if (Config_getBool("INHERIT_DOCS"))
       
 10126   {
       
 10127     msg("Inheriting documentation...\n");
       
 10128     inheritDocumentation();
       
 10129   }
       
 10130 
       
 10131   // compute the shortest possible names of all files
       
 10132   // without loosing the uniqueness of the file names.
       
 10133   msg("Generating disk names...\n");
       
 10134   Doxygen::inputNameList->generateDiskNames();
       
 10135   
       
 10136   msg("Adding source references...\n");
       
 10137   addSourceReferences();
       
 10138 
       
 10139   msg("Adding xrefitems...\n");
       
 10140   addListReferences();
       
 10141   generateXRefPages();
       
 10142 
       
 10143   if (Config_getBool("SHOW_DIRECTORIES") && Config_getBool("DIRECTORY_GRAPH"))
       
 10144   {
       
 10145     msg("Computing dependencies between directories...\n");
       
 10146     computeDirDependencies();
       
 10147   }
       
 10148 
       
 10149   msg("Counting data structures...\n");
       
 10150   countDataStructures();
       
 10151  
       
 10152   msg("Resolving user defined references...\n");
       
 10153   resolveUserReferences();
       
 10154 
       
 10155   msg("Finding anchors and sections in the documentation...\n");
       
 10156   findSectionsInDocumentation();
       
 10157 
       
 10158   transferFunctionReferences();
       
 10159 
       
 10160   msg("Combining using relations...\n");
       
 10161   combineUsingRelations();
       
 10162 
       
 10163   msg("Adding members to index pages...\n");
       
 10164   addMembersToIndex();
       
 10165 }
       
 10166 
       
 10167 void generateOutput()
       
 10168 {
       
 10169   /**************************************************************************
       
 10170    *            Initialize output generators                                *
       
 10171    **************************************************************************/
       
 10172 
       
 10173   //// dump all symbols
       
 10174   //SDict<DefinitionList>::Iterator sdi(Doxygen::symbolMap);
       
 10175   //DefinitionList *dl;
       
 10176   //for (sdi.toFirst();(dl=sdi.current());++sdi)
       
 10177   //{
       
 10178   //  DefinitionListIterator dli(*dl);
       
 10179   //  Definition *d;
       
 10180   //  printf("Symbol: ");
       
 10181   //  for (dli.toFirst();(d=dli.current());++dli)
       
 10182   //  {
       
 10183   //    printf("%s ",d->qualifiedName().data());
       
 10184   //  }
       
 10185   //  printf("\n");
       
 10186   //}
       
 10187   if (g_dumpSymbolMap)
       
 10188   {
       
 10189     dumpSymbolMap();
       
 10190     exit(0);
       
 10191   }
       
 10192 
       
 10193   initDocParser();
       
 10194 
       
 10195   g_outputList = new OutputList(TRUE);
       
 10196   if (Config_getBool("GENERATE_HTML"))  
       
 10197   {
       
 10198     g_outputList->add(new HtmlGenerator);
       
 10199     HtmlGenerator::init();
       
 10200 #if 0
       
 10201     if (Config_getBool("GENERATE_INDEXLOG")) Doxygen::indexList.addIndex(new IndexLog);
       
 10202 #endif
       
 10203     bool generateHtmlHelp = Config_getBool("GENERATE_HTMLHELP");
       
 10204     bool generateEclipseHelp = Config_getBool("GENERATE_ECLIPSEHELP");
       
 10205     bool generateQhp      = Config_getBool("GENERATE_QHP");
       
 10206     bool generateTreeView = Config_getBool("GENERATE_TREEVIEW");
       
 10207     bool generateDocSet   = Config_getBool("GENERATE_DOCSET");
       
 10208     if (generateEclipseHelp) Doxygen::indexList.addIndex(new EclipseHelp);
       
 10209     if (generateHtmlHelp) Doxygen::indexList.addIndex(new HtmlHelp);
       
 10210     if (generateQhp)      Doxygen::indexList.addIndex(new Qhp);
       
 10211     if (generateTreeView) Doxygen::indexList.addIndex(new FTVHelp);
       
 10212     if (generateDocSet)   Doxygen::indexList.addIndex(new DocSets);
       
 10213     Doxygen::indexList.initialize();
       
 10214     Doxygen::indexList.addImageFile("tab_r.gif");
       
 10215     Doxygen::indexList.addImageFile("tab_l.gif");
       
 10216     Doxygen::indexList.addImageFile("tab_b.gif");
       
 10217     Doxygen::indexList.addStyleSheetFile("tabs.css");
       
 10218     Doxygen::indexList.addImageFile("doxygen.png");
       
 10219     if (Config_getBool("HTML_DYNAMIC_SECTIONS")) HtmlGenerator::generateSectionImages();
       
 10220     copyStyleSheet();
       
 10221   }
       
 10222   if (Config_getBool("GENERATE_LATEX")) 
       
 10223   {
       
 10224     g_outputList->add(new LatexGenerator);
       
 10225     LatexGenerator::init();
       
 10226   }
       
 10227   if (Config_getBool("GENERATE_MAN"))
       
 10228   {
       
 10229     g_outputList->add(new ManGenerator);
       
 10230     ManGenerator::init();
       
 10231   }
       
 10232   if (Config_getBool("GENERATE_RTF"))
       
 10233   {
       
 10234     g_outputList->add(new RTFGenerator);
       
 10235     RTFGenerator::init();
       
 10236   }
       
 10237 
       
 10238   if (Config_getBool("USE_HTAGS"))
       
 10239   {
       
 10240     Htags::useHtags = TRUE;
       
 10241     QCString htmldir = Config_getString("HTML_OUTPUT");
       
 10242     if (!Htags::execute(htmldir))
       
 10243        err("Error: USE_HTAGS is YES but htags(1) failed. \n");
       
 10244     if (!Htags::loadFilemap(htmldir))
       
 10245        err("Error: htags(1) ended normally but failed to load the filemap. \n");
       
 10246   }
       
 10247   
       
 10248   /**************************************************************************
       
 10249    *                        Generate documentation                          *
       
 10250    **************************************************************************/
       
 10251 
       
 10252   QFile *tag=0;
       
 10253   QCString &generateTagFile = Config_getString("GENERATE_TAGFILE");
       
 10254   if (!generateTagFile.isEmpty())
       
 10255   {
       
 10256     tag=new QFile(generateTagFile);
       
 10257     if (!tag->open(IO_WriteOnly))
       
 10258     {
       
 10259       err("Error: cannot open tag file %s for writing\n",
       
 10260           generateTagFile.data()
       
 10261          );
       
 10262       cleanUpDoxygen();
       
 10263       exit(1);
       
 10264     }
       
 10265     Doxygen::tagFile.setDevice(tag);
       
 10266     Doxygen::tagFile.setEncoding(QTextStream::UnicodeUTF8);
       
 10267     Doxygen::tagFile << "<?xml version='1.0' encoding='ISO-8859-1' standalone='yes' ?>" << endl;
       
 10268     Doxygen::tagFile << "<tagfile>" << endl;
       
 10269   }
       
 10270 
       
 10271   if (Config_getBool("GENERATE_HTML"))  writeDoxFont(Config_getString("HTML_OUTPUT"));
       
 10272   if (Config_getBool("GENERATE_LATEX")) writeDoxFont(Config_getString("LATEX_OUTPUT"));
       
 10273   if (Config_getBool("GENERATE_RTF"))   writeDoxFont(Config_getString("RTF_OUTPUT"));
       
 10274 
       
 10275   msg("Generating style sheet...\n");
       
 10276   //printf("writing style info\n");
       
 10277   QCString genString = 
       
 10278         theTranslator->trGeneratedAt(dateToString(TRUE),Config_getString("PROJECT_NAME"));
       
 10279   g_outputList->writeStyleInfo(0); // write first part
       
 10280   g_outputList->disableAllBut(OutputGenerator::Latex);
       
 10281   g_outputList->parseText(genString);
       
 10282   g_outputList->writeStyleInfo(1); // write second part
       
 10283   //parseText(*g_outputList,theTranslator->trWrittenBy());
       
 10284   g_outputList->writeStyleInfo(2); // write third part
       
 10285   g_outputList->parseText(genString);
       
 10286   g_outputList->writeStyleInfo(3); // write fourth part
       
 10287   //parseText(*g_outputList,theTranslator->trWrittenBy());
       
 10288   g_outputList->writeStyleInfo(4); // write last part
       
 10289   g_outputList->enableAll();
       
 10290   
       
 10291   static bool searchEngine      = Config_getBool("SEARCHENGINE");
       
 10292   static bool serverBasedSearch = Config_getBool("SERVER_BASED_SEARCH");
       
 10293 
       
 10294   // generate search indices (need to do this before writing other HTML
       
 10295   // pages as these contain a drop down menu with options depending on
       
 10296   // what categories we find in this function.
       
 10297   if (searchEngine)
       
 10298   {
       
 10299     QCString searchDirName = Config_getString("HTML_OUTPUT")+"/search";
       
 10300     QDir searchDir(searchDirName);
       
 10301     if (!searchDir.exists() && !searchDir.mkdir(searchDirName))
       
 10302     {
       
 10303       err("Could not create search results directory '%s/search'\n",searchDirName.data());
       
 10304       return;
       
 10305     }
       
 10306     HtmlGenerator::writeSearchData(searchDirName);
       
 10307     writeSearchStyleSheet();
       
 10308     if (serverBasedSearch)
       
 10309     {
       
 10310     }
       
 10311     else
       
 10312     {
       
 10313       writeJavascriptSearchIndex();
       
 10314     }
       
 10315   }
       
 10316 
       
 10317   //statistics();
       
 10318   
       
 10319   // count the number of documented elements in the lists we have built. 
       
 10320   // If the result is 0 we do not generate the lists and omit the 
       
 10321   // corresponding links in the index.
       
 10322   msg("Generating index page...\n"); 
       
 10323   writeIndex(*g_outputList);
       
 10324 
       
 10325   msg("Generating page index...\n");
       
 10326   writePageIndex(*g_outputList);
       
 10327   
       
 10328   msg("Generating example documentation...\n");
       
 10329   generateExampleDocs();
       
 10330 
       
 10331   msg("Generating file sources...\n");
       
 10332   if (!Htags::useHtags)
       
 10333   {
       
 10334     generateFileSources();
       
 10335   }
       
 10336 
       
 10337   msg("Generating file documentation...\n");
       
 10338   generateFileDocs();
       
 10339   
       
 10340   msg("Generating page documentation...\n");
       
 10341   generatePageDocs();
       
 10342   
       
 10343   msg("Generating group documentation...\n");
       
 10344   generateGroupDocs();
       
 10345 
       
 10346   msg("Generating group index...\n");
       
 10347   writeGroupIndex(*g_outputList);
       
 10348  
       
 10349   msg("Generating class documentation...\n");
       
 10350   generateClassDocs();
       
 10351   
       
 10352   if (Config_getBool("HAVE_DOT") && Config_getBool("GRAPHICAL_HIERARCHY"))
       
 10353   {
       
 10354     msg("Generating graphical class hierarchy...\n");
       
 10355     writeGraphicalClassHierarchy(*g_outputList);
       
 10356   }
       
 10357 
       
 10358   msg("Generating namespace index...\n");
       
 10359   generateNamespaceDocs();
       
 10360   
       
 10361   msg("Generating namespace member index...\n");
       
 10362   writeNamespaceMemberIndex(*g_outputList);
       
 10363 
       
 10364   if (Config_getBool("GENERATE_LEGEND"))
       
 10365   {
       
 10366     msg("Generating graph info page...\n");
       
 10367     writeGraphInfo(*g_outputList);
       
 10368   }
       
 10369 
       
 10370   if (Config_getBool("SHOW_DIRECTORIES"))
       
 10371   {
       
 10372     msg("Generating directory documentation...\n");
       
 10373     generateDirDocs(*g_outputList);
       
 10374   }
       
 10375 
       
 10376   msg("Generating file index...\n");
       
 10377   writeFileIndex(*g_outputList);
       
 10378  
       
 10379   if (Config_getBool("SHOW_DIRECTORIES"))
       
 10380   {
       
 10381     msg("Generating directory index...\n");
       
 10382     writeDirIndex(*g_outputList);
       
 10383   }
       
 10384 
       
 10385   msg("Generating example index...\n");
       
 10386   writeExampleIndex(*g_outputList);
       
 10387   
       
 10388   msg("Generating file member index...\n");
       
 10389   writeFileMemberIndex(*g_outputList);
       
 10390 
       
 10391   
       
 10392   //writeDirDependencyGraph(Config_getString("HTML_OUTPUT"));
       
 10393   
       
 10394   if (Config_getBool("GENERATE_RTF"))
       
 10395   {
       
 10396     msg("Combining RTF output...\n");
       
 10397     if (!RTFGenerator::preProcessFileInplace(Config_getString("RTF_OUTPUT"),"refman.rtf"))
       
 10398     {
       
 10399       err("An error occurred during post-processing the RTF files!\n");
       
 10400     }
       
 10401   }
       
 10402   
       
 10403   if (Doxygen::formulaList.count()>0 && Config_getBool("GENERATE_HTML"))
       
 10404   {
       
 10405     msg("Generating bitmaps for formulas in HTML...\n");
       
 10406     Doxygen::formulaList.generateBitmaps(Config_getString("HTML_OUTPUT"));
       
 10407   }
       
 10408   
       
 10409   //if (Config_getBool("GENERATE_HTML") && Config_getBool("GENERATE_HTMLHELP"))  
       
 10410   //{
       
 10411   //  HtmlHelp::getInstance()->finalize();
       
 10412   //}
       
 10413   //if (Config_getBool("GENERATE_HTML") && Config_getBool("GENERATE_TREEVIEW"))  
       
 10414   //{
       
 10415   //  FTVHelp::getInstance()->finalize();
       
 10416   //}
       
 10417 
       
 10418   Doxygen::indexList.finalize();
       
 10419 
       
 10420   if (!Config_getString("GENERATE_TAGFILE").isEmpty())
       
 10421   {
       
 10422     Doxygen::tagFile << "</tagfile>" << endl;
       
 10423     delete tag;
       
 10424   }
       
 10425 
       
 10426   if (Config_getBool("DOT_CLEANUP"))
       
 10427   {
       
 10428     if (Config_getBool("GENERATE_HTML"))
       
 10429       removeDoxFont(Config_getString("HTML_OUTPUT"));
       
 10430     if (Config_getBool("GENERATE_RTF"))  
       
 10431       removeDoxFont(Config_getString("RTF_OUTPUT"));
       
 10432     if (Config_getBool("GENERATE_LATEX"))  
       
 10433       removeDoxFont(Config_getString("LATEX_OUTPUT"));
       
 10434   }
       
 10435 
       
 10436   if (Config_getBool("GENERATE_XML"))
       
 10437   {
       
 10438     msg("Generating XML output...\n");
       
 10439     generateXML();
       
 10440   }
       
 10441   if (Config_getBool("GENERATE_XML_DITA"))
       
 10442   {
       
 10443     msg("Generating XML DITA output...\n");
       
 10444     generateXMLDITA();
       
 10445   }
       
 10446   if (Config_getBool("GENERATE_AUTOGEN_DEF"))
       
 10447   {
       
 10448     msg("Generating AutoGen DEF output...\n");
       
 10449     generateDEF();
       
 10450   }
       
 10451   if (Config_getBool("GENERATE_PERLMOD"))
       
 10452   {
       
 10453     msg("Generating Perl module output...\n");
       
 10454     generatePerlMod();
       
 10455   }
       
 10456   if (Config_getBool("GENERATE_HTML") &&
       
 10457       Config_getBool("GENERATE_HTMLHELP") && 
       
 10458       !Config_getString("HHC_LOCATION").isEmpty())
       
 10459   {
       
 10460     msg("Running html help compiler...\n");
       
 10461     QString oldDir = QDir::currentDirPath();
       
 10462     QDir::setCurrent(Config_getString("HTML_OUTPUT"));
       
 10463     if (portable_system(Config_getString("HHC_LOCATION"), "index.hhp", FALSE))
       
 10464     {
       
 10465       err("Error: failed to run html help compiler on index.hhp\n");
       
 10466     }
       
 10467     QDir::setCurrent(oldDir);
       
 10468   }
       
 10469   if ( Config_getBool("GENERATE_HTML") &&
       
 10470        Config_getBool("GENERATE_QHP") && 
       
 10471       !Config_getString("QHG_LOCATION").isEmpty())
       
 10472   {
       
 10473     msg("Running qhelpgenerator...\n");
       
 10474     QCString const qhpFileName = Qhp::getQhpFileName();
       
 10475     QCString const qchFileName = getQchFileName();
       
 10476 
       
 10477     QCString const args = QCString().sprintf("%s -o \"%s\"", qhpFileName.data(), qchFileName.data());
       
 10478     QString const oldDir = QDir::currentDirPath();
       
 10479     QDir::setCurrent(Config_getString("HTML_OUTPUT"));
       
 10480     if (portable_system(Config_getString("QHG_LOCATION"), args.data(), FALSE))
       
 10481     {
       
 10482       err("Error: failed to run qhelpgenerator on index.qhp\n");
       
 10483     }
       
 10484     QDir::setCurrent(oldDir);
       
 10485   }
       
 10486 
       
 10487   if (Config_getBool("GENERATE_HTML") && searchEngine && serverBasedSearch)
       
 10488   {
       
 10489     msg("Generating search index\n");
       
 10490     HtmlGenerator::writeSearchPage();
       
 10491     Doxygen::searchIndex->write(Config_getString("HTML_OUTPUT")+"/search/search.idx");
       
 10492   }
       
 10493 
       
 10494   if (Debug::isFlagSet(Debug::Time))
       
 10495   {
       
 10496     msg("Total elapsed time: %.3f seconds\n(of which %.3f seconds waiting for external tools to finish)\n",
       
 10497          ((double)Doxygen::runningTime.elapsed())/1000.0,
       
 10498          portable_getSysElapsedTime()
       
 10499         );
       
 10500   }
       
 10501 
       
 10502   /**************************************************************************
       
 10503    *                        Start cleaning up                               *
       
 10504    **************************************************************************/
       
 10505 
       
 10506   //Doxygen::symbolCache->printStats();
       
 10507   //Doxygen::symbolStorage->printStats();
       
 10508   cleanUpDoxygen();
       
 10509 
       
 10510   finializeDocParser();
       
 10511   Doxygen::symbolStorage->close();
       
 10512   QDir thisDir;
       
 10513   thisDir.remove(Doxygen::objDBFileName);
       
 10514   Config::deleteInstance();
       
 10515   QTextCodec::deleteAllCodecs();
       
 10516   delete Doxygen::symbolCache;
       
 10517   delete Doxygen::symbolMap;
       
 10518   delete Doxygen::symbolStorage;
       
 10519   g_successfulRun=TRUE;
       
 10520   msg("generateOutput() exiting.\n");
       
 10521 }
       
 10522