Orb/Doxygen/src/doxygen.cpp
changeset 3 d8fccb2cd802
child 4 468f4c8d3d5b
equal deleted inserted replaced
2:932c358ece3e 3:d8fccb2cd802
       
     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 void clearAll()
       
   159 {
       
   160   g_inputFiles.clear();      
       
   161   //g_excludeNameDict.clear();  
       
   162   //delete g_outputList; g_outputList=0;
       
   163 
       
   164   Doxygen::classSDict->clear();       
       
   165   Doxygen::namespaceSDict->clear();   
       
   166   Doxygen::pageSDict->clear();         
       
   167   Doxygen::exampleSDict->clear();      
       
   168   Doxygen::inputNameList->clear();   
       
   169   Doxygen::formulaList.clear();     
       
   170   Doxygen::sectionDict.clear();       
       
   171   Doxygen::inputNameDict->clear();    
       
   172   Doxygen::includeNameDict->clear();  
       
   173   Doxygen::exampleNameDict->clear();  
       
   174   Doxygen::imageNameDict->clear();     
       
   175   Doxygen::dotFileNameDict->clear();     
       
   176   Doxygen::formulaDict.clear();      
       
   177   Doxygen::formulaNameDict.clear();  
       
   178   Doxygen::tagDestinationDict.clear();
       
   179   delete Doxygen::mainPage; Doxygen::mainPage=0;
       
   180 }
       
   181 
       
   182 void statistics()
       
   183 {
       
   184   fprintf(stderr,"--- inputNameDict stats ----\n");
       
   185   Doxygen::inputNameDict->statistics();
       
   186   fprintf(stderr,"--- includeNameDict stats ----\n");
       
   187   Doxygen::includeNameDict->statistics();
       
   188   fprintf(stderr,"--- exampleNameDict stats ----\n");
       
   189   Doxygen::exampleNameDict->statistics();
       
   190   fprintf(stderr,"--- imageNameDict stats ----\n");
       
   191   Doxygen::imageNameDict->statistics();
       
   192   fprintf(stderr,"--- dotFileNameDict stats ----\n");
       
   193   Doxygen::dotFileNameDict->statistics();
       
   194   //fprintf(stderr,"--- g_excludeNameDict stats ----\n");
       
   195   //g_excludeNameDict.statistics();
       
   196   fprintf(stderr,"--- aliasDict stats ----\n");
       
   197   Doxygen::aliasDict.statistics();
       
   198   fprintf(stderr,"--- typedefDict stats ----\n");
       
   199   fprintf(stderr,"--- namespaceAliasDict stats ----\n");
       
   200   Doxygen::namespaceAliasDict.statistics();
       
   201   fprintf(stderr,"--- formulaDict stats ----\n");
       
   202   Doxygen::formulaDict.statistics();
       
   203   fprintf(stderr,"--- formulaNameDict stats ----\n");
       
   204   Doxygen::formulaNameDict.statistics();
       
   205   fprintf(stderr,"--- tagDestinationDict stats ----\n");
       
   206   Doxygen::tagDestinationDict.statistics();
       
   207   fprintf(stderr,"--- g_compoundKeywordDict stats ----\n");
       
   208   g_compoundKeywordDict.statistics();
       
   209   fprintf(stderr,"--- expandAsDefinedDict stats ----\n");
       
   210   Doxygen::expandAsDefinedDict.statistics();
       
   211   fprintf(stderr,"--- memGrpInfoDict stats ----\n");
       
   212   Doxygen::memGrpInfoDict.statistics();
       
   213 }
       
   214 
       
   215 
       
   216 
       
   217 static void addMemberDocs(EntryNav *rootNav,MemberDef *md, const char *funcDecl,
       
   218                    ArgumentList *al,bool over_load,NamespaceSDict *nl=0);
       
   219 static void findMember(EntryNav *rootNav,
       
   220                        QCString funcDecl,
       
   221                        bool overloaded,
       
   222                        bool isFunc
       
   223                       );
       
   224 
       
   225 
       
   226 struct STLInfo
       
   227 {
       
   228   const char *className;
       
   229   const char *baseClass1;
       
   230   const char *baseClass2;
       
   231   const char *templType1;
       
   232   const char *templName1;
       
   233   const char *templType2;
       
   234   const char *templName2;
       
   235   bool virtualInheritance;
       
   236   bool iterators;
       
   237 };
       
   238 
       
   239 static STLInfo g_stlinfo[] =
       
   240 {
       
   241   // className              baseClass1                      baseClass2             templType1     templName1     templType2    templName2     virtInheritance  // iterators
       
   242   { "allocator",            0,                              0,                     "T",           "elements",    0,            0,             FALSE,              FALSE },
       
   243   { "auto_ptr",             0,                              0,                     "T",           "ptr",         0,            0,             FALSE,              FALSE },
       
   244   { "ios_base",             0,                              0,                     0,             0,             0,            0,             FALSE,              FALSE },
       
   245   { "basic_ios",            "ios_base",                     0,                     "Char",        0,             0,            0,             FALSE,              FALSE },
       
   246   { "basic_istream",        "basic_ios<Char>",              0,                     "Char",        0,             0,            0,             TRUE,               FALSE },
       
   247   { "basic_ostream",        "basic_ios<Char>",              0,                     "Char",        0,             0,            0,             TRUE,               FALSE },
       
   248   { "basic_iostream",       "basic_istream<Char>",          "basic_ostream<Char>", "Char",        0,             0,            0,             FALSE,              FALSE },
       
   249   { "basic_ifstream",       "basic_istream<Char>",          0,                     "Char",        0,             0,            0,             FALSE,              FALSE },
       
   250   { "basic_ofstream",       "basic_ostream<Char>",          0,                     "Char",        0,             0,            0,             FALSE,              FALSE },
       
   251   { "basic_fstream",        "basic_iostream<Char>",         0,                     "Char",        0,             0,            0,             FALSE,              FALSE },
       
   252   { "basic_istringstream",  "basic_istream<Char>",          0,                     "Char",        0,             0,            0,             FALSE,              FALSE },
       
   253   { "basic_ostringstream",  "basic_ostream<Char>",          0,                     "Char",        0,             0,            0,             FALSE,              FALSE },
       
   254   { "basic_stringstream",   "basic_iostream<Char>",         0,                     "Char",        0,             0,            0,             FALSE,              FALSE },
       
   255   { "ios",                  "basic_ios<char>",              0,                     0,             0,             0,            0,             FALSE,              FALSE },
       
   256   { "wios",                 "basic_ios<wchar_t>",           0,                     0,             0,             0,            0,             FALSE,              FALSE },
       
   257   { "istream",              "basic_istream<char>",          0,                     0,             0,             0,            0,             FALSE,              FALSE },
       
   258   { "wistream",             "basic_istream<wchar_t>",       0,                     0,             0,             0,            0,             FALSE,              FALSE },
       
   259   { "ostream",              "basic_ostream<char>",          0,                     0,             0,             0,            0,             FALSE,              FALSE },
       
   260   { "wostream",             "basic_ostream<wchar_t>",       0,                     0,             0,             0,            0,             FALSE,              FALSE },
       
   261   { "ifstream",             "basic_ifstream<char>",         0,                     0,             0,             0,            0,             FALSE,              FALSE },
       
   262   { "wifstream",            "basic_ifstream<wchar_t>",      0,                     0,             0,             0,            0,             FALSE,              FALSE },
       
   263   { "ofstream",             "basic_ofstream<char>",         0,                     0,             0,             0,            0,             FALSE,              FALSE },
       
   264   { "wofstream",            "basic_ofstream<wchar_t>",      0,                     0,             0,             0,            0,             FALSE,              FALSE },
       
   265   { "fstream",              "basic_fstream<char>",          0,                     0,             0,             0,            0,             FALSE,              FALSE },
       
   266   { "wfstream",             "basic_fstream<wchar_t>",       0,                     0,             0,             0,            0,             FALSE,              FALSE },
       
   267   { "istringstream",        "basic_istringstream<char>",    0,                     0,             0,             0,            0,             FALSE,              FALSE },
       
   268   { "wistringstream",       "basic_istringstream<wchar_t>", 0,                     0,             0,             0,            0,             FALSE,              FALSE },
       
   269   { "ostringstream",        "basic_ostringstream<char>",    0,                     0,             0,             0,            0,             FALSE,              FALSE },
       
   270   { "wostringstream",       "basic_ostringstream<wchar_t>", 0,                     0,             0,             0,            0,             FALSE,              FALSE },
       
   271   { "stringstream",         "basic_stringstream<char>",     0,                     0,             0,             0,            0,             FALSE,              FALSE },
       
   272   { "wstringstream",        "basic_stringstream<wchar_t>",  0,                     0,             0,             0,            0,             FALSE,              FALSE },
       
   273   { "basic_string",         0,                              0,                     "Char",        0,             0,            0,             FALSE,              TRUE  },
       
   274   { "string",               "basic_string<char>",           0,                     0,             0,             0,            0,             FALSE,              TRUE  },
       
   275   { "wstring",              "basic_string<wchar_t>",        0,                     0,             0,             0,            0,             FALSE,              TRUE  },
       
   276   { "complex",              0,                              0,                     0,             0,             0,            0,             FALSE,              FALSE },
       
   277   { "bitset",               0,                              0,                     "Bits",        0,             0,            0,             FALSE,              FALSE },
       
   278   { "deque",                0,                              0,                     "T",           "elements",    0,            0,             FALSE,              TRUE  },
       
   279   { "list",                 0,                              0,                     "T",           "elements",    0,            0,             FALSE,              TRUE  },
       
   280   { "map",                  0,                              0,                     "K",           "keys",        "T",          "elements",    FALSE,              TRUE  },
       
   281   { "multimap",             0,                              0,                     "K",           "keys",        "T",          "elements",    FALSE,              TRUE  },
       
   282   { "set",                  0,                              0,                     "K",           "keys",        0,            0,             FALSE,              TRUE  },
       
   283   { "multiset",             0,                              0,                     "K",           "keys",        0,            0,             FALSE,              TRUE  },
       
   284   { "vector",               0,                              0,                     "T",           "elements",    0,            0,             FALSE,              TRUE  },
       
   285   { "queue",                0,                              0,                     "T",           "elements",    0,            0,             FALSE,              FALSE },
       
   286   { "priority_queue",       0,                              0,                     "T",           "elements",    0,            0,             FALSE,              FALSE },
       
   287   { "stack",                0,                              0,                     "T",           "elements",    0,            0,             FALSE,              FALSE },
       
   288   { "valarray",             0,                              0,                     "T",           "elements",    0,            0,             FALSE,              FALSE },
       
   289   { "exception",            0,                              0,                     0,             0,             0,            0,             FALSE,              FALSE },
       
   290   { "bad_alloc",            "exception",                    0,                     0,             0,             0,            0,             FALSE,              FALSE },
       
   291   { "bad_cast",             "exception",                    0,                     0,             0,             0,            0,             FALSE,              FALSE },
       
   292   { "bad_typeid",           "exception",                    0,                     0,             0,             0,            0,             FALSE,              FALSE },
       
   293   { "logic_error",          "exception",                    0,                     0,             0,             0,            0,             FALSE,              FALSE },
       
   294   { "ios_base::failure",    "exception",                    0,                     0,             0,             0,            0,             FALSE,              FALSE },
       
   295   { "runtime_error",        "exception",                    0,                     0,             0,             0,            0,             FALSE,              FALSE },
       
   296   { "bad_exception",        "exception",                    0,                     0,             0,             0,            0,             FALSE,              FALSE },
       
   297   { "domain_error",         "logic_error",                  0,                     0,             0,             0,            0,             FALSE,              FALSE },
       
   298   { "invalid_argument",     "logic_error",                  0,                     0,             0,             0,            0,             FALSE,              FALSE },
       
   299   { "length_error",         "logic_error",                  0,                     0,             0,             0,            0,             FALSE,              FALSE },
       
   300   { "out_of_range",         "logic_error",                  0,                     0,             0,             0,            0,             FALSE,              FALSE },
       
   301   { "range_error",          "runtime_error",                0,                     0,             0,             0,            0,             FALSE,              FALSE },
       
   302   { "overflow_error",       "runtime_error",                0,                     0,             0,             0,            0,             FALSE,              FALSE },
       
   303   { "underflow_error",      "runtime_error",                0,                     0,             0,             0,            0,             FALSE,              FALSE },
       
   304   { 0,                      0,                              0,                     0,             0,             0,            0,             FALSE,              FALSE }
       
   305 };
       
   306 
       
   307 static void addSTLMember(EntryNav *rootNav,const char *type,const char *name)
       
   308 {
       
   309   Entry *memEntry = new Entry;
       
   310   memEntry->name       = name;
       
   311   memEntry->type       = type;
       
   312   memEntry->protection = Private;
       
   313   memEntry->section    = Entry::VARIABLE_SEC;
       
   314   memEntry->brief      = "STL member";
       
   315   memEntry->hidden     = FALSE; 
       
   316   memEntry->artificial = TRUE;
       
   317   //memEntry->parent     = root;
       
   318   //root->addSubEntry(memEntry);
       
   319   EntryNav *memEntryNav = new EntryNav(rootNav,memEntry);
       
   320   memEntryNav->setEntry(memEntry);
       
   321   rootNav->addChild(memEntryNav);
       
   322 }
       
   323 
       
   324 static void addSTLIterator(EntryNav *classEntryNav,const char *name)
       
   325 {
       
   326   Entry *iteratorClassEntry = new Entry;
       
   327   iteratorClassEntry->fileName  = "[STL]";
       
   328   iteratorClassEntry->startLine = 1;
       
   329   iteratorClassEntry->name      = name;
       
   330   iteratorClassEntry->section   = Entry::CLASS_SEC;
       
   331   iteratorClassEntry->brief     = "STL iterator class";
       
   332   iteratorClassEntry->hidden    = FALSE;
       
   333   iteratorClassEntry->artificial= TRUE;
       
   334   EntryNav *iteratorClassEntryNav = new EntryNav(classEntryNav,iteratorClassEntry);
       
   335   iteratorClassEntryNav->setEntry(iteratorClassEntry);
       
   336   classEntryNav->addChild(iteratorClassEntryNav);
       
   337 }
       
   338 
       
   339 
       
   340 static void addSTLClasses(EntryNav *rootNav)
       
   341 {
       
   342   Entry *namespaceEntry = new Entry;
       
   343   namespaceEntry->fileName  = "[STL]";
       
   344   namespaceEntry->startLine = 1;
       
   345   //namespaceEntry->parent    = rootNav->entry();
       
   346   namespaceEntry->name      = "std";
       
   347   namespaceEntry->section   = Entry::NAMESPACE_SEC;
       
   348   namespaceEntry->brief     = "STL namespace";
       
   349   namespaceEntry->hidden    = FALSE;
       
   350   namespaceEntry->artificial= TRUE;
       
   351   //root->addSubEntry(namespaceEntry);
       
   352   EntryNav *namespaceEntryNav = new EntryNav(rootNav,namespaceEntry);
       
   353   namespaceEntryNav->setEntry(namespaceEntry);
       
   354   rootNav->addChild(namespaceEntryNav);
       
   355   
       
   356   STLInfo *info = g_stlinfo;
       
   357   while (info->className)
       
   358   {
       
   359     //printf("Adding STL class %s\n",info->className);
       
   360     QCString fullName = info->className;
       
   361     fullName.prepend("std::");
       
   362 
       
   363     // add fake Entry for the class
       
   364     Entry *classEntry = new Entry;
       
   365     classEntry->fileName  = "[STL]";
       
   366     classEntry->startLine = 1;
       
   367     classEntry->name      = fullName;
       
   368     //classEntry->parent    = namespaceEntry;
       
   369     classEntry->section   = Entry::CLASS_SEC;
       
   370     classEntry->brief     = "STL class";
       
   371     classEntry->hidden    = FALSE;
       
   372     classEntry->artificial= TRUE;
       
   373     //namespaceEntry->addSubEntry(classEntry);
       
   374     EntryNav *classEntryNav = new EntryNav(namespaceEntryNav,classEntry);
       
   375     classEntryNav->setEntry(classEntry);
       
   376     namespaceEntryNav->addChild(classEntryNav);
       
   377 
       
   378     // add template arguments to class
       
   379     if (info->templType1)
       
   380     {
       
   381       ArgumentList *al = new ArgumentList;
       
   382       Argument *a=new Argument;
       
   383       a->type="typename";
       
   384       a->name=info->templType1;
       
   385       al->append(a);
       
   386       if (info->templType2) // another template argument
       
   387       {
       
   388         a=new Argument;
       
   389         a->type="typename";
       
   390         a->name=info->templType2;
       
   391         al->append(a);
       
   392       }
       
   393       classEntry->tArgLists = new QList<ArgumentList>;
       
   394       classEntry->tArgLists->setAutoDelete(TRUE);
       
   395       classEntry->tArgLists->append(al);
       
   396     }
       
   397     // add member variables
       
   398     if (info->templName1)
       
   399     {
       
   400       addSTLMember(classEntryNav,info->templType1,info->templName1);
       
   401     }
       
   402     if (info->templName2)
       
   403     {
       
   404       addSTLMember(classEntryNav,info->templType2,info->templName2);
       
   405     }
       
   406     if (info->baseClass1)
       
   407     {
       
   408       classEntry->extends->append(new BaseInfo(info->baseClass1,Public,info->virtualInheritance?Virtual:Normal));
       
   409     }
       
   410     if (info->baseClass2)
       
   411     {
       
   412       classEntry->extends->append(new BaseInfo(info->baseClass2,Public,info->virtualInheritance?Virtual:Normal));
       
   413     }
       
   414     if (info->iterators)
       
   415     {
       
   416       // add iterator class
       
   417       addSTLIterator(classEntryNav,fullName+"::iterator");
       
   418       addSTLIterator(classEntryNav,fullName+"::const_iterator");
       
   419       addSTLIterator(classEntryNav,fullName+"::reverse_iterator");
       
   420       addSTLIterator(classEntryNav,fullName+"::const_reverse_iterator");
       
   421     }
       
   422     info++;
       
   423   }
       
   424 }
       
   425 
       
   426 //----------------------------------------------------------------------------
       
   427 
       
   428 static Definition *findScopeFromQualifiedName(Definition *startScope,const QCString &n,
       
   429                                               FileDef *fileScope=0);
       
   430 
       
   431 static void addPageToContext(PageDef *pd,EntryNav *rootNav)
       
   432 {
       
   433   if (rootNav->parent()) // add the page to it's scope
       
   434   {
       
   435     QCString scope = rootNav->parent()->name();
       
   436     if (rootNav->parent()->section()==Entry::PACKAGEDOC_SEC)
       
   437     {
       
   438       scope=substitute(scope,".","::");
       
   439     }
       
   440     scope = stripAnonymousNamespaceScope(scope);
       
   441     scope+="::"+pd->name();
       
   442     Definition *d = findScopeFromQualifiedName(Doxygen::globalScope,scope);
       
   443     if (d) 
       
   444     {
       
   445       pd->setPageScope(d);
       
   446     }
       
   447   }
       
   448 }
       
   449 
       
   450 static void addRelatedPage(EntryNav *rootNav)
       
   451 {
       
   452   Entry *root = rootNav->entry();
       
   453   GroupDef *gd=0;
       
   454   QListIterator<Grouping> gli(*root->groups);
       
   455   Grouping *g;
       
   456   for (;(g=gli.current());++gli)
       
   457   {
       
   458     if (!g->groupname.isEmpty() && (gd=Doxygen::groupSDict->find(g->groupname))) break;
       
   459   }
       
   460   //printf("---> addRelatedPage() %s gd=%p\n",root->name.data(),gd);
       
   461   QCString doc;
       
   462   if (root->brief.isEmpty())
       
   463   {
       
   464     doc=root->doc+root->inbodyDocs;
       
   465   }
       
   466   else
       
   467   {
       
   468     doc=root->brief+"\n\n"+root->doc+root->inbodyDocs;
       
   469   }
       
   470   PageDef *pd = addRelatedPage(root->name,root->args,doc,root->anchors,
       
   471       root->fileName,root->startLine,
       
   472       root->sli,
       
   473       gd,rootNav->tagInfo()
       
   474      );
       
   475   if (pd)
       
   476   {
       
   477     pd->addSectionsToDefinition(root->anchors);
       
   478     addPageToContext(pd,rootNav);
       
   479   }
       
   480 }
       
   481 
       
   482 static void buildGroupListFiltered(EntryNav *rootNav,bool additional)
       
   483 {
       
   484   if (rootNav->section()==Entry::GROUPDOC_SEC && !rootNav->name().isEmpty())
       
   485   {
       
   486     //printf("Found group %s title=`%s type=%d'\n",
       
   487     //    root->name.data(),root->type.data(),root->groupDocType);
       
   488 
       
   489     rootNav->loadEntry(g_storage);
       
   490     Entry *root = rootNav->entry();
       
   491     
       
   492     if ((root->groupDocType==Entry::GROUPDOC_NORMAL && !additional) ||
       
   493         (root->groupDocType!=Entry::GROUPDOC_NORMAL && additional))
       
   494     {
       
   495       GroupDef *gd;
       
   496 
       
   497       if ((gd=Doxygen::groupSDict->find(root->name)))
       
   498       {
       
   499         if ( !gd->hasGroupTitle() )
       
   500         {
       
   501           gd->setGroupTitle( root->type );
       
   502         }
       
   503         else if ( root->type.length() > 0 && root->name != root->type && gd->groupTitle() != root->type )
       
   504         {
       
   505           warn( root->fileName,root->startLine,
       
   506               "group %s: ignoring title \"%s\" that does not match old title \"%s\"\n",
       
   507               root->name.data(), root->type.data(), gd->groupTitle() );
       
   508         }
       
   509         gd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
       
   510         gd->setDocumentation( root->doc, root->docFile, root->docLine );
       
   511         gd->setInbodyDocumentation( root->inbodyDocs, root->inbodyFile, root->inbodyLine );
       
   512         gd->addSectionsToDefinition(root->anchors);
       
   513         gd->setRefItems(root->sli);
       
   514       }
       
   515       else
       
   516       {
       
   517         if (rootNav->tagInfo())
       
   518         {
       
   519           gd = new GroupDef(root->fileName,root->startLine,root->name,root->type,rootNav->tagInfo()->fileName);
       
   520           gd->setReference(rootNav->tagInfo()->tagName);
       
   521         }
       
   522         else
       
   523         {
       
   524           gd = new GroupDef(root->fileName,root->startLine,root->name,root->type);
       
   525         }
       
   526         gd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
       
   527         gd->setDocumentation(root->doc,root->docFile,root->docLine);
       
   528         gd->setInbodyDocumentation( root->inbodyDocs, root->inbodyFile, root->inbodyLine );
       
   529         gd->addSectionsToDefinition(root->anchors);
       
   530         Doxygen::groupSDict->append(root->name,gd);
       
   531         gd->setRefItems(root->sli);
       
   532       }
       
   533     }
       
   534 
       
   535     rootNav->releaseEntry();
       
   536   }
       
   537   if (rootNav->children())
       
   538   {
       
   539     EntryNavListIterator eli(*rootNav->children());
       
   540     EntryNav *e;
       
   541     for (;(e=eli.current());++eli)
       
   542     {
       
   543       buildGroupListFiltered(e,additional);
       
   544     }
       
   545   }
       
   546 }
       
   547 
       
   548 static void buildGroupList(EntryNav *rootNav)
       
   549 {
       
   550   // first process the @defgroups blocks
       
   551   buildGroupListFiltered(rootNav,FALSE);
       
   552   // then process the @addtogroup, @weakgroup blocks
       
   553   buildGroupListFiltered(rootNav,TRUE);
       
   554 }
       
   555 
       
   556 static void findGroupScope(EntryNav *rootNav)
       
   557 {
       
   558   if (rootNav->section()==Entry::GROUPDOC_SEC && !rootNav->name().isEmpty() && 
       
   559       rootNav->parent() && !rootNav->parent()->name().isEmpty())
       
   560   {
       
   561     GroupDef *gd;
       
   562     if ((gd=Doxygen::groupSDict->find(rootNav->name())))
       
   563     {
       
   564       QCString scope = rootNav->parent()->name();
       
   565       if (rootNav->parent()->section()==Entry::PACKAGEDOC_SEC)
       
   566       {
       
   567         scope=substitute(scope,".","::");
       
   568       }
       
   569       scope = stripAnonymousNamespaceScope(scope);
       
   570       scope+="::"+gd->name();
       
   571       Definition *d = findScopeFromQualifiedName(Doxygen::globalScope,scope);
       
   572       if (d) 
       
   573       {
       
   574         gd->setGroupScope(d);
       
   575       }
       
   576     }
       
   577   }
       
   578   RECURSE_ENTRYTREE(findGroupScope,rootNav);
       
   579 }
       
   580 
       
   581 static void organizeSubGroupsFiltered(EntryNav *rootNav,bool additional)
       
   582 {
       
   583   if (rootNav->section()==Entry::GROUPDOC_SEC && !rootNav->name().isEmpty())
       
   584   {
       
   585     rootNav->loadEntry(g_storage);
       
   586     Entry *root = rootNav->entry();
       
   587 
       
   588     if ((root->groupDocType==Entry::GROUPDOC_NORMAL && !additional) ||
       
   589         (root->groupDocType!=Entry::GROUPDOC_NORMAL && additional))
       
   590     {
       
   591       GroupDef *gd;
       
   592       if ((gd=Doxygen::groupSDict->find(root->name)))
       
   593       {
       
   594         //printf("adding %s to group %s\n",root->name.data(),gd->name().data());
       
   595         addGroupToGroups(root,gd);
       
   596       }
       
   597     }
       
   598 
       
   599     rootNav->releaseEntry();
       
   600   }
       
   601   if (rootNav->children())
       
   602   {
       
   603     EntryNavListIterator eli(*rootNav->children());
       
   604     EntryNav *e;
       
   605     for (;(e=eli.current());++eli)
       
   606     {
       
   607       organizeSubGroupsFiltered(e,additional);
       
   608     }
       
   609   }
       
   610 }
       
   611 
       
   612 static void organizeSubGroups(EntryNav *rootNav)
       
   613 {
       
   614   //printf("Defining groups\n");
       
   615   // first process the @defgroups blocks
       
   616   organizeSubGroupsFiltered(rootNav,FALSE);
       
   617   //printf("Additional groups\n");
       
   618   // then process the @addtogroup, @weakgroup blocks
       
   619   organizeSubGroupsFiltered(rootNav,TRUE);
       
   620 }
       
   621 
       
   622 //----------------------------------------------------------------------
       
   623 
       
   624 static void buildFileList(EntryNav *rootNav)
       
   625 {
       
   626   if (((rootNav->section()==Entry::FILEDOC_SEC) ||
       
   627         ((rootNav->section() & Entry::FILE_MASK) && Config_getBool("EXTRACT_ALL"))) &&
       
   628       !rootNav->name().isEmpty() && !rootNav->tagInfo() // skip any file coming from tag files
       
   629      )
       
   630   {
       
   631     rootNav->loadEntry(g_storage);
       
   632     Entry *root = rootNav->entry();
       
   633 
       
   634     bool ambig;
       
   635     FileDef *fd=findFileDef(Doxygen::inputNameDict,root->name,ambig);
       
   636     //printf("**************** root->name=%s fd=%p\n",root->name.data(),fd);
       
   637     if (fd && !ambig)
       
   638     {
       
   639 #if 0
       
   640       if ((!root->doc.isEmpty() && !fd->documentation().isEmpty()) ||
       
   641           (!root->brief.isEmpty() && !fd->briefDescription().isEmpty()))
       
   642       {
       
   643         warn(
       
   644             root->fileName,root->startLine,
       
   645             "Warning: file %s already documented. "
       
   646             "Skipping documentation.",
       
   647             root->name.data()
       
   648             );
       
   649       }
       
   650       else
       
   651 #endif
       
   652       {
       
   653         //printf("Adding documentation!\n");
       
   654         // using FALSE in setDocumentation is small hack to make sure a file 
       
   655         // is documented even if a \file command is used without further 
       
   656         // documentation
       
   657         fd->setDocumentation(root->doc,root->docFile,root->docLine,FALSE);
       
   658         fd->setBriefDescription(root->brief,root->briefFile,root->briefLine); 
       
   659         fd->addSectionsToDefinition(root->anchors);
       
   660         fd->setRefItems(root->sli);
       
   661         QListIterator<Grouping> gli(*root->groups);
       
   662         Grouping *g;
       
   663         for (;(g=gli.current());++gli)
       
   664         {
       
   665           GroupDef *gd=0;
       
   666           if (!g->groupname.isEmpty() && (gd=Doxygen::groupSDict->find(g->groupname)))
       
   667           {
       
   668             gd->addFile(fd);
       
   669             //printf("File %s: in group %s\n",fd->name().data(),s->data());
       
   670           }
       
   671         }
       
   672       }
       
   673     }
       
   674 	// NOTE: if OUTPUT_INCLUDES is true then we will see files that are not in
       
   675 	// the INPUT list
       
   676     else if (!Config_getBool("OUTPUT_INCLUDES"))
       
   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 /** Recursively dumps the include files.*/
       
  1987 void dumpIncludeGraphRecursive(const FileDef *fd, const QCString &prefix)
       
  1988 {
       
  1989 	if (fd && fd->includeFileList()) {
       
  1990 		QList<IncludeInfo> *incList = fd->includeFileList();
       
  1991 		IncludeInfo *ii;
       
  1992 		for (ii=incList->first(); ii != 0; ii=incList->next()) {
       
  1993 			FileDef *incFd = ii->fileDef;
       
  1994 			if (incFd) {
       
  1995 				Debug::print(Debug::IncludeGraph, 0, "%sInc: %s\n", prefix.data(), incFd->absFilePath().data());
       
  1996 				dumpIncludeGraphRecursive(incFd, "  "+prefix);
       
  1997 			}
       
  1998 		}
       
  1999 	}
       
  2000 }
       
  2001 
       
  2002 /** Dumps the include files.*/
       
  2003 void dumpIncludeGraph()
       
  2004 {
       
  2005 	if (Debug::isFlagSet(Debug::IncludeGraph)) {
       
  2006 		Debug::print(Debug::IncludeGraph, 0, "Include Graph:\n");
       
  2007 		FileNameListIterator incFnli(*Doxygen::inputNameList);
       
  2008 		FileName *incFnLoop;
       
  2009 		for (;(incFnLoop=incFnli.current()); ++incFnli) {
       
  2010 			FileNameIterator incFni(*incFnLoop);
       
  2011 			FileDef *fd;
       
  2012 			for (;(fd=incFni.current()); ++incFni) {
       
  2013 				Debug::print(Debug::IncludeGraph, 0, "File: %s\n", fd->absFilePath().data());
       
  2014 				dumpIncludeGraphRecursive(fd, "  ");
       
  2015 			}
       
  2016 		}
       
  2017 	}
       
  2018 }
       
  2019 
       
  2020 /** Recursively searches the supplied FileDef for an filename that
       
  2021 matches the rootFileName and returns the FileDef* of the include file or
       
  2022 0 on failure.
       
  2023 @param fd The FileDef to search.
       
  2024 @param rootFileName The filename to match on.
       
  2025 */
       
  2026 static FileDef* findIncludeMatch(const FileDef *fd, const QCString &rootFileName)
       
  2027 {
       
  2028 	if (fd && fd->includeFileList()) {
       
  2029 		// Search the include dependency list for a file that matches root->fileName
       
  2030 		QList<IncludeInfo> *incList = fd->includeFileList();
       
  2031 		IncludeInfo *ii;
       
  2032 		for (ii=incList->first(); ii != 0; ii=incList->next()) {
       
  2033 			FileDef *incFd = ii->fileDef;
       
  2034 			// NOTE: this test stops only direct recursion, not indirect recursion
       
  2035 			if (incFd && incFd != fd) {
       
  2036 				if (incFd->absFilePath() == rootFileName) {
       
  2037 					return incFd;
       
  2038 				} else {
       
  2039 					// Depth first search
       
  2040 					FileDef *recurseFd = findIncludeMatch(incFd, rootFileName);
       
  2041 					if (recurseFd) {
       
  2042 						return recurseFd;
       
  2043 					}
       
  2044 				}
       
  2045 			}
       
  2046 		}
       
  2047 	}
       
  2048 	return 0;
       
  2049 }
       
  2050 
       
  2051 /** Adds an include file represented by fd to the list of input files
       
  2052 add it to the Doxygen::inputNameList so that the back ends can see it
       
  2053 as 'forced include'.
       
  2054 @param fd The FileDef that describes the file to include.
       
  2055 */
       
  2056 static void addIncludeFileToInput(FileDef *fd)
       
  2057 {
       
  2058 	FileNameListIterator incFnli(*Doxygen::inputNameList);
       
  2059 	FileName *incFnLoop;
       
  2060 	for (;(incFnLoop=incFnli.current()); ++incFnli) {
       
  2061 		FileNameIterator incFni(*incFnLoop);
       
  2062 		FileDef *listFd;
       
  2063 		for (;(listFd=incFni.current()); ++incFni) {
       
  2064 			// TODO: Test for file name not FileDef address
       
  2065 			if (listFd == fd) {
       
  2066 				// Already have it
       
  2067 				return;
       
  2068 			}
       
  2069 		}
       
  2070 	}
       
  2071 	//printf("Forcing include file onto inputNameList: %s\n", incFd->absFilePath().data());
       
  2072 	//FileName *fn = Doxygen::inputNameList->first();
       
  2073 	FileNameList *fnList = Doxygen::inputNameList;
       
  2074 	FileName *incFn = new FileName(fd->absFilePath(), fd->name());
       
  2075 	incFn->append(fd);
       
  2076 	fnList->inSort(incFn);
       
  2077 	//printf("Forced include file pushed onto inputNameList %p: %s\n", fnList, fd->absFilePath().data());
       
  2078 }
       
  2079 
       
  2080 static MemberDef *addVariableToFile(
       
  2081     EntryNav *rootNav,
       
  2082     MemberDef::MemberType mtype,
       
  2083     const QCString &scope,
       
  2084     const QCString &name,
       
  2085     bool fromAnnScope,
       
  2086     /*int indentDepth,*/
       
  2087     MemberDef *fromAnnMemb)
       
  2088 {
       
  2089   Entry *root = rootNav->entry();
       
  2090   Debug::print(Debug::Variables,0,
       
  2091       "  global variable:\n"
       
  2092       "    type=`%s' scope=`%s' name=`%s' args=`%s' prot=`%d mtype=%d\n",
       
  2093       root->type.data(),
       
  2094       scope.data(), 
       
  2095       name.data(),
       
  2096       root->args.data(),
       
  2097       root->protection,
       
  2098       mtype
       
  2099               );
       
  2100 
       
  2101   FileDef *fd = rootNav->fileDef();
       
  2102 
       
  2103   // see if we have a typedef that should hide a struct or union
       
  2104   if (mtype==MemberDef::Typedef && Config_getBool("TYPEDEF_HIDES_STRUCT"))
       
  2105   {
       
  2106     QCString type = root->type;
       
  2107     type.stripPrefix("typedef ");
       
  2108     if (type.left(7)=="struct " || type.left(6)=="union ")
       
  2109     {
       
  2110       type.stripPrefix("struct ");
       
  2111       type.stripPrefix("union ");
       
  2112       static QRegExp re("[a-z_A-Z][a-z_A-Z0-9]*");
       
  2113       int l,s;
       
  2114       s = re.match(type,0,&l);
       
  2115       if (s>=0)
       
  2116       {
       
  2117         QCString typeValue = type.mid(s,l);
       
  2118         ClassDef *cd = getClass(typeValue);
       
  2119         if (cd)
       
  2120         {
       
  2121           // this typedef should hide compound name cd, so we
       
  2122           // change the name that is displayed from cd.
       
  2123           cd->setClassName(name);
       
  2124           cd->setDocumentation(root->doc,root->docFile,root->docLine);
       
  2125           cd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
       
  2126           return 0;
       
  2127         }
       
  2128       }
       
  2129     }
       
  2130   }
       
  2131 
       
  2132   // see if the function is inside a namespace
       
  2133   NamespaceDef *nd = 0;
       
  2134   QCString nscope;
       
  2135   if (!scope.isEmpty())
       
  2136   {
       
  2137     if (scope.find('@')!=-1) return 0; // anonymous scope!
       
  2138     //nscope=removeAnonymousScopes(scope);
       
  2139     //if (!nscope.isEmpty())
       
  2140     //{
       
  2141     nd = getResolvedNamespace(scope);
       
  2142     //}
       
  2143   }
       
  2144   QCString def;
       
  2145 
       
  2146   // determine the definition of the global variable
       
  2147   if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@' && 
       
  2148       !Config_getBool("HIDE_SCOPE_NAMES")
       
  2149      )
       
  2150     // variable is inside a namespace, so put the scope before the name
       
  2151   {
       
  2152     static bool optimizeForJava = Config_getBool("OPTIMIZE_OUTPUT_JAVA");
       
  2153     QCString sep="::";
       
  2154     if (optimizeForJava) sep=".";
       
  2155     
       
  2156     if (!root->type.isEmpty())
       
  2157     {
       
  2158       def=root->type+" "+nd->name()+sep+name+root->args;
       
  2159     }
       
  2160     else
       
  2161     {
       
  2162       def=nd->name()+sep+name+root->args;
       
  2163     }
       
  2164   }
       
  2165   else
       
  2166   {
       
  2167     if (!root->type.isEmpty() && !root->name.isEmpty())
       
  2168     {
       
  2169       if (name.at(0)=='@') // dummy variable representing annonymous union
       
  2170         def=root->type;
       
  2171       else
       
  2172         def=root->type+" "+name+root->args;
       
  2173     }
       
  2174     else
       
  2175     {
       
  2176       def=name+root->args;
       
  2177     }
       
  2178   }
       
  2179   def.stripPrefix("static ");
       
  2180 
       
  2181   MemberName *mn=Doxygen::functionNameSDict->find(name);
       
  2182   if (mn)
       
  2183   {
       
  2184     //QCString nscope=removeAnonymousScopes(scope);
       
  2185     //NamespaceDef *nd=0;
       
  2186     //if (!nscope.isEmpty())
       
  2187     if (!scope.isEmpty())
       
  2188     {
       
  2189       nd = getResolvedNamespace(scope);
       
  2190     }
       
  2191     MemberNameIterator mni(*mn);
       
  2192     MemberDef *md;
       
  2193     for (mni.toFirst();(md=mni.current());++mni)
       
  2194     {
       
  2195       if (
       
  2196           ((nd==0 && md->getNamespaceDef()==0 && md->getFileDef() && 
       
  2197             root->fileName==md->getFileDef()->absFilePath()
       
  2198            ) // both variable names in the same file
       
  2199            || (nd!=0 && md->getNamespaceDef()==nd) // both in same namespace
       
  2200           )
       
  2201           && !md->isDefine() // function style #define's can be "overloaded" by typedefs or variables
       
  2202           && !md->isEnumerate() // in C# an enum value and enum can have the same name
       
  2203          )
       
  2204         // variable already in the scope
       
  2205       {
       
  2206         if (md->getFileDef() &&
       
  2207             ! // not a php array
       
  2208              (
       
  2209                (getLanguageFromFileName(md->getFileDef()->name())==SrcLangExt_PHP) &&
       
  2210                (md->argsString()!=root->args && root->args.find('[')!=-1)
       
  2211              )
       
  2212            ) 
       
  2213           // not a php array variable
       
  2214         {
       
  2215 
       
  2216           Debug::print(Debug::Variables,0,
       
  2217               "    variable already found: scope=%s\n",md->getOuterScope()->name().data());
       
  2218           addMemberDocs(rootNav,md,def,0,FALSE);
       
  2219           md->setRefItems(root->sli);
       
  2220           return md;
       
  2221         }
       
  2222       }
       
  2223     } 
       
  2224   }
       
  2225   Debug::print(Debug::Variables,0,
       
  2226     "    new variable, nd=%s!\n",nd?nd->name().data():"<global>");
       
  2227   // new global variable, enum value or typedef
       
  2228   MemberDef *md=new MemberDef(
       
  2229       root->fileName,root->startLine,
       
  2230       root->type,name,root->args,0,
       
  2231       Public, Normal,root->stat,Member,
       
  2232       mtype,0,0);
       
  2233   md->setTagInfo(rootNav->tagInfo());
       
  2234   md->setDocumentation(root->doc,root->docFile,root->docLine);
       
  2235   md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
       
  2236   md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
       
  2237   md->addSectionsToDefinition(root->anchors);
       
  2238   md->setFromAnonymousScope(fromAnnScope);
       
  2239   md->setFromAnonymousMember(fromAnnMemb);
       
  2240   md->setInitializer(root->initializer);
       
  2241   md->setMaxInitLines(root->initLines);
       
  2242   md->setMemberGroupId(root->mGrpId);
       
  2243   md->setDefinition(def);
       
  2244   md->enableCallGraph(root->callGraph);
       
  2245   md->enableCallerGraph(root->callerGraph);
       
  2246   md->setExplicitExternal(root->explicitExternal);
       
  2247   //md->setOuterScope(fd);
       
  2248   if (!root->explicitExternal)
       
  2249   {
       
  2250     md->setBodySegment(root->bodyLine,root->endBodyLine);
       
  2251     md->setBodyDef(fd);
       
  2252   }
       
  2253   addMemberToGroups(root,md);
       
  2254 
       
  2255   md->setRefItems(root->sli);
       
  2256   if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@')
       
  2257   {
       
  2258     md->setNamespace(nd);
       
  2259     nd->insertMember(md); 
       
  2260   }
       
  2261 
       
  2262   // add member to the file (we do this even if we have already inserted
       
  2263   // it into the namespace. 
       
  2264   if (fd)
       
  2265   {
       
  2266 		//printf("Setting FileDef %s\n", fd->fileName().data());
       
  2267 		if (root->fileName != fd->absFilePath()) {
       
  2268 			//printf("addVariableToFile() Missmatch Name=\"%s\" Root=%s, FileDef=%s\n",
       
  2269 			//	name.data(),
       
  2270 			//	root->fileName.data(),
       
  2271 			//	fd->absFilePath().data()
       
  2272 			//	);
       
  2273 			// Now search the include dependency list for a file that matches root->fileName
       
  2274 			FileDef *incFd = findIncludeMatch(fd, root->fileName);
       
  2275 			if (incFd) {
       
  2276 				//printf("Found include file match on: %s\n", incFd->absFilePath().data());
       
  2277 				// If found add this FileDef* to the member and add the MemberDef* to the FileDef
       
  2278 				md->setFileDef(incFd);
       
  2279 				incFd->insertMember(md);
       
  2280 				md->setBodyDef(incFd);
       
  2281 				// If this FileDef is not in Doxygen::inputNameList and
       
  2282 				// Config_getBool("OUTPUT_INCLUDES") is true then
       
  2283 				// add it to the Doxygen::inputNameList so that the back ends
       
  2284 				// can see it as 'forced include'.
       
  2285 				if (Config_getBool("OUTPUT_INCLUDES")) {
       
  2286 					addIncludeFileToInput(incFd);
       
  2287 				}
       
  2288 			} else {
       
  2289 				printf("Warning: addVariableToFile() failed to resolve missmatch Name=\"%s\" Root=%s, FileDef=%s\n",
       
  2290 					name.data(),
       
  2291 					root->fileName.data(),
       
  2292 					fd->absFilePath().data()
       
  2293 					);
       
  2294 				//md->setFileDef(fd);
       
  2295 				//fd->insertMember(md);
       
  2296 			}
       
  2297 	  } else {
       
  2298 		//printf("addVariableToFile() Match OK FileDef=%s\n", fd->absFilePath().data());
       
  2299 		md->setFileDef(fd); 
       
  2300 		fd->insertMember(md);
       
  2301 	  }
       
  2302   }
       
  2303 
       
  2304   // add member definition to the list of globals 
       
  2305   if (mn)
       
  2306   {
       
  2307     mn->append(md);
       
  2308   }
       
  2309   else
       
  2310   {
       
  2311     mn = new MemberName(name);
       
  2312     mn->append(md);
       
  2313 	// PaulRoss: This first line looks wrong to me but links to typedef's don't work without it!
       
  2314     Doxygen::functionNameSDict->append(name,mn);
       
  2315     //Doxygen::memberNameSDict->append(name,mn);
       
  2316   }
       
  2317   rootNav->changeSection(Entry::EMPTY_SEC);
       
  2318   return md;
       
  2319 }
       
  2320 
       
  2321 /*! See if the return type string \a type is that of a function pointer 
       
  2322  *  \returns -1 if this is not a function pointer variable or
       
  2323  *           the index at which the brace of (...*name) was found.
       
  2324  */
       
  2325 static int findFunctionPtr(const QCString &type,int *pLength=0)
       
  2326 {
       
  2327   static const QRegExp re("([^)]*\\*[^)]*)");
       
  2328   int i=-1,l;
       
  2329   if (!type.isEmpty() &&             // return type is non-empty
       
  2330       (i=re.match(type,0,&l))!=-1 && // contains (...*...)
       
  2331       type.find("operator")==-1 &&   // not an operator
       
  2332       (type.find(")(")==-1 || type.find("typedef ")!=-1)
       
  2333                                     // not a function pointer return type
       
  2334      )
       
  2335   {
       
  2336     if (pLength) *pLength=l;
       
  2337     return i;
       
  2338   }
       
  2339   else
       
  2340   {
       
  2341     return -1;
       
  2342   }
       
  2343 }
       
  2344 
       
  2345 
       
  2346 /*! Returns TRUE iff \a type is a class within scope \a context.
       
  2347  *  Used to detect variable declarations that look like function prototypes.
       
  2348  */
       
  2349 static bool isVarWithConstructor(EntryNav *rootNav)
       
  2350 {
       
  2351   static QRegExp initChars("[0-9\"'&*!^]+");
       
  2352   static QRegExp idChars("[a-z_A-Z][a-z_A-Z0-9]*");
       
  2353   bool result=FALSE;
       
  2354   bool typeIsClass;
       
  2355   QCString type;
       
  2356   Definition *ctx = 0;
       
  2357   FileDef *fd = 0;
       
  2358   int ti;
       
  2359 
       
  2360   //printf("isVarWithConstructor(%s)\n",rootNav->name().data());
       
  2361   rootNav->loadEntry(g_storage);
       
  2362   Entry *root = rootNav->entry();
       
  2363 
       
  2364   if (rootNav->parent()->section() & Entry::COMPOUND_MASK)
       
  2365   { // inside a class
       
  2366     result=FALSE;
       
  2367     goto done;
       
  2368   }
       
  2369   else if ((fd = rootNav->fileDef()) &&
       
  2370             (fd->name().right(2)==".c" || fd->name().right(2)==".h")
       
  2371           )
       
  2372   { // inside a .c file
       
  2373     result=FALSE;
       
  2374     goto done;
       
  2375   }
       
  2376   if (root->type.isEmpty()) 
       
  2377   {
       
  2378     result=FALSE;
       
  2379     goto done;
       
  2380   }
       
  2381   if (!rootNav->parent()->name().isEmpty()) 
       
  2382   {
       
  2383     ctx=Doxygen::namespaceSDict->find(rootNav->parent()->name());
       
  2384   }
       
  2385   type = root->type;
       
  2386   // remove qualifiers
       
  2387   findAndRemoveWord(type,"const");
       
  2388   findAndRemoveWord(type,"static");
       
  2389   findAndRemoveWord(type,"volatile");
       
  2390   //if (type.left(6)=="const ") type=type.right(type.length()-6);
       
  2391   typeIsClass=getResolvedClass(ctx,fd,type)!=0;
       
  2392   if (!typeIsClass && (ti=type.find('<'))!=-1)
       
  2393   {
       
  2394     typeIsClass=getResolvedClass(ctx,fd,type.left(ti))!=0;
       
  2395   }
       
  2396   if (typeIsClass) // now we still have to check if the arguments are 
       
  2397                    // types or values. Since we do not have complete type info
       
  2398                    // we need to rely on heuristics :-(
       
  2399   {
       
  2400     //printf("typeIsClass\n");
       
  2401     ArgumentList *al = root->argList;
       
  2402     if (al==0 || al->isEmpty()) 
       
  2403     {
       
  2404       result=FALSE; // empty arg list -> function prototype.
       
  2405       goto done;
       
  2406     }
       
  2407     ArgumentListIterator ali(*al);
       
  2408     Argument *a;
       
  2409     for (ali.toFirst();(a=ali.current());++ali)
       
  2410     {
       
  2411       if (!a->name.isEmpty() || !a->defval.isEmpty()) 
       
  2412       {
       
  2413         if (a->name.find(initChars)==0)
       
  2414         {
       
  2415           result=TRUE;
       
  2416         }
       
  2417         else
       
  2418         {
       
  2419           result=FALSE; // arg has (type,name) pair -> function prototype
       
  2420         }
       
  2421         goto done;
       
  2422       }
       
  2423       if (a->type.isEmpty() || getResolvedClass(ctx,fd,a->type)!=0) 
       
  2424       {
       
  2425         result=FALSE; // arg type is a known type
       
  2426         goto done;
       
  2427       }
       
  2428       if (checkIfTypedef(ctx,fd,a->type))
       
  2429       {
       
  2430          //printf("%s:%d: false (arg is typedef)\n",__FILE__,__LINE__);
       
  2431          result=FALSE; // argument is a typedef
       
  2432          goto done;
       
  2433       }
       
  2434       if (a->type.at(a->type.length()-1)=='*' ||
       
  2435           a->type.at(a->type.length()-1)=='&')  
       
  2436                      // type ends with * or & => pointer or reference
       
  2437       {
       
  2438         result=FALSE;
       
  2439         goto done;
       
  2440       }
       
  2441       if (a->type.find(initChars)==0) 
       
  2442       {
       
  2443         result=TRUE; // argument type starts with typical initializer char
       
  2444         goto done;
       
  2445       }
       
  2446       QCString resType=resolveTypeDef(ctx,a->type);
       
  2447       if (resType.isEmpty()) resType=a->type;
       
  2448       int len;
       
  2449       if (idChars.match(resType,0,&len)==0) // resType starts with identifier
       
  2450       {
       
  2451         resType=resType.left(len);
       
  2452         //printf("resType=%s\n",resType.data());
       
  2453         if (resType=="int"    || resType=="long" || resType=="float" || 
       
  2454             resType=="double" || resType=="char" || resType=="signed" || 
       
  2455             resType=="const"  || resType=="unsigned" || resType=="void") 
       
  2456         {
       
  2457           result=FALSE; // type keyword -> function prototype
       
  2458           goto done;
       
  2459         }
       
  2460       }
       
  2461     }
       
  2462     result=TRUE;
       
  2463   }
       
  2464 
       
  2465 done:
       
  2466   //printf("isVarWithConstructor(%s,%s)=%d\n",rootNav->parent()->name().data(),
       
  2467   //                                          root->type.data(),result);
       
  2468   rootNav->releaseEntry();
       
  2469   return result;
       
  2470 }
       
  2471 
       
  2472 static void addVariable(EntryNav *rootNav,int isFuncPtr=-1)
       
  2473 {
       
  2474     rootNav->loadEntry(g_storage);
       
  2475     Entry *root = rootNav->entry();
       
  2476 
       
  2477     Debug::print(Debug::Variables,0,
       
  2478                   "VARIABLE_SEC: \n"
       
  2479                   "  type=`%s' name=`%s' args=`%s' bodyLine=`%d' mGrpId=%d\n",
       
  2480                    root->type.data(),
       
  2481                    root->name.data(),
       
  2482                    root->args.data(),
       
  2483                    root->bodyLine,
       
  2484                    root->mGrpId
       
  2485                 );
       
  2486 	//Entry *pParent = root->parent();
       
  2487 	//if (pParent) {
       
  2488 	//	printf("root->parent->name=%s\n",root->parent()->name.data());
       
  2489 	//} else {
       
  2490 	//	printf("NO Parent\n");
       
  2491 	//}
       
  2492     if (root->type.isEmpty() && root->name.find("operator")==-1 &&
       
  2493         (root->name.find('*')!=-1 || root->name.find('&')!=-1))
       
  2494     {
       
  2495       // recover from parse error caused by redundant braces 
       
  2496       // like in "int *(var[10]);", which is parsed as
       
  2497       // type="" name="int *" args="(var[10])"
       
  2498 
       
  2499       root->type=root->name;
       
  2500       static const QRegExp reName("[a-z_A-Z][a-z_A-Z0-9]*");
       
  2501       int l;
       
  2502       int i=root->args.isEmpty() ? -1 : reName.match(root->args,0,&l);
       
  2503       root->name=root->args.mid(i,l);
       
  2504       root->args=root->args.mid(i+l,root->args.find(')',i+l)-i-l);
       
  2505       //printf("new: type=`%s' name=`%s' args=`%s'\n",
       
  2506       //    root->type.data(),root->name.data(),root->args.data());
       
  2507     }
       
  2508     else
       
  2509     {
       
  2510       int i=isFuncPtr;
       
  2511       if (i==-1) i=findFunctionPtr(root->type); // for typedefs isFuncPtr is not yet set
       
  2512       if (i!=-1) // function pointer
       
  2513       {
       
  2514         int ai = root->type.find('[',i);
       
  2515         if (ai>i) // function pointer array
       
  2516         {
       
  2517           root->args.prepend(root->type.right(root->type.length()-ai));
       
  2518           root->type=root->type.left(ai);
       
  2519         }
       
  2520         else if (root->type.find(')',i)!=-1) // function ptr, not variable like "int (*bla)[10]"
       
  2521         {
       
  2522           root->type=root->type.left(root->type.length()-1);
       
  2523           root->args.prepend(")");
       
  2524           //printf("root->type=%s root->args=%s\n",root->type.data(),root->args.data());
       
  2525         }
       
  2526       }
       
  2527       else if (root->type.find("typedef ")!=-1 && root->type.right(2)=="()") // typedef void (func)(int)
       
  2528       {
       
  2529         root->type=root->type.left(root->type.length()-1);
       
  2530         root->args.prepend(")");
       
  2531       }
       
  2532     }
       
  2533     
       
  2534     QCString scope,name=removeRedundantWhiteSpace(root->name);
       
  2535 
       
  2536     // find the scope of this variable 
       
  2537     EntryNav *p = rootNav->parent();
       
  2538     while ((p->section() & Entry::SCOPE_MASK))
       
  2539     {
       
  2540       QCString scopeName = p->name();
       
  2541       if (!scopeName.isEmpty())
       
  2542       {
       
  2543         scope.prepend(scopeName);
       
  2544         break;
       
  2545       }
       
  2546       p=p->parent();
       
  2547     }
       
  2548     
       
  2549     MemberDef::MemberType mtype;
       
  2550     QCString type=root->type.stripWhiteSpace();
       
  2551     ClassDef *cd=0;
       
  2552     bool isRelated=FALSE;
       
  2553     bool isMemberOf=FALSE;
       
  2554 
       
  2555     QCString classScope=stripAnonymousNamespaceScope(scope);
       
  2556     classScope=stripTemplateSpecifiersFromScope(classScope,FALSE);
       
  2557     QCString annScopePrefix=scope.left(scope.length()-classScope.length());
       
  2558 
       
  2559     if (root->name.findRev("::")!=-1) 
       
  2560     {
       
  2561       if (root->type=="friend class" || root->type=="friend struct" || 
       
  2562           root->type=="friend union")
       
  2563       {
       
  2564          cd=getClass(scope);
       
  2565          if (cd)
       
  2566          {
       
  2567            addVariableToClass(rootNav,  // entry
       
  2568                               cd,    // class to add member to
       
  2569                               MemberDef::Friend, // type of member
       
  2570                               name, // name of the member
       
  2571                               FALSE,  // from Anonymous scope
       
  2572                               0,      // anonymous member
       
  2573                               Public, // protection
       
  2574                               Member  // related to a class
       
  2575                              );
       
  2576          }
       
  2577       }
       
  2578       goto nextMember;
       
  2579                /* skip this member, because it is a 
       
  2580                 * static variable definition (always?), which will be
       
  2581                 * found in a class scope as well, but then we know the
       
  2582                 * correct protection level, so only then it will be
       
  2583                 * inserted in the correct list!
       
  2584                 */
       
  2585     }
       
  2586 
       
  2587     if (type=="@") 
       
  2588       mtype=MemberDef::EnumValue;
       
  2589     else if (type.left(8)=="typedef ") 
       
  2590       mtype=MemberDef::Typedef;
       
  2591     else if (type.left(7)=="friend ")
       
  2592       mtype=MemberDef::Friend;
       
  2593     else if (root->mtype==Property)
       
  2594       mtype=MemberDef::Property;
       
  2595     else if (root->mtype==Event)
       
  2596       mtype=MemberDef::Event;
       
  2597     else
       
  2598       mtype=MemberDef::Variable;
       
  2599 
       
  2600     if (!root->relates.isEmpty()) // related variable
       
  2601     {
       
  2602       isRelated=TRUE;
       
  2603       isMemberOf=(root->relatesType == MemberOf);
       
  2604       if (getClass(root->relates)==0 && !scope.isEmpty())
       
  2605         scope=mergeScopes(scope,root->relates);
       
  2606       else 
       
  2607         scope=root->relates;
       
  2608     }
       
  2609     
       
  2610     cd=getClass(scope);
       
  2611     if (cd==0 && classScope!=scope) cd=getClass(classScope);
       
  2612     if (cd)
       
  2613     {
       
  2614       MemberDef *md=0;
       
  2615 
       
  2616       // if cd is an annonymous scope we insert the member 
       
  2617       // into a non-annonymous scope as well. This is needed to
       
  2618       // be able to refer to it using \var or \fn
       
  2619 
       
  2620       //int indentDepth=0;
       
  2621       int si=scope.find('@');
       
  2622       //int anonyScopes = 0;
       
  2623       bool added=FALSE;
       
  2624       
       
  2625       if (si!=-1) // anonymous scope
       
  2626       {
       
  2627         QCString pScope;
       
  2628         ClassDef *pcd=0;
       
  2629         pScope = scope.left(QMAX(si-2,0));
       
  2630         if (!pScope.isEmpty())
       
  2631           pScope.prepend(annScopePrefix);
       
  2632         else if (annScopePrefix.length()>2)
       
  2633           pScope=annScopePrefix.left(annScopePrefix.length()-2);
       
  2634         if (name.at(0)!='@')
       
  2635         {
       
  2636           if (!pScope.isEmpty() && (pcd=getClass(pScope)))
       
  2637           {
       
  2638             md=addVariableToClass(rootNav,  // entry
       
  2639                                   pcd,   // class to add member to
       
  2640                                   mtype, // member type
       
  2641                                   name,  // member name
       
  2642                                   TRUE,  // from anonymous scope
       
  2643                                   0,     // from anonymous member
       
  2644                                   root->protection,
       
  2645                                   isMemberOf ? Foreign : isRelated ? Related : Member
       
  2646                                  );
       
  2647             added=TRUE;
       
  2648           }
       
  2649           else // anonymous scope inside namespace or file => put variable in the global scope
       
  2650           {
       
  2651             if (mtype==MemberDef::Variable)
       
  2652             {
       
  2653               md=addVariableToFile(rootNav,mtype,pScope,name,TRUE,0); 
       
  2654             }
       
  2655             added=TRUE;
       
  2656           }
       
  2657         }
       
  2658       }
       
  2659 
       
  2660       //printf("name=`%s' scope=%s scope.right=%s\n",
       
  2661       //                   name.data(),scope.data(),
       
  2662       //                   scope.right(scope.length()-si).data());
       
  2663       addVariableToClass(rootNav,   // entry
       
  2664                          cd,     // class to add member to
       
  2665                          mtype,  // member type
       
  2666                          name,   // name of the member
       
  2667                          FALSE,  // from anonymous scope
       
  2668                          md,     // from anonymous member
       
  2669                          root->protection, 
       
  2670                          isMemberOf ? Foreign : isRelated ? Related : Member);
       
  2671     }
       
  2672     else if (!name.isEmpty()) // global variable
       
  2673     {
       
  2674       //printf("Inserting member in global scope %s!\n",scope.data());
       
  2675       addVariableToFile(rootNav,mtype,scope,name,FALSE,/*0,*/0);
       
  2676     }
       
  2677 
       
  2678 nextMember:
       
  2679     rootNav->releaseEntry();
       
  2680 }
       
  2681 
       
  2682 //----------------------------------------------------------------------
       
  2683 // Searches the Entry tree for typedef documentation sections.
       
  2684 // If found they are stored in their class or in the global list.
       
  2685 static void buildTypedefList(EntryNav *rootNav)
       
  2686 {
       
  2687   //printf("buildVarList(%s)\n",rootNav->name().data());
       
  2688   if (!rootNav->name().isEmpty() &&
       
  2689       rootNav->section()==Entry::VARIABLE_SEC &&
       
  2690       rootNav->type().find("typedef ")!=-1 // its a typedef
       
  2691      ) 
       
  2692   {
       
  2693     addVariable(rootNav);
       
  2694 	//printf("addVariable() done\n");
       
  2695   }
       
  2696   if (rootNav->children())
       
  2697   {
       
  2698     EntryNavListIterator eli(*rootNav->children());
       
  2699     EntryNav *e;
       
  2700     for (;(e=eli.current());++eli)
       
  2701     {
       
  2702       if (e->section()!=Entry::ENUM_SEC) 
       
  2703       {
       
  2704         buildTypedefList(e);
       
  2705       }
       
  2706     }
       
  2707   }
       
  2708 }
       
  2709 
       
  2710 //----------------------------------------------------------------------
       
  2711 // Searches the Entry tree for Variable documentation sections.
       
  2712 // If found they are stored in their class or in the global list.
       
  2713 
       
  2714 static void buildVarList(EntryNav *rootNav)
       
  2715 {
       
  2716   //printf("buildVarList(%s)\n",rootNav->name().data());
       
  2717   int isFuncPtr=-1;
       
  2718   if (!rootNav->name().isEmpty() &&
       
  2719       (rootNav->type().isEmpty() || g_compoundKeywordDict.find(rootNav->type())==0) &&
       
  2720       (
       
  2721        (rootNav->section()==Entry::VARIABLE_SEC    // it's a variable
       
  2722        ) ||
       
  2723        (rootNav->section()==Entry::FUNCTION_SEC && // or maybe a function pointer variable 
       
  2724         (isFuncPtr=findFunctionPtr(rootNav->type()))!=-1
       
  2725        ) ||
       
  2726        (rootNav->section()==Entry::FUNCTION_SEC && // class variable initialized by constructor
       
  2727         isVarWithConstructor(rootNav)
       
  2728        )
       
  2729       ) 
       
  2730      ) // documented variable
       
  2731   {
       
  2732     addVariable(rootNav,isFuncPtr);
       
  2733   }
       
  2734   if (rootNav->children())
       
  2735   {
       
  2736     EntryNavListIterator eli(*rootNav->children());
       
  2737     EntryNav *e;
       
  2738     for (;(e=eli.current());++eli)
       
  2739     {
       
  2740       if (e->section()!=Entry::ENUM_SEC) 
       
  2741       {
       
  2742         buildVarList(e);
       
  2743       }
       
  2744     }
       
  2745   }
       
  2746 }
       
  2747 
       
  2748 //----------------------------------------------------------------------
       
  2749 // Searches the Entry tree for Function sections.
       
  2750 // If found they are stored in their class or in the global list.
       
  2751 
       
  2752 static void addMethodToClass(EntryNav *rootNav,ClassDef *cd,
       
  2753                   const QCString &rname,bool isFriend)
       
  2754 {
       
  2755   Entry *root = rootNav->entry();
       
  2756   FileDef *fd=rootNav->fileDef();
       
  2757 
       
  2758   int l,i=-1;
       
  2759   static QRegExp re("([a-z_A-Z0-9: ]*[ &*]+[ ]*");
       
  2760 
       
  2761   if (!root->type.isEmpty() && (i=re.match(root->type,0,&l))!=-1) // function variable
       
  2762   {
       
  2763     root->args+=root->type.right(root->type.length()-i-l);
       
  2764     root->type=root->type.left(i+l);
       
  2765   }
       
  2766 
       
  2767   QCString name=removeRedundantWhiteSpace(rname);
       
  2768   if (name.left(2)=="::") name=name.right(name.length()-2);
       
  2769 
       
  2770   MemberDef::MemberType mtype;
       
  2771   if (isFriend)                 mtype=MemberDef::Friend;
       
  2772   else if (root->mtype==Signal) mtype=MemberDef::Signal;
       
  2773   else if (root->mtype==Slot)   mtype=MemberDef::Slot;
       
  2774   else if (root->mtype==DCOP)   mtype=MemberDef::DCOP;
       
  2775   else                          mtype=MemberDef::Function;
       
  2776 
       
  2777   // strip redundant template specifier for constructors
       
  2778   if ((fd==0 || getLanguageFromFileName(fd->name())==SrcLangExt_Cpp) &&
       
  2779      name.left(9)!="operator " && (i=name.find('<'))!=-1 && name.find('>')!=-1)
       
  2780   {
       
  2781     name=name.left(i); 
       
  2782   }
       
  2783   if (Config_getBool("PREPROCESS_INCLUDES")) {
       
  2784     // If we are preprocessing the #included files we might have seen
       
  2785     // this member  more than once so we
       
  2786     // only add a member where one did not exist before
       
  2787 	  QCString myDefName = name;
       
  2788 	  myDefName.append(root->args);
       
  2789 	  if(cd->hasFunction(myDefName, root->protection)) {
       
  2790 	  //if (Doxygen::memberNameSDict->find(name)) {
       
  2791 		//printf("addMethodToClass() rejecting: %p %d %s::%s\n", cd, root->protection, cd->name().data(), myDefName.data());
       
  2792 		return;
       
  2793 	}
       
  2794 	//printf("addMethodToClass() accepting: %p %d %s::%s\n", cd, root->protection, cd->name().data(), myDefName.data());
       
  2795   }
       
  2796 
       
  2797   //printf("root->name=`%s; root->args=`%s' root->argList=`%s'\n", 
       
  2798   //    root->name.data(),root->args.data(),argListToString(root->argList).data()
       
  2799   //   );
       
  2800 
       
  2801   // adding class member
       
  2802   MemberDef *md=new MemberDef(
       
  2803       root->fileName,root->startLine,
       
  2804       root->type,name,root->args,root->exception,
       
  2805       root->protection,root->virt,
       
  2806       root->stat && root->relatesType != MemberOf,
       
  2807       root->relates.isEmpty() ? Member :
       
  2808           root->relatesType == MemberOf ? Foreign : Related,
       
  2809       mtype,root->tArgLists ? root->tArgLists->last() : 0,root->argList);
       
  2810   md->setTagInfo(rootNav->tagInfo());
       
  2811   md->setMemberClass(cd);
       
  2812   md->setDocumentation(root->doc,root->docFile,root->docLine);
       
  2813   md->setDocsForDefinition(!root->proto);
       
  2814   md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
       
  2815   md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
       
  2816   md->setBodySegment(root->bodyLine,root->endBodyLine);
       
  2817   md->setMemberSpecifiers(root->spec);
       
  2818   md->setMemberGroupId(root->mGrpId);
       
  2819   md->setTypeConstraints(root->typeConstr);
       
  2820   md->setBodyDef(fd);
       
  2821   md->setFileDef(fd);
       
  2822   //md->setScopeTemplateArguments(root->tArgList);
       
  2823   md->addSectionsToDefinition(root->anchors);
       
  2824   QCString def;
       
  2825   QCString qualScope = cd->qualifiedNameWithTemplateParameters();
       
  2826   QCString scopeSeparator="::";
       
  2827   if (Config_getBool("OPTIMIZE_OUTPUT_JAVA"))
       
  2828   {
       
  2829     qualScope = substitute(qualScope,"::",".");
       
  2830     scopeSeparator=".";
       
  2831   }
       
  2832   if (!root->relates.isEmpty() || isFriend || Config_getBool("HIDE_SCOPE_NAMES"))
       
  2833   {
       
  2834     if (!root->type.isEmpty())
       
  2835     {
       
  2836       if (root->argList)
       
  2837       {
       
  2838         def=root->type+" "+name;
       
  2839       }
       
  2840       else
       
  2841       {
       
  2842         def=root->type+" "+name+root->args;
       
  2843       }
       
  2844     }
       
  2845     else
       
  2846     {
       
  2847       if (root->argList)
       
  2848       {
       
  2849         def=name;
       
  2850       }
       
  2851       else
       
  2852       {
       
  2853         def=name+root->args;
       
  2854       }
       
  2855     }
       
  2856   }
       
  2857   else
       
  2858   {
       
  2859     if (!root->type.isEmpty())
       
  2860     {
       
  2861       if (root->argList)
       
  2862       {
       
  2863         def=root->type+" "+qualScope+scopeSeparator+name;
       
  2864       }
       
  2865       else
       
  2866       {
       
  2867         def=root->type+" "+qualScope+scopeSeparator+name+root->args;
       
  2868       }
       
  2869     }
       
  2870     else
       
  2871     {
       
  2872       if (root->argList)
       
  2873       {
       
  2874         def=qualScope+scopeSeparator+name;
       
  2875       }
       
  2876       else
       
  2877       {
       
  2878         def=qualScope+scopeSeparator+name+root->args;
       
  2879       }
       
  2880     }
       
  2881   }
       
  2882   if (def.left(7)=="friend ") def=def.right(def.length()-7);
       
  2883   md->setDefinition(def);
       
  2884   md->enableCallGraph(root->callGraph);
       
  2885   md->enableCallerGraph(root->callerGraph);
       
  2886 
       
  2887   Debug::print(Debug::Functions,0,
       
  2888       "  Func Member:\n"
       
  2889       "    `%s' `%s'::`%s' `%s' proto=%d\n"
       
  2890       "    def=`%s'\n",
       
  2891       root->type.data(),
       
  2892       qualScope.data(),
       
  2893       rname.data(),
       
  2894       root->args.data(),
       
  2895       root->proto,
       
  2896       def.data()
       
  2897               );
       
  2898 
       
  2899   // add member to the global list of all members
       
  2900   //printf("Adding member=%s class=%s\n",md->name().data(),cd->name().data());
       
  2901   MemberName *mn;
       
  2902   if ((mn=Doxygen::memberNameSDict->find(name)))
       
  2903   {
       
  2904     mn->append(md);
       
  2905   }
       
  2906   else
       
  2907   {
       
  2908     mn = new MemberName(name);
       
  2909     mn->append(md);
       
  2910     Doxygen::memberNameSDict->append(name,mn);
       
  2911   }
       
  2912 
       
  2913   // add member to the class cd
       
  2914   cd->insertMember(md);
       
  2915   // add file to list of used files
       
  2916   cd->insertUsedFile(root->fileName);
       
  2917 
       
  2918   addMemberToGroups(root,md);
       
  2919   rootNav->changeSection(Entry::EMPTY_SEC);
       
  2920   md->setRefItems(root->sli);
       
  2921 }
       
  2922 
       
  2923 
       
  2924 static void buildFunctionList(EntryNav *rootNav)
       
  2925 {
       
  2926   if (rootNav->section()==Entry::FUNCTION_SEC)
       
  2927   {
       
  2928     rootNav->loadEntry(g_storage);
       
  2929     Entry *root = rootNav->entry();
       
  2930 
       
  2931     Debug::print(Debug::Functions,0,
       
  2932                  "FUNCTION_SEC:\n"
       
  2933                  "  `%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",
       
  2934                  root->type.data(),
       
  2935                  rootNav->parent()->name().data(),
       
  2936                  root->name.data(),
       
  2937                  root->args.data(),
       
  2938                  root->relates.data(),
       
  2939                  root->relatesType,
       
  2940                  root->fileName.data(),
       
  2941                  root->startLine,
       
  2942                  root->bodyLine,
       
  2943                  root->tArgLists ? (int)root->tArgLists->count() : -1,
       
  2944                  root->mGrpId,
       
  2945                  root->spec,
       
  2946                  root->proto,
       
  2947                  root->docFile.data()
       
  2948                 );
       
  2949 
       
  2950     bool isFriend=root->type.find("friend ")!=-1;
       
  2951     QCString rname = removeRedundantWhiteSpace(root->name);
       
  2952     //printf("rname=%s\n",rname.data());
       
  2953 
       
  2954     QCString scope=rootNav->parent()->name(); //stripAnonymousNamespaceScope(root->parent->name);
       
  2955     if (!rname.isEmpty() && scope.find('@')==-1)
       
  2956     {
       
  2957       ClassDef *cd=0;
       
  2958       // check if this function's parent is a class
       
  2959       scope=stripTemplateSpecifiersFromScope(scope,FALSE);
       
  2960 
       
  2961       FileDef *rfd=rootNav->fileDef();
       
  2962 
       
  2963       int memIndex=rname.findRev("::");
       
  2964 
       
  2965       cd=getClass(scope);
       
  2966       if (cd && scope+"::"==rname.left(scope.length()+2)) // found A::f inside A
       
  2967       {
       
  2968         // strip scope from name
       
  2969         rname=rname.right(rname.length()-rootNav->parent()->name().length()-2); 
       
  2970       }
       
  2971 
       
  2972       NamespaceDef *nd = 0;
       
  2973       bool isMember=FALSE;
       
  2974       if (memIndex!=-1)
       
  2975       {
       
  2976         int ts=rname.find('<');
       
  2977         int te=rname.find('>');
       
  2978         if (memIndex>0 && (ts==-1 || te==-1))
       
  2979         {
       
  2980           // note: the following code was replaced by inMember=TRUE to deal with a 
       
  2981           // function rname='X::foo' of class X inside a namespace also called X...
       
  2982           // bug id 548175
       
  2983           //nd = Doxygen::namespaceSDict->find(rname.left(memIndex));
       
  2984           //isMember = nd==0;
       
  2985           //if (nd)
       
  2986           //{
       
  2987           //  // strip namespace scope from name
       
  2988           //  scope=rname.left(memIndex);
       
  2989           //  rname=rname.right(rname.length()-memIndex-2);
       
  2990           //}
       
  2991           isMember = TRUE;
       
  2992         }
       
  2993         else
       
  2994         {
       
  2995           isMember=memIndex<ts || memIndex>te;
       
  2996         }
       
  2997       }
       
  2998 
       
  2999       static QRegExp re("([a-z_A-Z0-9: ]*[ &*]+[ ]*");
       
  3000       if (!rootNav->parent()->name().isEmpty() &&
       
  3001           (rootNav->parent()->section() & Entry::COMPOUND_MASK) && 
       
  3002           cd &&
       
  3003           // do some fuzzy things to exclude function pointers 
       
  3004           (root->type.isEmpty() || 
       
  3005            (root->type.find(re,0)==-1 || root->args.find(")[")!=-1) ||  // type contains ..(..* and args not )[.. -> function pointer
       
  3006            root->type.find(")(")!=-1 || root->type.find("operator")!=-1 // type contains ..)(.. and not "operator"
       
  3007           )
       
  3008          )
       
  3009       {
       
  3010         Debug::print(Debug::Functions,0,"  --> member %s of class %s!\n",
       
  3011             rname.data(),cd->name().data());
       
  3012         addMethodToClass(rootNav,cd,rname,isFriend);
       
  3013       }
       
  3014       else if (!((rootNav->parent()->section() & Entry::COMPOUND_MASK) 
       
  3015                  || rootNav->parent()->section()==Entry::OBJCIMPL_SEC
       
  3016                 ) &&
       
  3017                !isMember &&
       
  3018                (root->relates.isEmpty() || root->relatesType == Duplicate) &&
       
  3019                root->type.left(7)!="extern " && root->type.left(8)!="typedef " 
       
  3020               )
       
  3021       // no member => unrelated function 
       
  3022       {
       
  3023         /* check the uniqueness of the function name in the file.
       
  3024          * A file could contain a function prototype and a function definition
       
  3025          * or even multiple function prototypes.
       
  3026          */
       
  3027         bool found=FALSE;
       
  3028         MemberName *mn;
       
  3029         MemberDef *md=0;
       
  3030         if ((mn=Doxygen::functionNameSDict->find(rname)))
       
  3031         {
       
  3032           Debug::print(Debug::Functions,0,"  --> function %s already found!\n",rname.data());
       
  3033           MemberNameIterator mni(*mn);
       
  3034           for (mni.toFirst();(!found && (md=mni.current()));++mni)
       
  3035           {
       
  3036             NamespaceDef *mnd = md->getNamespaceDef();
       
  3037             NamespaceDef *rnd = 0;
       
  3038             //printf("root namespace=%s\n",rootNav->parent()->name().data());
       
  3039             QCString fullScope = scope;
       
  3040             QCString parentScope = rootNav->parent()->name();
       
  3041             if (!parentScope.isEmpty() && !leftScopeMatch(parentScope,scope))
       
  3042             {
       
  3043               if (!scope.isEmpty()) fullScope.prepend("::");
       
  3044               fullScope.prepend(parentScope);
       
  3045             }
       
  3046             //printf("fullScope=%s\n",fullScope.data());
       
  3047             rnd = getResolvedNamespace(fullScope);
       
  3048             FileDef *mfd = md->getFileDef();
       
  3049             QCString nsName,rnsName;
       
  3050             if (mnd)  nsName = mnd->name().copy();
       
  3051             if (rnd) rnsName = rnd->name().copy();
       
  3052             //printf("matching arguments for %s%s %s%s\n",
       
  3053             //    md->name().data(),md->argsString(),rname.data(),argListToString(root->argList).data());
       
  3054             LockingPtr<ArgumentList> mdAl = md->argumentList();
       
  3055             LockingPtr<ArgumentList> mdTempl = md->templateArguments();
       
  3056 
       
  3057             // in case of template functions, we need to check if the
       
  3058             // functions have the same number of template parameters
       
  3059             bool sameNumTemplateArgs = TRUE;
       
  3060             if (mdTempl!=0 && root->tArgLists)
       
  3061             {
       
  3062               if (mdTempl->count()!=root->tArgLists->getLast()->count())
       
  3063               {
       
  3064                 sameNumTemplateArgs = FALSE;
       
  3065               }
       
  3066             }
       
  3067             if (
       
  3068                 matchArguments2(md->getOuterScope(),mfd,mdAl.pointer(),
       
  3069                                 rnd ? rnd : Doxygen::globalScope,rfd,root->argList,
       
  3070                                 FALSE) &&
       
  3071                 sameNumTemplateArgs
       
  3072                )
       
  3073             {
       
  3074               GroupDef *gd=0;
       
  3075               if (root->groups->first()!=0)
       
  3076               {
       
  3077                 gd = Doxygen::groupSDict->find(root->groups->first()->groupname.data());
       
  3078               }
       
  3079               //printf("match!\n");
       
  3080               //printf("mnd=%p rnd=%p nsName=%s rnsName=%s\n",mnd,rnd,nsName.data(),rnsName.data());
       
  3081               // see if we need to create a new member
       
  3082               found=(mnd && rnd && nsName==rnsName) ||   // members are in the same namespace
       
  3083                     ((mnd==0 && rnd==0 && mfd!=0 &&       // no external reference and
       
  3084                       mfd->absFilePath()==root->fileName // prototype in the same file
       
  3085                      )
       
  3086                     );
       
  3087               // otherwise, allow a duplicate global member with the same argument list
       
  3088               if (!found && gd && gd==md->getGroupDef())
       
  3089               {
       
  3090                 // member is already in the group, so we don't want to add it again.
       
  3091                 found=TRUE;
       
  3092               }
       
  3093 
       
  3094               //printf("combining function with prototype found=%d in namespace %s\n",
       
  3095               //    found,nsName.data());
       
  3096 
       
  3097               if (found)
       
  3098               {
       
  3099                 // merge argument lists
       
  3100                 mergeArguments(mdAl.pointer(),root->argList,!root->doc.isEmpty());
       
  3101                 // merge documentation
       
  3102                 if (md->documentation().isEmpty() && !root->doc.isEmpty())
       
  3103                 {
       
  3104                   ArgumentList *argList = new ArgumentList;
       
  3105                   stringToArgumentList(root->args,argList);
       
  3106                   if (root->proto)
       
  3107                   {
       
  3108                     //printf("setDeclArgumentList to %p\n",argList);
       
  3109                     md->setDeclArgumentList(argList);
       
  3110                   }
       
  3111                   else
       
  3112                   {
       
  3113                     md->setArgumentList(argList);
       
  3114                   }
       
  3115                 }
       
  3116 
       
  3117                 md->setDocumentation(root->doc,root->docFile,root->docLine);
       
  3118                 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
       
  3119                 md->setDocsForDefinition(!root->proto);
       
  3120                 md->setBodySegment(root->bodyLine,root->endBodyLine);
       
  3121                 md->setBodyDef(rfd);
       
  3122 
       
  3123                 if (md->briefDescription().isEmpty() && !root->brief.isEmpty())
       
  3124                 {
       
  3125                   md->setArgsString(root->args);
       
  3126                 }
       
  3127                 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
       
  3128 
       
  3129                 md->addSectionsToDefinition(root->anchors);
       
  3130 
       
  3131                 md->enableCallGraph(md->hasCallGraph() || root->callGraph);
       
  3132                 md->enableCallerGraph(md->hasCallerGraph() || root->callerGraph);
       
  3133 
       
  3134                 // merge ingroup specifiers
       
  3135                 if (md->getGroupDef()==0 && root->groups->first()!=0)
       
  3136                 {
       
  3137                   addMemberToGroups(root,md);
       
  3138                 }
       
  3139                 else if (md->getGroupDef()!=0 && root->groups->count()==0)
       
  3140                 {
       
  3141                   //printf("existing member is grouped, new member not\n");
       
  3142                   root->groups->append(new Grouping(md->getGroupDef()->name(), md->getGroupPri()));
       
  3143                 }
       
  3144                 else if (md->getGroupDef()!=0 && root->groups->first()!=0)
       
  3145                 {
       
  3146                   //printf("both members are grouped\n");
       
  3147                 }
       
  3148 
       
  3149                 // if md is a declaration and root is the corresponding
       
  3150                 // definition, then turn md into a definition.
       
  3151                 if (md->isPrototype() && !root->proto)
       
  3152                 {
       
  3153                   md->setPrototype(FALSE);
       
  3154                 }
       
  3155               }
       
  3156             }
       
  3157           }
       
  3158         }
       
  3159         if (!found) /* global function is unique with respect to the file */
       
  3160         {
       
  3161           Debug::print(Debug::Functions,0,"  --> new function %s found!\n",rname.data());
       
  3162           //printf("New function type=`%s' name=`%s' args=`%s' bodyLine=%d\n",
       
  3163           //       root->type.data(),rname.data(),root->args.data(),root->bodyLine);
       
  3164 
       
  3165           // new global function
       
  3166           ArgumentList *tArgList = root->tArgLists ? root->tArgLists->last() : 0;
       
  3167           QCString name=removeRedundantWhiteSpace(rname);
       
  3168           md=new MemberDef(
       
  3169               root->fileName,root->startLine,
       
  3170               root->type,name,root->args,root->exception,
       
  3171               root->protection,root->virt,root->stat,Member,
       
  3172               MemberDef::Function,tArgList,root->argList);
       
  3173 
       
  3174           md->setTagInfo(rootNav->tagInfo());
       
  3175           //md->setDefFile(root->fileName);
       
  3176           //md->setDefLine(root->startLine);
       
  3177           md->setDocumentation(root->doc,root->docFile,root->docLine);
       
  3178           md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
       
  3179           md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
       
  3180           md->setPrototype(root->proto);
       
  3181           md->setDocsForDefinition(!root->proto);
       
  3182           md->setTypeConstraints(root->typeConstr);
       
  3183           //md->setBody(root->body);
       
  3184           md->setBodySegment(root->bodyLine,root->endBodyLine);
       
  3185           FileDef *fd=rootNav->fileDef();
       
  3186           md->setBodyDef(fd);
       
  3187           md->addSectionsToDefinition(root->anchors);
       
  3188           md->setMemberSpecifiers(root->spec);
       
  3189           md->setMemberGroupId(root->mGrpId);
       
  3190 
       
  3191           // see if the function is inside a namespace that was not part of
       
  3192           // the name already (in that case nd should be non-zero already)
       
  3193           if (nd==0 && rootNav->parent()->section() == Entry::NAMESPACE_SEC )
       
  3194           {
       
  3195             //QCString nscope=removeAnonymousScopes(rootNav->parent()->name());
       
  3196             QCString nscope=rootNav->parent()->name();
       
  3197             if (!nscope.isEmpty())
       
  3198             {
       
  3199               nd = getResolvedNamespace(nscope);
       
  3200             }
       
  3201           }
       
  3202 
       
  3203           if (!scope.isEmpty())
       
  3204           {
       
  3205             if (Config_getBool("OPTIMIZE_OUTPUT_JAVA"))
       
  3206             {
       
  3207               scope = substitute(scope,"::",".")+".";
       
  3208             }
       
  3209             else
       
  3210             {
       
  3211               scope+="::";
       
  3212             }
       
  3213           }
       
  3214 
       
  3215           QCString def;
       
  3216           if (!root->type.isEmpty())
       
  3217           {
       
  3218             if (root->argList)
       
  3219             {
       
  3220               def=root->type+" "+scope+name;
       
  3221             }
       
  3222             else
       
  3223             {
       
  3224               def=root->type+" "+scope+name+root->args;
       
  3225             }
       
  3226           }
       
  3227           else
       
  3228           {
       
  3229             if (root->argList)
       
  3230             {
       
  3231               def=scope+name.copy();
       
  3232             }
       
  3233             else
       
  3234             {
       
  3235               def=scope+name+root->args;
       
  3236             }
       
  3237           }
       
  3238           Debug::print(Debug::Functions,0,
       
  3239                      "  Global Function:\n"
       
  3240                      "    `%s' `%s'::`%s' `%s' proto=%d\n"
       
  3241                      "    def=`%s'\n",
       
  3242                      root->type.data(),
       
  3243                      rootNav->parent()->name().data(),
       
  3244                      rname.data(),
       
  3245                      root->args.data(),
       
  3246                      root->proto,
       
  3247                      def.data()
       
  3248                     );
       
  3249           md->setDefinition(def);
       
  3250           md->enableCallGraph(root->callGraph);
       
  3251           md->enableCallerGraph(root->callerGraph);
       
  3252           //if (root->mGrpId!=-1) 
       
  3253           //{
       
  3254           //  md->setMemberGroup(memberGroupDict[root->mGrpId]);
       
  3255           //}
       
  3256 
       
  3257           md->setRefItems(root->sli);
       
  3258           if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@')
       
  3259           {
       
  3260             // add member to namespace
       
  3261             md->setNamespace(nd);
       
  3262             nd->insertMember(md); 
       
  3263           }
       
  3264           if (fd)
       
  3265           {
       
  3266             // add member to the file (we do this even if we have already
       
  3267             // inserted it into the namespace)
       
  3268             md->setFileDef(fd); 
       
  3269             fd->insertMember(md);
       
  3270           }
       
  3271 
       
  3272           // add member to the list of file members
       
  3273           //printf("Adding member=%s\n",md->name().data());
       
  3274           MemberName *mn;
       
  3275           if ((mn=Doxygen::functionNameSDict->find(name)))
       
  3276           {
       
  3277             mn->append(md);
       
  3278           }
       
  3279           else 
       
  3280           {
       
  3281             mn = new MemberName(name);
       
  3282             mn->append(md);
       
  3283             Doxygen::functionNameSDict->append(name,mn);
       
  3284           }
       
  3285           addMemberToGroups(root,md);
       
  3286           if (root->relatesType == Simple) // if this is a relatesalso command,
       
  3287                                            // allow find Member to pick it up
       
  3288           {
       
  3289             rootNav->changeSection(Entry::EMPTY_SEC); // Otherwise we have finished 
       
  3290                                                       // with this entry.
       
  3291 
       
  3292           }
       
  3293         }
       
  3294         else
       
  3295         {
       
  3296           FileDef *fd=rootNav->fileDef();
       
  3297           if (fd)
       
  3298           {
       
  3299             // add member to the file (we do this even if we have already
       
  3300             // inserted it into the namespace)
       
  3301             fd->insertMember(md);
       
  3302           }
       
  3303         }
       
  3304 
       
  3305         //printf("unrelated function %d `%s' `%s' `%s'\n",
       
  3306         //    root->parent->section,root->type.data(),rname.data(),root->args.data());
       
  3307       }
       
  3308       else
       
  3309       {
       
  3310           Debug::print(Debug::Functions,0,"  --> %s not processed!\n",rname.data());
       
  3311       }
       
  3312     }
       
  3313     else if (rname.isEmpty())
       
  3314     {
       
  3315         warn(root->fileName,root->startLine,
       
  3316              "Warning: Illegal member name found."
       
  3317             );
       
  3318     }
       
  3319 
       
  3320     rootNav->releaseEntry();
       
  3321   }
       
  3322   RECURSE_ENTRYTREE(buildFunctionList,rootNav);
       
  3323 }
       
  3324 
       
  3325 //----------------------------------------------------------------------
       
  3326 
       
  3327 static void findFriends()
       
  3328 {
       
  3329   //printf("findFriends()\n");
       
  3330   MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict);
       
  3331   MemberName *fn;
       
  3332   for (;(fn=fnli.current());++fnli) // for each global function name
       
  3333   {
       
  3334     //printf("Function name=`%s'\n",fn->memberName());
       
  3335     MemberName *mn;
       
  3336     if ((mn=Doxygen::memberNameSDict->find(fn->memberName())))
       
  3337     { // there are members with the same name
       
  3338       //printf("Function name is also a member name\n");
       
  3339       MemberNameIterator fni(*fn);
       
  3340       MemberDef *fmd;
       
  3341       for (;(fmd=fni.current());++fni) // for each function with that name
       
  3342       {
       
  3343         MemberNameIterator mni(*mn);
       
  3344         MemberDef *mmd;
       
  3345         for (;(mmd=mni.current());++mni) // for each member with that name
       
  3346         {
       
  3347           //printf("Checking for matching arguments 
       
  3348           //        mmd->isRelated()=%d mmd->isFriend()=%d mmd->isFunction()=%d\n",
       
  3349           //    mmd->isRelated(),mmd->isFriend(),mmd->isFunction());
       
  3350           LockingPtr<ArgumentList> mmdAl = mmd->argumentList();
       
  3351           LockingPtr<ArgumentList> fmdAl = fmd->argumentList();
       
  3352           if ((mmd->isFriend() || (mmd->isRelated() && mmd->isFunction())) &&
       
  3353               matchArguments2(mmd->getOuterScope(), mmd->getFileDef(), mmdAl.pointer(),
       
  3354                               fmd->getOuterScope(), fmd->getFileDef(), fmdAl.pointer(),
       
  3355                               TRUE
       
  3356                              )
       
  3357                              
       
  3358              ) // if the member is related and the arguments match then the 
       
  3359                // function is actually a friend.
       
  3360           {
       
  3361             mergeArguments(mmdAl.pointer(),fmdAl.pointer());
       
  3362             if (!fmd->documentation().isEmpty())
       
  3363             {
       
  3364               mmd->setDocumentation(fmd->documentation(),fmd->docFile(),fmd->docLine());
       
  3365             }
       
  3366             else if (!mmd->documentation().isEmpty())
       
  3367             {
       
  3368               fmd->setDocumentation(mmd->documentation(),mmd->docFile(),mmd->docLine());
       
  3369             }
       
  3370             if (mmd->briefDescription().isEmpty() && !fmd->briefDescription().isEmpty())
       
  3371             {
       
  3372               mmd->setBriefDescription(fmd->briefDescription(),fmd->briefFile(),fmd->briefLine());
       
  3373             }
       
  3374             else if (!mmd->briefDescription().isEmpty() && !fmd->briefDescription().isEmpty())
       
  3375             {
       
  3376               fmd->setBriefDescription(mmd->briefDescription(),mmd->briefFile(),mmd->briefLine());
       
  3377             }
       
  3378             if (!fmd->inbodyDocumentation().isEmpty())
       
  3379             {
       
  3380               mmd->setInbodyDocumentation(fmd->inbodyDocumentation(),fmd->inbodyFile(),fmd->inbodyLine());
       
  3381             }
       
  3382             else if (!mmd->inbodyDocumentation().isEmpty())
       
  3383             {
       
  3384               fmd->setInbodyDocumentation(mmd->inbodyDocumentation(),mmd->inbodyFile(),mmd->inbodyLine());
       
  3385             }
       
  3386             //printf("body mmd %d fmd %d\n",mmd->getStartBodyLine(),fmd->getStartBodyLine());
       
  3387             if (mmd->getStartBodyLine()==-1 && fmd->getStartBodyLine()!=-1)
       
  3388             {
       
  3389               mmd->setBodySegment(fmd->getStartBodyLine(),fmd->getEndBodyLine());
       
  3390               mmd->setBodyDef(fmd->getBodyDef());
       
  3391               //mmd->setBodyMember(fmd);
       
  3392             }
       
  3393             else if (mmd->getStartBodyLine()!=-1 && fmd->getStartBodyLine()==-1)
       
  3394             {
       
  3395               fmd->setBodySegment(mmd->getStartBodyLine(),mmd->getEndBodyLine());
       
  3396               fmd->setBodyDef(mmd->getBodyDef());
       
  3397               //fmd->setBodyMember(mmd);
       
  3398             }
       
  3399             mmd->setDocsForDefinition(fmd->isDocsForDefinition());
       
  3400 
       
  3401             mmd->enableCallGraph(mmd->hasCallGraph() || fmd->hasCallGraph());
       
  3402             mmd->enableCallerGraph(mmd->hasCallerGraph() || fmd->hasCallerGraph());
       
  3403             fmd->enableCallGraph(mmd->hasCallGraph() || fmd->hasCallGraph());
       
  3404             fmd->enableCallerGraph(mmd->hasCallerGraph() || fmd->hasCallerGraph());
       
  3405           }
       
  3406         }
       
  3407       }
       
  3408     }
       
  3409   }
       
  3410 }
       
  3411 
       
  3412 //----------------------------------------------------------------------
       
  3413 
       
  3414 static void transferArgumentDocumentation(ArgumentList *decAl,ArgumentList *defAl)
       
  3415 {
       
  3416   if (decAl && defAl)
       
  3417   {
       
  3418     ArgumentListIterator decAli(*decAl);
       
  3419     ArgumentListIterator defAli(*defAl);
       
  3420     Argument *decA,*defA;
       
  3421     for (decAli.toFirst(),defAli.toFirst();
       
  3422         (decA=decAli.current()) && (defA=defAli.current());
       
  3423         ++decAli,++defAli)
       
  3424     {
       
  3425       //printf("Argument decA->name=%s (doc=%s) defA->name=%s (doc=%s)\n",
       
  3426       //    decA->name.data(),decA->docs.data(),
       
  3427       //    defA->name.data(),defA->docs.data()
       
  3428       //      );
       
  3429       if (decA->docs.isEmpty() && !defA->docs.isEmpty())
       
  3430       {
       
  3431         decA->docs = defA->docs.copy();
       
  3432       }
       
  3433       else if (defA->docs.isEmpty() && !decA->docs.isEmpty())
       
  3434       {
       
  3435         defA->docs = decA->docs.copy();
       
  3436       }
       
  3437     }
       
  3438   }
       
  3439 }
       
  3440 
       
  3441 static void transferFunctionDocumentation()
       
  3442 {
       
  3443   //printf("---- transferFunctionDocumentation()\n");
       
  3444 
       
  3445   // find matching function declaration and definitions.
       
  3446   MemberNameSDict::Iterator mnli(*Doxygen::functionNameSDict);
       
  3447   MemberName *mn;
       
  3448   for (;(mn=mnli.current());++mnli)
       
  3449   {
       
  3450     //printf("memberName=%s count=%d\n",mn->memberName(),mn->count());
       
  3451     MemberDef *mdef=0,*mdec=0;
       
  3452     MemberNameIterator mni1(*mn);
       
  3453     /* find a matching function declaration and definition for this function */
       
  3454     for (;(mdec=mni1.current());++mni1)
       
  3455     {
       
  3456       //printf("mdec=%s isPrototype()=%d\n",mdec->name().data(),mdec->isPrototype());
       
  3457       if (mdec->isPrototype() ||
       
  3458           (mdec->isVariable() && mdec->isExternal()) 
       
  3459          )
       
  3460       {
       
  3461         MemberNameIterator mni2(*mn);
       
  3462         for (;(mdef=mni2.current());++mni2)
       
  3463         {
       
  3464           if (
       
  3465               (mdef->isFunction() && !mdef->isStatic() && !mdef->isPrototype()) ||
       
  3466               (mdef->isVariable() && !mdef->isExternal() && !mdef->isStatic())
       
  3467              )
       
  3468           {
       
  3469             //printf("mdef=(%p,%s) mdec=(%p,%s)\n",
       
  3470             //    mdef, mdef ? mdef->name().data() : "",
       
  3471             //    mdec, mdec ? mdec->name().data() : "");
       
  3472 
       
  3473             LockingPtr<ArgumentList> mdefAl = mdef->argumentList();
       
  3474             LockingPtr<ArgumentList> mdecAl = mdec->argumentList();
       
  3475             if (matchArguments2(mdef->getOuterScope(),mdef->getFileDef(),mdefAl.pointer(),
       
  3476                                 mdec->getOuterScope(),mdec->getFileDef(),mdecAl.pointer(),
       
  3477                                 TRUE
       
  3478                                )
       
  3479                ) /* match found */
       
  3480             {
       
  3481               //printf("Found member %s: definition in %s (doc=`%s') and declaration in %s (doc=`%s')\n",
       
  3482               //    mn->memberName(),
       
  3483               //    mdef->getFileDef()->name().data(),mdef->documentation().data(),
       
  3484               //    mdec->getFileDef()->name().data(),mdec->documentation().data()
       
  3485               //    );
       
  3486 
       
  3487               // first merge argument documentation
       
  3488               transferArgumentDocumentation(mdecAl.pointer(),mdefAl.pointer());
       
  3489 
       
  3490               /* copy documentation between function definition and declaration */
       
  3491               if (!mdec->briefDescription().isEmpty())
       
  3492               {
       
  3493                 mdef->setBriefDescription(mdec->briefDescription(),mdec->briefFile(),mdec->briefLine());
       
  3494               }
       
  3495               else if (!mdef->briefDescription().isEmpty())
       
  3496               {
       
  3497                 mdec->setBriefDescription(mdef->briefDescription(),mdef->briefFile(),mdef->briefLine());
       
  3498               }
       
  3499               if (!mdef->documentation().isEmpty())
       
  3500               {
       
  3501                 //printf("transfering docs mdef->mdec (%s->%s)\n",mdef->argsString(),mdec->argsString());
       
  3502                 mdec->setDocumentation(mdef->documentation(),mdef->docFile(),mdef->docLine());
       
  3503                 mdec->setDocsForDefinition(mdef->isDocsForDefinition());
       
  3504                 if (mdefAl!=0)
       
  3505                 {
       
  3506                   ArgumentList *mdefAlComb = new ArgumentList;
       
  3507                   stringToArgumentList(mdef->argsString(),mdefAlComb);
       
  3508                   transferArgumentDocumentation(mdefAl.pointer(),mdefAlComb);
       
  3509                   mdec->setArgumentList(mdefAlComb);
       
  3510                 }
       
  3511               }
       
  3512               else if (!mdec->documentation().isEmpty())
       
  3513               {
       
  3514                 //printf("transfering docs mdec->mdef (%s->%s)\n",mdec->argsString(),mdef->argsString());
       
  3515                 mdef->setDocumentation(mdec->documentation(),mdec->docFile(),mdec->docLine());
       
  3516                 mdef->setDocsForDefinition(mdec->isDocsForDefinition());
       
  3517                 if (mdecAl!=0)
       
  3518                 {
       
  3519                   ArgumentList *mdecAlComb = new ArgumentList;
       
  3520                   stringToArgumentList(mdec->argsString(),mdecAlComb);
       
  3521                   transferArgumentDocumentation(mdecAl.pointer(),mdecAlComb);
       
  3522                   mdef->setDeclArgumentList(mdecAlComb);
       
  3523                 }
       
  3524               }
       
  3525               if (!mdef->inbodyDocumentation().isEmpty())
       
  3526               {
       
  3527                 mdec->setInbodyDocumentation(mdef->inbodyDocumentation(),mdef->inbodyFile(),mdef->inbodyLine());
       
  3528               }
       
  3529               else if (!mdec->inbodyDocumentation().isEmpty())
       
  3530               {
       
  3531                 mdef->setInbodyDocumentation(mdec->inbodyDocumentation(),mdec->inbodyFile(),mdec->inbodyLine());
       
  3532               }
       
  3533               if (mdec->getStartBodyLine()!=-1 && mdef->getStartBodyLine()==-1)
       
  3534               {
       
  3535                 //printf("body mdec->mdef %d-%d\n",mdec->getStartBodyLine(),mdef->getEndBodyLine());
       
  3536                 mdef->setBodySegment(mdec->getStartBodyLine(),mdec->getEndBodyLine());
       
  3537                 mdef->setBodyDef(mdec->getBodyDef());
       
  3538                 //mdef->setBodyMember(mdec);
       
  3539               }
       
  3540               else if (mdef->getStartBodyLine()!=-1 && mdec->getStartBodyLine()==-1)
       
  3541               {
       
  3542                 //printf("body mdef->mdec %d-%d\n",mdef->getStartBodyLine(),mdec->getEndBodyLine());
       
  3543                 mdec->setBodySegment(mdef->getStartBodyLine(),mdef->getEndBodyLine());
       
  3544                 mdec->setBodyDef(mdef->getBodyDef());
       
  3545                 //mdec->setBodyMember(mdef);
       
  3546               }
       
  3547               mdec->mergeMemberSpecifiers(mdef->getMemberSpecifiers());
       
  3548               mdef->mergeMemberSpecifiers(mdec->getMemberSpecifiers());
       
  3549 
       
  3550 
       
  3551               // copy group info.
       
  3552               if (mdec->getGroupDef()==0 && mdef->getGroupDef()!=0)
       
  3553               {
       
  3554                 mdec->setGroupDef(mdef->getGroupDef(),
       
  3555                                   mdef->getGroupPri(),
       
  3556                                   mdef->docFile(),
       
  3557                                   mdef->docLine(),
       
  3558                                   mdef->hasDocumentation(),
       
  3559                                   mdef
       
  3560                                  );
       
  3561               }
       
  3562               else if (mdef->getGroupDef()==0 && mdec->getGroupDef()!=0)
       
  3563               {
       
  3564                 mdef->setGroupDef(mdec->getGroupDef(),
       
  3565                                   mdec->getGroupPri(),
       
  3566                                   mdec->docFile(),
       
  3567                                   mdec->docLine(),
       
  3568                                   mdec->hasDocumentation(),
       
  3569                                   mdec
       
  3570                                  );
       
  3571               }
       
  3572 
       
  3573 
       
  3574               mdec->mergeRefItems(mdef);
       
  3575               mdef->mergeRefItems(mdec);
       
  3576 
       
  3577               mdef->setMemberDeclaration(mdec);
       
  3578               mdec->setMemberDefinition(mdef);
       
  3579 
       
  3580               mdef->enableCallGraph(mdec->hasCallGraph() || mdef->hasCallGraph());
       
  3581               mdef->enableCallerGraph(mdec->hasCallerGraph() || mdef->hasCallerGraph());
       
  3582               mdec->enableCallGraph(mdec->hasCallGraph() || mdef->hasCallGraph());
       
  3583               mdec->enableCallerGraph(mdec->hasCallerGraph() || mdef->hasCallerGraph());
       
  3584             }
       
  3585           }
       
  3586         }
       
  3587       }
       
  3588     }
       
  3589   }
       
  3590 }
       
  3591 
       
  3592 //----------------------------------------------------------------------
       
  3593 
       
  3594 static void transferFunctionReferences()
       
  3595 {
       
  3596   MemberNameSDict::Iterator mnli(*Doxygen::functionNameSDict);
       
  3597   MemberName *mn;
       
  3598   for (;(mn=mnli.current());++mnli)
       
  3599   {
       
  3600     MemberDef *md,*mdef=0,*mdec=0;
       
  3601     MemberNameIterator mni(*mn);
       
  3602     /* find a matching function declaration and definition for this function */
       
  3603     for (;(md=mni.current());++mni)
       
  3604     {
       
  3605       if (md->isPrototype()) 
       
  3606         mdec=md;
       
  3607       else if (md->isVariable() && md->isExternal()) 
       
  3608         mdec=md;
       
  3609       
       
  3610       if (md->isFunction() && !md->isStatic() && !md->isPrototype()) 
       
  3611         mdef=md;
       
  3612       else if (md->isVariable() && !md->isExternal() && !md->isStatic())
       
  3613         mdef=md;
       
  3614     }
       
  3615     if (mdef && mdec)
       
  3616     {
       
  3617       LockingPtr<ArgumentList> mdefAl = mdef->argumentList();
       
  3618       LockingPtr<ArgumentList> mdecAl = mdec->argumentList();
       
  3619       if (
       
  3620           matchArguments2(mdef->getOuterScope(),mdef->getFileDef(),mdefAl.pointer(),
       
  3621                           mdec->getOuterScope(),mdec->getFileDef(),mdecAl.pointer(),
       
  3622                           TRUE
       
  3623             )
       
  3624          ) /* match found */
       
  3625       {
       
  3626         LockingPtr<MemberSDict> defDict = mdef->getReferencesMembers();
       
  3627         LockingPtr<MemberSDict> decDict = mdec->getReferencesMembers();
       
  3628         if (defDict!=0)
       
  3629         {
       
  3630           MemberSDict::Iterator msdi(*defDict);
       
  3631           MemberDef *rmd;
       
  3632           for (msdi.toFirst();(rmd=msdi.current());++msdi)
       
  3633           {
       
  3634             if (decDict==0 || decDict->find(rmd->name())==0)
       
  3635             {
       
  3636               mdec->addSourceReferences(rmd);
       
  3637             }
       
  3638           }
       
  3639         }
       
  3640         if (decDict!=0)
       
  3641         {
       
  3642           MemberSDict::Iterator msdi(*decDict);
       
  3643           MemberDef *rmd;
       
  3644           for (msdi.toFirst();(rmd=msdi.current());++msdi)
       
  3645           {
       
  3646             if (defDict==0 || defDict->find(rmd->name())==0)
       
  3647             {
       
  3648               mdef->addSourceReferences(rmd);
       
  3649             }
       
  3650           }
       
  3651         }
       
  3652 
       
  3653         defDict = mdef->getReferencedByMembers();
       
  3654         decDict = mdec->getReferencedByMembers();
       
  3655         if (defDict!=0)
       
  3656         {
       
  3657           MemberSDict::Iterator msdi(*defDict);
       
  3658           MemberDef *rmd;
       
  3659           for (msdi.toFirst();(rmd=msdi.current());++msdi)
       
  3660           {
       
  3661             if (decDict==0 || decDict->find(rmd->name())==0)
       
  3662             {
       
  3663               mdec->addSourceReferencedBy(rmd);
       
  3664             }
       
  3665           }
       
  3666         }
       
  3667         if (decDict!=0)
       
  3668         {
       
  3669           MemberSDict::Iterator msdi(*decDict);
       
  3670           MemberDef *rmd;
       
  3671           for (msdi.toFirst();(rmd=msdi.current());++msdi)
       
  3672           {
       
  3673             if (defDict==0 || defDict->find(rmd->name())==0)
       
  3674             {
       
  3675               mdef->addSourceReferencedBy(rmd);
       
  3676             }
       
  3677           }
       
  3678         }
       
  3679       }
       
  3680     }
       
  3681   }
       
  3682 }
       
  3683 
       
  3684 //----------------------------------------------------------------------
       
  3685 
       
  3686 static void transferRelatedFunctionDocumentation()
       
  3687 {
       
  3688   // find match between function declaration and definition for 
       
  3689   // related functions
       
  3690   MemberNameSDict::Iterator mnli(*Doxygen::functionNameSDict);
       
  3691   MemberName *mn;
       
  3692   for (mnli.toFirst();(mn=mnli.current());++mnli)
       
  3693   {
       
  3694     MemberDef *md;
       
  3695     MemberNameIterator mni(*mn);
       
  3696     /* find a matching function declaration and definition for this function */
       
  3697     for (mni.toFirst();(md=mni.current());++mni) // for each global function
       
  3698     {
       
  3699       //printf("  Function `%s'\n",md->name().data());
       
  3700       MemberName *rmn;
       
  3701       if ((rmn=Doxygen::memberNameSDict->find(md->name()))) // check if there is a member with the same name
       
  3702       {
       
  3703         //printf("  Member name found\n");
       
  3704         MemberDef *rmd;
       
  3705         MemberNameIterator rmni(*rmn);
       
  3706         for (rmni.toFirst();(rmd=rmni.current());++rmni) // for each member with the same name
       
  3707         {
       
  3708           LockingPtr<ArgumentList>  mdAl = md->argumentList();
       
  3709           LockingPtr<ArgumentList> rmdAl = rmd->argumentList();
       
  3710           //printf("  Member found: related=`%d'\n",rmd->isRelated());
       
  3711           if ((rmd->isRelated() || rmd->isForeign()) && // related function
       
  3712               matchArguments2( md->getOuterScope(), md->getFileDef(), mdAl.pointer(),
       
  3713                               rmd->getOuterScope(),rmd->getFileDef(),rmdAl.pointer(),
       
  3714                               TRUE
       
  3715                              )
       
  3716              )
       
  3717           {
       
  3718             //printf("  Found related member `%s'\n",md->name().data());
       
  3719             if (rmd->relatedAlso())
       
  3720               md->setRelatedAlso(rmd->relatedAlso());
       
  3721             else if (rmd->isForeign())
       
  3722               md->makeForeign();
       
  3723             else
       
  3724               md->makeRelated();
       
  3725           } 
       
  3726         }
       
  3727       } 
       
  3728     }
       
  3729   }
       
  3730 }
       
  3731 
       
  3732 //----------------------------------------------------------------------
       
  3733 
       
  3734 /*! make a dictionary of all template arguments of class cd
       
  3735  * that are part of the base class name. 
       
  3736  * Example: A template class A with template arguments <R,S,T> 
       
  3737  * that inherits from B<T,T,S> will have T and S in the dictionary.
       
  3738  */
       
  3739 static QDict<int> *getTemplateArgumentsInName(ArgumentList *templateArguments,const QCString &name)
       
  3740 {
       
  3741   QDict<int> *templateNames = new QDict<int>(17);
       
  3742   templateNames->setAutoDelete(TRUE);
       
  3743   static QRegExp re("[a-z_A-Z][a-z_A-Z0-9:]*");
       
  3744   if (templateArguments)
       
  3745   {
       
  3746     ArgumentListIterator ali(*templateArguments);
       
  3747     Argument *arg;
       
  3748     int count=0;
       
  3749     for (ali.toFirst();(arg=ali.current());++ali,count++)
       
  3750     {
       
  3751       int i,p=0,l;
       
  3752       while ((i=re.match(name,p,&l))!=-1)
       
  3753       {
       
  3754         QCString n = name.mid(i,l);
       
  3755         if (n==arg->name)
       
  3756         {
       
  3757           if (templateNames->find(n)==0)
       
  3758           {
       
  3759             templateNames->insert(n,new int(count));
       
  3760           }
       
  3761         }
       
  3762         p=i+l;
       
  3763       }
       
  3764     }
       
  3765   }
       
  3766   return templateNames;
       
  3767 }
       
  3768 
       
  3769 /*! Searches a class from within \a context and \a cd and returns its
       
  3770  *  definition if found (otherwise 0 is returned).
       
  3771  */
       
  3772 static ClassDef *findClassWithinClassContext(Definition *context,ClassDef *cd,const QCString &name)
       
  3773 {
       
  3774   FileDef *fd=cd->getFileDef();
       
  3775   ClassDef *result=0;
       
  3776   if (context && cd!=context)
       
  3777   {
       
  3778     result = getResolvedClass(context,0,name,0,0,TRUE,TRUE);
       
  3779   }
       
  3780   if (result==0)
       
  3781   {
       
  3782     result = getResolvedClass(cd,fd,name,0,0,TRUE,TRUE);
       
  3783   }
       
  3784   //printf("** Trying to find %s within context %s class %s result=%s lookup=%p\n",
       
  3785   //       name.data(),
       
  3786   //       context ? context->name().data() : "<none>",
       
  3787   //       cd      ? cd->name().data()      : "<none>",
       
  3788   //       result  ? result->name().data()  : "<none>",
       
  3789   //       Doxygen::classSDict.find(name)
       
  3790   //      );
       
  3791   return result;
       
  3792 }
       
  3793 
       
  3794 enum FindBaseClassRelation_Mode 
       
  3795 { 
       
  3796   TemplateInstances, 
       
  3797   DocumentedOnly, 
       
  3798   Undocumented 
       
  3799 };
       
  3800 
       
  3801 static bool findClassRelation(
       
  3802                            EntryNav *rootNav,
       
  3803                            Definition *context,
       
  3804                            ClassDef *cd,
       
  3805                            BaseInfo *bi,
       
  3806                            QDict<int> *templateNames,
       
  3807                            /*bool insertUndocumented*/
       
  3808                            FindBaseClassRelation_Mode mode,
       
  3809                            bool isArtificial
       
  3810                           );
       
  3811 
       
  3812 
       
  3813 static void findUsedClassesForClass(EntryNav *rootNav,
       
  3814                            Definition *context,
       
  3815                            ClassDef *masterCd,
       
  3816                            ClassDef *instanceCd,
       
  3817                            bool isArtificial,
       
  3818                            ArgumentList *actualArgs=0,
       
  3819                            QDict<int> *templateNames=0
       
  3820                            )
       
  3821 {
       
  3822   masterCd->visited=TRUE;
       
  3823   ArgumentList *formalArgs = masterCd->templateArguments();
       
  3824   if (masterCd->memberNameInfoSDict())
       
  3825   {
       
  3826     MemberNameInfoSDict::Iterator mnili(*masterCd->memberNameInfoSDict());
       
  3827     MemberNameInfo *mni;
       
  3828     for (;(mni=mnili.current());++mnili)
       
  3829     {
       
  3830       MemberNameInfoIterator mnii(*mni);
       
  3831       MemberInfo *mi;
       
  3832       for (mnii.toFirst();(mi=mnii.current());++mnii)
       
  3833       {
       
  3834         MemberDef *md=mi->memberDef;
       
  3835         if (md->isVariable()) // for each member variable in this class
       
  3836         {
       
  3837           //printf("    Found variable %s in class %s\n",md->name().data(),masterCd->name().data());
       
  3838           QCString type=removeRedundantWhiteSpace(md->typeString());
       
  3839           QCString typedefValue = resolveTypeDef(masterCd,type);
       
  3840           if (!typedefValue.isEmpty())
       
  3841           {
       
  3842             type = typedefValue;
       
  3843           }
       
  3844           int pos=0;
       
  3845           QCString usedClassName;
       
  3846           QCString templSpec;
       
  3847           bool found=FALSE;
       
  3848           // the type can contain template variables, replace them if present
       
  3849           if (actualArgs)
       
  3850           {
       
  3851             type = substituteTemplateArgumentsInString(type,formalArgs,actualArgs);
       
  3852           }
       
  3853 
       
  3854           //printf("      template substitution gives=%s\n",type.data());
       
  3855           while (!found && extractClassNameFromType(type,pos,usedClassName,templSpec)!=-1)
       
  3856           {
       
  3857             // find the type (if any) that matches usedClassName
       
  3858             ClassDef *typeCd = getResolvedClass(masterCd,
       
  3859                 masterCd->getFileDef(),
       
  3860                 usedClassName,
       
  3861                 0,0,
       
  3862                 FALSE,TRUE
       
  3863                 );
       
  3864             //printf("====>  usedClassName=%s -> typeCd=%s\n",
       
  3865             //     usedClassName.data(),typeCd?typeCd->name().data():"<none>");
       
  3866             if (typeCd)
       
  3867             {
       
  3868               usedClassName = typeCd->name();
       
  3869             }
       
  3870 
       
  3871             int sp=usedClassName.find('<');
       
  3872             if (sp==-1) sp=0;
       
  3873             int si=usedClassName.findRev("::",sp);
       
  3874             if (si!=-1)
       
  3875             {
       
  3876               // replace any namespace aliases
       
  3877               replaceNamespaceAliases(usedClassName,si);
       
  3878             }
       
  3879             // add any template arguments to the class
       
  3880             QCString usedName = removeRedundantWhiteSpace(usedClassName+templSpec);
       
  3881             //printf("    usedName=%s\n",usedName.data());
       
  3882 
       
  3883             bool delTempNames=FALSE;
       
  3884             if (templateNames==0)
       
  3885             {
       
  3886               templateNames = getTemplateArgumentsInName(formalArgs,usedName);
       
  3887               delTempNames=TRUE;
       
  3888             }
       
  3889             BaseInfo bi(usedName,Public,Normal);
       
  3890             findClassRelation(rootNav,context,instanceCd,&bi,templateNames,TemplateInstances,isArtificial);
       
  3891 
       
  3892             if (masterCd->templateArguments())
       
  3893             {
       
  3894               ArgumentListIterator ali(*masterCd->templateArguments());
       
  3895               Argument *arg;
       
  3896               int count=0;
       
  3897               for (ali.toFirst();(arg=ali.current());++ali,++count)
       
  3898               {
       
  3899                 if (arg->name==usedName) // type is a template argument
       
  3900                 {
       
  3901                   found=TRUE;
       
  3902                   Debug::print(Debug::Classes,0,"    New used class `%s'\n", usedName.data());
       
  3903 
       
  3904                   ClassDef *usedCd = Doxygen::hiddenClasses->find(usedName);
       
  3905                   if (usedCd==0)
       
  3906                   {
       
  3907                     usedCd = new ClassDef(
       
  3908                         masterCd->getDefFileName(),masterCd->getDefLine(),
       
  3909                         usedName,ClassDef::Class);
       
  3910                     //printf("making %s a template argument!!!\n",usedCd->name().data());
       
  3911                     usedCd->makeTemplateArgument();
       
  3912                     usedCd->setUsedOnly(TRUE);
       
  3913                     Doxygen::hiddenClasses->append(usedName,usedCd);
       
  3914                   }
       
  3915                   if (usedCd)
       
  3916                   {
       
  3917                     if (isArtificial) usedCd->setArtificial(TRUE);
       
  3918                     Debug::print(Debug::Classes,0,"      Adding used class `%s' (1)\n", usedCd->name().data());
       
  3919                     instanceCd->addUsedClass(usedCd,md->name());
       
  3920                     usedCd->addUsedByClass(instanceCd,md->name());
       
  3921                   }
       
  3922                 }
       
  3923               }
       
  3924             }
       
  3925 
       
  3926             if (!found)
       
  3927             {
       
  3928               ClassDef *usedCd=findClassWithinClassContext(context,masterCd,usedName);
       
  3929               //printf("Looking for used class %s: result=%s master=%s\n",
       
  3930               //    usedName.data(),usedCd?usedCd->name().data():"<none>",masterCd?masterCd->name().data():"<none>");
       
  3931 
       
  3932               if (usedCd) 
       
  3933               {
       
  3934                 found=TRUE;
       
  3935                 Debug::print(Debug::Classes,0,"    Adding used class `%s' (2)\n", usedCd->name().data());
       
  3936                 instanceCd->addUsedClass(usedCd,md->name()); // class exists 
       
  3937                 usedCd->addUsedByClass(instanceCd,md->name());
       
  3938               }
       
  3939             }
       
  3940             if (delTempNames)
       
  3941             {
       
  3942               delete templateNames;
       
  3943               templateNames=0;
       
  3944             }
       
  3945           }
       
  3946           if (!found && !type.isEmpty()) // used class is not documented in any scope
       
  3947           {
       
  3948             ClassDef *usedCd = Doxygen::hiddenClasses->find(type);
       
  3949             if (usedCd==0 && !Config_getBool("HIDE_UNDOC_RELATIONS"))
       
  3950             {
       
  3951               if (type.right(2)=="(*") // type is a function pointer
       
  3952               {
       
  3953                 type+=md->argsString();
       
  3954               }
       
  3955               Debug::print(Debug::Classes,0,"  New undocumented used class `%s'\n", type.data());
       
  3956               usedCd = new ClassDef(
       
  3957                   masterCd->getDefFileName(),masterCd->getDefLine(),
       
  3958                   type,ClassDef::Class);
       
  3959               usedCd->setUsedOnly(TRUE);
       
  3960               Doxygen::hiddenClasses->append(type,usedCd);
       
  3961             }
       
  3962             if (usedCd)
       
  3963             {
       
  3964               if (isArtificial) usedCd->setArtificial(TRUE);
       
  3965               Debug::print(Debug::Classes,0,"    Adding used class `%s' (3)\n", usedCd->name().data());
       
  3966               instanceCd->addUsedClass(usedCd,md->name()); 
       
  3967               usedCd->addUsedByClass(instanceCd,md->name());
       
  3968             }
       
  3969           }
       
  3970         }
       
  3971       }
       
  3972     }
       
  3973   }
       
  3974   else
       
  3975   {
       
  3976     //printf("no members for class %s (%p)\n",masterCd->name().data(),masterCd);
       
  3977   }
       
  3978 }
       
  3979 
       
  3980 static void findBaseClassesForClass(
       
  3981       EntryNav *rootNav,
       
  3982       Definition *context,
       
  3983       ClassDef *masterCd,
       
  3984       ClassDef *instanceCd,
       
  3985       FindBaseClassRelation_Mode mode,
       
  3986       bool isArtificial,
       
  3987       ArgumentList *actualArgs=0,
       
  3988       QDict<int> *templateNames=0
       
  3989     )
       
  3990 {
       
  3991   Entry *root = rootNav->entry();
       
  3992   //if (masterCd->visited) return;
       
  3993   masterCd->visited=TRUE;
       
  3994   // The base class could ofcouse also be a non-nested class
       
  3995   ArgumentList *formalArgs = masterCd->templateArguments();
       
  3996   QListIterator<BaseInfo> bii(*root->extends);
       
  3997   BaseInfo *bi=0;
       
  3998   for (bii.toFirst();(bi=bii.current());++bii)
       
  3999   {
       
  4000     //printf("masterCd=%s bi->name='%s' #actualArgs=%d\n",
       
  4001     //    masterCd->localName().data(),bi->name.data(),actualArgs?(int)actualArgs->count():-1);
       
  4002     bool delTempNames=FALSE;
       
  4003     if (templateNames==0)
       
  4004     {
       
  4005       templateNames = getTemplateArgumentsInName(formalArgs,bi->name);
       
  4006       delTempNames=TRUE;
       
  4007     }
       
  4008     BaseInfo tbi(bi->name,bi->prot,bi->virt);
       
  4009     if (actualArgs) // substitute the formal template arguments of the base class
       
  4010     {
       
  4011       tbi.name = substituteTemplateArgumentsInString(bi->name,formalArgs,actualArgs);
       
  4012     }
       
  4013     //printf("bi->name=%s tbi.name=%s\n",bi->name.data(),tbi.name.data());
       
  4014 
       
  4015     if (mode==DocumentedOnly)
       
  4016     {
       
  4017       // find a documented base class in the correct scope
       
  4018       if (!findClassRelation(rootNav,context,instanceCd,&tbi,templateNames,DocumentedOnly,isArtificial))
       
  4019       {
       
  4020         if (!Config_getBool("HIDE_UNDOC_RELATIONS"))
       
  4021         {
       
  4022           // no documented base class -> try to find an undocumented one
       
  4023           findClassRelation(rootNav,context,instanceCd,&tbi,templateNames,Undocumented,isArtificial);
       
  4024         }
       
  4025       }
       
  4026     }
       
  4027     else if (mode==TemplateInstances)
       
  4028     {
       
  4029       findClassRelation(rootNav,context,instanceCd,&tbi,templateNames,TemplateInstances,isArtificial);
       
  4030     }
       
  4031     if (delTempNames)
       
  4032     {
       
  4033       delete templateNames;
       
  4034       templateNames=0;
       
  4035     }  
       
  4036   }
       
  4037 }
       
  4038 
       
  4039 //----------------------------------------------------------------------
       
  4040 
       
  4041 static bool findTemplateInstanceRelation(Entry *root,
       
  4042             Definition *context,
       
  4043             ClassDef *templateClass,const QCString &templSpec,
       
  4044             QDict<int> *templateNames,
       
  4045             bool isArtificial)
       
  4046 {
       
  4047   Debug::print(Debug::Classes,0,"    derived from template %s with parameters %s\n",
       
  4048          templateClass->name().data(),templSpec.data());
       
  4049   //printf("findTemplateInstanceRelation(base=%s templSpec=%s templateNames=",
       
  4050   //    templateClass->name().data(),templSpec.data());
       
  4051   //if (templateNames)
       
  4052   //{
       
  4053   //  QDictIterator<int> qdi(*templateNames);
       
  4054   //  int *tempArgIndex;
       
  4055   //  for (;(tempArgIndex=qdi.current());++qdi)
       
  4056   //  {
       
  4057   //    printf("(%s->%d) ",qdi.currentKey().data(),*tempArgIndex);
       
  4058   //  }
       
  4059   //}
       
  4060   //printf("\n");
       
  4061   
       
  4062   bool existingClass = (templSpec ==
       
  4063                         tempArgListToString(templateClass->templateArguments())
       
  4064                        );
       
  4065   if (existingClass) return TRUE;
       
  4066 
       
  4067   bool freshInstance=FALSE;
       
  4068   ClassDef *instanceClass = templateClass->insertTemplateInstance(
       
  4069                      root->fileName,root->startLine,templSpec,freshInstance);
       
  4070   if (isArtificial) instanceClass->setArtificial(TRUE);
       
  4071   instanceClass->setIsObjectiveC(root->objc);
       
  4072 
       
  4073   if (freshInstance)
       
  4074   {
       
  4075     Debug::print(Debug::Classes,0,"      found fresh instance '%s'!\n",instanceClass->name().data());
       
  4076     Doxygen::classSDict->append(instanceClass->name(),instanceClass);
       
  4077     instanceClass->setTemplateBaseClassNames(templateNames);
       
  4078 
       
  4079     // search for new template instances caused by base classes of 
       
  4080     // instanceClass 
       
  4081     EntryNav *templateRootNav = g_classEntries.find(templateClass->name());
       
  4082     if (templateRootNav)
       
  4083     {
       
  4084       bool unloadNeeded=FALSE;
       
  4085       Entry *templateRoot = templateRootNav->entry();
       
  4086       if (templateRoot==0) // not yet loaded
       
  4087       {
       
  4088         templateRootNav->loadEntry(g_storage);
       
  4089         templateRoot = templateRootNav->entry();
       
  4090         ASSERT(templateRoot!=0); // now it should really be loaded
       
  4091         unloadNeeded=TRUE;
       
  4092       }
       
  4093 
       
  4094       Debug::print(Debug::Classes,0,"        template root found %s templSpec=%s!\n",
       
  4095           templateRoot->name.data(),templSpec.data());
       
  4096       ArgumentList *templArgs = new ArgumentList;
       
  4097       stringToArgumentList(templSpec,templArgs);
       
  4098       findBaseClassesForClass(templateRootNav,context,templateClass,instanceClass,
       
  4099           TemplateInstances,isArtificial,templArgs,templateNames);
       
  4100 
       
  4101       findUsedClassesForClass(templateRootNav,context,templateClass,instanceClass,
       
  4102           isArtificial,templArgs,templateNames);
       
  4103       delete templArgs;
       
  4104 
       
  4105       if (unloadNeeded) // still cleanup to do
       
  4106       {
       
  4107         templateRootNav->releaseEntry();
       
  4108       }
       
  4109     }
       
  4110     else
       
  4111     {
       
  4112       Debug::print(Debug::Classes,0,"        no template root entry found!\n");
       
  4113       // TODO: what happened if we get here?
       
  4114     }
       
  4115 
       
  4116     //Debug::print(Debug::Classes,0,"    Template instance %s : \n",instanceClass->name().data());
       
  4117     //ArgumentList *tl = templateClass->templateArguments();
       
  4118   }
       
  4119   else
       
  4120   {
       
  4121     Debug::print(Debug::Classes,0,"      instance already exists!\n");
       
  4122   }
       
  4123   return TRUE;
       
  4124 }
       
  4125 
       
  4126 static bool isRecursiveBaseClass(const QCString &scope,const QCString &name)
       
  4127 {
       
  4128   QCString n=name;
       
  4129   int index=n.find('<');
       
  4130   if (index!=-1)
       
  4131   {
       
  4132     n=n.left(index);
       
  4133   }
       
  4134   bool result = rightScopeMatch(scope,n);
       
  4135   return result;
       
  4136 }
       
  4137 
       
  4138 /*! Searches for the end of a template in prototype \a s starting from
       
  4139  *  character position \a startPos. If the end was found the position
       
  4140  *  of the closing \> is returned, otherwise -1 is returned.
       
  4141  *
       
  4142  *  Handles exotic cases such as 
       
  4143  *  \code
       
  4144  *    Class<(id<0)>
       
  4145  *    Class<bits<<2>
       
  4146  *    Class<"<">
       
  4147  *    Class<'<'>
       
  4148  *    Class<(")<")>
       
  4149  *  \endcode
       
  4150  */
       
  4151 static int findEndOfTemplate(const QCString &s,int startPos)
       
  4152 {
       
  4153   // locate end of template
       
  4154   int e=startPos;
       
  4155   int brCount=1;
       
  4156   int roundCount=0;
       
  4157   int len = s.length();
       
  4158   bool insideString=FALSE;
       
  4159   bool insideChar=FALSE;
       
  4160   char pc = 0;
       
  4161   while (e<len && brCount!=0)
       
  4162   {
       
  4163     char c=s.at(e);
       
  4164     switch(c)
       
  4165     {
       
  4166       case '<': 
       
  4167         if (!insideString && !insideChar)
       
  4168         {
       
  4169           if (e<len-1 && s.at(e+1)=='<') 
       
  4170             e++; 
       
  4171           else if (roundCount==0)
       
  4172             brCount++;
       
  4173         }
       
  4174         break;
       
  4175       case '>':
       
  4176         if (!insideString && !insideChar)
       
  4177         {
       
  4178           if (e<len-1 && s.at(e+1)=='>') 
       
  4179             e++; 
       
  4180           else if (roundCount==0)
       
  4181             brCount--;
       
  4182         }
       
  4183         break;
       
  4184       case '(':
       
  4185         if (!insideString && !insideChar) 
       
  4186           roundCount++;
       
  4187         break;
       
  4188       case ')':
       
  4189         if (!insideString && !insideChar) 
       
  4190           roundCount--;
       
  4191         break;
       
  4192       case '"':
       
  4193         if (!insideChar)
       
  4194         {
       
  4195           if (insideString && pc!='\\') 
       
  4196             insideString=FALSE;
       
  4197           else
       
  4198             insideString=TRUE;
       
  4199         }
       
  4200         break;
       
  4201       case '\'':
       
  4202         if (!insideString)
       
  4203         {
       
  4204           if (insideChar && pc!='\\')
       
  4205             insideChar=FALSE;
       
  4206           else
       
  4207             insideChar=TRUE;
       
  4208         }
       
  4209         break;
       
  4210     }
       
  4211     pc = c;
       
  4212     e++;
       
  4213   }
       
  4214   return brCount==0 ? e : -1;
       
  4215 }
       
  4216 
       
  4217 static bool findClassRelation(
       
  4218                            EntryNav *rootNav,
       
  4219                            Definition *context,
       
  4220                            ClassDef *cd,
       
  4221                            BaseInfo *bi,
       
  4222                            QDict<int> *templateNames,
       
  4223                            FindBaseClassRelation_Mode mode,
       
  4224                            bool isArtificial
       
  4225                           )
       
  4226 {
       
  4227   //printf("findClassRelation(class=%s base=%s templateNames=",
       
  4228   //    cd->name().data(),bi->name.data());
       
  4229   //if (templateNames)
       
  4230   //{
       
  4231   //  QDictIterator<int> qdi(*templateNames);
       
  4232   //  int *tempArgIndex;
       
  4233   //  for (;(tempArgIndex=qdi.current());++qdi)
       
  4234   //  {
       
  4235   //    printf("(%s->%d) ",qdi.currentKey(),*tempArgIndex);
       
  4236   //  }
       
  4237   //}
       
  4238   //printf("\n");
       
  4239 
       
  4240   Entry *root = rootNav->entry();
       
  4241 
       
  4242   QCString biName=bi->name;
       
  4243   bool explicitGlobalScope=FALSE;
       
  4244   //printf("findClassRelation: biName=`%s'\n",biName.data());
       
  4245   if (biName.left(2)=="::") // explicit global scope
       
  4246   {
       
  4247      biName=biName.right(biName.length()-2);
       
  4248      explicitGlobalScope=TRUE;
       
  4249   }
       
  4250 
       
  4251   EntryNav *parentNode=rootNav->parent();
       
  4252   bool lastParent=FALSE;
       
  4253   do // for each parent scope, starting with the largest scope 
       
  4254      // (in case of nested classes)
       
  4255   {
       
  4256     QCString scopeName= parentNode ? parentNode->name().data() : "";
       
  4257     int scopeOffset=explicitGlobalScope ? 0 : scopeName.length();
       
  4258     do // try all parent scope prefixes, starting with the largest scope
       
  4259     {
       
  4260       //printf("scopePrefix=`%s' biName=`%s'\n",
       
  4261       //    scopeName.left(scopeOffset).data(),biName.data());
       
  4262 
       
  4263       QCString baseClassName=biName;
       
  4264       if (scopeOffset>0)
       
  4265       {
       
  4266         baseClassName.prepend(scopeName.left(scopeOffset)+"::");
       
  4267       }
       
  4268       //QCString stripped;
       
  4269       //baseClassName=stripTemplateSpecifiersFromScope
       
  4270       //                    (removeRedundantWhiteSpace(baseClassName),TRUE,
       
  4271       //                    &stripped);
       
  4272       MemberDef *baseClassTypeDef=0;
       
  4273       QCString templSpec;
       
  4274       ClassDef *baseClass=getResolvedClass(explicitGlobalScope ? Doxygen::globalScope : context,
       
  4275                                            cd->getFileDef(), 
       
  4276                                            baseClassName,
       
  4277                                            &baseClassTypeDef,
       
  4278                                            &templSpec,
       
  4279                                            mode==Undocumented,
       
  4280                                            TRUE
       
  4281                                           );
       
  4282       //printf("baseClassName=%s baseClass=%p cd=%p explicitGlobalScope=%d\n",
       
  4283       //    baseClassName.data(),baseClass,cd,explicitGlobalScope);
       
  4284       //printf("    scope=`%s' baseClassName=`%s' baseClass=%s templSpec=%s\n",
       
  4285       //                    cd ? cd->name().data():"<none>",
       
  4286       //                    baseClassName.data(),
       
  4287       //                    baseClass?baseClass->name().data():"<none>",
       
  4288       //                    templSpec.data()
       
  4289       //      );
       
  4290       //if (baseClassName.left(root->name.length())!=root->name ||
       
  4291       //    baseClassName.at(root->name.length())!='<'
       
  4292       //   ) // Check for base class with the same name.
       
  4293       //     // If found then look in the outer scope for a match
       
  4294       //     // and prevent recursion.
       
  4295       if (!isRecursiveBaseClass(rootNav->name(),baseClassName) || explicitGlobalScope)
       
  4296       {
       
  4297         Debug::print(
       
  4298             Debug::Classes,0,"    class relation %s inherited/used by %s found (%s and %s) templSpec='%s'\n",
       
  4299             baseClassName.data(),
       
  4300             rootNav->name().data(),
       
  4301             (bi->prot==Private)?"private":((bi->prot==Protected)?"protected":"public"),
       
  4302             (bi->virt==Normal)?"normal":"virtual",
       
  4303             templSpec.data()
       
  4304            );
       
  4305 
       
  4306         int i=baseClassName.find('<');
       
  4307         int si=baseClassName.findRev("::",i==-1 ? baseClassName.length() : i);
       
  4308         if (si==-1) si=0;
       
  4309         if (baseClass==0 && i!=-1) 
       
  4310           // base class has template specifiers
       
  4311         {
       
  4312           // TODO: here we should try to find the correct template specialization
       
  4313           // but for now, we only look for the unspecializated base class.
       
  4314           int e=findEndOfTemplate(baseClassName,i+1);
       
  4315           //printf("baseClass==0 i=%d e=%d\n",i,e);
       
  4316           if (e!=-1) // end of template was found at e
       
  4317           {
       
  4318             templSpec=removeRedundantWhiteSpace(baseClassName.mid(i,e-i));
       
  4319             baseClassName=baseClassName.left(i)+baseClassName.right(baseClassName.length()-e);
       
  4320             baseClass=getResolvedClass(explicitGlobalScope ? Doxygen::globalScope : context,
       
  4321                                        cd->getFileDef(),
       
  4322                                        baseClassName,
       
  4323                                        &baseClassTypeDef,
       
  4324                                        0, //&templSpec,
       
  4325                                        mode==Undocumented,
       
  4326                                        TRUE
       
  4327                                       );
       
  4328             //printf("baseClass=%p -> baseClass=%s templSpec=%s\n",
       
  4329             //      baseClass,baseClassName.data(),templSpec.data());
       
  4330           }
       
  4331         }
       
  4332         else if (baseClass && !templSpec.isEmpty()) // we have a known class, but also
       
  4333                                                     // know it is a template, so see if
       
  4334                                                     // we can also link to the explicit
       
  4335                                                     // instance (for instance if a class
       
  4336                                                     // derived from a template argument)
       
  4337         {
       
  4338           //printf("baseClass=%p templSpec=%s\n",baseClass,templSpec.data());
       
  4339           ClassDef *templClass=getClass(baseClass->name()+templSpec);
       
  4340           if (templClass)
       
  4341           {
       
  4342             // use the template instance instead of the template base.
       
  4343             baseClass = templClass;
       
  4344             templSpec.resize(0);
       
  4345           }
       
  4346         }
       
  4347 
       
  4348         //printf("cd=%p baseClass=%p\n",cd,baseClass);
       
  4349         bool found=baseClass!=0 && (baseClass!=cd || mode==TemplateInstances);
       
  4350         //printf("1. found=%d\n",found);
       
  4351         if (!found && si!=-1)
       
  4352         {
       
  4353           QCString tmpTemplSpec;
       
  4354           // replace any namespace aliases
       
  4355           replaceNamespaceAliases(baseClassName,si);
       
  4356           baseClass=getResolvedClass(explicitGlobalScope ? Doxygen::globalScope : context,
       
  4357                                      cd->getFileDef(),
       
  4358                                      baseClassName,
       
  4359                                      &baseClassTypeDef,
       
  4360                                      &tmpTemplSpec,
       
  4361                                      mode==Undocumented,
       
  4362                                      TRUE
       
  4363                                     );
       
  4364           found=baseClass!=0 && baseClass!=cd;
       
  4365           if (found) templSpec = tmpTemplSpec;
       
  4366         }
       
  4367         //printf("2. found=%d\n",found);
       
  4368         
       
  4369         //printf("root->name=%s biName=%s baseClassName=%s\n",
       
  4370         //        root->name.data(),biName.data(),baseClassName.data());
       
  4371 
       
  4372         if (!found)
       
  4373         {
       
  4374           baseClass=findClassWithinClassContext(context,cd,baseClassName);
       
  4375           //printf("findClassWithinClassContext(%s,%s)=%p\n",
       
  4376           //    cd->name().data(),baseClassName.data(),baseClass);
       
  4377           found = baseClass!=0 && baseClass!=cd;
       
  4378 
       
  4379         }
       
  4380         bool isATemplateArgument = templateNames!=0 && templateNames->find(biName)!=0;
       
  4381         // make templSpec canonical
       
  4382         // Warning: the following line doesn't work for Mixin classes (see bug 560623)
       
  4383         // templSpec = getCanonicalTemplateSpec(cd, cd->getFileDef(), templSpec);
       
  4384 
       
  4385         //printf("3. found=%d\n",found);
       
  4386         if (found)
       
  4387         {
       
  4388           Debug::print(Debug::Classes,0,"    Documented base class `%s' templSpec=%s\n",biName.data(),templSpec.isEmpty()?"":templSpec.data());
       
  4389           // add base class to this class
       
  4390 
       
  4391           // if templSpec is not empty then we should "instantiate"
       
  4392           // the template baseClass. A new ClassDef should be created
       
  4393           // to represent the instance. To be able to add the (instantiated)
       
  4394           // members and documentation of a template class 
       
  4395           // (inserted in that template class at a later stage), 
       
  4396           // the template should know about its instances. 
       
  4397           // the instantiation process, should be done in a recursive way, 
       
  4398           // since instantiating a template may introduce new inheritance 
       
  4399           // relations.
       
  4400           if (!templSpec.isEmpty() && mode==TemplateInstances)
       
  4401           {
       
  4402             // if baseClass is actually a typedef then we should not
       
  4403             // instantiate it, since typedefs are in a different namespace
       
  4404             // see bug531637 for an example where this would otherwise hang
       
  4405             // doxygen
       
  4406             if (baseClassTypeDef==0)
       
  4407             {
       
  4408               //printf("       => findTemplateInstanceRelation: %p\n",baseClassTypeDef);
       
  4409               findTemplateInstanceRelation(root,context,baseClass,templSpec,templateNames,isArtificial);
       
  4410             }
       
  4411           }
       
  4412           else if (mode==DocumentedOnly || mode==Undocumented)
       
  4413           {
       
  4414             //printf("       => insert base class\n");
       
  4415             QCString usedName;
       
  4416             if (baseClassTypeDef) 
       
  4417             {
       
  4418               usedName=biName;
       
  4419               //printf("***** usedName=%s templSpec=%s\n",usedName.data(),templSpec.data());
       
  4420             }
       
  4421             if (Config_getBool("SIP_SUPPORT")) bi->prot=Public;
       
  4422             cd->insertBaseClass(baseClass,usedName,bi->prot,bi->virt,templSpec);
       
  4423             // add this class as super class to the base class
       
  4424             baseClass->insertSubClass(cd,bi->prot,bi->virt,templSpec);
       
  4425           }
       
  4426           return TRUE;
       
  4427         }
       
  4428         else if (mode==Undocumented && (scopeOffset==0 || isATemplateArgument))
       
  4429         {
       
  4430           Debug::print(Debug::Classes,0,
       
  4431                        "    New undocumented base class `%s' baseClassName=%s\n",
       
  4432                        biName.data(),baseClassName.data()
       
  4433                       );
       
  4434           baseClass=0;
       
  4435           if (isATemplateArgument)
       
  4436           {
       
  4437             baseClass=Doxygen::hiddenClasses->find(baseClassName);
       
  4438             if (baseClass==0)
       
  4439             {
       
  4440               baseClass=new ClassDef(root->fileName,root->startLine,
       
  4441                                  baseClassName,ClassDef::Class);
       
  4442               Doxygen::hiddenClasses->append(baseClassName,baseClass);
       
  4443               if (isArtificial) baseClass->setArtificial(TRUE);
       
  4444             }
       
  4445           }
       
  4446           else
       
  4447           {
       
  4448             baseClass=Doxygen::classSDict->find(baseClassName);
       
  4449             //printf("*** classDDict->find(%s)=%p biName=%s templSpec=%s\n",
       
  4450             //    baseClassName.data(),baseClass,biName.data(),templSpec.data());
       
  4451             if (baseClass==0)
       
  4452             {
       
  4453               baseClass=new ClassDef(root->fileName,root->startLine,
       
  4454                   baseClassName,ClassDef::Class);
       
  4455               Doxygen::classSDict->append(baseClassName,baseClass);
       
  4456               if (isArtificial) baseClass->setArtificial(TRUE);
       
  4457             }
       
  4458           }
       
  4459           // add base class to this class
       
  4460           cd->insertBaseClass(baseClass,biName,bi->prot,bi->virt,templSpec);
       
  4461           // add this class as super class to the base class
       
  4462           baseClass->insertSubClass(cd,bi->prot,bi->virt,templSpec);
       
  4463           // the undocumented base was found in this file
       
  4464           baseClass->insertUsedFile(root->fileName);
       
  4465           baseClass->setOuterScope(Doxygen::globalScope);
       
  4466           return TRUE;
       
  4467         }
       
  4468         else
       
  4469         {
       
  4470           Debug::print(Debug::Classes,0,"    Base class `%s' not found\n",biName.data());
       
  4471         }
       
  4472       }
       
  4473       else
       
  4474       {
       
  4475         if (mode!=TemplateInstances)
       
  4476         {
       
  4477           warn(root->fileName,root->startLine,
       
  4478               "Detected potential recursive class relation "
       
  4479               "between class %s and base class %s!\n",
       
  4480               root->name.data(),baseClassName.data()
       
  4481               );
       
  4482         }
       
  4483         // for mode==TemplateInstance this case is quite common and
       
  4484         // indicates a relation between a template class and a template 
       
  4485         // instance with the same name.
       
  4486       }
       
  4487       if (scopeOffset==0)
       
  4488       {
       
  4489         scopeOffset=-1;
       
  4490       }
       
  4491       else if ((scopeOffset=scopeName.findRev("::",scopeOffset-1))==-1)
       
  4492       {
       
  4493         scopeOffset=0;
       
  4494       }
       
  4495       //printf("new scopeOffset=`%d'",scopeOffset);
       
  4496     } while (scopeOffset>=0);
       
  4497 
       
  4498     if (parentNode==0)
       
  4499     {
       
  4500       lastParent=TRUE;
       
  4501     }
       
  4502     else
       
  4503     {
       
  4504       parentNode=parentNode->parent();
       
  4505     }
       
  4506   } while (lastParent);
       
  4507 
       
  4508   return FALSE;
       
  4509 }
       
  4510 
       
  4511 //----------------------------------------------------------------------
       
  4512 // Computes the base and super classes for each class in the tree
       
  4513 
       
  4514 static bool isClassSection(EntryNav *rootNav)
       
  4515 {
       
  4516   if ( !rootNav->name().isEmpty() )
       
  4517   {
       
  4518     if (rootNav->section() & Entry::COMPOUND_MASK)
       
  4519          // is it a compound (class, struct, union, interface ...)
       
  4520     {
       
  4521       return TRUE;
       
  4522     }
       
  4523     else if (rootNav->section() & Entry::COMPOUNDDOC_MASK) 
       
  4524          // is it a documentation block with inheritance info.
       
  4525     {
       
  4526       rootNav->loadEntry(g_storage);
       
  4527       Entry *root = rootNav->entry();
       
  4528       bool extends = root->extends->count()>0;
       
  4529       rootNav->releaseEntry(); 
       
  4530       if (extends) return TRUE;
       
  4531     }
       
  4532   }
       
  4533   return FALSE;
       
  4534 }
       
  4535 
       
  4536 
       
  4537 /*! Builds a dictionary of all entry nodes in the tree starting with \a root
       
  4538  */
       
  4539 static void findClassEntries(EntryNav *rootNav)
       
  4540 {
       
  4541   if (isClassSection(rootNav))
       
  4542   {
       
  4543     g_classEntries.insert(rootNav->name(),rootNav);
       
  4544   }
       
  4545   RECURSE_ENTRYTREE(findClassEntries,rootNav);
       
  4546 }
       
  4547 
       
  4548 /*! Using the dictionary build by findClassEntries(), this 
       
  4549  *  function will look for additional template specialization that
       
  4550  *  exists as inheritance relations only. These instances will be
       
  4551  *  added to the template they are derived from.
       
  4552  */
       
  4553 static void findInheritedTemplateInstances()
       
  4554 {
       
  4555   ClassSDict::Iterator cli(*Doxygen::classSDict);
       
  4556   for (cli.toFirst();cli.current();++cli) cli.current()->visited=FALSE;
       
  4557   QDictIterator<EntryNav> edi(g_classEntries);
       
  4558   EntryNav *rootNav;
       
  4559   for (;(rootNav=edi.current());++edi)
       
  4560   {
       
  4561     ClassDef *cd;
       
  4562     // strip any annonymous scopes first 
       
  4563     QCString bName=stripAnonymousNamespaceScope(rootNav->name());
       
  4564     bName=stripTemplateSpecifiersFromScope(bName);
       
  4565     Debug::print(Debug::Classes,0,"  Inheritance: Class %s : \n",bName.data());
       
  4566     if ((cd=getClass(bName)))
       
  4567     {
       
  4568       rootNav->loadEntry(g_storage);
       
  4569       //printf("Class %s %d\n",cd->name().data(),root->extends->count());
       
  4570       findBaseClassesForClass(rootNav,cd,cd,cd,TemplateInstances,FALSE);
       
  4571       rootNav->releaseEntry();
       
  4572     }
       
  4573   }
       
  4574 }
       
  4575 
       
  4576 static void findUsedTemplateInstances()
       
  4577 {
       
  4578   ClassSDict::Iterator cli(*Doxygen::classSDict);
       
  4579   for (cli.toFirst();cli.current();++cli) cli.current()->visited=FALSE;
       
  4580   QDictIterator<EntryNav> edi(g_classEntries);
       
  4581   EntryNav *rootNav;
       
  4582   for (;(rootNav=edi.current());++edi)
       
  4583   {
       
  4584     ClassDef *cd;
       
  4585     // strip any annonymous scopes first 
       
  4586     QCString bName=stripAnonymousNamespaceScope(rootNav->name());
       
  4587     bName=stripTemplateSpecifiersFromScope(bName);
       
  4588     Debug::print(Debug::Classes,0,"  Usage: Class %s : \n",bName.data());
       
  4589     if ((cd=getClass(bName)))
       
  4590     {
       
  4591       rootNav->loadEntry(g_storage);
       
  4592       findUsedClassesForClass(rootNav,cd,cd,cd,TRUE);
       
  4593       rootNav->releaseEntry();
       
  4594     }
       
  4595   }
       
  4596 }
       
  4597 
       
  4598 static void computeClassRelations()
       
  4599 {
       
  4600   ClassSDict::Iterator cli(*Doxygen::classSDict);
       
  4601   for (cli.toFirst();cli.current();++cli) cli.current()->visited=FALSE;
       
  4602   QDictIterator<EntryNav> edi(g_classEntries);
       
  4603   EntryNav *rootNav;
       
  4604   for (;(rootNav=edi.current());++edi)
       
  4605   {
       
  4606     ClassDef *cd;
       
  4607 
       
  4608     rootNav->loadEntry(g_storage);
       
  4609     Entry *root = rootNav->entry();
       
  4610 
       
  4611     // strip any annonymous scopes first 
       
  4612     QCString bName=stripAnonymousNamespaceScope(rootNav->name());
       
  4613     bName=stripTemplateSpecifiersFromScope(bName);
       
  4614     Debug::print(Debug::Classes,0,"  Relations: Class %s : \n",bName.data());
       
  4615     if ((cd=getClass(bName)))
       
  4616     {
       
  4617       findBaseClassesForClass(rootNav,cd,cd,cd,DocumentedOnly,FALSE);
       
  4618     }
       
  4619     if ((cd==0 || (!cd->hasDocumentation() && !cd->isReference())) && 
       
  4620         bName.right(2)!="::")
       
  4621     {
       
  4622       if (!root->name.isEmpty() && root->name.find('@')==-1 && // normal name
       
  4623           (guessSection(root->fileName)==Entry::HEADER_SEC || 
       
  4624            Config_getBool("EXTRACT_LOCAL_CLASSES")) && // not defined in source file
       
  4625           (root->protection!=Private || Config_getBool("EXTRACT_PRIVATE")) && // hidden by protection
       
  4626           !Config_getBool("HIDE_UNDOC_CLASSES") // undocumented class are visible
       
  4627          )
       
  4628         warn_undoc(
       
  4629                    root->fileName,root->startLine,
       
  4630                    "Warning: Compound %s is not documented.",
       
  4631                    root->name.data()
       
  4632              );
       
  4633     }
       
  4634 
       
  4635     rootNav->releaseEntry();
       
  4636   }
       
  4637 }
       
  4638 
       
  4639 static void computeTemplateClassRelations()
       
  4640 {
       
  4641   QDictIterator<EntryNav> edi(g_classEntries);
       
  4642   EntryNav *rootNav;
       
  4643   for (;(rootNav=edi.current());++edi)
       
  4644   {
       
  4645     rootNav->loadEntry(g_storage);
       
  4646     Entry *root = rootNav->entry();
       
  4647 
       
  4648     QCString bName=stripAnonymousNamespaceScope(root->name);
       
  4649     bName=stripTemplateSpecifiersFromScope(bName);
       
  4650     ClassDef *cd=getClass(bName);
       
  4651     // strip any annonymous scopes first 
       
  4652     QDict<ClassDef> *templInstances = 0;
       
  4653     if (cd && (templInstances=cd->getTemplateInstances()))
       
  4654     {
       
  4655       Debug::print(Debug::Classes,0,"  Template class %s : \n",cd->name().data());
       
  4656       QDictIterator<ClassDef> tdi(*templInstances);
       
  4657       ClassDef *tcd;
       
  4658       for (tdi.toFirst();(tcd=tdi.current());++tdi) // for each template instance
       
  4659       {
       
  4660         Debug::print(Debug::Classes,0,"    Template instance %s : \n",tcd->name().data());
       
  4661         QCString templSpec = tdi.currentKey();
       
  4662         ArgumentList *templArgs = new ArgumentList;
       
  4663         stringToArgumentList(templSpec,templArgs);
       
  4664         QList<BaseInfo> *baseList=root->extends;
       
  4665         BaseInfo *bi=baseList->first();
       
  4666         while (bi) // for each base class of the template
       
  4667         {
       
  4668           // check if the base class is a template argument
       
  4669           BaseInfo tbi(bi->name,bi->prot,bi->virt);
       
  4670           ArgumentList *tl = cd->templateArguments();
       
  4671           if (tl)
       
  4672           {
       
  4673             QDict<int> *baseClassNames = tcd->getTemplateBaseClassNames();
       
  4674             QDict<int> *templateNames = getTemplateArgumentsInName(tl,bi->name);
       
  4675             // for each template name that we inherit from we need to
       
  4676             // substitute the formal with the actual arguments
       
  4677             QDict<int> *actualTemplateNames = new QDict<int>(17);
       
  4678             actualTemplateNames->setAutoDelete(TRUE);
       
  4679             QDictIterator<int> qdi(*templateNames);
       
  4680             for (qdi.toFirst();qdi.current();++qdi)
       
  4681             {
       
  4682               int templIndex = *qdi.current();
       
  4683               Argument *actArg = 0;
       
  4684               if (templIndex<(int)templArgs->count()) 
       
  4685               {
       
  4686                 actArg=templArgs->at(templIndex);
       
  4687               }
       
  4688               if (actArg!=0 &&
       
  4689                   baseClassNames!=0 &&
       
  4690                   baseClassNames->find(actArg->type)!=0 &&
       
  4691                   actualTemplateNames->find(actArg->type)==0
       
  4692                  )
       
  4693               {
       
  4694                 actualTemplateNames->insert(actArg->type,new int(templIndex));
       
  4695               }
       
  4696             }
       
  4697             delete templateNames;
       
  4698             
       
  4699             tbi.name = substituteTemplateArgumentsInString(bi->name,tl,templArgs);
       
  4700             // find a documented base class in the correct scope
       
  4701             if (!findClassRelation(rootNav,cd,tcd,&tbi,actualTemplateNames,DocumentedOnly,FALSE))
       
  4702             {
       
  4703               // no documented base class -> try to find an undocumented one
       
  4704               findClassRelation(rootNav,cd,tcd,&tbi,actualTemplateNames,Undocumented,FALSE);
       
  4705             }
       
  4706             delete actualTemplateNames;
       
  4707           }
       
  4708           bi=baseList->next();
       
  4709         }
       
  4710         delete templArgs;
       
  4711       } // class has no base classes
       
  4712     }
       
  4713 
       
  4714     rootNav->releaseEntry();
       
  4715   }
       
  4716 }
       
  4717 
       
  4718 //-----------------------------------------------------------------------
       
  4719 // compute the references (anchors in HTML) for each function in the file
       
  4720 
       
  4721 static void computeMemberReferences()
       
  4722 {
       
  4723   ClassSDict::Iterator cli(*Doxygen::classSDict);
       
  4724   ClassDef *cd=0;
       
  4725   for (cli.toFirst();(cd=cli.current());++cli)
       
  4726   {
       
  4727     cd->computeAnchors();
       
  4728   } 
       
  4729   FileName *fn=Doxygen::inputNameList->first();
       
  4730   while (fn)
       
  4731   {
       
  4732     FileDef *fd=fn->first();
       
  4733     while (fd)
       
  4734     {
       
  4735       fd->computeAnchors();
       
  4736       fd=fn->next();
       
  4737     }
       
  4738     fn=Doxygen::inputNameList->next();
       
  4739   }
       
  4740   NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
       
  4741   NamespaceDef *nd=0;
       
  4742   for (nli.toFirst();(nd=nli.current());++nli)
       
  4743   {
       
  4744     nd->computeAnchors();
       
  4745   }
       
  4746   GroupSDict::Iterator gli(*Doxygen::groupSDict);
       
  4747   GroupDef *gd;
       
  4748   for (gli.toFirst();(gd=gli.current());++gli)
       
  4749   {
       
  4750     gd->computeAnchors();
       
  4751   }
       
  4752 }
       
  4753 
       
  4754 //----------------------------------------------------------------------
       
  4755 
       
  4756 static void addListReferences()
       
  4757 {
       
  4758   MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
       
  4759   MemberName *mn=0;
       
  4760   for (mnli.toFirst();(mn=mnli.current());++mnli)
       
  4761   {
       
  4762     MemberNameIterator mni(*mn);
       
  4763     MemberDef *md=0;
       
  4764     for (mni.toFirst();(md=mni.current());++mni)
       
  4765     {
       
  4766       md->visited=FALSE;
       
  4767     }
       
  4768   }
       
  4769   MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict);
       
  4770   for (fnli.toFirst();(mn=fnli.current());++fnli)
       
  4771   {
       
  4772     MemberNameIterator mni(*mn);
       
  4773     MemberDef *md=0;
       
  4774     for (mni.toFirst();(md=mni.current());++mni)
       
  4775     {
       
  4776       md->visited=FALSE;
       
  4777     }
       
  4778   }
       
  4779 
       
  4780   ClassSDict::Iterator cli(*Doxygen::classSDict);
       
  4781   ClassDef *cd=0;
       
  4782   for (cli.toFirst();(cd=cli.current());++cli)
       
  4783   {
       
  4784     cd->addListReferences();
       
  4785   } 
       
  4786   FileName *fn=Doxygen::inputNameList->first();
       
  4787   while (fn)
       
  4788   {
       
  4789     FileDef *fd=fn->first();
       
  4790     while (fd)
       
  4791     {
       
  4792       fd->addListReferences();
       
  4793       fd=fn->next();
       
  4794     }
       
  4795     fn=Doxygen::inputNameList->next();
       
  4796   }
       
  4797   NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
       
  4798   NamespaceDef *nd=0;
       
  4799   for (nli.toFirst();(nd=nli.current());++nli)
       
  4800   {
       
  4801     nd->addListReferences();
       
  4802   }
       
  4803   GroupSDict::Iterator gli(*Doxygen::groupSDict);
       
  4804   GroupDef *gd;
       
  4805   for (gli.toFirst();(gd=gli.current());++gli)
       
  4806   {
       
  4807     gd->addListReferences();
       
  4808   }
       
  4809   PageSDict::Iterator pdi(*Doxygen::pageSDict);
       
  4810   PageDef *pd=0;
       
  4811   for (pdi.toFirst();(pd=pdi.current());++pdi)
       
  4812   {
       
  4813     QCString name = pd->name();
       
  4814     if (pd->getGroupDef())
       
  4815     {
       
  4816       name = pd->getGroupDef()->getOutputFileBase();
       
  4817     }
       
  4818     {
       
  4819       LockingPtr< QList<ListItemInfo> > xrefItems = pd->xrefListItems();
       
  4820       addRefItem(xrefItems.pointer(),
       
  4821           name,
       
  4822           theTranslator->trPage(TRUE,TRUE),
       
  4823           name,pd->title(),0);
       
  4824     }
       
  4825   }
       
  4826   DirSDict::Iterator ddi(*Doxygen::directories);
       
  4827   DirDef *dd = 0;
       
  4828   for (ddi.toFirst();(dd=ddi.current());++ddi)
       
  4829   {
       
  4830     QCString name = dd->getOutputFileBase();
       
  4831     //if (dd->getGroupDef())
       
  4832     //{
       
  4833     //  name = dd->getGroupDef()->getOutputFileBase();
       
  4834     //}
       
  4835     LockingPtr< QList<ListItemInfo> > xrefItems = dd->xrefListItems();
       
  4836     addRefItem(xrefItems.pointer(),
       
  4837         name,
       
  4838         theTranslator->trDir(TRUE,TRUE),
       
  4839         name,dd->displayName(),0);
       
  4840   }
       
  4841 }
       
  4842 
       
  4843 //----------------------------------------------------------------------
       
  4844 
       
  4845 static void generateXRefPages()
       
  4846 {
       
  4847   QDictIterator<RefList> di(*Doxygen::xrefLists);
       
  4848   RefList *rl;
       
  4849   for (di.toFirst();(rl=di.current());++di)
       
  4850   {
       
  4851     rl->generatePage();
       
  4852   }
       
  4853 }
       
  4854 
       
  4855 //----------------------------------------------------------------------
       
  4856 // Copy the documentation in entry `root' to member definition `md' and
       
  4857 // set the function declaration of the member to `funcDecl'. If the boolean 
       
  4858 // over_load is set the standard overload text is added. 
       
  4859 
       
  4860 static void addMemberDocs(EntryNav *rootNav,
       
  4861                    MemberDef *md, const char *funcDecl,
       
  4862                    ArgumentList *al,
       
  4863                    bool over_load,
       
  4864                    NamespaceSDict *
       
  4865                   )
       
  4866 {
       
  4867   Entry *root = rootNav->entry();
       
  4868   //printf("addMemberDocs: `%s'::`%s' `%s' funcDecl=`%s' mSpec=%d\n",
       
  4869   //     root->parent->name.data(),md->name().data(),md->argsString(),funcDecl,root->spec);
       
  4870   QCString fDecl=funcDecl;
       
  4871   // strip extern specifier
       
  4872   fDecl.stripPrefix("extern ");
       
  4873   md->setDefinition(fDecl);
       
  4874   md->enableCallGraph(root->callGraph);
       
  4875   md->enableCallerGraph(root->callerGraph);
       
  4876   ClassDef     *cd=md->getClassDef();
       
  4877   NamespaceDef *nd=md->getNamespaceDef();
       
  4878   QCString fullName;
       
  4879   if (cd) 
       
  4880     fullName = cd->name();
       
  4881   else if (nd) 
       
  4882     fullName = nd->name();
       
  4883 
       
  4884   if (!fullName.isEmpty()) fullName+="::";
       
  4885   fullName+=md->name();
       
  4886   FileDef *rfd=rootNav->fileDef();
       
  4887 
       
  4888   // TODO determine scope based on root not md
       
  4889   Definition *rscope = md->getOuterScope();
       
  4890 
       
  4891   LockingPtr<ArgumentList> mdAl = md->argumentList();
       
  4892   if (al)
       
  4893   {
       
  4894     //printf("merging arguments (1) docs=%d\n",root->doc.isEmpty());
       
  4895     mergeArguments(mdAl.pointer(),al,!root->doc.isEmpty());
       
  4896   }
       
  4897   else
       
  4898   {
       
  4899     if ( 
       
  4900           matchArguments2( md->getOuterScope(), md->getFileDef(), mdAl.pointer(),
       
  4901                            rscope,rfd,root->argList,
       
  4902                            TRUE
       
  4903                          )
       
  4904        ) 
       
  4905     {
       
  4906       //printf("merging arguments (2)\n");
       
  4907       mergeArguments(mdAl.pointer(),root->argList,!root->doc.isEmpty());
       
  4908     }
       
  4909   }
       
  4910   if (over_load)  // the \overload keyword was used
       
  4911   {
       
  4912     QCString doc=getOverloadDocs();
       
  4913     if (!root->doc.isEmpty())
       
  4914     {
       
  4915       doc+="<p>";
       
  4916       doc+=root->doc;
       
  4917     }
       
  4918     md->setDocumentation(doc,root->docFile,root->docLine); 
       
  4919     md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
       
  4920     md->setDocsForDefinition(!root->proto);
       
  4921   }
       
  4922   else  
       
  4923   {
       
  4924     //printf("overwrite!\n");
       
  4925     md->setDocumentation(root->doc,root->docFile,root->docLine);
       
  4926     md->setDocsForDefinition(!root->proto);
       
  4927 
       
  4928     //printf("overwrite!\n");
       
  4929     md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
       
  4930 
       
  4931     if (
       
  4932         (md->inbodyDocumentation().isEmpty() ||
       
  4933          !rootNav->parent()->name().isEmpty()
       
  4934         ) && !root->inbodyDocs.isEmpty()
       
  4935        )
       
  4936     {
       
  4937       md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
       
  4938     }
       
  4939   }
       
  4940 
       
  4941   //printf("initializer: '%s'(isEmpty=%d) '%s'(isEmpty=%d)\n",
       
  4942   //    md->initializer().data(),md->initializer().isEmpty(),
       
  4943   //    root->initializer.data(),root->initializer.isEmpty()
       
  4944   //   );
       
  4945   if (md->initializer().isEmpty() && !root->initializer.isEmpty())
       
  4946   {
       
  4947     //printf("setInitializer\n");
       
  4948     md->setInitializer(root->initializer);
       
  4949   }
       
  4950 
       
  4951   md->setMaxInitLines(root->initLines);
       
  4952 
       
  4953   if (rfd)
       
  4954   {
       
  4955     if ((md->getStartBodyLine()==-1 && root->bodyLine!=-1) 
       
  4956        )
       
  4957     {
       
  4958       //printf("Setting new body segment [%d,%d]\n",root->bodyLine,root->endBodyLine);
       
  4959       md->setBodySegment(root->bodyLine,root->endBodyLine);
       
  4960       md->setBodyDef(rfd);
       
  4961     }
       
  4962 
       
  4963     md->setRefItems(root->sli);
       
  4964   }
       
  4965 
       
  4966   md->enableCallGraph(md->hasCallGraph() || root->callGraph);
       
  4967   md->enableCallerGraph(md->hasCallerGraph() || root->callerGraph);
       
  4968 
       
  4969   md->mergeMemberSpecifiers(root->spec);
       
  4970   md->addSectionsToDefinition(root->anchors);
       
  4971   addMemberToGroups(root,md);
       
  4972   if (cd) cd->insertUsedFile(root->fileName);
       
  4973   //printf("root->mGrpId=%d\n",root->mGrpId);
       
  4974   if (root->mGrpId!=-1)
       
  4975   {
       
  4976     if (md->getMemberGroupId()!=-1)
       
  4977     {
       
  4978       if (md->getMemberGroupId()!=root->mGrpId)
       
  4979       {
       
  4980         warn(
       
  4981              root->fileName,root->startLine,
       
  4982              "Warning: member %s belongs to two different groups. The second "
       
  4983              "one found here will be ignored.",
       
  4984              md->name().data()
       
  4985             );
       
  4986       }
       
  4987     }
       
  4988     else // set group id
       
  4989     {
       
  4990       //printf("setMemberGroupId=%d md=%s\n",root->mGrpId,md->name().data());
       
  4991       md->setMemberGroupId(root->mGrpId);
       
  4992     }
       
  4993   }
       
  4994 }
       
  4995 
       
  4996 //----------------------------------------------------------------------
       
  4997 // find a class definition given the scope name and (optionally) a 
       
  4998 // template list specifier
       
  4999 
       
  5000 static ClassDef *findClassDefinition(FileDef *fd,NamespaceDef *nd,
       
  5001                          const char *scopeName)
       
  5002 {
       
  5003   ClassDef *tcd = getResolvedClass(nd,fd,scopeName,0,0,TRUE,TRUE);
       
  5004   return tcd;
       
  5005 }
       
  5006 
       
  5007 
       
  5008 //----------------------------------------------------------------------
       
  5009 // Adds the documentation contained in `root' to a global function
       
  5010 // with name `name' and argument list `args' (for overloading) and
       
  5011 // function declaration `decl' to the corresponding member definition.
       
  5012 
       
  5013 static bool findGlobalMember(EntryNav *rootNav, 
       
  5014                            const QCString &namespaceName,
       
  5015                            const char *name, 
       
  5016                            const char *tempArg,
       
  5017                            const char *, 
       
  5018                            const char *decl)
       
  5019 {
       
  5020   Entry *root = rootNav->entry();
       
  5021   Debug::print(Debug::FindMembers,0,
       
  5022        "2. findGlobalMember(namespace=%s,name=%s,tempArg=%s,decl=%s)\n",
       
  5023           namespaceName.data(),name,tempArg,decl);
       
  5024   QCString n=name;
       
  5025   if (n.isEmpty()) return FALSE;
       
  5026   if (n.find("::")!=-1) return FALSE; // skip undefined class members
       
  5027   MemberName *mn=Doxygen::functionNameSDict->find(n+tempArg); // look in function dictionary
       
  5028   if (mn==0)
       
  5029   {
       
  5030     mn=Doxygen::functionNameSDict->find(n); // try without template arguments
       
  5031   }
       
  5032   if (mn) // function name defined
       
  5033   {
       
  5034     Debug::print(Debug::FindMembers,0,"3. Found function scope\n");
       
  5035     //int count=0;
       
  5036     MemberNameIterator mni(*mn);
       
  5037     MemberDef *md;
       
  5038     bool found=FALSE;
       
  5039     for (mni.toFirst();(md=mni.current()) && !found;++mni)
       
  5040     {
       
  5041       NamespaceDef *nd=md->getNamespaceDef();
       
  5042 
       
  5043       //printf("Namespace namespaceName=%s nd=%s\n",
       
  5044       //    namespaceName.data(),nd ? nd->name().data() : "<none>");
       
  5045 
       
  5046       FileDef *fd=rootNav->fileDef();
       
  5047       //printf("File %s\n",fd ? fd->name().data() : "<none>");
       
  5048       NamespaceSDict *nl = fd ? fd->getUsedNamespaces() : 0;
       
  5049       //SDict<Definition> *cl = fd ? fd->getUsedClasses()    : 0;
       
  5050       //printf("NamespaceList %p\n",nl);
       
  5051 
       
  5052       // search in the list of namespaces that are imported via a 
       
  5053       // using declaration
       
  5054       bool viaUsingDirective = nl && nd && nl->find(nd->qualifiedName())!=0;
       
  5055 
       
  5056       if ((namespaceName.isEmpty() && nd==0) ||  // not in a namespace
       
  5057           (nd && nd->name()==namespaceName) ||   // or in the same namespace 
       
  5058           viaUsingDirective                      // member in `using' namespace
       
  5059          )     
       
  5060       {
       
  5061         Debug::print(Debug::FindMembers,0,"4. Try to add member `%s' to scope `%s'\n",
       
  5062             md->name().data(),namespaceName.data());
       
  5063         QCString nsName = nd ? nd->name().data() : "";
       
  5064 
       
  5065         NamespaceDef *rnd = 0;
       
  5066         if (!namespaceName.isEmpty()) rnd = Doxygen::namespaceSDict->find(namespaceName);
       
  5067 
       
  5068         LockingPtr<ArgumentList> mdAl = md->argumentList();
       
  5069         bool matching=
       
  5070           (mdAl==0 && root->argList->count()==0) ||
       
  5071           md->isVariable() || md->isTypedef() || /* in case of function pointers */
       
  5072           matchArguments2(md->getOuterScope(),md->getFileDef(),mdAl.pointer(),
       
  5073                           rnd ? rnd : Doxygen::globalScope,fd,root->argList,
       
  5074                           FALSE);
       
  5075 
       
  5076         // for template members we need to check if the number of
       
  5077         // template arguments is the same, otherwise we are dealing with
       
  5078         // different functions.
       
  5079         if (matching && root->tArgLists)
       
  5080         {
       
  5081           LockingPtr<ArgumentList> mdTempl = md->templateArguments();
       
  5082           if (mdTempl!=0)
       
  5083           {
       
  5084             if (root->tArgLists->getLast()->count()!=mdTempl->count())
       
  5085             {
       
  5086               matching=FALSE;
       
  5087             }
       
  5088           }
       
  5089         }
       
  5090 
       
  5091 
       
  5092         //printf("%s<->%s\n",
       
  5093         //    argListToString(md->argumentList()).data(),
       
  5094         //    argListToString(root->argList).data());
       
  5095 
       
  5096         // for static members we also check if the comment block was found in 
       
  5097         // the same file. This is needed because static members with the same
       
  5098         // name can be in different files. Thus it would be wrong to just
       
  5099         // put the comment block at the first syntactically matching member.
       
  5100         if (matching && md->isStatic() && 
       
  5101             md->getDefFileName()!=root->fileName && 
       
  5102             mn->count()>1)
       
  5103         {
       
  5104           matching = FALSE;
       
  5105         }
       
  5106 
       
  5107         if (matching) // add docs to the member
       
  5108         {
       
  5109           Debug::print(Debug::FindMembers,0,"5. Match found\n");
       
  5110           addMemberDocs(rootNav,md,decl,root->argList,FALSE);
       
  5111           found=TRUE;
       
  5112         }
       
  5113       }
       
  5114     } 
       
  5115     if (!found && root->relatesType != Duplicate) // no match
       
  5116     {
       
  5117       QCString fullFuncDecl=decl;
       
  5118       if (root->argList) fullFuncDecl+=argListToString(root->argList,TRUE);
       
  5119       warn(root->fileName,root->startLine,
       
  5120            "Warning: no matching file member found for \n%s",fullFuncDecl.data());   
       
  5121       if (mn->count()>0)
       
  5122       {
       
  5123         warn_cont("Possible candidates:\n");
       
  5124         for (mni.toFirst();(md=mni.current());++mni)
       
  5125         {
       
  5126           warn_cont("  %s\n",md->declaration());
       
  5127         }
       
  5128       }
       
  5129     }
       
  5130   }
       
  5131   else // got docs for an undefined member!
       
  5132   {
       
  5133     if (root->type!="friend class" && 
       
  5134         root->type!="friend struct" &&
       
  5135         root->type!="friend union" &&
       
  5136         (!Config_getBool("TYPEDEF_HIDES_STRUCT") || 
       
  5137          root->type.find("typedef ")==-1)
       
  5138        )
       
  5139     {
       
  5140       warn(root->fileName,root->startLine,
       
  5141            "Warning: documented function `%s' was not declared or defined.",decl
       
  5142           );
       
  5143     }
       
  5144   }
       
  5145   return TRUE;
       
  5146 }
       
  5147 
       
  5148 static bool isSpecialization(
       
  5149                   const QList<ArgumentList> &srcTempArgLists,
       
  5150                   const QList<ArgumentList> &dstTempArgLists
       
  5151     )
       
  5152 {
       
  5153     QListIterator<ArgumentList> srclali(srcTempArgLists);
       
  5154     QListIterator<ArgumentList> dstlali(dstTempArgLists);
       
  5155     for (;srclali.current();++srclali,++dstlali)
       
  5156     {
       
  5157       ArgumentList *sal = srclali.current();
       
  5158       ArgumentList *dal = dstlali.current();
       
  5159       if (!(sal && dal && sal->count()==dal->count())) return TRUE;
       
  5160     }
       
  5161     return FALSE;
       
  5162 }
       
  5163 
       
  5164 
       
  5165 static QCString substituteTemplatesInString(
       
  5166     const QList<ArgumentList> &srcTempArgLists,
       
  5167     const QList<ArgumentList> &dstTempArgLists,
       
  5168     ArgumentList *funcTempArgList, // can be used to match template specializations
       
  5169     const QCString &src
       
  5170     )
       
  5171 {
       
  5172   QCString dst;
       
  5173   QRegExp re( "[A-Za-z_][A-Za-z_0-9]*");
       
  5174   //printf("type=%s\n",sa->type.data());
       
  5175   int i,p=0,l; 
       
  5176   while ((i=re.match(src,p,&l))!=-1) // for each word in srcType
       
  5177   {
       
  5178     bool found=FALSE;
       
  5179     dst+=src.mid(p,i-p);
       
  5180     QCString name=src.mid(i,l);
       
  5181 
       
  5182     QListIterator<ArgumentList> srclali(srcTempArgLists);
       
  5183     QListIterator<ArgumentList> dstlali(dstTempArgLists);
       
  5184     for (;srclali.current() && !found;++srclali,++dstlali)
       
  5185     {
       
  5186       ArgumentListIterator tsali(*srclali.current());
       
  5187       ArgumentListIterator tdali(*dstlali.current());
       
  5188       Argument *tsa =0,*tda=0, *fa=0;
       
  5189       if (funcTempArgList)
       
  5190       {
       
  5191         fa=funcTempArgList->first();
       
  5192       }
       
  5193 
       
  5194       for (tsali.toFirst();(tsa=tsali.current()) && !found;++tsali)
       
  5195       {
       
  5196         tda = tdali.current();
       
  5197         //if (tda) printf("tsa=%s|%s tda=%s|%s\n",
       
  5198         //    tsa->type.data(),tsa->name.data(),
       
  5199         //    tda->type.data(),tda->name.data());
       
  5200         if (name==tsa->name)
       
  5201         {
       
  5202           if (tda && tda->name.isEmpty())
       
  5203           {
       
  5204             int vc=0;
       
  5205             if (tda->type.left(6)=="class ") vc=6;
       
  5206             else if (tda->type.left(9)=="typename ") vc=9;
       
  5207             if (vc>0) // convert type=="class T" to type=="class" name=="T"
       
  5208             {
       
  5209               tda->name = tda->type.mid(vc);
       
  5210               tda->type = tda->type.left(vc-1);
       
  5211             }
       
  5212           }
       
  5213           if (tda && !tda->name.isEmpty())
       
  5214           {
       
  5215             name=tda->name; // substitute
       
  5216             found=TRUE;
       
  5217           }
       
  5218           else if (fa)
       
  5219           {
       
  5220             name=fa->type;
       
  5221             found=TRUE;
       
  5222           }
       
  5223         }
       
  5224         if (tda) 
       
  5225           ++tdali; 
       
  5226         else if (fa) 
       
  5227           fa=funcTempArgList->next();
       
  5228       }
       
  5229       //printf("   srcList='%s' dstList='%s faList='%s'\n",
       
  5230       //  argListToString(srclali.current()).data(),
       
  5231       //  argListToString(dstlali.current()).data(),
       
  5232       //  funcTempArgList ? argListToString(funcTempArgList).data() : "<none>");
       
  5233     }
       
  5234     dst+=name; 
       
  5235     p=i+l;
       
  5236   }
       
  5237   dst+=src.right(src.length()-p);
       
  5238   //printf("  substituteTemplatesInString(%s)=%s\n",
       
  5239   //    src.data(),dst.data());
       
  5240   return dst;
       
  5241 }
       
  5242 
       
  5243 static void substituteTemplatesInArgList(
       
  5244                   const QList<ArgumentList> &srcTempArgLists,
       
  5245                   const QList<ArgumentList> &dstTempArgLists,
       
  5246                   ArgumentList *src,
       
  5247                   ArgumentList *dst,
       
  5248                   ArgumentList *funcTempArgs = 0
       
  5249                  )
       
  5250 {
       
  5251   ArgumentListIterator sali(*src);
       
  5252   Argument *sa=0;
       
  5253   Argument *da=dst->first();
       
  5254 
       
  5255   for (sali.toFirst();(sa=sali.current());++sali) // for each member argument
       
  5256   {
       
  5257     QCString dstType = substituteTemplatesInString(
       
  5258                                   srcTempArgLists,dstTempArgLists,funcTempArgs,
       
  5259                                   sa->type);
       
  5260     QCString dstArray = substituteTemplatesInString(
       
  5261                                   srcTempArgLists,dstTempArgLists,funcTempArgs,
       
  5262                                   sa->array);
       
  5263     if (da==0)
       
  5264     {
       
  5265       da=new Argument(*sa);
       
  5266       dst->append(da);
       
  5267       da->type=dstType;
       
  5268       da->array=dstArray;
       
  5269       da=0;
       
  5270     }
       
  5271     else
       
  5272     {
       
  5273       da->type=dstType;
       
  5274       da->type=dstArray;
       
  5275       da=dst->next();
       
  5276     }
       
  5277   }
       
  5278   dst->constSpecifier    = src->constSpecifier;
       
  5279   dst->volatileSpecifier = src->volatileSpecifier;
       
  5280   dst->pureSpecifier     = src->pureSpecifier;
       
  5281   //printf("substituteTemplatesInArgList: replacing %s with %s\n",
       
  5282   //    argListToString(src).data(),argListToString(dst).data()
       
  5283   //    );
       
  5284 }
       
  5285 
       
  5286 
       
  5287 
       
  5288 /*! This function tries to find a member (in a documented class/file/namespace) 
       
  5289  * that corresponds to the function/variable declaration given in \a funcDecl.
       
  5290  *
       
  5291  * The boolean \a overloaded is used to specify whether or not a standard
       
  5292  * overload documentation line should be generated.
       
  5293  *
       
  5294  * The boolean \a isFunc is a hint that indicates that this is a function
       
  5295  * instead of a variable or typedef.
       
  5296  */
       
  5297 static void findMember(EntryNav *rootNav,
       
  5298                        QCString funcDecl,
       
  5299                        bool overloaded,
       
  5300                        bool isFunc
       
  5301                       )
       
  5302 {
       
  5303   Entry *root = rootNav->entry();
       
  5304 
       
  5305   Debug::print(Debug::FindMembers,0,
       
  5306                "findMember(root=%p,funcDecl=`%s',related=`%s',overload=%d,"
       
  5307                "isFunc=%d mGrpId=%d tArgList=%p (#=%d) "
       
  5308                "spec=%d isObjC=%d\n",
       
  5309                root,funcDecl.data(),root->relates.data(),overloaded,isFunc,root->mGrpId,
       
  5310                root->tArgLists,root->tArgLists ? root->tArgLists->count() : 0,
       
  5311                root->spec,root->objc
       
  5312               );
       
  5313 
       
  5314   QCString scopeName;
       
  5315   QCString className;
       
  5316   QCString namespaceName;
       
  5317   QCString funcType;
       
  5318   QCString funcName;
       
  5319   QCString funcArgs;
       
  5320   QCString funcTempList;
       
  5321   QCString exceptions;
       
  5322   QCString funcSpec;
       
  5323   bool isRelated=FALSE;
       
  5324   bool isMemberOf=FALSE;
       
  5325   bool isFriend=FALSE;
       
  5326   bool done;
       
  5327   do
       
  5328   {
       
  5329     done=TRUE;
       
  5330     if (funcDecl.stripPrefix("friend ")) // treat friends as related members
       
  5331     {
       
  5332       isFriend=TRUE;
       
  5333       done=FALSE;
       
  5334     }
       
  5335     if (funcDecl.stripPrefix("inline "))
       
  5336     {
       
  5337       root->spec|=Entry::Inline;
       
  5338       done=FALSE;
       
  5339     }
       
  5340     if (funcDecl.stripPrefix("explicit "))
       
  5341     {
       
  5342       root->spec|=Entry::Explicit;
       
  5343       done=FALSE;
       
  5344     }
       
  5345     if (funcDecl.stripPrefix("mutable "))
       
  5346     {
       
  5347       root->spec|=Entry::Mutable;
       
  5348       done=FALSE;
       
  5349     }
       
  5350     if (funcDecl.stripPrefix("virtual "))
       
  5351     {
       
  5352       done=FALSE;
       
  5353     }
       
  5354   } while (!done);
       
  5355 
       
  5356   // delete any ; from the function declaration
       
  5357   int sep;
       
  5358   while ((sep=funcDecl.find(';'))!=-1)
       
  5359   {
       
  5360     funcDecl=(funcDecl.left(sep)+funcDecl.right(funcDecl.length()-sep-1)).stripWhiteSpace();
       
  5361   }
       
  5362   
       
  5363   // make sure the first character is a space to simplify searching.
       
  5364   if (!funcDecl.isEmpty() && funcDecl[0]!=' ') funcDecl.prepend(" ");
       
  5365   
       
  5366   // remove some superfluous spaces
       
  5367   funcDecl= substitute(
       
  5368               substitute(
       
  5369                 substitute(funcDecl,"~ ","~"),
       
  5370                 ":: ","::"
       
  5371               ),
       
  5372               " ::","::"
       
  5373             ).stripWhiteSpace();
       
  5374   
       
  5375   //printf("funcDecl=`%s'\n",funcDecl.data());
       
  5376   if (isFriend && funcDecl.left(6)=="class ")
       
  5377   {
       
  5378     //printf("friend class\n");
       
  5379     funcDecl=funcDecl.right(funcDecl.length()-6);
       
  5380     funcName = funcDecl.copy();
       
  5381   }
       
  5382   else if (isFriend && funcDecl.left(7)=="struct ")
       
  5383   {
       
  5384     funcDecl=funcDecl.right(funcDecl.length()-7);
       
  5385     funcName = funcDecl.copy();
       
  5386   }
       
  5387   else
       
  5388   {
       
  5389     // extract information from the declarations
       
  5390     parseFuncDecl(funcDecl,root->objc,scopeName,funcType,funcName,
       
  5391                 funcArgs,funcTempList,exceptions
       
  5392                );
       
  5393   }
       
  5394   //printf("scopeName=`%s' funcType=`%s' funcName=`%s' funcArgs=`%s'\n",
       
  5395   //    scopeName.data(),funcType.data(),funcName.data(),funcArgs.data());
       
  5396 
       
  5397   // the class name can also be a namespace name, we decide this later.
       
  5398   // if a related class name is specified and the class name could
       
  5399   // not be derived from the function declaration, then use the
       
  5400   // related field.
       
  5401   //printf("scopeName=`%s' className=`%s' namespaceName=`%s'\n",
       
  5402   //    scopeName.data(),className.data(),namespaceName.data());
       
  5403   if (!root->relates.isEmpty()) 
       
  5404   {                             // related member, prefix user specified scope
       
  5405     isRelated=TRUE;
       
  5406     isMemberOf=(root->relatesType == MemberOf);
       
  5407     if (getClass(root->relates)==0 && !scopeName.isEmpty())
       
  5408     {
       
  5409       scopeName= mergeScopes(scopeName,root->relates);
       
  5410     }
       
  5411     else 
       
  5412     {
       
  5413       scopeName = root->relates;
       
  5414     }
       
  5415   }
       
  5416 
       
  5417   if (root->relates.isEmpty() && rootNav->parent() && 
       
  5418       ((rootNav->parent()->section()&Entry::SCOPE_MASK) ||
       
  5419        (rootNav->parent()->section()==Entry::OBJCIMPL_SEC)
       
  5420       ) &&
       
  5421       !rootNav->parent()->name().isEmpty()) // see if we can combine scopeName 
       
  5422                                      // with the scope in which it was found
       
  5423   {
       
  5424     QCString joinedName = rootNav->parent()->name()+"::"+scopeName;
       
  5425     if (!scopeName.isEmpty() && 
       
  5426         (getClass(joinedName) || Doxygen::namespaceSDict->find(joinedName)))
       
  5427     {
       
  5428       scopeName = joinedName;
       
  5429     }
       
  5430     else
       
  5431     {
       
  5432       scopeName = mergeScopes(rootNav->parent()->name(),scopeName);
       
  5433     }
       
  5434   }
       
  5435   else // see if we can prefix a namespace or class that is used from the file
       
  5436   {
       
  5437      FileDef *fd=rootNav->fileDef();
       
  5438      if (fd)
       
  5439      {
       
  5440        NamespaceSDict *fnl = fd->getUsedNamespaces();
       
  5441        if (fnl)
       
  5442        {
       
  5443          QCString joinedName;
       
  5444          NamespaceDef *fnd;
       
  5445          NamespaceSDict::Iterator nsdi(*fnl);
       
  5446          for (nsdi.toFirst();(fnd=nsdi.current());++nsdi)
       
  5447          {
       
  5448            joinedName = fnd->name()+"::"+scopeName;
       
  5449            if (Doxygen::namespaceSDict->find(joinedName))
       
  5450            {
       
  5451              scopeName=joinedName;
       
  5452              break;
       
  5453            }
       
  5454          }
       
  5455        }
       
  5456      }
       
  5457   }
       
  5458   scopeName=stripTemplateSpecifiersFromScope(
       
  5459       removeRedundantWhiteSpace(scopeName),FALSE,&funcSpec); 
       
  5460 
       
  5461   // funcSpec contains the last template specifiers of the given scope.
       
  5462   // If this method does not have any template arguments or they are 
       
  5463   // empty while funcSpec is not empty we assume this is a 
       
  5464   // specialization of a method. If not, we clear the funcSpec and treat
       
  5465   // this as a normal method of a template class.
       
  5466   if (!(root->tArgLists && 
       
  5467         root->tArgLists->count()>0 &&
       
  5468         root->tArgLists->first()->count()==0
       
  5469        )
       
  5470      ) 
       
  5471   {
       
  5472     funcSpec.resize(0);
       
  5473   }
       
  5474   
       
  5475   // split scope into a namespace and a class part
       
  5476   extractNamespaceName(scopeName,className,namespaceName,TRUE);
       
  5477   //printf("scopeName=`%s' className=`%s' namespaceName=`%s'\n",
       
  5478   //       scopeName.data(),className.data(),namespaceName.data());
       
  5479   
       
  5480   //namespaceName=removeAnonymousScopes(namespaceName);
       
  5481   if (namespaceName.find('@')!=-1) return; // skip stuff in anonymous namespace...
       
  5482 
       
  5483   //printf("namespaceName=`%s' className=`%s'\n",namespaceName.data(),className.data());
       
  5484   // merge class and namespace scopes again
       
  5485   scopeName.resize(0);
       
  5486   if (!namespaceName.isEmpty())
       
  5487   {
       
  5488     if (className.isEmpty())
       
  5489     {
       
  5490       scopeName=namespaceName;
       
  5491     }
       
  5492     else if (!root->relates.isEmpty() || // relates command with explicit scope
       
  5493              !getClass(className)) // class name only exists in a namespace
       
  5494     {
       
  5495       scopeName=namespaceName+"::"+className;
       
  5496     }
       
  5497     else
       
  5498     {
       
  5499       scopeName=className;
       
  5500     }
       
  5501   }
       
  5502   else if (!className.isEmpty())
       
  5503   {
       
  5504     scopeName=className;
       
  5505   }
       
  5506   //printf("new scope=`%s'\n",scopeName.data());
       
  5507 
       
  5508   QCString tempScopeName=scopeName;
       
  5509   ClassDef *cd=getClass(scopeName);
       
  5510   if (cd)
       
  5511   {
       
  5512     if (root->tArgLists) root->tArgLists->first();
       
  5513     if (funcSpec.isEmpty())
       
  5514     {
       
  5515       tempScopeName=cd->qualifiedNameWithTemplateParameters(root->tArgLists);
       
  5516     }
       
  5517     else
       
  5518     {
       
  5519       tempScopeName=scopeName+funcSpec;
       
  5520     }
       
  5521   }
       
  5522   //printf("scopeName=%s cd=%p root->tArgLists=%p result=%s\n",
       
  5523   //    scopeName.data(),cd,root->tArgLists,tempScopeName.data());
       
  5524   
       
  5525   //printf("scopeName=`%s' className=`%s'\n",scopeName.data(),className.data());
       
  5526   // rebuild the function declaration (needed to get the scope right).
       
  5527   if (!scopeName.isEmpty() && !isRelated && !isFriend && !Config_getBool("HIDE_SCOPE_NAMES"))
       
  5528   {
       
  5529     if (!funcType.isEmpty())
       
  5530     {
       
  5531       if (isFunc) // a function -> we use argList for the arguments
       
  5532       {
       
  5533         funcDecl=funcType+" "+tempScopeName+"::"+funcName+funcTempList;
       
  5534       }
       
  5535       else
       
  5536       {
       
  5537         funcDecl=funcType+" "+tempScopeName+"::"+funcName+funcArgs;
       
  5538       }
       
  5539     }
       
  5540     else
       
  5541     {
       
  5542       if (isFunc) // a function => we use argList for the arguments
       
  5543       {
       
  5544         funcDecl=tempScopeName+"::"+funcName+funcTempList;
       
  5545       }
       
  5546       else // variable => add `argument' list
       
  5547       {
       
  5548         funcDecl=tempScopeName+"::"+funcName+funcArgs;
       
  5549       }
       
  5550     }
       
  5551   }
       
  5552   else // build declaration without scope
       
  5553   {
       
  5554     if (!funcType.isEmpty()) // but with a type
       
  5555     {
       
  5556       if (isFunc) // function => omit argument list
       
  5557       {
       
  5558         funcDecl=funcType+" "+funcName+funcTempList;
       
  5559       }
       
  5560       else // variable => add `argument' list
       
  5561       {
       
  5562         funcDecl=funcType+" "+funcName+funcArgs;
       
  5563       }
       
  5564     }
       
  5565     else // no type
       
  5566     {
       
  5567       if (isFunc)
       
  5568       {
       
  5569         funcDecl=funcName+funcTempList;
       
  5570       }
       
  5571       else
       
  5572       {
       
  5573         funcDecl=funcName+funcArgs;
       
  5574       }
       
  5575     }
       
  5576   }
       
  5577   
       
  5578   if (funcType=="template class" && !funcTempList.isEmpty())
       
  5579     return;   // ignore explicit template instantiations
       
  5580   
       
  5581   Debug::print(Debug::FindMembers,0,
       
  5582            "findMember() Parse results:\n"
       
  5583            "  namespaceName=`%s'\n"
       
  5584            "  className=`%s`\n"
       
  5585            "  funcType=`%s'\n"
       
  5586            "  funcSpec=`%s'\n"
       
  5587            "  funcName=`%s'\n"
       
  5588            "  funcArgs=`%s'\n"
       
  5589            "  funcTempList=`%s'\n"
       
  5590            "  funcDecl=`%s'\n"
       
  5591            "  related=`%s'\n" 
       
  5592            "  exceptions=`%s'\n"
       
  5593            "  isRelated=%d\n"
       
  5594            "  isMemberOf=%d\n"
       
  5595            "  isFriend=%d\n"
       
  5596            "  isFunc=%d\n\n",
       
  5597            namespaceName.data(),className.data(),
       
  5598            funcType.data(),funcSpec.data(),funcName.data(),funcArgs.data(),funcTempList.data(),
       
  5599            funcDecl.data(),root->relates.data(),exceptions.data(),isRelated,isMemberOf,isFriend,
       
  5600            isFunc
       
  5601           );
       
  5602 
       
  5603   MemberName *mn=0;
       
  5604   if (!funcName.isEmpty()) // function name is valid
       
  5605   { 
       
  5606     Debug::print(Debug::FindMembers,0,
       
  5607                  "1. funcName=`%s'\n",funcName.data());
       
  5608     if (funcName.left(9)=="operator ") // strip class scope from cast operator
       
  5609     {
       
  5610       funcName = substitute(funcName,className+"::","");
       
  5611     }
       
  5612     if (!funcTempList.isEmpty()) // try with member specialization
       
  5613     {
       
  5614       mn=Doxygen::memberNameSDict->find(funcName+funcTempList);
       
  5615     }
       
  5616     if (mn==0) // try without specialization
       
  5617     {
       
  5618       mn=Doxygen::memberNameSDict->find(funcName);
       
  5619     }
       
  5620     if (!isRelated && mn) // function name already found
       
  5621     {
       
  5622       Debug::print(Debug::FindMembers,0,
       
  5623                    "2. member name exists (%d members with this name)\n",mn->count());
       
  5624       if (!className.isEmpty()) // class name is valid
       
  5625       {
       
  5626         if (funcSpec.isEmpty()) // not a member specialization
       
  5627         {
       
  5628           int count=0;
       
  5629           int noMatchCount=0;
       
  5630           MemberNameIterator mni(*mn);
       
  5631           MemberDef *md;
       
  5632           bool memFound=FALSE;
       
  5633           for (mni.toFirst();!memFound && (md=mni.current());++mni)
       
  5634           {
       
  5635             ClassDef *cd=md->getClassDef();
       
  5636             Debug::print(Debug::FindMembers,0,
       
  5637                 "3. member definition found, "
       
  5638                 "scope needed=`%s' scope=`%s' args=`%s' fileName=%s\n",
       
  5639                 scopeName.data(),cd ? cd->name().data() : "<none>",
       
  5640                 md->argsString(),
       
  5641                 root->fileName.data());
       
  5642             //printf("Member %s (member scopeName=%s) (this scopeName=%s) classTempList=%s\n",md->name().data(),cd->name().data(),scopeName.data(),classTempList.data());
       
  5643             FileDef *fd=rootNav->fileDef();
       
  5644             NamespaceDef *nd=0;
       
  5645             if (!namespaceName.isEmpty()) nd=getResolvedNamespace(namespaceName);
       
  5646 
       
  5647             //printf("scopeName %s->%s\n",scopeName.data(),
       
  5648             //       stripTemplateSpecifiersFromScope(scopeName,FALSE).data());
       
  5649 
       
  5650             ClassDef *tcd=findClassDefinition(fd,nd,scopeName);
       
  5651             if (tcd==0 && stripAnonymousNamespaceScope(cd->name())==scopeName)
       
  5652             {
       
  5653               // don't be fooled by anonymous scopes
       
  5654               tcd=cd;
       
  5655             }
       
  5656             //printf("Looking for %s inside nd=%s result=%p (%s) cd=%p\n",
       
  5657             //    scopeName.data(),nd?nd->name().data():"<none>",tcd,tcd?tcd->name().data():"",cd);
       
  5658 
       
  5659             if (cd && tcd==cd) // member's classes match
       
  5660             {
       
  5661               Debug::print(Debug::FindMembers,0,
       
  5662                   "4. class definition %s found\n",cd->name().data());
       
  5663 
       
  5664               // get the template parameter lists found at the member declaration
       
  5665               QList<ArgumentList> declTemplArgs;
       
  5666               cd->getTemplateParameterLists(declTemplArgs);
       
  5667               LockingPtr<ArgumentList> templAl = md->templateArguments();
       
  5668               if (templAl!=0)
       
  5669               {
       
  5670                 declTemplArgs.append(templAl.pointer());
       
  5671               }
       
  5672 
       
  5673               // get the template parameter lists found at the member definition
       
  5674               QList<ArgumentList> *defTemplArgs = root->tArgLists;
       
  5675               //printf("defTemplArgs=%p\n",defTemplArgs);
       
  5676 
       
  5677               // do we replace the decl argument lists with the def argument lists?
       
  5678               bool substDone=FALSE;
       
  5679               ArgumentList *argList=0;
       
  5680 
       
  5681               /* substitute the occurrences of class template names in the 
       
  5682                * argument list before matching 
       
  5683                */
       
  5684               LockingPtr<ArgumentList> mdAl = md->argumentList();
       
  5685               if (declTemplArgs.count()>0 && defTemplArgs &&
       
  5686                   declTemplArgs.count()==defTemplArgs->count() &&
       
  5687                   mdAl.pointer()
       
  5688                  )
       
  5689               {
       
  5690                 /* the function definition has template arguments
       
  5691                  * and the class definition also has template arguments, so
       
  5692                  * we must substitute the template names of the class by that
       
  5693                  * of the function definition before matching.
       
  5694                  */
       
  5695                 argList = new ArgumentList;
       
  5696                 substituteTemplatesInArgList(declTemplArgs,*defTemplArgs,
       
  5697                     mdAl.pointer(),argList);
       
  5698 
       
  5699                 substDone=TRUE;
       
  5700               }
       
  5701               else /* no template arguments, compare argument lists directly */
       
  5702               {
       
  5703                 argList = mdAl.pointer();
       
  5704               }
       
  5705 
       
  5706               Debug::print(Debug::FindMembers,0,
       
  5707                   "5. matching `%s'<=>`%s' className=%s namespaceName=%s\n",
       
  5708                   argListToString(argList,TRUE).data(),argListToString(root->argList,TRUE).data(),
       
  5709                   className.data(),namespaceName.data()
       
  5710                   );
       
  5711 
       
  5712               bool matching=
       
  5713                 md->isVariable() || md->isTypedef() || // needed for function pointers
       
  5714                 (mdAl.pointer()==0 && root->argList->count()==0) || 
       
  5715                 matchArguments2(
       
  5716                     md->getClassDef(),md->getFileDef(),argList, 
       
  5717                     cd,fd,root->argList,
       
  5718                     TRUE);
       
  5719 
       
  5720               Debug::print(Debug::FindMembers,0,
       
  5721                   "6. match results of matchArguments2 = %d\n",matching);
       
  5722 
       
  5723               if (substDone) // found a new argument list
       
  5724               {
       
  5725                 if (matching) // replace member's argument list
       
  5726                 {
       
  5727                   md->setDefinitionTemplateParameterLists(root->tArgLists);
       
  5728                   md->setArgumentList(argList); // new owner of the list => no delete
       
  5729                 }
       
  5730                 else // no match 
       
  5731                 {
       
  5732                   if (!funcTempList.isEmpty() && 
       
  5733                       isSpecialization(declTemplArgs,*defTemplArgs))
       
  5734                   {
       
  5735                     // check if we are dealing with a partial template
       
  5736                     // specialization. In this case we add it to the class
       
  5737                     // even though the member arguments do not match.
       
  5738                     
       
  5739                     // TODO: copy other aspects?
       
  5740                     root->protection=md->protection(); // copy protection level
       
  5741                     addMethodToClass(rootNav,cd,md->name(),isFriend);
       
  5742                     return;
       
  5743                   }
       
  5744                   delete argList;
       
  5745                 }
       
  5746               }
       
  5747               if (matching) 
       
  5748               {
       
  5749                 addMemberDocs(rootNav,md,funcDecl,0,overloaded,0/* TODO */);
       
  5750                 count++;
       
  5751                 memFound=TRUE;
       
  5752               }
       
  5753             } 
       
  5754             else if (cd && cd!=tcd) // we did find a class with the same name as cd
       
  5755                                     // but in a different namespace
       
  5756             {
       
  5757               noMatchCount++;
       
  5758             }
       
  5759           } 
       
  5760           if (count==0 && rootNav->parent() && 
       
  5761               rootNav->parent()->section()==Entry::OBJCIMPL_SEC)
       
  5762           {
       
  5763             goto localObjCMethod;
       
  5764           }
       
  5765           if (count==0 && !(isFriend && funcType=="class"))
       
  5766           {
       
  5767             int candidates=0;
       
  5768             if (mn->count()>0)
       
  5769             {
       
  5770               //printf("Assume template class\n");
       
  5771               for (mni.toFirst();(md=mni.current());++mni)
       
  5772               {
       
  5773                 ClassDef *cd=md->getClassDef();
       
  5774                 //printf("cd->name()==%s className=%s\n",cd->name().data(),className.data());
       
  5775                 if (cd!=0 && rightScopeMatch(cd->name(),className)) 
       
  5776                 {
       
  5777                   LockingPtr<ArgumentList> templAl = md->templateArguments();
       
  5778                   if (root->tArgLists && templAl!=0 &&
       
  5779                       root->tArgLists->getLast()->count()<=templAl->count())
       
  5780                   { 
       
  5781                     addMethodToClass(rootNav,cd,md->name(),isFriend);
       
  5782                     return;
       
  5783                   }
       
  5784                   candidates++;
       
  5785                 }
       
  5786               }
       
  5787             }
       
  5788 
       
  5789             warn(root->fileName,root->startLine,
       
  5790                 "Warning: no %smatching class member found for",
       
  5791                 noMatchCount>1 ? "uniquely " : ""
       
  5792                 );   
       
  5793 
       
  5794             if (root->tArgLists)
       
  5795             {
       
  5796               QListIterator<ArgumentList> alli(*root->tArgLists);
       
  5797               ArgumentList *al;
       
  5798               for (;(al=alli.current());++alli)
       
  5799               {
       
  5800                 warn_cont("  template %s\n",tempArgListToString(al).data());
       
  5801               }
       
  5802             }
       
  5803             QCString fullFuncDecl=funcDecl.copy();
       
  5804             if (isFunc) fullFuncDecl+=argListToString(root->argList,TRUE);
       
  5805 
       
  5806             warn_cont("  %s\n",fullFuncDecl.data());
       
  5807 
       
  5808             if (candidates>0)
       
  5809             {
       
  5810               warn_cont("Possible candidates:\n");
       
  5811               for (mni.toFirst();(md=mni.current());++mni)
       
  5812               {
       
  5813                 ClassDef *cd=md->getClassDef();
       
  5814                 if (cd!=0 && rightScopeMatch(cd->name(),className))
       
  5815                 {
       
  5816                   LockingPtr<ArgumentList> templAl = md->templateArguments();
       
  5817                   if (templAl!=0)
       
  5818                   {
       
  5819                     warn_cont("  template %s\n",tempArgListToString(templAl.pointer()).data());
       
  5820                   }
       
  5821                   warn_cont("  ");
       
  5822                   if (md->typeString()) 
       
  5823                   {
       
  5824                     warn_cont("%s ",md->typeString());
       
  5825                   }
       
  5826                   QCString qScope = cd->qualifiedNameWithTemplateParameters();
       
  5827                   if (!qScope.isEmpty()) warn_cont("%s::%s",qScope.data(),md->name().data());
       
  5828                   if (md->argsString()) warn_cont("%s",md->argsString());
       
  5829                   if (noMatchCount>1) warn_cont(" at line %d of file %s",md->getDefLine(),md->getDefFileName().data());
       
  5830                   warn_cont("\n");
       
  5831                 }
       
  5832               }
       
  5833             }
       
  5834           }
       
  5835         }
       
  5836         else if (cd) // member specialization
       
  5837         {
       
  5838           MemberDef::MemberType mtype=MemberDef::Function;
       
  5839           ArgumentList *tArgList = new ArgumentList;
       
  5840           //  getTemplateArgumentsFromName(cd->name()+"::"+funcName,root->tArgLists);
       
  5841           MemberDef *md=new MemberDef(
       
  5842               root->fileName,root->startLine,
       
  5843               funcType,funcName,funcArgs,exceptions,
       
  5844               root->protection,root->virt,root->stat,Member,
       
  5845               mtype,tArgList,root->argList);
       
  5846           //printf("new specialized member %s args=`%s'\n",md->name().data(),funcArgs.data());
       
  5847           md->setTagInfo(rootNav->tagInfo());
       
  5848           md->setMemberClass(cd);
       
  5849           md->setTemplateSpecialization(TRUE);
       
  5850           md->setTypeConstraints(root->typeConstr);
       
  5851           md->setDefinition(funcDecl);
       
  5852           md->enableCallGraph(root->callGraph);
       
  5853           md->enableCallerGraph(root->callerGraph);
       
  5854           md->setDocumentation(root->doc,root->docFile,root->docLine);
       
  5855           md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
       
  5856           md->setDocsForDefinition(!root->proto);
       
  5857           md->setPrototype(root->proto);
       
  5858           md->addSectionsToDefinition(root->anchors);
       
  5859           md->setBodySegment(root->bodyLine,root->endBodyLine);
       
  5860           FileDef *fd=rootNav->fileDef();
       
  5861           md->setBodyDef(fd);
       
  5862           md->setMemberSpecifiers(root->spec);
       
  5863           md->setMemberGroupId(root->mGrpId);
       
  5864           mn->append(md);
       
  5865           cd->insertMember(md);
       
  5866           md->setRefItems(root->sli);
       
  5867           delete tArgList;
       
  5868         }
       
  5869         else
       
  5870         {
       
  5871           //printf("*** Specialized member %s of unknown scope %s%s found!\n",
       
  5872           //        scopeName.data(),funcName.data(),funcArgs.data());
       
  5873         }
       
  5874       }
       
  5875       else if (overloaded) // check if the function belongs to only one class 
       
  5876       {
       
  5877         // for unique overloaded member we allow the class to be
       
  5878         // omitted, this is to be Qt compatable. Using this should 
       
  5879         // however be avoided, because it is error prone
       
  5880         MemberNameIterator mni(*mn);
       
  5881         MemberDef *md=mni.toFirst();
       
  5882         ASSERT(md);
       
  5883         ClassDef *cd=md->getClassDef();
       
  5884         ASSERT(cd);
       
  5885         QCString className=cd->name().copy();
       
  5886         ++mni;
       
  5887         bool unique=TRUE;
       
  5888         for (;(md=mni.current());++mni)
       
  5889         {
       
  5890           ClassDef *cd=md->getClassDef();
       
  5891           if (className!=cd->name()) unique=FALSE; 
       
  5892         } 
       
  5893         if (unique)
       
  5894         {
       
  5895           MemberDef::MemberType mtype;
       
  5896           if      (root->mtype==Signal)  mtype=MemberDef::Signal;
       
  5897           else if (root->mtype==Slot)    mtype=MemberDef::Slot;
       
  5898           else if (root->mtype==DCOP)    mtype=MemberDef::DCOP;
       
  5899           else                 mtype=MemberDef::Function;
       
  5900           
       
  5901           // new overloaded member function
       
  5902           ArgumentList *tArgList = 
       
  5903             getTemplateArgumentsFromName(cd->name()+"::"+funcName,root->tArgLists);
       
  5904           //printf("new related member %s args=`%s'\n",md->name().data(),funcArgs.data());
       
  5905           MemberDef *md=new MemberDef(
       
  5906               root->fileName,root->startLine,
       
  5907               funcType,funcName,funcArgs,exceptions,
       
  5908               root->protection,root->virt,root->stat,Related,
       
  5909               mtype,tArgList,root->argList);
       
  5910           md->setTagInfo(rootNav->tagInfo());
       
  5911           md->setTypeConstraints(root->typeConstr);
       
  5912           md->setMemberClass(cd);
       
  5913           md->setDefinition(funcDecl);
       
  5914           md->enableCallGraph(root->callGraph);
       
  5915           md->enableCallerGraph(root->callerGraph);
       
  5916           QCString doc=getOverloadDocs();
       
  5917           doc+="<p>";
       
  5918           doc+=root->doc;
       
  5919           md->setDocumentation(doc,root->docFile,root->docLine);
       
  5920           md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
       
  5921           md->setDocsForDefinition(!root->proto);
       
  5922           md->setPrototype(root->proto);
       
  5923           md->addSectionsToDefinition(root->anchors);
       
  5924           md->setBodySegment(root->bodyLine,root->endBodyLine);
       
  5925           FileDef *fd=rootNav->fileDef();
       
  5926           md->setBodyDef(fd);
       
  5927           md->setMemberSpecifiers(root->spec);
       
  5928           md->setMemberGroupId(root->mGrpId);
       
  5929           mn->append(md);
       
  5930           cd->insertMember(md);
       
  5931           cd->insertUsedFile(root->fileName);
       
  5932           md->setRefItems(root->sli);
       
  5933         }
       
  5934       }
       
  5935       else // unrelated function with the same name as a member
       
  5936       {
       
  5937         if (!findGlobalMember(rootNav,namespaceName,funcName,funcTempList,funcArgs,funcDecl))
       
  5938         {
       
  5939           QCString fullFuncDecl=funcDecl.copy();
       
  5940           if (isFunc) fullFuncDecl+=argListToString(root->argList,TRUE);
       
  5941           warn(root->fileName,root->startLine,
       
  5942                "Warning: Cannot determine class for function\n%s",
       
  5943                fullFuncDecl.data()
       
  5944               );   
       
  5945         }
       
  5946       }
       
  5947     }
       
  5948     else if (isRelated && !root->relates.isEmpty())
       
  5949     {
       
  5950       Debug::print(Debug::FindMembers,0,"2. related function\n"
       
  5951               "  scopeName=%s className=%s\n",scopeName.data(),className.data());
       
  5952       if (className.isEmpty()) className=root->relates;
       
  5953       ClassDef *cd;
       
  5954       //printf("scopeName=`%s' className=`%s'\n",scopeName.data(),className.data());
       
  5955       if ((cd=getClass(scopeName)))
       
  5956       {
       
  5957         bool newMember=TRUE; // assume we have a new member
       
  5958         bool newMemberName=FALSE; 
       
  5959         bool isDefine=FALSE;
       
  5960         {
       
  5961           MemberName *mn = Doxygen::functionNameSDict->find(funcName);
       
  5962           if (mn)
       
  5963           {
       
  5964             MemberDef *md = mn->first();
       
  5965             while (md && !isDefine)
       
  5966             {
       
  5967               isDefine = isDefine || md->isDefine();
       
  5968               md = mn->next();
       
  5969             }
       
  5970           }
       
  5971         }
       
  5972 
       
  5973         FileDef *fd=rootNav->fileDef();
       
  5974 
       
  5975         if ((mn=Doxygen::memberNameSDict->find(funcName))==0)
       
  5976         {
       
  5977           mn=new MemberName(funcName);
       
  5978           newMemberName=TRUE; // we create a new member name
       
  5979         }
       
  5980         else
       
  5981         {
       
  5982           MemberDef *rmd=mn->first();
       
  5983           while (rmd && newMember) // see if we got another member with matching arguments
       
  5984           {
       
  5985             LockingPtr<ArgumentList> rmdAl = rmd->argumentList();
       
  5986 
       
  5987             newMember=newMember && 
       
  5988               !matchArguments2(rmd->getOuterScope(),rmd->getFileDef(),rmdAl.pointer(),
       
  5989                                cd,fd,root->argList,
       
  5990                                TRUE);
       
  5991             if (newMember) rmd=mn->next();
       
  5992           }
       
  5993           if (!newMember && rmd) // member already exists as rmd -> add docs
       
  5994           {
       
  5995             //printf("addMemberDocs for related member %s\n",root->name.data());
       
  5996             //rmd->setMemberDefTemplateArguments(root->mtArgList);
       
  5997             addMemberDocs(rootNav,rmd,funcDecl,0,overloaded);
       
  5998           }
       
  5999         }
       
  6000 
       
  6001         if (newMember) // need to create a new member
       
  6002         {
       
  6003           MemberDef::MemberType mtype;
       
  6004           if (isDefine)
       
  6005             mtype=MemberDef::Define;
       
  6006           else if (root->mtype==Signal)  
       
  6007             mtype=MemberDef::Signal;
       
  6008           else if (root->mtype==Slot) 
       
  6009             mtype=MemberDef::Slot;
       
  6010           else if (root->mtype==DCOP)
       
  6011             mtype=MemberDef::DCOP;
       
  6012           else
       
  6013             mtype=MemberDef::Function;
       
  6014 
       
  6015           //printf("New related name `%s' `%d'\n",funcName.data(),
       
  6016           //    root->argList ? (int)root->argList->count() : -1);
       
  6017 
       
  6018           // new related (member) function
       
  6019 #if 0 // removed as it doesn't handle related template functions correctly
       
  6020           ArgumentList *tArgList = 
       
  6021             getTemplateArgumentsFromName(scopeName+"::"+funcName,root->tArgLists);
       
  6022           MemberDef *md=new MemberDef(
       
  6023               root->fileName,root->startLine,
       
  6024               funcType,funcName,funcArgs,exceptions,
       
  6025               root->protection,root->virt,root->stat,TRUE,
       
  6026               mtype,tArgList,funcArgs.isEmpty() ? 0 : root->argList);
       
  6027 #endif
       
  6028           // first note that we pass:
       
  6029           //   (root->tArgLists ? root->tArgLists->last() : 0)
       
  6030           // for the template arguments fo the new "member."
       
  6031           // this accurately reflects the template arguments of
       
  6032           // the related function, which don't have to do with
       
  6033           // those of the related class.
       
  6034           MemberDef *md=new MemberDef(
       
  6035               root->fileName,root->startLine,
       
  6036               funcType,funcName,funcArgs,exceptions,
       
  6037               root->protection,root->virt,
       
  6038               root->stat && !isMemberOf,
       
  6039               isMemberOf ? Foreign : isRelated ? Related : Member,
       
  6040               mtype,
       
  6041               (root->tArgLists ? root->tArgLists->last() : 0),
       
  6042               funcArgs.isEmpty() ? 0 : root->argList);
       
  6043           // 
       
  6044           // we still have the problem that
       
  6045           // MemberDef::writeDocumentation() in memberdef.cpp
       
  6046           // writes the template argument list for the class,
       
  6047           // as if this member is a member of the class.
       
  6048           // fortunately, MemberDef::writeDocumentation() has
       
  6049           // a special mechanism that allows us to totally
       
  6050           // override the set of template argument lists that
       
  6051           // are printed.  We use that and set it to the
       
  6052           // template argument lists of the related function.
       
  6053           //
       
  6054           md->setDefinitionTemplateParameterLists(root->tArgLists);
       
  6055 
       
  6056           md->setTagInfo(rootNav->tagInfo());
       
  6057 
       
  6058 
       
  6059 
       
  6060           //printf("Related member name=`%s' decl=`%s' bodyLine=`%d'\n",
       
  6061           //       funcName.data(),funcDecl.data(),root->bodyLine);
       
  6062 
       
  6063           // try to find the matching line number of the body from the
       
  6064           // global function list 
       
  6065           bool found=FALSE;
       
  6066           if (root->bodyLine==-1)
       
  6067           {
       
  6068             MemberName *rmn=Doxygen::functionNameSDict->find(funcName);
       
  6069             if (rmn)
       
  6070             {
       
  6071               MemberDef *rmd=rmn->first();
       
  6072               while (rmd && !found) // see if we got another member with matching arguments
       
  6073               {
       
  6074                 LockingPtr<ArgumentList> rmdAl = rmd->argumentList();
       
  6075                 // check for matching argument lists
       
  6076                 if (
       
  6077                     matchArguments2(rmd->getOuterScope(),rmd->getFileDef(),rmdAl.pointer(),
       
  6078                                     cd,fd,root->argList,
       
  6079                                     TRUE)
       
  6080                    )
       
  6081                 {
       
  6082                   found=TRUE;
       
  6083                 }
       
  6084                 if (!found) rmd=rmn->next();
       
  6085               }
       
  6086               if (rmd) // member found -> copy line number info
       
  6087               {
       
  6088                 md->setBodySegment(rmd->getStartBodyLine(),rmd->getEndBodyLine());
       
  6089                 md->setBodyDef(rmd->getBodyDef());
       
  6090                 //md->setBodyMember(rmd);
       
  6091               }
       
  6092             }
       
  6093           }
       
  6094           if (!found) // line number could not be found or is available in this
       
  6095                       // entry
       
  6096           {
       
  6097             md->setBodySegment(root->bodyLine,root->endBodyLine);
       
  6098             md->setBodyDef(fd);
       
  6099           }
       
  6100 
       
  6101           //if (root->mGrpId!=-1) 
       
  6102           //{
       
  6103           //  md->setMemberGroup(memberGroupDict[root->mGrpId]);
       
  6104           //}
       
  6105           md->setMemberClass(cd);
       
  6106           md->setMemberSpecifiers(root->spec);
       
  6107           md->setDefinition(funcDecl);
       
  6108           md->enableCallGraph(root->callGraph);
       
  6109           md->enableCallerGraph(root->callerGraph);
       
  6110           md->setDocumentation(root->doc,root->docFile,root->docLine);
       
  6111           md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
       
  6112           md->setDocsForDefinition(!root->proto);
       
  6113           md->setPrototype(root->proto);
       
  6114           md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
       
  6115           md->addSectionsToDefinition(root->anchors);
       
  6116           md->setMemberGroupId(root->mGrpId);
       
  6117           //md->setMemberDefTemplateArguments(root->mtArgList);
       
  6118           mn->append(md);
       
  6119           cd->insertMember(md);
       
  6120           cd->insertUsedFile(root->fileName);
       
  6121           md->setRefItems(root->sli);
       
  6122           if (root->relatesType == Duplicate) md->setRelatedAlso(cd);
       
  6123           addMemberToGroups(root,md);
       
  6124           //printf("Adding member=%s\n",md->name().data());
       
  6125           if (newMemberName)
       
  6126           {
       
  6127             //Doxygen::memberNameList.append(mn);
       
  6128             //Doxygen::memberNameDict.insert(funcName,mn);
       
  6129             Doxygen::memberNameSDict->append(funcName,mn);
       
  6130           }
       
  6131         }
       
  6132         if (root->relatesType == Duplicate)
       
  6133         {
       
  6134           if (!findGlobalMember(rootNav,namespaceName,funcName,funcTempList,funcArgs,funcDecl))
       
  6135           {
       
  6136             QCString fullFuncDecl=funcDecl.copy();
       
  6137             if (isFunc) fullFuncDecl+=argListToString(root->argList,TRUE);
       
  6138             warn(root->fileName,root->startLine,
       
  6139                "Warning: Cannot determine file/namespace for relatedalso function\n%s",
       
  6140                fullFuncDecl.data()
       
  6141               );   
       
  6142           }
       
  6143         }
       
  6144       }
       
  6145       else
       
  6146       {
       
  6147         warn_undoc(root->fileName,root->startLine,
       
  6148                    "Warning: class `%s' for related function `%s' is not "
       
  6149                    "documented.", 
       
  6150                    className.data(),funcName.data()
       
  6151                   );
       
  6152       }
       
  6153     }
       
  6154     else if (rootNav->parent() && rootNav->parent()->section()==Entry::OBJCIMPL_SEC)
       
  6155     {
       
  6156 localObjCMethod:
       
  6157       ClassDef *cd;
       
  6158       //printf("scopeName=`%s' className=`%s'\n",scopeName.data(),className.data());
       
  6159       if (Config_getBool("EXTRACT_LOCAL_METHODS") && (cd=getClass(scopeName)))
       
  6160       {
       
  6161         //printf("Local objective C method `%s' of class `%s' found\n",root->name.data(),cd->name().data());
       
  6162         MemberDef *md=new MemberDef(
       
  6163             root->fileName,root->startLine,
       
  6164             funcType,funcName,funcArgs,exceptions,
       
  6165             root->protection,root->virt,root->stat,Member,
       
  6166             MemberDef::Function,0,root->argList);
       
  6167         md->setTagInfo(rootNav->tagInfo());
       
  6168         md->makeImplementationDetail();
       
  6169         md->setMemberClass(cd);
       
  6170         md->setDefinition(funcDecl);
       
  6171         md->enableCallGraph(root->callGraph);
       
  6172         md->enableCallerGraph(root->callerGraph);
       
  6173         md->setDocumentation(root->doc,root->docFile,root->docLine);
       
  6174         md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
       
  6175         md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
       
  6176         md->setDocsForDefinition(!root->proto);
       
  6177         md->setPrototype(root->proto);
       
  6178         md->addSectionsToDefinition(root->anchors);
       
  6179         md->setBodySegment(root->bodyLine,root->endBodyLine);
       
  6180         FileDef *fd=rootNav->fileDef();
       
  6181         md->setBodyDef(fd);
       
  6182         md->setMemberSpecifiers(root->spec);
       
  6183         md->setMemberGroupId(root->mGrpId);
       
  6184         cd->insertMember(md);
       
  6185         cd->insertUsedFile(root->fileName);
       
  6186         md->setRefItems(root->sli);
       
  6187         if ((mn=Doxygen::memberNameSDict->find(root->name)))
       
  6188         {
       
  6189           mn->append(md);
       
  6190         }
       
  6191         else 
       
  6192         {
       
  6193           mn = new MemberName(root->name);
       
  6194           mn->append(md);
       
  6195           Doxygen::memberNameSDict->append(root->name,mn);
       
  6196         }
       
  6197       }
       
  6198       else
       
  6199       {
       
  6200         // local objective C method found for class without interface
       
  6201       }
       
  6202     }
       
  6203     else // unrelated not overloaded member found
       
  6204     {
       
  6205       bool globMem = findGlobalMember(rootNav,namespaceName,funcName,funcTempList,funcArgs,funcDecl);
       
  6206       if (className.isEmpty() && !globMem)
       
  6207       {
       
  6208         warn(root->fileName,root->startLine,
       
  6209              "Warning: class for member `%s' cannot "
       
  6210              "be found.", funcName.data()
       
  6211             ); 
       
  6212       }
       
  6213       else if (!className.isEmpty() && !globMem)
       
  6214       {
       
  6215         warn(root->fileName,root->startLine,
       
  6216              "Warning: member `%s' of class `%s' cannot be found",
       
  6217              funcName.data(),className.data());
       
  6218       }
       
  6219     }
       
  6220   }
       
  6221   else
       
  6222   {
       
  6223     // this should not be called
       
  6224     warn(root->fileName,root->startLine,
       
  6225          "Warning: member with no name found.");
       
  6226   }
       
  6227   return;
       
  6228 } 
       
  6229 
       
  6230 //----------------------------------------------------------------------
       
  6231 // find the members corresponding to the different documentation blocks
       
  6232 // that are extracted from the sources.
       
  6233 
       
  6234 static void filterMemberDocumentation(EntryNav *rootNav)
       
  6235 {
       
  6236   Entry *root = rootNav->entry();
       
  6237   int i=-1,l;
       
  6238   Debug::print(Debug::FindMembers,0,
       
  6239       "findMemberDocumentation(): root->type=`%s' root->inside=`%s' root->name=`%s' root->args=`%s' section=%x root->spec=%d root->mGrpId=%d\n",
       
  6240       root->type.data(),root->inside.data(),root->name.data(),root->args.data(),root->section,root->spec,root->mGrpId
       
  6241       );
       
  6242   //printf("rootNav->parent()->name()=%s\n",rootNav->parent()->name().data());
       
  6243   bool isFunc=TRUE;
       
  6244 
       
  6245   if (root->relatesType == Duplicate && !root->relates.isEmpty())
       
  6246   {
       
  6247     QCString tmp = root->relates;
       
  6248     root->relates.resize(0);
       
  6249     filterMemberDocumentation(rootNav);
       
  6250     root->relates = tmp;
       
  6251   }
       
  6252 
       
  6253   if ( // detect func variable/typedef to func ptr
       
  6254       (i=findFunctionPtr(root->type,&l))!=-1 
       
  6255      )
       
  6256   {
       
  6257     //printf("Fixing function pointer!\n");
       
  6258     // fix type and argument
       
  6259     root->args.prepend(root->type.right(root->type.length()-i-l));
       
  6260     root->type=root->type.left(i+l);
       
  6261     //printf("Results type=%s,name=%s,args=%s\n",root->type.data(),root->name.data(),root->args.data());
       
  6262     isFunc=FALSE;
       
  6263   }
       
  6264   else if ((root->type.left(8)=="typedef " && root->args.find('(')!=-1)) 
       
  6265     // detect function types marked as functions
       
  6266   {
       
  6267     isFunc=FALSE;
       
  6268   }
       
  6269 
       
  6270   //printf("Member %s isFunc=%d\n",root->name.data(),isFunc);
       
  6271   if (root->section==Entry::MEMBERDOC_SEC)
       
  6272   {
       
  6273     //printf("Documentation for inline member `%s' found args=`%s'\n",
       
  6274     //    root->name.data(),root->args.data());
       
  6275     //if (root->relates.length()) printf("  Relates %s\n",root->relates.data());
       
  6276     if (root->type.isEmpty())
       
  6277     {
       
  6278       findMember(rootNav,root->name+root->args+root->exception,FALSE,isFunc);
       
  6279     }
       
  6280     else
       
  6281     {
       
  6282       findMember(rootNav,root->type+" "+root->name+root->args+root->exception,FALSE,isFunc);
       
  6283     }
       
  6284   }
       
  6285   else if (root->section==Entry::OVERLOADDOC_SEC) 
       
  6286   {
       
  6287     //printf("Overloaded member %s found\n",root->name.data());
       
  6288     findMember(rootNav,root->name,TRUE,isFunc);
       
  6289   }
       
  6290   else if 
       
  6291     ((root->section==Entry::FUNCTION_SEC      // function
       
  6292       ||   
       
  6293       (root->section==Entry::VARIABLE_SEC &&  // variable
       
  6294        !root->type.isEmpty() &&                // with a type
       
  6295        g_compoundKeywordDict.find(root->type)==0 // that is not a keyword 
       
  6296        // (to skip forward declaration of class etc.)
       
  6297       )
       
  6298      ) 
       
  6299     )
       
  6300     {
       
  6301       //printf("Documentation for member `%s' found args=`%s' excp=`%s'\n",
       
  6302       //    root->name.data(),root->args.data(),root->exception.data());
       
  6303       //if (root->relates.length()) printf("  Relates %s\n",root->relates.data());
       
  6304       //printf("Inside=%s\n Relates=%s\n",root->inside.data(),root->relates.data());
       
  6305       if (root->type=="friend class" || root->type=="friend struct" || 
       
  6306           root->type=="friend union")
       
  6307       {
       
  6308         findMember(rootNav,
       
  6309             root->type+" "+
       
  6310             root->name,
       
  6311             FALSE,FALSE);
       
  6312 
       
  6313       }
       
  6314       else if (!root->type.isEmpty())
       
  6315       {
       
  6316         findMember(rootNav,
       
  6317             root->type+" "+
       
  6318             root->inside+
       
  6319             root->name+
       
  6320             root->args+
       
  6321             root->exception,
       
  6322             FALSE,isFunc);
       
  6323       }
       
  6324       else
       
  6325       {
       
  6326         findMember(rootNav,
       
  6327             root->inside+
       
  6328             root->name+
       
  6329             root->args+
       
  6330             root->exception,
       
  6331             FALSE,isFunc);
       
  6332       }
       
  6333     }
       
  6334   else if (root->section==Entry::DEFINE_SEC && !root->relates.isEmpty())
       
  6335   {
       
  6336     findMember(rootNav,root->name+root->args,FALSE,!root->args.isEmpty());
       
  6337   }
       
  6338   else if (root->section==Entry::VARIABLEDOC_SEC)
       
  6339   {
       
  6340     //printf("Documentation for variable %s found\n",root->name.data());
       
  6341     //if (!root->relates.isEmpty()) printf("  Relates %s\n",root->relates.data());
       
  6342     findMember(rootNav,root->name,FALSE,FALSE);
       
  6343   }
       
  6344   else
       
  6345   {
       
  6346     // skip section 
       
  6347     //printf("skip section\n");
       
  6348   }
       
  6349 }
       
  6350 
       
  6351 static void findMemberDocumentation(EntryNav *rootNav)
       
  6352 {
       
  6353   if (rootNav->section()==Entry::MEMBERDOC_SEC ||
       
  6354       rootNav->section()==Entry::OVERLOADDOC_SEC ||
       
  6355       rootNav->section()==Entry::FUNCTION_SEC ||
       
  6356       rootNav->section()==Entry::VARIABLE_SEC ||
       
  6357       rootNav->section()==Entry::VARIABLEDOC_SEC ||
       
  6358       rootNav->section()==Entry::DEFINE_SEC
       
  6359      )
       
  6360   {
       
  6361     rootNav->loadEntry(g_storage);
       
  6362 
       
  6363     filterMemberDocumentation(rootNav);
       
  6364 
       
  6365     rootNav->releaseEntry();
       
  6366   }
       
  6367   if (rootNav->children())
       
  6368   {
       
  6369     EntryNavListIterator eli(*rootNav->children());
       
  6370     EntryNav *e;
       
  6371     for (;(e=eli.current());++eli)
       
  6372     {
       
  6373       if (e->section()!=Entry::ENUM_SEC) findMemberDocumentation(e);
       
  6374     }
       
  6375   }
       
  6376 }
       
  6377 
       
  6378 //----------------------------------------------------------------------
       
  6379 
       
  6380 static void findObjCMethodDefinitions(EntryNav *rootNav)
       
  6381 {
       
  6382   if (rootNav->children())
       
  6383   {
       
  6384     EntryNavListIterator eli(*rootNav->children());
       
  6385     EntryNav *objCImplNav;
       
  6386     for (;(objCImplNav=eli.current());++eli)
       
  6387     {
       
  6388       if (objCImplNav->section()==Entry::OBJCIMPL_SEC && objCImplNav->children())
       
  6389       {
       
  6390         EntryNavListIterator seli(*objCImplNav->children());
       
  6391         EntryNav *objCMethodNav;
       
  6392         for (;(objCMethodNav=seli.current());++seli)
       
  6393         {
       
  6394           if (objCMethodNav->section()==Entry::FUNCTION_SEC)
       
  6395           {
       
  6396             objCMethodNav->loadEntry(g_storage);
       
  6397             Entry *objCMethod = objCMethodNav->entry();
       
  6398 
       
  6399             //Printf("  Found ObjC method definition %s\n",objCMethod->name.data());
       
  6400             findMember(objCMethodNav, objCMethod->type+" "+objCImplNav->name()+"::"+
       
  6401                        objCMethod->name+" "+objCMethod->args, FALSE,TRUE);
       
  6402             objCMethod->section=Entry::EMPTY_SEC;
       
  6403 
       
  6404             objCMethodNav->releaseEntry();
       
  6405           }
       
  6406         }
       
  6407       }
       
  6408     }
       
  6409   }
       
  6410 }
       
  6411 
       
  6412 //----------------------------------------------------------------------
       
  6413 // find and add the enumeration to their classes, namespaces or files
       
  6414 
       
  6415 static void findEnums(EntryNav *rootNav)
       
  6416 {
       
  6417   if (rootNav->section()==Entry::ENUM_SEC)
       
  6418     // non anonymous enumeration
       
  6419   {
       
  6420     rootNav->loadEntry(g_storage);
       
  6421     Entry *root = rootNav->entry();
       
  6422 
       
  6423     MemberDef      *md=0;
       
  6424     ClassDef       *cd=0;
       
  6425     FileDef        *fd=0;
       
  6426     NamespaceDef   *nd=0;
       
  6427     MemberNameSDict *mnsd=0;
       
  6428     bool isGlobal;
       
  6429     bool isRelated=FALSE;
       
  6430     bool isMemberOf=FALSE;
       
  6431     //printf("Found enum with name `%s' relates=%s\n",root->name.data(),root->relates.data());
       
  6432     int i;
       
  6433 
       
  6434     QCString name;
       
  6435     QCString scope;
       
  6436 
       
  6437     if ((i=root->name.findRev("::"))!=-1) // scope is specified
       
  6438     {
       
  6439       scope=root->name.left(i); // extract scope
       
  6440       name=root->name.right(root->name.length()-i-2); // extract name
       
  6441       if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope);
       
  6442     }
       
  6443     else // no scope, check the scope in which the docs where found
       
  6444     {
       
  6445       if (( rootNav->parent()->section() & Entry::SCOPE_MASK )
       
  6446           && !rootNav->parent()->name().isEmpty()
       
  6447          ) // found enum docs inside a compound
       
  6448       {
       
  6449         scope=rootNav->parent()->name();
       
  6450         if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope);
       
  6451       }
       
  6452       name=root->name;
       
  6453     }
       
  6454 
       
  6455     if (!root->relates.isEmpty()) 
       
  6456     {   // related member, prefix user specified scope
       
  6457       isRelated=TRUE;
       
  6458       isMemberOf=(root->relatesType == MemberOf);
       
  6459       if (getClass(root->relates)==0 && !scope.isEmpty())
       
  6460         scope=mergeScopes(scope,root->relates);
       
  6461       else 
       
  6462         scope=root->relates.copy();
       
  6463       if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope);
       
  6464     }
       
  6465 
       
  6466     if (cd && !name.isEmpty()) // found a enum inside a compound
       
  6467     {
       
  6468       //printf("Enum `%s'::`%s'\n",cd->name(),name.data());
       
  6469       fd=0;
       
  6470       mnsd=Doxygen::memberNameSDict;
       
  6471       isGlobal=FALSE;
       
  6472     }
       
  6473     else if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@') // found enum inside namespace
       
  6474     {
       
  6475       mnsd=Doxygen::functionNameSDict;
       
  6476       isGlobal=TRUE;
       
  6477     }
       
  6478     else // found a global enum
       
  6479     {
       
  6480       fd=rootNav->fileDef();
       
  6481       mnsd=Doxygen::functionNameSDict;
       
  6482       isGlobal=TRUE;
       
  6483     }
       
  6484 
       
  6485     if (!name.isEmpty())
       
  6486     {
       
  6487       // new enum type
       
  6488       md = new MemberDef(
       
  6489           root->fileName,root->startLine,
       
  6490           0,name,0,0,
       
  6491           root->protection,Normal,FALSE,
       
  6492           isMemberOf ? Foreign : isRelated ? Related : Member,
       
  6493           MemberDef::Enumeration,
       
  6494           0,0);
       
  6495       md->setTagInfo(rootNav->tagInfo());
       
  6496       if (!isGlobal) md->setMemberClass(cd); else md->setFileDef(fd);
       
  6497       md->setBodySegment(root->bodyLine,root->endBodyLine);
       
  6498       md->setBodyDef(rootNav->fileDef());
       
  6499       //printf("Enum %s definition at line %d of %s: protection=%d\n",
       
  6500       //    root->name.data(),root->bodyLine,root->fileName.data(),root->protection);
       
  6501       md->addSectionsToDefinition(root->anchors);
       
  6502       md->setMemberGroupId(root->mGrpId);
       
  6503       md->enableCallGraph(root->callGraph);
       
  6504       md->enableCallerGraph(root->callerGraph);
       
  6505       //printf("%s::setRefItems(%d)\n",md->name().data(),root->sli?root->sli->count():-1);
       
  6506       md->setRefItems(root->sli);
       
  6507       //printf("found enum %s nd=%p\n",name.data(),nd);
       
  6508       bool defSet=FALSE;
       
  6509       if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@')
       
  6510       {
       
  6511         if (isRelated || Config_getBool("HIDE_SCOPE_NAMES"))
       
  6512         {
       
  6513           md->setDefinition(name);  
       
  6514         }
       
  6515         else
       
  6516         {
       
  6517           md->setDefinition(nd->name()+"::"+name);  
       
  6518         }
       
  6519         //printf("definition=%s\n",md->definition());
       
  6520         defSet=TRUE;
       
  6521         md->setNamespace(nd);
       
  6522         nd->insertMember(md);
       
  6523       }
       
  6524 
       
  6525       // even if we have already added the enum to a namespace, we still
       
  6526       // also want to add it to other appropriate places such as file
       
  6527       // or class.
       
  6528       if (isGlobal)
       
  6529       {
       
  6530         if (!defSet) md->setDefinition(name);
       
  6531         if (fd==0 && rootNav->parent())
       
  6532         {
       
  6533           fd=rootNav->parent()->fileDef();
       
  6534         }
       
  6535         if (fd) 
       
  6536         {
       
  6537           md->setFileDef(fd);
       
  6538           fd->insertMember(md);
       
  6539         }
       
  6540       }
       
  6541       else if (cd)
       
  6542       {
       
  6543         if (isRelated || Config_getBool("HIDE_SCOPE_NAMES"))
       
  6544         {
       
  6545           md->setDefinition(name);  
       
  6546         }
       
  6547         else
       
  6548         {
       
  6549           md->setDefinition(cd->name()+"::"+name);  
       
  6550         }
       
  6551         cd->insertMember(md);
       
  6552         cd->insertUsedFile(root->fileName);
       
  6553       }
       
  6554       md->setDocumentation(root->doc,root->docFile,root->docLine);
       
  6555       md->setDocsForDefinition(!root->proto);
       
  6556       md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
       
  6557       md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
       
  6558 
       
  6559       //printf("Adding member=%s\n",md->name().data());
       
  6560       MemberName *mn;
       
  6561       if ((mn=(*mnsd)[name]))
       
  6562       {
       
  6563         // this is used if the same enum is in multiple namespaces/classes
       
  6564         mn->append(md);
       
  6565       }
       
  6566       else // new enum name
       
  6567       {
       
  6568         mn = new MemberName(name);
       
  6569         mn->append(md);
       
  6570         mnsd->append(name,mn);
       
  6571         //printf("add %s to new memberName. Now %d members\n",
       
  6572         //       name.data(),mn->count());
       
  6573       }
       
  6574       addMemberToGroups(root,md);
       
  6575 
       
  6576 #if 0
       
  6577       if (rootNav->children())
       
  6578       {
       
  6579         EntryNavListIterator eli(*rootNav->children());
       
  6580         EntryNav *e;
       
  6581         for (;(e=eli.current());++eli)
       
  6582         {
       
  6583           //printf("e->name=%s isRelated=%d\n",e->name.data(),isRelated);
       
  6584           MemberName *fmn=0;
       
  6585           MemberNameSDict *emnsd = isRelated ? Doxygen::functionNameSDict : mnsd;
       
  6586           if (!e->name().isEmpty() && (fmn=(*emnsd)[e->name()])) 
       
  6587             // get list of members with the same name as the field
       
  6588           {
       
  6589             MemberNameIterator fmni(*fmn);
       
  6590             MemberDef *fmd;
       
  6591             for (fmni.toFirst(); (fmd=fmni.current()) ; ++fmni) 
       
  6592             {
       
  6593               if (fmd->isEnumValue())
       
  6594               {
       
  6595                 //printf("found enum value with same name\n");
       
  6596                 if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@')
       
  6597                 {
       
  6598                   NamespaceDef *fnd=fmd->getNamespaceDef();
       
  6599                   if (fnd==nd) // enum value is inside a namespace
       
  6600                   {
       
  6601                     md->insertEnumField(fmd);
       
  6602                     fmd->setEnumScope(md);
       
  6603                   }
       
  6604                 }
       
  6605                 else if (isGlobal)
       
  6606                 {
       
  6607                   FileDef *ffd=fmd->getFileDef();
       
  6608                   if (ffd==fd) // enum value has file scope
       
  6609                   {
       
  6610                     md->insertEnumField(fmd);
       
  6611                     fmd->setEnumScope(md);
       
  6612                   }
       
  6613                 }
       
  6614                 else if (isRelated && cd) // reparent enum value to
       
  6615                   // match the enum's scope
       
  6616                 {
       
  6617                   md->insertEnumField(fmd);   // add field def to list
       
  6618                   fmd->setEnumScope(md);      // cross ref with enum name
       
  6619                   fmd->setEnumClassScope(cd); // cross ref with enum name
       
  6620                   fmd->setOuterScope(cd);
       
  6621                   fmd->makeRelated();
       
  6622                   cd->insertMember(fmd);
       
  6623                 }
       
  6624                 else
       
  6625                 {
       
  6626                   ClassDef *fcd=fmd->getClassDef();
       
  6627                   if (fcd==cd) // enum value is inside a class
       
  6628                   {
       
  6629                     //printf("Inserting enum field %s in enum scope %s\n",
       
  6630                     //    fmd->name().data(),md->name().data());
       
  6631                     md->insertEnumField(fmd); // add field def to list
       
  6632                     fmd->setEnumScope(md);    // cross ref with enum name
       
  6633                   }
       
  6634                 }
       
  6635               } 
       
  6636             }
       
  6637           }
       
  6638         }
       
  6639       }
       
  6640 #endif
       
  6641     }
       
  6642 
       
  6643     rootNav->releaseEntry();
       
  6644   }
       
  6645   else
       
  6646   {
       
  6647     RECURSE_ENTRYTREE(findEnums,rootNav);
       
  6648   }
       
  6649 }
       
  6650 
       
  6651 //----------------------------------------------------------------------
       
  6652 
       
  6653 static void addEnumValuesToEnums(EntryNav *rootNav)
       
  6654 {
       
  6655   if (rootNav->section()==Entry::ENUM_SEC)
       
  6656     // non anonymous enumeration
       
  6657   {
       
  6658     rootNav->loadEntry(g_storage);
       
  6659     Entry *root = rootNav->entry();
       
  6660 
       
  6661     ClassDef       *cd=0;
       
  6662     FileDef        *fd=0;
       
  6663     NamespaceDef   *nd=0;
       
  6664     MemberNameSDict *mnsd=0;
       
  6665     bool isGlobal;
       
  6666     bool isRelated=FALSE;
       
  6667     //printf("Found enum with name `%s' relates=%s\n",root->name.data(),root->relates.data());
       
  6668     int i;
       
  6669 
       
  6670     QCString name;
       
  6671     QCString scope;
       
  6672 
       
  6673     if ((i=root->name.findRev("::"))!=-1) // scope is specified
       
  6674     {
       
  6675       scope=root->name.left(i); // extract scope
       
  6676       name=root->name.right(root->name.length()-i-2); // extract name
       
  6677       if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope);
       
  6678     }
       
  6679     else // no scope, check the scope in which the docs where found
       
  6680     {
       
  6681       if (( rootNav->parent()->section() & Entry::SCOPE_MASK )
       
  6682           && !rootNav->parent()->name().isEmpty()
       
  6683          ) // found enum docs inside a compound
       
  6684       {
       
  6685         scope=rootNav->parent()->name();
       
  6686         if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope);
       
  6687       }
       
  6688       name=root->name;
       
  6689     }
       
  6690 
       
  6691     if (!root->relates.isEmpty()) 
       
  6692     {   // related member, prefix user specified scope
       
  6693       isRelated=TRUE;
       
  6694       if (getClass(root->relates)==0 && !scope.isEmpty())
       
  6695         scope=mergeScopes(scope,root->relates);
       
  6696       else 
       
  6697         scope=root->relates.copy();
       
  6698       if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope);
       
  6699     }
       
  6700 
       
  6701     if (cd && !name.isEmpty()) // found a enum inside a compound
       
  6702     {
       
  6703       //printf("Enum in class `%s'::`%s'\n",cd->name().data(),name.data());
       
  6704       fd=0;
       
  6705       mnsd=Doxygen::memberNameSDict;
       
  6706       isGlobal=FALSE;
       
  6707     }
       
  6708     else if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@') // found enum inside namespace
       
  6709     {
       
  6710       //printf("Enum in namespace `%s'::`%s'\n",nd->name().data(),name.data());
       
  6711       mnsd=Doxygen::functionNameSDict;
       
  6712       isGlobal=TRUE;
       
  6713     }
       
  6714     else // found a global enum
       
  6715     {
       
  6716       fd=rootNav->fileDef();
       
  6717       //printf("Enum in file `%s': `%s'\n",fd->name().data(),name.data());
       
  6718       mnsd=Doxygen::functionNameSDict;
       
  6719       isGlobal=TRUE;
       
  6720     }
       
  6721 
       
  6722     if (!name.isEmpty())
       
  6723     {
       
  6724       MemberName *mn = mnsd->find(name); // for all members with this name
       
  6725       if (mn)
       
  6726       {
       
  6727         MemberNameIterator mni(*mn);
       
  6728         MemberDef *md;
       
  6729         for (mni.toFirst(); (md=mni.current()) ; ++mni)  // for each enum in this list
       
  6730         {
       
  6731           if (md->isEnumerate() && rootNav->children())
       
  6732           {
       
  6733             EntryNavListIterator eli(*rootNav->children()); // for each enum value
       
  6734             EntryNav *e;
       
  6735             for (;(e=eli.current());++eli)
       
  6736             {
       
  6737               SrcLangExt sle;
       
  6738               if (rootNav->fileDef() &&
       
  6739                   ( (sle=getLanguageFromFileName(rootNav->fileDef()->name()))==SrcLangExt_CSharp
       
  6740                   || sle==SrcLangExt_Java || sle==SrcLangExt_XML
       
  6741                   )
       
  6742                  )
       
  6743               {
       
  6744                 // Unlike C++, for C# enum value are only inside the enum 
       
  6745                 // scope, so we must create them here and only add them to the
       
  6746                 // enum
       
  6747                 e->loadEntry(g_storage);
       
  6748                 Entry *root = e->entry();
       
  6749                 if (md->qualifiedName()==rootNav->name()) // enum value scope matches that of the enum
       
  6750                 {
       
  6751                   MemberDef *fmd=new MemberDef(
       
  6752                       root->fileName,root->startLine,
       
  6753                       root->type,root->name,root->args,0,
       
  6754                       Public, Normal,root->stat,Member,
       
  6755                       MemberDef::EnumValue,0,0);
       
  6756                   if (md->getClassDef()) fmd->setMemberClass(md->getClassDef());
       
  6757                   else if (md->getNamespaceDef()) fmd->setNamespace(md->getNamespaceDef());
       
  6758                   else if (md->getFileDef()) fmd->setFileDef(md->getFileDef());
       
  6759                   fmd->setOuterScope(md->getOuterScope());
       
  6760                   fmd->setTagInfo(e->tagInfo());
       
  6761                   fmd->setDocumentation(root->doc,root->docFile,root->docLine);
       
  6762                   fmd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
       
  6763                   fmd->addSectionsToDefinition(root->anchors);
       
  6764                   fmd->setInitializer(root->initializer);
       
  6765                   fmd->setMaxInitLines(root->initLines);
       
  6766                   fmd->setMemberGroupId(root->mGrpId);
       
  6767                   fmd->setExplicitExternal(root->explicitExternal);
       
  6768                   if (fmd)
       
  6769                   {
       
  6770                     md->insertEnumField(fmd);
       
  6771                     fmd->setEnumScope(md);
       
  6772                   }
       
  6773                 }
       
  6774                 e->releaseEntry();
       
  6775               }
       
  6776               else
       
  6777               {
       
  6778                 //printf("e->name=%s isRelated=%d\n",e->name().data(),isRelated);
       
  6779                 MemberName *fmn=0;
       
  6780                 MemberNameSDict *emnsd = isRelated ? Doxygen::functionNameSDict : mnsd;
       
  6781                 if (!e->name().isEmpty() && (fmn=(*emnsd)[e->name()])) 
       
  6782                   // get list of members with the same name as the field
       
  6783                 {
       
  6784                   MemberNameIterator fmni(*fmn);
       
  6785                   MemberDef *fmd;
       
  6786                   for (fmni.toFirst(); (fmd=fmni.current()) ; ++fmni) 
       
  6787                   {
       
  6788                     if (fmd->isEnumValue() && fmd->getOuterScope()==md->getOuterScope()) // in same scope
       
  6789                     {
       
  6790                       //printf("found enum value with same name %s in scope %s\n",
       
  6791                       //    fmd->name().data(),fmd->getOuterScope()->name().data());
       
  6792                       if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@')
       
  6793                       {
       
  6794                         NamespaceDef *fnd=fmd->getNamespaceDef();
       
  6795                         if (fnd==nd) // enum value is inside a namespace
       
  6796                         {
       
  6797                           md->insertEnumField(fmd);
       
  6798                           fmd->setEnumScope(md);
       
  6799                         }
       
  6800                       }
       
  6801                       else if (isGlobal)
       
  6802                       {
       
  6803                         FileDef *ffd=fmd->getFileDef();
       
  6804                         if (ffd==fd) // enum value has file scope
       
  6805                         {
       
  6806                           md->insertEnumField(fmd);
       
  6807                           fmd->setEnumScope(md);
       
  6808                         }
       
  6809                       }
       
  6810                       else if (isRelated && cd) // reparent enum value to
       
  6811                                                 // match the enum's scope
       
  6812                       {
       
  6813                         md->insertEnumField(fmd);   // add field def to list
       
  6814                         fmd->setEnumScope(md);      // cross ref with enum name
       
  6815                         fmd->setEnumClassScope(cd); // cross ref with enum name
       
  6816                         fmd->setOuterScope(cd);
       
  6817                         fmd->makeRelated();
       
  6818                         cd->insertMember(fmd);
       
  6819                       }
       
  6820                       else
       
  6821                       {
       
  6822                         ClassDef *fcd=fmd->getClassDef();
       
  6823                         if (fcd==cd) // enum value is inside a class
       
  6824                         {
       
  6825                           //printf("Inserting enum field %s in enum scope %s\n",
       
  6826                           //    fmd->name().data(),md->name().data());
       
  6827                           md->insertEnumField(fmd); // add field def to list
       
  6828                           fmd->setEnumScope(md);    // cross ref with enum name
       
  6829                         }
       
  6830                       }
       
  6831                     } 
       
  6832                   }
       
  6833                 }
       
  6834               }
       
  6835             }
       
  6836           }
       
  6837         }
       
  6838       }
       
  6839     }
       
  6840 
       
  6841     rootNav->releaseEntry();
       
  6842   }
       
  6843   else
       
  6844   {
       
  6845     RECURSE_ENTRYTREE(addEnumValuesToEnums,rootNav);
       
  6846   }
       
  6847 }
       
  6848 
       
  6849 
       
  6850 //----------------------------------------------------------------------
       
  6851 // find the documentation blocks for the enumerations
       
  6852 
       
  6853 static void findEnumDocumentation(EntryNav *rootNav)
       
  6854 {
       
  6855   if (rootNav->section()==Entry::ENUMDOC_SEC
       
  6856       && !rootNav->name().isEmpty()
       
  6857       && rootNav->name().at(0)!='@'        // skip anonymous enums
       
  6858      )
       
  6859   {
       
  6860     rootNav->loadEntry(g_storage);
       
  6861     Entry *root = rootNav->entry();
       
  6862 
       
  6863     //printf("Found docs for enum with name `%s' in context %s\n",
       
  6864     //    root->name.data(),root->parent->name.data());
       
  6865     int i;
       
  6866     QCString name;
       
  6867     QCString scope;
       
  6868     if ((i=root->name.findRev("::"))!=-1) // scope is specified as part of the name
       
  6869     {
       
  6870       name=root->name.right(root->name.length()-i-2); // extract name
       
  6871       scope=root->name.left(i); // extract scope
       
  6872       //printf("Scope=`%s' Name=`%s'\n",scope.data(),name.data());
       
  6873     }
       
  6874     else // just the name
       
  6875     {
       
  6876       name=root->name;
       
  6877     }
       
  6878     if (( rootNav->parent()->section() & Entry::SCOPE_MASK )
       
  6879         && !rootNav->parent()->name().isEmpty()
       
  6880        ) // found enum docs inside a compound
       
  6881     {
       
  6882       if (!scope.isEmpty()) scope.prepend("::");
       
  6883       scope.prepend(rootNav->parent()->name());
       
  6884     }
       
  6885     ClassDef *cd=getClass(scope);
       
  6886 
       
  6887     if (!name.isEmpty())
       
  6888     {
       
  6889       bool found=FALSE;
       
  6890       if (cd)
       
  6891       {
       
  6892         //printf("Enum: scope=`%s' name=`%s'\n",cd->name(),name.data());
       
  6893         QCString className=cd->name().copy();
       
  6894         MemberName *mn=Doxygen::memberNameSDict->find(name);
       
  6895         if (mn)
       
  6896         {
       
  6897           MemberNameIterator mni(*mn);
       
  6898           MemberDef *md;
       
  6899           for (mni.toFirst();(md=mni.current()) && !found;++mni)
       
  6900           {
       
  6901             ClassDef *cd=md->getClassDef();
       
  6902             if (cd && cd->name()==className && md->isEnumerate())
       
  6903             {
       
  6904               // documentation outside a compound overrides the documentation inside it
       
  6905 #if 0
       
  6906               if (!md->documentation() || rootNav->parent()->name().isEmpty()) 
       
  6907 #endif
       
  6908               {
       
  6909                 md->setDocumentation(root->doc,root->docFile,root->docLine);
       
  6910                 md->setDocsForDefinition(!root->proto);
       
  6911               }
       
  6912 
       
  6913               // brief descriptions inside a compound override the documentation 
       
  6914               // outside it
       
  6915 #if 0
       
  6916               if (!md->briefDescription() || !rootNav->parent()->name().isEmpty())
       
  6917 #endif
       
  6918               {
       
  6919                 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
       
  6920               }
       
  6921 
       
  6922               if (!md->inbodyDocumentation() || !rootNav->parent()->name().isEmpty())
       
  6923               {
       
  6924                 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
       
  6925               }
       
  6926 
       
  6927               if (root->mGrpId!=-1 && md->getMemberGroupId()==-1)
       
  6928               {
       
  6929                 md->setMemberGroupId(root->mGrpId);
       
  6930               }
       
  6931 
       
  6932               md->addSectionsToDefinition(root->anchors);
       
  6933               md->setRefItems(root->sli);
       
  6934 
       
  6935               GroupDef *gd=md->getGroupDef();
       
  6936               if (gd==0 &&root->groups->first()!=0) // member not grouped but out-of-line documentation is
       
  6937               {
       
  6938                 addMemberToGroups(root,md);
       
  6939               }
       
  6940 
       
  6941               found=TRUE;
       
  6942             }
       
  6943           }
       
  6944         }
       
  6945         else
       
  6946         {
       
  6947           //printf("MemberName %s not found!\n",name.data());
       
  6948         }
       
  6949       }
       
  6950       else // enum outside class 
       
  6951       {
       
  6952         //printf("Enum outside class: %s grpId=%d\n",name.data(),root->mGrpId);
       
  6953         MemberName *mn=Doxygen::functionNameSDict->find(name);
       
  6954         if (mn)
       
  6955         {
       
  6956           MemberNameIterator mni(*mn);
       
  6957           MemberDef *md;
       
  6958           for (mni.toFirst();(md=mni.current()) && !found;++mni)
       
  6959           {
       
  6960             if (md->isEnumerate())
       
  6961             {
       
  6962               md->setDocumentation(root->doc,root->docFile,root->docLine);
       
  6963               md->setDocsForDefinition(!root->proto);
       
  6964               md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
       
  6965               md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
       
  6966               md->addSectionsToDefinition(root->anchors);
       
  6967               md->setMemberGroupId(root->mGrpId);
       
  6968 
       
  6969               GroupDef *gd=md->getGroupDef();
       
  6970               if (gd==0 && root->groups->first()!=0) // member not grouped but out-of-line documentation is
       
  6971               {
       
  6972                 addMemberToGroups(root,md);
       
  6973               }
       
  6974 
       
  6975               found=TRUE;
       
  6976             }
       
  6977           }
       
  6978         }
       
  6979       } 
       
  6980       if (!found)
       
  6981       {
       
  6982         warn(root->fileName,root->startLine,
       
  6983              "Warning: Documentation for undefined enum `%s' found.",
       
  6984              name.data()
       
  6985             );
       
  6986       }
       
  6987     }
       
  6988 
       
  6989     rootNav->releaseEntry();
       
  6990   }
       
  6991   RECURSE_ENTRYTREE(findEnumDocumentation,rootNav);
       
  6992 }
       
  6993 
       
  6994 // seach for each enum (member or function) in mnl if it has documented 
       
  6995 // enum values.
       
  6996 static void findDEV(const MemberNameSDict &mnsd)
       
  6997 {
       
  6998   MemberName *mn;
       
  6999   MemberNameSDict::Iterator mnli(mnsd);
       
  7000   // for each member name
       
  7001   for (mnli.toFirst();(mn=mnli.current());++mnli)
       
  7002   {
       
  7003     MemberDef *md;
       
  7004     MemberNameIterator mni(*mn);
       
  7005     // for each member definition
       
  7006     for (mni.toFirst();(md=mni.current());++mni)
       
  7007     {
       
  7008       if (md->isEnumerate()) // member is an enum
       
  7009       {
       
  7010         LockingPtr<MemberList> fmdl = md->enumFieldList();
       
  7011         int documentedEnumValues=0;
       
  7012         if (fmdl!=0) // enum has values
       
  7013         {
       
  7014           MemberListIterator fmni(*fmdl);
       
  7015           MemberDef *fmd;
       
  7016           // for each enum value
       
  7017           for (fmni.toFirst();(fmd=fmni.current());++fmni)
       
  7018           {
       
  7019             if (fmd->isLinkableInProject()) documentedEnumValues++;
       
  7020           }
       
  7021         }
       
  7022         // at least one enum value is documented
       
  7023         if (documentedEnumValues>0) md->setDocumentedEnumValues(TRUE);
       
  7024       }
       
  7025     }
       
  7026   }
       
  7027 }
       
  7028 
       
  7029 // seach for each enum (member or function) if it has documented enum 
       
  7030 // values.
       
  7031 static void findDocumentedEnumValues()
       
  7032 {
       
  7033   findDEV(*Doxygen::memberNameSDict);
       
  7034   findDEV(*Doxygen::functionNameSDict); 
       
  7035 }
       
  7036 
       
  7037 //----------------------------------------------------------------------
       
  7038 
       
  7039 static void addMembersToIndex()
       
  7040 {
       
  7041   MemberName *mn;
       
  7042   MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
       
  7043   // for each member name
       
  7044   for (mnli.toFirst();(mn=mnli.current());++mnli)
       
  7045   {
       
  7046     MemberDef *md;
       
  7047     MemberNameIterator mni(*mn);
       
  7048     // for each member definition
       
  7049     for (mni.toFirst();(md=mni.current());++mni)
       
  7050     {
       
  7051       addClassMemberNameToIndex(md);
       
  7052     }
       
  7053   }
       
  7054   MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict);
       
  7055   // for each member name
       
  7056   for (fnli.toFirst();(mn=fnli.current());++fnli)
       
  7057   {
       
  7058     MemberDef *md;
       
  7059     MemberNameIterator mni(*mn);
       
  7060     // for each member definition
       
  7061     for (mni.toFirst();(md=mni.current());++mni)
       
  7062     {
       
  7063       if (md->getNamespaceDef())
       
  7064       {
       
  7065         addNamespaceMemberNameToIndex(md);
       
  7066       }
       
  7067       else
       
  7068       {
       
  7069         addFileMemberNameToIndex(md);
       
  7070       }
       
  7071     }
       
  7072   }
       
  7073 }
       
  7074 
       
  7075 //----------------------------------------------------------------------
       
  7076 // computes the relation between all members. For each member `m'
       
  7077 // the members that override the implementation of `m' are searched and
       
  7078 // the member that `m' overrides is searched.
       
  7079 
       
  7080 static void computeMemberRelations()
       
  7081 {
       
  7082   MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
       
  7083   MemberName *mn;
       
  7084   for ( ; (mn=mnli.current()) ; ++mnli ) // for each member name
       
  7085   {
       
  7086     MemberNameIterator mdi(*mn);
       
  7087     MemberDef *md;
       
  7088     for ( ; (md=mdi.current()) ; ++mdi ) // for each member with a specific name
       
  7089     {
       
  7090       MemberDef *bmd = mn->first(); // for each other member with the same name
       
  7091       while (bmd)
       
  7092       {
       
  7093         ClassDef *mcd  = md->getClassDef();
       
  7094         if (mcd && mcd->baseClasses())
       
  7095         {
       
  7096           ClassDef *bmcd = bmd->getClassDef();
       
  7097           //printf("Check relation between `%s'::`%s' (%p) and `%s'::`%s' (%p)\n",
       
  7098           //      mcd->name().data(),md->name().data(),md,
       
  7099           //       bmcd->name().data(),bmd->name().data(),bmd
       
  7100           //      );
       
  7101           if (md!=bmd && bmcd && mcd && bmcd!=mcd && mcd->isBaseClass(bmcd,TRUE))
       
  7102           {
       
  7103             LockingPtr<ArgumentList> bmdAl = bmd->argumentList();
       
  7104             LockingPtr<ArgumentList>  mdAl =  md->argumentList();
       
  7105             //printf(" Base argList=`%s'\n Super argList=`%s'\n",
       
  7106             //        argListToString(bmdAl.pointer()).data(),
       
  7107             //        argListToString(mdAl.pointer()).data()
       
  7108             //      );
       
  7109             if ( 
       
  7110                 matchArguments2(bmd->getOuterScope(),bmd->getFileDef(),bmdAl.pointer(),
       
  7111                   md->getOuterScope(), md->getFileDef(), mdAl.pointer(),
       
  7112                   TRUE
       
  7113                   ) 
       
  7114                )
       
  7115             {
       
  7116               //printf("  match found!\n");
       
  7117               if (mcd && bmcd && 
       
  7118                   mcd->isLinkable() && bmcd->isLinkable()
       
  7119                  )
       
  7120               {
       
  7121                 MemberDef *rmd;
       
  7122                 if ((rmd=md->reimplements())==0 ||
       
  7123                     minClassDistance(mcd,bmcd)<minClassDistance(mcd,rmd->getClassDef())
       
  7124                    )
       
  7125                 {
       
  7126                   //printf("setting (new) reimplements member\n");
       
  7127                   md->setReimplements(bmd);
       
  7128                 }
       
  7129                 //printf("%s: add reimplements member %s\n",mcd->name().data(),bmcd->name().data());
       
  7130                 //md->setImplements(bmd);
       
  7131                 //printf("%s: add reimplementedBy member %s\n",bmcd->name().data(),mcd->name().data());
       
  7132                 bmd->insertReimplementedBy(md);
       
  7133               }
       
  7134             }  
       
  7135           }
       
  7136         }
       
  7137         bmd = mn->next();
       
  7138       }
       
  7139     }
       
  7140   }  
       
  7141 }
       
  7142 
       
  7143 
       
  7144 //----------------------------------------------------------------------------
       
  7145 //static void computeClassImplUsageRelations()
       
  7146 //{
       
  7147 //  ClassDef *cd;
       
  7148 //  ClassSDict::Iterator cli(*Doxygen::classSDict);
       
  7149 //  for (;(cd=cli.current());++cli)
       
  7150 //  {
       
  7151 //    cd->determineImplUsageRelation();
       
  7152 //  }
       
  7153 //}
       
  7154 
       
  7155 //----------------------------------------------------------------------------
       
  7156 
       
  7157 static void createTemplateInstanceMembers()
       
  7158 {
       
  7159   ClassSDict::Iterator cli(*Doxygen::classSDict);
       
  7160   ClassDef *cd;
       
  7161   // for each class
       
  7162   for (cli.toFirst();(cd=cli.current());++cli)
       
  7163   {
       
  7164     // that is a template
       
  7165     QDict<ClassDef> *templInstances = cd->getTemplateInstances();
       
  7166     if (templInstances)
       
  7167     {
       
  7168       QDictIterator<ClassDef> qdi(*templInstances);
       
  7169       ClassDef *tcd=0;
       
  7170       // for each instance of the template
       
  7171       for (qdi.toFirst();(tcd=qdi.current());++qdi)
       
  7172       {
       
  7173         tcd->addMembersToTemplateInstance(cd,qdi.currentKey());
       
  7174       }
       
  7175     }
       
  7176   }
       
  7177 }
       
  7178 
       
  7179 //----------------------------------------------------------------------------
       
  7180 
       
  7181 // builds the list of all members for each class
       
  7182 
       
  7183 static void buildCompleteMemberLists()
       
  7184 {
       
  7185   ClassDef *cd;
       
  7186   // merge members of categories into the class they extend
       
  7187   ClassSDict::Iterator cli(*Doxygen::classSDict);
       
  7188   for (cli.toFirst();(cd=cli.current());++cli)
       
  7189   {
       
  7190     int i=cd->name().find('(');
       
  7191     if (i!=-1) // it is an Objective-C category
       
  7192     {
       
  7193       QCString baseName=cd->name().left(i);
       
  7194       ClassDef *baseClass=Doxygen::classSDict->find(baseName);
       
  7195       if (baseClass)
       
  7196       {
       
  7197         //printf("*** merging members of category %s into %s\n",
       
  7198         //    cd->name().data(),baseClass->name().data());
       
  7199         baseClass->mergeCategory(cd);
       
  7200       }
       
  7201     }
       
  7202   }
       
  7203   // merge the member list of base classes into the inherited classes.
       
  7204   for (cli.toFirst();(cd=cli.current());++cli)
       
  7205   {
       
  7206     if (// !cd->isReference() && // not an external class
       
  7207          cd->subClasses()==0 && // is a root of the hierarchy
       
  7208          cd->baseClasses()) // and has at least one base class
       
  7209     {
       
  7210       //printf("*** merging members for %s\n",cd->name().data());
       
  7211       cd->mergeMembers();
       
  7212     }
       
  7213   }
       
  7214   // now sort the member list of all classes.
       
  7215   for (cli.toFirst();(cd=cli.current());++cli)
       
  7216   {
       
  7217     if (cd->memberNameInfoSDict()) cd->memberNameInfoSDict()->sort();
       
  7218   }
       
  7219 }
       
  7220 
       
  7221 //----------------------------------------------------------------------------
       
  7222 
       
  7223 static void generateFileSources()
       
  7224 {
       
  7225   if (documentedHtmlFiles==0) return;
       
  7226   if (Doxygen::inputNameList->count()>0)
       
  7227   {
       
  7228     FileNameListIterator fnli(*Doxygen::inputNameList); 
       
  7229     FileName *fn;
       
  7230     for (;(fn=fnli.current());++fnli)
       
  7231     {
       
  7232       FileNameIterator fni(*fn);
       
  7233       FileDef *fd;
       
  7234       for (;(fd=fni.current());++fni)
       
  7235       {
       
  7236         if (fd->generateSourceFile()) // sources need to be shown in the output
       
  7237         {
       
  7238           msg("Generating code for file %s...\n",fd->docName().data());
       
  7239           fd->writeSource(*g_outputList);
       
  7240         }
       
  7241         else if (!fd->isReference() && Doxygen::parseSourcesNeeded)
       
  7242           // we needed to parse the sources even if we do not show them
       
  7243         {
       
  7244           msg("Parsing code for file %s...\n",fd->docName().data());
       
  7245           fd->parseSource();
       
  7246         }
       
  7247       }
       
  7248     }
       
  7249   }
       
  7250 }
       
  7251 
       
  7252 //----------------------------------------------------------------------------
       
  7253 
       
  7254 static void generateFileDocs()
       
  7255 {
       
  7256   if (documentedHtmlFiles==0) return;
       
  7257   
       
  7258   if (Doxygen::inputNameList->count()>0)
       
  7259   {
       
  7260     FileNameListIterator fnli(*Doxygen::inputNameList);
       
  7261     FileName *fn;
       
  7262     for (fnli.toFirst();(fn=fnli.current());++fnli)
       
  7263     {
       
  7264       FileNameIterator fni(*fn);
       
  7265       FileDef *fd;
       
  7266       for (fni.toFirst();(fd=fni.current());++fni)
       
  7267       {
       
  7268         bool doc = fd->isLinkableInProject();
       
  7269         if (doc)
       
  7270         {
       
  7271           msg("Generating docs for file %s...\n",fd->docName().data());
       
  7272           fd->writeDocumentation(*g_outputList);
       
  7273         }
       
  7274       }
       
  7275     }
       
  7276   }
       
  7277 }
       
  7278 
       
  7279 //----------------------------------------------------------------------------
       
  7280 
       
  7281 static void addSourceReferences()
       
  7282 {
       
  7283   // add source references for class definitions
       
  7284   ClassSDict::Iterator cli(*Doxygen::classSDict);
       
  7285   ClassDef *cd=0;
       
  7286   for (cli.toFirst();(cd=cli.current());++cli)
       
  7287   {
       
  7288     FileDef *fd=cd->getBodyDef();
       
  7289     if (fd && cd->isLinkableInProject() && cd->getStartBodyLine()!=-1)
       
  7290     {
       
  7291       fd->addSourceRef(cd->getStartBodyLine(),cd,0);
       
  7292     }
       
  7293   }
       
  7294   // add source references for namespace definitions
       
  7295   NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
       
  7296   NamespaceDef *nd=0;
       
  7297   for (nli.toFirst();(nd=nli.current());++nli)
       
  7298   {
       
  7299     FileDef *fd=nd->getBodyDef();
       
  7300     if (fd && nd->isLinkableInProject() && nd->getStartBodyLine()!=-1)
       
  7301     {
       
  7302       fd->addSourceRef(nd->getStartBodyLine(),nd,0);
       
  7303     }
       
  7304   }
       
  7305   
       
  7306   // add source references for member names
       
  7307   MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
       
  7308   MemberName *mn=0;
       
  7309   for (mnli.toFirst();(mn=mnli.current());++mnli)
       
  7310   {
       
  7311     MemberNameIterator mni(*mn);
       
  7312     MemberDef *md=0;
       
  7313     for (mni.toFirst();(md=mni.current());++mni)
       
  7314     {
       
  7315       //printf("class member %s\n",md->name().data());
       
  7316       FileDef *fd=md->getBodyDef();
       
  7317       if (fd && 
       
  7318           md->getStartBodyLine()!=-1 &&
       
  7319           md->isLinkableInProject() &&
       
  7320           (fd->generateSourceFile() || Doxygen::parseSourcesNeeded)
       
  7321          )
       
  7322       {
       
  7323         //printf("Found member `%s' in file `%s' at line `%d' def=%s\n",
       
  7324         //    md->name().data(),fd->name().data(),md->getStartBodyLine(),md->getOuterScope()->name().data()); 
       
  7325         fd->addSourceRef(md->getStartBodyLine(),md->getOuterScope(),md);
       
  7326       }
       
  7327     }
       
  7328   }
       
  7329   MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict);
       
  7330   for (fnli.toFirst();(mn=fnli.current());++fnli)
       
  7331   {
       
  7332     MemberNameIterator mni(*mn);
       
  7333     MemberDef *md=0;
       
  7334     for (mni.toFirst();(md=mni.current());++mni)
       
  7335     {
       
  7336       FileDef *fd=md->getBodyDef();
       
  7337       //printf("member %s body=[%d,%d] fd=%p link=%d parseSources=%d\n",
       
  7338       //    md->name().data(),
       
  7339       //    md->getStartBodyLine(),md->getEndBodyLine(),fd,
       
  7340       //    md->isLinkableInProject(),
       
  7341       //    Doxygen::parseSourcesNeeded);
       
  7342       if (fd && 
       
  7343           md->getStartBodyLine()!=-1 && 
       
  7344           md->isLinkableInProject() && 
       
  7345           (fd->generateSourceFile() || Doxygen::parseSourcesNeeded)
       
  7346          )
       
  7347       {
       
  7348         //printf("Found member `%s' in file `%s' at line `%d' def=%s\n",
       
  7349         //    md->name().data(),fd->name().data(),md->getStartBodyLine(),md->getOuterScope()->name().data()); 
       
  7350         fd->addSourceRef(md->getStartBodyLine(),md->getOuterScope(),md);
       
  7351       }  
       
  7352     }
       
  7353   }
       
  7354 }
       
  7355 
       
  7356 //----------------------------------------------------------------------------
       
  7357 // generate the documentation of all classes
       
  7358   
       
  7359 static void generateClassList(ClassSDict &classSDict)
       
  7360 {
       
  7361   ClassSDict::Iterator cli(classSDict);
       
  7362   for ( ; cli.current() ; ++cli )
       
  7363   {
       
  7364     ClassDef *cd=cli.current();
       
  7365    
       
  7366     //printf("cd=%s getOuterScope=%p global=%p\n",cd->name().data(),cd->getOuterScope(),Doxygen::globalScope);
       
  7367     if ((cd->getOuterScope()==0 || // <-- should not happen, but can if we read an old tag file
       
  7368          cd->getOuterScope()==Doxygen::globalScope // only look at global classes
       
  7369         ) && !cd->isHidden()
       
  7370        ) 
       
  7371     {
       
  7372       // skip external references, anonymous compounds and 
       
  7373       // template instances 
       
  7374       if ( cd->isLinkableInProject() && cd->templateMaster()==0)
       
  7375       {
       
  7376         msg("Generating docs for compound %s...\n",cd->name().data());
       
  7377 
       
  7378         cd->writeDocumentation(*g_outputList);
       
  7379         cd->writeMemberList(*g_outputList);
       
  7380       }
       
  7381       // even for undocumented classes, the inner classes can be documented.
       
  7382       cd->writeDocumentationForInnerClasses(*g_outputList);
       
  7383     }
       
  7384   }
       
  7385 }
       
  7386 
       
  7387 static void generateClassDocs()
       
  7388 {
       
  7389   // write the installdox script if necessary
       
  7390   if (Config_getBool("GENERATE_HTML") && 
       
  7391       (Config_getList("TAGFILES").count()>0 || 
       
  7392        Config_getBool("SEARCHENGINE")
       
  7393       )
       
  7394      ) 
       
  7395   {
       
  7396     writeInstallScript();
       
  7397   }
       
  7398   
       
  7399   msg("Generating annotated compound index...\n");
       
  7400   writeAnnotatedIndex(*g_outputList);
       
  7401 
       
  7402   //if (Config_getBool("ALPHABETICAL_INDEX"))
       
  7403   //{
       
  7404     msg("Generating alphabetical compound index...\n");
       
  7405     writeAlphabeticalIndex(*g_outputList);
       
  7406   //}
       
  7407 
       
  7408   msg("Generating hierarchical class index...\n");
       
  7409   writeHierarchicalIndex(*g_outputList);
       
  7410 
       
  7411   msg("Generating member index...\n");
       
  7412   writeClassMemberIndex(*g_outputList);
       
  7413 
       
  7414   if (Doxygen::exampleSDict->count()>0)
       
  7415   {
       
  7416     msg("Generating example index...\n");
       
  7417   }
       
  7418 
       
  7419   generateClassList(*Doxygen::classSDict);
       
  7420   generateClassList(*Doxygen::hiddenClasses);
       
  7421 }
       
  7422 
       
  7423 //----------------------------------------------------------------------------
       
  7424 
       
  7425 static void inheritDocumentation()
       
  7426 {
       
  7427   MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
       
  7428   MemberName *mn;
       
  7429   //int count=0;
       
  7430   for (;(mn=mnli.current());++mnli)
       
  7431   {
       
  7432     MemberNameIterator mni(*mn);
       
  7433     MemberDef *md;
       
  7434     for (;(md=mni.current());++mni)
       
  7435     {
       
  7436       //printf("%04d Member `%s'\n",count++,md->name().data());
       
  7437       if (md->documentation().isEmpty() && md->briefDescription().isEmpty())
       
  7438       { // no documentation yet
       
  7439         MemberDef *bmd = md->reimplements();
       
  7440         while (bmd && bmd->documentation().isEmpty() && 
       
  7441                       bmd->briefDescription().isEmpty()
       
  7442               )
       
  7443         { // search up the inheritance tree for a documentation member
       
  7444           //printf("bmd=%s class=%s\n",bmd->name().data(),bmd->getClassDef()->name().data());
       
  7445           bmd = bmd->reimplements();
       
  7446         }
       
  7447         if (bmd) // copy the documentation from the reimplemented member
       
  7448         {
       
  7449           md->setInheritsDocsFrom(bmd);
       
  7450           md->setDocumentation(bmd->documentation(),bmd->docFile(),bmd->docLine());
       
  7451           md->setDocsForDefinition(bmd->isDocsForDefinition());
       
  7452           md->setBriefDescription(bmd->briefDescription(),bmd->briefFile(),bmd->briefLine());
       
  7453           md->copyArgumentNames(bmd);
       
  7454           md->setInbodyDocumentation(bmd->inbodyDocumentation(),bmd->inbodyFile(),bmd->inbodyLine());
       
  7455         }
       
  7456       }
       
  7457     }
       
  7458   }
       
  7459 }
       
  7460 
       
  7461 //----------------------------------------------------------------------------
       
  7462 
       
  7463 static void combineUsingRelations()
       
  7464 {
       
  7465   // for each file
       
  7466   FileNameListIterator fnli(*Doxygen::inputNameList);
       
  7467   FileName *fn;
       
  7468   for (fnli.toFirst();(fn=fnli.current());++fnli)
       
  7469   {
       
  7470     FileNameIterator fni(*fn);
       
  7471     FileDef *fd;
       
  7472     for (fni.toFirst();(fd=fni.current());++fni)
       
  7473     {
       
  7474       fd->visited=FALSE;
       
  7475     }
       
  7476   }
       
  7477   for (fnli.toFirst();(fn=fnli.current());++fnli)
       
  7478   {
       
  7479     FileNameIterator fni(*fn);
       
  7480     FileDef *fd;
       
  7481     for (fni.toFirst();(fd=fni.current());++fni)
       
  7482     {
       
  7483       fd->combineUsingRelations();
       
  7484     }
       
  7485   }
       
  7486 
       
  7487   // for each namespace
       
  7488   NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
       
  7489   NamespaceDef *nd;
       
  7490   for (nli.toFirst() ; (nd=nli.current()) ; ++nli )
       
  7491   {
       
  7492     nd->visited=FALSE;
       
  7493   }
       
  7494   for (nli.toFirst() ; (nd=nli.current()) ; ++nli )
       
  7495   {
       
  7496     nd->combineUsingRelations();
       
  7497   }
       
  7498 }
       
  7499 
       
  7500 //----------------------------------------------------------------------------
       
  7501   
       
  7502 static void addMembersToMemberGroup()
       
  7503 {
       
  7504   // for each class
       
  7505   ClassSDict::Iterator cli(*Doxygen::classSDict);
       
  7506   ClassDef *cd;
       
  7507   for ( ; (cd=cli.current()) ; ++cli )
       
  7508   {
       
  7509     cd->addMembersToMemberGroup();
       
  7510   }
       
  7511   // for each file
       
  7512   FileName *fn=Doxygen::inputNameList->first();
       
  7513   while (fn)
       
  7514   {
       
  7515     FileDef *fd=fn->first();
       
  7516     while (fd)
       
  7517     {
       
  7518       fd->addMembersToMemberGroup();
       
  7519       fd=fn->next();
       
  7520     }
       
  7521     fn=Doxygen::inputNameList->next();
       
  7522   }
       
  7523   // for each namespace
       
  7524   NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
       
  7525   NamespaceDef *nd;
       
  7526   for ( ; (nd=nli.current()) ; ++nli )
       
  7527   {
       
  7528     nd->addMembersToMemberGroup();
       
  7529   }
       
  7530   // for each group
       
  7531   GroupSDict::Iterator gli(*Doxygen::groupSDict);
       
  7532   GroupDef *gd;
       
  7533   for (gli.toFirst();(gd=gli.current());++gli)
       
  7534   {
       
  7535     gd->addMembersToMemberGroup();
       
  7536   }
       
  7537 }
       
  7538 
       
  7539 //----------------------------------------------------------------------------
       
  7540 
       
  7541 static void distributeMemberGroupDocumentation()
       
  7542 {
       
  7543   // for each class
       
  7544   ClassSDict::Iterator cli(*Doxygen::classSDict);
       
  7545   ClassDef *cd;
       
  7546   for ( ; (cd=cli.current()) ; ++cli )
       
  7547   {
       
  7548     cd->distributeMemberGroupDocumentation();
       
  7549   }
       
  7550   // for each file
       
  7551   FileName *fn=Doxygen::inputNameList->first();
       
  7552   while (fn)
       
  7553   {
       
  7554     FileDef *fd=fn->first();
       
  7555     while (fd)
       
  7556     {
       
  7557       fd->distributeMemberGroupDocumentation();
       
  7558       fd=fn->next();
       
  7559     }
       
  7560     fn=Doxygen::inputNameList->next();
       
  7561   }
       
  7562   // for each namespace
       
  7563   NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
       
  7564   NamespaceDef *nd;
       
  7565   for ( ; (nd=nli.current()) ; ++nli )
       
  7566   {
       
  7567     nd->distributeMemberGroupDocumentation();
       
  7568   }
       
  7569   // for each group
       
  7570   GroupSDict::Iterator gli(*Doxygen::groupSDict);
       
  7571   GroupDef *gd;
       
  7572   for (gli.toFirst();(gd=gli.current());++gli)
       
  7573   {
       
  7574     gd->distributeMemberGroupDocumentation();
       
  7575   }
       
  7576 }
       
  7577 
       
  7578 //----------------------------------------------------------------------------
       
  7579 
       
  7580 static void findSectionsInDocumentation()
       
  7581 {
       
  7582   // for each class
       
  7583   ClassSDict::Iterator cli(*Doxygen::classSDict);
       
  7584   ClassDef *cd;
       
  7585   for ( ; (cd=cli.current()) ; ++cli )
       
  7586   {
       
  7587     cd->findSectionsInDocumentation();
       
  7588   }
       
  7589   // for each file
       
  7590   FileName *fn=Doxygen::inputNameList->first();
       
  7591   while (fn)
       
  7592   {
       
  7593     FileDef *fd=fn->first();
       
  7594     while (fd)
       
  7595     {
       
  7596       fd->findSectionsInDocumentation();
       
  7597       fd=fn->next();
       
  7598     }
       
  7599     fn=Doxygen::inputNameList->next();
       
  7600   }
       
  7601   // for each namespace
       
  7602   NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
       
  7603   NamespaceDef *nd;
       
  7604   for ( ; (nd=nli.current()) ; ++nli )
       
  7605   {
       
  7606     nd->findSectionsInDocumentation();
       
  7607   }
       
  7608   // for each group
       
  7609   GroupSDict::Iterator gli(*Doxygen::groupSDict);
       
  7610   GroupDef *gd;
       
  7611   for (gli.toFirst();(gd=gli.current());++gli)
       
  7612   {
       
  7613     gd->findSectionsInDocumentation();
       
  7614   }
       
  7615   // for each page
       
  7616   PageSDict::Iterator pdi(*Doxygen::pageSDict);
       
  7617   PageDef *pd=0;
       
  7618   for (pdi.toFirst();(pd=pdi.current());++pdi)
       
  7619   {
       
  7620     pd->findSectionsInDocumentation();
       
  7621   }
       
  7622   if (Doxygen::mainPage) Doxygen::mainPage->findSectionsInDocumentation();
       
  7623 }
       
  7624 
       
  7625 static void flushCachedTemplateRelations()
       
  7626 {
       
  7627   // remove all references to classes from the cache
       
  7628   // as there can be new template instances in the inheritance path
       
  7629   // to this class. Optimization: only remove those classes that
       
  7630   // have inheritance instances as direct or indirect sub classes.
       
  7631   QCacheIterator<LookupInfo> ci(Doxygen::lookupCache);
       
  7632   LookupInfo *li=0;
       
  7633   for (ci.toFirst();(li=ci.current());++ci)
       
  7634   {
       
  7635     if (li->classDef)
       
  7636     {
       
  7637       Doxygen::lookupCache.remove(ci.currentKey());
       
  7638     }
       
  7639   }
       
  7640   // remove all cached typedef resolutions whose target is a
       
  7641   // template class as this may now be a template instance
       
  7642   MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict);
       
  7643   MemberName *fn;
       
  7644   for (;(fn=fnli.current());++fnli) // for each global function name
       
  7645   {
       
  7646     MemberNameIterator fni(*fn);
       
  7647     MemberDef *fmd;
       
  7648     for (;(fmd=fni.current());++fni) // for each function with that name
       
  7649     {
       
  7650       if (fmd->isTypedefValCached())
       
  7651       {
       
  7652         ClassDef *cd = fmd->getCachedTypedefVal();
       
  7653         if (cd->isTemplate()) fmd->invalidateTypedefValCache();
       
  7654       }
       
  7655     }
       
  7656   }
       
  7657   MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
       
  7658   for (;(fn=mnli.current());++mnli) // for each class method name
       
  7659   {
       
  7660     MemberNameIterator mni(*fn);
       
  7661     MemberDef *fmd;
       
  7662     for (;(fmd=mni.current());++mni) // for each function with that name
       
  7663     {
       
  7664       if (fmd->isTypedefValCached())
       
  7665       {
       
  7666         ClassDef *cd = fmd->getCachedTypedefVal();
       
  7667         if (cd->isTemplate()) fmd->invalidateTypedefValCache();
       
  7668       }
       
  7669     }
       
  7670   }
       
  7671 }
       
  7672 
       
  7673 //----------------------------------------------------------------------------
       
  7674 
       
  7675 static void flushUnresolvedRelations()
       
  7676 {
       
  7677   // Remove all unresolved references to classes from the cache.
       
  7678   // This is needed before resolving the inheritance relations, since
       
  7679   // it would otherwise not find the inheritance relation
       
  7680   // for C in the example below, as B::I was already found to be unresolvable 
       
  7681   // (which is correct if you igore the inheritance relation between A and B).
       
  7682   // 
       
  7683   // class A { class I {} };
       
  7684   // class B : public A {};
       
  7685   // class C : public B::I {};
       
  7686   //
       
  7687   QCacheIterator<LookupInfo> ci(Doxygen::lookupCache);
       
  7688   LookupInfo *li=0;
       
  7689   for (ci.toFirst();(li=ci.current());++ci)
       
  7690   {
       
  7691     if (li->classDef==0 && li->typeDef==0)
       
  7692     {
       
  7693       Doxygen::lookupCache.remove(ci.currentKey());
       
  7694     }
       
  7695   }
       
  7696 
       
  7697   MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict);
       
  7698   MemberName *fn;
       
  7699   for (;(fn=fnli.current());++fnli) // for each global function name
       
  7700   {
       
  7701     MemberNameIterator fni(*fn);
       
  7702     MemberDef *fmd;
       
  7703     for (;(fmd=fni.current());++fni) // for each function with that name
       
  7704     {
       
  7705       fmd->invalidateCachedArgumentTypes();
       
  7706     }
       
  7707   }
       
  7708   MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
       
  7709   for (;(fn=mnli.current());++mnli) // for each class method name
       
  7710   {
       
  7711     MemberNameIterator mni(*fn);
       
  7712     MemberDef *fmd;
       
  7713     for (;(fmd=mni.current());++mni) // for each function with that name
       
  7714     {
       
  7715       fmd->invalidateCachedArgumentTypes();
       
  7716     }
       
  7717   }
       
  7718 
       
  7719 }
       
  7720 
       
  7721 //----------------------------------------------------------------------------
       
  7722 
       
  7723 static void findDefineDocumentation(EntryNav *rootNav)
       
  7724 {
       
  7725   if ((rootNav->section()==Entry::DEFINEDOC_SEC ||
       
  7726        rootNav->section()==Entry::DEFINE_SEC) && !rootNav->name().isEmpty()
       
  7727      )
       
  7728   {
       
  7729     rootNav->loadEntry(g_storage);
       
  7730     Entry *root = rootNav->entry();
       
  7731     
       
  7732     //printf("found define `%s' `%s' brief=`%s' doc=`%s'\n",
       
  7733     //       root->name.data(),root->args.data(),root->brief.data(),root->doc.data());
       
  7734 
       
  7735     if (rootNav->tagInfo() && !root->name.isEmpty()) // define read from a tag file
       
  7736     {
       
  7737       MemberDef *md=new MemberDef("<tagfile>",1,
       
  7738                     "#define",root->name,root->args,0,
       
  7739                     Public,Normal,FALSE,Member,MemberDef::Define,0,0);
       
  7740       md->setTagInfo(rootNav->tagInfo());
       
  7741       //printf("Searching for `%s' fd=%p\n",filePathName.data(),fd);
       
  7742       md->setFileDef(rootNav->parent()->fileDef());
       
  7743       //printf("Adding member=%s\n",md->name().data());
       
  7744       MemberName *mn;
       
  7745       if ((mn=Doxygen::functionNameSDict->find(root->name)))
       
  7746       {
       
  7747         mn->append(md);
       
  7748       }
       
  7749       else 
       
  7750       {
       
  7751         mn = new MemberName(root->name);
       
  7752         mn->append(md);
       
  7753         Doxygen::functionNameSDict->append(root->name,mn);
       
  7754       }
       
  7755     }
       
  7756     MemberName *mn=Doxygen::functionNameSDict->find(root->name);
       
  7757     if (mn)
       
  7758     {
       
  7759       int count=0;
       
  7760       MemberDef *md=mn->first();
       
  7761       while (md)
       
  7762       {
       
  7763         if (md->memberType()==MemberDef::Define) count++;
       
  7764         md=mn->next();
       
  7765       }
       
  7766       if (count==1)
       
  7767       {
       
  7768         md=mn->first();
       
  7769         while (md)
       
  7770         {
       
  7771           if (md->memberType()==MemberDef::Define)
       
  7772           {
       
  7773 #if 0
       
  7774             if (md->documentation().isEmpty())
       
  7775 #endif
       
  7776             {
       
  7777               md->setDocumentation(root->doc,root->docFile,root->docLine);
       
  7778               md->setDocsForDefinition(!root->proto);
       
  7779             }
       
  7780 #if 0
       
  7781             if (md->briefDescription().isEmpty())
       
  7782 #endif
       
  7783             {
       
  7784               md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
       
  7785             }
       
  7786             if (md->inbodyDocumentation().isEmpty())
       
  7787             {
       
  7788               md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
       
  7789             }
       
  7790             md->setBodySegment(root->bodyLine,root->endBodyLine);
       
  7791             md->setBodyDef(rootNav->fileDef());
       
  7792             md->addSectionsToDefinition(root->anchors);
       
  7793             md->setMaxInitLines(root->initLines);
       
  7794             md->setRefItems(root->sli);
       
  7795             if (root->mGrpId!=-1) md->setMemberGroupId(root->mGrpId);
       
  7796             addMemberToGroups(root,md);
       
  7797           }
       
  7798           md=mn->next();
       
  7799         }
       
  7800       }
       
  7801       else if (count>1 && 
       
  7802                (!root->doc.isEmpty() || 
       
  7803                 !root->brief.isEmpty() || 
       
  7804                 root->bodyLine!=-1
       
  7805                )
       
  7806               ) 
       
  7807         // multiple defines don't know where to add docs
       
  7808         // but maybe they are in different files together with their documentation
       
  7809       {
       
  7810         md=mn->first();
       
  7811         while (md)
       
  7812         {
       
  7813           if (md->memberType()==MemberDef::Define)
       
  7814           {
       
  7815             FileDef *fd=md->getFileDef();
       
  7816             if (fd && fd->absFilePath()==root->fileName) 
       
  7817               // doc and define in the same file assume they belong together.
       
  7818             {
       
  7819 #if 0
       
  7820               if (md->documentation().isEmpty())
       
  7821 #endif
       
  7822               {
       
  7823                 md->setDocumentation(root->doc,root->docFile,root->docLine);
       
  7824                 md->setDocsForDefinition(!root->proto);
       
  7825               }
       
  7826 #if 0
       
  7827               if (md->briefDescription().isEmpty())
       
  7828 #endif
       
  7829               {
       
  7830                 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
       
  7831               }
       
  7832               if (md->inbodyDocumentation().isEmpty())
       
  7833               {
       
  7834                 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
       
  7835               }
       
  7836               md->setBodySegment(root->bodyLine,root->endBodyLine);
       
  7837               md->setBodyDef(rootNav->fileDef());
       
  7838               md->addSectionsToDefinition(root->anchors);
       
  7839               md->setRefItems(root->sli);
       
  7840               if (root->mGrpId!=-1) md->setMemberGroupId(root->mGrpId);
       
  7841               addMemberToGroups(root,md);
       
  7842             }
       
  7843           }
       
  7844           md=mn->next();
       
  7845         }
       
  7846         //warn("Warning: define %s found in the following files:\n",root->name.data());
       
  7847         //warn("Cannot determine where to add the documentation found "
       
  7848         //     "at line %d of file %s. \n",
       
  7849         //     root->startLine,root->fileName.data());
       
  7850       }
       
  7851     }
       
  7852     else if (!root->doc.isEmpty() || !root->brief.isEmpty()) // define not found
       
  7853     {
       
  7854       static bool preEnabled = Config_getBool("ENABLE_PREPROCESSING");
       
  7855       if (preEnabled)
       
  7856       {
       
  7857         warn(root->fileName,root->startLine,
       
  7858              "Warning: documentation for unknown define %s found.\n",
       
  7859              root->name.data()
       
  7860             );
       
  7861       }
       
  7862       else
       
  7863       {
       
  7864         warn(root->fileName,root->startLine,
       
  7865              "Warning: found documented #define but ignoring it because "
       
  7866              "ENABLE_PREPROCESSING is NO.\n",
       
  7867              root->name.data()
       
  7868             );
       
  7869       }
       
  7870     }
       
  7871 
       
  7872     rootNav->releaseEntry();
       
  7873   }
       
  7874   RECURSE_ENTRYTREE(findDefineDocumentation,rootNav);
       
  7875 }
       
  7876 
       
  7877 //----------------------------------------------------------------------------
       
  7878 
       
  7879 static void findDirDocumentation(EntryNav *rootNav)
       
  7880 {
       
  7881   if (rootNav->section() == Entry::DIRDOC_SEC)
       
  7882   {
       
  7883     rootNav->loadEntry(g_storage);
       
  7884     Entry *root = rootNav->entry();
       
  7885 
       
  7886     QCString normalizedName = root->name;
       
  7887     normalizedName = substitute(normalizedName,"\\","/");
       
  7888     if (normalizedName.at(normalizedName.length()-1)!='/')
       
  7889     {
       
  7890       normalizedName+='/';
       
  7891     }
       
  7892     DirDef *dir,*matchingDir=0;
       
  7893     SDict<DirDef>::Iterator sdi(*Doxygen::directories);
       
  7894     for (sdi.toFirst();(dir=sdi.current());++sdi)
       
  7895     {
       
  7896       //printf("Dir: %s<->%s\n",dir->name().data(),normalizedName.data());
       
  7897       if (dir->name().right(normalizedName.length())==normalizedName)
       
  7898       {
       
  7899         if (matchingDir)
       
  7900         {
       
  7901            warn(root->fileName,root->startLine,
       
  7902              "Warning: \\dir command matches multiple directories.\n"
       
  7903              "  Applying the command for directory %s\n"
       
  7904              "  Ignoring the command for directory %s\n",
       
  7905              matchingDir->name().data(),dir->name().data()
       
  7906            );
       
  7907         }
       
  7908         else
       
  7909         {
       
  7910           matchingDir=dir;
       
  7911         }
       
  7912       }
       
  7913     }
       
  7914     if (matchingDir)
       
  7915     {
       
  7916       //printf("Match for with dir %s\n",matchingDir->name().data());
       
  7917       matchingDir->setBriefDescription(root->brief,root->briefFile,root->briefLine);
       
  7918       matchingDir->setDocumentation(root->doc,root->docFile,root->docLine);
       
  7919       matchingDir->setRefItems(root->sli);
       
  7920       addDirToGroups(root,matchingDir);
       
  7921     }
       
  7922     else
       
  7923     {
       
  7924       warn(root->fileName,root->startLine,"Warning: No matching "
       
  7925           "directory found for command \\dir %s\n",root->name.data());
       
  7926     }
       
  7927     rootNav->releaseEntry();
       
  7928   }
       
  7929   RECURSE_ENTRYTREE(findDirDocumentation,rootNav);
       
  7930 }
       
  7931 
       
  7932 
       
  7933 //----------------------------------------------------------------------------
       
  7934 // create a (sorted) list of separate documentation pages
       
  7935 
       
  7936 static void buildPageList(EntryNav *rootNav)
       
  7937 {
       
  7938   if (rootNav->section() == Entry::PAGEDOC_SEC)
       
  7939   {
       
  7940     rootNav->loadEntry(g_storage);
       
  7941     Entry *root = rootNav->entry();
       
  7942 
       
  7943     if (!root->name.isEmpty())
       
  7944     {
       
  7945       addRelatedPage(rootNav);
       
  7946     }
       
  7947 
       
  7948     rootNav->releaseEntry();
       
  7949   }
       
  7950   else if (rootNav->section() == Entry::MAINPAGEDOC_SEC)
       
  7951   {
       
  7952     rootNav->loadEntry(g_storage);
       
  7953     Entry *root = rootNav->entry();
       
  7954 
       
  7955     QCString title=root->args.stripWhiteSpace();
       
  7956     if (title.isEmpty()) title=theTranslator->trMainPage();
       
  7957     QCString name = Config_getBool("GENERATE_TREEVIEW")?"main":"index";
       
  7958     addRefItem(root->sli,
       
  7959                name,
       
  7960                "page",
       
  7961                name,
       
  7962                title,
       
  7963                0
       
  7964                );
       
  7965 
       
  7966     rootNav->releaseEntry();
       
  7967   }
       
  7968   RECURSE_ENTRYTREE(buildPageList,rootNav);
       
  7969 }
       
  7970 
       
  7971 static void findMainPage(EntryNav *rootNav)
       
  7972 {
       
  7973   if (rootNav->section() == Entry::MAINPAGEDOC_SEC)
       
  7974   {
       
  7975     rootNav->loadEntry(g_storage);
       
  7976     Entry *root = rootNav->entry();
       
  7977 
       
  7978     if (Doxygen::mainPage==0)
       
  7979     {
       
  7980       //printf("Found main page! \n======\n%s\n=======\n",root->doc.data());
       
  7981       QCString title=root->args.stripWhiteSpace();
       
  7982       QCString indexName=Config_getBool("GENERATE_TREEVIEW")?"main":"index";
       
  7983       Doxygen::mainPage = new PageDef(root->fileName,root->startLine,
       
  7984                               indexName, root->brief+root->doc+root->inbodyDocs,title);
       
  7985       //setFileNameForSections(root->anchors,"index",Doxygen::mainPage);
       
  7986       Doxygen::mainPage->setFileName(indexName);
       
  7987       addPageToContext(Doxygen::mainPage,rootNav);
       
  7988           
       
  7989       // a page name is a label as well!
       
  7990       SectionInfo *si=new SectionInfo(
       
  7991           indexName,
       
  7992           Doxygen::mainPage->name(),
       
  7993           Doxygen::mainPage->title(),
       
  7994           SectionInfo::Page);
       
  7995       Doxygen::sectionDict.insert(indexName,si);
       
  7996       Doxygen::mainPage->addSectionsToDefinition(root->anchors);
       
  7997     }
       
  7998     else
       
  7999     {
       
  8000       warn(root->fileName,root->startLine,
       
  8001            "Warning: found more than one \\mainpage comment block! Skipping this "
       
  8002            "block."
       
  8003           );
       
  8004     }
       
  8005 
       
  8006     rootNav->releaseEntry();
       
  8007   }
       
  8008   RECURSE_ENTRYTREE(findMainPage,rootNav);
       
  8009 }
       
  8010 
       
  8011 static void computePageRelations(EntryNav *rootNav)
       
  8012 {
       
  8013   if ((rootNav->section()==Entry::PAGEDOC_SEC || 
       
  8014        rootNav->section()==Entry::MAINPAGEDOC_SEC
       
  8015       )
       
  8016       && !rootNav->name().isEmpty()
       
  8017      )
       
  8018   {
       
  8019     rootNav->loadEntry(g_storage);
       
  8020     Entry *root = rootNav->entry();
       
  8021 
       
  8022     PageDef *pd = root->section==Entry::PAGEDOC_SEC ?
       
  8023                     Doxygen::pageSDict->find(root->name) : 
       
  8024                     Doxygen::mainPage; 
       
  8025     if (pd)
       
  8026     {
       
  8027       QListIterator<BaseInfo> bii(*root->extends);
       
  8028       BaseInfo *bi;
       
  8029       for (bii.toFirst();(bi=bii.current());++bii)
       
  8030       {
       
  8031         PageDef *subPd = Doxygen::pageSDict->find(bi->name);
       
  8032         if (subPd)
       
  8033         {
       
  8034           pd->addInnerCompound(subPd);
       
  8035           //printf("*** Added subpage relation: %s->%s\n",
       
  8036           //    pd->name().data(),subPd->name().data());
       
  8037         }
       
  8038       }
       
  8039     }
       
  8040 
       
  8041     rootNav->releaseEntry();
       
  8042   }
       
  8043   RECURSE_ENTRYTREE(computePageRelations,rootNav);
       
  8044 }
       
  8045 
       
  8046 static void checkPageRelations()
       
  8047 {
       
  8048   PageSDict::Iterator pdi(*Doxygen::pageSDict);
       
  8049   PageDef *pd=0;
       
  8050   for (pdi.toFirst();(pd=pdi.current());++pdi)
       
  8051   {
       
  8052     Definition *ppd = pd->getOuterScope();
       
  8053     while (ppd)
       
  8054     {
       
  8055       if (ppd==pd)
       
  8056       {
       
  8057         err("Warning: page defined at line %d of file %s with label %s is a subpage "
       
  8058             "of itself! Please remove this cyclic dependency.\n",
       
  8059             pd->docLine(),pd->docFile().data(),pd->name().data());
       
  8060         exit(1);
       
  8061       }
       
  8062       ppd=ppd->getOuterScope();
       
  8063     }
       
  8064   }
       
  8065 }
       
  8066 
       
  8067 //----------------------------------------------------------------------------
       
  8068 
       
  8069 static void resolveUserReferences()
       
  8070 {
       
  8071   QDictIterator<SectionInfo> sdi(Doxygen::sectionDict);
       
  8072   SectionInfo *si;
       
  8073   for (;(si=sdi.current());++sdi)
       
  8074   {
       
  8075     //printf("si->label=`%s' si->definition=%s si->fileName=`%s'\n",
       
  8076     //        si->label.data(),si->definition?si->definition->name().data():"<none>",
       
  8077     //        si->fileName.data());
       
  8078     PageDef *pd=0;
       
  8079 
       
  8080     // hack: the items of a todo/test/bug/deprecated list are all fragments from 
       
  8081     // different files, so the resulting section's all have the wrong file 
       
  8082     // name (not from the todo/test/bug/deprecated list, but from the file in 
       
  8083     // which they are defined). We correct this here by looking at the 
       
  8084     // generated section labels!
       
  8085     QDictIterator<RefList> rli(*Doxygen::xrefLists);
       
  8086     RefList *rl;
       
  8087     for (rli.toFirst();(rl=rli.current());++rli)
       
  8088     {
       
  8089       QCString label="_"+rl->listName(); // "_todo", "_test", ...
       
  8090       if (si->label.left(label.length())==label)
       
  8091       {
       
  8092         si->fileName=rl->listName();
       
  8093         si->generated=TRUE;
       
  8094         break;
       
  8095       }
       
  8096     }
       
  8097 
       
  8098     //printf("start: si->label=%s si->fileName=%s\n",si->label.data(),si->fileName.data());
       
  8099     if (!si->generated)
       
  8100     {
       
  8101       // if this section is in a page and the page is in a group, then we
       
  8102       // have to adjust the link file name to point to the group.
       
  8103       if (!si->fileName.isEmpty() && 
       
  8104           (pd=Doxygen::pageSDict->find(si->fileName)) &&
       
  8105           pd->getGroupDef())
       
  8106       {
       
  8107         si->fileName=pd->getGroupDef()->getOutputFileBase().copy();
       
  8108       }
       
  8109 
       
  8110       if (si->definition)
       
  8111       {
       
  8112         // TODO: there should be one function in Definition that returns
       
  8113         // the file to link to, so we can avoid the following tests.
       
  8114         GroupDef *gd=0;
       
  8115         if (si->definition->definitionType()==Definition::TypeMember)
       
  8116         {
       
  8117           gd = ((MemberDef *)si->definition)->getGroupDef();
       
  8118         }
       
  8119 
       
  8120         if (gd)
       
  8121         {
       
  8122           si->fileName=gd->getOutputFileBase().copy();
       
  8123         }
       
  8124         else
       
  8125         {
       
  8126           //si->fileName=si->definition->getOutputFileBase().copy();
       
  8127           //printf("Setting si->fileName to %s\n",si->fileName.data());
       
  8128         }
       
  8129       }
       
  8130     }
       
  8131     //printf("end: si->label=%s si->fileName=%s\n",si->label.data(),si->fileName.data());
       
  8132   }
       
  8133 }
       
  8134 
       
  8135 
       
  8136 //----------------------------------------------------------------------------
       
  8137 // generate all separate documentation pages
       
  8138 
       
  8139 
       
  8140 static void generatePageDocs()
       
  8141 {
       
  8142   //printf("documentedPages=%d real=%d\n",documentedPages,Doxygen::pageSDict->count());
       
  8143   if (documentedPages==0) return;
       
  8144   PageSDict::Iterator pdi(*Doxygen::pageSDict);
       
  8145   PageDef *pd=0;
       
  8146   for (pdi.toFirst();(pd=pdi.current());++pdi)
       
  8147   {
       
  8148     if (!pd->getGroupDef() && !pd->isReference())
       
  8149     {
       
  8150       msg("Generating docs for page %s...\n",pd->name().data());
       
  8151       Doxygen::insideMainPage=TRUE;
       
  8152       pd->writeDocumentation(*g_outputList);
       
  8153       Doxygen::insideMainPage=FALSE;
       
  8154     }
       
  8155   }
       
  8156 }
       
  8157 
       
  8158 //----------------------------------------------------------------------------
       
  8159 // create a (sorted) list & dictionary of example pages
       
  8160 
       
  8161 static void buildExampleList(EntryNav *rootNav)
       
  8162 {
       
  8163   if (rootNav->section()==Entry::EXAMPLE_SEC && !rootNav->name().isEmpty()) 
       
  8164   {
       
  8165     rootNav->loadEntry(g_storage);
       
  8166     Entry *root = rootNav->entry();
       
  8167 
       
  8168     if (Doxygen::exampleSDict->find(root->name))
       
  8169     {
       
  8170       warn(root->fileName,root->startLine,
       
  8171           "Warning: Example %s was already documented. Ignoring "
       
  8172           "documentation found here.",
       
  8173           root->name.data()
       
  8174           );
       
  8175     }
       
  8176     else
       
  8177     {
       
  8178       PageDef *pd=new PageDef(root->fileName,root->startLine,
       
  8179           root->name,root->brief+root->doc+root->inbodyDocs,root->args);
       
  8180       pd->setFileName(convertNameToFile(pd->name()+"-example"));
       
  8181       pd->addSectionsToDefinition(root->anchors);
       
  8182       //pi->addSections(root->anchors);
       
  8183 
       
  8184       Doxygen::exampleSDict->inSort(root->name,pd);
       
  8185       //we don't add example to groups 
       
  8186       //addExampleToGroups(root,pd);
       
  8187     }
       
  8188 
       
  8189     rootNav->releaseEntry();
       
  8190   }
       
  8191   RECURSE_ENTRYTREE(buildExampleList,rootNav);
       
  8192 }
       
  8193 
       
  8194 //----------------------------------------------------------------------------
       
  8195 // prints the Entry tree (for debugging)
       
  8196 
       
  8197 void printNavTree(EntryNav *rootNav,int indent)
       
  8198 {
       
  8199   QCString indentStr;
       
  8200   indentStr.fill(' ',indent);
       
  8201   msg("%s%s (sec=0x%x)\n",
       
  8202       indentStr.isEmpty()?"":indentStr.data(),
       
  8203       rootNav->name().isEmpty()?"<empty>":rootNav->name().data(),
       
  8204       rootNav->section());
       
  8205   if (rootNav->children()) 
       
  8206   {
       
  8207     EntryNavListIterator eli(*rootNav->children());
       
  8208     for (;eli.current();++eli) printNavTree(eli.current(),indent+2);
       
  8209   }
       
  8210 }
       
  8211 
       
  8212 
       
  8213 //----------------------------------------------------------------------------
       
  8214 // generate the example documentation 
       
  8215 
       
  8216 static void generateExampleDocs()
       
  8217 {
       
  8218   g_outputList->disable(OutputGenerator::Man);
       
  8219   PageSDict::Iterator pdi(*Doxygen::exampleSDict);
       
  8220   PageDef *pd=0;
       
  8221   for (pdi.toFirst();(pd=pdi.current());++pdi)
       
  8222   {
       
  8223     msg("Generating docs for example %s...\n",pd->name().data());
       
  8224     resetCCodeParserState();
       
  8225     QCString n=pd->getOutputFileBase();
       
  8226     startFile(*g_outputList,n,n,pd->name());
       
  8227     startTitle(*g_outputList,n);
       
  8228     g_outputList->docify(pd->name());
       
  8229     endTitle(*g_outputList,n,0);
       
  8230     g_outputList->parseDoc(pd->docFile(),                            // file
       
  8231                          pd->docLine(),                            // startLine
       
  8232                          pd,                                       // context
       
  8233                          0,                                        // memberDef
       
  8234                          pd->documentation()+"\n\n\\include "+pd->name(),          // docs
       
  8235                          TRUE,                                     // index words
       
  8236                          TRUE,                                     // is example
       
  8237                          pd->name()
       
  8238                         );
       
  8239     endFile(*g_outputList);
       
  8240   }
       
  8241   g_outputList->enable(OutputGenerator::Man);
       
  8242 }
       
  8243 
       
  8244 //----------------------------------------------------------------------------
       
  8245 // generate module pages
       
  8246 
       
  8247 static void generateGroupDocs()
       
  8248 {
       
  8249   GroupSDict::Iterator gli(*Doxygen::groupSDict);
       
  8250   GroupDef *gd;
       
  8251   for (gli.toFirst();(gd=gli.current());++gli)
       
  8252   {
       
  8253     if (!gd->isReference())
       
  8254     {
       
  8255       gd->writeDocumentation(*g_outputList);
       
  8256     }
       
  8257   }
       
  8258 }
       
  8259 
       
  8260 //----------------------------------------------------------------------------
       
  8261 
       
  8262 //static void generatePackageDocs()
       
  8263 //{
       
  8264 //  writePackageIndex(*g_outputList);
       
  8265 //  
       
  8266 //  if (Doxygen::packageDict.count()>0)
       
  8267 //  {
       
  8268 //    PackageSDict::Iterator pdi(Doxygen::packageDict);
       
  8269 //    PackageDef *pd;
       
  8270 //    for (pdi.toFirst();(pd=pdi.current());++pdi)
       
  8271 //    {
       
  8272 //      pd->writeDocumentation(*g_outputList);
       
  8273 //    }
       
  8274 //  }
       
  8275 //}
       
  8276 
       
  8277 //----------------------------------------------------------------------------
       
  8278 // generate module pages
       
  8279 
       
  8280 static void generateNamespaceDocs()
       
  8281 {
       
  8282   writeNamespaceIndex(*g_outputList);
       
  8283   
       
  8284   NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
       
  8285   NamespaceDef *nd;
       
  8286   // for each namespace...
       
  8287   for (;(nd=nli.current());++nli)
       
  8288   {
       
  8289 
       
  8290     if (nd->isLinkableInProject())
       
  8291     {
       
  8292       msg("Generating docs for namespace %s\n",nd->name().data());
       
  8293       nd->writeDocumentation(*g_outputList);
       
  8294     }
       
  8295 
       
  8296     // for each class in the namespace...
       
  8297     ClassSDict::Iterator cli(*nd->getClassSDict());
       
  8298     for ( ; cli.current() ; ++cli )
       
  8299     {
       
  8300       ClassDef *cd=cli.current();
       
  8301       if ( ( cd->isLinkableInProject() && 
       
  8302              cd->templateMaster()==0
       
  8303            ) // skip external references, anonymous compounds and 
       
  8304              // template instances and nested classes
       
  8305            && !cd->isHidden()
       
  8306          )
       
  8307       {
       
  8308         msg("Generating docs for compound %s...\n",cd->name().data());
       
  8309 
       
  8310         cd->writeDocumentation(*g_outputList);
       
  8311         cd->writeMemberList(*g_outputList);
       
  8312       }
       
  8313       cd->writeDocumentationForInnerClasses(*g_outputList);
       
  8314     }
       
  8315   }
       
  8316 }
       
  8317 
       
  8318 #if defined(_WIN32)
       
  8319 static QCString fixSlashes(QCString &s)
       
  8320 {
       
  8321   QCString result;
       
  8322   uint i;
       
  8323   for (i=0;i<s.length();i++)
       
  8324   {
       
  8325     switch(s.at(i))
       
  8326     {
       
  8327       case '/': 
       
  8328       case '\\': 
       
  8329         result+="\\\\"; 
       
  8330         break;
       
  8331       default:
       
  8332         result+=s.at(i);
       
  8333     }
       
  8334   }
       
  8335   return result;
       
  8336 }
       
  8337 #endif
       
  8338 
       
  8339 
       
  8340 //----------------------------------------------------------------------------
       
  8341 // generate files for the search engine
       
  8342 
       
  8343 //static void generateSearchIndex()
       
  8344 //{
       
  8345 //  if (Config_getBool("SEARCHENGINE") && Config_getBool("GENERATE_HTML"))
       
  8346 //  {
       
  8347 //    // create search index
       
  8348 //    QCString fileName;
       
  8349 //    writeSearchButton(Config_getString("HTML_OUTPUT"));
       
  8350 //
       
  8351 //#if !defined(_WIN32)
       
  8352 //    // create cgi script
       
  8353 //    fileName = Config_getString("HTML_OUTPUT")+"/"+Config_getString("CGI_NAME");
       
  8354 //    QFile f(fileName);
       
  8355 //    if (f.open(IO_WriteOnly))
       
  8356 //    {
       
  8357 //      QTextStream t(&f);
       
  8358 //      t << "#!/bin/sh"   << endl
       
  8359 //        << "DOXYSEARCH=" << Config_getString("BIN_ABSPATH") << "/doxysearch" << endl
       
  8360 //        << "DOXYPATH=\"" << Config_getString("DOC_ABSPATH") << " ";
       
  8361 //
       
  8362 //      QStrList &extDocPaths=Config_getList("EXT_DOC_PATHS");
       
  8363 //      char *s= extDocPaths.first();
       
  8364 //      while (s)
       
  8365 //      {
       
  8366 //        t << s << " ";
       
  8367 //        s=extDocPaths.next();
       
  8368 //      }
       
  8369 //
       
  8370 //      t << "\"" << endl 
       
  8371 //        << "if [ -f $DOXYSEARCH ]" << endl
       
  8372 //        << "then" << endl
       
  8373 //        << "  $DOXYSEARCH $DOXYPATH" << endl 
       
  8374 //        << "else" << endl
       
  8375 //        << "  echo \"Content-Type: text/html\"" << endl
       
  8376 //        << "  echo \"\"" << endl
       
  8377 //        << "  echo \"<h2>Error: $DOXYSEARCH not found. Check cgi script!</h2>\"" << endl
       
  8378 //        << "fi" << endl;
       
  8379 //
       
  8380 //      f.close();
       
  8381 //      struct stat stat_struct;
       
  8382 //      stat(fileName,&stat_struct);
       
  8383 //      chmod(fileName,stat_struct.st_mode|S_IXUSR|S_IXGRP|S_IXOTH);
       
  8384 //    }
       
  8385 //    else
       
  8386 //    {
       
  8387 //      err("Error: Cannot open file %s for writing\n",fileName.data());
       
  8388 //    }
       
  8389 //#else /* Windows platform */
       
  8390 //    // create cgi program
       
  8391 //    fileName = Config_getString("CGI_NAME").copy();
       
  8392 //    if (fileName.right(4)==".cgi") 
       
  8393 //      fileName=fileName.left(fileName.length()-4);
       
  8394 //    fileName+=".c";
       
  8395 //    fileName.prepend(Config_getString("HTML_OUTPUT")+"/");
       
  8396 //    QFile f(fileName);
       
  8397 //    if (f.open(IO_WriteOnly))
       
  8398 //    {
       
  8399 //      QTextStream t(&f);
       
  8400 //      t << "#include <stdio.h>" << endl;
       
  8401 //      t << "#include <stdlib.h>" << endl;
       
  8402 //      t << "#include <process.h>" << endl;
       
  8403 //      t << endl;
       
  8404 //      t << "const char *DOXYSEARCH = \"" << 
       
  8405 //           fixSlashes(Config_getString("BIN_ABSPATH")) << "\\\\doxysearch.exe\";" << endl;
       
  8406 //      t << "const char *DOXYPATH = \"" << 
       
  8407 //           fixSlashes(Config_getString("DOC_ABSPATH")) << "\";" << endl;
       
  8408 //      t << endl;
       
  8409 //      t << "int main(void)" << endl;
       
  8410 //      t << "{" << endl;
       
  8411 //      t << "  char buf[1024];" << endl;
       
  8412 //      t << "  sprintf(buf,\"%s %s\",DOXYSEARCH,DOXYPATH);" << endl; 
       
  8413 //      t << "  if (system(buf))" << endl;
       
  8414 //      t << "  {" << endl;
       
  8415 //      t << "    printf(\"Content-Type: text/html\\n\\n\");" << endl;
       
  8416 //      t << "    printf(\"<h2>Error: failed to execute %s</h2>\\n\",DOXYSEARCH);" << endl;
       
  8417 //      t << "    exit(1);" << endl;
       
  8418 //      t << "  }" << endl;
       
  8419 //      t << "  return 0;" << endl;
       
  8420 //      t << "}" << endl;
       
  8421 //      f.close();
       
  8422 //    }
       
  8423 //    else
       
  8424 //    {
       
  8425 //      err("Error: Cannot open file %s for writing\n",fileName.data());
       
  8426 //    }
       
  8427 //#endif /* !defined(_WIN32) */
       
  8428 //    
       
  8429 //    // create config file
       
  8430 //    fileName = Config_getString("HTML_OUTPUT")+"/search.cfg";
       
  8431 //    f.setName(fileName);
       
  8432 //    if (f.open(IO_WriteOnly))
       
  8433 //    {
       
  8434 //      QTextStream t(&f);
       
  8435 //      t << Config_getString("DOC_URL") << "/" << endl 
       
  8436 //        << Config_getString("CGI_URL") << "/" << Config_getString("CGI_NAME") << endl;
       
  8437 //      f.close();
       
  8438 //    }
       
  8439 //    else
       
  8440 //    {
       
  8441 //      err("Error: Cannot open file %s for writing\n",fileName.data());
       
  8442 //    }
       
  8443 //    //g_outputList->generateExternalIndex();
       
  8444 //    g_outputList->pushGeneratorState();
       
  8445 //    g_outputList->disableAllBut(OutputGenerator::Html);
       
  8446 //    startFile(*g_outputList,"header"+Doxygen::htmlFileExtension,0,"Search Engine",TRUE);
       
  8447 //    g_outputList->endPlainFile();
       
  8448 //    g_outputList->startPlainFile("footer"+Doxygen::htmlFileExtension);
       
  8449 //    endFile(*g_outputList,TRUE);
       
  8450 //    g_outputList->popGeneratorState();
       
  8451 //  }
       
  8452 //}
       
  8453 
       
  8454 //----------------------------------------------------------------------------
       
  8455 
       
  8456 static bool openOutputFile(const char *outFile,QFile &f)
       
  8457 {
       
  8458   bool fileOpened=FALSE;
       
  8459   bool writeToStdout=(outFile[0]=='-' && outFile[1]=='\0');
       
  8460   if (writeToStdout) // write to stdout
       
  8461   {
       
  8462     fileOpened = f.open(IO_WriteOnly,stdout);
       
  8463   }
       
  8464   else // write to file
       
  8465   {
       
  8466     QFileInfo fi(outFile);
       
  8467     if (fi.exists()) // create a backup
       
  8468     {
       
  8469       QDir dir=fi.dir();
       
  8470       QFileInfo backup(fi.fileName()+".bak");
       
  8471       if (backup.exists()) // remove existing backup
       
  8472         dir.remove(backup.fileName());
       
  8473       dir.rename(fi.fileName(),fi.fileName()+".bak");
       
  8474     } 
       
  8475     f.setName(outFile);
       
  8476     fileOpened = f.open(IO_WriteOnly|IO_Translate);
       
  8477   }
       
  8478   return fileOpened;
       
  8479 }
       
  8480 
       
  8481 /*! Generate a template version of the configuration file.
       
  8482  *  If the \a shortList parameter is TRUE a configuration file without
       
  8483  *  comments will be generated.
       
  8484  */
       
  8485 static void generateConfigFile(const char *configFile,bool shortList,
       
  8486                                bool updateOnly=FALSE)
       
  8487 {
       
  8488   QFile f;
       
  8489   bool fileOpened=openOutputFile(configFile,f);
       
  8490   bool writeToStdout=(configFile[0]=='-' && configFile[1]=='\0');
       
  8491   if (fileOpened)
       
  8492   {
       
  8493     QTextStream t(&f);
       
  8494     t.setEncoding(QTextStream::UnicodeUTF8);
       
  8495     Config::instance()->writeTemplate(t,shortList,updateOnly);
       
  8496     if (!writeToStdout)
       
  8497     {
       
  8498       if (!updateOnly)
       
  8499       {
       
  8500         msg("\n\nConfiguration file `%s' created.\n\n",configFile);
       
  8501         msg("Now edit the configuration file and enter\n\n");
       
  8502         if (strcmp(configFile,"Doxyfile") || strcmp(configFile,"doxyfile"))
       
  8503           msg("  doxygen %s\n\n",configFile);
       
  8504         else
       
  8505           msg("  doxygen\n\n");
       
  8506         msg("to generate the documentation for your project\n\n");
       
  8507       }
       
  8508       else
       
  8509       {
       
  8510         msg("\n\nConfiguration file `%s' updated.\n\n",configFile);
       
  8511       }
       
  8512     }
       
  8513   }
       
  8514   else
       
  8515   {
       
  8516     err("Error: Cannot open file %s for writing\n",configFile);
       
  8517     exit(1);
       
  8518   }
       
  8519 }
       
  8520 
       
  8521 //----------------------------------------------------------------------------
       
  8522 // read and parse a tag file
       
  8523 
       
  8524 //static bool readLineFromFile(QFile &f,QCString &s)
       
  8525 //{
       
  8526 //  char c=0;
       
  8527 //  s.resize(0);
       
  8528 //  while (!f.atEnd() && (c=f.getch())!='\n') s+=c;
       
  8529 //  return f.atEnd();
       
  8530 //}
       
  8531 
       
  8532 //----------------------------------------------------------------------------
       
  8533 
       
  8534 static void readTagFile(Entry *root,const char *tl)
       
  8535 {
       
  8536   QCString tagLine = tl;
       
  8537   QCString fileName;
       
  8538   QCString destName;
       
  8539   int eqPos = tagLine.find('=');
       
  8540   if (eqPos!=-1) // tag command contains a destination
       
  8541   {
       
  8542     fileName = tagLine.left(eqPos).stripWhiteSpace();
       
  8543     destName = tagLine.right(tagLine.length()-eqPos-1).stripWhiteSpace();
       
  8544     QFileInfo fi(fileName);
       
  8545     Doxygen::tagDestinationDict.insert(fi.fileName(),new QCString(destName));
       
  8546     //printf("insert tagDestination %s->%s\n",fi.fileName().data(),destName.data());
       
  8547   }
       
  8548   else
       
  8549   {
       
  8550     fileName = tagLine;
       
  8551   }
       
  8552     
       
  8553   QFileInfo fi(fileName);
       
  8554   if (!fi.exists() || !fi.isFile())
       
  8555   {
       
  8556     err("Error: Tag file `%s' does not exist or is not a file. Skipping it...\n",
       
  8557         fileName.data());
       
  8558     return;
       
  8559   }
       
  8560 
       
  8561   if (!destName.isEmpty())
       
  8562     msg("Reading tag file `%s', location `%s'...\n",fileName.data(),destName.data());
       
  8563   else
       
  8564     msg("Reading tag file `%s'...\n",fileName.data());
       
  8565 
       
  8566   parseTagFile(root,fi.absFilePath(),fi.fileName());
       
  8567 
       
  8568 }
       
  8569 
       
  8570 //----------------------------------------------------------------------------
       
  8571 // returns TRUE if the name of the file represented by `fi' matches
       
  8572 // one of the file patterns in the `patList' list.
       
  8573 
       
  8574 static bool patternMatch(QFileInfo *fi,QStrList *patList)
       
  8575 {
       
  8576   bool found=FALSE;
       
  8577   if (patList)
       
  8578   { 
       
  8579     QCString pattern=patList->first();
       
  8580     while (!pattern.isEmpty() && !found)
       
  8581     {
       
  8582       int i=pattern.find('=');
       
  8583       if (i!=-1) pattern=pattern.left(i); // strip of the extension specific filter name
       
  8584 
       
  8585 #if defined(_WIN32) // windows
       
  8586       QRegExp re(pattern,FALSE,TRUE); // case insensitive match 
       
  8587 #else                // unix
       
  8588       QRegExp re(pattern,TRUE,TRUE);  // case sensitive match
       
  8589 #endif
       
  8590       found = found || re.match(fi->fileName())!=-1 || 
       
  8591                        re.match(fi->filePath())!=-1 ||
       
  8592                        re.match(fi->absFilePath())!=-1;
       
  8593       //printf("Matching `%s' against pattern `%s' found=%d\n",
       
  8594       //    fi->fileName().data(),pattern.data(),found);
       
  8595       pattern=patList->next();
       
  8596     }
       
  8597   }
       
  8598   return found;
       
  8599 }
       
  8600 
       
  8601 //----------------------------------------------------------------------------
       
  8602 static void copyStyleSheet()
       
  8603 {
       
  8604   QCString &htmlStyleSheet = Config_getString("HTML_STYLESHEET");
       
  8605   if (!htmlStyleSheet.isEmpty())
       
  8606   {
       
  8607     QFile cssf(htmlStyleSheet);
       
  8608     QFileInfo cssfi(htmlStyleSheet);
       
  8609     if (cssf.open(IO_ReadOnly))
       
  8610     {
       
  8611       QCString destFileName = Config_getString("HTML_OUTPUT")+"/"+cssfi.fileName().data();
       
  8612       QFile df(destFileName);
       
  8613       if (df.open(IO_WriteOnly))
       
  8614       {
       
  8615         char *buffer = new char[cssf.size()];
       
  8616         cssf.readBlock(buffer,cssf.size());
       
  8617         df.writeBlock(buffer,cssf.size());
       
  8618         df.flush();
       
  8619         delete[] buffer;
       
  8620       }
       
  8621       else
       
  8622       {
       
  8623         err("Error: could not write to style sheet %s\n",destFileName.data());
       
  8624       }
       
  8625     }
       
  8626     else
       
  8627     {
       
  8628       err("Error: could not open user specified style sheet %s\n",Config_getString("HTML_STYLESHEET").data());
       
  8629       htmlStyleSheet.resize(0); // revert to the default
       
  8630     }
       
  8631   }
       
  8632 }
       
  8633 
       
  8634 static void reportParseFileSize(const QCString *fileName, const BufStr &theBuf)
       
  8635 {
       
  8636 	int numLines = 1;
       
  8637 	int numWs = 0;
       
  8638 	int byteCount = 0;
       
  8639 	for (int i=0; i < theBuf.size(); ++i) {
       
  8640 		if ('\n' == theBuf.at(i)) {
       
  8641 			++numLines;
       
  8642 		} else if (' ' == theBuf.at(i)) {
       
  8643 			++numWs;
       
  8644 		}
       
  8645 		++byteCount;
       
  8646 		//if ('\0' == theBuf.at(i)) {
       
  8647 		//	break;
       
  8648 		//}
       
  8649 	}
       
  8650 	msg("Have input for \"%s\", bytes=%d, buffer size=%d bytes, lines=%d ws=%d\n",
       
  8651 		fileName->data(),
       
  8652 		byteCount,
       
  8653 		theBuf.size(),
       
  8654 		numLines,
       
  8655 		numWs);
       
  8656 }
       
  8657 
       
  8658 //! parse the list of input files
       
  8659 static void parseFiles(Entry *root,EntryNav *rootNav)
       
  8660 {
       
  8661 #if 0
       
  8662   void *cd = 0;
       
  8663   QCString inpEncoding = Config_getString("INPUT_ENCODING");
       
  8664   bool needsTranscoding = !inpEncoding.isEmpty();
       
  8665   if (needsTranscoding)
       
  8666   {
       
  8667     if (!(cd = portable_iconv_open("UTF-8", inpEncoding)))
       
  8668     {
       
  8669        err("Error: unsupported character enconding: '%s'",inpEncoding.data());
       
  8670        exit(1);
       
  8671     }
       
  8672   }
       
  8673 #endif
       
  8674 
       
  8675   QCString *s=g_inputFiles.first();
       
  8676   while (s)
       
  8677   {
       
  8678     QCString fileName=*s;
       
  8679     QCString extension;
       
  8680     int ei = fileName.findRev('.');
       
  8681     if (ei!=-1) extension=fileName.right(fileName.length()-ei);
       
  8682     ParserInterface *parser = Doxygen::parserManager->getParser(extension);
       
  8683 
       
  8684     QFileInfo fi(fileName);
       
  8685     BufStr preBuf(fi.size()+4096);
       
  8686 
       
  8687     if (Config_getBool("ENABLE_PREPROCESSING") && 
       
  8688         parser->needsPreprocessing(extension))
       
  8689     {
       
  8690       BufStr inBuf(fi.size()+4096);
       
  8691       msg("Preprocessing %s...\n",s->data());
       
  8692       readInputFile(fileName,inBuf);
       
  8693       preprocessFile(fileName,inBuf,preBuf);
       
  8694     }
       
  8695     else // no preprocessing
       
  8696     {
       
  8697       msg("Reading %s...\n",s->data());
       
  8698       readInputFile(fileName,preBuf);
       
  8699     }
       
  8700 	reportParseFileSize(s, preBuf);
       
  8701     BufStr convBuf(preBuf.curPos()+1024);
       
  8702 
       
  8703     // convert multi-line C++ comments to C style comments
       
  8704     convertCppComments(&preBuf,&convBuf,fileName);
       
  8705 
       
  8706     convBuf.addChar('\0');
       
  8707 
       
  8708     // use language parse to parse the file
       
  8709     parser->parseInput(fileName,convBuf.data(),root);
       
  8710 
       
  8711     // store the Entry tree in a file and create an index to
       
  8712     // navigate/load entries
       
  8713     bool ambig;
       
  8714     FileDef *fd=findFileDef(Doxygen::inputNameDict,fileName,ambig);
       
  8715     ASSERT(fd!=0);
       
  8716     root->createNavigationIndex(rootNav,g_storage,fd);
       
  8717 
       
  8718     s=g_inputFiles.next();
       
  8719   }
       
  8720 }
       
  8721 
       
  8722 // resolves a path that may include symlinks, if a recursive symlink is
       
  8723 // found an empty string is returned.
       
  8724 static QCString resolveSymlink(QCString path)
       
  8725 {
       
  8726   int sepPos=0;
       
  8727   QFileInfo fi;
       
  8728   QDict<void> nonSymlinks;
       
  8729   QDict<void> known;
       
  8730   QCString result = path;
       
  8731   QCString oldPrefix = "/";
       
  8732   do
       
  8733   {
       
  8734 #ifdef WIN32
       
  8735     // UNC path, skip server and share name
       
  8736     if (sepPos==0 && (result.left(2)=="//" || result.left(2)=="\\\\")) 
       
  8737       sepPos = result.find('/',2);
       
  8738     if (sepPos!=-1) 
       
  8739       sepPos = result.find('/',sepPos+1);
       
  8740 #else
       
  8741     sepPos = result.find('/',sepPos+1);
       
  8742 #endif
       
  8743     QCString prefix = sepPos==-1 ? result : result.left(sepPos);
       
  8744     if (nonSymlinks.find(prefix)==0)
       
  8745     {
       
  8746       fi.setFile(prefix);
       
  8747       if (fi.isSymLink())
       
  8748       {
       
  8749         QString target = fi.readLink();
       
  8750         if (QFileInfo(target).isRelative())
       
  8751         {
       
  8752           target = QDir::cleanDirPath(oldPrefix+"/"+target.data());
       
  8753         }
       
  8754         if (sepPos!=-1)
       
  8755         {
       
  8756           if (fi.isDir() && target.length()>0 && target.at(target.length()-1)!='/')
       
  8757           {
       
  8758             target+='/';
       
  8759           }
       
  8760           target+=result.mid(sepPos);
       
  8761         }
       
  8762         result = QDir::cleanDirPath(target).data();
       
  8763         sepPos = 0;
       
  8764         if (known.find(result)) return QCString(); // recursive symlink!
       
  8765         known.insert(result,(void*)0x8);
       
  8766       }
       
  8767       else
       
  8768       {
       
  8769         nonSymlinks.insert(prefix,(void*)0x8);
       
  8770       }
       
  8771       oldPrefix = prefix;
       
  8772     }
       
  8773   }
       
  8774   while (sepPos!=-1);
       
  8775   return QDir::cleanDirPath(result).data();
       
  8776 }
       
  8777 
       
  8778 static QDict<void> g_pathsVisited(1009);
       
  8779 
       
  8780 //----------------------------------------------------------------------------
       
  8781 // Read all files matching at least one pattern in `patList' in the 
       
  8782 // directory represented by `fi'.
       
  8783 // The directory is read iff the recusiveFlag is set.
       
  8784 // The contents of all files is append to the input string
       
  8785 
       
  8786 int readDir(QFileInfo *fi,
       
  8787             FileNameList *fnList,
       
  8788             FileNameDict *fnDict,
       
  8789             StringDict  *exclDict,
       
  8790             QStrList *patList,
       
  8791             QStrList *exclPatList,
       
  8792             StringList *resultList,
       
  8793             StringDict *resultDict,
       
  8794             bool errorIfNotExist,
       
  8795             bool recursive,
       
  8796             QDict<void> *killDict
       
  8797            )
       
  8798 {
       
  8799   QString dirName = fi->absFilePath();
       
  8800   if (fi->isSymLink())
       
  8801   {
       
  8802     dirName = resolveSymlink(dirName.data());
       
  8803     if (dirName.isEmpty()) return 0;            // recusive symlink
       
  8804     if (g_pathsVisited.find(dirName)) return 0; // already visited path
       
  8805     g_pathsVisited.insert(dirName,(void*)0x8);
       
  8806   }
       
  8807   QDir dir(dirName);
       
  8808   dir.setFilter( QDir::Files | QDir::Dirs | QDir::Hidden );
       
  8809   int totalSize=0;
       
  8810   msg("Searching for files in directory %s\n", fi->absFilePath().data());
       
  8811   //printf("killDict=%p count=%d\n",killDict,killDict->count());
       
  8812   
       
  8813   const QFileInfoList *list = dir.entryInfoList();
       
  8814   if (list)
       
  8815   {
       
  8816     QFileInfoListIterator it( *list );
       
  8817     QFileInfo *cfi;
       
  8818 
       
  8819     while ((cfi=it.current()))
       
  8820     {
       
  8821       if (exclDict==0 || exclDict->find(cfi->absFilePath())==0) 
       
  8822       { // file should not be excluded
       
  8823         //printf("killDict->find(%s)\n",cfi->absFilePath().data());
       
  8824         if (!cfi->exists() || !cfi->isReadable())
       
  8825         {
       
  8826           if (errorIfNotExist)
       
  8827           {
       
  8828             err("Warning: source %s is not a readable file or directory... skipping.\n",cfi->absFilePath().data());
       
  8829           }
       
  8830         }
       
  8831         else if (cfi->isFile() && 
       
  8832             (!Config_getBool("EXCLUDE_SYMLINKS") || !cfi->isSymLink()) &&
       
  8833             (patList==0 || patternMatch(cfi,patList)) && 
       
  8834             !patternMatch(cfi,exclPatList) &&
       
  8835             (killDict==0 || killDict->find(cfi->absFilePath())==0)
       
  8836             )
       
  8837         {
       
  8838           totalSize+=cfi->size()+cfi->absFilePath().length()+4;
       
  8839           QCString name=convertToQCString(cfi->fileName());
       
  8840           //printf("New file %s\n",name.data());
       
  8841           if (fnDict)
       
  8842           {
       
  8843             FileDef  *fd=new FileDef(cfi->dirPath()+"/",name);
       
  8844             FileName *fn=0;
       
  8845             if (!name.isEmpty() && (fn=(*fnDict)[name]))
       
  8846             {
       
  8847               fn->append(fd);
       
  8848             }
       
  8849             else
       
  8850             {
       
  8851               fn = new FileName(cfi->absFilePath(),name);
       
  8852               fn->append(fd);
       
  8853               if (fnList) fnList->inSort(fn);
       
  8854               fnDict->insert(name,fn);
       
  8855             }
       
  8856           }
       
  8857           QCString *rs=0;
       
  8858           if (resultList || resultDict)
       
  8859           {
       
  8860             rs=new QCString(cfi->absFilePath());
       
  8861           }
       
  8862           if (resultList) resultList->append(rs);
       
  8863           if (resultDict) resultDict->insert(cfi->absFilePath(),rs);
       
  8864           if (killDict) killDict->insert(cfi->absFilePath(),(void *)0x8);
       
  8865         }
       
  8866         else if (recursive &&
       
  8867             (!Config_getBool("EXCLUDE_SYMLINKS") || !cfi->isSymLink()) &&
       
  8868             cfi->isDir() && cfi->fileName()!="." && 
       
  8869             !patternMatch(cfi,exclPatList) &&
       
  8870             cfi->fileName()!="..")
       
  8871         {
       
  8872           cfi->setFile(cfi->absFilePath());
       
  8873           totalSize+=readDir(cfi,fnList,fnDict,exclDict,
       
  8874               patList,exclPatList,resultList,resultDict,errorIfNotExist,
       
  8875               recursive,killDict);
       
  8876         }
       
  8877       }
       
  8878       ++it;
       
  8879     }
       
  8880   }
       
  8881   return totalSize;
       
  8882 }
       
  8883 
       
  8884 
       
  8885 //----------------------------------------------------------------------------
       
  8886 // read a file or all files in a directory and append their contents to the
       
  8887 // input string. The names of the files are appended to the `fiList' list.
       
  8888 
       
  8889 int readFileOrDirectory(const char *s,
       
  8890                         FileNameList *fnList,
       
  8891                         FileNameDict *fnDict,
       
  8892                         StringDict *exclDict,
       
  8893                         QStrList *patList,
       
  8894                         QStrList *exclPatList,
       
  8895                         StringList *resultList,
       
  8896                         StringDict *resultDict,
       
  8897                         bool recursive,
       
  8898                         bool errorIfNotExist,
       
  8899                         QDict<void> *killDict
       
  8900                        )
       
  8901 {
       
  8902   //printf("killDict=%p count=%d\n",killDict,killDict->count());
       
  8903   // strip trailing slashes
       
  8904   if (s==0) return 0;
       
  8905   QCString fs = s;
       
  8906   char lc = fs.at(fs.length()-1);
       
  8907   if (lc=='/' || lc=='\\') fs = fs.left(fs.length()-1);
       
  8908 
       
  8909   QFileInfo fi(fs);
       
  8910   //printf("readFileOrDirectory(%s)\n",s);
       
  8911   int totalSize=0;
       
  8912   {
       
  8913     if (exclDict==0 || exclDict->find(fi.absFilePath())==0)
       
  8914     {
       
  8915       if (!fi.exists() || !fi.isReadable())
       
  8916       {
       
  8917         if (errorIfNotExist)
       
  8918         {
       
  8919           err("Warning: source %s is not a readable file or directory... skipping.\n",s);
       
  8920         }
       
  8921       }
       
  8922       else if (!Config_getBool("EXCLUDE_SYMLINKS") || !fi.isSymLink())
       
  8923       {
       
  8924         if (fi.isFile())
       
  8925         {
       
  8926           //printf("killDict->find(%s)\n",fi.absFilePath().data());
       
  8927           if (killDict==0 || killDict->find(fi.absFilePath())==0)
       
  8928           {
       
  8929             totalSize+=fi.size()+fi.absFilePath().length()+4; //readFile(&fi,fiList,input); 
       
  8930             //fiList->inSort(new FileInfo(fi));
       
  8931             QCString name=convertToQCString(fi.fileName());
       
  8932             //printf("New file %s\n",name.data());
       
  8933             if (fnDict)
       
  8934             {
       
  8935               FileDef  *fd=new FileDef(fi.dirPath(TRUE)+"/",name);
       
  8936               FileName *fn=0;
       
  8937               if (!name.isEmpty() && (fn=(*fnDict)[name]))
       
  8938               {
       
  8939                 fn->append(fd);
       
  8940               }
       
  8941               else
       
  8942               {
       
  8943                 fn = new FileName(fi.absFilePath(),name);
       
  8944                 fn->append(fd);
       
  8945                 if (fnList) fnList->inSort(fn);
       
  8946                 fnDict->insert(name,fn);
       
  8947               }
       
  8948             }
       
  8949             QCString *rs=0;
       
  8950             if (resultList || resultDict)
       
  8951             {
       
  8952               rs=new QCString(fi.absFilePath());
       
  8953               if (resultList) resultList->append(rs);
       
  8954               if (resultDict) resultDict->insert(fi.absFilePath(),rs);
       
  8955             }
       
  8956 
       
  8957             if (killDict) killDict->insert(fi.absFilePath(),(void *)0x8);
       
  8958           }
       
  8959         }
       
  8960         else if (fi.isDir()) // readable dir
       
  8961         {
       
  8962           totalSize+=readDir(&fi,fnList,fnDict,exclDict,patList,
       
  8963               exclPatList,resultList,resultDict,errorIfNotExist,
       
  8964               recursive,killDict);
       
  8965         }
       
  8966       }
       
  8967     }
       
  8968   }
       
  8969   return totalSize;
       
  8970 }
       
  8971 
       
  8972 //----------------------------------------------------------------------------
       
  8973 
       
  8974 void readFormulaRepository()
       
  8975 {
       
  8976   QFile f(Config_getString("HTML_OUTPUT")+"/formula.repository");
       
  8977   if (f.open(IO_ReadOnly)) // open repository
       
  8978   {
       
  8979     msg("Reading formula repository...\n");
       
  8980     QTextStream t(&f);
       
  8981     QCString line;
       
  8982     while (!t.eof())
       
  8983     {
       
  8984       line=t.readLine();
       
  8985       int se=line.find(':'); // find name and text separator.
       
  8986       if (se==-1)
       
  8987       {
       
  8988         err("Warning: formula.repository is corrupted!\n");
       
  8989         break;
       
  8990       }
       
  8991       else
       
  8992       {
       
  8993         QCString formName = line.left(se);
       
  8994         QCString formText = line.right(line.length()-se-1); 
       
  8995         Formula *f=new Formula(formText);
       
  8996         Doxygen::formulaList.append(f);
       
  8997         Doxygen::formulaDict.insert(formText,f);
       
  8998         Doxygen::formulaNameDict.insert(formName,f);
       
  8999       }
       
  9000     }
       
  9001   }
       
  9002 }
       
  9003 
       
  9004 //----------------------------------------------------------------------------
       
  9005 
       
  9006 static void expandAliases()
       
  9007 {
       
  9008   QDictIterator<QCString> adi(Doxygen::aliasDict);
       
  9009   QCString *s;
       
  9010   for (adi.toFirst();(s=adi.current());++adi)
       
  9011   {
       
  9012     *s = expandAlias(adi.currentKey(),*s);
       
  9013   }
       
  9014 }
       
  9015 
       
  9016 //----------------------------------------------------------------------------
       
  9017 
       
  9018 static void escapeAliases()
       
  9019 {
       
  9020   QDictIterator<QCString> adi(Doxygen::aliasDict);
       
  9021   QCString *s;
       
  9022   for (adi.toFirst();(s=adi.current());++adi)
       
  9023   {
       
  9024     QCString value=*s,newValue;
       
  9025     int in,p=0;
       
  9026     // for each \n in the alias command value
       
  9027     while ((in=value.find("\\n",p))!=-1)
       
  9028     {
       
  9029       newValue+=value.mid(p,in-p);
       
  9030       // expand \n's except if \n is part of a built-in command.
       
  9031       if (value.mid(in,5)!="\\note" && 
       
  9032           value.mid(in,5)!="\\name" && 
       
  9033           value.mid(in,10)!="\\namespace" && 
       
  9034           value.mid(in,14)!="\\nosubgrouping"
       
  9035          ) 
       
  9036       {
       
  9037         newValue+="\\_linebr ";
       
  9038       }
       
  9039       else 
       
  9040       {
       
  9041         newValue+="\\n";
       
  9042       }
       
  9043       p=in+2;
       
  9044     }
       
  9045     newValue+=value.mid(p,value.length()-p);
       
  9046     *s=newValue;
       
  9047     //printf("Alias %s has value %s\n",adi.currentKey().data(),s->data());
       
  9048   }
       
  9049 }
       
  9050 
       
  9051 //----------------------------------------------------------------------------
       
  9052 
       
  9053 void readAliases()
       
  9054 { 
       
  9055   // add aliases to a dictionary
       
  9056   Doxygen::aliasDict.setAutoDelete(TRUE);
       
  9057   QStrList &aliasList = Config_getList("ALIASES");
       
  9058   const char *s=aliasList.first();
       
  9059   while (s)
       
  9060   {
       
  9061     if (Doxygen::aliasDict[s]==0)
       
  9062     {
       
  9063       QCString alias=s;
       
  9064       int i=alias.find('=');
       
  9065       if (i>0)
       
  9066       {
       
  9067         QCString name=alias.left(i).stripWhiteSpace();
       
  9068         QCString value=alias.right(alias.length()-i-1);
       
  9069         //printf("Alias: found name=`%s' value=`%s'\n",name.data(),value.data()); 
       
  9070         if (!name.isEmpty())
       
  9071         {
       
  9072           QCString *dn=Doxygen::aliasDict[name];
       
  9073           if (dn==0) // insert new alias
       
  9074           {
       
  9075             Doxygen::aliasDict.insert(name,new QCString(value));
       
  9076           }
       
  9077           else // overwrite previous alias
       
  9078           {
       
  9079             *dn=value;
       
  9080           }
       
  9081         }
       
  9082       }
       
  9083     }
       
  9084     s=aliasList.next();
       
  9085   }
       
  9086   expandAliases();
       
  9087   escapeAliases();
       
  9088 }
       
  9089 
       
  9090 //----------------------------------------------------------------------------
       
  9091 
       
  9092 static void dumpSymbol(QTextStream &t,Definition *d)
       
  9093 {
       
  9094   QCString anchor;
       
  9095   if (d->definitionType()==Definition::TypeMember)
       
  9096   {
       
  9097     MemberDef *md = (MemberDef *)d;
       
  9098     anchor=":"+md->anchor();
       
  9099   }
       
  9100   QCString scope;
       
  9101   if (d->getOuterScope() && d->getOuterScope()!=Doxygen::globalScope) 
       
  9102   {
       
  9103     scope = d->getOuterScope()->getOutputFileBase()+Doxygen::htmlFileExtension;
       
  9104   }
       
  9105   t << "REPLACE INTO symbols (symbol_id,scope_id,name,file,line) VALUES('"
       
  9106     << d->getOutputFileBase()+Doxygen::htmlFileExtension+anchor << "','"
       
  9107     << scope << "','"
       
  9108     << d->name() << "','"
       
  9109     << d->getDefFileName() << "','"
       
  9110     << d->getDefLine()
       
  9111     << "');" << endl;
       
  9112 }
       
  9113 
       
  9114 static void dumpSymbolMap()
       
  9115 { 
       
  9116   QFile f("symbols.sql");
       
  9117   if (f.open(IO_WriteOnly))
       
  9118   {
       
  9119     QTextStream t(&f);
       
  9120     QDictIterator<DefinitionIntf> di(*Doxygen::symbolMap);
       
  9121     DefinitionIntf *intf;
       
  9122     for (;(intf=di.current());++di)
       
  9123     {
       
  9124       if (intf->definitionType()==DefinitionIntf::TypeSymbolList) // list of symbols
       
  9125       {
       
  9126         DefinitionListIterator dli(*(DefinitionList*)intf);
       
  9127         Definition *d;
       
  9128         // for each symbol
       
  9129         for (dli.toFirst();(d=dli.current());++dli)
       
  9130         {
       
  9131           dumpSymbol(t,d);
       
  9132         }
       
  9133       }
       
  9134       else // single symbol
       
  9135       {
       
  9136         Definition *d = (Definition *)intf;
       
  9137         if (d!=Doxygen::globalScope) dumpSymbol(t,d);
       
  9138       }
       
  9139     }
       
  9140   }
       
  9141 }
       
  9142 
       
  9143 //----------------------------------------------------------------------------
       
  9144 
       
  9145 void dumpConfigAsXML()
       
  9146 {
       
  9147   QFile f("config.xml");
       
  9148   if (f.open(IO_WriteOnly))
       
  9149   {
       
  9150     QTextStream t(&f);
       
  9151     Config::instance()->writeXML(t);
       
  9152   }
       
  9153 }
       
  9154 
       
  9155 //----------------------------------------------------------------------------
       
  9156 // print the usage of doxygen
       
  9157 
       
  9158 static void usage(const char *name)
       
  9159 {
       
  9160   msg("Doxygen version %s\nCopyright Dimitri van Heesch 1997-2008\n\n",versionString);
       
  9161   msg("You can use doxygen in a number of ways:\n\n");
       
  9162   msg("1) Use doxygen to generate a template configuration file:\n");
       
  9163   msg("    %s [-s] -g [configName]\n\n",name);
       
  9164   msg("    If - is used for configName doxygen will write to standard output.\n\n");
       
  9165   msg("2) Use doxygen to update an old configuration file:\n");
       
  9166   msg("    %s [-s] -u [configName]\n\n",name);
       
  9167   msg("3) Use doxygen to generate documentation using an existing ");
       
  9168   msg("configuration file:\n");
       
  9169   msg("    %s [configName]\n\n",name);
       
  9170   msg("    If - is used for configName doxygen will read from standard input.\n\n");
       
  9171   msg("4) Use doxygen to generate a template file controlling the layout of the\n");
       
  9172   msg("   generated documentation:\n");
       
  9173   msg("    %s -l layoutFileName.xml\n\n",name);
       
  9174   msg("5) Use doxygen to generate a template style sheet file for RTF, HTML or Latex.\n");
       
  9175   msg("    RTF:   %s -w rtf styleSheetFile\n",name);
       
  9176   msg("    HTML:  %s -w html headerFile footerFile styleSheetFile [configFile]\n",name);
       
  9177   msg("    LaTeX: %s -w latex headerFile styleSheetFile [configFile]\n\n",name);
       
  9178   msg("6) Use doxygen to generate an rtf extensions file\n");
       
  9179   msg("    RTF:   %s -e rtf extensionsFile\n\n",name);
       
  9180   msg("If -s is specified the comments in the config file will be omitted.\n");
       
  9181   msg("If configName is omitted `Doxyfile' will be used as a default.\n\n");
       
  9182   exit(1);
       
  9183 }
       
  9184 
       
  9185 //----------------------------------------------------------------------------
       
  9186 // read the argument of option `c' from the comment argument list and
       
  9187 // update the option index `optind'.
       
  9188 
       
  9189 static const char *getArg(int argc,char **argv,int &optind)
       
  9190 {
       
  9191   char *s=0;
       
  9192   if (strlen(&argv[optind][2])>0)
       
  9193     s=&argv[optind][2];
       
  9194   else if (optind+1<argc && argv[optind+1][0]!='-')
       
  9195     s=argv[++optind];
       
  9196   return s;
       
  9197 }
       
  9198 
       
  9199 //----------------------------------------------------------------------------
       
  9200 
       
  9201 extern void commentScanTest();
       
  9202 
       
  9203 void initDoxygen()
       
  9204 {
       
  9205   setlocale(LC_ALL,"");
       
  9206   setlocale(LC_CTYPE,"C"); // to get isspace(0xA0)==0, needed for UTF-8
       
  9207   setlocale(LC_NUMERIC,"C");
       
  9208 
       
  9209   //Doxygen::symbolMap->setAutoDelete(TRUE);
       
  9210 
       
  9211   Doxygen::runningTime.start();
       
  9212   initPreprocessor();
       
  9213 
       
  9214   Doxygen::parserManager = new ParserManager;
       
  9215   Doxygen::parserManager->registerParser("c",       new CLanguageScanner, TRUE);
       
  9216   Doxygen::parserManager->registerParser("python",  new PythonLanguageScanner);
       
  9217   Doxygen::parserManager->registerParser("fortran", new FortranLanguageScanner);
       
  9218   Doxygen::parserManager->registerParser("vhdl",    new VHDLLanguageScanner);
       
  9219   Doxygen::parserManager->registerParser("dbusxml", new DBusXMLScanner);
       
  9220 
       
  9221   // register any additional parsers here...
       
  9222 
       
  9223   initDefaultExtensionMapping();
       
  9224   initClassMemberIndices();
       
  9225   initNamespaceMemberIndices();
       
  9226   initFileMemberIndices();
       
  9227 
       
  9228   Doxygen::symbolMap     = new QDict<DefinitionIntf>(1000);
       
  9229   Doxygen::inputNameList = new FileNameList;
       
  9230   Doxygen::inputNameList->setAutoDelete(TRUE);
       
  9231   Doxygen::memberNameSDict = new MemberNameSDict(10000);   
       
  9232   Doxygen::memberNameSDict->setAutoDelete(TRUE);
       
  9233   Doxygen::functionNameSDict = new MemberNameSDict(10000);   
       
  9234   Doxygen::functionNameSDict->setAutoDelete(TRUE);
       
  9235   Doxygen::groupSDict = new GroupSDict(17);          
       
  9236   Doxygen::groupSDict->setAutoDelete(TRUE);
       
  9237   Doxygen::globalScope = new NamespaceDef("<globalScope>",1,"<globalScope>");
       
  9238   Doxygen::namespaceSDict = new NamespaceSDict(20);      
       
  9239   Doxygen::namespaceSDict->setAutoDelete(TRUE);
       
  9240   Doxygen::classSDict = new ClassSDict(1009);         
       
  9241   Doxygen::classSDict->setAutoDelete(TRUE);
       
  9242   Doxygen::hiddenClasses = new ClassSDict(257);
       
  9243   Doxygen::hiddenClasses->setAutoDelete(TRUE);
       
  9244   Doxygen::directories = new DirSDict(17);
       
  9245   Doxygen::directories->setAutoDelete(TRUE);
       
  9246   Doxygen::pageSDict = new PageSDict(1009);          // all doc pages
       
  9247   Doxygen::pageSDict->setAutoDelete(TRUE);
       
  9248   Doxygen::exampleSDict = new PageSDict(1009);       // all examples
       
  9249   Doxygen::exampleSDict->setAutoDelete(TRUE);
       
  9250   Doxygen::inputNameDict = new FileNameDict(10007);
       
  9251   Doxygen::includeNameDict = new FileNameDict(10007);
       
  9252   Doxygen::exampleNameDict = new FileNameDict(1009);
       
  9253   Doxygen::exampleNameDict->setAutoDelete(TRUE);
       
  9254   Doxygen::imageNameDict = new FileNameDict(257);
       
  9255   Doxygen::dotFileNameDict = new FileNameDict(257);
       
  9256   Doxygen::sectionDict.setAutoDelete(TRUE);
       
  9257   Doxygen::memGrpInfoDict.setAutoDelete(TRUE);
       
  9258   Doxygen::tagDestinationDict.setAutoDelete(TRUE);
       
  9259   Doxygen::lookupCache.setAutoDelete(TRUE);
       
  9260   Doxygen::dirRelations.setAutoDelete(TRUE);
       
  9261 }
       
  9262 
       
  9263 void cleanUpDoxygen()
       
  9264 {
       
  9265   delete Doxygen::inputNameDict;
       
  9266   delete Doxygen::includeNameDict;
       
  9267   delete Doxygen::exampleNameDict;
       
  9268   delete Doxygen::imageNameDict;
       
  9269   delete Doxygen::dotFileNameDict;
       
  9270   delete Doxygen::mainPage;
       
  9271   delete Doxygen::pageSDict;  
       
  9272   delete Doxygen::exampleSDict;
       
  9273   delete Doxygen::globalScope;
       
  9274   delete Doxygen::xrefLists;
       
  9275   delete Doxygen::parserManager;
       
  9276   cleanUpPreprocessor();
       
  9277   delete theTranslator;
       
  9278   delete g_outputList;
       
  9279   Mappers::freeMappers();
       
  9280   codeFreeScanner();
       
  9281 
       
  9282   if (Doxygen::symbolMap)
       
  9283   {
       
  9284     // iterate through Doxygen::symbolMap and delete all
       
  9285     // DefinitionList objects, since they have no owner
       
  9286     QDictIterator<DefinitionIntf> dli(*Doxygen::symbolMap);
       
  9287     DefinitionIntf *di;
       
  9288     for (dli.toFirst();(di=dli.current());)
       
  9289     {
       
  9290       if (di->definitionType()==DefinitionIntf::TypeSymbolList)
       
  9291       {
       
  9292         DefinitionIntf *tmp = Doxygen::symbolMap->take(dli.currentKey());
       
  9293         delete (DefinitionList *)tmp;
       
  9294       }
       
  9295       else
       
  9296       {
       
  9297         ++dli;
       
  9298       }
       
  9299     } 
       
  9300   }
       
  9301 
       
  9302   delete Doxygen::inputNameList;
       
  9303   delete Doxygen::memberNameSDict;
       
  9304   delete Doxygen::functionNameSDict;
       
  9305   delete Doxygen::groupSDict;
       
  9306   delete Doxygen::classSDict;
       
  9307   delete Doxygen::hiddenClasses;
       
  9308   delete Doxygen::namespaceSDict;
       
  9309   delete Doxygen::directories;
       
  9310 
       
  9311   //delete Doxygen::symbolMap; <- we cannot do this unless all static lists 
       
  9312   //                              (such as Doxygen::namespaceSDict)
       
  9313   //                              with objects based on Definition are made
       
  9314   //                              dynamic first
       
  9315 }
       
  9316 
       
  9317 void readConfiguration(int argc, char **argv)
       
  9318 {
       
  9319   /**************************************************************************
       
  9320    *             Handle arguments                                           *
       
  9321    **************************************************************************/
       
  9322 
       
  9323   int optind=1;
       
  9324   const char *configName=0;
       
  9325   const char *layoutName=0;
       
  9326   const char *debugLabel;
       
  9327   const char *formatName;
       
  9328   bool genConfig=FALSE;
       
  9329   bool shortList=FALSE;
       
  9330   bool updateConfig=FALSE;
       
  9331   bool genLayout=FALSE;
       
  9332   while (optind<argc && argv[optind][0]=='-' && 
       
  9333                (isalpha(argv[optind][1]) || argv[optind][1]=='?' || 
       
  9334                 argv[optind][1]=='-')
       
  9335         )
       
  9336   {
       
  9337     switch(argv[optind][1])
       
  9338     {
       
  9339       case 'g':
       
  9340         genConfig=TRUE;
       
  9341         configName=getArg(argc,argv,optind);
       
  9342         if (strcmp(argv[optind+1],"-")==0)
       
  9343         { configName="-"; optind++; }
       
  9344         if (!configName) 
       
  9345         { configName="Doxyfile"; }
       
  9346         break;
       
  9347       case 'l':
       
  9348         genLayout=TRUE;
       
  9349         layoutName=getArg(argc,argv,optind);
       
  9350         if (!layoutName)
       
  9351         { layoutName="DoxygenLayout.xml"; }
       
  9352         break;
       
  9353       case 'd':
       
  9354         debugLabel=getArg(argc,argv,optind);
       
  9355         Debug::setFlag(debugLabel);
       
  9356         break;
       
  9357       case 's':
       
  9358         shortList=TRUE;
       
  9359         break;
       
  9360       case 'u':
       
  9361         updateConfig=TRUE;
       
  9362         break;
       
  9363       case 'e':
       
  9364         formatName=getArg(argc,argv,optind);
       
  9365         if (!formatName)
       
  9366         {
       
  9367           err("Error:option -e is missing format specifier rtf.\n");
       
  9368           cleanUpDoxygen();
       
  9369           exit(1);
       
  9370         }
       
  9371         if (stricmp(formatName,"rtf")==0)
       
  9372         {
       
  9373           if (optind+1>=argc)
       
  9374           {
       
  9375             err("Error: option \"-e rtf\" is missing an extensions file name\n");
       
  9376             cleanUpDoxygen();
       
  9377             exit(1);
       
  9378           }
       
  9379           QFile f;
       
  9380           if (openOutputFile(argv[optind+1],f))
       
  9381           {
       
  9382             RTFGenerator::writeExtensionsFile(f);
       
  9383           }
       
  9384           cleanUpDoxygen();
       
  9385           exit(1);
       
  9386         }
       
  9387         err("Error: option \"-e\" has invalid format specifier.\n");
       
  9388         cleanUpDoxygen();
       
  9389         exit(1);
       
  9390         break; 
       
  9391       case 'w':
       
  9392         formatName=getArg(argc,argv,optind);
       
  9393         if (!formatName)
       
  9394         {
       
  9395           err("Error: option -w is missing format specifier rtf, html or latex\n");
       
  9396           cleanUpDoxygen();
       
  9397           exit(1);
       
  9398         } 
       
  9399         if (stricmp(formatName,"rtf")==0)
       
  9400         {
       
  9401           if (optind+1>=argc)
       
  9402           {
       
  9403             err("Error: option \"-w rtf\" is missing a style sheet file name\n");
       
  9404             cleanUpDoxygen();
       
  9405             exit(1);
       
  9406           }
       
  9407           QFile f;
       
  9408           if (openOutputFile(argv[optind+1],f))
       
  9409           {
       
  9410             RTFGenerator::writeStyleSheetFile(f);
       
  9411           }
       
  9412           cleanUpDoxygen();
       
  9413           exit(1);
       
  9414         }
       
  9415         else if (stricmp(formatName,"html")==0)
       
  9416         {
       
  9417           if (optind+4<argc)
       
  9418           {
       
  9419             if (!Config::instance()->parse(argv[optind+4]))
       
  9420             {
       
  9421               err("Error opening or reading configuration file %s!\n",argv[optind+4]);
       
  9422               cleanUpDoxygen();
       
  9423               exit(1);
       
  9424             }
       
  9425             Config::instance()->substituteEnvironmentVars();
       
  9426             Config::instance()->convertStrToVal();
       
  9427             Config::instance()->check();
       
  9428           }
       
  9429           else
       
  9430           {
       
  9431             Config::instance()->init();
       
  9432           }
       
  9433           if (optind+3>=argc)
       
  9434           {
       
  9435             err("Error: option \"-w html\" does not have enough arguments\n");
       
  9436             cleanUpDoxygen();
       
  9437             exit(1);
       
  9438           }
       
  9439 
       
  9440           QCString outputLanguage=Config_getEnum("OUTPUT_LANGUAGE");
       
  9441           if (!setTranslator(outputLanguage))
       
  9442           {
       
  9443             err("Warning: Output language %s not supported! Using English instead.\n", outputLanguage.data());
       
  9444           }
       
  9445 
       
  9446           QFile f;
       
  9447           if (openOutputFile(argv[optind+1],f))
       
  9448           {
       
  9449             HtmlGenerator::writeHeaderFile(f);
       
  9450           }
       
  9451           f.close();
       
  9452           if (openOutputFile(argv[optind+2],f))
       
  9453           {
       
  9454             HtmlGenerator::writeFooterFile(f);
       
  9455           }
       
  9456           f.close();
       
  9457           if (openOutputFile(argv[optind+3],f))
       
  9458           {
       
  9459             HtmlGenerator::writeStyleSheetFile(f);
       
  9460           } 
       
  9461           cleanUpDoxygen();
       
  9462           exit(0);
       
  9463         }
       
  9464         else if (stricmp(formatName,"latex")==0)
       
  9465         {
       
  9466           if (optind+3<argc) // use config file to get settings
       
  9467           {
       
  9468             if (!Config::instance()->parse(argv[optind+3]))
       
  9469             {
       
  9470               err("Error opening or reading configuration file %s!\n",argv[optind+3]);
       
  9471               exit(1);
       
  9472             }
       
  9473             Config::instance()->substituteEnvironmentVars();
       
  9474             Config::instance()->convertStrToVal();
       
  9475             Config::instance()->check();
       
  9476           }
       
  9477           else // use default config
       
  9478           {
       
  9479             Config::instance()->init();
       
  9480           }
       
  9481           if (optind+2>=argc)
       
  9482           {
       
  9483             err("Error: option \"-w latex\" does not have enough arguments\n");
       
  9484             cleanUpDoxygen();
       
  9485             exit(1);
       
  9486           }
       
  9487 
       
  9488           QCString outputLanguage=Config_getEnum("OUTPUT_LANGUAGE");
       
  9489           if (!setTranslator(outputLanguage))
       
  9490           {
       
  9491             err("Warning: Output language %s not supported! Using English instead.\n", outputLanguage.data());
       
  9492           }
       
  9493 
       
  9494           QFile f;
       
  9495           if (openOutputFile(argv[optind+1],f))
       
  9496           {
       
  9497             LatexGenerator::writeHeaderFile(f);
       
  9498           }
       
  9499           f.close();
       
  9500           if (openOutputFile(argv[optind+2],f))
       
  9501           {
       
  9502             LatexGenerator::writeStyleSheetFile(f);
       
  9503           }
       
  9504           cleanUpDoxygen();
       
  9505           exit(0);
       
  9506         }
       
  9507         else 
       
  9508         {
       
  9509           err("Error: Illegal format specifier %s: should be one of rtf, html, or latex\n",formatName);
       
  9510           cleanUpDoxygen();
       
  9511           exit(1);
       
  9512         }
       
  9513         break;
       
  9514       case 'm':
       
  9515         g_dumpSymbolMap = TRUE;
       
  9516         break;
       
  9517       case 'x':
       
  9518         g_dumpConfigAsXML = TRUE;
       
  9519         break;
       
  9520       case '-':
       
  9521         if (strcmp(&argv[optind][2],"help")==0)
       
  9522         {
       
  9523           usage(argv[0]);
       
  9524         }
       
  9525         else if (strcmp(&argv[optind][2],"version")==0)
       
  9526         {
       
  9527           msg("%s\n",versionString); 
       
  9528           cleanUpDoxygen();
       
  9529           exit(0);
       
  9530         }
       
  9531         break;
       
  9532       case 'b':
       
  9533         setvbuf(stdout,NULL,_IONBF,0);
       
  9534         Doxygen::outputToWizard=TRUE;
       
  9535         break;
       
  9536       case 'h':
       
  9537       case '?':
       
  9538         usage(argv[0]);
       
  9539         break;
       
  9540       default:
       
  9541         err("Unknown option -%c\n",argv[optind][1]);
       
  9542         usage(argv[0]);
       
  9543     }
       
  9544     optind++;
       
  9545   }
       
  9546   
       
  9547   /**************************************************************************
       
  9548    *            Parse or generate the config file                           *
       
  9549    **************************************************************************/
       
  9550 
       
  9551   Config::instance()->init();
       
  9552 
       
  9553   if (genConfig)
       
  9554   {
       
  9555     if (g_dumpConfigAsXML)
       
  9556     {
       
  9557       checkConfiguration();
       
  9558       generateConfigFile(configName,shortList);
       
  9559       dumpConfigAsXML();
       
  9560       exit(0); 
       
  9561     }
       
  9562     else
       
  9563     {
       
  9564       generateConfigFile(configName,shortList);
       
  9565     }
       
  9566     cleanUpDoxygen();
       
  9567     exit(0);
       
  9568   }
       
  9569   if (genLayout)
       
  9570   {
       
  9571     writeDefaultLayoutFile(layoutName);
       
  9572     cleanUpDoxygen();
       
  9573     exit(0);
       
  9574   }
       
  9575 
       
  9576   QFileInfo configFileInfo1("Doxyfile"),configFileInfo2("doxyfile");
       
  9577   if (optind>=argc)
       
  9578   { 
       
  9579     if (configFileInfo1.exists()) 
       
  9580     {
       
  9581       configName="Doxyfile";
       
  9582     }
       
  9583     else if (configFileInfo2.exists())
       
  9584     {
       
  9585       configName="doxyfile";
       
  9586     }
       
  9587     else
       
  9588     {
       
  9589       err("Doxyfile not found and no input file specified!\n");
       
  9590       usage(argv[0]);
       
  9591     }
       
  9592   }
       
  9593   else
       
  9594   {
       
  9595     QFileInfo fi(argv[optind]);
       
  9596     if (fi.exists() || strcmp(argv[optind],"-")==0)
       
  9597     {
       
  9598       configName=argv[optind];
       
  9599     }
       
  9600     else
       
  9601     {
       
  9602       err("Error: configuration file %s not found!\n",argv[optind]);
       
  9603       usage(argv[0]);
       
  9604     }
       
  9605   }
       
  9606 
       
  9607 
       
  9608   if (!Config::instance()->parse(configName))
       
  9609   {
       
  9610     err("Error: could not open or read configuration file %s!\n",configName);
       
  9611     cleanUpDoxygen();
       
  9612     exit(1);
       
  9613   }
       
  9614 
       
  9615   if (updateConfig)
       
  9616   {
       
  9617     generateConfigFile(configName,shortList,TRUE);
       
  9618     cleanUpDoxygen();
       
  9619     exit(0);
       
  9620   }
       
  9621 
       
  9622   /* Perlmod wants to know the path to the config file.*/
       
  9623   QFileInfo configFileInfo(configName);
       
  9624   setPerlModDoxyfile(configFileInfo.absFilePath());
       
  9625 
       
  9626 }
       
  9627 
       
  9628 /** check and resolve config options */
       
  9629 void checkConfiguration()
       
  9630 {
       
  9631   
       
  9632   Config::instance()->substituteEnvironmentVars();
       
  9633   Config::instance()->convertStrToVal();
       
  9634   Config::instance()->check();
       
  9635   
       
  9636   initWarningFormat();
       
  9637 }
       
  9638 
       
  9639 /** adjust globals that depend on configuration settings. */
       
  9640 void adjustConfiguration()
       
  9641 {
       
  9642   QCString outputLanguage=Config_getEnum("OUTPUT_LANGUAGE");
       
  9643   if (!setTranslator(outputLanguage))
       
  9644   {
       
  9645     err("Warning: Output language %s not supported! Using English instead.\n",
       
  9646        outputLanguage.data());
       
  9647   }
       
  9648   QStrList &includePath = Config_getList("INCLUDE_PATH");
       
  9649   char *s=includePath.first();
       
  9650   while (s)
       
  9651   {
       
  9652     QFileInfo fi(s);
       
  9653     addSearchDir(fi.absFilePath());
       
  9654     s=includePath.next();
       
  9655   }
       
  9656 
       
  9657   /* Set the global html file extension. */ 
       
  9658   Doxygen::htmlFileExtension = Config_getString("HTML_FILE_EXTENSION");
       
  9659 
       
  9660 
       
  9661   Doxygen::xrefLists->setAutoDelete(TRUE);
       
  9662 
       
  9663   Doxygen::parseSourcesNeeded = Config_getBool("CALL_GRAPH") || 
       
  9664                                 Config_getBool("CALLER_GRAPH") ||
       
  9665                                 Config_getBool("REFERENCES_RELATION") ||
       
  9666                                 Config_getBool("REFERENCED_BY_RELATION");
       
  9667   
       
  9668   /**************************************************************************
       
  9669    *            Add custom extension mappings
       
  9670    **************************************************************************/
       
  9671 
       
  9672   QStrList &extMaps = Config_getList("EXTENSION_MAPPING");
       
  9673   char *mapping = extMaps.first();
       
  9674   while (mapping)
       
  9675   {
       
  9676     QCString mapStr = mapping;
       
  9677     int i;
       
  9678     if ((i=mapStr.find('='))!=-1)
       
  9679     {
       
  9680       QCString ext=mapStr.left(i).stripWhiteSpace().lower();
       
  9681       QCString language=mapStr.mid(i+1).stripWhiteSpace().lower();
       
  9682       if (!updateLanguageMapping(ext,language))
       
  9683       {
       
  9684         err("Failed to map file extension '%s' to unsupported language '%s'.\n"
       
  9685             "Check the EXTENSION_MAPPING setting in the config file.\n", 
       
  9686             ext.data(),language.data());
       
  9687       }
       
  9688       else
       
  9689       {
       
  9690         msg("Adding custom extension mapping: .%s will be treated as language %s\n",
       
  9691             ext.data(),language.data());
       
  9692       }
       
  9693     }
       
  9694     mapping = extMaps.next();
       
  9695   }
       
  9696 
       
  9697 
       
  9698   // add predefined macro name to a dictionary
       
  9699   QStrList &expandAsDefinedList =Config_getList("EXPAND_AS_DEFINED");
       
  9700   s=expandAsDefinedList.first();
       
  9701   while (s)
       
  9702   {
       
  9703     if (Doxygen::expandAsDefinedDict[s]==0)
       
  9704     {
       
  9705       Doxygen::expandAsDefinedDict.insert(s,(void *)666);
       
  9706     }
       
  9707     s=expandAsDefinedList.next();
       
  9708   }
       
  9709 
       
  9710   // read aliases and store them in a dictionary
       
  9711   readAliases();
       
  9712 
       
  9713   // store number of spaces in a tab into Doxygen::spaces
       
  9714   int &tabSize = Config_getInt("TAB_SIZE");
       
  9715   Doxygen::spaces.resize(tabSize+1);
       
  9716   int sp;for (sp=0;sp<tabSize;sp++) Doxygen::spaces.at(sp)=' ';
       
  9717   Doxygen::spaces.at(tabSize)='\0';
       
  9718 }
       
  9719 
       
  9720 #ifdef HAS_SIGNALS
       
  9721 static void stopDoxygen(int)
       
  9722 {
       
  9723   QDir thisDir;
       
  9724   msg("Cleaning up...\n");
       
  9725   if (!Doxygen::entryDBFileName.isEmpty())
       
  9726   {
       
  9727     thisDir.remove(Doxygen::entryDBFileName);
       
  9728   }
       
  9729   if (!Doxygen::objDBFileName.isEmpty())
       
  9730   {
       
  9731     thisDir.remove(Doxygen::objDBFileName);
       
  9732   }
       
  9733   exit(1);
       
  9734 }
       
  9735 #endif
       
  9736 
       
  9737 static void exitDoxygen()
       
  9738 {
       
  9739   if (!g_successfulRun)  // premature exit
       
  9740   {
       
  9741     QDir thisDir;
       
  9742     msg("Exiting...\n");
       
  9743     if (!Doxygen::entryDBFileName.isEmpty())
       
  9744     {
       
  9745       thisDir.remove(Doxygen::entryDBFileName);
       
  9746     }
       
  9747     if (!Doxygen::objDBFileName.isEmpty())
       
  9748     {
       
  9749       thisDir.remove(Doxygen::objDBFileName);
       
  9750     }
       
  9751   }
       
  9752 }
       
  9753 
       
  9754 static QCString createOutputDirectory(const QCString &baseDirName,
       
  9755                                   const char *formatDirOption,
       
  9756                                   const char *defaultDirName)
       
  9757 {
       
  9758   // Note the & on the next line, we modify the formatDirOption!
       
  9759   QCString &formatDirName = Config_getString(formatDirOption);
       
  9760   if (formatDirName.isEmpty())
       
  9761   {
       
  9762     formatDirName = baseDirName + defaultDirName;
       
  9763   }
       
  9764   else if (formatDirName[0]!='/' && (formatDirName.length()==1 || formatDirName[1]!=':'))
       
  9765   {
       
  9766     formatDirName.prepend(baseDirName+'/');
       
  9767   }
       
  9768   QDir formatDir(formatDirName);
       
  9769   if (!formatDir.exists() && !formatDir.mkdir(formatDirName))
       
  9770   {
       
  9771     err("Could not create output directory %s\n", formatDirName.data());
       
  9772     cleanUpDoxygen();
       
  9773     exit(1);
       
  9774   }
       
  9775   return formatDirName;
       
  9776 }
       
  9777 
       
  9778 static QCString getQchFileName()
       
  9779 {
       
  9780   QCString const & qchFile = Config_getString("QCH_FILE");
       
  9781   if (!qchFile.isEmpty())
       
  9782   {
       
  9783     return qchFile;
       
  9784   }
       
  9785 
       
  9786   QCString const & projectName = Config_getString("PROJECT_NAME");
       
  9787   QCString const & versionText = Config_getString("PROJECT_NUMBER");
       
  9788 
       
  9789   return QCString("../qch/")
       
  9790       + (projectName.isEmpty() ? QCString("index") : projectName)
       
  9791       + (versionText.isEmpty() ? QCString("") : QCString("-") + versionText)
       
  9792       + QCString(".qch");
       
  9793 }
       
  9794 
       
  9795 void searchInputFiles(StringList &inputFiles)
       
  9796 {
       
  9797   QStrList &exclPatterns = Config_getList("EXCLUDE_PATTERNS");
       
  9798   bool alwaysRecursive = Config_getBool("RECURSIVE");
       
  9799   StringDict excludeNameDict(1009);
       
  9800   excludeNameDict.setAutoDelete(TRUE);
       
  9801 
       
  9802   // gather names of all files in the include path
       
  9803   msg("Searching for include files...\n");
       
  9804   QStrList &includePathList = Config_getList("INCLUDE_PATH");
       
  9805   char *s=includePathList.first();
       
  9806   while (s)
       
  9807   {
       
  9808     QStrList &pl = Config_getList("INCLUDE_FILE_PATTERNS");
       
  9809     if (pl.count()==0) 
       
  9810     {
       
  9811       pl = Config_getList("FILE_PATTERNS");
       
  9812     }
       
  9813     readFileOrDirectory(s,0,Doxygen::includeNameDict,0,&pl,
       
  9814                         &exclPatterns,0,0,
       
  9815                         alwaysRecursive);
       
  9816     s=includePathList.next(); 
       
  9817   }
       
  9818   
       
  9819   msg("Searching for example files...\n");
       
  9820   QStrList &examplePathList = Config_getList("EXAMPLE_PATH");
       
  9821   s=examplePathList.first();
       
  9822   while (s)
       
  9823   {
       
  9824     readFileOrDirectory(s,0,Doxygen::exampleNameDict,0,
       
  9825                         &Config_getList("EXAMPLE_PATTERNS"),
       
  9826                         0,0,0,
       
  9827                         (alwaysRecursive || Config_getBool("EXAMPLE_RECURSIVE")));
       
  9828     s=examplePathList.next(); 
       
  9829   }
       
  9830 
       
  9831   msg("Searching for images...\n");
       
  9832   QStrList &imagePathList=Config_getList("IMAGE_PATH");
       
  9833   s=imagePathList.first();
       
  9834   while (s)
       
  9835   {
       
  9836     readFileOrDirectory(s,0,Doxygen::imageNameDict,0,0,
       
  9837                         0,0,0,
       
  9838                         alwaysRecursive);
       
  9839     s=imagePathList.next(); 
       
  9840   }
       
  9841 
       
  9842   msg("Searching for dot files...\n");
       
  9843   QStrList &dotFileList=Config_getList("DOTFILE_DIRS");
       
  9844   s=dotFileList.first();
       
  9845   while (s)
       
  9846   {
       
  9847     readFileOrDirectory(s,0,Doxygen::dotFileNameDict,0,0,
       
  9848                         0,0,0,
       
  9849                         alwaysRecursive);
       
  9850     s=dotFileList.next(); 
       
  9851   }
       
  9852 
       
  9853   msg("Searching for files to exclude\n");
       
  9854   QStrList &excludeList = Config_getList("EXCLUDE");
       
  9855   s=excludeList.first();
       
  9856   while (s)
       
  9857   {
       
  9858     readFileOrDirectory(s,0,0,0,&Config_getList("FILE_PATTERNS"),
       
  9859                         0,0,&excludeNameDict,
       
  9860                         alwaysRecursive,
       
  9861                         FALSE);
       
  9862     s=excludeList.next();
       
  9863   }
       
  9864 
       
  9865   /**************************************************************************
       
  9866    *             Determine Input Files                                      *
       
  9867    **************************************************************************/
       
  9868 
       
  9869   msg("Searching for files to process...\n");
       
  9870   QDict<void> *killDict = new QDict<void>(10007);
       
  9871   int inputSize=0;
       
  9872   QStrList &inputList=Config_getList("INPUT");
       
  9873   inputFiles.setAutoDelete(TRUE);
       
  9874   s=inputList.first();
       
  9875   while (s)
       
  9876   {
       
  9877     QCString path=s;
       
  9878     uint l = path.length();
       
  9879     // strip trailing slashes
       
  9880     if (path.at(l-1)=='\\' || path.at(l-1)=='/') path=path.left(l-1);
       
  9881 
       
  9882     inputSize+=readFileOrDirectory(
       
  9883         path,
       
  9884         Doxygen::inputNameList,
       
  9885         Doxygen::inputNameDict,
       
  9886         &excludeNameDict,
       
  9887         &Config_getList("FILE_PATTERNS"),
       
  9888         &exclPatterns,
       
  9889         &inputFiles,0,
       
  9890         alwaysRecursive,
       
  9891         TRUE,
       
  9892         killDict);
       
  9893     s=inputList.next();
       
  9894   }
       
  9895   delete killDict;
       
  9896 }
       
  9897 
       
  9898   
       
  9899 void parseInput()
       
  9900 {
       
  9901   atexit(exitDoxygen);
       
  9902 
       
  9903 
       
  9904   /**************************************************************************
       
  9905    *            Make sure the output directory exists
       
  9906    **************************************************************************/
       
  9907   QCString &outputDirectory = Config_getString("OUTPUT_DIRECTORY");
       
  9908   if (outputDirectory.isEmpty()) 
       
  9909   {
       
  9910     outputDirectory=QDir::currentDirPath();
       
  9911   }
       
  9912   else
       
  9913   {
       
  9914     QDir dir(outputDirectory);
       
  9915     if (!dir.exists())
       
  9916     {
       
  9917       dir.setPath(QDir::currentDirPath());
       
  9918       if (!dir.mkdir(outputDirectory))
       
  9919       {
       
  9920         err("Error: tag OUTPUT_DIRECTORY: Output directory `%s' does not "
       
  9921 	    "exist and cannot be created\n",outputDirectory.data());
       
  9922         cleanUpDoxygen();
       
  9923         exit(1);
       
  9924       }
       
  9925       else if (!Config_getBool("QUIET"))
       
  9926       {
       
  9927 	err("Notice: Output directory `%s' does not exist. "
       
  9928 	    "I have created it for you.\n", outputDirectory.data());
       
  9929       }
       
  9930       dir.cd(outputDirectory);
       
  9931     }
       
  9932     outputDirectory=dir.absPath();
       
  9933   }
       
  9934 
       
  9935   /**************************************************************************
       
  9936    *            Initialize global lists and dictionaries
       
  9937    **************************************************************************/
       
  9938 
       
  9939   int cacheSize = Config_getInt("SYMBOL_CACHE_SIZE");
       
  9940   if (cacheSize<0) cacheSize=0;
       
  9941   if (cacheSize>9) cacheSize=9;
       
  9942   Doxygen::symbolCache   = new ObjCache(16+cacheSize); // 16 -> room for 65536 elements, 
       
  9943                                                 //       ~2.0 MByte "overhead"
       
  9944   Doxygen::symbolStorage = new Store;
       
  9945 
       
  9946 #ifdef HAS_SIGNALS
       
  9947   signal(SIGINT, stopDoxygen);
       
  9948 #endif
       
  9949 
       
  9950   uint pid = portable_pid();
       
  9951   Doxygen::objDBFileName.sprintf("doxygen_objdb_%d.tmp",pid);
       
  9952   Doxygen::objDBFileName.prepend(outputDirectory+"/");
       
  9953   Doxygen::entryDBFileName.sprintf("doxygen_entrydb_%d.tmp",pid);
       
  9954   Doxygen::entryDBFileName.prepend(outputDirectory+"/");
       
  9955   
       
  9956   if (Doxygen::symbolStorage->open(Doxygen::objDBFileName)==-1)
       
  9957   {
       
  9958     err("Failed to open temporary file %s\n",Doxygen::objDBFileName.data());
       
  9959     exit(1);
       
  9960   }
       
  9961 
       
  9962 
       
  9963   /**************************************************************************
       
  9964    *            Initialize some global constants
       
  9965    **************************************************************************/
       
  9966   
       
  9967   g_compoundKeywordDict.insert("template class",(void *)8);
       
  9968   g_compoundKeywordDict.insert("template struct",(void *)8);
       
  9969   g_compoundKeywordDict.insert("class",(void *)8);
       
  9970   g_compoundKeywordDict.insert("struct",(void *)8);
       
  9971   g_compoundKeywordDict.insert("union",(void *)8);
       
  9972   g_compoundKeywordDict.insert("interface",(void *)8);
       
  9973   g_compoundKeywordDict.insert("exception",(void *)8);
       
  9974 
       
  9975 
       
  9976   /**************************************************************************
       
  9977    *            Check/create output directorties                            *
       
  9978    **************************************************************************/
       
  9979 
       
  9980   QCString htmlOutput;
       
  9981   bool &generateHtml = Config_getBool("GENERATE_HTML");
       
  9982   if (generateHtml)
       
  9983     htmlOutput = createOutputDirectory(outputDirectory,"HTML_OUTPUT","/html");
       
  9984 
       
  9985   QCString xmlOutput;
       
  9986   bool &generateXml = Config_getBool("GENERATE_XML");
       
  9987   if (generateXml)
       
  9988     xmlOutput = createOutputDirectory(outputDirectory,"XML_OUTPUT","/xml");
       
  9989     
       
  9990   QCString xmlDitaOutput;
       
  9991   bool &generateXmlDita = Config_getBool("GENERATE_XML_DITA");
       
  9992   if (generateXmlDita)
       
  9993     xmlDitaOutput = createOutputDirectory(outputDirectory,"XML_DITA_OUTPUT","/dita");
       
  9994 
       
  9995   QCString latexOutput;
       
  9996   bool &generateLatex = Config_getBool("GENERATE_LATEX");
       
  9997   if (generateLatex)
       
  9998     latexOutput = createOutputDirectory(outputDirectory,"LATEX_OUTPUT","/latex");
       
  9999 
       
 10000   QCString rtfOutput;
       
 10001   bool &generateRtf = Config_getBool("GENERATE_RTF");
       
 10002   if (generateRtf)
       
 10003     rtfOutput = createOutputDirectory(outputDirectory,"RTF_OUTPUT","/rtf");
       
 10004 
       
 10005   QCString manOutput;
       
 10006   bool &generateMan = Config_getBool("GENERATE_MAN");
       
 10007   if (generateMan)
       
 10008     manOutput = createOutputDirectory(outputDirectory,"MAN_OUTPUT","/man");
       
 10009 
       
 10010 
       
 10011   if (Config_getBool("HAVE_DOT"))
       
 10012   {
       
 10013     QCString curFontPath = Config_getString("DOT_FONTPATH");
       
 10014     if (curFontPath.isEmpty())
       
 10015     {
       
 10016       portable_getenv("DOTFONTPATH");
       
 10017       QCString newFontPath = ".";
       
 10018       if (!curFontPath.isEmpty())
       
 10019       {
       
 10020         newFontPath+=portable_pathListSeparator();
       
 10021         newFontPath+=curFontPath;
       
 10022       }
       
 10023       portable_setenv("DOTFONTPATH",newFontPath);
       
 10024     }
       
 10025     else
       
 10026     {
       
 10027       portable_setenv("DOTFONTPATH",curFontPath);
       
 10028     }
       
 10029   }
       
 10030 
       
 10031 
       
 10032 
       
 10033   /**************************************************************************
       
 10034    *             Handle layout file                                         *
       
 10035    **************************************************************************/
       
 10036 
       
 10037   LayoutDocManager::instance().init();
       
 10038   QCString layoutFileName = Config_getString("LAYOUT_FILE");
       
 10039   bool defaultLayoutUsed = FALSE;
       
 10040   if (layoutFileName.isEmpty())
       
 10041   {
       
 10042     layoutFileName = "DoxygenLayout.xml";
       
 10043     defaultLayoutUsed = TRUE;
       
 10044   }
       
 10045 
       
 10046   QFile layoutFile(layoutFileName);
       
 10047   if (layoutFile.open(IO_ReadOnly))
       
 10048   {
       
 10049     msg("Parsing layout file %s...\n",layoutFileName.data());
       
 10050     QTextStream t(&layoutFile); 
       
 10051     LayoutDocManager::instance().parse(t);
       
 10052   }
       
 10053   else if (!defaultLayoutUsed)
       
 10054   {
       
 10055     err("Warning: failed to open layout file '%s' for reading!\n",layoutFileName.data());
       
 10056   }
       
 10057 
       
 10058   /**************************************************************************
       
 10059    *             Read and preprocess input                                  *
       
 10060    **************************************************************************/
       
 10061  
       
 10062   // prevent search in the output directories
       
 10063   QStrList &exclPatterns = Config_getList("EXCLUDE_PATTERNS");
       
 10064   if (generateHtml)  exclPatterns.append(htmlOutput);
       
 10065   if (generateXml)   exclPatterns.append(xmlOutput);
       
 10066   if (generateXmlDita)   exclPatterns.append(xmlDitaOutput);
       
 10067   if (generateLatex) exclPatterns.append(latexOutput);
       
 10068   if (generateRtf)   exclPatterns.append(rtfOutput);
       
 10069   if (generateMan)   exclPatterns.append(manOutput);
       
 10070 
       
 10071 
       
 10072   searchInputFiles(g_inputFiles);
       
 10073 
       
 10074   // Notice: the order of the function calls below is very important!
       
 10075   
       
 10076   if (Config_getBool("GENERATE_HTML"))
       
 10077   {
       
 10078     readFormulaRepository();
       
 10079   }
       
 10080   
       
 10081   /**************************************************************************
       
 10082    *             Handle Tag Files                                           *
       
 10083    **************************************************************************/
       
 10084 
       
 10085   g_storage = new FileStorage;
       
 10086   g_storage->setName(Doxygen::entryDBFileName);
       
 10087   if (!g_storage->open(IO_WriteOnly))
       
 10088   {
       
 10089     err("Failed to create temporary storage file %s\n",
       
 10090         Doxygen::entryDBFileName.data());
       
 10091     exit(1);
       
 10092   }
       
 10093   Entry *root=new Entry;
       
 10094   EntryNav *rootNav = new EntryNav(0,root);
       
 10095   rootNav->setEntry(root);
       
 10096   msg("Reading and parsing tag files\n");
       
 10097   
       
 10098   QStrList &tagFileList = Config_getList("TAGFILES");
       
 10099   char *s=tagFileList.first();
       
 10100   while (s)
       
 10101   {
       
 10102     readTagFile(root,s);
       
 10103     root->createNavigationIndex(rootNav,g_storage,0);
       
 10104     s=tagFileList.next();
       
 10105   }
       
 10106   
       
 10107   /**************************************************************************
       
 10108    *             Parse source files                                         * 
       
 10109    **************************************************************************/
       
 10110 
       
 10111   parseFiles(root,rootNav);
       
 10112   g_storage->close();
       
 10113   if (!g_storage->open(IO_ReadOnly))
       
 10114   {
       
 10115     err("Failed to open temporary storage file %s for reading",
       
 10116         Doxygen::entryDBFileName.data());
       
 10117     exit(1);
       
 10118   }
       
 10119 
       
 10120   //printNavTree(rootNav,0);
       
 10121 
       
 10122   // we are done with input scanning now, so free up the buffers used by flex
       
 10123   // (can be around 4MB)
       
 10124   preFreeScanner();
       
 10125   scanFreeScanner();
       
 10126   pyscanFreeScanner();
       
 10127 
       
 10128   //delete rootNav;
       
 10129   //g_storage.close();
       
 10130   //exit(1);
       
 10131 
       
 10132   /**************************************************************************
       
 10133    *             Gather information                                         * 
       
 10134    **************************************************************************/
       
 10135   
       
 10136   msg("Building group list...\n");
       
 10137   buildGroupList(rootNav);
       
 10138   organizeSubGroups(rootNav);
       
 10139 
       
 10140   msg("Building directory list...\n");
       
 10141   buildDirectories();
       
 10142   findDirDocumentation(rootNav);
       
 10143 
       
 10144   if (Config_getBool("BUILTIN_STL_SUPPORT"))
       
 10145   {
       
 10146     addSTLClasses(rootNav);
       
 10147   }
       
 10148 
       
 10149   msg("Building namespace list...\n");
       
 10150   buildNamespaceList(rootNav);
       
 10151   findUsingDirectives(rootNav);
       
 10152 
       
 10153   msg("Building file list...\n");
       
 10154   buildFileList(rootNav);
       
 10155   //generateFileTree();
       
 10156   
       
 10157   msg("Building class list...\n");
       
 10158   buildClassList(rootNav);
       
 10159 
       
 10160   msg("Associating documentation with classes...\n");
       
 10161   buildClassDocList(rootNav);
       
 10162 
       
 10163   // build list of using declarations here (global list)
       
 10164   buildListOfUsingDecls(rootNav);
       
 10165   
       
 10166   msg("Computing nesting relations for classes...\n");
       
 10167   resolveClassNestingRelations();
       
 10168 
       
 10169   // calling buildClassList may result in cached relations that
       
 10170   // become invalid after resolveClassNestingRelations(), that's why
       
 10171   // we need to clear the cache here
       
 10172   Doxygen::lookupCache.clear();
       
 10173   // we don't need the list of using declaration anymore
       
 10174   g_usingDeclarations.clear();
       
 10175 
       
 10176   msg("Building example list...\n");
       
 10177   buildExampleList(rootNav);
       
 10178   
       
 10179   msg("Searching for enumerations...\n");
       
 10180   findEnums(rootNav);
       
 10181   
       
 10182   // Since buildVarList calls isVarWithConstructor
       
 10183   // and this calls getResolvedClass we need to process
       
 10184   // typedefs first so the relations between classes via typedefs
       
 10185   // are properly resolved. See bug 536385 for an example.
       
 10186   msg("Searching for documented typedefs...\n");
       
 10187   buildTypedefList(rootNav);
       
 10188 
       
 10189   msg("Searching for members imported via using declarations...\n");
       
 10190   findUsingDeclImports(rootNav);
       
 10191   // this should be after buildTypedefList in order to properly import
       
 10192   // used typedefs
       
 10193   findUsingDeclarations(rootNav);
       
 10194 
       
 10195   msg("Searching for included using directives...\n");
       
 10196   findIncludedUsingDirectives();
       
 10197 
       
 10198   msg("Searching for documented variables...\n");
       
 10199   buildVarList(rootNav);
       
 10200 
       
 10201   msg("Building member list...\n"); // using class info only !
       
 10202   buildFunctionList(rootNav);
       
 10203 
       
 10204   msg("Searching for friends...\n");
       
 10205   findFriends();
       
 10206   
       
 10207   msg("Searching for documented defines...\n");
       
 10208   findDefineDocumentation(rootNav); 
       
 10209   
       
 10210   findClassEntries(rootNav);         
       
 10211   msg("Computing class inheritance relations...\n");
       
 10212   findInheritedTemplateInstances();       
       
 10213   msg("Computing class usage relations...\n");
       
 10214   findUsedTemplateInstances();       
       
 10215 
       
 10216   msg("Flushing cached template relations that have become invalid...\n");
       
 10217   flushCachedTemplateRelations();
       
 10218   
       
 10219   msg("Creating members for template instances...\n");
       
 10220   createTemplateInstanceMembers();
       
 10221 
       
 10222   msg("Computing class relations...\n");
       
 10223   computeTemplateClassRelations(); 
       
 10224   flushUnresolvedRelations();
       
 10225   if (Config_getBool("OPTIMIZE_OUTPUT_VHDL"))
       
 10226   {
       
 10227     VhdlDocGen::computeVhdlComponentRelations();
       
 10228   }
       
 10229   else
       
 10230   {
       
 10231     computeClassRelations();        
       
 10232   }
       
 10233   g_classEntries.clear();          
       
 10234 
       
 10235   msg("Add enum values to enums...\n");
       
 10236   addEnumValuesToEnums(rootNav);
       
 10237   findEnumDocumentation(rootNav);
       
 10238 
       
 10239   msg("Searching for member function documentation...\n");
       
 10240   findObjCMethodDefinitions(rootNav);
       
 10241   findMemberDocumentation(rootNav); // may introduce new members !
       
 10242 
       
 10243   transferRelatedFunctionDocumentation();
       
 10244   transferFunctionDocumentation();
       
 10245   
       
 10246   msg("Building page list...\n");
       
 10247   buildPageList(rootNav);
       
 10248 
       
 10249   msg("Search for main page...\n");
       
 10250   findMainPage(rootNav);
       
 10251 
       
 10252   msg("Computing page relations...\n");
       
 10253   computePageRelations(rootNav);
       
 10254   checkPageRelations();
       
 10255 
       
 10256   msg("Determining the scope of groups...\n");
       
 10257   findGroupScope(rootNav);
       
 10258 
       
 10259   msg("Sorting lists...\n");
       
 10260   Doxygen::memberNameSDict->sort();
       
 10261   Doxygen::functionNameSDict->sort();
       
 10262   Doxygen::hiddenClasses->sort();
       
 10263   Doxygen::classSDict->sort();
       
 10264   
       
 10265   msg("Freeing entry tree\n");
       
 10266   delete rootNav;
       
 10267   g_storage->close();
       
 10268   delete g_storage;
       
 10269   g_storage=0;
       
 10270 
       
 10271   QDir thisDir;
       
 10272   thisDir.remove(Doxygen::entryDBFileName);
       
 10273   
       
 10274   msg("Determining which enums are documented\n");
       
 10275   findDocumentedEnumValues();
       
 10276 
       
 10277   msg("Computing member relations...\n");
       
 10278   // TODO: This seems to generate an infinite loop
       
 10279   computeMemberRelations();
       
 10280 
       
 10281   msg("Building full member lists recursively...\n");
       
 10282   buildCompleteMemberLists();
       
 10283   
       
 10284   msg("Adding members to member groups.\n");
       
 10285   addMembersToMemberGroup();
       
 10286 
       
 10287   if (Config_getBool("DISTRIBUTE_GROUP_DOC"))
       
 10288   {
       
 10289     msg("Distributing member group documentation.\n");
       
 10290     distributeMemberGroupDocumentation();
       
 10291   }
       
 10292   
       
 10293   msg("Computing member references...\n");
       
 10294   computeMemberReferences(); 
       
 10295 
       
 10296   if (Config_getBool("INHERIT_DOCS"))
       
 10297   {
       
 10298     msg("Inheriting documentation...\n");
       
 10299     inheritDocumentation();
       
 10300   }
       
 10301 
       
 10302   // compute the shortest possible names of all files
       
 10303   // without loosing the uniqueness of the file names.
       
 10304   msg("Generating disk names...\n");
       
 10305   Doxygen::inputNameList->generateDiskNames();
       
 10306   
       
 10307   msg("Adding source references...\n");
       
 10308   addSourceReferences();
       
 10309 
       
 10310   msg("Adding xrefitems...\n");
       
 10311   addListReferences();
       
 10312   generateXRefPages();
       
 10313 
       
 10314   if (Config_getBool("SHOW_DIRECTORIES") && Config_getBool("DIRECTORY_GRAPH"))
       
 10315   {
       
 10316     msg("Computing dependencies between directories...\n");
       
 10317     computeDirDependencies();
       
 10318   }
       
 10319 
       
 10320   msg("Counting data structures...\n");
       
 10321   countDataStructures();
       
 10322  
       
 10323   msg("Resolving user defined references...\n");
       
 10324   resolveUserReferences();
       
 10325 
       
 10326   msg("Finding anchors and sections in the documentation...\n");
       
 10327   findSectionsInDocumentation();
       
 10328 
       
 10329   transferFunctionReferences();
       
 10330 
       
 10331   msg("Combining using relations...\n");
       
 10332   combineUsingRelations();
       
 10333 
       
 10334   msg("Adding members to index pages...\n");
       
 10335   addMembersToIndex();
       
 10336   dumpIncludeGraph();
       
 10337 }
       
 10338 
       
 10339 void generateOutput()
       
 10340 {
       
 10341   /**************************************************************************
       
 10342    *            Initialize output generators                                *
       
 10343    **************************************************************************/
       
 10344 
       
 10345   //// dump all symbols
       
 10346   //SDict<DefinitionList>::Iterator sdi(Doxygen::symbolMap);
       
 10347   //DefinitionList *dl;
       
 10348   //for (sdi.toFirst();(dl=sdi.current());++sdi)
       
 10349   //{
       
 10350   //  DefinitionListIterator dli(*dl);
       
 10351   //  Definition *d;
       
 10352   //  printf("Symbol: ");
       
 10353   //  for (dli.toFirst();(d=dli.current());++dli)
       
 10354   //  {
       
 10355   //    printf("%s ",d->qualifiedName().data());
       
 10356   //  }
       
 10357   //  printf("\n");
       
 10358   //}
       
 10359   if (g_dumpSymbolMap)
       
 10360   {
       
 10361     dumpSymbolMap();
       
 10362     exit(0);
       
 10363   }
       
 10364 
       
 10365   initDocParser();
       
 10366 
       
 10367   g_outputList = new OutputList(TRUE);
       
 10368   if (Config_getBool("GENERATE_HTML"))  
       
 10369   {
       
 10370     g_outputList->add(new HtmlGenerator);
       
 10371     HtmlGenerator::init();
       
 10372 #if 0
       
 10373     if (Config_getBool("GENERATE_INDEXLOG")) Doxygen::indexList.addIndex(new IndexLog);
       
 10374 #endif
       
 10375     bool generateHtmlHelp = Config_getBool("GENERATE_HTMLHELP");
       
 10376     bool generateEclipseHelp = Config_getBool("GENERATE_ECLIPSEHELP");
       
 10377     bool generateQhp      = Config_getBool("GENERATE_QHP");
       
 10378     bool generateTreeView = Config_getBool("GENERATE_TREEVIEW");
       
 10379     bool generateDocSet   = Config_getBool("GENERATE_DOCSET");
       
 10380     if (generateEclipseHelp) Doxygen::indexList.addIndex(new EclipseHelp);
       
 10381     if (generateHtmlHelp) Doxygen::indexList.addIndex(new HtmlHelp);
       
 10382     if (generateQhp)      Doxygen::indexList.addIndex(new Qhp);
       
 10383     if (generateTreeView) Doxygen::indexList.addIndex(new FTVHelp);
       
 10384     if (generateDocSet)   Doxygen::indexList.addIndex(new DocSets);
       
 10385     Doxygen::indexList.initialize();
       
 10386     Doxygen::indexList.addImageFile("tab_r.gif");
       
 10387     Doxygen::indexList.addImageFile("tab_l.gif");
       
 10388     Doxygen::indexList.addImageFile("tab_b.gif");
       
 10389     Doxygen::indexList.addStyleSheetFile("tabs.css");
       
 10390     Doxygen::indexList.addImageFile("doxygen.png");
       
 10391     if (Config_getBool("HTML_DYNAMIC_SECTIONS")) HtmlGenerator::generateSectionImages();
       
 10392     copyStyleSheet();
       
 10393   }
       
 10394   if (Config_getBool("GENERATE_LATEX")) 
       
 10395   {
       
 10396     g_outputList->add(new LatexGenerator);
       
 10397     LatexGenerator::init();
       
 10398   }
       
 10399   if (Config_getBool("GENERATE_MAN"))
       
 10400   {
       
 10401     g_outputList->add(new ManGenerator);
       
 10402     ManGenerator::init();
       
 10403   }
       
 10404   if (Config_getBool("GENERATE_RTF"))
       
 10405   {
       
 10406     g_outputList->add(new RTFGenerator);
       
 10407     RTFGenerator::init();
       
 10408   }
       
 10409 
       
 10410   if (Config_getBool("USE_HTAGS"))
       
 10411   {
       
 10412     Htags::useHtags = TRUE;
       
 10413     QCString htmldir = Config_getString("HTML_OUTPUT");
       
 10414     if (!Htags::execute(htmldir))
       
 10415        err("Error: USE_HTAGS is YES but htags(1) failed. \n");
       
 10416     if (!Htags::loadFilemap(htmldir))
       
 10417        err("Error: htags(1) ended normally but failed to load the filemap. \n");
       
 10418   }
       
 10419   
       
 10420   /**************************************************************************
       
 10421    *                        Generate documentation                          *
       
 10422    **************************************************************************/
       
 10423 
       
 10424   QFile *tag=0;
       
 10425   QCString &generateTagFile = Config_getString("GENERATE_TAGFILE");
       
 10426   if (!generateTagFile.isEmpty())
       
 10427   {
       
 10428     tag=new QFile(generateTagFile);
       
 10429     if (!tag->open(IO_WriteOnly))
       
 10430     {
       
 10431       err("Error: cannot open tag file %s for writing\n",
       
 10432           generateTagFile.data()
       
 10433          );
       
 10434       cleanUpDoxygen();
       
 10435       exit(1);
       
 10436     }
       
 10437     Doxygen::tagFile.setDevice(tag);
       
 10438     Doxygen::tagFile.setEncoding(QTextStream::UnicodeUTF8);
       
 10439     Doxygen::tagFile << "<?xml version='1.0' encoding='ISO-8859-1' standalone='yes' ?>" << endl;
       
 10440     Doxygen::tagFile << "<tagfile>" << endl;
       
 10441   }
       
 10442 
       
 10443   if (Config_getBool("GENERATE_HTML"))  writeDoxFont(Config_getString("HTML_OUTPUT"));
       
 10444   if (Config_getBool("GENERATE_LATEX")) writeDoxFont(Config_getString("LATEX_OUTPUT"));
       
 10445   if (Config_getBool("GENERATE_RTF"))   writeDoxFont(Config_getString("RTF_OUTPUT"));
       
 10446 
       
 10447   msg("Generating style sheet...\n");
       
 10448   //printf("writing style info\n");
       
 10449   QCString genString = 
       
 10450         theTranslator->trGeneratedAt(dateToString(TRUE),Config_getString("PROJECT_NAME"));
       
 10451   g_outputList->writeStyleInfo(0); // write first part
       
 10452   g_outputList->disableAllBut(OutputGenerator::Latex);
       
 10453   g_outputList->parseText(genString);
       
 10454   g_outputList->writeStyleInfo(1); // write second part
       
 10455   //parseText(*g_outputList,theTranslator->trWrittenBy());
       
 10456   g_outputList->writeStyleInfo(2); // write third part
       
 10457   g_outputList->parseText(genString);
       
 10458   g_outputList->writeStyleInfo(3); // write fourth part
       
 10459   //parseText(*g_outputList,theTranslator->trWrittenBy());
       
 10460   g_outputList->writeStyleInfo(4); // write last part
       
 10461   g_outputList->enableAll();
       
 10462   
       
 10463   static bool searchEngine      = Config_getBool("SEARCHENGINE");
       
 10464   static bool serverBasedSearch = Config_getBool("SERVER_BASED_SEARCH");
       
 10465 
       
 10466   // generate search indices (need to do this before writing other HTML
       
 10467   // pages as these contain a drop down menu with options depending on
       
 10468   // what categories we find in this function.
       
 10469   if (searchEngine)
       
 10470   {
       
 10471     QCString searchDirName = Config_getString("HTML_OUTPUT")+"/search";
       
 10472     QDir searchDir(searchDirName);
       
 10473     if (!searchDir.exists() && !searchDir.mkdir(searchDirName))
       
 10474     {
       
 10475       err("Could not create search results directory '%s/search'\n",searchDirName.data());
       
 10476       return;
       
 10477     }
       
 10478     HtmlGenerator::writeSearchData(searchDirName);
       
 10479     writeSearchStyleSheet();
       
 10480     if (serverBasedSearch)
       
 10481     {
       
 10482     }
       
 10483     else
       
 10484     {
       
 10485       writeJavascriptSearchIndex();
       
 10486     }
       
 10487   }
       
 10488 
       
 10489   //statistics();
       
 10490   
       
 10491   // count the number of documented elements in the lists we have built. 
       
 10492   // If the result is 0 we do not generate the lists and omit the 
       
 10493   // corresponding links in the index.
       
 10494   msg("Generating index page...\n"); 
       
 10495   writeIndex(*g_outputList);
       
 10496 
       
 10497   msg("Generating page index...\n");
       
 10498   writePageIndex(*g_outputList);
       
 10499   
       
 10500   msg("Generating example documentation...\n");
       
 10501   generateExampleDocs();
       
 10502 
       
 10503   msg("Generating file sources...\n");
       
 10504   if (!Htags::useHtags)
       
 10505   {
       
 10506     generateFileSources();
       
 10507   }
       
 10508 
       
 10509   msg("Generating file documentation...\n");
       
 10510   generateFileDocs();
       
 10511   
       
 10512   msg("Generating page documentation...\n");
       
 10513   generatePageDocs();
       
 10514   
       
 10515   msg("Generating group documentation...\n");
       
 10516   generateGroupDocs();
       
 10517 
       
 10518   msg("Generating group index...\n");
       
 10519   writeGroupIndex(*g_outputList);
       
 10520  
       
 10521   msg("Generating class documentation...\n");
       
 10522   generateClassDocs();
       
 10523   
       
 10524   if (Config_getBool("HAVE_DOT") && Config_getBool("GRAPHICAL_HIERARCHY"))
       
 10525   {
       
 10526     msg("Generating graphical class hierarchy...\n");
       
 10527     writeGraphicalClassHierarchy(*g_outputList);
       
 10528   }
       
 10529 
       
 10530   msg("Generating namespace index...\n");
       
 10531   generateNamespaceDocs();
       
 10532   
       
 10533   msg("Generating namespace member index...\n");
       
 10534   writeNamespaceMemberIndex(*g_outputList);
       
 10535 
       
 10536   if (Config_getBool("GENERATE_LEGEND"))
       
 10537   {
       
 10538     msg("Generating graph info page...\n");
       
 10539     writeGraphInfo(*g_outputList);
       
 10540   }
       
 10541 
       
 10542   if (Config_getBool("SHOW_DIRECTORIES"))
       
 10543   {
       
 10544     msg("Generating directory documentation...\n");
       
 10545     generateDirDocs(*g_outputList);
       
 10546   }
       
 10547 
       
 10548   msg("Generating file index...\n");
       
 10549   writeFileIndex(*g_outputList);
       
 10550  
       
 10551   if (Config_getBool("SHOW_DIRECTORIES"))
       
 10552   {
       
 10553     msg("Generating directory index...\n");
       
 10554     writeDirIndex(*g_outputList);
       
 10555   }
       
 10556 
       
 10557   msg("Generating example index...\n");
       
 10558   writeExampleIndex(*g_outputList);
       
 10559   
       
 10560   msg("Generating file member index...\n");
       
 10561   writeFileMemberIndex(*g_outputList);
       
 10562 
       
 10563   
       
 10564   //writeDirDependencyGraph(Config_getString("HTML_OUTPUT"));
       
 10565   
       
 10566   if (Config_getBool("GENERATE_RTF"))
       
 10567   {
       
 10568     msg("Combining RTF output...\n");
       
 10569     if (!RTFGenerator::preProcessFileInplace(Config_getString("RTF_OUTPUT"),"refman.rtf"))
       
 10570     {
       
 10571       err("An error occurred during post-processing the RTF files!\n");
       
 10572     }
       
 10573   }
       
 10574   
       
 10575   if (Doxygen::formulaList.count()>0 && Config_getBool("GENERATE_HTML"))
       
 10576   {
       
 10577     msg("Generating bitmaps for formulas in HTML...\n");
       
 10578     Doxygen::formulaList.generateBitmaps(Config_getString("HTML_OUTPUT"));
       
 10579   }
       
 10580   
       
 10581   //if (Config_getBool("GENERATE_HTML") && Config_getBool("GENERATE_HTMLHELP"))  
       
 10582   //{
       
 10583   //  HtmlHelp::getInstance()->finalize();
       
 10584   //}
       
 10585   //if (Config_getBool("GENERATE_HTML") && Config_getBool("GENERATE_TREEVIEW"))  
       
 10586   //{
       
 10587   //  FTVHelp::getInstance()->finalize();
       
 10588   //}
       
 10589 
       
 10590   Doxygen::indexList.finalize();
       
 10591 
       
 10592   if (!Config_getString("GENERATE_TAGFILE").isEmpty())
       
 10593   {
       
 10594     Doxygen::tagFile << "</tagfile>" << endl;
       
 10595     delete tag;
       
 10596   }
       
 10597 
       
 10598   if (Config_getBool("DOT_CLEANUP"))
       
 10599   {
       
 10600     if (Config_getBool("GENERATE_HTML"))
       
 10601       removeDoxFont(Config_getString("HTML_OUTPUT"));
       
 10602     if (Config_getBool("GENERATE_RTF"))  
       
 10603       removeDoxFont(Config_getString("RTF_OUTPUT"));
       
 10604     if (Config_getBool("GENERATE_LATEX"))  
       
 10605       removeDoxFont(Config_getString("LATEX_OUTPUT"));
       
 10606   }
       
 10607 
       
 10608   if (Config_getBool("GENERATE_XML"))
       
 10609   {
       
 10610     msg("Generating XML output...\n");
       
 10611     generateXML();
       
 10612   }
       
 10613   if (Config_getBool("GENERATE_XML_DITA"))
       
 10614   {
       
 10615     msg("Generating XML DITA output...\n");
       
 10616     generateXMLDITA();
       
 10617   }
       
 10618   if (Config_getBool("GENERATE_AUTOGEN_DEF"))
       
 10619   {
       
 10620     msg("Generating AutoGen DEF output...\n");
       
 10621     generateDEF();
       
 10622   }
       
 10623   if (Config_getBool("GENERATE_PERLMOD"))
       
 10624   {
       
 10625     msg("Generating Perl module output...\n");
       
 10626     generatePerlMod();
       
 10627   }
       
 10628   if (Config_getBool("GENERATE_HTML") &&
       
 10629       Config_getBool("GENERATE_HTMLHELP") && 
       
 10630       !Config_getString("HHC_LOCATION").isEmpty())
       
 10631   {
       
 10632     msg("Running html help compiler...\n");
       
 10633     QString oldDir = QDir::currentDirPath();
       
 10634     QDir::setCurrent(Config_getString("HTML_OUTPUT"));
       
 10635     if (portable_system(Config_getString("HHC_LOCATION"), "index.hhp", FALSE))
       
 10636     {
       
 10637       err("Error: failed to run html help compiler on index.hhp\n");
       
 10638     }
       
 10639     QDir::setCurrent(oldDir);
       
 10640   }
       
 10641   if ( Config_getBool("GENERATE_HTML") &&
       
 10642        Config_getBool("GENERATE_QHP") && 
       
 10643       !Config_getString("QHG_LOCATION").isEmpty())
       
 10644   {
       
 10645     msg("Running qhelpgenerator...\n");
       
 10646     QCString const qhpFileName = Qhp::getQhpFileName();
       
 10647     QCString const qchFileName = getQchFileName();
       
 10648 
       
 10649     QCString const args = QCString().sprintf("%s -o \"%s\"", qhpFileName.data(), qchFileName.data());
       
 10650     QString const oldDir = QDir::currentDirPath();
       
 10651     QDir::setCurrent(Config_getString("HTML_OUTPUT"));
       
 10652     if (portable_system(Config_getString("QHG_LOCATION"), args.data(), FALSE))
       
 10653     {
       
 10654       err("Error: failed to run qhelpgenerator on index.qhp\n");
       
 10655     }
       
 10656     QDir::setCurrent(oldDir);
       
 10657   }
       
 10658 
       
 10659   if (Config_getBool("GENERATE_HTML") && searchEngine && serverBasedSearch)
       
 10660   {
       
 10661     msg("Generating search index\n");
       
 10662     HtmlGenerator::writeSearchPage();
       
 10663     Doxygen::searchIndex->write(Config_getString("HTML_OUTPUT")+"/search/search.idx");
       
 10664   }
       
 10665 
       
 10666   if (Debug::isFlagSet(Debug::Time))
       
 10667   {
       
 10668     msg("Total elapsed time: %.3f seconds\n(of which %.3f seconds waiting for external tools to finish)\n",
       
 10669          ((double)Doxygen::runningTime.elapsed())/1000.0,
       
 10670          portable_getSysElapsedTime()
       
 10671         );
       
 10672   }
       
 10673 
       
 10674   /**************************************************************************
       
 10675    *                        Start cleaning up                               *
       
 10676    **************************************************************************/
       
 10677 
       
 10678   //Doxygen::symbolCache->printStats();
       
 10679   //Doxygen::symbolStorage->printStats();
       
 10680   cleanUpDoxygen();
       
 10681 
       
 10682   finializeDocParser();
       
 10683   Doxygen::symbolStorage->close();
       
 10684   QDir thisDir;
       
 10685   thisDir.remove(Doxygen::objDBFileName);
       
 10686   Config::deleteInstance();
       
 10687   QTextCodec::deleteAllCodecs();
       
 10688   delete Doxygen::symbolCache;
       
 10689   delete Doxygen::symbolMap;
       
 10690   delete Doxygen::symbolStorage;
       
 10691   g_successfulRun=TRUE;
       
 10692   msg("generateOutput() exiting.\n");
       
 10693 }
       
 10694