Fix for UBSan build
[platform/upstream/doxygen.git] / src / doxygen.cpp
1 /******************************************************************************
2  *
3  * Copyright (C) 1997-2012 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 #include <qptrdict.h>
30
31 #include "version.h"
32 #include "doxygen.h"
33 #include "scanner.h"
34 #include "entry.h"
35 #include "index.h"
36 #include "logos.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 "msc.h"
44 #include "docparser.h"
45 #include "dirdef.h"
46 #include "outputlist.h"
47 #include "declinfo.h"
48 #include "htmlgen.h"
49 #include "latexgen.h"
50 #include "mangen.h"
51 #include "language.h"
52 #include "debug.h"
53 #include "htmlhelp.h"
54 #include "qhp.h"
55 #include "ftvhelp.h"
56 #include "defargs.h"
57 #include "rtfgen.h"
58 #include "xmlgen.h"
59 #include "defgen.h"
60 #include "perlmodgen.h"
61 #include "reflist.h"
62 #include "pagedef.h"
63 #include "bufstr.h"
64 #include "commentcnv.h"
65 #include "cmdmapper.h"
66 #include "searchindex.h"
67 #include "parserintf.h"
68 #include "htags.h"
69 #include "pyscanner.h"
70 #include "fortranscanner.h"
71 #include "dbusxmlscanner.h"
72 #include "tclscanner.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 #include "cite.h"
82 #include "filestorage.h"
83 #include "markdown.h"
84 #include "arguments.h"
85
86 #include "layout.h"
87
88 #define RECURSE_ENTRYTREE(func,var) \
89   do { if (var->children()) { \
90     EntryNavListIterator eli(*var->children()); \
91     for (;eli.current();++eli) func(eli.current()); \
92   } } while(0) 
93
94
95 #if !defined(_WIN32) || defined(__CYGWIN__)
96 #include <signal.h>
97 #define HAS_SIGNALS
98 #endif
99
100 // globally accessible variables
101 ClassSDict      *Doxygen::classSDict = 0;
102 ClassSDict      *Doxygen::hiddenClasses = 0;
103 NamespaceSDict  *Doxygen::namespaceSDict = 0;
104 MemberNameSDict *Doxygen::memberNameSDict = 0;
105 MemberNameSDict *Doxygen::functionNameSDict = 0;   
106 FileNameList    *Doxygen::inputNameList = 0;       // all input files
107 FileNameDict    *Doxygen::inputNameDict = 0;          
108 GroupSDict      *Doxygen::groupSDict = 0;
109 FormulaList      Doxygen::formulaList;             // all formulas
110 FormulaDict      Doxygen::formulaDict(1009);       // all formulas
111 FormulaDict      Doxygen::formulaNameDict(1009);   // the label name of all formulas
112 PageSDict       *Doxygen::pageSDict = 0;
113 PageSDict       *Doxygen::exampleSDict = 0;
114 SectionDict      Doxygen::sectionDict(257);        // all page sections
115 CiteDict        *Doxygen::citeDict=0;              // database of bibliographic references
116 StringDict       Doxygen::aliasDict(257);          // aliases
117 FileNameDict    *Doxygen::includeNameDict = 0;     // include names
118 FileNameDict    *Doxygen::exampleNameDict = 0;     // examples
119 FileNameDict    *Doxygen::imageNameDict = 0;       // images
120 FileNameDict    *Doxygen::dotFileNameDict = 0;     // dot files
121 FileNameDict    *Doxygen::mscFileNameDict = 0;     // dot files
122 StringDict       Doxygen::namespaceAliasDict(257); // all namespace aliases
123 StringDict       Doxygen::tagDestinationDict(257); // all tag locations
124 QDict<void>      Doxygen::expandAsDefinedDict(257); // all macros that should be expanded
125 QIntDict<MemberGroupInfo> Doxygen::memGrpInfoDict(1009); // dictionary of the member groups heading
126 PageDef         *Doxygen::mainPage = 0;
127 bool             Doxygen::insideMainPage = FALSE; // are we generating docs for the main page?
128 FTextStream      Doxygen::tagFile;
129 NamespaceDef    *Doxygen::globalScope = 0;
130 QDict<RefList>  *Doxygen::xrefLists = new QDict<RefList>; // dictionary of cross-referenced item lists
131 bool             Doxygen::parseSourcesNeeded = FALSE;
132 QTime            Doxygen::runningTime;
133 SearchIndexIntf *Doxygen::searchIndex=0;
134 QDict<DefinitionIntf> *Doxygen::symbolMap;
135 bool             Doxygen::outputToWizard=FALSE;
136 QDict<int> *     Doxygen::htmlDirMap = 0;
137 QCache<LookupInfo> *Doxygen::lookupCache;
138 DirSDict        *Doxygen::directories;
139 SDict<DirRelation> Doxygen::dirRelations(257);
140 ParserManager   *Doxygen::parserManager = 0;
141 QCString Doxygen::htmlFileExtension;
142 bool             Doxygen::suppressDocWarnings = FALSE;
143 ObjCache        *Doxygen::symbolCache = 0;
144 Store           *Doxygen::symbolStorage;
145 QCString         Doxygen::objDBFileName;
146 QCString         Doxygen::entryDBFileName;
147 bool             Doxygen::gatherDefines = TRUE;
148 IndexList        Doxygen::indexList;
149 int              Doxygen::subpageNestingLevel = 0;
150 bool             Doxygen::userComments = FALSE;
151 QCString         Doxygen::spaces;
152 bool             Doxygen::generatingXmlOutput = FALSE;
153 bool             Doxygen::markdownSupport = TRUE;
154 GenericsSDict    Doxygen::genericsDict;
155
156 // locally accessible globals
157 static QDict<EntryNav>  g_classEntries(1009);
158 static StringList       g_inputFiles;         
159 static QDict<void>      g_compoundKeywordDict(7);  // keywords recognised as compounds
160 static OutputList      *g_outputList = 0;          // list of output generating objects
161 static QDict<FileDef>   g_usingDeclarations(1009); // used classes
162 static FileStorage     *g_storage = 0;
163 static bool             g_successfulRun = FALSE;
164 static bool             g_dumpSymbolMap = FALSE;
165 static bool             g_dumpConfigAsXML = FALSE;
166
167 void clearAll()
168 {
169   g_inputFiles.clear();      
170   //g_excludeNameDict.clear();  
171   //delete g_outputList; g_outputList=0;
172
173   Doxygen::classSDict->clear();       
174   Doxygen::namespaceSDict->clear();   
175   Doxygen::pageSDict->clear();         
176   Doxygen::exampleSDict->clear();      
177   Doxygen::inputNameList->clear();   
178   Doxygen::formulaList.clear();     
179   Doxygen::sectionDict.clear();       
180   Doxygen::inputNameDict->clear();    
181   Doxygen::includeNameDict->clear();  
182   Doxygen::exampleNameDict->clear();  
183   Doxygen::imageNameDict->clear();     
184   Doxygen::dotFileNameDict->clear();     
185   Doxygen::mscFileNameDict->clear();     
186   Doxygen::formulaDict.clear();      
187   Doxygen::formulaNameDict.clear();  
188   Doxygen::tagDestinationDict.clear();
189   delete Doxygen::citeDict;
190   delete Doxygen::mainPage; Doxygen::mainPage=0;
191 }
192
193 void statistics()
194 {
195   fprintf(stderr,"--- inputNameDict stats ----\n");
196   Doxygen::inputNameDict->statistics();
197   fprintf(stderr,"--- includeNameDict stats ----\n");
198   Doxygen::includeNameDict->statistics();
199   fprintf(stderr,"--- exampleNameDict stats ----\n");
200   Doxygen::exampleNameDict->statistics();
201   fprintf(stderr,"--- imageNameDict stats ----\n");
202   Doxygen::imageNameDict->statistics();
203   fprintf(stderr,"--- dotFileNameDict stats ----\n");
204   Doxygen::dotFileNameDict->statistics();
205   fprintf(stderr,"--- mscFileNameDict stats ----\n");
206   Doxygen::mscFileNameDict->statistics();
207   //fprintf(stderr,"--- g_excludeNameDict stats ----\n");
208   //g_excludeNameDict.statistics();
209   fprintf(stderr,"--- aliasDict stats ----\n");
210   Doxygen::aliasDict.statistics();
211   fprintf(stderr,"--- typedefDict stats ----\n");
212   fprintf(stderr,"--- namespaceAliasDict stats ----\n");
213   Doxygen::namespaceAliasDict.statistics();
214   fprintf(stderr,"--- formulaDict stats ----\n");
215   Doxygen::formulaDict.statistics();
216   fprintf(stderr,"--- formulaNameDict stats ----\n");
217   Doxygen::formulaNameDict.statistics();
218   fprintf(stderr,"--- tagDestinationDict stats ----\n");
219   Doxygen::tagDestinationDict.statistics();
220   fprintf(stderr,"--- g_compoundKeywordDict stats ----\n");
221   g_compoundKeywordDict.statistics();
222   fprintf(stderr,"--- expandAsDefinedDict stats ----\n");
223   Doxygen::expandAsDefinedDict.statistics();
224   fprintf(stderr,"--- memGrpInfoDict stats ----\n");
225   Doxygen::memGrpInfoDict.statistics();
226 }
227
228
229
230 static void addMemberDocs(EntryNav *rootNav,MemberDef *md, const char *funcDecl,
231                    ArgumentList *al,bool over_load,NamespaceSDict *nl=0);
232 static void findMember(EntryNav *rootNav,
233                        QCString funcDecl,
234                        bool overloaded,
235                        bool isFunc
236                       );
237
238 /** A struct contained the data for an STL class */
239 struct STLInfo
240 {
241   const char *className;
242   const char *baseClass1;
243   const char *baseClass2;
244   const char *templType1;
245   const char *templName1;
246   const char *templType2;
247   const char *templName2;
248   bool virtualInheritance;
249   bool iterators;
250 };
251
252 static STLInfo g_stlinfo[] =
253 {
254   // className              baseClass1                      baseClass2             templType1     templName1     templType2    templName2     virtInheritance  // iterators
255   { "allocator",            0,                              0,                     "T",           "elements",    0,            0,             FALSE,              FALSE },
256   { "array",                0,                              0,                     "T",           "elements",    0,            0,             FALSE,              FALSE }, // C++11
257   { "auto_ptr",             0,                              0,                     "T",           "ptr",         0,            0,             FALSE,              FALSE }, // deprecated
258   { "smart_ptr",            0,                              0,                     "T",           "ptr",         0,            0,             FALSE,              FALSE }, // C++11
259   { "unique_ptr",           0,                              0,                     "T",           "ptr",         0,            0,             FALSE,              FALSE }, // C++11
260   { "weak_ptr",             0,                              0,                     "T",           "ptr",         0,            0,             FALSE,              FALSE }, // C++11
261   { "ios_base",             0,                              0,                     0,             0,             0,            0,             FALSE,              FALSE }, // C++11
262   { "error_code",           0,                              0,                     0,             0,             0,            0,             FALSE,              FALSE }, // C++11
263   { "error_category",       0,                              0,                     0,             0,             0,            0,             FALSE,              FALSE }, // C++11
264   { "system_error",         0,                              0,                     0,             0,             0,            0,             FALSE,              FALSE }, // C++11
265   { "error_condition",      0,                              0,                     0,             0,             0,            0,             FALSE,              FALSE }, // C++11
266   { "thread",               0,                              0,                     0,             0,             0,            0,             FALSE,              FALSE }, // C++11
267   { "basic_ios",            "ios_base",                     0,                     "Char",        0,             0,            0,             FALSE,              FALSE },
268   { "basic_istream",        "basic_ios<Char>",              0,                     "Char",        0,             0,            0,             TRUE,               FALSE },
269   { "basic_ostream",        "basic_ios<Char>",              0,                     "Char",        0,             0,            0,             TRUE,               FALSE },
270   { "basic_iostream",       "basic_istream<Char>",          "basic_ostream<Char>", "Char",        0,             0,            0,             FALSE,              FALSE },
271   { "basic_ifstream",       "basic_istream<Char>",          0,                     "Char",        0,             0,            0,             FALSE,              FALSE },
272   { "basic_ofstream",       "basic_ostream<Char>",          0,                     "Char",        0,             0,            0,             FALSE,              FALSE },
273   { "basic_fstream",        "basic_iostream<Char>",         0,                     "Char",        0,             0,            0,             FALSE,              FALSE },
274   { "basic_istringstream",  "basic_istream<Char>",          0,                     "Char",        0,             0,            0,             FALSE,              FALSE },
275   { "basic_ostringstream",  "basic_ostream<Char>",          0,                     "Char",        0,             0,            0,             FALSE,              FALSE },
276   { "basic_stringstream",   "basic_iostream<Char>",         0,                     "Char",        0,             0,            0,             FALSE,              FALSE },
277   { "ios",                  "basic_ios<char>",              0,                     0,             0,             0,            0,             FALSE,              FALSE },
278   { "wios",                 "basic_ios<wchar_t>",           0,                     0,             0,             0,            0,             FALSE,              FALSE },
279   { "istream",              "basic_istream<char>",          0,                     0,             0,             0,            0,             FALSE,              FALSE },
280   { "wistream",             "basic_istream<wchar_t>",       0,                     0,             0,             0,            0,             FALSE,              FALSE },
281   { "ostream",              "basic_ostream<char>",          0,                     0,             0,             0,            0,             FALSE,              FALSE },
282   { "wostream",             "basic_ostream<wchar_t>",       0,                     0,             0,             0,            0,             FALSE,              FALSE },
283   { "ifstream",             "basic_ifstream<char>",         0,                     0,             0,             0,            0,             FALSE,              FALSE },
284   { "wifstream",            "basic_ifstream<wchar_t>",      0,                     0,             0,             0,            0,             FALSE,              FALSE },
285   { "ofstream",             "basic_ofstream<char>",         0,                     0,             0,             0,            0,             FALSE,              FALSE },
286   { "wofstream",            "basic_ofstream<wchar_t>",      0,                     0,             0,             0,            0,             FALSE,              FALSE },
287   { "fstream",              "basic_fstream<char>",          0,                     0,             0,             0,            0,             FALSE,              FALSE },
288   { "wfstream",             "basic_fstream<wchar_t>",       0,                     0,             0,             0,            0,             FALSE,              FALSE },
289   { "istringstream",        "basic_istringstream<char>",    0,                     0,             0,             0,            0,             FALSE,              FALSE },
290   { "wistringstream",       "basic_istringstream<wchar_t>", 0,                     0,             0,             0,            0,             FALSE,              FALSE },
291   { "ostringstream",        "basic_ostringstream<char>",    0,                     0,             0,             0,            0,             FALSE,              FALSE },
292   { "wostringstream",       "basic_ostringstream<wchar_t>", 0,                     0,             0,             0,            0,             FALSE,              FALSE },
293   { "stringstream",         "basic_stringstream<char>",     0,                     0,             0,             0,            0,             FALSE,              FALSE },
294   { "wstringstream",        "basic_stringstream<wchar_t>",  0,                     0,             0,             0,            0,             FALSE,              FALSE },
295   { "basic_string",         0,                              0,                     "Char",        0,             0,            0,             FALSE,              TRUE  },
296   { "string",               "basic_string<char>",           0,                     0,             0,             0,            0,             FALSE,              TRUE  },
297   { "wstring",              "basic_string<wchar_t>",        0,                     0,             0,             0,            0,             FALSE,              TRUE  },
298   { "complex",              0,                              0,                     0,             0,             0,            0,             FALSE,              FALSE },
299   { "bitset",               0,                              0,                     "Bits",        0,             0,            0,             FALSE,              FALSE },
300   { "deque",                0,                              0,                     "T",           "elements",    0,            0,             FALSE,              TRUE  },
301   { "list",                 0,                              0,                     "T",           "elements",    0,            0,             FALSE,              TRUE  },
302   { "forward_list",         0,                              0,                     "T",           "elements",    0,            0,             FALSE,              TRUE  }, // C++11
303   { "map",                  0,                              0,                     "K",           "keys",        "T",          "elements",    FALSE,              TRUE  },
304   { "unordered_map",        0,                              0,                     "K",           "keys",        "T",          "elements",    FALSE,              TRUE  }, // C++11
305   { "multimap",             0,                              0,                     "K",           "keys",        "T",          "elements",    FALSE,              TRUE  },
306   { "unordered_multimap",   0,                              0,                     "K",           "keys",        "T",          "elements",    FALSE,              TRUE  }, // C++11
307   { "set",                  0,                              0,                     "K",           "keys",        0,            0,             FALSE,              TRUE  },
308   { "unordered_set",        0,                              0,                     "K",           "keys",        0,            0,             FALSE,              TRUE  }, // C++11
309   { "multiset",             0,                              0,                     "K",           "keys",        0,            0,             FALSE,              TRUE  },
310   { "unordered_multiset",   0,                              0,                     "K",           "keys",        0,            0,             FALSE,              TRUE  }, // C++11
311   { "vector",               0,                              0,                     "T",           "elements",    0,            0,             FALSE,              TRUE  },
312   { "queue",                0,                              0,                     "T",           "elements",    0,            0,             FALSE,              FALSE },
313   { "priority_queue",       0,                              0,                     "T",           "elements",    0,            0,             FALSE,              FALSE },
314   { "stack",                0,                              0,                     "T",           "elements",    0,            0,             FALSE,              FALSE },
315   { "valarray",             0,                              0,                     "T",           "elements",    0,            0,             FALSE,              FALSE },
316   { "exception",            0,                              0,                     0,             0,             0,            0,             FALSE,              FALSE },
317   { "bad_alloc",            "exception",                    0,                     0,             0,             0,            0,             FALSE,              FALSE },
318   { "bad_cast",             "exception",                    0,                     0,             0,             0,            0,             FALSE,              FALSE },
319   { "bad_typeid",           "exception",                    0,                     0,             0,             0,            0,             FALSE,              FALSE },
320   { "logic_error",          "exception",                    0,                     0,             0,             0,            0,             FALSE,              FALSE },
321   { "ios_base::failure",    "exception",                    0,                     0,             0,             0,            0,             FALSE,              FALSE },
322   { "runtime_error",        "exception",                    0,                     0,             0,             0,            0,             FALSE,              FALSE },
323   { "bad_exception",        "exception",                    0,                     0,             0,             0,            0,             FALSE,              FALSE },
324   { "domain_error",         "logic_error",                  0,                     0,             0,             0,            0,             FALSE,              FALSE },
325   { "invalid_argument",     "logic_error",                  0,                     0,             0,             0,            0,             FALSE,              FALSE },
326   { "length_error",         "logic_error",                  0,                     0,             0,             0,            0,             FALSE,              FALSE },
327   { "out_of_range",         "logic_error",                  0,                     0,             0,             0,            0,             FALSE,              FALSE },
328   { "range_error",          "runtime_error",                0,                     0,             0,             0,            0,             FALSE,              FALSE },
329   { "overflow_error",       "runtime_error",                0,                     0,             0,             0,            0,             FALSE,              FALSE },
330   { "underflow_error",      "runtime_error",                0,                     0,             0,             0,            0,             FALSE,              FALSE },
331   { 0,                      0,                              0,                     0,             0,             0,            0,             FALSE,              FALSE }
332 };
333
334 static void addSTLMember(EntryNav *rootNav,const char *type,const char *name)
335 {
336   Entry *memEntry = new Entry;
337   memEntry->name       = name;
338   memEntry->type       = type;
339   memEntry->protection = Public;
340   memEntry->section    = Entry::VARIABLE_SEC;
341   memEntry->brief      = "STL member";
342   memEntry->hidden     = FALSE; 
343   memEntry->artificial = TRUE;
344   //memEntry->parent     = root;
345   //root->addSubEntry(memEntry);
346   EntryNav *memEntryNav = new EntryNav(rootNav,memEntry);
347   memEntryNav->setEntry(memEntry);
348   rootNav->addChild(memEntryNav);
349 }
350
351 static void addSTLIterator(EntryNav *classEntryNav,const char *name)
352 {
353   Entry *iteratorClassEntry = new Entry;
354   iteratorClassEntry->fileName  = "[STL]";
355   iteratorClassEntry->startLine = 1;
356   iteratorClassEntry->name      = name;
357   iteratorClassEntry->section   = Entry::CLASS_SEC;
358   iteratorClassEntry->brief     = "STL iterator class";
359   iteratorClassEntry->hidden    = FALSE;
360   iteratorClassEntry->artificial= TRUE;
361   EntryNav *iteratorClassEntryNav = new EntryNav(classEntryNav,iteratorClassEntry);
362   iteratorClassEntryNav->setEntry(iteratorClassEntry);
363   classEntryNav->addChild(iteratorClassEntryNav);
364 }
365
366
367 static void addSTLClasses(EntryNav *rootNav)
368 {
369   Entry *namespaceEntry = new Entry;
370   namespaceEntry->fileName  = "[STL]";
371   namespaceEntry->startLine = 1;
372   //namespaceEntry->parent    = rootNav->entry();
373   namespaceEntry->name      = "std";
374   namespaceEntry->section   = Entry::NAMESPACE_SEC;
375   namespaceEntry->brief     = "STL namespace";
376   namespaceEntry->hidden    = FALSE;
377   namespaceEntry->artificial= TRUE;
378   //root->addSubEntry(namespaceEntry);
379   EntryNav *namespaceEntryNav = new EntryNav(rootNav,namespaceEntry);
380   namespaceEntryNav->setEntry(namespaceEntry);
381   rootNav->addChild(namespaceEntryNav);
382   
383   STLInfo *info = g_stlinfo;
384   while (info->className)
385   {
386     //printf("Adding STL class %s\n",info->className);
387     QCString fullName = info->className;
388     fullName.prepend("std::");
389
390     // add fake Entry for the class
391     Entry *classEntry = new Entry;
392     classEntry->fileName  = "[STL]";
393     classEntry->startLine = 1;
394     classEntry->name      = fullName;
395     //classEntry->parent    = namespaceEntry;
396     classEntry->section   = Entry::CLASS_SEC;
397     classEntry->brief     = "STL class";
398     classEntry->hidden    = FALSE;
399     classEntry->artificial= TRUE;
400     //namespaceEntry->addSubEntry(classEntry);
401     EntryNav *classEntryNav = new EntryNav(namespaceEntryNav,classEntry);
402     classEntryNav->setEntry(classEntry);
403     namespaceEntryNav->addChild(classEntryNav);
404
405     // add template arguments to class
406     if (info->templType1)
407     {
408       ArgumentList *al = new ArgumentList;
409       Argument *a=new Argument;
410       a->type="typename";
411       a->name=info->templType1;
412       al->append(a);
413       if (info->templType2) // another template argument
414       {
415         a=new Argument;
416         a->type="typename";
417         a->name=info->templType2;
418         al->append(a);
419       }
420       classEntry->tArgLists = new QList<ArgumentList>;
421       classEntry->tArgLists->setAutoDelete(TRUE);
422       classEntry->tArgLists->append(al);
423     }
424     // add member variables
425     if (info->templName1)
426     {
427       addSTLMember(classEntryNav,info->templType1,info->templName1);
428     }
429     if (info->templName2)
430     {
431       addSTLMember(classEntryNav,info->templType2,info->templName2);
432     }
433     if (fullName=="std::auto_ptr" || fullName=="std::smart_ptr" ||
434         fullName=="std::unique_ptr" || fullName=="std::weak_ptr")
435     {
436       Entry *memEntry = new Entry;
437       memEntry->name       = "operator->";
438       memEntry->args       = "()";
439       memEntry->type       = "T*";
440       memEntry->protection = Public;
441       memEntry->section    = Entry::FUNCTION_SEC;
442       memEntry->brief      = "STL member";
443       memEntry->hidden     = FALSE; 
444       memEntry->artificial = FALSE;
445       EntryNav *memEntryNav = new EntryNav(classEntryNav,memEntry);
446       memEntryNav->setEntry(memEntry);
447       classEntryNav->addChild(memEntryNav);
448     }
449     if (info->baseClass1)
450     {
451       classEntry->extends->append(new BaseInfo(info->baseClass1,Public,info->virtualInheritance?Virtual:Normal));
452     }
453     if (info->baseClass2)
454     {
455       classEntry->extends->append(new BaseInfo(info->baseClass2,Public,info->virtualInheritance?Virtual:Normal));
456     }
457     if (info->iterators)
458     {
459       // add iterator class
460       addSTLIterator(classEntryNav,fullName+"::iterator");
461       addSTLIterator(classEntryNav,fullName+"::const_iterator");
462       addSTLIterator(classEntryNav,fullName+"::reverse_iterator");
463       addSTLIterator(classEntryNav,fullName+"::const_reverse_iterator");
464     }
465     info++;
466   }
467 }
468
469 //----------------------------------------------------------------------------
470
471 static Definition *findScopeFromQualifiedName(Definition *startScope,const QCString &n,
472                                               FileDef *fileScope=0);
473
474 static void addPageToContext(PageDef *pd,EntryNav *rootNav)
475 {
476   if (rootNav->parent()) // add the page to it's scope
477   {
478     QCString scope = rootNav->parent()->name();
479     if (rootNav->parent()->section()==Entry::PACKAGEDOC_SEC)
480     {
481       scope=substitute(scope,".","::");
482     }
483     scope = stripAnonymousNamespaceScope(scope);
484     scope+="::"+pd->name();
485     Definition *d = findScopeFromQualifiedName(Doxygen::globalScope,scope);
486     if (d) 
487     {
488       pd->setPageScope(d);
489     }
490   }
491 }
492
493 static void addRelatedPage(EntryNav *rootNav)
494 {
495   Entry *root = rootNav->entry();
496   GroupDef *gd=0;
497   QListIterator<Grouping> gli(*root->groups);
498   Grouping *g;
499   for (;(g=gli.current());++gli)
500   {
501     if (!g->groupname.isEmpty() && (gd=Doxygen::groupSDict->find(g->groupname))) break;
502   }
503   //printf("---> addRelatedPage() %s gd=%p\n",root->name.data(),gd);
504   QCString doc;
505   if (root->brief.isEmpty())
506   {
507     doc=root->doc+root->inbodyDocs;
508   }
509   else
510   {
511     doc=root->brief+"\n\n"+root->doc+root->inbodyDocs;
512   }
513   PageDef *pd = addRelatedPage(root->name,root->args,doc,root->anchors,
514       root->docFile,root->docLine,
515       root->sli,
516       gd,rootNav->tagInfo(),
517       root->lang
518      );
519   if (pd)
520   {
521     pd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
522     pd->addSectionsToDefinition(root->anchors);
523     pd->setShowToc(root->stat);
524     addPageToContext(pd,rootNav);
525   }
526 }
527
528 static void buildGroupListFiltered(EntryNav *rootNav,bool additional, bool includeExternal)
529 {
530   if (rootNav->section()==Entry::GROUPDOC_SEC && !rootNav->name().isEmpty() && 
531         ((!includeExternal && rootNav->tagInfo()==0) ||
532          ( includeExternal && rootNav->tagInfo()!=0))
533      )
534   {
535     rootNav->loadEntry(g_storage);
536     Entry *root = rootNav->entry();
537
538     if ((root->groupDocType==Entry::GROUPDOC_NORMAL && !additional) ||
539         (root->groupDocType!=Entry::GROUPDOC_NORMAL &&  additional))
540     {
541       GroupDef *gd = Doxygen::groupSDict->find(root->name);
542       //printf("Processing group '%s':'%s' add=%d ext=%d gd=%p\n",
543       //    root->type.data(),root->name.data(),additional,includeExternal,gd);
544
545       if (gd)
546       {
547         if ( !gd->hasGroupTitle() )
548         {
549           gd->setGroupTitle( root->type );
550         }
551         else if ( root->type.length() > 0 && root->name != root->type && gd->groupTitle() != root->type )
552         {
553           warn( root->fileName,root->startLine,
554               "group %s: ignoring title \"%s\" that does not match old title \"%s\"\n",
555               qPrint(root->name), qPrint(root->type), qPrint(gd->groupTitle()) );
556         }
557         gd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
558         gd->setDocumentation( root->doc, root->docFile, root->docLine );
559         gd->setInbodyDocumentation( root->inbodyDocs, root->inbodyFile, root->inbodyLine );
560         gd->addSectionsToDefinition(root->anchors);
561         gd->setRefItems(root->sli);
562         gd->setLanguage(root->lang);
563       }
564       else
565       {
566         if (rootNav->tagInfo())
567         {
568           gd = new GroupDef(root->fileName,root->startLine,root->name,root->type,rootNav->tagInfo()->fileName);
569           gd->setReference(rootNav->tagInfo()->tagName);
570         }
571         else
572         {
573           gd = new GroupDef(root->fileName,root->startLine,root->name,root->type);
574         }
575         gd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
576         // allow empty docs for group
577         gd->setDocumentation(!root->doc.isEmpty() ? root->doc : QCString(" "),root->docFile,root->docLine,FALSE);
578         gd->setInbodyDocumentation( root->inbodyDocs, root->inbodyFile, root->inbodyLine );
579         gd->addSectionsToDefinition(root->anchors);
580         Doxygen::groupSDict->append(root->name,gd);
581         gd->setRefItems(root->sli);
582         gd->setLanguage(root->lang);
583       }
584     }
585
586     rootNav->releaseEntry();
587   }
588   if (rootNav->children())
589   {
590     EntryNavListIterator eli(*rootNav->children());
591     EntryNav *e;
592     for (;(e=eli.current());++eli)
593     {
594       buildGroupListFiltered(e,additional,includeExternal);
595     }
596   }
597 }
598
599 static void buildGroupList(EntryNav *rootNav)
600 {
601   // --- first process only local groups
602   // first process the @defgroups blocks
603   buildGroupListFiltered(rootNav,FALSE,FALSE);
604   // then process the @addtogroup, @weakgroup blocks
605   buildGroupListFiltered(rootNav,TRUE,FALSE);
606
607   // --- then also process external groups
608   // first process the @defgroups blocks
609   buildGroupListFiltered(rootNav,FALSE,TRUE);
610   // then process the @addtogroup, @weakgroup blocks
611   buildGroupListFiltered(rootNav,TRUE,TRUE);
612 }
613
614 static void findGroupScope(EntryNav *rootNav)
615 {
616   if (rootNav->section()==Entry::GROUPDOC_SEC && !rootNav->name().isEmpty() && 
617       rootNav->parent() && !rootNav->parent()->name().isEmpty())
618   {
619     GroupDef *gd;
620     if ((gd=Doxygen::groupSDict->find(rootNav->name())))
621     {
622       QCString scope = rootNav->parent()->name();
623       if (rootNav->parent()->section()==Entry::PACKAGEDOC_SEC)
624       {
625         scope=substitute(scope,".","::");
626       }
627       scope = stripAnonymousNamespaceScope(scope);
628       scope+="::"+gd->name();
629       Definition *d = findScopeFromQualifiedName(Doxygen::globalScope,scope);
630       if (d) 
631       {
632         gd->setGroupScope(d);
633       }
634     }
635   }
636   RECURSE_ENTRYTREE(findGroupScope,rootNav);
637 }
638
639 static void organizeSubGroupsFiltered(EntryNav *rootNav,bool additional)
640 {
641   if (rootNav->section()==Entry::GROUPDOC_SEC && !rootNav->name().isEmpty())
642   {
643     rootNav->loadEntry(g_storage);
644     Entry *root = rootNav->entry();
645
646     if ((root->groupDocType==Entry::GROUPDOC_NORMAL && !additional) ||
647         (root->groupDocType!=Entry::GROUPDOC_NORMAL && additional))
648     {
649       GroupDef *gd;
650       if ((gd=Doxygen::groupSDict->find(root->name)))
651       {
652         //printf("adding %s to group %s\n",root->name.data(),gd->name().data());
653         addGroupToGroups(root,gd);
654       }
655     }
656
657     rootNav->releaseEntry();
658   }
659   if (rootNav->children())
660   {
661     EntryNavListIterator eli(*rootNav->children());
662     EntryNav *e;
663     for (;(e=eli.current());++eli)
664     {
665       organizeSubGroupsFiltered(e,additional);
666     }
667   }
668 }
669
670 static void organizeSubGroups(EntryNav *rootNav)
671 {
672   //printf("Defining groups\n");
673   // first process the @defgroups blocks
674   organizeSubGroupsFiltered(rootNav,FALSE);
675   //printf("Additional groups\n");
676   // then process the @addtogroup, @weakgroup blocks
677   organizeSubGroupsFiltered(rootNav,TRUE);
678 }
679
680 //----------------------------------------------------------------------
681
682 static void buildFileList(EntryNav *rootNav)
683 {
684   if (((rootNav->section()==Entry::FILEDOC_SEC) ||
685         ((rootNav->section() & Entry::FILE_MASK) && Config_getBool("EXTRACT_ALL"))) &&
686       !rootNav->name().isEmpty() && !rootNav->tagInfo() // skip any file coming from tag files
687      )
688   {
689     rootNav->loadEntry(g_storage);
690     Entry *root = rootNav->entry();
691
692     bool ambig;
693     FileDef *fd=findFileDef(Doxygen::inputNameDict,root->name,ambig);
694     //printf("**************** root->name=%s fd=%p\n",root->name.data(),fd);
695     if (fd && !ambig)
696     {
697 #if 0
698       if ((!root->doc.isEmpty() && !fd->documentation().isEmpty()) ||
699           (!root->brief.isEmpty() && !fd->briefDescription().isEmpty()))
700       {
701         warn(
702             root->fileName,root->startLine,
703             "warning: file %s already documented. "
704             "Skipping documentation.",
705             root->name.data()
706             );
707       }
708       else
709 #endif
710       {
711         //printf("Adding documentation!\n");
712         // using FALSE in setDocumentation is small hack to make sure a file 
713         // is documented even if a \file command is used without further 
714         // documentation
715         fd->setDocumentation(root->doc,root->docFile,root->docLine,FALSE);
716         fd->setBriefDescription(root->brief,root->briefFile,root->briefLine); 
717         fd->addSectionsToDefinition(root->anchors);
718         fd->setRefItems(root->sli);
719         QListIterator<Grouping> gli(*root->groups);
720         Grouping *g;
721         for (;(g=gli.current());++gli)
722         {
723           GroupDef *gd=0;
724           if (!g->groupname.isEmpty() && (gd=Doxygen::groupSDict->find(g->groupname)))
725           {
726             gd->addFile(fd);
727             fd->makePartOfGroup(gd);
728             //printf("File %s: in group %s\n",fd->name().data(),s->data());
729           }
730         }
731       }
732     }
733     else
734     {
735       const char *fn = root->fileName.data();
736       QCString text(4096);
737       text.sprintf("warning: the name `%s' supplied as "
738           "the second argument in the \\file statement ",
739           qPrint(root->name));
740       if (ambig) // name is ambiguous
741       {
742         text+="matches the following input files:\n";
743         text+=showFileDefMatches(Doxygen::inputNameDict,root->name);
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(fn,root->startLine,text);
752     }
753
754     rootNav->releaseEntry();
755   }
756   RECURSE_ENTRYTREE(buildFileList,rootNav);
757 }
758
759 static void addIncludeFile(ClassDef *cd,FileDef *ifd,Entry *root)
760 {
761   if ( 
762       (!root->doc.stripWhiteSpace().isEmpty() || 
763        !root->brief.stripWhiteSpace().isEmpty() || 
764        Config_getBool("EXTRACT_ALL")
765       ) && root->protection!=Private
766      )
767   { 
768     //printf(">>>>>> includeFile=%s\n",root->includeFile.data());
769
770     bool local=Config_getBool("FORCE_LOCAL_INCLUDES");
771     QCString includeFile = root->includeFile;
772     if (!includeFile.isEmpty() && includeFile.at(0)=='"')
773     {
774       local = TRUE;
775       includeFile=includeFile.mid(1,includeFile.length()-2);
776     }
777     else if (!includeFile.isEmpty() && includeFile.at(0)=='<')
778     {
779       local = FALSE;
780       includeFile=includeFile.mid(1,includeFile.length()-2);
781     }
782
783     bool ambig;
784     FileDef *fd=0;
785     // see if we need to include a verbatim copy of the header file
786     //printf("root->includeFile=%s\n",root->includeFile.data());
787     if (!includeFile.isEmpty() && 
788         (fd=findFileDef(Doxygen::inputNameDict,includeFile,ambig))==0
789        )
790     { // explicit request
791       QCString text;
792       text.sprintf("warning: the name `%s' supplied as "
793                   "the argument of the \\class, \\struct, \\union, or \\include command ",
794                   qPrint(includeFile)
795                  );
796       if (ambig) // name is ambiguous
797       {
798         text+="matches the following input files:\n";
799         text+=showFileDefMatches(Doxygen::inputNameDict,root->includeFile);
800         text+="Please use a more specific name by "
801             "including a (larger) part of the path!";
802       }
803       else // name is not an input file
804       {
805         text+="is not an input file";
806       }
807       warn(root->fileName,root->startLine,text);
808     }
809     else if (includeFile.isEmpty() && ifd &&
810         // see if the file extension makes sense
811         guessSection(ifd->name())==Entry::HEADER_SEC)
812     { // implicit assumption
813       fd=ifd;
814     }
815
816     // if a file is found, we mark it as a source file.
817     if (fd)
818     {
819       QCString iName = !root->includeName.isEmpty() ? 
820                        root->includeName : includeFile;
821       if (!iName.isEmpty()) // user specified include file
822       {
823         if (iName.at(0)=='<') local=FALSE; // explicit override
824         else if (iName.at(0)=='"') local=TRUE;
825         if (iName.at(0)=='"' || iName.at(0)=='<')
826         {
827           iName=iName.mid(1,iName.length()-2); // strip quotes or brackets
828         }
829         if (iName.isEmpty())
830         {
831           iName=fd->name();
832         }
833       }
834       else if (!Config_getList("STRIP_FROM_INC_PATH").isEmpty()) 
835       {
836         iName=stripFromIncludePath(fd->absFilePath());
837       }
838       else // use name of the file containing the class definition
839       {
840         iName=fd->name();
841       }
842       if (fd->generateSourceFile()) // generate code for header
843       {
844         cd->setIncludeFile(fd,iName,local,!root->includeName.isEmpty());
845       }
846       else // put #include in the class documentation without link
847       {
848         cd->setIncludeFile(0,iName,local,TRUE);
849       }
850     }
851   }
852 }
853
854 #if 0
855 static bool addNamespace(Entry *root,ClassDef *cd)
856 {
857   // see if this class is defined inside a namespace
858   if (root->section & Entry::COMPOUND_MASK)
859   {
860     Entry *e = root->parent;
861     while (e)
862     {
863       if (e->section==Entry::NAMESPACE_SEC)
864       {
865         NamespaceDef *nd=0;
866         QCString nsName = stripAnonymousNamespaceScope(e->name);
867         //printf("addNameSpace() trying: %s\n",nsName.data());
868         if (!nsName.isEmpty() && nsName.at(0)!='@' &&
869             (nd=getResolvedNamespace(nsName))
870            )
871         {
872           cd->setNamespace(nd);
873           cd->setOuterScope(nd);
874           nd->insertClass(cd);
875           return TRUE;
876         }
877       }
878       e=e->parent;
879     } 
880   }
881   return FALSE;
882 }
883 #endif
884
885 #if 0
886 static Definition *findScope(Entry *root,int level=0)
887 {
888   if (root==0) return 0;
889   //printf("start findScope name=%s\n",root->name.data());
890   Definition *result=0;
891   if (root->section&Entry::SCOPE_MASK)
892   {
893     result = findScope(root->parent,level+1); // traverse to the root of the tree
894     if (result)
895     {
896       //printf("Found %s inside %s at level %d\n",root->name.data(),result->name().data(),level);
897       // TODO: look at template arguments
898       result = result->findInnerCompound(root->name);
899     }
900     else // reached the global scope
901     {
902       // TODO: look at template arguments
903       result = Doxygen::globalScope->findInnerCompound(root->name);
904       //printf("Found in globalScope %s at level %d\n",result->name().data(),level);
905     }
906   }
907   //printf("end findScope(%s,%d)=%s\n",root->name.data(),
908   //       level,result==0 ? "<none>" : result->name().data());
909   return result;
910 }
911 #endif
912
913 /*! returns the Definition object belonging to the first \a level levels of 
914  *  full qualified name \a name. Creates an artificial scope if the scope is
915  *  not found and set the parent/child scope relation if the scope is found.
916  */
917 static Definition *buildScopeFromQualifiedName(const QCString name,int level,SrcLangExt lang)
918 {
919   int i=0;
920   int p=0,l;
921   Definition *prevScope=Doxygen::globalScope;
922   QCString fullScope;
923   while (i<level)
924   {
925     int idx=getScopeFragment(name,p,&l);
926     QCString nsName = name.mid(idx,l);
927     if (nsName.isEmpty()) return prevScope;
928     if (!fullScope.isEmpty()) fullScope+="::";
929     fullScope+=nsName;
930     NamespaceDef *nd=Doxygen::namespaceSDict->find(fullScope);
931     Definition *innerScope = nd;
932     ClassDef *cd=0; 
933     if (nd==0) cd = getClass(fullScope);
934     if (nd==0 && cd) // scope is a class
935     {
936       innerScope = cd;
937     }
938     else if (nd==0 && cd==0) // scope is not known!
939     {
940       // introduce bogus namespace
941       //printf("++ adding dummy namespace %s to %s\n",nsName.data(),prevScope->name().data());
942       nd=new NamespaceDef(
943         "[generated]",1,fullScope);
944       nd->setLanguage(lang);
945
946       // add namespace to the list
947       Doxygen::namespaceSDict->inSort(fullScope,nd);
948       innerScope = nd;
949     }
950     else // scope is a namespace
951     {
952     }
953     // make the parent/child scope relation
954     prevScope->addInnerCompound(innerScope);
955     innerScope->setOuterScope(prevScope);
956     // proceed to the next scope fragment
957     p=idx+l+2;
958     prevScope=innerScope;
959     i++;
960   }
961   return prevScope;
962 }
963
964 static Definition *findScopeFromQualifiedName(Definition *startScope,const QCString &n,
965                                               FileDef *fileScope)
966 {
967   //printf("<findScopeFromQualifiedName(%s,%s)\n",startScope ? startScope->name().data() : 0, n.data());
968   Definition *resultScope=startScope;
969   if (resultScope==0) resultScope=Doxygen::globalScope;
970   QCString scope=stripTemplateSpecifiersFromScope(n,FALSE);
971   int l1=0,i1;
972   i1=getScopeFragment(scope,0,&l1);
973   if (i1==-1) 
974   {
975     //printf(">no fragments!\n");
976     return resultScope;
977   }
978   int p=i1+l1,l2=0,i2;
979   while ((i2=getScopeFragment(scope,p,&l2))!=-1)
980   {
981     QCString nestedNameSpecifier = scope.mid(i1,l1);
982     Definition *orgScope = resultScope;
983     //printf("  nestedNameSpecifier=%s\n",nestedNameSpecifier.data());
984     resultScope = resultScope->findInnerCompound(nestedNameSpecifier);
985     //printf("  resultScope=%p\n",resultScope);
986     if (resultScope==0) 
987     {
988       NamespaceSDict *usedNamespaces;
989       if (orgScope==Doxygen::globalScope && fileScope &&
990           (usedNamespaces = fileScope->getUsedNamespaces())) 
991         // also search for used namespaces 
992       {
993         NamespaceSDict::Iterator ni(*usedNamespaces);
994         NamespaceDef *nd;
995         for (ni.toFirst();((nd=ni.current()) && resultScope==0);++ni)
996         {
997           // restart search within the used namespace
998           resultScope = findScopeFromQualifiedName(nd,n,fileScope);
999         }
1000         if (resultScope) 
1001         {
1002           // for a nested class A::I in used namespace N, we get
1003           // N::A::I while looking for A, so we should compare
1004           // resultScope->name() against scope.left(i2+l2)
1005           //printf("  -> result=%s scope=%s\n",resultScope->name().data(),scope.data());
1006           if (rightScopeMatch(resultScope->name(),scope.left(i2+l2)))
1007           {
1008             break;
1009           }
1010           goto nextFragment;
1011         }
1012       }
1013
1014       // also search for used classes. Complication: we haven't been able 
1015       // to put them in the right scope yet, because we are still resolving
1016       // the scope relations!
1017       // Therefore loop through all used classes and see if there is a right 
1018       // scope match between the used class and nestedNameSpecifier.
1019       QDictIterator<FileDef> ui(g_usingDeclarations);
1020       FileDef *usedFd;
1021       for (ui.toFirst();(usedFd=ui.current());++ui)
1022       {
1023         //printf("Checking using class %s\n",ui.currentKey());
1024         if (rightScopeMatch(ui.currentKey(),nestedNameSpecifier))
1025         {
1026           // ui.currentKey() is the fully qualified name of nestedNameSpecifier
1027           // so use this instead.
1028           QCString fqn = QCString(ui.currentKey())+
1029                          scope.right(scope.length()-p);
1030           resultScope = buildScopeFromQualifiedName(fqn,fqn.contains("::"),startScope->getLanguage());
1031           //printf("Creating scope from fqn=%s result %p\n",fqn.data(),resultScope);
1032           if (resultScope) 
1033           {
1034             //printf("> Match! resultScope=%s\n",resultScope->name().data());
1035             return resultScope;
1036           }
1037         }
1038       }
1039       
1040       //printf("> name %s not found in scope %s\n",nestedNameSpecifier.data(),orgScope->name().data());
1041       return 0;
1042     }
1043  nextFragment:
1044     i1=i2;
1045     l1=l2;
1046     p=i2+l2;
1047   }
1048   //printf(">findScopeFromQualifiedName scope %s\n",resultScope->name().data());
1049   return resultScope;
1050 }
1051
1052 ArgumentList *getTemplateArgumentsFromName(
1053                   const QCString &name,
1054                   const QList<ArgumentList> *tArgLists)
1055 {
1056   if (tArgLists==0) return 0;
1057   
1058   QListIterator<ArgumentList> ali(*tArgLists);
1059   // for each scope fragment, check if it is a template and advance through
1060   // the list if so.
1061   int i,p=0;
1062   while ((i=name.find("::",p))!=-1)
1063   {
1064     NamespaceDef *nd = Doxygen::namespaceSDict->find(name.left(i));
1065     if (nd==0)
1066     {
1067       ClassDef *cd = getClass(name.left(i));
1068       if (cd)
1069       {
1070         if (cd->templateArguments())
1071         {
1072           ++ali;
1073         }
1074       }
1075     }
1076     p=i+2;
1077   }
1078   return ali.current();
1079 }
1080
1081 static ClassDef::CompoundType convertToCompoundType(int section,int specifier)
1082 {
1083   ClassDef::CompoundType sec=ClassDef::Class; 
1084   if (specifier&Entry::Struct) 
1085     sec=ClassDef::Struct;
1086   else if (specifier&Entry::Union) 
1087     sec=ClassDef::Union;
1088   else if (specifier&Entry::Category) 
1089     sec=ClassDef::Category;
1090   else if (specifier&Entry::Interface) 
1091     sec=ClassDef::Interface;
1092   else if (specifier&Entry::Protocol) 
1093     sec=ClassDef::Protocol;
1094   else if (specifier&Entry::Exception) 
1095     sec=ClassDef::Exception;
1096
1097   switch(section)
1098   {
1099     //case Entry::UNION_SEC: 
1100     case Entry::UNIONDOC_SEC: 
1101       sec=ClassDef::Union; 
1102       break;
1103       //case Entry::STRUCT_SEC:
1104     case Entry::STRUCTDOC_SEC: 
1105       sec=ClassDef::Struct; 
1106       break;
1107       //case Entry::INTERFACE_SEC:
1108     case Entry::INTERFACEDOC_SEC:
1109       sec=ClassDef::Interface; 
1110       break;
1111       //case Entry::PROTOCOL_SEC:
1112     case Entry::PROTOCOLDOC_SEC:
1113       sec=ClassDef::Protocol; 
1114       break;
1115       //case Entry::CATEGORY_SEC:
1116     case Entry::CATEGORYDOC_SEC:
1117       sec=ClassDef::Category; 
1118       break;
1119       //case Entry::EXCEPTION_SEC:
1120     case Entry::EXCEPTIONDOC_SEC:
1121       sec=ClassDef::Exception; 
1122       break;
1123   }
1124   return sec;
1125 }
1126
1127
1128 static void addClassToContext(EntryNav *rootNav)
1129 {
1130   //printf("Loading entry for rootNav=%p name=%s\n",rootNav,rootNav->name().data());
1131   rootNav->loadEntry(g_storage);
1132   Entry *root = rootNav->entry();
1133
1134   //NamespaceDef *nd = 0;
1135   FileDef *fd = rootNav->fileDef();
1136
1137   QCString scName;
1138   if (rootNav->parent()->section()&Entry::SCOPE_MASK)
1139   {
1140      scName=rootNav->parent()->name();
1141   }
1142   // name without parent's scope
1143   QCString fullName = root->name;
1144
1145   // strip off any template parameters (but not those for specializations)
1146   fullName=stripTemplateSpecifiersFromScope(fullName);
1147
1148   // name with scope (if not present already)
1149   QCString qualifiedName = fullName;
1150   if (!scName.isEmpty() && !leftScopeMatch(fullName,scName))
1151   {
1152     qualifiedName.prepend(scName+"::");
1153   }
1154
1155   // see if we already found the class before
1156   ClassDef *cd = getClass(qualifiedName);
1157
1158   Debug::print(Debug::Classes,0, "  Found class with name %s (qualifiedName=%s -> cd=%p)\n",
1159       cd ? cd->name().data() : root->name.data(), qualifiedName.data(),cd);
1160
1161   if (cd) 
1162   {
1163     fullName=cd->name();
1164     Debug::print(Debug::Classes,0,"  Existing class %s!\n",cd->name().data());
1165     //if (cd->templateArguments()==0)
1166     //{
1167     //  //printf("existing ClassDef tempArgList=%p specScope=%s\n",root->tArgList,root->scopeSpec.data());
1168     //  cd->setTemplateArguments(tArgList);
1169     //}
1170
1171     cd->setDocumentation(root->doc,root->docFile,root->docLine);
1172     cd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1173
1174     if (root->bodyLine!=-1 && cd->getStartBodyLine()==-1)
1175     {
1176       cd->setBodySegment(root->bodyLine,root->endBodyLine);
1177       cd->setBodyDef(fd);
1178     }
1179     //cd->setName(fullName); // change name to match docs
1180
1181     if (cd->templateArguments()==0) 
1182     {
1183       // this happens if a template class declared with @class is found
1184       // before the actual definition.
1185       ArgumentList *tArgList = 
1186         getTemplateArgumentsFromName(cd->name(),root->tArgLists);
1187       cd->setTemplateArguments(tArgList);
1188     }
1189
1190     cd->setCompoundType(convertToCompoundType(root->section,root->spec));
1191   }
1192   else // new class
1193   {
1194     ClassDef::CompoundType sec = convertToCompoundType(root->section,root->spec);
1195
1196     QCString className;
1197     QCString namespaceName;
1198     extractNamespaceName(fullName,className,namespaceName);
1199
1200     //printf("New class: fullname %s namespace `%s' name=`%s' brief=`%s' docs=`%s'\n",
1201     //    fullName.data(),namespaceName.data(),className.data(),root->brief.data(),root->doc.data());
1202
1203     QCString tagName;
1204     QCString refFileName;
1205     if (rootNav->tagInfo())
1206     {
1207       tagName     = rootNav->tagInfo()->tagName;
1208       refFileName = rootNav->tagInfo()->fileName;
1209     }
1210     cd=new ClassDef(root->fileName,root->startLine,fullName,sec,
1211         tagName,refFileName,TRUE,root->spec&Entry::Enum);
1212     Debug::print(Debug::Classes,0,"  New class `%s' (sec=0x%08x)! #tArgLists=%d\n",
1213         fullName.data(),sec,root->tArgLists ? (int)root->tArgLists->count() : -1);
1214     cd->setDocumentation(root->doc,root->docFile,root->docLine); // copy docs to definition
1215     cd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1216     cd->setLanguage(root->lang);    
1217     cd->setHidden(root->hidden);        
1218     cd->setArtificial(root->artificial);        
1219     cd->setClassSpecifier(root->spec);
1220     cd->setTypeConstraints(root->typeConstr);   
1221     //printf("new ClassDef %s tempArgList=%p specScope=%s\n",fullName.data(),root->tArgList,root->scopeSpec.data());    
1222
1223     ArgumentList *tArgList =    
1224       getTemplateArgumentsFromName(fullName,root->tArgLists);   
1225     //printf("class %s template args=%s\n",fullName.data(),     
1226     //    tArgList ? tempArgListToString(tArgList).data() : "<none>");          
1227     cd->setTemplateArguments(tArgList);         
1228     cd->setProtection(root->protection);        
1229     cd->setIsStatic(root->stat);        
1230
1231     // file definition containing the class cd          
1232     cd->setBodySegment(root->bodyLine,root->endBodyLine);       
1233     cd->setBodyDef(fd);         
1234
1235     // see if the class is found inside a namespace     
1236     //bool found=addNamespace(root,cd);         
1237
1238     // the empty string test is needed for extract all case     
1239     cd->setBriefDescription(root->brief,root->briefFile,root->briefLine);    
1240     cd->insertUsedFile(root->fileName);
1241
1242     // add class to the list
1243     //printf("ClassDict.insert(%s)\n",resolveDefines(fullName).data());
1244     Doxygen::classSDict->append(fullName,cd);
1245
1246     if (cd->isGeneric()) // generics are also stored in a separate dictionary for fast lookup of instantions
1247     {
1248       Doxygen::genericsDict.insert(fullName,cd);
1249     }
1250   }
1251
1252   cd->addSectionsToDefinition(root->anchors);
1253   if (!root->subGrouping) cd->setSubGrouping(FALSE);
1254   if (cd->hasDocumentation())
1255   {
1256     addIncludeFile(cd,fd,root);
1257   }
1258   if (fd && (root->section & Entry::COMPOUND_MASK)) 
1259   {
1260     //printf(">> Inserting class `%s' in file `%s' (root->fileName=`%s')\n",
1261     //    cd->name().data(),
1262     //    fd->name().data(),
1263     //    root->fileName.data()
1264     //   );
1265     cd->setFileDef(fd);
1266     fd->insertClass(cd);
1267   }
1268   addClassToGroups(root,cd);
1269   cd->setRefItems(root->sli);
1270
1271   rootNav->releaseEntry();
1272 }
1273             
1274 //----------------------------------------------------------------------
1275 // build a list of all classes mentioned in the documentation
1276 // and all classes that have a documentation block before their definition.
1277 static void buildClassList(EntryNav *rootNav)
1278 {
1279   if (
1280         ((rootNav->section() & Entry::COMPOUND_MASK) || 
1281          rootNav->section()==Entry::OBJCIMPL_SEC) && !rootNav->name().isEmpty()
1282      )
1283   {
1284     addClassToContext(rootNav);
1285   }
1286   RECURSE_ENTRYTREE(buildClassList,rootNav);
1287 }
1288
1289 static void buildClassDocList(EntryNav *rootNav)
1290 {
1291   if (
1292        (rootNav->section() & Entry::COMPOUNDDOC_MASK) && !rootNav->name().isEmpty()
1293      )
1294   {
1295     addClassToContext(rootNav);
1296   }
1297   RECURSE_ENTRYTREE(buildClassDocList,rootNav);
1298 }
1299
1300 static void resolveClassNestingRelations()
1301 {
1302   ClassSDict::Iterator cli(*Doxygen::classSDict);
1303   for (cli.toFirst();cli.current();++cli) cli.current()->visited=FALSE;
1304
1305   bool done=FALSE;
1306   int iteration=0;
1307   while (!done)
1308   {
1309     done=TRUE;
1310     ++iteration;
1311     ClassDef *cd=0;
1312     for (cli.toFirst();(cd=cli.current());++cli)
1313     {
1314       if (!cd->visited)
1315       {
1316         QCString name = stripAnonymousNamespaceScope(cd->name());
1317         //printf("processing=%s, iteration=%d\n",cd->name().data(),iteration);
1318         // also add class to the correct structural context 
1319         Definition *d = findScopeFromQualifiedName(Doxygen::globalScope,
1320                                                  name,cd->getFileDef());
1321         if (d)
1322         {
1323           //printf("****** adding %s to scope %s in iteration %d\n",cd->name().data(),d->name().data(),iteration);
1324           d->addInnerCompound(cd);
1325           cd->setOuterScope(d);
1326           cd->visited=TRUE;
1327           done=FALSE;
1328         }
1329         //else
1330         //{
1331         //  printf("****** ignoring %s: scope not (yet) found in iteration %d\n",cd->name().data(),iteration);
1332         //}
1333       }
1334     }
1335   }
1336
1337   //give warnings for unresolved compounds
1338   ClassDef *cd=0;
1339   for (cli.toFirst();(cd=cli.current());++cli)
1340   {
1341     if (!cd->visited)
1342     {
1343       QCString name = stripAnonymousNamespaceScope(cd->name());
1344       //printf("processing unresolved=%s, iteration=%d\n",cd->name().data(),iteration);
1345       /// create the scope artificially
1346       // anyway, so we can at least relate scopes properly.
1347       Definition *d = buildScopeFromQualifiedName(name,name.contains("::"),cd->getLanguage());
1348       if (d!=cd && !cd->getDefFileName().isEmpty()) 
1349                  // avoid recursion in case of redundant scopes, i.e: namespace N { class N::C {}; }
1350                  // for this case doxygen assumes the exitance of a namespace N::N in which C is to be found!
1351                  // also avoid warning for stuff imported via a tagfile.
1352       {
1353         d->addInnerCompound(cd);
1354         cd->setOuterScope(d);
1355         warn(cd->getDefFileName(),cd->getDefLine(),
1356             "warning: Internal inconsistency: scope for class %s not "
1357             "found!",name.data()
1358             );
1359       }
1360     }
1361   }
1362 }
1363
1364 void distributeClassGroupRelations()
1365 {
1366   //static bool inlineGroupedClasses = Config_getBool("INLINE_GROUPED_CLASSES");
1367   //if (!inlineGroupedClasses) return;
1368   //printf("** distributeClassGroupRelations()\n");
1369
1370   ClassSDict::Iterator cli(*Doxygen::classSDict);
1371   for (cli.toFirst();cli.current();++cli) cli.current()->visited=FALSE;
1372
1373   ClassDef *cd;
1374   for (cli.toFirst();(cd=cli.current());++cli)
1375   {
1376     //printf("Checking %s\n",cd->name().data());
1377     // distribute the group to nested classes as well
1378     if (!cd->visited && cd->partOfGroups()!=0 && cd->getClassSDict())
1379     {
1380       //printf("  Candidate for merging\n");
1381       ClassSDict::Iterator ncli(*cd->getClassSDict());
1382       ClassDef *ncd;
1383       GroupDef *gd = cd->partOfGroups()->at(0);
1384       for (ncli.toFirst();(ncd=ncli.current());++ncli)
1385       {
1386         if (ncd->partOfGroups()==0)
1387         {
1388           //printf("  Adding %s to group '%s'\n",ncd->name().data(),
1389           //    gd->groupTitle());
1390           ncd->makePartOfGroup(gd);
1391           gd->addClass(ncd);
1392         }
1393       }
1394       cd->visited=TRUE; // only visit every class once
1395     }
1396   }
1397 }
1398
1399 //----------------------------
1400
1401 static ClassDef *createTagLessInstance(ClassDef *rootCd,ClassDef *templ,const QCString &fieldName)
1402 {
1403   QCString fullName = removeAnonymousScopes(templ->name());
1404   if (fullName.right(2)=="::") fullName=fullName.left(fullName.length()-2);
1405   fullName+="."+fieldName;
1406   ClassDef *cd = new ClassDef(templ->getDefFileName(),
1407                               templ->getDefLine(),
1408                               fullName,
1409                               templ->compoundType());
1410   cd->setDocumentation(templ->documentation(),templ->docFile(),templ->docLine()); // copy docs to definition
1411   cd->setBriefDescription(templ->briefDescription(),templ->briefFile(),templ->briefLine());
1412   cd->setLanguage(templ->getLanguage());
1413   cd->setBodySegment(templ->getStartBodyLine(),templ->getEndBodyLine());
1414   cd->setBodyDef(templ->getBodyDef());
1415
1416   cd->setOuterScope(rootCd->getOuterScope());
1417   if (rootCd->getOuterScope()!=Doxygen::globalScope)
1418   {
1419     rootCd->getOuterScope()->addInnerCompound(cd);
1420   }
1421
1422   FileDef *fd = templ->getFileDef();
1423   if (fd)
1424   {
1425     cd->setFileDef(fd);
1426     fd->insertClass(cd);
1427   }
1428   LockingPtr<GroupList> groups = rootCd->partOfGroups();
1429   if ( groups!=0 )
1430   {
1431     GroupListIterator gli(*groups);
1432     GroupDef *gd;
1433     for (gli.toFirst();(gd=gli.current());++gli)
1434     {
1435       cd->makePartOfGroup(gd);
1436       gd->addClass(cd);
1437     }
1438   }
1439   //cd->insertUsedFile(root->fileName);
1440   //printf("** adding class %s based on %s\n",fullName.data(),templ->name().data());
1441   Doxygen::classSDict->append(fullName,cd);
1442
1443   MemberList *ml = templ->getMemberList(MemberList::pubAttribs);
1444   if (ml)
1445   {
1446     MemberListIterator li(*ml);
1447     MemberDef *md;
1448     for (li.toFirst();(md=li.current());++li)
1449     {
1450       //printf("    Member %s type=%s\n",md->name().data(),md->typeString());
1451       MemberDef *imd = new MemberDef(md->getDefFileName(),md->getDefLine(),
1452                                      md->typeString(),md->name(),md->argsString(),md->excpString(),
1453                                      md->protection(),md->virtualness(),md->isStatic(),Member,
1454                                      md->memberType(),
1455                                      0,0);
1456       imd->setMemberClass(cd);
1457       imd->setDocumentation(md->documentation(),md->docFile(),md->docLine());
1458       imd->setBriefDescription(md->briefDescription(),md->briefFile(),md->briefLine());
1459       imd->setInbodyDocumentation(md->inbodyDocumentation(),md->inbodyFile(),md->inbodyLine());
1460       imd->setMemberSpecifiers(md->getMemberSpecifiers());
1461       imd->setMemberGroupId(md->getMemberGroupId());
1462       imd->setInitializer(md->initializer());
1463       imd->setMaxInitLines(md->initializerLines());
1464       imd->setBitfields(md->bitfieldString());
1465       imd->setLanguage(md->getLanguage());
1466       cd->insertMember(imd);
1467     }
1468   }
1469   return cd;
1470 }
1471
1472 /** Look through the members of class \a cd and its public members.
1473  *  If there is a member m of a tag less struct/union, 
1474  *  then we create a duplicate of the struct/union with the name of the 
1475  *  member to identify it.
1476  *  So if cd has name S, then the tag less struct/union will get name S.m
1477  *  Since tag less structs can be nested we need to call this function
1478  *  recursively. Later on we need to patch the member types so we keep
1479  *  track of the hierarchy of classes we create.
1480  */
1481 static void processTagLessClasses(ClassDef *rootCd,
1482                                   ClassDef *cd,
1483                                   ClassDef *tagParentCd,
1484                                   const QCString &prefix,int count)
1485 {
1486   //printf("%d: processTagLessClasses %s\n",count,cd->name().data());
1487   //printf("checking members for %s\n",cd->name().data());
1488   if (cd->getClassSDict())
1489   {
1490     MemberList *ml = cd->getMemberList(MemberList::pubAttribs);
1491     if (ml)
1492     {
1493       MemberListIterator li(*ml);
1494       MemberDef *md;
1495       for (li.toFirst();(md=li.current());++li)
1496       {
1497         QCString type = md->typeString();
1498         if (type.find("::@")!=-1) // member of tag less struct/union
1499         {
1500           ClassSDict::Iterator it(*cd->getClassSDict());
1501           ClassDef *icd;
1502           for (it.toFirst();(icd=it.current());++it)
1503           {
1504             //printf("  member %s: type='%s'\n",md->name().data(),type.data());
1505             //printf("  comparing '%s'<->'%s'\n",type.data(),icd->name().data());
1506             if (type.find(icd->name())!=-1) // matching tag less struct/union
1507             {
1508               QCString name = md->name();
1509               if (name.at(0)=='@') name = "__unnamed__";
1510               if (!prefix.isEmpty()) name.prepend(prefix+".");
1511               //printf("    found %s for class %s\n",name.data(),cd->name().data());
1512               ClassDef *ncd = createTagLessInstance(rootCd,icd,name);
1513               processTagLessClasses(rootCd,icd,ncd,name,count+1);
1514               //printf("    addTagged %s to %s\n",ncd->name().data(),tagParentCd->name().data());
1515               tagParentCd->addTaggedInnerClass(ncd);
1516               ncd->setTagLessReference(icd);
1517
1518               // replace tag-less type for generated/original member
1519               // by newly created class name.
1520               // note the difference between changing cd and tagParentCd.
1521               // for the initial call this is the same pointer, but for 
1522               // recursive calls cd is the original tag-less struct (of which
1523               // there is only one instance) and tagParentCd is the newly
1524               // generated tagged struct of which there can be multiple instances!
1525               MemberList *pml = tagParentCd->getMemberList(MemberList::pubAttribs);
1526               if (pml)
1527               {
1528                 MemberListIterator pli(*pml);
1529                 MemberDef *pmd;
1530                 for (pli.toFirst();(pmd=pli.current());++pli)
1531                 {
1532                   if (pmd->name()==md->name())
1533                   {
1534                     pmd->setAccessorType(ncd,substitute(pmd->typeString(),icd->name(),ncd->name()));
1535                     //pmd->setType(substitute(pmd->typeString(),icd->name(),ncd->name()));
1536                   }
1537                 }
1538               }
1539             }
1540           }
1541         }
1542       }
1543     }
1544   }
1545 }
1546
1547 static void writeMainPageTagFileData()
1548 {
1549   if (Doxygen::mainPage && !Config_getString("GENERATE_TAGFILE").isEmpty())
1550   {
1551     Doxygen::tagFile << "  <compound kind=\"page\">" << endl
1552                      << "    <name>"
1553                      << convertToXML(Doxygen::mainPage->name())
1554                      << "</name>" << endl
1555                      << "    <title>"
1556                      << convertToXML(Doxygen::mainPage->title())
1557                      << "</title>" << endl
1558                      << "    <filename>"
1559                      << convertToXML(Doxygen::mainPage->getOutputFileBase())
1560                      << "</filename>" << endl;
1561
1562     Doxygen::mainPage->writeDocAnchorsToTagFile();
1563     Doxygen::tagFile << "  </compound>" << endl;
1564   }
1565 }
1566
1567 static void findTagLessClasses(ClassDef *cd)
1568 {
1569   if (cd->getClassSDict())
1570   {
1571     ClassSDict::Iterator it(*cd->getClassSDict());
1572     ClassDef *icd;
1573     for (it.toFirst();(icd=it.current());++it)
1574     {
1575       if (icd->name().find("@")==-1) // process all non-anonymous inner classes
1576       {
1577         findTagLessClasses(icd);
1578       }
1579     }
1580   }
1581
1582   processTagLessClasses(cd,cd,cd,"",0); // process tag less inner struct/classes (if any)
1583 }
1584
1585 static void findTagLessClasses()
1586 {
1587   ClassSDict::Iterator cli(*Doxygen::classSDict);
1588   ClassDef *cd;
1589   for (cli.toFirst();(cd=cli.current());++cli) // for each class
1590   {
1591     Definition *scope = cd->getOuterScope();
1592     if (scope && scope->definitionType()!=Definition::TypeClass) // that is not nested
1593     {
1594       findTagLessClasses(cd);
1595     }
1596   }
1597 }
1598
1599
1600 //----------------------------------------------------------------------
1601 // build a list of all namespaces mentioned in the documentation
1602 // and all namespaces that have a documentation block before their definition.
1603 static void buildNamespaceList(EntryNav *rootNav)
1604 {
1605   if (
1606        (rootNav->section()==Entry::NAMESPACE_SEC ||
1607         rootNav->section()==Entry::NAMESPACEDOC_SEC ||
1608         rootNav->section()==Entry::PACKAGEDOC_SEC
1609        ) && 
1610        !rootNav->name().isEmpty()
1611      )
1612   {
1613     rootNav->loadEntry(g_storage);
1614     Entry *root = rootNav->entry();
1615
1616     //printf("** buildNamespaceList(%s)\n",root->name.data());
1617
1618     QCString fName = root->name;
1619     if (root->section==Entry::PACKAGEDOC_SEC)
1620     {
1621       fName=substitute(fName,".","::");
1622     }
1623
1624     QCString fullName = stripAnonymousNamespaceScope(fName);
1625     if (!fullName.isEmpty())
1626     {
1627       //printf("Found namespace %s in %s at line %d\n",root->name.data(),
1628       //        root->fileName.data(), root->startLine);
1629       NamespaceDef *nd;
1630       if ((nd=Doxygen::namespaceSDict->find(fullName))) // existing namespace
1631       {
1632         nd->setDocumentation(root->doc,root->docFile,root->docLine);
1633         nd->setName(fullName); // change name to match docs
1634         nd->addSectionsToDefinition(root->anchors);
1635         nd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1636         if (nd->getLanguage()==SrcLangExt_Unknown)
1637         {
1638           nd->setLanguage(root->lang);
1639         }
1640
1641         // file definition containing the namespace nd
1642         FileDef *fd=rootNav->fileDef();
1643         // insert the namespace in the file definition
1644         if (fd) fd->insertNamespace(nd);
1645         addNamespaceToGroups(root,nd);
1646         nd->setRefItems(root->sli);
1647       }
1648       else // fresh namespace
1649       {
1650         QCString tagName;
1651         QCString tagFileName;
1652         if (rootNav->tagInfo())
1653         {
1654           tagName=rootNav->tagInfo()->tagName;
1655           tagFileName=rootNav->tagInfo()->fileName;
1656         }
1657         //printf("++ new namespace %s lang=%s\n",fullName.data(),langToString(root->lang).data());
1658         NamespaceDef *nd=new NamespaceDef(root->fileName,root->startLine,fullName,tagName,tagFileName);
1659         nd->setDocumentation(root->doc,root->docFile,root->docLine); // copy docs to definition
1660         nd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1661         nd->addSectionsToDefinition(root->anchors);
1662         nd->setHidden(root->hidden);
1663         nd->setArtificial(root->artificial);
1664         nd->setLanguage(root->lang);
1665
1666         //printf("Adding namespace to group\n");
1667         addNamespaceToGroups(root,nd);
1668         nd->setRefItems(root->sli);
1669
1670         // file definition containing the namespace nd
1671         FileDef *fd=rootNav->fileDef();
1672         // insert the namespace in the file definition
1673         if (fd) fd->insertNamespace(nd);
1674
1675         // the empty string test is needed for extract all case
1676         nd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1677         nd->insertUsedFile(root->fileName);
1678         nd->setBodySegment(root->bodyLine,root->endBodyLine);
1679         nd->setBodyDef(fd);
1680         // add class to the list
1681         Doxygen::namespaceSDict->inSort(fullName,nd);
1682
1683         // also add namespace to the correct structural context 
1684         Definition *d = findScopeFromQualifiedName(Doxygen::globalScope,fullName);
1685         //printf("adding namespace %s to context %s\n",nd->name().data(),d?d->name().data():"<none>");
1686         if (d==0) // we didn't find anything, create the scope artificially
1687                   // anyway, so we can at least relate scopes properly.
1688         {
1689           Definition *d = buildScopeFromQualifiedName(fullName,fullName.contains("::"),nd->getLanguage());
1690           d->addInnerCompound(nd);
1691           nd->setOuterScope(d);
1692           // TODO: Due to the order in which the tag file is written
1693           // a nested class can be found before its parent!
1694         }
1695         else
1696         {
1697           d->addInnerCompound(nd);
1698           nd->setOuterScope(d);
1699         }
1700       }
1701     }
1702
1703     rootNav->releaseEntry();
1704   }
1705   RECURSE_ENTRYTREE(buildNamespaceList,rootNav);
1706 }
1707
1708 //----------------------------------------------------------------------
1709
1710 static NamespaceDef *findUsedNamespace(NamespaceSDict *unl,
1711                               const QCString &name)
1712 {
1713   NamespaceDef *usingNd =0;
1714   if (unl)
1715   {
1716     //printf("Found namespace dict %d\n",unl->count());
1717     NamespaceSDict::Iterator unli(*unl);
1718     NamespaceDef *und;
1719     for (unli.toFirst();(und=unli.current());++unli)
1720     {
1721       QCString uScope=und->name()+"::";
1722       usingNd = getResolvedNamespace(uScope+name);
1723       //printf("Also trying with scope=`%s' usingNd=%p\n",(uScope+name).data(),usingNd);
1724     }
1725   }
1726   return usingNd;
1727 }
1728
1729 static void findUsingDirectives(EntryNav *rootNav)
1730 {
1731   if (rootNav->section()==Entry::USINGDIR_SEC)
1732   {
1733     rootNav->loadEntry(g_storage);
1734     Entry *root = rootNav->entry();
1735
1736     //printf("Found using directive %s at line %d of %s\n",
1737     //    root->name.data(),root->startLine,root->fileName.data());
1738     QCString name=substitute(root->name,".","::");
1739     if (!name.isEmpty())
1740     {
1741       NamespaceDef *usingNd = 0;
1742       NamespaceDef *nd = 0;
1743       FileDef      *fd = rootNav->fileDef();
1744       QCString nsName;
1745
1746       // see if the using statement was found inside a namespace or inside
1747       // the global file scope.
1748       if (rootNav->parent() && rootNav->parent()->section()==Entry::NAMESPACE_SEC &&
1749           (fd==0 || fd->getLanguage()!=SrcLangExt_Java) // not a .java file
1750          )
1751       {
1752         nsName=stripAnonymousNamespaceScope(rootNav->parent()->name());
1753         if (!nsName.isEmpty())
1754         {
1755           nd = getResolvedNamespace(nsName);
1756         }
1757       }
1758
1759       // find the scope in which the `using' namespace is defined by prepending
1760       // the possible scopes in which the using statement was found, starting
1761       // with the most inner scope and going to the most outer scope (i.e. 
1762       // file scope). 
1763       int scopeOffset = nsName.length();
1764       do
1765       {
1766         QCString scope=scopeOffset>0 ? 
1767                       nsName.left(scopeOffset)+"::" : QCString();
1768         usingNd = getResolvedNamespace(scope+name);
1769         //printf("Trying with scope=`%s' usingNd=%p\n",(scope+name).data(),usingNd);
1770         if (scopeOffset==0)
1771         {
1772           scopeOffset=-1;
1773         }
1774         else if ((scopeOffset=nsName.findRev("::",scopeOffset-1))==-1)
1775         {
1776           scopeOffset=0;
1777         }
1778       } while (scopeOffset>=0 && usingNd==0);
1779
1780       if (usingNd==0 && nd) // not found, try used namespaces in this scope
1781                             // or in one of the parent namespace scopes
1782       {
1783         NamespaceDef *pnd = nd;
1784         while (pnd && usingNd==0)
1785         {
1786           // also try with one of the used namespaces found earlier
1787           usingNd = findUsedNamespace(pnd->getUsedNamespaces(),name);
1788
1789           // goto the parent
1790           Definition *s = pnd->getOuterScope();
1791           if (s && s->definitionType()==Definition::TypeNamespace)
1792           {
1793             pnd = (NamespaceDef*)s;
1794           }
1795           else
1796           {
1797             pnd = 0;
1798           }
1799         }
1800       }
1801       if (usingNd==0 && fd) // still nothing, also try used namespace in the
1802                             // global scope
1803       {
1804         usingNd = findUsedNamespace(fd->getUsedNamespaces(),name);
1805       }
1806
1807       //printf("%s -> %s\n",name.data(),usingNd?usingNd->name().data():"<none>");
1808
1809       // add the namespace the correct scope
1810       if (usingNd)
1811       {
1812         //printf("using fd=%p nd=%p\n",fd,nd);
1813         if (nd)
1814         {
1815           //printf("Inside namespace %s\n",nd->name().data());
1816           nd->addUsingDirective(usingNd);
1817         }
1818         else if (fd)
1819         {
1820           //printf("Inside file %s\n",fd->name().data());
1821           fd->addUsingDirective(usingNd);
1822         }
1823       }
1824       else // unknown namespace, but add it anyway.
1825       {
1826         //printf("++ new unknown namespace %s lang=%s\n",name.data(),langToString(root->lang).data());
1827         NamespaceDef *nd=new NamespaceDef(root->fileName,root->startLine,name);
1828         nd->setDocumentation(root->doc,root->docFile,root->docLine); // copy docs to definition
1829         nd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1830         nd->addSectionsToDefinition(root->anchors);
1831         //printf("** Adding namespace %s hidden=%d\n",name.data(),root->hidden);
1832         nd->setHidden(root->hidden);
1833         nd->setArtificial(TRUE);
1834         nd->setLanguage(root->lang);
1835
1836         QListIterator<Grouping> gli(*root->groups);
1837         Grouping *g;
1838         for (;(g=gli.current());++gli)
1839         {
1840           GroupDef *gd=0;
1841           if (!g->groupname.isEmpty() && (gd=Doxygen::groupSDict->find(g->groupname)))
1842             gd->addNamespace(nd);
1843         }
1844
1845         // insert the namespace in the file definition
1846         if (fd) 
1847         {
1848           fd->insertNamespace(nd);
1849           fd->addUsingDirective(nd);
1850         }
1851
1852         // the empty string test is needed for extract all case
1853         nd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1854         nd->insertUsedFile(root->fileName);
1855         // add class to the list
1856         Doxygen::namespaceSDict->inSort(name,nd);
1857         nd->setRefItems(root->sli);
1858       }
1859     }
1860
1861     rootNav->releaseEntry();
1862   }
1863   RECURSE_ENTRYTREE(findUsingDirectives,rootNav);
1864 }
1865
1866 //----------------------------------------------------------------------
1867
1868 static void buildListOfUsingDecls(EntryNav *rootNav)
1869 {
1870   if (rootNav->section()==Entry::USINGDECL_SEC &&
1871       !(rootNav->parent()->section()&Entry::COMPOUND_MASK) // not a class/struct member
1872      )
1873   {
1874     rootNav->loadEntry(g_storage);
1875     Entry *root = rootNav->entry();
1876
1877     QCString name = substitute(root->name,".","::");
1878
1879     if (g_usingDeclarations.find(name)==0)
1880     {
1881       FileDef *fd = rootNav->fileDef();
1882       if (fd)
1883       {
1884         g_usingDeclarations.insert(name,fd);
1885       }
1886     }
1887
1888     rootNav->releaseEntry();
1889   }
1890   RECURSE_ENTRYTREE(buildListOfUsingDecls,rootNav);
1891 }
1892
1893   
1894 static void findUsingDeclarations(EntryNav *rootNav)
1895 {
1896   if (rootNav->section()==Entry::USINGDECL_SEC &&
1897       !(rootNav->parent()->section()&Entry::COMPOUND_MASK) // not a class/struct member
1898      )
1899   {
1900     rootNav->loadEntry(g_storage);
1901     Entry *root = rootNav->entry();
1902
1903     //printf("Found using declaration %s at line %d of %s inside section %x\n",
1904     //   root->name.data(),root->startLine,root->fileName.data(),
1905     //   rootNav->parent()->section());
1906     if (!root->name.isEmpty())
1907     {
1908       ClassDef *usingCd = 0;
1909       NamespaceDef *nd = 0;
1910       FileDef      *fd = rootNav->fileDef();
1911       QCString scName;
1912
1913       // see if the using statement was found inside a namespace or inside
1914       // the global file scope.
1915       if (rootNav->parent()->section() == Entry::NAMESPACE_SEC)
1916       {
1917         scName=rootNav->parent()->name();
1918         if (!scName.isEmpty())
1919         {
1920           nd = getResolvedNamespace(scName);
1921         }
1922       }
1923
1924       // Assume the using statement was used to import a class.
1925       // Find the scope in which the `using' namespace is defined by prepending
1926       // the possible scopes in which the using statement was found, starting
1927       // with the most inner scope and going to the most outer scope (i.e. 
1928       // file scope).
1929
1930       QCString name = substitute(root->name,".","::"); //Java/C# scope->internal
1931       usingCd = getClass(name);
1932       if (usingCd==0)
1933       {
1934         usingCd = Doxygen::hiddenClasses->find(name);
1935       }
1936
1937       //printf("%s -> %p\n",root->name.data(),usingCd);
1938       if (usingCd==0) // definition not in the input => add an artificial class
1939       {
1940         Debug::print(Debug::Classes,0,"  New using class `%s' (sec=0x%08x)! #tArgLists=%d\n",
1941              name.data(),root->section,root->tArgLists ? (int)root->tArgLists->count() : -1);
1942         usingCd = new ClassDef(
1943                      "<using>",1,
1944                      name,ClassDef::Class);
1945         Doxygen::hiddenClasses->append(root->name,usingCd);
1946         usingCd->setArtificial(TRUE);
1947         usingCd->setLanguage(root->lang);
1948       }
1949       else
1950       {
1951         Debug::print(Debug::Classes,0,"  Found used class %s in scope=%s\n",
1952             usingCd->name().data(),nd?nd->name().data():fd->name().data());
1953       }
1954
1955       if (usingCd) // add the class to the correct scope
1956       {
1957         if (nd)
1958         {
1959           //printf("Inside namespace %s\n",nd->name().data());
1960           nd->addUsingDeclaration(usingCd);
1961         }
1962         else if (fd)
1963         {
1964           //printf("Inside file %s\n",fd->name().data());
1965           fd->addUsingDeclaration(usingCd);
1966         }
1967       }
1968     }
1969
1970     rootNav->releaseEntry();
1971   }
1972   RECURSE_ENTRYTREE(findUsingDeclarations,rootNav);
1973 }
1974
1975 //----------------------------------------------------------------------
1976
1977 static void findUsingDeclImports(EntryNav *rootNav)
1978 {
1979   if (rootNav->section()==Entry::USINGDECL_SEC &&
1980       (rootNav->parent()->section()&Entry::COMPOUND_MASK) // in a class/struct member
1981      )
1982   {
1983     //printf("Found using declaration %s at line %d of %s inside section %x\n",
1984     //    root->name.data(),root->startLine,root->fileName.data(),
1985     //    root->parent->section);
1986     QCString fullName=removeRedundantWhiteSpace(rootNav->parent()->name());
1987     fullName=stripAnonymousNamespaceScope(fullName);
1988     fullName=stripTemplateSpecifiersFromScope(fullName);
1989     ClassDef *cd = getClass(fullName);
1990     if (cd)
1991     {
1992       //printf("found class %s\n",cd->name().data());
1993       int i=rootNav->name().find("::");
1994       if (i!=-1)
1995       {
1996         QCString scope=rootNav->name().left(i);
1997         QCString memName=rootNav->name().right(rootNav->name().length()-i-2);
1998         ClassDef *bcd = getResolvedClass(cd,0,scope); // todo: file in fileScope parameter
1999         if (bcd)
2000         {
2001           //printf("found class %s\n",bcd->name().data());
2002           MemberNameInfoSDict *mndict=bcd->memberNameInfoSDict();
2003           if (mndict)
2004           {
2005             MemberNameInfo *mni = mndict->find(memName);
2006             if (mni)
2007             {
2008               MemberNameInfoIterator mnii(*mni); 
2009               MemberInfo *mi;
2010               for ( ; (mi=mnii.current()) ; ++mnii )
2011               {
2012                 MemberDef *md = mi->memberDef;
2013                 if (md && md->protection()!=Private)
2014                 {
2015
2016                   rootNav->loadEntry(g_storage);
2017                   Entry *root = rootNav->entry();
2018
2019                   //printf("found member %s\n",mni->memberName());
2020                   MemberDef *newMd = 0;
2021                   {
2022                     LockingPtr<ArgumentList> templAl = md->templateArguments();
2023                     LockingPtr<ArgumentList> al = md->templateArguments();
2024                     newMd = new MemberDef(
2025                       root->fileName,root->startLine,
2026                       md->typeString(),memName,md->argsString(),
2027                       md->excpString(),root->protection,root->virt,
2028                       md->isStatic(),Member,md->memberType(),
2029                       templAl.pointer(),al.pointer()
2030                       );
2031                   }
2032                   newMd->setMemberClass(cd);
2033                   cd->insertMember(newMd);
2034                   if (!root->doc.isEmpty() || !root->brief.isEmpty())
2035                   {
2036                     newMd->setDocumentation(root->doc,root->docFile,root->docLine);
2037                     newMd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
2038                     newMd->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
2039                   }
2040                   else
2041                   {
2042                     newMd->setDocumentation(md->documentation(),md->docFile(),md->docLine());
2043                     newMd->setBriefDescription(md->briefDescription(),md->briefFile(),md->briefLine());
2044                     newMd->setInbodyDocumentation(md->inbodyDocumentation(),md->inbodyFile(),md->inbodyLine());
2045                   }
2046                   newMd->setDefinition(md->definition());
2047                   newMd->enableCallGraph(root->callGraph);
2048                   newMd->enableCallerGraph(root->callerGraph);
2049                   newMd->setBitfields(md->bitfieldString());
2050                   newMd->addSectionsToDefinition(root->anchors);
2051                   newMd->setBodySegment(md->getStartBodyLine(),md->getEndBodyLine());
2052                   newMd->setBodyDef(md->getBodyDef());
2053                   newMd->setInitializer(md->initializer());
2054                   newMd->setMaxInitLines(md->initializerLines());
2055                   newMd->setMemberGroupId(root->mGrpId);
2056                   newMd->setMemberSpecifiers(md->getMemberSpecifiers());
2057                   newMd->setLanguage(root->lang);
2058
2059                   rootNav->releaseEntry();
2060                 }
2061               }
2062             }
2063           }
2064         }
2065       }
2066     }
2067
2068   }
2069   RECURSE_ENTRYTREE(findUsingDeclImports,rootNav);
2070 }
2071
2072 //----------------------------------------------------------------------
2073
2074 static void findIncludedUsingDirectives()
2075 {
2076   // first mark all files as not visited
2077   FileNameListIterator fnli(*Doxygen::inputNameList); 
2078   FileName *fn;
2079   for (fnli.toFirst();(fn=fnli.current());++fnli)
2080   {
2081     FileNameIterator fni(*fn);
2082     FileDef *fd;
2083     for (;(fd=fni.current());++fni)
2084     {
2085       fd->visited=FALSE;
2086     }
2087   }
2088   // then recursively add using directives found in #include files
2089   // to files that have not been visited.
2090   for (fnli.toFirst();(fn=fnli.current());++fnli)
2091   {
2092     FileNameIterator fni(*fn);
2093     FileDef *fd;
2094     for (fni.toFirst();(fd=fni.current());++fni)
2095     {
2096       if (!fd->visited) 
2097       {
2098         //printf("----- adding using directives for file %s\n",fd->name().data());
2099         fd->addIncludedUsingDirectives();
2100       }
2101     }
2102   }
2103 }
2104
2105 //----------------------------------------------------------------------
2106
2107 static MemberDef *addVariableToClass(
2108     EntryNav *rootNav,
2109     ClassDef *cd,
2110     MemberDef::MemberType mtype,
2111     const QCString &name,
2112     bool fromAnnScope,
2113     MemberDef *fromAnnMemb,
2114     Protection prot,
2115     Relationship related)
2116 {
2117   Entry *root = rootNav->entry();
2118
2119   QCString qualScope = cd->qualifiedNameWithTemplateParameters();
2120   QCString scopeSeparator="::";
2121   SrcLangExt lang = cd->getLanguage();
2122   if (lang==SrcLangExt_Java || lang==SrcLangExt_CSharp)
2123   {
2124     qualScope = substitute(qualScope,"::",".");
2125     scopeSeparator=".";
2126   }
2127   Debug::print(Debug::Variables,0,
2128       "  class variable:\n"
2129       "    `%s' `%s'::`%s' `%s' prot=`%d ann=%d init=`%s'\n",
2130       root->type.data(),
2131       qualScope.data(), 
2132       name.data(),
2133       root->args.data(),
2134       root->protection,
2135       fromAnnScope,
2136       root->initializer.data()
2137               );
2138
2139   QCString def;
2140   if (!root->type.isEmpty())
2141   {
2142     if (related || mtype==MemberDef::Friend || Config_getBool("HIDE_SCOPE_NAMES"))
2143     {
2144       if (root->spec&Entry::Alias) // turn 'typedef B A' into 'using A = B'  
2145       {
2146         def="using "+name+" = "+root->type.mid(7);
2147       }
2148       else
2149       {
2150         def=root->type+" "+name+root->args;
2151       }
2152     }
2153     else
2154     {
2155       if (root->spec&Entry::Alias) // turn 'typedef B C::A' into 'using C::A = B'  
2156       {
2157         def="using "+qualScope+scopeSeparator+name+" = "+root->type.mid(7);
2158       }
2159       else
2160       {
2161         def=root->type+" "+qualScope+scopeSeparator+name+root->args;
2162       }
2163     }
2164   }
2165   else
2166   {
2167     if (Config_getBool("HIDE_SCOPE_NAMES"))
2168     {
2169       def=name+root->args;
2170     }
2171     else
2172     {
2173       def=qualScope+scopeSeparator+name+root->args;
2174     }
2175   }
2176   def.stripPrefix("static ");
2177
2178   // see if the member is already found in the same scope
2179   // (this may be the case for a static member that is initialized
2180   //  outside the class)
2181   MemberName *mn=Doxygen::memberNameSDict->find(name);
2182   if (mn)
2183   {
2184     MemberNameIterator mni(*mn);
2185     MemberDef *md;
2186     for (mni.toFirst();(md=mni.current());++mni)
2187     {
2188       //printf("md->getClassDef()=%p cd=%p type=[%s] md->typeString()=[%s]\n",
2189       //    md->getClassDef(),cd,root->type.data(),md->typeString());
2190       if (md->getClassDef()==cd && 
2191           removeRedundantWhiteSpace(root->type)==md->typeString()) 
2192         // member already in the scope
2193       {
2194
2195         if (root->lang==SrcLangExt_ObjC && 
2196             root->mtype==Property && 
2197             md->memberType()==MemberDef::Variable)
2198         { // Objective-C 2.0 property
2199           // turn variable into a property
2200           md->setProtection(root->protection);
2201           cd->reclassifyMember(md,MemberDef::Property);
2202         }
2203         addMemberDocs(rootNav,md,def,0,FALSE);
2204         //printf("    Member already found!\n");
2205         return md;
2206       }
2207     } 
2208   }
2209
2210   // new member variable, typedef or enum value
2211   MemberDef *md=new MemberDef(
2212       root->fileName,root->startLine,
2213       root->type,name,root->args,0,
2214       prot,Normal,root->stat,related,
2215       mtype,root->tArgLists ? root->tArgLists->last() : 0,0);
2216   md->setTagInfo(rootNav->tagInfo());
2217   md->setMemberClass(cd); // also sets outer scope (i.e. getOuterScope())
2218   //md->setDefFile(root->fileName);
2219   //md->setDefLine(root->startLine);
2220   md->setDocumentation(root->doc,root->docFile,root->docLine);
2221   md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
2222   md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
2223   md->setDefinition(def);
2224   md->setBitfields(root->bitfields);
2225   md->addSectionsToDefinition(root->anchors);
2226   md->setFromAnonymousScope(fromAnnScope);
2227   md->setFromAnonymousMember(fromAnnMemb);
2228   //md->setIndentDepth(indentDepth);
2229   md->setBodySegment(root->bodyLine,root->endBodyLine);
2230   md->setInitializer(root->initializer);
2231   md->setMaxInitLines(root->initLines);
2232   md->setMemberGroupId(root->mGrpId);
2233   md->setMemberSpecifiers(root->spec);
2234   md->setReadAccessor(root->read);
2235   md->setWriteAccessor(root->write);
2236   md->enableCallGraph(root->callGraph);
2237   md->enableCallerGraph(root->callerGraph);
2238   md->setHidden(root->hidden);
2239   md->setArtificial(root->artificial);
2240   md->setLanguage(root->lang);
2241   addMemberToGroups(root,md);
2242   //if (root->mGrpId!=-1) 
2243   //{
2244   //  printf("memberdef %s in memberGroup %d\n",name.data(),root->mGrpId);
2245   //  md->setMemberGroup(memberGroupDict[root->mGrpId]);
2246   //
2247   md->setBodyDef(rootNav->fileDef());
2248
2249   //printf("    Adding member=%s\n",md->name().data());
2250   // add the member to the global list
2251   if (mn)
2252   {
2253     mn->append(md);
2254   }
2255   else // new variable name
2256   {
2257     mn = new MemberName(name);
2258     mn->append(md);
2259     //printf("Adding memberName=%s\n",mn->memberName());
2260     //Doxygen::memberNameDict.insert(name,mn);
2261     //Doxygen::memberNameList.append(mn);
2262     Doxygen::memberNameSDict->append(name,mn);
2263     // add the member to the class
2264   }
2265   //printf("    New member adding to %s (%p)!\n",cd->name().data(),cd);
2266   cd->insertMember(md);
2267   md->setRefItems(root->sli);
2268
2269   //TODO: insert FileDef instead of filename strings.
2270   cd->insertUsedFile(root->fileName);
2271   rootNav->changeSection(Entry::EMPTY_SEC);
2272   return md;
2273 }
2274
2275 //----------------------------------------------------------------------
2276
2277 static MemberDef *addVariableToFile(
2278     EntryNav *rootNav,
2279     MemberDef::MemberType mtype,
2280     const QCString &scope,
2281     const QCString &name,
2282     bool fromAnnScope,
2283     /*int indentDepth,*/
2284     MemberDef *fromAnnMemb)
2285 {
2286   Entry *root = rootNav->entry();
2287   Debug::print(Debug::Variables,0,
2288       "  global variable:\n"
2289       "    type=`%s' scope=`%s' name=`%s' args=`%s' prot=`%d mtype=%d lang=%d\n",
2290       root->type.data(),
2291       scope.data(), 
2292       name.data(),
2293       root->args.data(),
2294       root->protection,
2295       mtype,
2296       root->lang
2297               );
2298
2299   FileDef *fd = rootNav->fileDef();
2300
2301   // see if we have a typedef that should hide a struct or union
2302   if (mtype==MemberDef::Typedef && Config_getBool("TYPEDEF_HIDES_STRUCT"))
2303   {
2304     QCString type = root->type;
2305     type.stripPrefix("typedef ");
2306     if (type.left(7)=="struct " || type.left(6)=="union ")
2307     {
2308       type.stripPrefix("struct ");
2309       type.stripPrefix("union ");
2310       static QRegExp re("[a-z_A-Z][a-z_A-Z0-9]*");
2311       int l,s;
2312       s = re.match(type,0,&l);
2313       if (s>=0)
2314       {
2315         QCString typeValue = type.mid(s,l);
2316         ClassDef *cd = getClass(typeValue);
2317         if (cd)
2318         {
2319           // this typedef should hide compound name cd, so we
2320           // change the name that is displayed from cd.
2321           cd->setClassName(name);
2322           cd->setDocumentation(root->doc,root->docFile,root->docLine);
2323           cd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
2324           return 0;
2325         }
2326       }
2327     }
2328   }
2329
2330   // see if the function is inside a namespace
2331   NamespaceDef *nd = 0;
2332   QCString nscope;
2333   if (!scope.isEmpty())
2334   {
2335     if (scope.find('@')!=-1) return 0; // anonymous scope!
2336     //nscope=removeAnonymousScopes(scope);
2337     //if (!nscope.isEmpty())
2338     //{
2339     nd = getResolvedNamespace(scope);
2340     //}
2341   }
2342   QCString def;
2343
2344   // determine the definition of the global variable
2345   if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@' && 
2346       !Config_getBool("HIDE_SCOPE_NAMES")
2347      )
2348     // variable is inside a namespace, so put the scope before the name
2349   {
2350     SrcLangExt lang = nd->getLanguage();
2351     QCString sep=getLanguageSpecificSeparator(lang);
2352
2353     if (!root->type.isEmpty())
2354     {
2355       if (root->spec&Entry::Alias) // turn 'typedef B NS::A' into 'using NS::A = B'  
2356       {
2357         def="using "+nd->name()+sep+name+" = "+root->type;
2358       }
2359       else // normal member
2360       {
2361         def=root->type+" "+nd->name()+sep+name+root->args;
2362       }
2363     }
2364     else
2365     {
2366       def=nd->name()+sep+name+root->args;
2367     }
2368   }
2369   else
2370   {
2371     if (!root->type.isEmpty() && !root->name.isEmpty())
2372     {
2373       if (name.at(0)=='@') // dummy variable representing anonymous union
2374       {
2375         def=root->type;
2376       }
2377       else
2378       {
2379         if (root->spec&Entry::Alias) // turn 'typedef B A' into 'using A = B'  
2380         {
2381           def="using "+root->name+" = "+root->type.mid(7);
2382         }
2383         else // normal member
2384         {
2385           def=root->type+" "+name+root->args;
2386         }
2387       }
2388     }
2389     else
2390     {
2391       def=name+root->args;
2392     }
2393   }
2394   def.stripPrefix("static ");
2395
2396   MemberName *mn=Doxygen::functionNameSDict->find(name);
2397   if (mn)
2398   {
2399     //QCString nscope=removeAnonymousScopes(scope);
2400     //NamespaceDef *nd=0;
2401     //if (!nscope.isEmpty())
2402     if (!scope.isEmpty())
2403     {
2404       nd = getResolvedNamespace(scope);
2405     }
2406     MemberNameIterator mni(*mn);
2407     MemberDef *md;
2408     for (mni.toFirst();(md=mni.current());++mni)
2409     {
2410       if (
2411           ((nd==0 && md->getNamespaceDef()==0 && md->getFileDef() && 
2412             root->fileName==md->getFileDef()->absFilePath()
2413            ) // both variable names in the same file
2414            || (nd!=0 && md->getNamespaceDef()==nd) // both in same namespace
2415           )
2416           && !md->isDefine() // function style #define's can be "overloaded" by typedefs or variables
2417           && !md->isEnumerate() // in C# an enum value and enum can have the same name
2418          )
2419         // variable already in the scope
2420       {
2421         bool isPHPArray = md->getLanguage()==SrcLangExt_PHP &&
2422                           md->argsString()!=root->args && 
2423                           root->args.find('[')!=-1;
2424         bool staticsInDifferentFiles = 
2425                           root->stat && md->isStatic() && 
2426                           root->fileName!=md->getDefFileName();
2427
2428         if (md->getFileDef() &&
2429             !isPHPArray && // not a php array
2430             !staticsInDifferentFiles
2431            ) 
2432           // not a php array variable
2433         {
2434
2435           Debug::print(Debug::Variables,0,
2436               "    variable already found: scope=%s\n",md->getOuterScope()->name().data());
2437           addMemberDocs(rootNav,md,def,0,FALSE);
2438           md->setRefItems(root->sli);
2439           return md;
2440         }
2441       }
2442     } 
2443   }
2444   Debug::print(Debug::Variables,0,
2445     "    new variable, nd=%s!\n",nd?nd->name().data():"<global>");
2446   // new global variable, enum value or typedef
2447   MemberDef *md=new MemberDef(
2448       root->fileName,root->startLine,
2449       root->type,name,root->args,0,
2450       Public, Normal,root->stat,Member,
2451       mtype,root->tArgLists ? root->tArgLists->last() : 0,0);
2452   md->setTagInfo(rootNav->tagInfo());
2453   md->setMemberSpecifiers(root->spec);
2454   md->setDocumentation(root->doc,root->docFile,root->docLine);
2455   md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
2456   md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
2457   md->addSectionsToDefinition(root->anchors);
2458   md->setFromAnonymousScope(fromAnnScope);
2459   md->setFromAnonymousMember(fromAnnMemb);
2460   md->setInitializer(root->initializer);
2461   md->setMaxInitLines(root->initLines);
2462   md->setMemberGroupId(root->mGrpId);
2463   md->setDefinition(def);
2464   md->setLanguage(root->lang);
2465   md->enableCallGraph(root->callGraph);
2466   md->enableCallerGraph(root->callerGraph);
2467   md->setExplicitExternal(root->explicitExternal);
2468   //md->setOuterScope(fd);
2469   if (!root->explicitExternal)
2470   {
2471     md->setBodySegment(root->bodyLine,root->endBodyLine);
2472     md->setBodyDef(fd);
2473   }
2474   addMemberToGroups(root,md);
2475
2476   md->setRefItems(root->sli);
2477   if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@')
2478   {
2479     md->setNamespace(nd);
2480     nd->insertMember(md); 
2481   }
2482
2483   // add member to the file (we do this even if we have already inserted
2484   // it into the namespace. 
2485   if (fd)
2486   {
2487     md->setFileDef(fd); 
2488     fd->insertMember(md);
2489   }
2490
2491   // add member definition to the list of globals 
2492   if (mn)
2493   {
2494     mn->append(md);
2495   }
2496   else
2497   {
2498     mn = new MemberName(name);
2499     mn->append(md);
2500     Doxygen::functionNameSDict->append(name,mn);
2501   }
2502   rootNav->changeSection(Entry::EMPTY_SEC);
2503   return md;
2504 }
2505
2506 /*! See if the return type string \a type is that of a function pointer 
2507  *  \returns -1 if this is not a function pointer variable or
2508  *           the index at which the closing brace of (...*name) was found.
2509  */
2510 static int findFunctionPtr(const QCString &type,int lang, int *pLength=0)
2511 {
2512   if (lang == SrcLangExt_Fortran) return -1; // Fortran does not have function pointers
2513   static const QRegExp re("([^)]*[\\*\\^][^)]*)");
2514   int i=-1,l;
2515   int bb=type.find('<');
2516   int be=type.findRev('>');
2517   if (!type.isEmpty() &&             // return type is non-empty
2518       (i=re.match(type,0,&l))!=-1 && // contains (...*...)
2519       type.find("operator")==-1 &&   // not an operator
2520       (type.find(")(")==-1 || type.find("typedef ")!=-1) &&
2521                                     // not a function pointer return type
2522       !(bb<i && i<be) // bug665855: avoid treating "typedef A<void (T*)> type" as a function pointer
2523      )
2524   {
2525     if (pLength) *pLength=l;
2526     //printf("findFunctionPtr=%d\n",i);
2527     return i;
2528   }
2529   else
2530   {
2531     //printf("findFunctionPtr=%d\n",-1);
2532     return -1;
2533   }
2534 }
2535
2536
2537 /*! Returns TRUE iff \a type is a class within scope \a context.
2538  *  Used to detect variable declarations that look like function prototypes.
2539  */
2540 static bool isVarWithConstructor(EntryNav *rootNav)
2541 {
2542   static QRegExp initChars("[0-9\"'&*!^]+");
2543   static QRegExp idChars("[a-z_A-Z][a-z_A-Z0-9]*");
2544   bool result=FALSE;
2545   bool typeIsClass;
2546   QCString type;
2547   Definition *ctx = 0;
2548   FileDef *fd = 0;
2549   int ti;
2550
2551   //printf("isVarWithConstructor(%s)\n",rootNav->name().data());
2552   rootNav->loadEntry(g_storage);
2553   Entry *root = rootNav->entry();
2554
2555   if (rootNav->parent()->section() & Entry::COMPOUND_MASK)
2556   { // inside a class
2557     result=FALSE;
2558     goto done;
2559   }
2560   else if ((fd = rootNav->fileDef()) &&
2561             (fd->name().right(2)==".c" || fd->name().right(2)==".h")
2562           )
2563   { // inside a .c file
2564     result=FALSE;
2565     goto done;
2566   }
2567   if (root->type.isEmpty()) 
2568   {
2569     result=FALSE;
2570     goto done;
2571   }
2572   if (!rootNav->parent()->name().isEmpty()) 
2573   {
2574     ctx=Doxygen::namespaceSDict->find(rootNav->parent()->name());
2575   }
2576   type = root->type;
2577   // remove qualifiers
2578   findAndRemoveWord(type,"const");
2579   findAndRemoveWord(type,"static");
2580   findAndRemoveWord(type,"volatile");
2581   //if (type.left(6)=="const ") type=type.right(type.length()-6);
2582   typeIsClass=getResolvedClass(ctx,fd,type)!=0;
2583   if (!typeIsClass && (ti=type.find('<'))!=-1)
2584   {
2585     typeIsClass=getResolvedClass(ctx,fd,type.left(ti))!=0;
2586   }
2587   if (typeIsClass) // now we still have to check if the arguments are 
2588                    // types or values. Since we do not have complete type info
2589                    // we need to rely on heuristics :-(
2590   {
2591     //printf("typeIsClass\n");
2592     ArgumentList *al = root->argList;
2593     if (al==0 || al->isEmpty()) 
2594     {
2595       result=FALSE; // empty arg list -> function prototype.
2596       goto done;
2597     }
2598     ArgumentListIterator ali(*al);
2599     Argument *a;
2600     for (ali.toFirst();(a=ali.current());++ali)
2601     {
2602       if (!a->name.isEmpty() || !a->defval.isEmpty()) 
2603       {
2604         if (a->name.find(initChars)==0)
2605         {
2606           result=TRUE;
2607         }
2608         else
2609         {
2610           result=FALSE; // arg has (type,name) pair -> function prototype
2611         }
2612         goto done;
2613       }
2614       if (a->type.isEmpty() || getResolvedClass(ctx,fd,a->type)!=0) 
2615       {
2616         result=FALSE; // arg type is a known type
2617         goto done;
2618       }
2619       if (checkIfTypedef(ctx,fd,a->type))
2620       {
2621          //printf("%s:%d: false (arg is typedef)\n",__FILE__,__LINE__);
2622          result=FALSE; // argument is a typedef
2623          goto done;
2624       }
2625       if (a->type.at(a->type.length()-1)=='*' ||
2626           a->type.at(a->type.length()-1)=='&')  
2627                      // type ends with * or & => pointer or reference
2628       {
2629         result=FALSE;
2630         goto done;
2631       }
2632       if (a->type.find(initChars)==0) 
2633       {
2634         result=TRUE; // argument type starts with typical initializer char
2635         goto done;
2636       }
2637       QCString resType=resolveTypeDef(ctx,a->type);
2638       if (resType.isEmpty()) resType=a->type;
2639       int len;
2640       if (idChars.match(resType,0,&len)==0) // resType starts with identifier
2641       {
2642         resType=resType.left(len);
2643         //printf("resType=%s\n",resType.data());
2644         if (resType=="int"    || resType=="long" || resType=="float" || 
2645             resType=="double" || resType=="char" || resType=="signed" || 
2646             resType=="const"  || resType=="unsigned" || resType=="void") 
2647         {
2648           result=FALSE; // type keyword -> function prototype
2649           goto done;
2650         }
2651       }
2652     }
2653     result=TRUE;
2654   }
2655
2656 done:
2657   //printf("isVarWithConstructor(%s,%s)=%d\n",rootNav->parent()->name().data(),
2658   //                                          root->type.data(),result);
2659   rootNav->releaseEntry();
2660   return result;
2661 }
2662
2663 static void addVariable(EntryNav *rootNav,int isFuncPtr=-1)
2664 {
2665     rootNav->loadEntry(g_storage);
2666     Entry *root = rootNav->entry();
2667
2668     Debug::print(Debug::Variables,0,
2669                   "VARIABLE_SEC: \n"
2670                   "  type=`%s' name=`%s' args=`%s' bodyLine=`%d' mGrpId=%d relates=%s\n",
2671                    root->type.data(),
2672                    root->name.data(),
2673                    root->args.data(),
2674                    root->bodyLine,
2675                    root->mGrpId,
2676                    root->relates.data()
2677                 );
2678     //printf("root->parent->name=%s\n",root->parent->name.data());
2679
2680     if (root->type.isEmpty() && root->name.find("operator")==-1 &&
2681         (root->name.find('*')!=-1 || root->name.find('&')!=-1))
2682     {
2683       // recover from parse error caused by redundant braces 
2684       // like in "int *(var[10]);", which is parsed as
2685       // type="" name="int *" args="(var[10])"
2686
2687       root->type=root->name;
2688       static const QRegExp reName("[a-z_A-Z][a-z_A-Z0-9]*");
2689       int l;
2690       int i=root->args.isEmpty() ? -1 : reName.match(root->args,0,&l);
2691       root->name=root->args.mid(i,l);
2692       root->args=root->args.mid(i+l,root->args.find(')',i+l)-i-l);
2693       //printf("new: type=`%s' name=`%s' args=`%s'\n",
2694       //    root->type.data(),root->name.data(),root->args.data());
2695     }
2696     else
2697     {
2698       int i=isFuncPtr;
2699       if (i==-1 && (root->spec&Entry::Alias)==0) i=findFunctionPtr(root->type,root->lang); // for typedefs isFuncPtr is not yet set
2700       Debug::print(Debug::Variables,0,"  functionPtr? %s\n",i!=-1?"yes":"no");
2701       if (i!=-1) // function pointer
2702       {
2703         int ai = root->type.find('[',i);
2704         if (ai>i) // function pointer array
2705         {
2706           root->args.prepend(root->type.right(root->type.length()-ai));
2707           root->type=root->type.left(ai);
2708         }
2709         else if (root->type.find(')',i)!=-1) // function ptr, not variable like "int (*bla)[10]"
2710         {
2711           root->type=root->type.left(root->type.length()-1);
2712           root->args.prepend(")");
2713           //printf("root->type=%s root->args=%s\n",root->type.data(),root->args.data());
2714         }
2715       }
2716       else if (root->type.find("typedef ")!=-1 && root->type.right(2)=="()") // typedef void (func)(int)
2717       {
2718         root->type=root->type.left(root->type.length()-1);
2719         root->args.prepend(")");
2720       }
2721     }
2722     
2723     QCString scope,name=removeRedundantWhiteSpace(root->name);
2724
2725     // find the scope of this variable 
2726     EntryNav *p = rootNav->parent();
2727     while ((p->section() & Entry::SCOPE_MASK))
2728     {
2729       QCString scopeName = p->name();
2730       if (!scopeName.isEmpty())
2731       {
2732         scope.prepend(scopeName);
2733         break;
2734       }
2735       p=p->parent();
2736     }
2737     
2738     MemberDef::MemberType mtype;
2739     QCString type=root->type.stripWhiteSpace();
2740     ClassDef *cd=0;
2741     bool isRelated=FALSE;
2742     bool isMemberOf=FALSE;
2743
2744     QCString classScope=stripAnonymousNamespaceScope(scope);
2745     classScope=stripTemplateSpecifiersFromScope(classScope,FALSE);
2746     QCString annScopePrefix=scope.left(scope.length()-classScope.length());
2747
2748     if (root->name.findRev("::")!=-1) 
2749     {
2750       if (root->type=="friend class" || root->type=="friend struct" || 
2751           root->type=="friend union")
2752       {
2753          cd=getClass(scope);
2754          if (cd)
2755          {
2756            addVariableToClass(rootNav,  // entry
2757                               cd,    // class to add member to
2758                               MemberDef::Friend, // type of member
2759                               name, // name of the member
2760                               FALSE,  // from Anonymous scope
2761                               0,      // anonymous member
2762                               Public, // protection
2763                               Member  // related to a class
2764                              );
2765          }
2766       }
2767       goto nextMember;
2768                /* skip this member, because it is a 
2769                 * static variable definition (always?), which will be
2770                 * found in a class scope as well, but then we know the
2771                 * correct protection level, so only then it will be
2772                 * inserted in the correct list!
2773                 */
2774     }
2775
2776     if (type=="@") 
2777       mtype=MemberDef::EnumValue;
2778     else if (type.left(8)=="typedef ") 
2779       mtype=MemberDef::Typedef;
2780     else if (type.left(7)=="friend ")
2781       mtype=MemberDef::Friend;
2782     else if (root->mtype==Property)
2783       mtype=MemberDef::Property;
2784     else if (root->mtype==Event)
2785       mtype=MemberDef::Event;
2786     else
2787       mtype=MemberDef::Variable;
2788
2789     if (!root->relates.isEmpty()) // related variable
2790     {
2791       isRelated=TRUE;
2792       isMemberOf=(root->relatesType == MemberOf);
2793       if (getClass(root->relates)==0 && !scope.isEmpty())
2794         scope=mergeScopes(scope,root->relates);
2795       else 
2796         scope=root->relates;
2797     }
2798     
2799     cd=getClass(scope);
2800     if (cd==0 && classScope!=scope) cd=getClass(classScope);
2801     if (cd)
2802     {
2803       MemberDef *md=0;
2804
2805       // if cd is an anonymous (=tag less) scope we insert the member 
2806       // into a non-anonymous parent scope as well. This is needed to
2807       // be able to refer to it using \var or \fn
2808
2809       //int indentDepth=0;
2810       int si=scope.find('@');
2811       //int anonyScopes = 0;
2812       //bool added=FALSE;
2813       
2814       static bool inlineSimpleStructs = Config_getBool("INLINE_SIMPLE_STRUCTS");
2815       if (si!=-1 && !inlineSimpleStructs) // anonymous scope or type
2816       {
2817         QCString pScope;
2818         ClassDef *pcd=0;
2819         pScope = scope.left(QMAX(si-2,0)); // scope without tag less parts
2820         if (!pScope.isEmpty())
2821           pScope.prepend(annScopePrefix);
2822         else if (annScopePrefix.length()>2)
2823           pScope=annScopePrefix.left(annScopePrefix.length()-2);
2824         if (name.at(0)!='@')
2825         {
2826           if (!pScope.isEmpty() && (pcd=getClass(pScope)))
2827           {
2828             md=addVariableToClass(rootNav,  // entry
2829                                   pcd,   // class to add member to
2830                                   mtype, // member type
2831                                   name,  // member name
2832                                   TRUE,  // from anonymous scope
2833                                   0,     // from anonymous member
2834                                   root->protection,
2835                                   isMemberOf ? Foreign : isRelated ? Related : Member
2836                                  );
2837             //added=TRUE;
2838           }
2839           else // anonymous scope inside namespace or file => put variable in the global scope
2840           {
2841             if (mtype==MemberDef::Variable)
2842             {
2843               md=addVariableToFile(rootNav,mtype,pScope,name,TRUE,0); 
2844             }
2845             //added=TRUE;
2846           }
2847         }
2848       }
2849
2850       //printf("name=`%s' scope=%s scope.right=%s\n",
2851       //                   name.data(),scope.data(),
2852       //                   scope.right(scope.length()-si).data());
2853       addVariableToClass(rootNav,   // entry
2854                          cd,     // class to add member to
2855                          mtype,  // member type
2856                          name,   // name of the member
2857                          FALSE,  // from anonymous scope
2858                          md,     // from anonymous member
2859                          root->protection, 
2860                          isMemberOf ? Foreign : isRelated ? Related : Member);
2861     }
2862     else if (!name.isEmpty()) // global variable
2863     {
2864       //printf("Inserting member in global scope %s!\n",scope.data());
2865       addVariableToFile(rootNav,mtype,scope,name,FALSE,/*0,*/0);
2866     }
2867
2868 nextMember:
2869     rootNav->releaseEntry();
2870 }
2871
2872 //----------------------------------------------------------------------
2873 // Searches the Entry tree for typedef documentation sections.
2874 // If found they are stored in their class or in the global list.
2875 static void buildTypedefList(EntryNav *rootNav)
2876 {
2877   //printf("buildVarList(%s)\n",rootNav->name().data());
2878   if (!rootNav->name().isEmpty() &&
2879       rootNav->section()==Entry::VARIABLE_SEC &&
2880       rootNav->type().find("typedef ")!=-1 // its a typedef
2881      ) 
2882   {
2883     addVariable(rootNav);
2884   }
2885   if (rootNav->children())
2886   {
2887     EntryNavListIterator eli(*rootNav->children());
2888     EntryNav *e;
2889     for (;(e=eli.current());++eli)
2890     {
2891       if (e->section()!=Entry::ENUM_SEC) 
2892       {
2893         buildTypedefList(e);
2894       }
2895     }
2896   }
2897 }
2898
2899 //----------------------------------------------------------------------
2900 // Searches the Entry tree for Variable documentation sections.
2901 // If found they are stored in their class or in the global list.
2902
2903 static void buildVarList(EntryNav *rootNav)
2904 {
2905   //printf("buildVarList(%s) section=%08x\n",rootNav->name().data(),rootNav->section());
2906   int isFuncPtr=-1;
2907   if (!rootNav->name().isEmpty() &&
2908       (rootNav->type().isEmpty() || g_compoundKeywordDict.find(rootNav->type())==0) &&
2909       (
2910        (rootNav->section()==Entry::VARIABLE_SEC    // it's a variable
2911        ) ||
2912        (rootNav->section()==Entry::FUNCTION_SEC && // or maybe a function pointer variable 
2913         (isFuncPtr=findFunctionPtr(rootNav->type(),rootNav->lang()))!=-1
2914        ) ||
2915        (rootNav->section()==Entry::FUNCTION_SEC && // class variable initialized by constructor
2916         isVarWithConstructor(rootNav)
2917        )
2918       ) 
2919      ) // documented variable
2920   {
2921     addVariable(rootNav,isFuncPtr);
2922   }
2923   if (rootNav->children())
2924   {
2925     EntryNavListIterator eli(*rootNav->children());
2926     EntryNav *e;
2927     for (;(e=eli.current());++eli)
2928     {
2929       if (e->section()!=Entry::ENUM_SEC) 
2930       {
2931         buildVarList(e);
2932       }
2933     }
2934   }
2935 }
2936
2937 //----------------------------------------------------------------------
2938 // Searches the Entry tree for Function sections.
2939 // If found they are stored in their class or in the global list.
2940
2941 static void addMethodToClass(EntryNav *rootNav,ClassDef *cd,
2942                   const QCString &rname,bool isFriend)
2943 {
2944   Entry *root = rootNav->entry();
2945   FileDef *fd=rootNav->fileDef();
2946
2947   int l;
2948   static QRegExp re("([a-z_A-Z0-9: ]*[ &*]+[ ]*");
2949   int ts=root->type.find('<');
2950   int te=root->type.findRev('>');
2951   int i=re.match(root->type,0,&l);
2952   if (i!=-1 && ts!=-1 && ts<te && ts<i && i<te) // avoid changing A<int(int*)>, see bug 677315
2953   {
2954     i=-1;
2955   }
2956
2957   if (cd->getLanguage()==SrcLangExt_Cpp && // only C has pointers
2958       !root->type.isEmpty() && (root->spec&Entry::Alias)==0 && i!=-1) // function variable
2959   {
2960     root->args+=root->type.right(root->type.length()-i-l);
2961     root->type=root->type.left(i+l);
2962   }
2963
2964   QCString name=removeRedundantWhiteSpace(rname);
2965   if (name.left(2)=="::") name=name.right(name.length()-2);
2966
2967   MemberDef::MemberType mtype;
2968   if (isFriend)                 mtype=MemberDef::Friend;
2969   else if (root->mtype==Signal) mtype=MemberDef::Signal;
2970   else if (root->mtype==Slot)   mtype=MemberDef::Slot;
2971   else if (root->mtype==DCOP)   mtype=MemberDef::DCOP;
2972   else                          mtype=MemberDef::Function;
2973
2974   // strip redundant template specifier for constructors
2975   if ((fd==0 || fd->getLanguage()==SrcLangExt_Cpp) &&
2976      name.left(9)!="operator " && (i=name.find('<'))!=-1 && name.find('>')!=-1)
2977   {
2978     name=name.left(i); 
2979   }
2980
2981   //printf("root->name=`%s; root->args=`%s' root->argList=`%s'\n", 
2982   //    root->name.data(),root->args.data(),argListToString(root->argList).data()
2983   //   );
2984
2985   // adding class member
2986   MemberDef *md=new MemberDef(
2987       root->fileName,root->startLine,
2988       root->type,name,root->args,root->exception,
2989       root->protection,root->virt,
2990       root->stat && root->relatesType != MemberOf,
2991       root->relates.isEmpty() ? Member :
2992           root->relatesType == MemberOf ? Foreign : Related,
2993       mtype,root->tArgLists ? root->tArgLists->last() : 0,root->argList);
2994   md->setTagInfo(rootNav->tagInfo());
2995   md->setMemberClass(cd);
2996   md->setDocumentation(root->doc,root->docFile,root->docLine);
2997   md->setDocsForDefinition(!root->proto);
2998   md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
2999   md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
3000   md->setBodySegment(root->bodyLine,root->endBodyLine);
3001   md->setMemberSpecifiers(root->spec);
3002   md->setMemberGroupId(root->mGrpId);
3003   md->setTypeConstraints(root->typeConstr);
3004   md->setLanguage(root->lang);
3005   md->setBodyDef(fd);
3006   md->setFileDef(fd);
3007   //md->setScopeTemplateArguments(root->tArgList);
3008   md->addSectionsToDefinition(root->anchors);
3009   QCString def;
3010   QCString qualScope = cd->qualifiedNameWithTemplateParameters();
3011   SrcLangExt lang = cd->getLanguage();
3012   QCString scopeSeparator=getLanguageSpecificSeparator(lang);
3013   if (scopeSeparator!="::")
3014   {
3015     qualScope = substitute(qualScope,"::",scopeSeparator);
3016   }
3017   if (lang==SrcLangExt_PHP)
3018   {
3019     // for PHP we use Class::method and Namespace\method
3020     scopeSeparator="::";
3021   }
3022   if (!root->relates.isEmpty() || isFriend || Config_getBool("HIDE_SCOPE_NAMES"))
3023   {
3024     if (!root->type.isEmpty())
3025     {
3026       if (root->argList)
3027       {
3028         def=root->type+" "+name;
3029       }
3030       else
3031       {
3032         def=root->type+" "+name+root->args;
3033       }
3034     }
3035     else
3036     {
3037       if (root->argList)
3038       {
3039         def=name;
3040       }
3041       else
3042       {
3043         def=name+root->args;
3044       }
3045     }
3046   }
3047   else
3048   {
3049     if (!root->type.isEmpty())
3050     {
3051       if (root->argList)
3052       {
3053         def=root->type+" "+qualScope+scopeSeparator+name;
3054       }
3055       else
3056       {
3057         def=root->type+" "+qualScope+scopeSeparator+name+root->args;
3058       }
3059     }
3060     else
3061     {
3062       if (root->argList)
3063       {
3064         def=qualScope+scopeSeparator+name;
3065       }
3066       else
3067       {
3068         def=qualScope+scopeSeparator+name+root->args;
3069       }
3070     }
3071   }
3072   if (def.left(7)=="friend ") def=def.right(def.length()-7);
3073   md->setDefinition(def);
3074   md->enableCallGraph(root->callGraph);
3075   md->enableCallerGraph(root->callerGraph);
3076
3077   Debug::print(Debug::Functions,0,
3078       "  Func Member:\n"
3079       "    `%s' `%s'::`%s' `%s' proto=%d\n"
3080       "    def=`%s'\n",
3081       root->type.data(),
3082       qualScope.data(),
3083       rname.data(),
3084       root->args.data(),
3085       root->proto,
3086       def.data()
3087               );
3088
3089   // add member to the global list of all members
3090   //printf("Adding member=%s class=%s\n",md->name().data(),cd->name().data());
3091   MemberName *mn;
3092   if ((mn=Doxygen::memberNameSDict->find(name)))
3093   {
3094     mn->append(md);
3095   }
3096   else
3097   {
3098     mn = new MemberName(name);
3099     mn->append(md);
3100     Doxygen::memberNameSDict->append(name,mn);
3101   }
3102
3103   // add member to the class cd
3104   cd->insertMember(md);
3105   // add file to list of used files
3106   cd->insertUsedFile(root->fileName);
3107
3108   addMemberToGroups(root,md);
3109   rootNav->changeSection(Entry::EMPTY_SEC);
3110   md->setRefItems(root->sli);
3111 }
3112
3113
3114 static void buildFunctionList(EntryNav *rootNav)
3115 {
3116   if (rootNav->section()==Entry::FUNCTION_SEC)
3117   {
3118     rootNav->loadEntry(g_storage);
3119     Entry *root = rootNav->entry();
3120
3121     Debug::print(Debug::Functions,0,
3122                  "FUNCTION_SEC:\n"
3123                  "  `%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",
3124                  root->type.data(),
3125                  rootNav->parent()->name().data(),
3126                  root->name.data(),
3127                  root->args.data(),
3128                  root->relates.data(),
3129                  root->relatesType,
3130                  root->fileName.data(),
3131                  root->startLine,
3132                  root->bodyLine,
3133                  root->tArgLists ? (int)root->tArgLists->count() : -1,
3134                  root->mGrpId,
3135                  root->spec,
3136                  root->proto,
3137                  root->docFile.data()
3138                 );
3139
3140     bool isFriend=root->type.find("friend ")!=-1;
3141     QCString rname = removeRedundantWhiteSpace(root->name);
3142     //printf("rname=%s\n",rname.data());
3143
3144     QCString scope=rootNav->parent()->name(); //stripAnonymousNamespaceScope(root->parent->name);
3145     if (!rname.isEmpty() && scope.find('@')==-1)
3146     {
3147       ClassDef *cd=0;
3148       // check if this function's parent is a class
3149       scope=stripTemplateSpecifiersFromScope(scope,FALSE);
3150
3151       FileDef *rfd=rootNav->fileDef();
3152
3153       int memIndex=rname.findRev("::");
3154
3155       cd=getClass(scope);
3156       if (cd && scope+"::"==rname.left(scope.length()+2)) // found A::f inside A
3157       {
3158         // strip scope from name
3159         rname=rname.right(rname.length()-rootNav->parent()->name().length()-2); 
3160       }
3161
3162       NamespaceDef *nd = 0;
3163       bool isMember=FALSE;
3164       if (memIndex!=-1)
3165       {
3166         int ts=rname.find('<');
3167         int te=rname.find('>');
3168         if (memIndex>0 && (ts==-1 || te==-1))
3169         {
3170           // note: the following code was replaced by inMember=TRUE to deal with a 
3171           // function rname='X::foo' of class X inside a namespace also called X...
3172           // bug id 548175
3173           //nd = Doxygen::namespaceSDict->find(rname.left(memIndex));
3174           //isMember = nd==0;
3175           //if (nd)
3176           //{
3177           //  // strip namespace scope from name
3178           //  scope=rname.left(memIndex);
3179           //  rname=rname.right(rname.length()-memIndex-2);
3180           //}
3181           isMember = TRUE;
3182         }
3183         else
3184         {
3185           isMember=memIndex<ts || memIndex>te;
3186         }
3187       }
3188
3189       static QRegExp re("([a-z_A-Z0-9: ]*[ &*]+[ ]*");
3190       int ts=root->type.find('<');
3191       int te=root->type.findRev('>');
3192       int ti;
3193       if (!rootNav->parent()->name().isEmpty() &&
3194           (rootNav->parent()->section() & Entry::COMPOUND_MASK) && 
3195           cd &&
3196           // do some fuzzy things to exclude function pointers 
3197           (root->type.isEmpty() || 
3198            ((ti=root->type.find(re,0))==-1 ||      // type does not contain ..(..* 
3199             (ts!=-1 && ts<te && ts<ti && ti<te) || // outside of < ... >
3200            root->args.find(")[")!=-1) ||           // and args not )[.. -> function pointer
3201            root->type.find(")(")!=-1 || root->type.find("operator")!=-1 || // type contains ..)(.. and not "operator"
3202            cd->getLanguage()!=SrcLangExt_Cpp                               // language other than C
3203           )
3204          )
3205       {
3206         Debug::print(Debug::Functions,0,"  --> member %s of class %s!\n",
3207             rname.data(),cd->name().data());
3208         addMethodToClass(rootNav,cd,rname,isFriend);
3209       }
3210       else if (!((rootNav->parent()->section() & Entry::COMPOUND_MASK) 
3211                  || rootNav->parent()->section()==Entry::OBJCIMPL_SEC
3212                 ) &&
3213                !isMember &&
3214                (root->relates.isEmpty() || root->relatesType == Duplicate) &&
3215                root->type.left(7)!="extern " && root->type.left(8)!="typedef " 
3216               )
3217       // no member => unrelated function 
3218       {
3219         /* check the uniqueness of the function name in the file.
3220          * A file could contain a function prototype and a function definition
3221          * or even multiple function prototypes.
3222          */
3223         bool found=FALSE;
3224         MemberName *mn;
3225         MemberDef *md=0;
3226         if ((mn=Doxygen::functionNameSDict->find(rname)))
3227         {
3228           Debug::print(Debug::Functions,0,"  --> function %s already found!\n",rname.data());
3229           MemberNameIterator mni(*mn);
3230           for (mni.toFirst();(!found && (md=mni.current()));++mni)
3231           {
3232             NamespaceDef *mnd = md->getNamespaceDef();
3233             NamespaceDef *rnd = 0;
3234             //printf("root namespace=%s\n",rootNav->parent()->name().data());
3235             QCString fullScope = scope;
3236             QCString parentScope = rootNav->parent()->name();
3237             if (!parentScope.isEmpty() && !leftScopeMatch(parentScope,scope))
3238             {
3239               if (!scope.isEmpty()) fullScope.prepend("::");
3240               fullScope.prepend(parentScope);
3241             }
3242             //printf("fullScope=%s\n",fullScope.data());
3243             rnd = getResolvedNamespace(fullScope);
3244             FileDef *mfd = md->getFileDef();
3245             QCString nsName,rnsName;
3246             if (mnd)  nsName = mnd->name().copy();
3247             if (rnd) rnsName = rnd->name().copy();
3248             //printf("matching arguments for %s%s %s%s\n",
3249             //    md->name().data(),md->argsString(),rname.data(),argListToString(root->argList).data());
3250             LockingPtr<ArgumentList> mdAl = md->argumentList();
3251             LockingPtr<ArgumentList> mdTempl = md->templateArguments();
3252
3253             // in case of template functions, we need to check if the
3254             // functions have the same number of template parameters
3255             bool sameNumTemplateArgs = TRUE;
3256             if (mdTempl!=0 && root->tArgLists)
3257             {
3258               if (mdTempl->count()!=root->tArgLists->getLast()->count())
3259               {
3260                 sameNumTemplateArgs = FALSE;
3261               }
3262             }
3263
3264             bool staticsInDifferentFiles = 
3265                     root->stat && md->isStatic() && root->fileName!=md->getDefFileName();
3266
3267             if (
3268                 matchArguments2(md->getOuterScope(),mfd,mdAl.pointer(),
3269                                 rnd ? rnd : Doxygen::globalScope,rfd,root->argList,
3270                                 FALSE) &&
3271                 sameNumTemplateArgs && 
3272                 !staticsInDifferentFiles
3273                )
3274             {
3275               GroupDef *gd=0;
3276               if (root->groups->first()!=0)
3277               {
3278                 gd = Doxygen::groupSDict->find(root->groups->first()->groupname.data());
3279               }
3280               //printf("match!\n");
3281               //printf("mnd=%p rnd=%p nsName=%s rnsName=%s\n",mnd,rnd,nsName.data(),rnsName.data());
3282               // see if we need to create a new member
3283               found=(mnd && rnd && nsName==rnsName) ||   // members are in the same namespace
3284                     ((mnd==0 && rnd==0 && mfd!=0 &&       // no external reference and
3285                       mfd->absFilePath()==root->fileName // prototype in the same file
3286                      )
3287                     );
3288               // otherwise, allow a duplicate global member with the same argument list
3289               if (!found && gd && gd==md->getGroupDef() && nsName==rnsName)
3290               {
3291                 // member is already in the group, so we don't want to add it again.
3292                 found=TRUE;
3293               }
3294
3295               //printf("combining function with prototype found=%d in namespace %s\n",
3296               //    found,nsName.data());
3297
3298               if (found)
3299               {
3300                 // merge argument lists
3301                 mergeArguments(mdAl.pointer(),root->argList,!root->doc.isEmpty());
3302                 // merge documentation
3303                 if (md->documentation().isEmpty() && !root->doc.isEmpty())
3304                 {
3305                   ArgumentList *argList = new ArgumentList;
3306                   stringToArgumentList(root->args,argList);
3307                   if (root->proto)
3308                   {
3309                     //printf("setDeclArgumentList to %p\n",argList);
3310                     md->setDeclArgumentList(argList);
3311                   }
3312                   else
3313                   {
3314                     md->setArgumentList(argList);
3315                   }
3316                 }
3317
3318                 md->setDocumentation(root->doc,root->docFile,root->docLine);
3319                 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
3320                 md->setDocsForDefinition(!root->proto);
3321                 if (md->getStartBodyLine()!=-1 && md->getStartBodyLine()==-1)
3322                 {
3323                   md->setBodySegment(root->bodyLine,root->endBodyLine);
3324                   md->setBodyDef(rfd);
3325                 }
3326
3327                 if (md->briefDescription().isEmpty() && !root->brief.isEmpty())
3328                 {
3329                   md->setArgsString(root->args);
3330                 }
3331                 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
3332
3333                 md->addSectionsToDefinition(root->anchors);
3334
3335                 md->enableCallGraph(md->hasCallGraph() || root->callGraph);
3336                 md->enableCallerGraph(md->hasCallerGraph() || root->callerGraph);
3337
3338                 // merge ingroup specifiers
3339                 if (md->getGroupDef()==0 && root->groups->first()!=0)
3340                 {
3341                   addMemberToGroups(root,md);
3342                 }
3343                 else if (md->getGroupDef()!=0 && root->groups->count()==0)
3344                 {
3345                   //printf("existing member is grouped, new member not\n");
3346                   root->groups->append(new Grouping(md->getGroupDef()->name(), md->getGroupPri()));
3347                 }
3348                 else if (md->getGroupDef()!=0 && root->groups->first()!=0)
3349                 {
3350                   //printf("both members are grouped\n");
3351                 }
3352
3353                 // if md is a declaration and root is the corresponding
3354                 // definition, then turn md into a definition.
3355                 if (md->isPrototype() && !root->proto)
3356                 {
3357                   md->setPrototype(FALSE);
3358                 }
3359               }
3360             }
3361           }
3362         }
3363         if (!found) /* global function is unique with respect to the file */
3364         {
3365           Debug::print(Debug::Functions,0,"  --> new function %s found!\n",rname.data());
3366           //printf("New function type=`%s' name=`%s' args=`%s' bodyLine=%d\n",
3367           //       root->type.data(),rname.data(),root->args.data(),root->bodyLine);
3368
3369           // new global function
3370           ArgumentList *tArgList = root->tArgLists ? root->tArgLists->last() : 0;
3371           QCString name=removeRedundantWhiteSpace(rname);
3372           md=new MemberDef(
3373               root->fileName,root->startLine,
3374               root->type,name,root->args,root->exception,
3375               root->protection,root->virt,root->stat,Member,
3376               MemberDef::Function,tArgList,root->argList);
3377
3378           md->setTagInfo(rootNav->tagInfo());
3379           md->setLanguage(root->lang);
3380           //md->setDefFile(root->fileName);
3381           //md->setDefLine(root->startLine);
3382           md->setDocumentation(root->doc,root->docFile,root->docLine);
3383           md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
3384           md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
3385           md->setPrototype(root->proto);
3386           md->setDocsForDefinition(!root->proto);
3387           md->setTypeConstraints(root->typeConstr);
3388           //md->setBody(root->body);
3389           md->setBodySegment(root->bodyLine,root->endBodyLine);
3390           FileDef *fd=rootNav->fileDef();
3391           md->setBodyDef(fd);
3392           md->addSectionsToDefinition(root->anchors);
3393           md->setMemberSpecifiers(root->spec);
3394           md->setMemberGroupId(root->mGrpId);
3395
3396           // see if the function is inside a namespace that was not part of
3397           // the name already (in that case nd should be non-zero already)
3398           if (nd==0 && rootNav->parent()->section() == Entry::NAMESPACE_SEC )
3399           {
3400             //QCString nscope=removeAnonymousScopes(rootNav->parent()->name());
3401             QCString nscope=rootNav->parent()->name();
3402             if (!nscope.isEmpty())
3403             {
3404               nd = getResolvedNamespace(nscope);
3405             }
3406           }
3407
3408           if (!scope.isEmpty())
3409           {
3410             QCString sep = getLanguageSpecificSeparator(root->lang);
3411             if (sep!="::")
3412             {
3413               scope = substitute(scope,"::",sep);
3414             }
3415             scope+=sep;
3416           }
3417
3418           QCString def;
3419           if (!root->type.isEmpty())
3420           {
3421             if (root->argList)
3422             {
3423               def=root->type+" "+scope+name;
3424             }
3425             else
3426             {
3427               def=root->type+" "+scope+name+root->args;
3428             }
3429           }
3430           else
3431           {
3432             if (root->argList)
3433             {
3434               def=scope+name.copy();
3435             }
3436             else
3437             {
3438               def=scope+name+root->args;
3439             }
3440           }
3441           Debug::print(Debug::Functions,0,
3442                      "  Global Function:\n"
3443                      "    `%s' `%s'::`%s' `%s' proto=%d\n"
3444                      "    def=`%s'\n",
3445                      root->type.data(),
3446                      rootNav->parent()->name().data(),
3447                      rname.data(),
3448                      root->args.data(),
3449                      root->proto,
3450                      def.data()
3451                     );
3452           md->setDefinition(def);
3453           md->enableCallGraph(root->callGraph);
3454           md->enableCallerGraph(root->callerGraph);
3455           //if (root->mGrpId!=-1) 
3456           //{
3457           //  md->setMemberGroup(memberGroupDict[root->mGrpId]);
3458           //}
3459
3460           md->setRefItems(root->sli);
3461           if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@')
3462           {
3463             // add member to namespace
3464             md->setNamespace(nd);
3465             nd->insertMember(md); 
3466           }
3467           if (fd)
3468           {
3469             // add member to the file (we do this even if we have already
3470             // inserted it into the namespace)
3471             md->setFileDef(fd); 
3472             fd->insertMember(md);
3473           }
3474
3475           // add member to the list of file members
3476           //printf("Adding member=%s\n",md->name().data());
3477           MemberName *mn;
3478           if ((mn=Doxygen::functionNameSDict->find(name)))
3479           {
3480             mn->append(md);
3481           }
3482           else 
3483           {
3484             mn = new MemberName(name);
3485             mn->append(md);
3486             Doxygen::functionNameSDict->append(name,mn);
3487           }
3488           addMemberToGroups(root,md);
3489           if (root->relatesType == Simple) // if this is a relatesalso command,
3490                                            // allow find Member to pick it up
3491           {
3492             rootNav->changeSection(Entry::EMPTY_SEC); // Otherwise we have finished 
3493                                                       // with this entry.
3494
3495           }
3496         }
3497         else
3498         {
3499           FileDef *fd=rootNav->fileDef();
3500           if (fd)
3501           {
3502             // add member to the file (we do this even if we have already
3503             // inserted it into the namespace)
3504             fd->insertMember(md);
3505           }
3506         }
3507
3508         //printf("unrelated function %d `%s' `%s' `%s'\n",
3509         //    root->parent->section,root->type.data(),rname.data(),root->args.data());
3510       }
3511       else
3512       {
3513           Debug::print(Debug::Functions,0,"  --> %s not processed!\n",rname.data());
3514       }
3515     }
3516     else if (rname.isEmpty())
3517     {
3518         warn(root->fileName,root->startLine,
3519              "warning: Illegal member name found."
3520             );
3521     }
3522
3523     rootNav->releaseEntry();
3524   }
3525   RECURSE_ENTRYTREE(buildFunctionList,rootNav);
3526 }
3527
3528 //----------------------------------------------------------------------
3529
3530 static void findFriends()
3531 {
3532   //printf("findFriends()\n");
3533   MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict);
3534   MemberName *fn;
3535   for (;(fn=fnli.current());++fnli) // for each global function name
3536   {
3537     //printf("Function name=`%s'\n",fn->memberName());
3538     MemberName *mn;
3539     if ((mn=Doxygen::memberNameSDict->find(fn->memberName())))
3540     { // there are members with the same name
3541       //printf("Function name is also a member name\n");
3542       MemberNameIterator fni(*fn);
3543       MemberDef *fmd;
3544       for (;(fmd=fni.current());++fni) // for each function with that name
3545       {
3546         MemberNameIterator mni(*mn);
3547         MemberDef *mmd;
3548         for (;(mmd=mni.current());++mni) // for each member with that name
3549         {
3550           //printf("Checking for matching arguments 
3551           //        mmd->isRelated()=%d mmd->isFriend()=%d mmd->isFunction()=%d\n",
3552           //    mmd->isRelated(),mmd->isFriend(),mmd->isFunction());
3553           LockingPtr<ArgumentList> mmdAl = mmd->argumentList();
3554           LockingPtr<ArgumentList> fmdAl = fmd->argumentList();
3555           if ((mmd->isFriend() || (mmd->isRelated() && mmd->isFunction())) &&
3556               matchArguments2(mmd->getOuterScope(), mmd->getFileDef(), mmdAl.pointer(),
3557                               fmd->getOuterScope(), fmd->getFileDef(), fmdAl.pointer(),
3558                               TRUE
3559                              )
3560                              
3561              ) // if the member is related and the arguments match then the 
3562                // function is actually a friend.
3563           {
3564             mergeArguments(mmdAl.pointer(),fmdAl.pointer());
3565             if (!fmd->documentation().isEmpty())
3566             {
3567               mmd->setDocumentation(fmd->documentation(),fmd->docFile(),fmd->docLine());
3568             }
3569             else if (!mmd->documentation().isEmpty())
3570             {
3571               fmd->setDocumentation(mmd->documentation(),mmd->docFile(),mmd->docLine());
3572             }
3573             if (mmd->briefDescription().isEmpty() && !fmd->briefDescription().isEmpty())
3574             {
3575               mmd->setBriefDescription(fmd->briefDescription(),fmd->briefFile(),fmd->briefLine());
3576             }
3577             else if (!mmd->briefDescription().isEmpty() && !fmd->briefDescription().isEmpty())
3578             {
3579               fmd->setBriefDescription(mmd->briefDescription(),mmd->briefFile(),mmd->briefLine());
3580             }
3581             if (!fmd->inbodyDocumentation().isEmpty())
3582             {
3583               mmd->setInbodyDocumentation(fmd->inbodyDocumentation(),fmd->inbodyFile(),fmd->inbodyLine());
3584             }
3585             else if (!mmd->inbodyDocumentation().isEmpty())
3586             {
3587               fmd->setInbodyDocumentation(mmd->inbodyDocumentation(),mmd->inbodyFile(),mmd->inbodyLine());
3588             }
3589             //printf("body mmd %d fmd %d\n",mmd->getStartBodyLine(),fmd->getStartBodyLine());
3590             if (mmd->getStartBodyLine()==-1 && fmd->getStartBodyLine()!=-1)
3591             {
3592               mmd->setBodySegment(fmd->getStartBodyLine(),fmd->getEndBodyLine());
3593               mmd->setBodyDef(fmd->getBodyDef());
3594               //mmd->setBodyMember(fmd);
3595             }
3596             else if (mmd->getStartBodyLine()!=-1 && fmd->getStartBodyLine()==-1)
3597             {
3598               fmd->setBodySegment(mmd->getStartBodyLine(),mmd->getEndBodyLine());
3599               fmd->setBodyDef(mmd->getBodyDef());
3600               //fmd->setBodyMember(mmd);
3601             }
3602             mmd->setDocsForDefinition(fmd->isDocsForDefinition());
3603
3604             mmd->enableCallGraph(mmd->hasCallGraph() || fmd->hasCallGraph());
3605             mmd->enableCallerGraph(mmd->hasCallerGraph() || fmd->hasCallerGraph());
3606             fmd->enableCallGraph(mmd->hasCallGraph() || fmd->hasCallGraph());
3607             fmd->enableCallerGraph(mmd->hasCallerGraph() || fmd->hasCallerGraph());
3608           }
3609         }
3610       }
3611     }
3612   }
3613 }
3614
3615 //----------------------------------------------------------------------
3616
3617 static void transferFunctionDocumentation()
3618 {
3619   //printf("---- transferFunctionDocumentation()\n");
3620
3621   // find matching function declaration and definitions.
3622   MemberNameSDict::Iterator mnli(*Doxygen::functionNameSDict);
3623   MemberName *mn;
3624   for (;(mn=mnli.current());++mnli)
3625   {
3626     //printf("memberName=%s count=%d\n",mn->memberName(),mn->count());
3627     MemberDef *mdef=0,*mdec=0;
3628     MemberNameIterator mni1(*mn);
3629     /* find a matching function declaration and definition for this function */
3630     for (;(mdec=mni1.current());++mni1)
3631     {
3632       if (mdec->isPrototype() ||
3633           (mdec->isVariable() && mdec->isExternal()) 
3634          )
3635       {
3636         MemberNameIterator mni2(*mn);
3637         for (;(mdef=mni2.current());++mni2)
3638         {
3639           combineDeclarationAndDefinition(mdec,mdef);
3640         }
3641       }
3642     }
3643   }
3644 }
3645
3646 //----------------------------------------------------------------------
3647
3648 static void transferFunctionReferences()
3649 {
3650   MemberNameSDict::Iterator mnli(*Doxygen::functionNameSDict);
3651   MemberName *mn;
3652   for (;(mn=mnli.current());++mnli)
3653   {
3654     MemberDef *md,*mdef=0,*mdec=0;
3655     MemberNameIterator mni(*mn);
3656     /* find a matching function declaration and definition for this function */
3657     for (;(md=mni.current());++mni)
3658     {
3659       if (md->isPrototype()) 
3660         mdec=md;
3661       else if (md->isVariable() && md->isExternal()) 
3662         mdec=md;
3663       
3664       if (md->isFunction() && !md->isStatic() && !md->isPrototype()) 
3665         mdef=md;
3666       else if (md->isVariable() && !md->isExternal() && !md->isStatic())
3667         mdef=md;
3668     }
3669     if (mdef && mdec)
3670     {
3671       LockingPtr<ArgumentList> mdefAl = mdef->argumentList();
3672       LockingPtr<ArgumentList> mdecAl = mdec->argumentList();
3673       if (
3674           matchArguments2(mdef->getOuterScope(),mdef->getFileDef(),mdefAl.pointer(),
3675                           mdec->getOuterScope(),mdec->getFileDef(),mdecAl.pointer(),
3676                           TRUE
3677             )
3678          ) /* match found */
3679       {
3680         LockingPtr<MemberSDict> defDict = mdef->getReferencesMembers();
3681         LockingPtr<MemberSDict> decDict = mdec->getReferencesMembers();
3682         if (defDict!=0)
3683         {
3684           MemberSDict::Iterator msdi(*defDict);
3685           MemberDef *rmd;
3686           for (msdi.toFirst();(rmd=msdi.current());++msdi)
3687           {
3688             if (decDict==0 || decDict->find(rmd->name())==0)
3689             {
3690               mdec->addSourceReferences(rmd);
3691             }
3692           }
3693         }
3694         if (decDict!=0)
3695         {
3696           MemberSDict::Iterator msdi(*decDict);
3697           MemberDef *rmd;
3698           for (msdi.toFirst();(rmd=msdi.current());++msdi)
3699           {
3700             if (defDict==0 || defDict->find(rmd->name())==0)
3701             {
3702               mdef->addSourceReferences(rmd);
3703             }
3704           }
3705         }
3706
3707         defDict = mdef->getReferencedByMembers();
3708         decDict = mdec->getReferencedByMembers();
3709         if (defDict!=0)
3710         {
3711           MemberSDict::Iterator msdi(*defDict);
3712           MemberDef *rmd;
3713           for (msdi.toFirst();(rmd=msdi.current());++msdi)
3714           {
3715             if (decDict==0 || decDict->find(rmd->name())==0)
3716             {
3717               mdec->addSourceReferencedBy(rmd);
3718             }
3719           }
3720         }
3721         if (decDict!=0)
3722         {
3723           MemberSDict::Iterator msdi(*decDict);
3724           MemberDef *rmd;
3725           for (msdi.toFirst();(rmd=msdi.current());++msdi)
3726           {
3727             if (defDict==0 || defDict->find(rmd->name())==0)
3728             {
3729               mdef->addSourceReferencedBy(rmd);
3730             }
3731           }
3732         }
3733       }
3734     }
3735   }
3736 }
3737
3738 //----------------------------------------------------------------------
3739
3740 static void transferRelatedFunctionDocumentation()
3741 {
3742   // find match between function declaration and definition for 
3743   // related functions
3744   MemberNameSDict::Iterator mnli(*Doxygen::functionNameSDict);
3745   MemberName *mn;
3746   for (mnli.toFirst();(mn=mnli.current());++mnli)
3747   {
3748     MemberDef *md;
3749     MemberNameIterator mni(*mn);
3750     /* find a matching function declaration and definition for this function */
3751     for (mni.toFirst();(md=mni.current());++mni) // for each global function
3752     {
3753       //printf("  Function `%s'\n",md->name().data());
3754       MemberName *rmn;
3755       if ((rmn=Doxygen::memberNameSDict->find(md->name()))) // check if there is a member with the same name
3756       {
3757         //printf("  Member name found\n");
3758         MemberDef *rmd;
3759         MemberNameIterator rmni(*rmn);
3760         for (rmni.toFirst();(rmd=rmni.current());++rmni) // for each member with the same name
3761         {
3762           LockingPtr<ArgumentList>  mdAl = md->argumentList();
3763           LockingPtr<ArgumentList> rmdAl = rmd->argumentList();
3764           //printf("  Member found: related=`%d'\n",rmd->isRelated());
3765           if ((rmd->isRelated() || rmd->isForeign()) && // related function
3766               matchArguments2( md->getOuterScope(), md->getFileDef(), mdAl.pointer(),
3767                               rmd->getOuterScope(),rmd->getFileDef(),rmdAl.pointer(),
3768                               TRUE
3769                              )
3770              )
3771           {
3772             //printf("  Found related member `%s'\n",md->name().data());
3773             if (rmd->relatedAlso())
3774               md->setRelatedAlso(rmd->relatedAlso());
3775             else if (rmd->isForeign())
3776               md->makeForeign();
3777             else
3778               md->makeRelated();
3779           } 
3780         }
3781       } 
3782     }
3783   }
3784 }
3785
3786 //----------------------------------------------------------------------
3787
3788 /*! make a dictionary of all template arguments of class cd
3789  * that are part of the base class name. 
3790  * Example: A template class A with template arguments <R,S,T> 
3791  * that inherits from B<T,T,S> will have T and S in the dictionary.
3792  */
3793 static QDict<int> *getTemplateArgumentsInName(ArgumentList *templateArguments,const QCString &name)
3794 {
3795   QDict<int> *templateNames = new QDict<int>(17);
3796   templateNames->setAutoDelete(TRUE);
3797   static QRegExp re("[a-z_A-Z][a-z_A-Z0-9:]*");
3798   if (templateArguments)
3799   {
3800     ArgumentListIterator ali(*templateArguments);
3801     Argument *arg;
3802     int count=0;
3803     for (ali.toFirst();(arg=ali.current());++ali,count++)
3804     {
3805       int i,p=0,l;
3806       while ((i=re.match(name,p,&l))!=-1)
3807       {
3808         QCString n = name.mid(i,l);
3809         if (n==arg->name)
3810         {
3811           if (templateNames->find(n)==0)
3812           {
3813             templateNames->insert(n,new int(count));
3814           }
3815         }
3816         p=i+l;
3817       }
3818     }
3819   }
3820   return templateNames;
3821 }
3822
3823 /*! Searches a class from within \a context and \a cd and returns its
3824  *  definition if found (otherwise 0 is returned).
3825  */
3826 static ClassDef *findClassWithinClassContext(Definition *context,ClassDef *cd,const QCString &name)
3827 {
3828   FileDef *fd=cd->getFileDef();
3829   ClassDef *result=0;
3830   if (context && cd!=context)
3831   {
3832     result = getResolvedClass(context,0,name,0,0,TRUE,TRUE);
3833   }
3834   if (result==0)
3835   {
3836     result = getResolvedClass(cd,fd,name,0,0,TRUE,TRUE);
3837   }
3838   if (result==0) // try direct class, needed for namespaced classes imported via tag files (see bug624095)
3839   {
3840     result = getClass(name);
3841   }
3842   if (result==0 && cd && cd->getLanguage()==SrcLangExt_CSharp && name.find('<')!=-1)
3843   {
3844     result = Doxygen::genericsDict.find(name);
3845   }
3846   //printf("** Trying to find %s within context %s class %s result=%s lookup=%p\n",
3847   //       name.data(),
3848   //       context ? context->name().data() : "<none>",
3849   //       cd      ? cd->name().data()      : "<none>",
3850   //       result  ? result->name().data()  : "<none>",
3851   //       Doxygen::classSDict->find(name)
3852   //      );
3853   return result;
3854 }
3855
3856 enum FindBaseClassRelation_Mode 
3857
3858   TemplateInstances, 
3859   DocumentedOnly, 
3860   Undocumented 
3861 };
3862
3863 static bool findClassRelation(
3864                            EntryNav *rootNav,
3865                            Definition *context,
3866                            ClassDef *cd,
3867                            BaseInfo *bi,
3868                            QDict<int> *templateNames,
3869                            /*bool insertUndocumented*/
3870                            FindBaseClassRelation_Mode mode,
3871                            bool isArtificial
3872                           );
3873
3874
3875 static void findUsedClassesForClass(EntryNav *rootNav,
3876                            Definition *context,
3877                            ClassDef *masterCd,
3878                            ClassDef *instanceCd,
3879                            bool isArtificial,
3880                            ArgumentList *actualArgs=0,
3881                            QDict<int> *templateNames=0
3882                            )
3883 {
3884   masterCd->visited=TRUE;
3885   ArgumentList *formalArgs = masterCd->templateArguments();
3886   if (masterCd->memberNameInfoSDict())
3887   {
3888     MemberNameInfoSDict::Iterator mnili(*masterCd->memberNameInfoSDict());
3889     MemberNameInfo *mni;
3890     for (;(mni=mnili.current());++mnili)
3891     {
3892       MemberNameInfoIterator mnii(*mni);
3893       MemberInfo *mi;
3894       for (mnii.toFirst();(mi=mnii.current());++mnii)
3895       {
3896         MemberDef *md=mi->memberDef;
3897         if (md->isVariable() || md->isObjCProperty()) // for each member variable in this class
3898         {
3899           //printf("    Found variable %s in class %s\n",md->name().data(),masterCd->name().data());
3900           QCString type=removeRedundantWhiteSpace(md->typeString());
3901           QCString typedefValue = resolveTypeDef(masterCd,type);
3902           if (!typedefValue.isEmpty())
3903           {
3904             type = typedefValue;
3905           }
3906           int pos=0;
3907           QCString usedClassName;
3908           QCString templSpec;
3909           bool found=FALSE;
3910           // the type can contain template variables, replace them if present
3911           if (actualArgs)
3912           {
3913             type = substituteTemplateArgumentsInString(type,formalArgs,actualArgs);
3914           }
3915
3916           //printf("      template substitution gives=%s\n",type.data());
3917           while (!found && extractClassNameFromType(type,pos,usedClassName,templSpec,rootNav->lang())!=-1)
3918           {
3919             // find the type (if any) that matches usedClassName
3920             ClassDef *typeCd = getResolvedClass(masterCd,
3921                 masterCd->getFileDef(),
3922                 usedClassName,
3923                 0,0,
3924                 FALSE,TRUE
3925                 );
3926             //printf("====>  usedClassName=%s -> typeCd=%s\n",
3927             //     usedClassName.data(),typeCd?typeCd->name().data():"<none>");
3928             if (typeCd)
3929             {
3930               usedClassName = typeCd->name();
3931             }
3932
3933             int sp=usedClassName.find('<');
3934             if (sp==-1) sp=0;
3935             int si=usedClassName.findRev("::",sp);
3936             if (si!=-1)
3937             {
3938               // replace any namespace aliases
3939               replaceNamespaceAliases(usedClassName,si);
3940             }
3941             // add any template arguments to the class
3942             QCString usedName = removeRedundantWhiteSpace(usedClassName+templSpec);
3943             //printf("    usedName=%s\n",usedName.data());
3944
3945             bool delTempNames=FALSE;
3946             if (templateNames==0)
3947             {
3948               templateNames = getTemplateArgumentsInName(formalArgs,usedName);
3949               delTempNames=TRUE;
3950             }
3951             BaseInfo bi(usedName,Public,Normal);
3952             findClassRelation(rootNav,context,instanceCd,&bi,templateNames,TemplateInstances,isArtificial);
3953
3954             if (masterCd->templateArguments())
3955             {
3956               ArgumentListIterator ali(*masterCd->templateArguments());
3957               Argument *arg;
3958               int count=0;
3959               for (ali.toFirst();(arg=ali.current());++ali,++count)
3960               {
3961                 if (arg->name==usedName) // type is a template argument
3962                 {
3963                   found=TRUE;
3964                   Debug::print(Debug::Classes,0,"    New used class `%s'\n", usedName.data());
3965
3966                   ClassDef *usedCd = Doxygen::hiddenClasses->find(usedName);
3967                   if (usedCd==0)
3968                   {
3969                     usedCd = new ClassDef(
3970                         masterCd->getDefFileName(),masterCd->getDefLine(),
3971                         usedName,ClassDef::Class);
3972                     //printf("making %s a template argument!!!\n",usedCd->name().data());
3973                     usedCd->makeTemplateArgument();
3974                     usedCd->setUsedOnly(TRUE);
3975                     usedCd->setLanguage(masterCd->getLanguage());
3976                     Doxygen::hiddenClasses->append(usedName,usedCd);
3977                   }
3978                   if (usedCd)
3979                   {
3980                     if (isArtificial) usedCd->setArtificial(TRUE);
3981                     Debug::print(Debug::Classes,0,"      Adding used class `%s' (1)\n", usedCd->name().data());
3982                     instanceCd->addUsedClass(usedCd,md->name(),md->protection());
3983                     usedCd->addUsedByClass(instanceCd,md->name(),md->protection());
3984                   }
3985                 }
3986               }
3987             }
3988
3989             if (!found)
3990             {
3991               ClassDef *usedCd=findClassWithinClassContext(context,masterCd,usedName);
3992               //printf("Looking for used class %s: result=%s master=%s\n",
3993               //    usedName.data(),usedCd?usedCd->name().data():"<none>",masterCd?masterCd->name().data():"<none>");
3994
3995               if (usedCd) 
3996               {
3997                 found=TRUE;
3998                 Debug::print(Debug::Classes,0,"    Adding used class `%s' (2)\n", usedCd->name().data());
3999                 instanceCd->addUsedClass(usedCd,md->name(),md->protection()); // class exists 
4000                 usedCd->addUsedByClass(instanceCd,md->name(),md->protection());
4001               }
4002             }
4003             if (delTempNames)
4004             {
4005               delete templateNames;
4006               templateNames=0;
4007             }
4008           }
4009           if (!found && !type.isEmpty()) // used class is not documented in any scope
4010           {
4011             ClassDef *usedCd = Doxygen::hiddenClasses->find(type);
4012             if (usedCd==0 && !Config_getBool("HIDE_UNDOC_RELATIONS"))
4013             {
4014               if (type.right(2)=="(*" || type.right(2)=="(^") // type is a function pointer
4015               {
4016                 type+=md->argsString();
4017               }
4018               Debug::print(Debug::Classes,0,"  New undocumented used class `%s'\n", type.data());
4019               usedCd = new ClassDef(
4020                   masterCd->getDefFileName(),masterCd->getDefLine(),
4021                   type,ClassDef::Class);
4022               usedCd->setUsedOnly(TRUE);
4023               usedCd->setLanguage(masterCd->getLanguage());
4024               Doxygen::hiddenClasses->append(type,usedCd);
4025             }
4026             if (usedCd)
4027             {
4028               if (isArtificial) usedCd->setArtificial(TRUE);
4029               Debug::print(Debug::Classes,0,"    Adding used class `%s' (3)\n", usedCd->name().data());
4030               instanceCd->addUsedClass(usedCd,md->name(),md->protection()); 
4031               usedCd->addUsedByClass(instanceCd,md->name(),md->protection());
4032             }
4033           }
4034         }
4035       }
4036     }
4037   }
4038   else
4039   {
4040     //printf("no members for class %s (%p)\n",masterCd->name().data(),masterCd);
4041   }
4042 }
4043
4044 static void findBaseClassesForClass(
4045       EntryNav *rootNav,
4046       Definition *context,
4047       ClassDef *masterCd,
4048       ClassDef *instanceCd,
4049       FindBaseClassRelation_Mode mode,
4050       bool isArtificial,
4051       ArgumentList *actualArgs=0,
4052       QDict<int> *templateNames=0
4053     )
4054 {
4055   Entry *root = rootNav->entry();
4056   //if (masterCd->visited) return;
4057   masterCd->visited=TRUE;
4058   // The base class could ofcouse also be a non-nested class
4059   ArgumentList *formalArgs = masterCd->templateArguments();
4060   QListIterator<BaseInfo> bii(*root->extends);
4061   BaseInfo *bi=0;
4062   for (bii.toFirst();(bi=bii.current());++bii)
4063   {
4064     //printf("masterCd=%s bi->name='%s' #actualArgs=%d\n",
4065     //    masterCd->localName().data(),bi->name.data(),actualArgs?(int)actualArgs->count():-1);
4066     bool delTempNames=FALSE;
4067     if (templateNames==0)
4068     {
4069       templateNames = getTemplateArgumentsInName(formalArgs,bi->name);
4070       delTempNames=TRUE;
4071     }
4072     BaseInfo tbi(bi->name,bi->prot,bi->virt);
4073     if (actualArgs) // substitute the formal template arguments of the base class
4074     {
4075       tbi.name = substituteTemplateArgumentsInString(bi->name,formalArgs,actualArgs);
4076     }
4077     //printf("bi->name=%s tbi.name=%s\n",bi->name.data(),tbi.name.data());
4078
4079     if (mode==DocumentedOnly)
4080     {
4081       // find a documented base class in the correct scope
4082       if (!findClassRelation(rootNav,context,instanceCd,&tbi,templateNames,DocumentedOnly,isArtificial))
4083       {
4084         // 1.8.2: decided to show inheritance relations even if not documented,
4085         //        we do make them artificial, so they do not appear in the index
4086         //if (!Config_getBool("HIDE_UNDOC_RELATIONS")) 
4087         bool b = Config_getBool("HIDE_UNDOC_RELATIONS") ? TRUE : isArtificial;
4088         //{
4089           // no documented base class -> try to find an undocumented one
4090           findClassRelation(rootNav,context,instanceCd,&tbi,templateNames,Undocumented,b);
4091         //}
4092       }
4093     }
4094     else if (mode==TemplateInstances)
4095     {
4096       findClassRelation(rootNav,context,instanceCd,&tbi,templateNames,TemplateInstances,isArtificial);
4097     }
4098     if (delTempNames)
4099     {
4100       delete templateNames;
4101       templateNames=0;
4102     }  
4103   }
4104 }
4105
4106 //----------------------------------------------------------------------
4107
4108 static bool findTemplateInstanceRelation(Entry *root,
4109             Definition *context,
4110             ClassDef *templateClass,const QCString &templSpec,
4111             QDict<int> *templateNames,
4112             bool isArtificial)
4113 {
4114   Debug::print(Debug::Classes,0,"    derived from template %s with parameters %s\n",
4115          templateClass->name().data(),templSpec.data());
4116   //printf("findTemplateInstanceRelation(base=%s templSpec=%s templateNames=",
4117   //    templateClass->name().data(),templSpec.data());
4118   //if (templateNames)
4119   //{
4120   //  QDictIterator<int> qdi(*templateNames);
4121   //  int *tempArgIndex;
4122   //  for (;(tempArgIndex=qdi.current());++qdi)
4123   //  {
4124   //    printf("(%s->%d) ",qdi.currentKey(),*tempArgIndex);
4125   //  }
4126   //}
4127   //printf("\n");
4128   
4129   bool existingClass = (templSpec ==
4130                         tempArgListToString(templateClass->templateArguments())
4131                        );
4132   if (existingClass) return TRUE;
4133
4134   bool freshInstance=FALSE;
4135   ClassDef *instanceClass = templateClass->insertTemplateInstance(
4136                      root->fileName,root->startLine,templSpec,freshInstance);
4137   if (isArtificial) instanceClass->setArtificial(TRUE);
4138   instanceClass->setLanguage(root->lang);
4139
4140   if (freshInstance)
4141   {
4142     Debug::print(Debug::Classes,0,"      found fresh instance '%s'!\n",instanceClass->name().data());
4143     Doxygen::classSDict->append(instanceClass->name(),instanceClass);
4144     instanceClass->setTemplateBaseClassNames(templateNames);
4145
4146     // search for new template instances caused by base classes of 
4147     // instanceClass 
4148     EntryNav *templateRootNav = g_classEntries.find(templateClass->name());
4149     if (templateRootNav)
4150     {
4151       bool unloadNeeded=FALSE;
4152       Entry *templateRoot = templateRootNav->entry();
4153       if (templateRoot==0) // not yet loaded
4154       {
4155         templateRootNav->loadEntry(g_storage);
4156         templateRoot = templateRootNav->entry();
4157         ASSERT(templateRoot!=0); // now it should really be loaded
4158         unloadNeeded=TRUE;
4159       }
4160
4161       Debug::print(Debug::Classes,0,"        template root found %s templSpec=%s!\n",
4162           templateRoot->name.data(),templSpec.data());
4163       ArgumentList *templArgs = new ArgumentList;
4164       stringToArgumentList(templSpec,templArgs);
4165       findBaseClassesForClass(templateRootNav,context,templateClass,instanceClass,
4166           TemplateInstances,isArtificial,templArgs,templateNames);
4167
4168       findUsedClassesForClass(templateRootNav,context,templateClass,instanceClass,
4169           isArtificial,templArgs,templateNames);
4170       delete templArgs;
4171
4172       if (unloadNeeded) // still cleanup to do
4173       {
4174         templateRootNav->releaseEntry();
4175       }
4176     }
4177     else
4178     {
4179       Debug::print(Debug::Classes,0,"        no template root entry found!\n");
4180       // TODO: what happened if we get here?
4181     }
4182
4183     //Debug::print(Debug::Classes,0,"    Template instance %s : \n",instanceClass->name().data());
4184     //ArgumentList *tl = templateClass->templateArguments();
4185   }
4186   else
4187   {
4188     Debug::print(Debug::Classes,0,"      instance already exists!\n");
4189   }
4190   return TRUE;
4191 }
4192
4193 static bool isRecursiveBaseClass(const QCString &scope,const QCString &name)
4194 {
4195   QCString n=name;
4196   int index=n.find('<');
4197   if (index!=-1)
4198   {
4199     n=n.left(index);
4200   }
4201   bool result = rightScopeMatch(scope,n);
4202   return result;
4203 }
4204
4205 /*! Searches for the end of a template in prototype \a s starting from
4206  *  character position \a startPos. If the end was found the position
4207  *  of the closing \> is returned, otherwise -1 is returned.
4208  *
4209  *  Handles exotic cases such as 
4210  *  \code
4211  *    Class<(id<0)>
4212  *    Class<bits<<2>
4213  *    Class<"<">
4214  *    Class<'<'>
4215  *    Class<(")<")>
4216  *  \endcode
4217  */
4218 static int findEndOfTemplate(const QCString &s,int startPos)
4219 {
4220   // locate end of template
4221   int e=startPos;
4222   int brCount=1;
4223   int roundCount=0;
4224   int len = s.length();
4225   bool insideString=FALSE;
4226   bool insideChar=FALSE;
4227   char pc = 0;
4228   while (e<len && brCount!=0)
4229   {
4230     char c=s.at(e);
4231     switch(c)
4232     {
4233       case '<': 
4234         if (!insideString && !insideChar)
4235         {
4236           if (e<len-1 && s.at(e+1)=='<') 
4237             e++; 
4238           else if (roundCount==0)
4239             brCount++;
4240         }
4241         break;
4242       case '>':
4243         if (!insideString && !insideChar)
4244         {
4245           if (e<len-1 && s.at(e+1)=='>') 
4246             e++; 
4247           else if (roundCount==0)
4248             brCount--;
4249         }
4250         break;
4251       case '(':
4252         if (!insideString && !insideChar) 
4253           roundCount++;
4254         break;
4255       case ')':
4256         if (!insideString && !insideChar) 
4257           roundCount--;
4258         break;
4259       case '"':
4260         if (!insideChar)
4261         {
4262           if (insideString && pc!='\\') 
4263             insideString=FALSE;
4264           else
4265             insideString=TRUE;
4266         }
4267         break;
4268       case '\'':
4269         if (!insideString)
4270         {
4271           if (insideChar && pc!='\\')
4272             insideChar=FALSE;
4273           else
4274             insideChar=TRUE;
4275         }
4276         break;
4277     }
4278     pc = c;
4279     e++;
4280   }
4281   return brCount==0 ? e : -1;
4282 }
4283
4284 static bool findClassRelation(
4285                            EntryNav *rootNav,
4286                            Definition *context,
4287                            ClassDef *cd,
4288                            BaseInfo *bi,
4289                            QDict<int> *templateNames,
4290                            FindBaseClassRelation_Mode mode,
4291                            bool isArtificial
4292                           )
4293 {
4294   //printf("findClassRelation(class=%s base=%s templateNames=",
4295   //    cd->name().data(),bi->name.data());
4296   //if (templateNames)
4297   //{
4298   //  QDictIterator<int> qdi(*templateNames);
4299   //  int *tempArgIndex;
4300   //  for (;(tempArgIndex=qdi.current());++qdi)
4301   //  {
4302   //    printf("(%s->%d) ",qdi.currentKey(),*tempArgIndex);
4303   //  }
4304   //}
4305   //printf("\n");
4306
4307   Entry *root = rootNav->entry();
4308
4309   QCString biName=bi->name;
4310   bool explicitGlobalScope=FALSE;
4311   //printf("findClassRelation: biName=`%s'\n",biName.data());
4312   if (biName.left(2)=="::") // explicit global scope
4313   {
4314      biName=biName.right(biName.length()-2);
4315      explicitGlobalScope=TRUE;
4316   }
4317
4318   EntryNav *parentNode=rootNav->parent();
4319   bool lastParent=FALSE;
4320   do // for each parent scope, starting with the largest scope 
4321      // (in case of nested classes)
4322   {
4323     QCString scopeName= parentNode ? parentNode->name().data() : "";
4324     int scopeOffset=explicitGlobalScope ? 0 : scopeName.length();
4325     do // try all parent scope prefixes, starting with the largest scope
4326     {
4327       //printf("scopePrefix=`%s' biName=`%s'\n",
4328       //    scopeName.left(scopeOffset).data(),biName.data());
4329
4330       QCString baseClassName=biName;
4331       if (scopeOffset>0)
4332       {
4333         baseClassName.prepend(scopeName.left(scopeOffset)+"::");
4334       }
4335       //QCString stripped;
4336       //baseClassName=stripTemplateSpecifiersFromScope
4337       //                    (removeRedundantWhiteSpace(baseClassName),TRUE,
4338       //                    &stripped);
4339       MemberDef *baseClassTypeDef=0;
4340       QCString templSpec;
4341       ClassDef *baseClass=getResolvedClass(explicitGlobalScope ? Doxygen::globalScope : context,
4342                                            cd->getFileDef(), 
4343                                            baseClassName,
4344                                            &baseClassTypeDef,
4345                                            &templSpec,
4346                                            mode==Undocumented,
4347                                            TRUE
4348                                           );
4349       //printf("baseClassName=%s baseClass=%p cd=%p explicitGlobalScope=%d\n",
4350       //    baseClassName.data(),baseClass,cd,explicitGlobalScope);
4351       //printf("    scope=`%s' baseClassName=`%s' baseClass=%s templSpec=%s\n",
4352       //                    cd ? cd->name().data():"<none>",
4353       //                    baseClassName.data(),
4354       //                    baseClass?baseClass->name().data():"<none>",
4355       //                    templSpec.data()
4356       //      );
4357       //if (baseClassName.left(root->name.length())!=root->name ||
4358       //    baseClassName.at(root->name.length())!='<'
4359       //   ) // Check for base class with the same name.
4360       //     // If found then look in the outer scope for a match
4361       //     // and prevent recursion.
4362       if (!isRecursiveBaseClass(rootNav->name(),baseClassName) || explicitGlobalScope)
4363       {
4364         Debug::print(
4365             Debug::Classes,0,"    class relation %s inherited/used by %s found (%s and %s) templSpec='%s'\n",
4366             baseClassName.data(),
4367             rootNav->name().data(),
4368             (bi->prot==Private)?"private":((bi->prot==Protected)?"protected":"public"),
4369             (bi->virt==Normal)?"normal":"virtual",
4370             templSpec.data()
4371            );
4372
4373         int i=baseClassName.find('<');
4374         int si=baseClassName.findRev("::",i==-1 ? baseClassName.length() : i);
4375         if (si==-1) si=0;
4376         if (baseClass==0 && i!=-1) 
4377           // base class has template specifiers
4378         {
4379           if (root->lang == SrcLangExt_CSharp)
4380           {
4381             baseClass = Doxygen::genericsDict.find(baseClassName);
4382           }
4383           else
4384           {
4385             // TODO: here we should try to find the correct template specialization
4386             // but for now, we only look for the unspecializated base class.
4387             int e=findEndOfTemplate(baseClassName,i+1);
4388             //printf("baseClass==0 i=%d e=%d\n",i,e);
4389             if (e!=-1) // end of template was found at e
4390             {
4391               templSpec=removeRedundantWhiteSpace(baseClassName.mid(i,e-i));
4392               baseClassName=baseClassName.left(i)+baseClassName.right(baseClassName.length()-e);
4393               baseClass=getResolvedClass(explicitGlobalScope ? Doxygen::globalScope : context,
4394                   cd->getFileDef(),
4395                   baseClassName,
4396                   &baseClassTypeDef,
4397                   0, //&templSpec,
4398                   mode==Undocumented,
4399                   TRUE
4400                   );
4401               //printf("baseClass=%p -> baseClass=%s templSpec=%s\n",
4402               //      baseClass,baseClassName.data(),templSpec.data());
4403             }
4404           }
4405         }
4406         else if (baseClass && !templSpec.isEmpty()) // we have a known class, but also
4407                                                     // know it is a template, so see if
4408                                                     // we can also link to the explicit
4409                                                     // instance (for instance if a class
4410                                                     // derived from a template argument)
4411         {
4412           //printf("baseClass=%p templSpec=%s\n",baseClass,templSpec.data());
4413           ClassDef *templClass=getClass(baseClass->name()+templSpec);
4414           if (templClass)
4415           {
4416             // use the template instance instead of the template base.
4417             baseClass = templClass;
4418             templSpec.resize(0);
4419           }
4420         }
4421
4422         //printf("cd=%p baseClass=%p\n",cd,baseClass);
4423         bool found=baseClass!=0 && (baseClass!=cd || mode==TemplateInstances);
4424         //printf("1. found=%d\n",found);
4425         if (!found && si!=-1)
4426         {
4427           QCString tmpTemplSpec;
4428           // replace any namespace aliases
4429           replaceNamespaceAliases(baseClassName,si);
4430           baseClass=getResolvedClass(explicitGlobalScope ? Doxygen::globalScope : context,
4431                                      cd->getFileDef(),
4432                                      baseClassName,
4433                                      &baseClassTypeDef,
4434                                      &tmpTemplSpec,
4435                                      mode==Undocumented,
4436                                      TRUE
4437                                     );
4438           found=baseClass!=0 && baseClass!=cd;
4439           if (found) templSpec = tmpTemplSpec;
4440         }
4441         //printf("2. found=%d\n",found);
4442         
4443         //printf("root->name=%s biName=%s baseClassName=%s\n",
4444         //        root->name.data(),biName.data(),baseClassName.data());
4445         //if (cd->isCSharp() && i!=-1) // C# generic -> add internal -g postfix
4446         //{
4447         //  baseClassName+="-g";
4448         //}
4449
4450         if (!found)
4451         {
4452           baseClass=findClassWithinClassContext(context,cd,baseClassName);
4453           //printf("findClassWithinClassContext(%s,%s)=%p\n",
4454           //    cd->name().data(),baseClassName.data(),baseClass);
4455           found = baseClass!=0 && baseClass!=cd;
4456
4457         }
4458         if (!found)
4459         {
4460           // for PHP the "use A\B as C" construct map class C to A::B, so we lookup
4461           // the class name also in the alias mapping.
4462           QCString *aliasName = Doxygen::namespaceAliasDict[baseClassName];
4463           if (aliasName) // see if it is indeed a class.
4464           {
4465             baseClass=getClass(*aliasName);
4466             found = baseClass!=0 && baseClass!=cd;
4467           }
4468         }
4469         bool isATemplateArgument = templateNames!=0 && templateNames->find(biName)!=0;
4470         // make templSpec canonical
4471         // warning: the following line doesn't work for Mixin classes (see bug 560623)
4472         // templSpec = getCanonicalTemplateSpec(cd, cd->getFileDef(), templSpec);
4473
4474         //printf("3. found=%d\n",found);
4475         if (found)
4476         {
4477           Debug::print(Debug::Classes,0,"    Documented base class `%s' templSpec=%s\n",biName.data(),templSpec.isEmpty()?"":templSpec.data());
4478           // add base class to this class
4479
4480           // if templSpec is not empty then we should "instantiate"
4481           // the template baseClass. A new ClassDef should be created
4482           // to represent the instance. To be able to add the (instantiated)
4483           // members and documentation of a template class 
4484           // (inserted in that template class at a later stage), 
4485           // the template should know about its instances. 
4486           // the instantiation process, should be done in a recursive way, 
4487           // since instantiating a template may introduce new inheritance 
4488           // relations.
4489           if (!templSpec.isEmpty() && mode==TemplateInstances)
4490           {
4491             // if baseClass is actually a typedef then we should not
4492             // instantiate it, since typedefs are in a different namespace
4493             // see bug531637 for an example where this would otherwise hang
4494             // doxygen
4495             if (baseClassTypeDef==0)
4496             {
4497               //printf("       => findTemplateInstanceRelation: %p\n",baseClassTypeDef);
4498               findTemplateInstanceRelation(root,context,baseClass,templSpec,templateNames,isArtificial);
4499             }
4500           }
4501           else if (mode==DocumentedOnly || mode==Undocumented)
4502           {
4503             //printf("       => insert base class\n");
4504             QCString usedName;
4505             if (baseClassTypeDef || cd->isCSharp()) 
4506             {
4507               usedName=biName;
4508               //printf("***** usedName=%s templSpec=%s\n",usedName.data(),templSpec.data());
4509             }
4510             if (Config_getBool("SIP_SUPPORT")) bi->prot=Public;
4511             cd->insertBaseClass(baseClass,usedName,bi->prot,bi->virt,templSpec);
4512             // add this class as super class to the base class
4513             baseClass->insertSubClass(cd,bi->prot,bi->virt,templSpec);
4514           }
4515           return TRUE;
4516         }
4517         else if (mode==Undocumented && (scopeOffset==0 || isATemplateArgument))
4518         {
4519           Debug::print(Debug::Classes,0,
4520                        "    New undocumented base class `%s' baseClassName=%s templSpec=%s isArtificial=%d\n",
4521                        biName.data(),baseClassName.data(),templSpec.data(),isArtificial
4522                       );
4523           baseClass=0;
4524           if (isATemplateArgument)
4525           {
4526             baseClass=Doxygen::hiddenClasses->find(baseClassName);
4527             if (baseClass==0)
4528             {
4529               baseClass=new ClassDef(root->fileName,root->startLine,
4530                                  baseClassName,ClassDef::Class);
4531               Doxygen::hiddenClasses->append(baseClassName,baseClass);
4532               if (isArtificial) baseClass->setArtificial(TRUE);
4533               baseClass->setLanguage(root->lang);
4534             }
4535           }
4536           else
4537           {
4538             baseClass=Doxygen::classSDict->find(baseClassName);
4539             //printf("*** classDDict->find(%s)=%p biName=%s templSpec=%s\n",
4540             //    baseClassName.data(),baseClass,biName.data(),templSpec.data());
4541             if (baseClass==0)
4542             {
4543               baseClass=new ClassDef(root->fileName,root->startLine,
4544                   baseClassName,ClassDef::Class);
4545               Doxygen::classSDict->append(baseClassName,baseClass);
4546               if (isArtificial) baseClass->setArtificial(TRUE);
4547               baseClass->setLanguage(root->lang);
4548             }
4549           }
4550           if (biName.right(2)=="-p")
4551           {
4552             biName="<"+biName.left(biName.length()-2)+">";
4553           }
4554           // add base class to this class
4555           cd->insertBaseClass(baseClass,biName,bi->prot,bi->virt,templSpec);
4556           // add this class as super class to the base class
4557           baseClass->insertSubClass(cd,bi->prot,bi->virt,templSpec);
4558           // the undocumented base was found in this file
4559           baseClass->insertUsedFile(root->fileName);
4560           baseClass->setOuterScope(Doxygen::globalScope);
4561           if (baseClassName.right(2)=="-p")
4562           {
4563             baseClass->setCompoundType(ClassDef::Protocol);
4564           }
4565           return TRUE;
4566         }
4567         else
4568         {
4569           Debug::print(Debug::Classes,0,"    Base class `%s' not found\n",biName.data());
4570         }
4571       }
4572       else
4573       {
4574         if (mode!=TemplateInstances)
4575         {
4576           warn(root->fileName,root->startLine,
4577               "Detected potential recursive class relation "
4578               "between class %s and base class %s!\n",
4579               root->name.data(),baseClassName.data()
4580               );
4581         }
4582         // for mode==TemplateInstance this case is quite common and
4583         // indicates a relation between a template class and a template 
4584         // instance with the same name.
4585       }
4586       if (scopeOffset==0)
4587       {
4588         scopeOffset=-1;
4589       }
4590       else if ((scopeOffset=scopeName.findRev("::",scopeOffset-1))==-1)
4591       {
4592         scopeOffset=0;
4593       }
4594       //printf("new scopeOffset=`%d'",scopeOffset);
4595     } while (scopeOffset>=0);
4596
4597     if (parentNode==0)
4598     {
4599       lastParent=TRUE;
4600     }
4601     else
4602     {
4603       parentNode=parentNode->parent();
4604     }
4605   } while (lastParent);
4606
4607   return FALSE;
4608 }
4609
4610 //----------------------------------------------------------------------
4611 // Computes the base and super classes for each class in the tree
4612
4613 static bool isClassSection(EntryNav *rootNav)
4614 {
4615   if ( !rootNav->name().isEmpty() )
4616   {
4617     if (rootNav->section() & Entry::COMPOUND_MASK)
4618          // is it a compound (class, struct, union, interface ...)
4619     {
4620       return TRUE;
4621     }
4622     else if (rootNav->section() & Entry::COMPOUNDDOC_MASK) 
4623          // is it a documentation block with inheritance info.
4624     {
4625       rootNav->loadEntry(g_storage);
4626       Entry *root = rootNav->entry();
4627       bool extends = root->extends->count()>0;
4628       rootNav->releaseEntry(); 
4629       if (extends) return TRUE;
4630     }
4631   }
4632   return FALSE;
4633 }
4634
4635
4636 /*! Builds a dictionary of all entry nodes in the tree starting with \a root
4637  */
4638 static void findClassEntries(EntryNav *rootNav)
4639 {
4640   if (isClassSection(rootNav))
4641   {
4642     g_classEntries.insert(rootNav->name(),rootNav);
4643   }
4644   RECURSE_ENTRYTREE(findClassEntries,rootNav);
4645 }
4646
4647 /*! Using the dictionary build by findClassEntries(), this 
4648  *  function will look for additional template specialization that
4649  *  exists as inheritance relations only. These instances will be
4650  *  added to the template they are derived from.
4651  */
4652 static void findInheritedTemplateInstances()
4653 {
4654   ClassSDict::Iterator cli(*Doxygen::classSDict);
4655   for (cli.toFirst();cli.current();++cli) cli.current()->visited=FALSE;
4656   QDictIterator<EntryNav> edi(g_classEntries);
4657   EntryNav *rootNav;
4658   for (;(rootNav=edi.current());++edi)
4659   {
4660     ClassDef *cd;
4661     // strip any anonymous scopes first 
4662     QCString bName=stripAnonymousNamespaceScope(rootNav->name());
4663     bName=stripTemplateSpecifiersFromScope(bName);
4664     Debug::print(Debug::Classes,0,"  Inheritance: Class %s : \n",bName.data());
4665     if ((cd=getClass(bName)))
4666     {
4667       rootNav->loadEntry(g_storage);
4668       //printf("Class %s %d\n",cd->name().data(),root->extends->count());
4669       findBaseClassesForClass(rootNav,cd,cd,cd,TemplateInstances,FALSE);
4670       rootNav->releaseEntry();
4671     }
4672   }
4673 }
4674
4675 static void findUsedTemplateInstances()
4676 {
4677   ClassSDict::Iterator cli(*Doxygen::classSDict);
4678   for (cli.toFirst();cli.current();++cli) cli.current()->visited=FALSE;
4679   QDictIterator<EntryNav> edi(g_classEntries);
4680   EntryNav *rootNav;
4681   for (;(rootNav=edi.current());++edi)
4682   {
4683     ClassDef *cd;
4684     // strip any anonymous scopes first 
4685     QCString bName=stripAnonymousNamespaceScope(rootNav->name());
4686     bName=stripTemplateSpecifiersFromScope(bName);
4687     Debug::print(Debug::Classes,0,"  Usage: Class %s : \n",bName.data());
4688     if ((cd=getClass(bName)))
4689     {
4690       rootNav->loadEntry(g_storage);
4691       findUsedClassesForClass(rootNav,cd,cd,cd,TRUE);
4692       rootNav->releaseEntry();
4693     }
4694   }
4695 }
4696
4697 static void computeClassRelations()
4698 {
4699   ClassSDict::Iterator cli(*Doxygen::classSDict);
4700   for (cli.toFirst();cli.current();++cli) cli.current()->visited=FALSE;
4701   QDictIterator<EntryNav> edi(g_classEntries);
4702   EntryNav *rootNav;
4703   for (;(rootNav=edi.current());++edi)
4704   {
4705     ClassDef *cd;
4706
4707     rootNav->loadEntry(g_storage);
4708     Entry *root = rootNav->entry();
4709
4710     // strip any anonymous scopes first 
4711     QCString bName=stripAnonymousNamespaceScope(rootNav->name());
4712     bName=stripTemplateSpecifiersFromScope(bName);
4713     Debug::print(Debug::Classes,0,"  Relations: Class %s : \n",bName.data());
4714     if ((cd=getClass(bName)))
4715     {
4716       findBaseClassesForClass(rootNav,cd,cd,cd,DocumentedOnly,FALSE);
4717     }
4718     int numMembers = cd && cd->memberNameInfoSDict() ? cd->memberNameInfoSDict()->count() : 0;
4719     if ((cd==0 || (!cd->hasDocumentation() && !cd->isReference())) && numMembers>0 &&
4720         bName.right(2)!="::")
4721     {
4722       if (!root->name.isEmpty() && root->name.find('@')==-1 && // normal name
4723           (guessSection(root->fileName)==Entry::HEADER_SEC || 
4724            Config_getBool("EXTRACT_LOCAL_CLASSES")) && // not defined in source file
4725            protectionLevelVisible(root->protection) && // hidden by protection
4726            !Config_getBool("HIDE_UNDOC_CLASSES") // undocumented class are visible
4727          )
4728         warn_undoc(
4729                    root->fileName,root->startLine,
4730                    "warning: Compound %s is not documented.",
4731                    root->name.data()
4732              );
4733     }
4734
4735     rootNav->releaseEntry();
4736   }
4737 }
4738
4739 static void computeTemplateClassRelations()
4740 {
4741   QDictIterator<EntryNav> edi(g_classEntries);
4742   EntryNav *rootNav;
4743   for (;(rootNav=edi.current());++edi)
4744   {
4745     rootNav->loadEntry(g_storage);
4746     Entry *root = rootNav->entry();
4747
4748     QCString bName=stripAnonymousNamespaceScope(root->name);
4749     bName=stripTemplateSpecifiersFromScope(bName);
4750     ClassDef *cd=getClass(bName);
4751     // strip any anonymous scopes first 
4752     QDict<ClassDef> *templInstances = 0;
4753     if (cd && (templInstances=cd->getTemplateInstances()))
4754     {
4755       Debug::print(Debug::Classes,0,"  Template class %s : \n",cd->name().data());
4756       QDictIterator<ClassDef> tdi(*templInstances);
4757       ClassDef *tcd;
4758       for (tdi.toFirst();(tcd=tdi.current());++tdi) // for each template instance
4759       {
4760         Debug::print(Debug::Classes,0,"    Template instance %s : \n",tcd->name().data());
4761         QCString templSpec = tdi.currentKey();
4762         ArgumentList *templArgs = new ArgumentList;
4763         stringToArgumentList(templSpec,templArgs);
4764         QList<BaseInfo> *baseList=root->extends;
4765         BaseInfo *bi=baseList->first();
4766         while (bi) // for each base class of the template
4767         {
4768           // check if the base class is a template argument
4769           BaseInfo tbi(bi->name,bi->prot,bi->virt);
4770           ArgumentList *tl = cd->templateArguments();
4771           if (tl)
4772           {
4773             QDict<int> *baseClassNames = tcd->getTemplateBaseClassNames();
4774             QDict<int> *templateNames = getTemplateArgumentsInName(tl,bi->name);
4775             // for each template name that we inherit from we need to
4776             // substitute the formal with the actual arguments
4777             QDict<int> *actualTemplateNames = new QDict<int>(17);
4778             actualTemplateNames->setAutoDelete(TRUE);
4779             QDictIterator<int> qdi(*templateNames);
4780             for (qdi.toFirst();qdi.current();++qdi)
4781             {
4782               int templIndex = *qdi.current();
4783               Argument *actArg = 0;
4784               if (templIndex<(int)templArgs->count()) 
4785               {
4786                 actArg=templArgs->at(templIndex);
4787               }
4788               if (actArg!=0 &&
4789                   baseClassNames!=0 &&
4790                   baseClassNames->find(actArg->type)!=0 &&
4791                   actualTemplateNames->find(actArg->type)==0
4792                  )
4793               {
4794                 actualTemplateNames->insert(actArg->type,new int(templIndex));
4795               }
4796             }
4797             delete templateNames;
4798             
4799             tbi.name = substituteTemplateArgumentsInString(bi->name,tl,templArgs);
4800             // find a documented base class in the correct scope
4801             if (!findClassRelation(rootNav,cd,tcd,&tbi,actualTemplateNames,DocumentedOnly,FALSE))
4802             {
4803               // no documented base class -> try to find an undocumented one
4804               findClassRelation(rootNav,cd,tcd,&tbi,actualTemplateNames,Undocumented,FALSE);
4805             }
4806             delete actualTemplateNames;
4807           }
4808           bi=baseList->next();
4809         }
4810         delete templArgs;
4811       } // class has no base classes
4812     }
4813
4814     rootNav->releaseEntry();
4815   }
4816 }
4817
4818 //-----------------------------------------------------------------------
4819 // compute the references (anchors in HTML) for each function in the file
4820
4821 static void computeMemberReferences()
4822 {
4823   ClassSDict::Iterator cli(*Doxygen::classSDict);
4824   ClassDef *cd=0;
4825   for (cli.toFirst();(cd=cli.current());++cli)
4826   {
4827     cd->computeAnchors();
4828   } 
4829   FileName *fn=Doxygen::inputNameList->first();
4830   while (fn)
4831   {
4832     FileDef *fd=fn->first();
4833     while (fd)
4834     {
4835       fd->computeAnchors();
4836       fd=fn->next();
4837     }
4838     fn=Doxygen::inputNameList->next();
4839   }
4840   NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
4841   NamespaceDef *nd=0;
4842   for (nli.toFirst();(nd=nli.current());++nli)
4843   {
4844     nd->computeAnchors();
4845   }
4846   GroupSDict::Iterator gli(*Doxygen::groupSDict);
4847   GroupDef *gd;
4848   for (gli.toFirst();(gd=gli.current());++gli)
4849   {
4850     gd->computeAnchors();
4851   }
4852 }
4853
4854 //----------------------------------------------------------------------
4855
4856 static void addListReferences()
4857 {
4858   MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
4859   MemberName *mn=0;
4860   for (mnli.toFirst();(mn=mnli.current());++mnli)
4861   {
4862     MemberNameIterator mni(*mn);
4863     MemberDef *md=0;
4864     for (mni.toFirst();(md=mni.current());++mni)
4865     {
4866       md->visited=FALSE;
4867     }
4868   }
4869   MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict);
4870   for (fnli.toFirst();(mn=fnli.current());++fnli)
4871   {
4872     MemberNameIterator mni(*mn);
4873     MemberDef *md=0;
4874     for (mni.toFirst();(md=mni.current());++mni)
4875     {
4876       md->visited=FALSE;
4877     }
4878   }
4879
4880   ClassSDict::Iterator cli(*Doxygen::classSDict);
4881   ClassDef *cd=0;
4882   for (cli.toFirst();(cd=cli.current());++cli)
4883   {
4884     cd->addListReferences();
4885   } 
4886   FileName *fn=Doxygen::inputNameList->first();
4887   while (fn)
4888   {
4889     FileDef *fd=fn->first();
4890     while (fd)
4891     {
4892       fd->addListReferences();
4893       fd=fn->next();
4894     }
4895     fn=Doxygen::inputNameList->next();
4896   }
4897   NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
4898   NamespaceDef *nd=0;
4899   for (nli.toFirst();(nd=nli.current());++nli)
4900   {
4901     nd->addListReferences();
4902   }
4903   GroupSDict::Iterator gli(*Doxygen::groupSDict);
4904   GroupDef *gd;
4905   for (gli.toFirst();(gd=gli.current());++gli)
4906   {
4907     gd->addListReferences();
4908   }
4909   PageSDict::Iterator pdi(*Doxygen::pageSDict);
4910   PageDef *pd=0;
4911   for (pdi.toFirst();(pd=pdi.current());++pdi)
4912   {
4913     QCString name = pd->getOutputFileBase();
4914     if (pd->getGroupDef())
4915     {
4916       name = pd->getGroupDef()->getOutputFileBase();
4917     }
4918     {
4919       LockingPtr< QList<ListItemInfo> > xrefItems = pd->xrefListItems();
4920       addRefItem(xrefItems.pointer(),
4921           name,
4922           theTranslator->trPage(TRUE,TRUE),
4923           name,pd->title(),0);
4924     }
4925   }
4926   DirSDict::Iterator ddi(*Doxygen::directories);
4927   DirDef *dd = 0;
4928   for (ddi.toFirst();(dd=ddi.current());++ddi)
4929   {
4930     QCString name = dd->getOutputFileBase();
4931     //if (dd->getGroupDef())
4932     //{
4933     //  name = dd->getGroupDef()->getOutputFileBase();
4934     //}
4935     LockingPtr< QList<ListItemInfo> > xrefItems = dd->xrefListItems();
4936     addRefItem(xrefItems.pointer(),
4937         name,
4938         theTranslator->trDir(TRUE,TRUE),
4939         name,dd->displayName(),0);
4940   }
4941 }
4942
4943 //----------------------------------------------------------------------
4944
4945 static void generateXRefPages()
4946 {
4947   QDictIterator<RefList> di(*Doxygen::xrefLists);
4948   RefList *rl;
4949   for (di.toFirst();(rl=di.current());++di)
4950   {
4951     rl->generatePage();
4952   }
4953 }
4954
4955 //----------------------------------------------------------------------
4956 // Copy the documentation in entry `root' to member definition `md' and
4957 // set the function declaration of the member to `funcDecl'. If the boolean 
4958 // over_load is set the standard overload text is added. 
4959
4960 static void addMemberDocs(EntryNav *rootNav,
4961                    MemberDef *md, const char *funcDecl,
4962                    ArgumentList *al,
4963                    bool over_load,
4964                    NamespaceSDict *
4965                   )
4966 {
4967   Entry *root = rootNav->entry();
4968   //printf("addMemberDocs: `%s'::`%s' `%s' funcDecl=`%s' mSpec=%d\n",
4969   //     root->parent->name.data(),md->name().data(),md->argsString(),funcDecl,root->spec);
4970   QCString fDecl=funcDecl;
4971   // strip extern specifier
4972   fDecl.stripPrefix("extern ");
4973   md->setDefinition(fDecl);
4974   md->enableCallGraph(root->callGraph);
4975   md->enableCallerGraph(root->callerGraph);
4976   ClassDef     *cd=md->getClassDef();
4977   NamespaceDef *nd=md->getNamespaceDef();
4978   QCString fullName;
4979   if (cd) 
4980     fullName = cd->name();
4981   else if (nd) 
4982     fullName = nd->name();
4983
4984   if (!fullName.isEmpty()) fullName+="::";
4985   fullName+=md->name();
4986   FileDef *rfd=rootNav->fileDef();
4987
4988   // TODO determine scope based on root not md
4989   Definition *rscope = md->getOuterScope();
4990
4991   LockingPtr<ArgumentList> mdAl = md->argumentList();
4992   if (al)
4993   {
4994     //printf("merging arguments (1) docs=%d\n",root->doc.isEmpty());
4995     mergeArguments(mdAl.pointer(),al,!root->doc.isEmpty());
4996   }
4997   else
4998   {
4999     if ( 
5000           matchArguments2( md->getOuterScope(), md->getFileDef(), mdAl.pointer(),
5001                            rscope,rfd,root->argList,
5002                            TRUE
5003                          )
5004        ) 
5005     {
5006       //printf("merging arguments (2)\n");
5007       mergeArguments(mdAl.pointer(),root->argList,!root->doc.isEmpty());
5008     }
5009   }
5010   if (over_load)  // the \overload keyword was used
5011   {
5012     QCString doc=getOverloadDocs();
5013     if (!root->doc.isEmpty())
5014     {
5015       doc+="<p>";
5016       doc+=root->doc;
5017     }
5018     md->setDocumentation(doc,root->docFile,root->docLine); 
5019     md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
5020     md->setDocsForDefinition(!root->proto);
5021   }
5022   else  
5023   {
5024     //printf("overwrite!\n");
5025     md->setDocumentation(root->doc,root->docFile,root->docLine);
5026     md->setDocsForDefinition(!root->proto);
5027
5028     //printf("overwrite!\n");
5029     md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
5030
5031     if (
5032         (md->inbodyDocumentation().isEmpty() ||
5033          !rootNav->parent()->name().isEmpty()
5034         ) && !root->inbodyDocs.isEmpty()
5035        )
5036     {
5037       md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
5038     }
5039   }
5040
5041   //printf("initializer: '%s'(isEmpty=%d) '%s'(isEmpty=%d)\n",
5042   //    md->initializer().data(),md->initializer().isEmpty(),
5043   //    root->initializer.data(),root->initializer.isEmpty()
5044   //   );
5045   if (md->initializer().isEmpty() && !root->initializer.isEmpty())
5046   {
5047     //printf("setInitializer\n");
5048     md->setInitializer(root->initializer);
5049   }
5050
5051   md->setMaxInitLines(root->initLines);
5052
5053   if (rfd)
5054   {
5055     if ((md->getStartBodyLine()==-1 && root->bodyLine!=-1) 
5056        )
5057     {
5058       //printf("Setting new body segment [%d,%d]\n",root->bodyLine,root->endBodyLine);
5059       md->setBodySegment(root->bodyLine,root->endBodyLine);
5060       md->setBodyDef(rfd);
5061     }
5062
5063     md->setRefItems(root->sli);
5064   }
5065
5066   md->enableCallGraph(md->hasCallGraph() || root->callGraph);
5067   md->enableCallerGraph(md->hasCallerGraph() || root->callerGraph);
5068
5069   md->mergeMemberSpecifiers(root->spec);
5070   md->addSectionsToDefinition(root->anchors);
5071   addMemberToGroups(root,md);
5072   if (cd) cd->insertUsedFile(root->fileName);
5073   //printf("root->mGrpId=%d\n",root->mGrpId);
5074   if (root->mGrpId!=-1)
5075   {
5076     if (md->getMemberGroupId()!=-1)
5077     {
5078       if (md->getMemberGroupId()!=root->mGrpId)
5079       {
5080         warn(
5081              root->fileName,root->startLine,
5082              "warning: member %s belongs to two different groups. The second "
5083              "one found here will be ignored.",
5084              md->name().data()
5085             );
5086       }
5087     }
5088     else // set group id
5089     {
5090       //printf("setMemberGroupId=%d md=%s\n",root->mGrpId,md->name().data());
5091       md->setMemberGroupId(root->mGrpId);
5092     }
5093   }
5094 }
5095
5096 //----------------------------------------------------------------------
5097 // find a class definition given the scope name and (optionally) a 
5098 // template list specifier
5099
5100 static ClassDef *findClassDefinition(FileDef *fd,NamespaceDef *nd,
5101                          const char *scopeName)
5102 {
5103   ClassDef *tcd = getResolvedClass(nd,fd,scopeName,0,0,TRUE,TRUE);
5104   return tcd;
5105 }
5106
5107
5108 //----------------------------------------------------------------------
5109 // Adds the documentation contained in `root' to a global function
5110 // with name `name' and argument list `args' (for overloading) and
5111 // function declaration `decl' to the corresponding member definition.
5112
5113 static bool findGlobalMember(EntryNav *rootNav, 
5114                            const QCString &namespaceName,
5115                            const char *name, 
5116                            const char *tempArg,
5117                            const char *, 
5118                            const char *decl)
5119 {
5120   Entry *root = rootNav->entry();
5121   Debug::print(Debug::FindMembers,0,
5122        "2. findGlobalMember(namespace=%s,name=%s,tempArg=%s,decl=%s)\n",
5123           namespaceName.data(),name,tempArg,decl);
5124   QCString n=name;
5125   if (n.isEmpty()) return FALSE;
5126   if (n.find("::")!=-1) return FALSE; // skip undefined class members
5127   MemberName *mn=Doxygen::functionNameSDict->find(n+tempArg); // look in function dictionary
5128   if (mn==0)
5129   {
5130     mn=Doxygen::functionNameSDict->find(n); // try without template arguments
5131   }
5132   if (mn) // function name defined
5133   {
5134     Debug::print(Debug::FindMembers,0,"3. Found function scope\n");
5135     //int count=0;
5136     MemberNameIterator mni(*mn);
5137     MemberDef *md;
5138     bool found=FALSE;
5139     for (mni.toFirst();(md=mni.current()) && !found;++mni)
5140     {
5141       NamespaceDef *nd=md->getNamespaceDef();
5142
5143       //printf("Namespace namespaceName=%s nd=%s\n",
5144       //    namespaceName.data(),nd ? nd->name().data() : "<none>");
5145
5146       FileDef *fd=rootNav->fileDef();
5147       //printf("File %s\n",fd ? fd->name().data() : "<none>");
5148       NamespaceSDict *nl = fd ? fd->getUsedNamespaces() : 0;
5149       //SDict<Definition> *cl = fd ? fd->getUsedClasses()    : 0;
5150       //printf("NamespaceList %p\n",nl);
5151
5152       // search in the list of namespaces that are imported via a 
5153       // using declaration
5154       bool viaUsingDirective = nl && nd && nl->find(nd->qualifiedName())!=0;
5155
5156       if ((namespaceName.isEmpty() && nd==0) ||  // not in a namespace
5157           (nd && nd->name()==namespaceName) ||   // or in the same namespace 
5158           viaUsingDirective                      // member in `using' namespace
5159          )     
5160       {
5161         Debug::print(Debug::FindMembers,0,"4. Try to add member `%s' to scope `%s'\n",
5162             md->name().data(),namespaceName.data());
5163         QCString nsName = nd ? nd->name().data() : "";
5164
5165         NamespaceDef *rnd = 0;
5166         if (!namespaceName.isEmpty()) rnd = Doxygen::namespaceSDict->find(namespaceName);
5167
5168         LockingPtr<ArgumentList> mdAl = md->argumentList();
5169         bool matching=
5170           (mdAl==0 && root->argList->count()==0) ||
5171           md->isVariable() || md->isTypedef() || /* in case of function pointers */
5172           matchArguments2(md->getOuterScope(),md->getFileDef(),mdAl.pointer(),
5173                           rnd ? rnd : Doxygen::globalScope,fd,root->argList,
5174                           FALSE);
5175
5176         // for template members we need to check if the number of
5177         // template arguments is the same, otherwise we are dealing with
5178         // different functions.
5179         if (matching && root->tArgLists)
5180         {
5181           LockingPtr<ArgumentList> mdTempl = md->templateArguments();
5182           if (mdTempl!=0)
5183           {
5184             if (root->tArgLists->getLast()->count()!=mdTempl->count())
5185             {
5186               matching=FALSE;
5187             }
5188           }
5189         }
5190
5191         //printf("%s<->%s\n",
5192         //    argListToString(md->argumentList()).data(),
5193         //    argListToString(root->argList).data());
5194
5195         // for static members we also check if the comment block was found in 
5196         // the same file. This is needed because static members with the same
5197         // name can be in different files. Thus it would be wrong to just
5198         // put the comment block at the first syntactically matching member.
5199         if (matching && md->isStatic() && 
5200             md->getDefFileName()!=root->fileName && 
5201             mn->count()>1)
5202         {
5203           matching = FALSE;
5204         }
5205
5206         if (matching) // add docs to the member
5207         {
5208           Debug::print(Debug::FindMembers,0,"5. Match found\n");
5209           addMemberDocs(rootNav,md,decl,root->argList,FALSE);
5210           found=TRUE;
5211         }
5212       }
5213     } 
5214     if (!found && root->relatesType != Duplicate && root->section==Entry::FUNCTION_SEC) // no match
5215     {
5216       QCString fullFuncDecl=decl;
5217       if (root->argList) fullFuncDecl+=argListToString(root->argList,TRUE);
5218       QCString warnMsg =
5219          QCString("warning: no matching file member found for \n")+substitute(fullFuncDecl,"%","%%");
5220       if (mn->count()>0)
5221       {
5222         warnMsg+="\nPossible candidates:\n";
5223         for (mni.toFirst();(md=mni.current());++mni)
5224         {
5225           warnMsg+=" '";
5226           warnMsg+=substitute(md->declaration(),"%","%%");
5227           warnMsg+="' at line "+QCString().setNum(md->getDefLine())+
5228                    " of file"+md->getDefFileName()+"\n";
5229         }
5230       }
5231       warn(root->fileName,root->startLine,warnMsg);
5232     }
5233   }
5234   else // got docs for an undefined member!
5235   {
5236     if (root->type!="friend class" && 
5237         root->type!="friend struct" &&
5238         root->type!="friend union" &&
5239         (!Config_getBool("TYPEDEF_HIDES_STRUCT") || 
5240          root->type.find("typedef ")==-1)
5241        )
5242     {
5243       warn(root->fileName,root->startLine,
5244            "warning: documented function `%s' was not declared or defined.",decl
5245           );
5246     }
5247   }
5248   return TRUE;
5249 }
5250
5251 static bool isSpecialization(
5252                   const QList<ArgumentList> &srcTempArgLists,
5253                   const QList<ArgumentList> &dstTempArgLists
5254     )
5255 {
5256     QListIterator<ArgumentList> srclali(srcTempArgLists);
5257     QListIterator<ArgumentList> dstlali(dstTempArgLists);
5258     for (;srclali.current();++srclali,++dstlali)
5259     {
5260       ArgumentList *sal = srclali.current();
5261       ArgumentList *dal = dstlali.current();
5262       if (!(sal && dal && sal->count()==dal->count())) return TRUE;
5263     }
5264     return FALSE;
5265 }
5266
5267
5268 static QCString substituteTemplatesInString(
5269     const QList<ArgumentList> &srcTempArgLists,
5270     const QList<ArgumentList> &dstTempArgLists,
5271     ArgumentList *funcTempArgList, // can be used to match template specializations
5272     const QCString &src
5273     )
5274 {
5275   QCString dst;
5276   QRegExp re( "[A-Za-z_][A-Za-z_0-9]*");
5277   //printf("type=%s\n",sa->type.data());
5278   int i,p=0,l; 
5279   while ((i=re.match(src,p,&l))!=-1) // for each word in srcType
5280   {
5281     bool found=FALSE;
5282     dst+=src.mid(p,i-p);
5283     QCString name=src.mid(i,l);
5284
5285     QListIterator<ArgumentList> srclali(srcTempArgLists);
5286     QListIterator<ArgumentList> dstlali(dstTempArgLists);
5287     for (;srclali.current() && !found;++srclali,++dstlali)
5288     {
5289       ArgumentListIterator tsali(*srclali.current());
5290       ArgumentListIterator tdali(*dstlali.current());
5291       Argument *tsa =0,*tda=0, *fa=0;
5292       if (funcTempArgList)
5293       {
5294         fa=funcTempArgList->first();
5295       }
5296
5297       for (tsali.toFirst();(tsa=tsali.current()) && !found;++tsali)
5298       {
5299         tda = tdali.current();
5300         //if (tda) printf("tsa=%s|%s tda=%s|%s\n",
5301         //    tsa->type.data(),tsa->name.data(),
5302         //    tda->type.data(),tda->name.data());
5303         if (name==tsa->name)
5304         {
5305           if (tda && tda->name.isEmpty())
5306           {
5307             int vc=0;
5308             if (tda->type.left(6)=="class ") vc=6;
5309             else if (tda->type.left(9)=="typename ") vc=9;
5310             if (vc>0) // convert type=="class T" to type=="class" name=="T"
5311             {
5312               tda->name = tda->type.mid(vc);
5313               tda->type = tda->type.left(vc-1);
5314             }
5315           }
5316           if (tda && !tda->name.isEmpty())
5317           {
5318             name=tda->name; // substitute
5319             found=TRUE;
5320           }
5321           else if (fa)
5322           {
5323             name=fa->type;
5324             found=TRUE;
5325           }
5326         }
5327         if (tda) 
5328           ++tdali; 
5329         else if (fa) 
5330           fa=funcTempArgList->next();
5331       }
5332       //printf("   srcList='%s' dstList='%s faList='%s'\n",
5333       //  argListToString(srclali.current()).data(),
5334       //  argListToString(dstlali.current()).data(),
5335       //  funcTempArgList ? argListToString(funcTempArgList).data() : "<none>");
5336     }
5337     dst+=name; 
5338     p=i+l;
5339   }
5340   dst+=src.right(src.length()-p);
5341   //printf("  substituteTemplatesInString(%s)=%s\n",
5342   //    src.data(),dst.data());
5343   return dst;
5344 }
5345
5346 static void substituteTemplatesInArgList(
5347                   const QList<ArgumentList> &srcTempArgLists,
5348                   const QList<ArgumentList> &dstTempArgLists,
5349                   ArgumentList *src,
5350                   ArgumentList *dst,
5351                   ArgumentList *funcTempArgs = 0
5352                  )
5353 {
5354   ArgumentListIterator sali(*src);
5355   Argument *sa=0;
5356   Argument *da=dst->first();
5357
5358   for (sali.toFirst();(sa=sali.current());++sali) // for each member argument
5359   {
5360     QCString dstType = substituteTemplatesInString(
5361                                   srcTempArgLists,dstTempArgLists,funcTempArgs,
5362                                   sa->type);
5363     QCString dstArray = substituteTemplatesInString(
5364                                   srcTempArgLists,dstTempArgLists,funcTempArgs,
5365                                   sa->array);
5366     if (da==0)
5367     {
5368       da=new Argument(*sa);
5369       dst->append(da);
5370       da->type=dstType;
5371       da->array=dstArray;
5372       da=0;
5373     }
5374     else
5375     {
5376       da->type=dstType;
5377       da->type=dstArray;
5378       da=dst->next();
5379     }
5380   }
5381   dst->constSpecifier     = src->constSpecifier;
5382   dst->volatileSpecifier  = src->volatileSpecifier;
5383   dst->pureSpecifier      = src->pureSpecifier;
5384   dst->trailingReturnType = substituteTemplatesInString(
5385                              srcTempArgLists,dstTempArgLists,
5386                              funcTempArgs,src->trailingReturnType);
5387   //printf("substituteTemplatesInArgList: replacing %s with %s\n",
5388   //    argListToString(src).data(),argListToString(dst).data()
5389   //    );
5390 }
5391
5392
5393
5394 /*! This function tries to find a member (in a documented class/file/namespace) 
5395  * that corresponds to the function/variable declaration given in \a funcDecl.
5396  *
5397  * The boolean \a overloaded is used to specify whether or not a standard
5398  * overload documentation line should be generated.
5399  *
5400  * The boolean \a isFunc is a hint that indicates that this is a function
5401  * instead of a variable or typedef.
5402  */
5403 static void findMember(EntryNav *rootNav,
5404                        QCString funcDecl,
5405                        bool overloaded,
5406                        bool isFunc
5407                       )
5408 {
5409   Entry *root = rootNav->entry();
5410
5411   Debug::print(Debug::FindMembers,0,
5412                "findMember(root=%p,funcDecl=`%s',related=`%s',overload=%d,"
5413                "isFunc=%d mGrpId=%d tArgList=%p (#=%d) "
5414                "spec=%d lang=%x\n",
5415                root,funcDecl.data(),root->relates.data(),overloaded,isFunc,root->mGrpId,
5416                root->tArgLists,root->tArgLists ? root->tArgLists->count() : 0,
5417                root->spec,root->lang
5418               );
5419
5420   QCString scopeName;
5421   QCString className;
5422   QCString namespaceName;
5423   QCString funcType;
5424   QCString funcName;
5425   QCString funcArgs;
5426   QCString funcTempList;
5427   QCString exceptions;
5428   QCString funcSpec;
5429   bool isRelated=FALSE;
5430   bool isMemberOf=FALSE;
5431   bool isFriend=FALSE;
5432   bool done;
5433   do
5434   {
5435     done=TRUE;
5436     if (funcDecl.stripPrefix("friend ")) // treat friends as related members
5437     {
5438       isFriend=TRUE;
5439       done=FALSE;
5440     }
5441     if (funcDecl.stripPrefix("inline "))
5442     {
5443       root->spec|=Entry::Inline;
5444       done=FALSE;
5445     }
5446     if (funcDecl.stripPrefix("explicit "))
5447     {
5448       root->spec|=Entry::Explicit;
5449       done=FALSE;
5450     }
5451     if (funcDecl.stripPrefix("mutable "))
5452     {
5453       root->spec|=Entry::Mutable;
5454       done=FALSE;
5455     }
5456     if (funcDecl.stripPrefix("virtual "))
5457     {
5458       done=FALSE;
5459     }
5460   } while (!done);
5461
5462   // delete any ; from the function declaration
5463   int sep;
5464   while ((sep=funcDecl.find(';'))!=-1)
5465   {
5466     funcDecl=(funcDecl.left(sep)+funcDecl.right(funcDecl.length()-sep-1)).stripWhiteSpace();
5467   }
5468   
5469   // make sure the first character is a space to simplify searching.
5470   if (!funcDecl.isEmpty() && funcDecl[0]!=' ') funcDecl.prepend(" ");
5471   
5472   // remove some superfluous spaces
5473   funcDecl= substitute(
5474               substitute(
5475                 substitute(funcDecl,"~ ","~"),
5476                 ":: ","::"
5477               ),
5478               " ::","::"
5479             ).stripWhiteSpace();
5480   
5481   //printf("funcDecl=`%s'\n",funcDecl.data());
5482   if (isFriend && funcDecl.left(6)=="class ")
5483   {
5484     //printf("friend class\n");
5485     funcDecl=funcDecl.right(funcDecl.length()-6);
5486     funcName = funcDecl.copy();
5487   }
5488   else if (isFriend && funcDecl.left(7)=="struct ")
5489   {
5490     funcDecl=funcDecl.right(funcDecl.length()-7);
5491     funcName = funcDecl.copy();
5492   }
5493   else
5494   {
5495     // extract information from the declarations
5496     parseFuncDecl(funcDecl,root->lang==SrcLangExt_ObjC,scopeName,funcType,funcName,
5497                 funcArgs,funcTempList,exceptions
5498                );
5499   }
5500   //printf("scopeName=`%s' funcType=`%s' funcName=`%s' funcArgs=`%s'\n",
5501   //    scopeName.data(),funcType.data(),funcName.data(),funcArgs.data());
5502
5503   // the class name can also be a namespace name, we decide this later.
5504   // if a related class name is specified and the class name could
5505   // not be derived from the function declaration, then use the
5506   // related field.
5507   //printf("scopeName=`%s' className=`%s' namespaceName=`%s'\n",
5508   //    scopeName.data(),className.data(),namespaceName.data());
5509   if (!root->relates.isEmpty()) 
5510   {                             // related member, prefix user specified scope
5511     isRelated=TRUE;
5512     isMemberOf=(root->relatesType == MemberOf);
5513     if (getClass(root->relates)==0 && !scopeName.isEmpty())
5514     {
5515       scopeName= mergeScopes(scopeName,root->relates);
5516     }
5517     else 
5518     {
5519       scopeName = root->relates;
5520     }
5521   }
5522
5523   if (root->relates.isEmpty() && rootNav->parent() && 
5524       ((rootNav->parent()->section()&Entry::SCOPE_MASK) ||
5525        (rootNav->parent()->section()==Entry::OBJCIMPL_SEC)
5526       ) &&
5527       !rootNav->parent()->name().isEmpty()) // see if we can combine scopeName 
5528                                      // with the scope in which it was found
5529   {
5530     QCString joinedName = rootNav->parent()->name()+"::"+scopeName;
5531     if (!scopeName.isEmpty() && 
5532         (getClass(joinedName) || Doxygen::namespaceSDict->find(joinedName)))
5533     {
5534       scopeName = joinedName;
5535     }
5536     else
5537     {
5538       scopeName = mergeScopes(rootNav->parent()->name(),scopeName);
5539     }
5540   }
5541   else // see if we can prefix a namespace or class that is used from the file
5542   {
5543      FileDef *fd=rootNav->fileDef();
5544      if (fd)
5545      {
5546        NamespaceSDict *fnl = fd->getUsedNamespaces();
5547        if (fnl)
5548        {
5549          QCString joinedName;
5550          NamespaceDef *fnd;
5551          NamespaceSDict::Iterator nsdi(*fnl);
5552          for (nsdi.toFirst();(fnd=nsdi.current());++nsdi)
5553          {
5554            joinedName = fnd->name()+"::"+scopeName;
5555            if (Doxygen::namespaceSDict->find(joinedName))
5556            {
5557              scopeName=joinedName;
5558              break;
5559            }
5560          }
5561        }
5562      }
5563   }
5564   scopeName=stripTemplateSpecifiersFromScope(
5565       removeRedundantWhiteSpace(scopeName),FALSE,&funcSpec); 
5566
5567   // funcSpec contains the last template specifiers of the given scope.
5568   // If this method does not have any template arguments or they are 
5569   // empty while funcSpec is not empty we assume this is a 
5570   // specialization of a method. If not, we clear the funcSpec and treat
5571   // this as a normal method of a template class.
5572   if (!(root->tArgLists && 
5573         root->tArgLists->count()>0 &&
5574         root->tArgLists->first()->count()==0
5575        )
5576      ) 
5577   {
5578     funcSpec.resize(0);
5579   }
5580   
5581   // split scope into a namespace and a class part
5582   extractNamespaceName(scopeName,className,namespaceName,TRUE);
5583   //printf("scopeName=`%s' className=`%s' namespaceName=`%s'\n",
5584   //       scopeName.data(),className.data(),namespaceName.data());
5585   
5586   //namespaceName=removeAnonymousScopes(namespaceName);
5587   if (namespaceName.find('@')!=-1) return; // skip stuff in anonymous namespace...
5588
5589   //printf("namespaceName=`%s' className=`%s'\n",namespaceName.data(),className.data());
5590   // merge class and namespace scopes again
5591   scopeName.resize(0);
5592   if (!namespaceName.isEmpty())
5593   {
5594     if (className.isEmpty())
5595     {
5596       scopeName=namespaceName;
5597     }
5598     else if (!root->relates.isEmpty() || // relates command with explicit scope
5599              !getClass(className)) // class name only exists in a namespace
5600     {
5601       scopeName=namespaceName+"::"+className;
5602     }
5603     else
5604     {
5605       scopeName=className;
5606     }
5607   }
5608   else if (!className.isEmpty())
5609   {
5610     scopeName=className;
5611   }
5612   //printf("new scope=`%s'\n",scopeName.data());
5613
5614   QCString tempScopeName=scopeName;
5615   ClassDef *cd=getClass(scopeName);
5616   if (cd)
5617   {
5618     if (root->tArgLists) root->tArgLists->first();
5619     if (funcSpec.isEmpty())
5620     {
5621       tempScopeName=cd->qualifiedNameWithTemplateParameters(root->tArgLists);
5622     }
5623     else
5624     {
5625       tempScopeName=scopeName+funcSpec;
5626     }
5627   }
5628   //printf("scopeName=%s cd=%p root->tArgLists=%p result=%s\n",
5629   //    scopeName.data(),cd,root->tArgLists,tempScopeName.data());
5630   
5631   //printf("scopeName=`%s' className=`%s'\n",scopeName.data(),className.data());
5632   // rebuild the function declaration (needed to get the scope right).
5633   if (!scopeName.isEmpty() && !isRelated && !isFriend && !Config_getBool("HIDE_SCOPE_NAMES"))
5634   {
5635     if (!funcType.isEmpty())
5636     {
5637       if (isFunc) // a function -> we use argList for the arguments
5638       {
5639         funcDecl=funcType+" "+tempScopeName+"::"+funcName+funcTempList;
5640       }
5641       else
5642       {
5643         funcDecl=funcType+" "+tempScopeName+"::"+funcName+funcArgs;
5644       }
5645     }
5646     else
5647     {
5648       if (isFunc) // a function => we use argList for the arguments
5649       {
5650         funcDecl=tempScopeName+"::"+funcName+funcTempList;
5651       }
5652       else // variable => add `argument' list
5653       {
5654         funcDecl=tempScopeName+"::"+funcName+funcArgs;
5655       }
5656     }
5657   }
5658   else // build declaration without scope
5659   {
5660     if (!funcType.isEmpty()) // but with a type
5661     {
5662       if (isFunc) // function => omit argument list
5663       {
5664         funcDecl=funcType+" "+funcName+funcTempList;
5665       }
5666       else // variable => add `argument' list
5667       {
5668         funcDecl=funcType+" "+funcName+funcArgs;
5669       }
5670     }
5671     else // no type
5672     {
5673       if (isFunc)
5674       {
5675         funcDecl=funcName+funcTempList;
5676       }
5677       else
5678       {
5679         funcDecl=funcName+funcArgs;
5680       }
5681     }
5682   }
5683   
5684   if (funcType=="template class" && !funcTempList.isEmpty())
5685     return;   // ignore explicit template instantiations
5686   
5687   Debug::print(Debug::FindMembers,0,
5688            "findMember() Parse results:\n"
5689            "  namespaceName=`%s'\n"
5690            "  className=`%s`\n"
5691            "  funcType=`%s'\n"
5692            "  funcSpec=`%s'\n"
5693            "  funcName=`%s'\n"
5694            "  funcArgs=`%s'\n"
5695            "  funcTempList=`%s'\n"
5696            "  funcDecl=`%s'\n"
5697            "  related=`%s'\n" 
5698            "  exceptions=`%s'\n"
5699            "  isRelated=%d\n"
5700            "  isMemberOf=%d\n"
5701            "  isFriend=%d\n"
5702            "  isFunc=%d\n\n",
5703            namespaceName.data(),className.data(),
5704            funcType.data(),funcSpec.data(),funcName.data(),funcArgs.data(),funcTempList.data(),
5705            funcDecl.data(),root->relates.data(),exceptions.data(),isRelated,isMemberOf,isFriend,
5706            isFunc
5707           );
5708
5709   MemberName *mn=0;
5710   if (!funcName.isEmpty()) // function name is valid
5711   { 
5712     Debug::print(Debug::FindMembers,0,
5713                  "1. funcName=`%s'\n",funcName.data());
5714     if (funcName.left(9)=="operator ") // strip class scope from cast operator
5715     {
5716       funcName = substitute(funcName,className+"::","");
5717     }
5718     if (!funcTempList.isEmpty()) // try with member specialization
5719     {
5720       mn=Doxygen::memberNameSDict->find(funcName+funcTempList);
5721     }
5722     if (mn==0) // try without specialization
5723     {
5724       mn=Doxygen::memberNameSDict->find(funcName);
5725     }
5726     if (!isRelated && mn) // function name already found
5727     {
5728       Debug::print(Debug::FindMembers,0,
5729                    "2. member name exists (%d members with this name)\n",mn->count());
5730       if (!className.isEmpty()) // class name is valid
5731       {
5732         if (funcSpec.isEmpty()) // not a member specialization
5733         {
5734           int count=0;
5735           int noMatchCount=0;
5736           MemberNameIterator mni(*mn);
5737           MemberDef *md;
5738           bool memFound=FALSE;
5739           for (mni.toFirst();!memFound && (md=mni.current());++mni)
5740           {
5741             ClassDef *cd=md->getClassDef();
5742             Debug::print(Debug::FindMembers,0,
5743                 "3. member definition found, "
5744                 "scope needed=`%s' scope=`%s' args=`%s' fileName=%s\n",
5745                 scopeName.data(),cd ? cd->name().data() : "<none>",
5746                 md->argsString(),
5747                 root->fileName.data());
5748             //printf("Member %s (member scopeName=%s) (this scopeName=%s) classTempList=%s\n",md->name().data(),cd->name().data(),scopeName.data(),classTempList.data());
5749             FileDef *fd=rootNav->fileDef();
5750             NamespaceDef *nd=0;
5751             if (!namespaceName.isEmpty()) nd=getResolvedNamespace(namespaceName);
5752
5753             //printf("scopeName %s->%s\n",scopeName.data(),
5754             //       stripTemplateSpecifiersFromScope(scopeName,FALSE).data());
5755
5756             ClassDef *tcd=findClassDefinition(fd,nd,scopeName);
5757             if (tcd==0 && stripAnonymousNamespaceScope(cd->name())==scopeName)
5758             {
5759               // don't be fooled by anonymous scopes
5760               tcd=cd;
5761             }
5762             //printf("Looking for %s inside nd=%s result=%p (%s) cd=%p\n",
5763             //    scopeName.data(),nd?nd->name().data():"<none>",tcd,tcd?tcd->name().data():"",cd);
5764
5765             if (cd && tcd==cd) // member's classes match
5766             {
5767               Debug::print(Debug::FindMembers,0,
5768                   "4. class definition %s found\n",cd->name().data());
5769
5770               // get the template parameter lists found at the member declaration
5771               QList<ArgumentList> declTemplArgs;
5772               cd->getTemplateParameterLists(declTemplArgs);
5773               LockingPtr<ArgumentList> templAl = md->templateArguments();
5774               if (templAl!=0)
5775               {
5776                 declTemplArgs.append(templAl.pointer());
5777               }
5778
5779               // get the template parameter lists found at the member definition
5780               QList<ArgumentList> *defTemplArgs = root->tArgLists;
5781               //printf("defTemplArgs=%p\n",defTemplArgs);
5782
5783               // do we replace the decl argument lists with the def argument lists?
5784               bool substDone=FALSE;
5785               ArgumentList *argList=0;
5786
5787               /* substitute the occurrences of class template names in the 
5788                * argument list before matching 
5789                */
5790               LockingPtr<ArgumentList> mdAl = md->argumentList();
5791               if (declTemplArgs.count()>0 && defTemplArgs &&
5792                   declTemplArgs.count()==defTemplArgs->count() &&
5793                   mdAl.pointer()
5794                  )
5795               {
5796                 /* the function definition has template arguments
5797                  * and the class definition also has template arguments, so
5798                  * we must substitute the template names of the class by that
5799                  * of the function definition before matching.
5800                  */
5801                 argList = new ArgumentList;
5802                 substituteTemplatesInArgList(declTemplArgs,*defTemplArgs,
5803                     mdAl.pointer(),argList);
5804
5805                 substDone=TRUE;
5806               }
5807               else /* no template arguments, compare argument lists directly */
5808               {
5809                 argList = mdAl.pointer();
5810               }
5811
5812               Debug::print(Debug::FindMembers,0,
5813                   "5. matching `%s'<=>`%s' className=%s namespaceName=%s\n",
5814                   argListToString(argList,TRUE).data(),argListToString(root->argList,TRUE).data(),
5815                   className.data(),namespaceName.data()
5816                   );
5817
5818               bool matching=
5819                 md->isVariable() || md->isTypedef() || // needed for function pointers
5820                 (mdAl.pointer()==0 && root->argList->count()==0) || 
5821                 matchArguments2(
5822                     md->getClassDef(),md->getFileDef(),argList, 
5823                     cd,fd,root->argList,
5824                     TRUE);
5825
5826               if (md->getLanguage()==SrcLangExt_ObjC && md->isVariable() && (root->section&Entry::FUNCTION_SEC))
5827               {
5828                 matching = FALSE; // don't match methods and attributes with the same name
5829               }
5830
5831               Debug::print(Debug::FindMembers,0,
5832                   "6. match results of matchArguments2 = %d\n",matching);
5833
5834               if (substDone) // found a new argument list
5835               {
5836                 if (matching) // replace member's argument list
5837                 {
5838                   md->setDefinitionTemplateParameterLists(root->tArgLists);
5839                   md->setArgumentList(argList); // new owner of the list => no delete
5840                 }
5841                 else // no match 
5842                 {
5843                   if (!funcTempList.isEmpty() && 
5844                       isSpecialization(declTemplArgs,*defTemplArgs))
5845                   {
5846                     // check if we are dealing with a partial template
5847                     // specialization. In this case we add it to the class
5848                     // even though the member arguments do not match.
5849                     
5850                     // TODO: copy other aspects?
5851                     root->protection=md->protection(); // copy protection level
5852                     addMethodToClass(rootNav,cd,md->name(),isFriend);
5853                     return;
5854                   }
5855                   delete argList;
5856                 }
5857               }
5858               if (matching) 
5859               {
5860                 addMemberDocs(rootNav,md,funcDecl,0,overloaded,0/* TODO */);
5861                 count++;
5862                 memFound=TRUE;
5863               }
5864             } 
5865             else if (cd && cd!=tcd) // we did find a class with the same name as cd
5866                                     // but in a different namespace
5867             {
5868               noMatchCount++;
5869             }
5870           } 
5871           if (count==0 && rootNav->parent() && 
5872               rootNav->parent()->section()==Entry::OBJCIMPL_SEC)
5873           {
5874             goto localObjCMethod;
5875           }
5876           if (count==0 && !(isFriend && funcType=="class"))
5877           {
5878             int candidates=0;
5879             ClassDef *ecd = 0, *ucd = 0;
5880             MemberDef *emd = 0, *umd = 0;
5881             if (mn->count()>0)
5882             {
5883               //printf("Assume template class\n");
5884               for (mni.toFirst();(md=mni.current());++mni)
5885               {
5886                 ClassDef *ccd=md->getClassDef();
5887                 MemberDef *cmd=md;
5888                 //printf("ccd->name()==%s className=%s\n",ccd->name().data(),className.data());
5889                 if (ccd!=0 && rightScopeMatch(ccd->name(),className)) 
5890                 {
5891                   LockingPtr<ArgumentList> templAl = md->templateArguments();
5892                   if (root->tArgLists && templAl!=0 &&
5893                       root->tArgLists->getLast()->count()<=templAl->count())
5894                   { 
5895                     addMethodToClass(rootNav,ccd,md->name(),isFriend);
5896                     return;
5897                   }
5898                   if (md->argsString()==argListToString(root->argList,TRUE,FALSE))
5899                   { // exact argument list match -> remember
5900                     ucd = ecd = ccd;
5901                     umd = emd = cmd;
5902                     Debug::print(Debug::FindMembers,0,
5903                      "7. new candidate className=%s scope=%s args=%s exact match\n",
5904                          className.data(),ccd->name().data(),md->argsString());
5905                   }
5906                   else // arguments do not match, but member name and scope do -> remember
5907                   {
5908                     ucd = ccd;
5909                     umd = cmd;
5910                     Debug::print(Debug::FindMembers,0,
5911                      "7. new candidate className=%s scope=%s args=%s no match\n",
5912                          className.data(),ccd->name().data(),md->argsString());
5913                   }
5914                   candidates++;
5915                 }
5916               }
5917             }
5918             static bool strictProtoMatching = Config_getBool("STRICT_PROTO_MATCHING");
5919             if (!strictProtoMatching)
5920             {
5921               if (candidates==1 && ucd && umd)
5922               {
5923                 // we didn't find an actual match on argument lists, but there is only 1 member with this
5924                 // name in the same scope, so that has to be the one. 
5925                 addMemberDocs(rootNav,umd,funcDecl,0,overloaded,0);
5926                 return;
5927               }
5928               else if (candidates>1 && ecd && emd)
5929               {
5930                 // we didn't find a unique match using type resolution, 
5931                 // but one of the matches has the exact same signature so
5932                 // we take that one.
5933                 addMemberDocs(rootNav,emd,funcDecl,0,overloaded,0);
5934                 return;
5935               }
5936             }
5937
5938             QCString warnMsg = "warning: no ";
5939             if (noMatchCount>1) warnMsg+="uniquely ";
5940             warnMsg+="matching class member found for \n";
5941
5942             if (root->tArgLists)
5943             {
5944               QListIterator<ArgumentList> alli(*root->tArgLists);
5945               ArgumentList *al;
5946               for (;(al=alli.current());++alli)
5947               {
5948                 warnMsg+="  template ";
5949                 warnMsg+=tempArgListToString(al);
5950                 warnMsg+='\n';
5951               }
5952             }
5953             QCString fullFuncDecl=funcDecl.copy();
5954             if (isFunc) fullFuncDecl+=argListToString(root->argList,TRUE);
5955
5956             warnMsg+="  ";
5957             warnMsg+=fullFuncDecl;
5958             warnMsg+='\n';
5959
5960             if (candidates>0)
5961             {
5962               warnMsg+="Possible candidates:\n";
5963               for (mni.toFirst();(md=mni.current());++mni)
5964               {
5965                 ClassDef *cd=md->getClassDef();
5966                 if (cd!=0 && rightScopeMatch(cd->name(),className))
5967                 {
5968                   LockingPtr<ArgumentList> templAl = md->templateArguments();
5969                   if (templAl!=0)
5970                   {
5971                     warnMsg+="  'template ";
5972                     warnMsg+=tempArgListToString(templAl.pointer());
5973                     warnMsg+='\n';
5974                   }
5975                   warnMsg+="  ";
5976                   if (md->typeString()) 
5977                   {
5978                     warnMsg+=md->typeString();
5979                     warnMsg+=' ';
5980                   }
5981                   QCString qScope = cd->qualifiedNameWithTemplateParameters();
5982                   if (!qScope.isEmpty()) 
5983                     warnMsg+=qScope+"::"+md->name();
5984                   if (md->argsString()) 
5985                     warnMsg+=md->argsString();
5986                   if (noMatchCount>1) 
5987                   {
5988                     warnMsg+="' at line "+QCString().setNum(md->getDefLine()) +
5989                              " of file "+md->getDefFileName();
5990                   }
5991
5992                   warnMsg+='\n';
5993                 }
5994               }
5995             }
5996             warn_simple(root->fileName,root->startLine,warnMsg);
5997           }
5998         }
5999         else if (cd) // member specialization
6000         {
6001           MemberNameIterator mni(*mn);
6002           MemberDef *declMd=0;
6003           MemberDef *md=0;
6004           for (mni.toFirst();(md=mni.current());++mni)
6005           {
6006             if (md->getClassDef()==cd) 
6007             {
6008               // TODO: we should probably also check for matching arguments
6009               declMd = md;
6010               break;
6011             }
6012           }
6013           MemberDef::MemberType mtype=MemberDef::Function;
6014           ArgumentList *tArgList = new ArgumentList;
6015           //  getTemplateArgumentsFromName(cd->name()+"::"+funcName,root->tArgLists);
6016           md=new MemberDef(
6017               root->fileName,root->startLine,
6018               funcType,funcName,funcArgs,exceptions,
6019               declMd ? declMd->protection() : root->protection,
6020               root->virt,root->stat,Member,
6021               mtype,tArgList,root->argList);
6022           //printf("new specialized member %s args=`%s'\n",md->name().data(),funcArgs.data());
6023           md->setTagInfo(rootNav->tagInfo());
6024           md->setLanguage(root->lang);
6025           md->setMemberClass(cd);
6026           md->setTemplateSpecialization(TRUE);
6027           md->setTypeConstraints(root->typeConstr);
6028           md->setDefinition(funcDecl);
6029           md->enableCallGraph(root->callGraph);
6030           md->enableCallerGraph(root->callerGraph);
6031           md->setDocumentation(root->doc,root->docFile,root->docLine);
6032           md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
6033           md->setDocsForDefinition(!root->proto);
6034           md->setPrototype(root->proto);
6035           md->addSectionsToDefinition(root->anchors);
6036           md->setBodySegment(root->bodyLine,root->endBodyLine);
6037           FileDef *fd=rootNav->fileDef();
6038           md->setBodyDef(fd);
6039           md->setMemberSpecifiers(root->spec);
6040           md->setMemberGroupId(root->mGrpId);
6041           mn->append(md);
6042           cd->insertMember(md);
6043           md->setRefItems(root->sli);
6044           delete tArgList;
6045         }
6046         else
6047         {
6048           //printf("*** Specialized member %s of unknown scope %s%s found!\n",
6049           //        scopeName.data(),funcName.data(),funcArgs.data());
6050         }
6051       }
6052       else if (overloaded) // check if the function belongs to only one class 
6053       {
6054         // for unique overloaded member we allow the class to be
6055         // omitted, this is to be Qt compatible. Using this should 
6056         // however be avoided, because it is error prone
6057         MemberNameIterator mni(*mn);
6058         MemberDef *md=mni.toFirst();
6059         ASSERT(md);
6060         ClassDef *cd=md->getClassDef();
6061         ASSERT(cd);
6062         QCString className=cd->name().copy();
6063         ++mni;
6064         bool unique=TRUE;
6065         for (;(md=mni.current());++mni)
6066         {
6067           ClassDef *cd=md->getClassDef();
6068           if (className!=cd->name()) unique=FALSE; 
6069         } 
6070         if (unique)
6071         {
6072           MemberDef::MemberType mtype;
6073           if      (root->mtype==Signal)  mtype=MemberDef::Signal;
6074           else if (root->mtype==Slot)    mtype=MemberDef::Slot;
6075           else if (root->mtype==DCOP)    mtype=MemberDef::DCOP;
6076           else                 mtype=MemberDef::Function;
6077           
6078           // new overloaded member function
6079           ArgumentList *tArgList = 
6080             getTemplateArgumentsFromName(cd->name()+"::"+funcName,root->tArgLists);
6081           //printf("new related member %s args=`%s'\n",md->name().data(),funcArgs.data());
6082           MemberDef *md=new MemberDef(
6083               root->fileName,root->startLine,
6084               funcType,funcName,funcArgs,exceptions,
6085               root->protection,root->virt,root->stat,Related,
6086               mtype,tArgList,root->argList);
6087           md->setTagInfo(rootNav->tagInfo());
6088           md->setLanguage(root->lang);
6089           md->setTypeConstraints(root->typeConstr);
6090           md->setMemberClass(cd);
6091           md->setDefinition(funcDecl);
6092           md->enableCallGraph(root->callGraph);
6093           md->enableCallerGraph(root->callerGraph);
6094           QCString doc=getOverloadDocs();
6095           doc+="<p>";
6096           doc+=root->doc;
6097           md->setDocumentation(doc,root->docFile,root->docLine);
6098           md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
6099           md->setDocsForDefinition(!root->proto);
6100           md->setPrototype(root->proto);
6101           md->addSectionsToDefinition(root->anchors);
6102           md->setBodySegment(root->bodyLine,root->endBodyLine);
6103           FileDef *fd=rootNav->fileDef();
6104           md->setBodyDef(fd);
6105           md->setMemberSpecifiers(root->spec);
6106           md->setMemberGroupId(root->mGrpId);
6107           mn->append(md);
6108           cd->insertMember(md);
6109           cd->insertUsedFile(root->fileName);
6110           md->setRefItems(root->sli);
6111         }
6112       }
6113       else // unrelated function with the same name as a member
6114       {
6115         if (!findGlobalMember(rootNav,namespaceName,funcName,funcTempList,funcArgs,funcDecl))
6116         {
6117           QCString fullFuncDecl=funcDecl.copy();
6118           if (isFunc) fullFuncDecl+=argListToString(root->argList,TRUE);
6119           warn(root->fileName,root->startLine,
6120                "warning: Cannot determine class for function\n%s",
6121                fullFuncDecl.data()
6122               );   
6123         }
6124       }
6125     }
6126     else if (isRelated && !root->relates.isEmpty())
6127     {
6128       Debug::print(Debug::FindMembers,0,"2. related function\n"
6129               "  scopeName=%s className=%s\n",scopeName.data(),className.data());
6130       if (className.isEmpty()) className=root->relates;
6131       ClassDef *cd;
6132       //printf("scopeName=`%s' className=`%s'\n",scopeName.data(),className.data());
6133       if ((cd=getClass(scopeName)))
6134       {
6135         bool newMember=TRUE; // assume we have a new member
6136         bool newMemberName=FALSE; 
6137         MemberDef *mdDefine=0;
6138         bool isDefine=FALSE;
6139         {
6140           MemberName *mn = Doxygen::functionNameSDict->find(funcName);
6141           if (mn)
6142           {
6143             mdDefine = mn->first();
6144             while (mdDefine && !isDefine)
6145             {
6146               isDefine = isDefine || mdDefine->isDefine();
6147               if (!isDefine) mdDefine = mn->next();
6148             }
6149           }
6150         }
6151
6152         FileDef *fd=rootNav->fileDef();
6153
6154         if ((mn=Doxygen::memberNameSDict->find(funcName))==0)
6155         {
6156           mn=new MemberName(funcName);
6157           newMemberName=TRUE; // we create a new member name
6158         }
6159         else
6160         {
6161           MemberDef *rmd=mn->first();
6162           while (rmd && newMember) // see if we got another member with matching arguments
6163           {
6164             LockingPtr<ArgumentList> rmdAl = rmd->argumentList();
6165
6166             newMember=
6167               className!=rmd->getOuterScope()->name() ||
6168               !matchArguments2(rmd->getOuterScope(),rmd->getFileDef(),rmdAl.pointer(),
6169                                cd,fd,root->argList,
6170                                TRUE);
6171             if (newMember) rmd=mn->next();
6172           }
6173           if (!newMember && rmd) // member already exists as rmd -> add docs
6174           {
6175             //printf("addMemberDocs for related member %s\n",root->name.data());
6176             //rmd->setMemberDefTemplateArguments(root->mtArgList);
6177             addMemberDocs(rootNav,rmd,funcDecl,0,overloaded);
6178           }
6179         }
6180
6181         if (newMember) // need to create a new member
6182         {
6183           MemberDef::MemberType mtype;
6184           if (isDefine)
6185             mtype=MemberDef::Define;
6186           else if (root->mtype==Signal)  
6187             mtype=MemberDef::Signal;
6188           else if (root->mtype==Slot) 
6189             mtype=MemberDef::Slot;
6190           else if (root->mtype==DCOP)
6191             mtype=MemberDef::DCOP;
6192           else
6193             mtype=MemberDef::Function;
6194
6195           if (isDefine && mdDefine)
6196           {
6197             mdDefine->setHidden(TRUE);
6198             funcType="#define";
6199             funcArgs=mdDefine->argsString();
6200             funcDecl=funcType + " " + funcName;
6201           } 
6202
6203           //printf("New related name `%s' `%d'\n",funcName.data(),
6204           //    root->argList ? (int)root->argList->count() : -1);
6205
6206           // first note that we pass:
6207           //   (root->tArgLists ? root->tArgLists->last() : 0)
6208           // for the template arguments fo the new "member."
6209           // this accurately reflects the template arguments of
6210           // the related function, which don't have to do with
6211           // those of the related class.
6212           MemberDef *md=new MemberDef(
6213               root->fileName,root->startLine,
6214               funcType,funcName,funcArgs,exceptions,
6215               root->protection,root->virt,
6216               root->stat && !isMemberOf,
6217               isMemberOf ? Foreign : isRelated ? Related : Member,
6218               mtype,
6219               (root->tArgLists ? root->tArgLists->last() : 0),
6220               funcArgs.isEmpty() ? 0 : root->argList);
6221
6222           if (isDefine && mdDefine)
6223           {
6224             md->setInitializer(mdDefine->initializer());
6225           }
6226
6227           // 
6228           // we still have the problem that
6229           // MemberDef::writeDocumentation() in memberdef.cpp
6230           // writes the template argument list for the class,
6231           // as if this member is a member of the class.
6232           // fortunately, MemberDef::writeDocumentation() has
6233           // a special mechanism that allows us to totally
6234           // override the set of template argument lists that
6235           // are printed.  We use that and set it to the
6236           // template argument lists of the related function.
6237           //
6238           md->setDefinitionTemplateParameterLists(root->tArgLists);
6239
6240           md->setTagInfo(rootNav->tagInfo());
6241
6242
6243
6244           //printf("Related member name=`%s' decl=`%s' bodyLine=`%d'\n",
6245           //       funcName.data(),funcDecl.data(),root->bodyLine);
6246
6247           // try to find the matching line number of the body from the
6248           // global function list 
6249           bool found=FALSE;
6250           if (root->bodyLine==-1)
6251           {
6252             MemberName *rmn=Doxygen::functionNameSDict->find(funcName);
6253             if (rmn)
6254             {
6255               MemberDef *rmd=rmn->first();
6256               while (rmd && !found) // see if we got another member with matching arguments
6257               {
6258                 LockingPtr<ArgumentList> rmdAl = rmd->argumentList();
6259                 // check for matching argument lists
6260                 if (
6261                     matchArguments2(rmd->getOuterScope(),rmd->getFileDef(),rmdAl.pointer(),
6262                                     cd,fd,root->argList,
6263                                     TRUE)
6264                    )
6265                 {
6266                   found=TRUE;
6267                 }
6268                 if (!found) rmd=rmn->next();
6269               }
6270               if (rmd) // member found -> copy line number info
6271               {
6272                 md->setBodySegment(rmd->getStartBodyLine(),rmd->getEndBodyLine());
6273                 md->setBodyDef(rmd->getBodyDef());
6274                 //md->setBodyMember(rmd);
6275               }
6276             }
6277           }
6278           if (!found) // line number could not be found or is available in this
6279                       // entry
6280           {
6281             md->setBodySegment(root->bodyLine,root->endBodyLine);
6282             md->setBodyDef(fd);
6283           }
6284
6285           //if (root->mGrpId!=-1) 
6286           //{
6287           //  md->setMemberGroup(memberGroupDict[root->mGrpId]);
6288           //}
6289           md->setMemberClass(cd);
6290           md->setMemberSpecifiers(root->spec);
6291           md->setDefinition(funcDecl);
6292           md->enableCallGraph(root->callGraph);
6293           md->enableCallerGraph(root->callerGraph);
6294           md->setDocumentation(root->doc,root->docFile,root->docLine);
6295           md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
6296           md->setDocsForDefinition(!root->proto);
6297           md->setPrototype(root->proto);
6298           md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
6299           md->addSectionsToDefinition(root->anchors);
6300           md->setMemberGroupId(root->mGrpId);
6301           md->setLanguage(root->lang);
6302           //md->setMemberDefTemplateArguments(root->mtArgList);
6303           mn->append(md);
6304           cd->insertMember(md);
6305           cd->insertUsedFile(root->fileName);
6306           md->setRefItems(root->sli);
6307           if (root->relatesType == Duplicate) md->setRelatedAlso(cd);
6308           if (!isDefine)
6309           {
6310             addMemberToGroups(root,md);
6311           }
6312           //printf("Adding member=%s\n",md->name().data());
6313           if (newMemberName)
6314           {
6315             //Doxygen::memberNameList.append(mn);
6316             //Doxygen::memberNameDict.insert(funcName,mn);
6317             Doxygen::memberNameSDict->append(funcName,mn);
6318           }
6319         }
6320         if (root->relatesType == Duplicate)
6321         {
6322           if (!findGlobalMember(rootNav,namespaceName,funcName,funcTempList,funcArgs,funcDecl))
6323           {
6324             QCString fullFuncDecl=funcDecl.copy();
6325             if (isFunc) fullFuncDecl+=argListToString(root->argList,TRUE);
6326             warn(root->fileName,root->startLine,
6327                "warning: Cannot determine file/namespace for relatedalso function\n%s",
6328                fullFuncDecl.data()
6329               );   
6330           }
6331         }
6332       }
6333       else
6334       {
6335         warn_undoc(root->fileName,root->startLine,
6336                    "warning: class `%s' for related function `%s' is not "
6337                    "documented.", 
6338                    className.data(),funcName.data()
6339                   );
6340       }
6341     }
6342     else if (rootNav->parent() && rootNav->parent()->section()==Entry::OBJCIMPL_SEC)
6343     {
6344 localObjCMethod:
6345       ClassDef *cd;
6346       //printf("scopeName=`%s' className=`%s'\n",scopeName.data(),className.data());
6347       if (Config_getBool("EXTRACT_LOCAL_METHODS") && (cd=getClass(scopeName)))
6348       {
6349         Debug::print(Debug::FindMembers,0,"4. Local objective C method %s\n"
6350               "  scopeName=%s className=%s\n",root->name.data(),scopeName.data(),className.data());
6351         //printf("Local objective C method `%s' of class `%s' found\n",root->name.data(),cd->name().data());
6352         MemberDef *md=new MemberDef(
6353             root->fileName,root->startLine,
6354             funcType,funcName,funcArgs,exceptions,
6355             root->protection,root->virt,root->stat,Member,
6356             MemberDef::Function,0,root->argList);
6357         md->setTagInfo(rootNav->tagInfo());
6358         md->setLanguage(root->lang);
6359         md->makeImplementationDetail();
6360         md->setMemberClass(cd);
6361         md->setDefinition(funcDecl);
6362         md->enableCallGraph(root->callGraph);
6363         md->enableCallerGraph(root->callerGraph);
6364         md->setDocumentation(root->doc,root->docFile,root->docLine);
6365         md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
6366         md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
6367         md->setDocsForDefinition(!root->proto);
6368         md->setPrototype(root->proto);
6369         md->addSectionsToDefinition(root->anchors);
6370         md->setBodySegment(root->bodyLine,root->endBodyLine);
6371         FileDef *fd=rootNav->fileDef();
6372         md->setBodyDef(fd);
6373         md->setMemberSpecifiers(root->spec);
6374         md->setMemberGroupId(root->mGrpId);
6375         cd->insertMember(md);
6376         cd->insertUsedFile(root->fileName);
6377         md->setRefItems(root->sli);
6378         if ((mn=Doxygen::memberNameSDict->find(root->name)))
6379         {
6380           mn->append(md);
6381         }
6382         else 
6383         {
6384           mn = new MemberName(root->name);
6385           mn->append(md);
6386           Doxygen::memberNameSDict->append(root->name,mn);
6387         }
6388       }
6389       else
6390       {
6391         // local objective C method found for class without interface
6392       }
6393     }
6394     else // unrelated not overloaded member found
6395     {
6396       bool globMem = findGlobalMember(rootNav,namespaceName,funcName,funcTempList,funcArgs,funcDecl);
6397       if (className.isEmpty() && !globMem)
6398       {
6399         warn(root->fileName,root->startLine,
6400              "warning: class for member `%s' cannot "
6401              "be found.", funcName.data()
6402             ); 
6403       }
6404       else if (!className.isEmpty() && !globMem)
6405       {
6406         warn(root->fileName,root->startLine,
6407              "warning: member `%s' of class `%s' cannot be found",
6408              funcName.data(),className.data());
6409       }
6410     }
6411   }
6412   else
6413   {
6414     // this should not be called
6415     warn(root->fileName,root->startLine,
6416          "warning: member with no name found.");
6417   }
6418   return;
6419
6420
6421 //----------------------------------------------------------------------
6422 // find the members corresponding to the different documentation blocks
6423 // that are extracted from the sources.
6424
6425 static void filterMemberDocumentation(EntryNav *rootNav)
6426 {
6427   Entry *root = rootNav->entry();
6428   int i=-1,l;
6429   Debug::print(Debug::FindMembers,0,
6430       "findMemberDocumentation(): root->type=`%s' root->inside=`%s' root->name=`%s' root->args=`%s' section=%x root->spec=%d root->mGrpId=%d\n",
6431       root->type.data(),root->inside.data(),root->name.data(),root->args.data(),root->section,root->spec,root->mGrpId
6432       );
6433   //printf("rootNav->parent()->name()=%s\n",rootNav->parent()->name().data());
6434   bool isFunc=TRUE;
6435
6436   if (root->relatesType == Duplicate && !root->relates.isEmpty())
6437   {
6438     QCString tmp = root->relates;
6439     root->relates.resize(0);
6440     filterMemberDocumentation(rootNav);
6441     root->relates = tmp;
6442   }
6443
6444   if ( // detect func variable/typedef to func ptr
6445       (i=findFunctionPtr(root->type,root->lang,&l))!=-1 
6446      )
6447   {
6448     //printf("Fixing function pointer!\n");
6449     // fix type and argument
6450     root->args.prepend(root->type.right(root->type.length()-i-l));
6451     root->type=root->type.left(i+l);
6452     //printf("Results type=%s,name=%s,args=%s\n",root->type.data(),root->name.data(),root->args.data());
6453     isFunc=FALSE;
6454   }
6455   else if ((root->type.left(8)=="typedef " && root->args.find('(')!=-1)) 
6456     // detect function types marked as functions
6457   {
6458     isFunc=FALSE;
6459   }
6460
6461   //printf("Member %s isFunc=%d\n",root->name.data(),isFunc);
6462   if (root->section==Entry::MEMBERDOC_SEC)
6463   {
6464     //printf("Documentation for inline member `%s' found args=`%s'\n",
6465     //    root->name.data(),root->args.data());
6466     //if (root->relates.length()) printf("  Relates %s\n",root->relates.data());
6467     if (root->type.isEmpty())
6468     {
6469       findMember(rootNav,root->name+root->args+root->exception,FALSE,isFunc);
6470     }
6471     else
6472     {
6473       findMember(rootNav,root->type+" "+root->name+root->args+root->exception,FALSE,isFunc);
6474     }
6475   }
6476   else if (root->section==Entry::OVERLOADDOC_SEC) 
6477   {
6478     //printf("Overloaded member %s found\n",root->name.data());
6479     findMember(rootNav,root->name,TRUE,isFunc);
6480   }
6481   else if 
6482     ((root->section==Entry::FUNCTION_SEC      // function
6483       ||   
6484       (root->section==Entry::VARIABLE_SEC &&  // variable
6485        !root->type.isEmpty() &&                // with a type
6486        g_compoundKeywordDict.find(root->type)==0 // that is not a keyword 
6487        // (to skip forward declaration of class etc.)
6488       )
6489      ) 
6490     )
6491     {
6492       //printf("Documentation for member `%s' found args=`%s' excp=`%s'\n",
6493       //    root->name.data(),root->args.data(),root->exception.data());
6494       //if (root->relates.length()) printf("  Relates %s\n",root->relates.data());
6495       //printf("Inside=%s\n Relates=%s\n",root->inside.data(),root->relates.data());
6496       if (root->type=="friend class" || root->type=="friend struct" || 
6497           root->type=="friend union")
6498       {
6499         findMember(rootNav,
6500             root->type+" "+
6501             root->name,
6502             FALSE,FALSE);
6503
6504       }
6505       else if (!root->type.isEmpty())
6506       {
6507         findMember(rootNav,
6508             root->type+" "+
6509             root->inside+
6510             root->name+
6511             root->args+
6512             root->exception,
6513             FALSE,isFunc);
6514       }
6515       else
6516       {
6517         findMember(rootNav,
6518             root->inside+
6519             root->name+
6520             root->args+
6521             root->exception,
6522             FALSE,isFunc);
6523       }
6524     }
6525   else if (root->section==Entry::DEFINE_SEC && !root->relates.isEmpty())
6526   {
6527     findMember(rootNav,root->name+root->args,FALSE,!root->args.isEmpty());
6528   }
6529   else if (root->section==Entry::VARIABLEDOC_SEC)
6530   {
6531     //printf("Documentation for variable %s found\n",root->name.data());
6532     //if (!root->relates.isEmpty()) printf("  Relates %s\n",root->relates.data());
6533     findMember(rootNav,root->name,FALSE,FALSE);
6534   }
6535   else
6536   {
6537     // skip section 
6538     //printf("skip section\n");
6539   }
6540 }
6541
6542 static void findMemberDocumentation(EntryNav *rootNav)
6543 {
6544   if (rootNav->section()==Entry::MEMBERDOC_SEC ||
6545       rootNav->section()==Entry::OVERLOADDOC_SEC ||
6546       rootNav->section()==Entry::FUNCTION_SEC ||
6547       rootNav->section()==Entry::VARIABLE_SEC ||
6548       rootNav->section()==Entry::VARIABLEDOC_SEC ||
6549       rootNav->section()==Entry::DEFINE_SEC
6550      )
6551   {
6552     rootNav->loadEntry(g_storage);
6553
6554     filterMemberDocumentation(rootNav);
6555
6556     rootNav->releaseEntry();
6557   }
6558   if (rootNav->children())
6559   {
6560     EntryNavListIterator eli(*rootNav->children());
6561     EntryNav *e;
6562     for (;(e=eli.current());++eli)
6563     {
6564       if (e->section()!=Entry::ENUM_SEC) findMemberDocumentation(e);
6565     }
6566   }
6567 }
6568
6569 //----------------------------------------------------------------------
6570
6571 static void findObjCMethodDefinitions(EntryNav *rootNav)
6572 {
6573   if (rootNav->children())
6574   {
6575     EntryNavListIterator eli(*rootNav->children());
6576     EntryNav *objCImplNav;
6577     for (;(objCImplNav=eli.current());++eli)
6578     {
6579       if (objCImplNav->section()==Entry::OBJCIMPL_SEC && objCImplNav->children())
6580       {
6581         EntryNavListIterator seli(*objCImplNav->children());
6582         EntryNav *objCMethodNav;
6583         for (;(objCMethodNav=seli.current());++seli)
6584         {
6585           if (objCMethodNav->section()==Entry::FUNCTION_SEC)
6586           {
6587             objCMethodNav->loadEntry(g_storage);
6588             Entry *objCMethod = objCMethodNav->entry();
6589
6590             //Printf("  Found ObjC method definition %s\n",objCMethod->name.data());
6591             findMember(objCMethodNav, objCMethod->type+" "+objCImplNav->name()+"::"+
6592                        objCMethod->name+" "+objCMethod->args, FALSE,TRUE);
6593             objCMethod->section=Entry::EMPTY_SEC;
6594
6595             objCMethodNav->releaseEntry();
6596           }
6597         }
6598       }
6599     }
6600   }
6601 }
6602
6603 //----------------------------------------------------------------------
6604 // find and add the enumeration to their classes, namespaces or files
6605
6606 static void findEnums(EntryNav *rootNav)
6607 {
6608   if (rootNav->section()==Entry::ENUM_SEC)
6609     // non anonymous enumeration
6610   {
6611     rootNav->loadEntry(g_storage);
6612     Entry *root = rootNav->entry();
6613
6614     MemberDef      *md=0;
6615     ClassDef       *cd=0;
6616     FileDef        *fd=0;
6617     NamespaceDef   *nd=0;
6618     MemberNameSDict *mnsd=0;
6619     bool isGlobal;
6620     bool isRelated=FALSE;
6621     bool isMemberOf=FALSE;
6622     //printf("Found enum with name `%s' relates=%s\n",root->name.data(),root->relates.data());
6623     int i;
6624
6625     QCString name;
6626     QCString scope;
6627
6628     if ((i=root->name.findRev("::"))!=-1) // scope is specified
6629     {
6630       scope=root->name.left(i); // extract scope
6631       name=root->name.right(root->name.length()-i-2); // extract name
6632       if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope);
6633     }
6634     else // no scope, check the scope in which the docs where found
6635     {
6636       if (( rootNav->parent()->section() & Entry::SCOPE_MASK )
6637           && !rootNav->parent()->name().isEmpty()
6638          ) // found enum docs inside a compound
6639       {
6640         scope=rootNav->parent()->name();
6641         if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope);
6642       }
6643       name=root->name;
6644     }
6645
6646     if (!root->relates.isEmpty()) 
6647     {   // related member, prefix user specified scope
6648       isRelated=TRUE;
6649       isMemberOf=(root->relatesType == MemberOf);
6650       if (getClass(root->relates)==0 && !scope.isEmpty())
6651         scope=mergeScopes(scope,root->relates);
6652       else 
6653         scope=root->relates.copy();
6654       if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope);
6655     }
6656
6657     if (cd && !name.isEmpty()) // found a enum inside a compound
6658     {
6659       //printf("Enum `%s'::`%s'\n",cd->name(),name.data());
6660       fd=0;
6661       mnsd=Doxygen::memberNameSDict;
6662       isGlobal=FALSE;
6663     }
6664     else if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@') // found enum inside namespace
6665     {
6666       mnsd=Doxygen::functionNameSDict;
6667       isGlobal=TRUE;
6668     }
6669     else // found a global enum
6670     {
6671       fd=rootNav->fileDef();
6672       mnsd=Doxygen::functionNameSDict;
6673       isGlobal=TRUE;
6674     }
6675
6676     if (!name.isEmpty())
6677     {
6678       // new enum type
6679       md = new MemberDef(
6680           root->fileName,root->startLine,
6681           0,name,0,0,
6682           root->protection,Normal,FALSE,
6683           isMemberOf ? Foreign : isRelated ? Related : Member,
6684           MemberDef::Enumeration,
6685           0,0);
6686       md->setTagInfo(rootNav->tagInfo());
6687       md->setLanguage(root->lang);
6688       if (!isGlobal) md->setMemberClass(cd); else md->setFileDef(fd);
6689       md->setBodySegment(root->bodyLine,root->endBodyLine);
6690       md->setBodyDef(rootNav->fileDef());
6691       md->setEnumBaseType(root->args);
6692       //printf("Enum %s definition at line %d of %s: protection=%d\n",
6693       //    root->name.data(),root->bodyLine,root->fileName.data(),root->protection);
6694       md->addSectionsToDefinition(root->anchors);
6695       md->setMemberGroupId(root->mGrpId);
6696       md->enableCallGraph(root->callGraph);
6697       md->enableCallerGraph(root->callerGraph);
6698       //printf("%s::setRefItems(%d)\n",md->name().data(),root->sli?root->sli->count():-1);
6699       md->setRefItems(root->sli);
6700       //printf("found enum %s nd=%p\n",name.data(),nd);
6701       bool defSet=FALSE;
6702
6703       QCString baseType = root->args;
6704       if (!baseType.isEmpty())
6705       {
6706         baseType.prepend(" : ");
6707       }
6708
6709       if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@')
6710       {
6711         if (isRelated || Config_getBool("HIDE_SCOPE_NAMES"))
6712         {
6713           md->setDefinition(name+baseType);  
6714         }
6715         else
6716         {
6717           md->setDefinition(nd->name()+"::"+name+baseType);  
6718         }
6719         //printf("definition=%s\n",md->definition());
6720         defSet=TRUE;
6721         md->setNamespace(nd);
6722         nd->insertMember(md);
6723       }
6724
6725       // even if we have already added the enum to a namespace, we still
6726       // also want to add it to other appropriate places such as file
6727       // or class.
6728       if (isGlobal)
6729       {
6730         if (!defSet) md->setDefinition(name+baseType);
6731         if (fd==0 && rootNav->parent())
6732         {
6733           fd=rootNav->parent()->fileDef();
6734         }
6735         if (fd) 
6736         {
6737           md->setFileDef(fd);
6738           fd->insertMember(md);
6739         }
6740       }
6741       else if (cd)
6742       {
6743         if (isRelated || Config_getBool("HIDE_SCOPE_NAMES"))
6744         {
6745           md->setDefinition(name+baseType);  
6746         }
6747         else
6748         {
6749           md->setDefinition(cd->name()+"::"+name+baseType);  
6750         }
6751         cd->insertMember(md);
6752         cd->insertUsedFile(root->fileName);
6753       }
6754       md->setDocumentation(root->doc,root->docFile,root->docLine);
6755       md->setDocsForDefinition(!root->proto);
6756       md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
6757       md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
6758
6759       //printf("Adding member=%s\n",md->name().data());
6760       MemberName *mn;
6761       if ((mn=(*mnsd)[name]))
6762       {
6763         // this is used if the same enum is in multiple namespaces/classes
6764         mn->append(md);
6765       }
6766       else // new enum name
6767       {
6768         mn = new MemberName(name);
6769         mn->append(md);
6770         mnsd->append(name,mn);
6771         //printf("add %s to new memberName. Now %d members\n",
6772         //       name.data(),mn->count());
6773       }
6774       addMemberToGroups(root,md);
6775
6776 #if 0
6777       if (rootNav->children())
6778       {
6779         EntryNavListIterator eli(*rootNav->children());
6780         EntryNav *e;
6781         for (;(e=eli.current());++eli)
6782         {
6783           //printf("e->name=%s isRelated=%d\n",e->name.data(),isRelated);
6784           MemberName *fmn=0;
6785           MemberNameSDict *emnsd = isRelated ? Doxygen::functionNameSDict : mnsd;
6786           if (!e->name().isEmpty() && (fmn=(*emnsd)[e->name()])) 
6787             // get list of members with the same name as the field
6788           {
6789             MemberNameIterator fmni(*fmn);
6790             MemberDef *fmd;
6791             for (fmni.toFirst(); (fmd=fmni.current()) ; ++fmni) 
6792             {
6793               if (fmd->isEnumValue())
6794               {
6795                 //printf("found enum value with same name\n");
6796                 if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@')
6797                 {
6798                   NamespaceDef *fnd=fmd->getNamespaceDef();
6799                   if (fnd==nd) // enum value is inside a namespace
6800                   {
6801                     md->insertEnumField(fmd);
6802                     fmd->setEnumScope(md);
6803                   }
6804                 }
6805                 else if (isGlobal)
6806                 {
6807                   FileDef *ffd=fmd->getFileDef();
6808                   if (ffd==fd) // enum value has file scope
6809                   {
6810                     md->insertEnumField(fmd);
6811                     fmd->setEnumScope(md);
6812                   }
6813                 }
6814                 else if (isRelated && cd) // reparent enum value to
6815                   // match the enum's scope
6816                 {
6817                   md->insertEnumField(fmd);   // add field def to list
6818                   fmd->setEnumScope(md);      // cross ref with enum name
6819                   fmd->setEnumClassScope(cd); // cross ref with enum name
6820                   fmd->setOuterScope(cd);
6821                   fmd->makeRelated();
6822                   cd->insertMember(fmd);
6823                 }
6824                 else
6825                 {
6826                   ClassDef *fcd=fmd->getClassDef();
6827                   if (fcd==cd) // enum value is inside a class
6828                   {
6829                     //printf("Inserting enum field %s in enum scope %s\n",
6830                     //    fmd->name().data(),md->name().data());
6831                     md->insertEnumField(fmd); // add field def to list
6832                     fmd->setEnumScope(md);    // cross ref with enum name
6833                   }
6834                 }
6835               } 
6836             }
6837           }
6838         }
6839       }
6840 #endif
6841     }
6842
6843     rootNav->releaseEntry();
6844   }
6845   else
6846   {
6847     RECURSE_ENTRYTREE(findEnums,rootNav);
6848   }
6849 }
6850
6851 //----------------------------------------------------------------------
6852
6853 static void addEnumValuesToEnums(EntryNav *rootNav)
6854 {
6855   if (rootNav->section()==Entry::ENUM_SEC)
6856     // non anonymous enumeration
6857   {
6858     rootNav->loadEntry(g_storage);
6859     Entry *root = rootNav->entry();
6860
6861     ClassDef       *cd=0;
6862     FileDef        *fd=0;
6863     NamespaceDef   *nd=0;
6864     MemberNameSDict *mnsd=0;
6865     bool isGlobal;
6866     bool isRelated=FALSE;
6867     //printf("Found enum with name `%s' relates=%s\n",root->name.data(),root->relates.data());
6868     int i;
6869
6870     QCString name;
6871     QCString scope;
6872
6873     if ((i=root->name.findRev("::"))!=-1) // scope is specified
6874     {
6875       scope=root->name.left(i); // extract scope
6876       name=root->name.right(root->name.length()-i-2); // extract name
6877       if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope);
6878     }
6879     else // no scope, check the scope in which the docs where found
6880     {
6881       if (( rootNav->parent()->section() & Entry::SCOPE_MASK )
6882           && !rootNav->parent()->name().isEmpty()
6883          ) // found enum docs inside a compound
6884       {
6885         scope=rootNav->parent()->name();
6886         if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope);
6887       }
6888       name=root->name;
6889     }
6890
6891     if (!root->relates.isEmpty()) 
6892     {   // related member, prefix user specified scope
6893       isRelated=TRUE;
6894       if (getClass(root->relates)==0 && !scope.isEmpty())
6895         scope=mergeScopes(scope,root->relates);
6896       else 
6897         scope=root->relates.copy();
6898       if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope);
6899     }
6900
6901     if (cd && !name.isEmpty()) // found a enum inside a compound
6902     {
6903       //printf("Enum in class `%s'::`%s'\n",cd->name().data(),name.data());
6904       fd=0;
6905       mnsd=Doxygen::memberNameSDict;
6906       isGlobal=FALSE;
6907     }
6908     else if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@') // found enum inside namespace
6909     {
6910       //printf("Enum in namespace `%s'::`%s'\n",nd->name().data(),name.data());
6911       mnsd=Doxygen::functionNameSDict;
6912       isGlobal=TRUE;
6913     }
6914     else // found a global enum
6915     {
6916       fd=rootNav->fileDef();
6917       //printf("Enum in file `%s': `%s'\n",fd->name().data(),name.data());
6918       mnsd=Doxygen::functionNameSDict;
6919       isGlobal=TRUE;
6920     }
6921
6922     if (!name.isEmpty())
6923     {
6924       //printf("** name=%s\n",name.data());
6925       MemberName *mn = mnsd->find(name); // for all members with this name
6926       if (mn)
6927       {
6928         MemberNameIterator mni(*mn);
6929         MemberDef *md;
6930         for (mni.toFirst(); (md=mni.current()) ; ++mni)  // for each enum in this list
6931         {
6932           if (md->isEnumerate() && rootNav->children())
6933           {
6934             //printf("   enum with %d children\n",rootNav->children()->count());
6935             EntryNavListIterator eli(*rootNav->children()); // for each enum value
6936             EntryNav *e;
6937             for (;(e=eli.current());++eli)
6938             {
6939               SrcLangExt sle;
6940               if (
6941                    (sle=rootNav->lang())==SrcLangExt_CSharp || 
6942                    sle==SrcLangExt_Java || 
6943                    sle==SrcLangExt_XML ||
6944                    (root->spec&Entry::Strong)
6945                  )
6946               {
6947                 // Unlike classic C/C++ enums, for C++11, C# & Java enum 
6948                 // values are only inside the enum scope, so we must create 
6949                 // them here and only add them to the enum
6950                 e->loadEntry(g_storage);
6951                 Entry *root = e->entry();
6952                 //printf("md->qualifiedName()=%s rootNav->name()=%s\n",
6953                 //    md->qualifiedName().data(),rootNav->name().data());
6954                 if (md->qualifiedName()==substitute(rootNav->name(),"::",".")) // enum value scope matches that of the enum
6955                 {
6956                   MemberDef *fmd=new MemberDef(
6957                       root->fileName,root->startLine,
6958                       root->type,root->name,root->args,0,
6959                       Public, Normal,root->stat,Member,
6960                       MemberDef::EnumValue,0,0);
6961                   if (md->getClassDef()) fmd->setMemberClass(md->getClassDef());
6962                   else if (md->getNamespaceDef()) fmd->setNamespace(md->getNamespaceDef());
6963                   else if (md->getFileDef()) fmd->setFileDef(md->getFileDef());
6964                   fmd->setOuterScope(md->getOuterScope());
6965                   fmd->setTagInfo(e->tagInfo());
6966                   fmd->setLanguage(root->lang);
6967                   fmd->setDocumentation(root->doc,root->docFile,root->docLine);
6968                   fmd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
6969                   fmd->addSectionsToDefinition(root->anchors);
6970                   fmd->setInitializer(root->initializer);
6971                   fmd->setMaxInitLines(root->initLines);
6972                   fmd->setMemberGroupId(root->mGrpId);
6973                   fmd->setExplicitExternal(root->explicitExternal);
6974                   fmd->setRefItems(root->sli);
6975                   if (fmd)
6976                   {
6977                     md->insertEnumField(fmd);
6978                     fmd->setEnumScope(md);
6979                   }
6980                 }
6981                 e->releaseEntry();
6982               }
6983               else
6984               {
6985                 //printf("e->name=%s isRelated=%d\n",e->name().data(),isRelated);
6986                 MemberName *fmn=0;
6987                 MemberNameSDict *emnsd = isRelated ? Doxygen::functionNameSDict : mnsd;
6988                 if (!e->name().isEmpty() && (fmn=(*emnsd)[e->name()])) 
6989                   // get list of members with the same name as the field
6990                 {
6991                   MemberNameIterator fmni(*fmn);
6992                   MemberDef *fmd;
6993                   for (fmni.toFirst(); (fmd=fmni.current()) ; ++fmni) 
6994                   {
6995                     if (fmd->isEnumValue() && fmd->getOuterScope()==md->getOuterScope()) // in same scope
6996                     {
6997                       //printf("found enum value with same name %s in scope %s\n",
6998                       //    fmd->name().data(),fmd->getOuterScope()->name().data());
6999                       if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@')
7000                       {
7001                         NamespaceDef *fnd=fmd->getNamespaceDef();
7002                         if (fnd==nd) // enum value is inside a namespace
7003                         {
7004                           md->insertEnumField(fmd);
7005                           fmd->setEnumScope(md);
7006                         }
7007                       }
7008                       else if (isGlobal)
7009                       {
7010                         FileDef *ffd=fmd->getFileDef();
7011                         if (ffd==fd) // enum value has file scope
7012                         {
7013                           md->insertEnumField(fmd);
7014                           fmd->setEnumScope(md);
7015                         }
7016                       }
7017                       else if (isRelated && cd) // reparent enum value to
7018                                                 // match the enum's scope
7019                       {
7020                         md->insertEnumField(fmd);   // add field def to list
7021                         fmd->setEnumScope(md);      // cross ref with enum name
7022                         fmd->setEnumClassScope(cd); // cross ref with enum name
7023                         fmd->setOuterScope(cd);
7024                         fmd->makeRelated();
7025                         cd->insertMember(fmd);
7026                       }
7027                       else
7028                       {
7029                         ClassDef *fcd=fmd->getClassDef();
7030                         if (fcd==cd) // enum value is inside a class
7031                         {
7032                           //printf("Inserting enum field %s in enum scope %s\n",
7033                           //    fmd->name().data(),md->name().data());
7034                           md->insertEnumField(fmd); // add field def to list
7035                           fmd->setEnumScope(md);    // cross ref with enum name
7036                         }
7037                       }
7038                     } 
7039                   }
7040                 }
7041               }
7042             }
7043           }
7044         }
7045       }
7046     }
7047
7048     rootNav->releaseEntry();
7049   }
7050   else
7051   {
7052     RECURSE_ENTRYTREE(addEnumValuesToEnums,rootNav);
7053   }
7054 }
7055
7056
7057 //----------------------------------------------------------------------
7058 // find the documentation blocks for the enumerations
7059
7060 static void findEnumDocumentation(EntryNav *rootNav)
7061 {
7062   if (rootNav->section()==Entry::ENUMDOC_SEC
7063       && !rootNav->name().isEmpty()
7064       && rootNav->name().at(0)!='@'        // skip anonymous enums
7065      )
7066   {
7067     rootNav->loadEntry(g_storage);
7068     Entry *root = rootNav->entry();
7069
7070     //printf("Found docs for enum with name `%s' in context %s\n",
7071     //    root->name.data(),root->parent->name.data());
7072     int i;
7073     QCString name;
7074     QCString scope;
7075     if ((i=root->name.findRev("::"))!=-1) // scope is specified as part of the name
7076     {
7077       name=root->name.right(root->name.length()-i-2); // extract name
7078       scope=root->name.left(i); // extract scope
7079       //printf("Scope=`%s' Name=`%s'\n",scope.data(),name.data());
7080     }
7081     else // just the name
7082     {
7083       name=root->name;
7084     }
7085     if (( rootNav->parent()->section() & Entry::SCOPE_MASK )
7086         && !rootNav->parent()->name().isEmpty()
7087        ) // found enum docs inside a compound
7088     {
7089       if (!scope.isEmpty()) scope.prepend("::");
7090       scope.prepend(rootNav->parent()->name());
7091     }
7092     ClassDef *cd=getClass(scope);
7093
7094     if (!name.isEmpty())
7095     {
7096       bool found=FALSE;
7097       if (cd)
7098       {
7099         //printf("Enum: scope=`%s' name=`%s'\n",cd->name(),name.data());
7100         QCString className=cd->name().copy();
7101         MemberName *mn=Doxygen::memberNameSDict->find(name);
7102         if (mn)
7103         {
7104           MemberNameIterator mni(*mn);
7105           MemberDef *md;
7106           for (mni.toFirst();(md=mni.current()) && !found;++mni)
7107           {
7108             ClassDef *cd=md->getClassDef();
7109             if (cd && cd->name()==className && md->isEnumerate())
7110             {
7111               // documentation outside a compound overrides the documentation inside it
7112 #if 0
7113               if (!md->documentation() || rootNav->parent()->name().isEmpty()) 
7114 #endif
7115               {
7116                 md->setDocumentation(root->doc,root->docFile,root->docLine);
7117                 md->setDocsForDefinition(!root->proto);
7118               }
7119
7120               // brief descriptions inside a compound override the documentation 
7121               // outside it
7122 #if 0
7123               if (!md->briefDescription() || !rootNav->parent()->name().isEmpty())
7124 #endif
7125               {
7126                 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
7127               }
7128
7129               if (!md->inbodyDocumentation() || !rootNav->parent()->name().isEmpty())
7130               {
7131                 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
7132               }
7133
7134               if (root->mGrpId!=-1 && md->getMemberGroupId()==-1)
7135               {
7136                 md->setMemberGroupId(root->mGrpId);
7137               }
7138
7139               md->addSectionsToDefinition(root->anchors);
7140               md->setRefItems(root->sli);
7141
7142               GroupDef *gd=md->getGroupDef();
7143               if (gd==0 &&root->groups->first()!=0) // member not grouped but out-of-line documentation is
7144               {
7145                 addMemberToGroups(root,md);
7146               }
7147
7148               found=TRUE;
7149             }
7150           }
7151         }
7152         else
7153         {
7154           //printf("MemberName %s not found!\n",name.data());
7155         }
7156       }
7157       else // enum outside class 
7158       {
7159         //printf("Enum outside class: %s grpId=%d\n",name.data(),root->mGrpId);
7160         MemberName *mn=Doxygen::functionNameSDict->find(name);
7161         if (mn)
7162         {
7163           MemberNameIterator mni(*mn);
7164           MemberDef *md;
7165           for (mni.toFirst();(md=mni.current()) && !found;++mni)
7166           {
7167             if (md->isEnumerate())
7168             {
7169               md->setDocumentation(root->doc,root->docFile,root->docLine);
7170               md->setDocsForDefinition(!root->proto);
7171               md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
7172               md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
7173               md->addSectionsToDefinition(root->anchors);
7174               md->setMemberGroupId(root->mGrpId);
7175
7176               GroupDef *gd=md->getGroupDef();
7177               if (gd==0 && root->groups->first()!=0) // member not grouped but out-of-line documentation is
7178               {
7179                 addMemberToGroups(root,md);
7180               }
7181
7182               found=TRUE;
7183             }
7184           }
7185         }
7186       } 
7187       if (!found)
7188       {
7189         warn(root->fileName,root->startLine,
7190              "warning: Documentation for undefined enum `%s' found.",
7191              name.data()
7192             );
7193       }
7194     }
7195
7196     rootNav->releaseEntry();
7197   }
7198   RECURSE_ENTRYTREE(findEnumDocumentation,rootNav);
7199 }
7200
7201 // search for each enum (member or function) in mnl if it has documented 
7202 // enum values.
7203 static void findDEV(const MemberNameSDict &mnsd)
7204 {
7205   MemberName *mn;
7206   MemberNameSDict::Iterator mnli(mnsd);
7207   // for each member name
7208   for (mnli.toFirst();(mn=mnli.current());++mnli)
7209   {
7210     MemberDef *md;
7211     MemberNameIterator mni(*mn);
7212     // for each member definition
7213     for (mni.toFirst();(md=mni.current());++mni)
7214     {
7215       if (md->isEnumerate()) // member is an enum
7216       {
7217         LockingPtr<MemberList> fmdl = md->enumFieldList();
7218         int documentedEnumValues=0;
7219         if (fmdl!=0) // enum has values
7220         {
7221           MemberListIterator fmni(*fmdl);
7222           MemberDef *fmd;
7223           // for each enum value
7224           for (fmni.toFirst();(fmd=fmni.current());++fmni)
7225           {
7226             if (fmd->isLinkableInProject()) documentedEnumValues++;
7227           }
7228         }
7229         // at least one enum value is documented
7230         if (documentedEnumValues>0) md->setDocumentedEnumValues(TRUE);
7231       }
7232     }
7233   }
7234 }
7235
7236 // search for each enum (member or function) if it has documented enum 
7237 // values.
7238 static void findDocumentedEnumValues()
7239 {
7240   findDEV(*Doxygen::memberNameSDict);
7241   findDEV(*Doxygen::functionNameSDict); 
7242 }
7243
7244 //----------------------------------------------------------------------
7245
7246 static void addMembersToIndex()
7247 {
7248   MemberName *mn;
7249   MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
7250   // for each member name
7251   for (mnli.toFirst();(mn=mnli.current());++mnli)
7252   {
7253     MemberDef *md;
7254     MemberNameIterator mni(*mn);
7255     // for each member definition
7256     for (mni.toFirst();(md=mni.current());++mni)
7257     {
7258       addClassMemberNameToIndex(md);
7259     }
7260   }
7261   MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict);
7262   // for each member name
7263   for (fnli.toFirst();(mn=fnli.current());++fnli)
7264   {
7265     MemberDef *md;
7266     MemberNameIterator mni(*mn);
7267     // for each member definition
7268     for (mni.toFirst();(md=mni.current());++mni)
7269     {
7270       if (md->getNamespaceDef())
7271       {
7272         addNamespaceMemberNameToIndex(md);
7273       }
7274       else
7275       {
7276         addFileMemberNameToIndex(md);
7277       }
7278     }
7279   }
7280 }
7281
7282 //----------------------------------------------------------------------
7283 // computes the relation between all members. For each member `m'
7284 // the members that override the implementation of `m' are searched and
7285 // the member that `m' overrides is searched.
7286
7287 static void computeMemberRelations()
7288 {
7289   MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
7290   MemberName *mn;
7291   for ( ; (mn=mnli.current()) ; ++mnli ) // for each member name
7292   {
7293     MemberNameIterator mdi(*mn);
7294     MemberDef *md;
7295     for ( ; (md=mdi.current()) ; ++mdi ) // for each member with a specific name
7296     {
7297       MemberDef *bmd = mn->first(); // for each other member with the same name
7298       while (bmd)
7299       {
7300         ClassDef *mcd  = md->getClassDef();
7301         if (mcd && mcd->baseClasses())
7302         {
7303           ClassDef *bmcd = bmd->getClassDef();
7304           //printf("Check relation between `%s'::`%s' (%p) and `%s'::`%s' (%p)\n",
7305           //      mcd->name().data(),md->name().data(),md,
7306           //       bmcd->name().data(),bmd->name().data(),bmd
7307           //      );
7308           if (md!=bmd && bmd->virtualness()!=Normal && md->isFunction() && 
7309               bmcd && mcd && mcd->isLinkable() && bmcd->isLinkable() &&
7310               bmcd!=mcd && mcd->isBaseClass(bmcd,TRUE))
7311           {
7312             //printf("  derived scope\n");
7313             LockingPtr<ArgumentList> bmdAl = bmd->argumentList();
7314             LockingPtr<ArgumentList>  mdAl =  md->argumentList();
7315             //printf(" Base argList=`%s'\n Super argList=`%s'\n",
7316             //        argListToString(bmdAl.pointer()).data(),
7317             //        argListToString(mdAl.pointer()).data()
7318             //      );
7319             if ( 
7320                 matchArguments2(bmd->getOuterScope(),bmd->getFileDef(),bmdAl.pointer(),
7321                   md->getOuterScope(), md->getFileDef(), mdAl.pointer(),
7322                   TRUE
7323                   ) 
7324                )
7325             {
7326               MemberDef *rmd;
7327               if ((rmd=md->reimplements())==0 ||
7328                   minClassDistance(mcd,bmcd)<minClassDistance(mcd,rmd->getClassDef())
7329                  )
7330               {
7331                 //printf("setting (new) reimplements member\n");
7332                 md->setReimplements(bmd);
7333               }
7334               //printf("%s: add reimplementedBy member %s\n",bmcd->name().data(),mcd->name().data());
7335               bmd->insertReimplementedBy(md);
7336             }
7337           }
7338         }
7339         bmd = mn->next();
7340       }
7341     }
7342   }  
7343 }
7344
7345
7346 //----------------------------------------------------------------------------
7347 //static void computeClassImplUsageRelations()
7348 //{
7349 //  ClassDef *cd;
7350 //  ClassSDict::Iterator cli(*Doxygen::classSDict);
7351 //  for (;(cd=cli.current());++cli)
7352 //  {
7353 //    cd->determineImplUsageRelation();
7354 //  }
7355 //}
7356
7357 //----------------------------------------------------------------------------
7358
7359 static void createTemplateInstanceMembers()
7360 {
7361   ClassSDict::Iterator cli(*Doxygen::classSDict);
7362   ClassDef *cd;
7363   // for each class
7364   for (cli.toFirst();(cd=cli.current());++cli)
7365   {
7366     // that is a template
7367     QDict<ClassDef> *templInstances = cd->getTemplateInstances();
7368     if (templInstances)
7369     {
7370       QDictIterator<ClassDef> qdi(*templInstances);
7371       ClassDef *tcd=0;
7372       // for each instance of the template
7373       for (qdi.toFirst();(tcd=qdi.current());++qdi)
7374       {
7375         tcd->addMembersToTemplateInstance(cd,qdi.currentKey());
7376       }
7377     }
7378   }
7379 }
7380
7381 //----------------------------------------------------------------------------
7382
7383 static void mergeCategories()
7384 {
7385   ClassDef *cd;
7386   ClassSDict::Iterator cli(*Doxygen::classSDict);
7387   // merge members of categories into the class they extend
7388   for (cli.toFirst();(cd=cli.current());++cli)
7389   {
7390     int i=cd->name().find('(');
7391     if (i!=-1) // it is an Objective-C category
7392     {
7393       QCString baseName=cd->name().left(i);
7394       ClassDef *baseClass=Doxygen::classSDict->find(baseName);
7395       if (baseClass)
7396       {
7397         //printf("*** merging members of category %s into %s\n",
7398         //    cd->name().data(),baseClass->name().data());
7399         baseClass->mergeCategory(cd);
7400       }
7401     }
7402   }
7403 }
7404
7405 // builds the list of all members for each class
7406
7407 static void buildCompleteMemberLists()
7408 {
7409   ClassDef *cd;
7410   ClassSDict::Iterator cli(*Doxygen::classSDict);
7411   // merge the member list of base classes into the inherited classes.
7412   for (cli.toFirst();(cd=cli.current());++cli)
7413   {
7414     if (// !cd->isReference() && // not an external class
7415          cd->subClasses()==0 && // is a root of the hierarchy
7416          cd->baseClasses()) // and has at least one base class
7417     {
7418       //printf("*** merging members for %s\n",cd->name().data());
7419       cd->mergeMembers();
7420     }
7421   }
7422   // now sort the member list of all classes.
7423   for (cli.toFirst();(cd=cli.current());++cli)
7424   {
7425     if (cd->memberNameInfoSDict()) cd->memberNameInfoSDict()->sort();
7426   }
7427 }
7428
7429 //----------------------------------------------------------------------------
7430
7431 static void generateFileSources()
7432 {
7433   if (documentedHtmlFiles==0) return;
7434   if (Doxygen::inputNameList->count()>0)
7435   {
7436     FileNameListIterator fnli(*Doxygen::inputNameList); 
7437     FileName *fn;
7438     for (;(fn=fnli.current());++fnli)
7439     {
7440       FileNameIterator fni(*fn);
7441       FileDef *fd;
7442       for (;(fd=fni.current());++fni)
7443       {
7444         if (fd->generateSourceFile()) // sources need to be shown in the output
7445         {
7446           msg("Generating code for file %s...\n",fd->docName().data());
7447           fd->writeSource(*g_outputList);
7448         }
7449         else if (!fd->isReference() && Doxygen::parseSourcesNeeded)
7450           // we needed to parse the sources even if we do not show them
7451         {
7452           msg("Parsing code for file %s...\n",fd->docName().data());
7453           fd->parseSource();
7454         }
7455       }
7456     }
7457   }
7458 }
7459
7460 //----------------------------------------------------------------------------
7461
7462 static void generateFileDocs()
7463 {
7464   if (documentedHtmlFiles==0) return;
7465   
7466   if (Doxygen::inputNameList->count()>0)
7467   {
7468     FileNameListIterator fnli(*Doxygen::inputNameList);
7469     FileName *fn;
7470     for (fnli.toFirst();(fn=fnli.current());++fnli)
7471     {
7472       FileNameIterator fni(*fn);
7473       FileDef *fd;
7474       for (fni.toFirst();(fd=fni.current());++fni)
7475       {
7476         bool doc = fd->isLinkableInProject();
7477         if (doc)
7478         {
7479           msg("Generating docs for file %s...\n",fd->docName().data());
7480           fd->writeDocumentation(*g_outputList);
7481         }
7482       }
7483     }
7484   }
7485 }
7486
7487 //----------------------------------------------------------------------------
7488
7489 static void addSourceReferences()
7490 {
7491   // add source references for class definitions
7492   ClassSDict::Iterator cli(*Doxygen::classSDict);
7493   ClassDef *cd=0;
7494   for (cli.toFirst();(cd=cli.current());++cli)
7495   {
7496     FileDef *fd=cd->getBodyDef();
7497     if (fd && cd->isLinkableInProject() && cd->getStartBodyLine()!=-1)
7498     {
7499       fd->addSourceRef(cd->getStartBodyLine(),cd,0);
7500     }
7501   }
7502   // add source references for namespace definitions
7503   NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
7504   NamespaceDef *nd=0;
7505   for (nli.toFirst();(nd=nli.current());++nli)
7506   {
7507     FileDef *fd=nd->getBodyDef();
7508     if (fd && nd->isLinkableInProject() && nd->getStartBodyLine()!=-1)
7509     {
7510       fd->addSourceRef(nd->getStartBodyLine(),nd,0);
7511     }
7512   }
7513   
7514   // add source references for member names
7515   MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
7516   MemberName *mn=0;
7517   for (mnli.toFirst();(mn=mnli.current());++mnli)
7518   {
7519     MemberNameIterator mni(*mn);
7520     MemberDef *md=0;
7521     for (mni.toFirst();(md=mni.current());++mni)
7522     {
7523       //printf("class member %s: def=%s body=%d link?=%d\n",
7524       //    md->name().data(),
7525       //    md->getBodyDef()?md->getBodyDef()->name().data():"<none>",
7526       //    md->getStartBodyLine(),md->isLinkableInProject());
7527       FileDef *fd=md->getBodyDef();
7528       if (fd && 
7529           md->getStartBodyLine()!=-1 &&
7530           md->isLinkableInProject() &&
7531           (fd->generateSourceFile() || Doxygen::parseSourcesNeeded)
7532          )
7533       {
7534         //printf("Found member `%s' in file `%s' at line `%d' def=%s\n",
7535         //    md->name().data(),fd->name().data(),md->getStartBodyLine(),md->getOuterScope()->name().data()); 
7536         fd->addSourceRef(md->getStartBodyLine(),md->getOuterScope(),md);
7537       }
7538     }
7539   }
7540   MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict);
7541   for (fnli.toFirst();(mn=fnli.current());++fnli)
7542   {
7543     MemberNameIterator mni(*mn);
7544     MemberDef *md=0;
7545     for (mni.toFirst();(md=mni.current());++mni)
7546     {
7547       FileDef *fd=md->getBodyDef();
7548       //printf("member %s body=[%d,%d] fd=%p link=%d parseSources=%d\n",
7549       //    md->name().data(),
7550       //    md->getStartBodyLine(),md->getEndBodyLine(),fd,
7551       //    md->isLinkableInProject(),
7552       //    Doxygen::parseSourcesNeeded);
7553       if (fd && 
7554           md->getStartBodyLine()!=-1 && 
7555           md->isLinkableInProject() && 
7556           (fd->generateSourceFile() || Doxygen::parseSourcesNeeded)
7557          )
7558       {
7559         //printf("Found member `%s' in file `%s' at line `%d' def=%s\n",
7560         //    md->name().data(),fd->name().data(),md->getStartBodyLine(),md->getOuterScope()->name().data()); 
7561         fd->addSourceRef(md->getStartBodyLine(),md->getOuterScope(),md);
7562       }  
7563     }
7564   }
7565 }
7566
7567 //----------------------------------------------------------------------------
7568
7569 static void sortMemberLists()
7570 {
7571   // sort class member lists
7572   ClassSDict::Iterator cli(*Doxygen::classSDict);
7573   ClassDef *cd=0;
7574   for (cli.toFirst();(cd=cli.current());++cli)
7575   {
7576     cd->sortMemberLists();
7577   }
7578
7579   // sort namespace member lists
7580   NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
7581   NamespaceDef *nd=0;
7582   for (nli.toFirst();(nd=nli.current());++nli)
7583   {
7584     nd->sortMemberLists();
7585   }
7586
7587   // sort file member lists
7588   FileNameListIterator fnli(*Doxygen::inputNameList); 
7589   FileName *fn;
7590   for (;(fn=fnli.current());++fnli)
7591   {
7592     FileNameIterator fni(*fn);
7593     FileDef *fd;
7594     for (;(fd=fni.current());++fni)
7595     {
7596       fd->sortMemberLists();
7597     }
7598   }
7599
7600   // sort group member lists
7601   GroupSDict::Iterator gli(*Doxygen::groupSDict);
7602   GroupDef *gd;
7603   for (gli.toFirst();(gd=gli.current());++gli)
7604   {
7605     gd->sortMemberLists();
7606   }
7607 }
7608
7609 //----------------------------------------------------------------------------
7610 // generate the documentation of all classes
7611   
7612 static void generateClassList(ClassSDict &classSDict)
7613 {
7614   ClassSDict::Iterator cli(classSDict);
7615   for ( ; cli.current() ; ++cli )
7616   {
7617     ClassDef *cd=cli.current();
7618    
7619     //printf("cd=%s getOuterScope=%p global=%p\n",cd->name().data(),cd->getOuterScope(),Doxygen::globalScope);
7620     if ((cd->getOuterScope()==0 || // <-- should not happen, but can if we read an old tag file
7621          cd->getOuterScope()==Doxygen::globalScope // only look at global classes
7622         ) && !cd->isHidden() && !cd->isEmbeddedInOuterScope()
7623        ) 
7624     {
7625       // skip external references, anonymous compounds and 
7626       // template instances 
7627       if ( cd->isLinkableInProject() && cd->templateMaster()==0)
7628       {
7629         msg("Generating docs for compound %s...\n",cd->name().data());
7630
7631         cd->writeDocumentation(*g_outputList);
7632         cd->writeMemberList(*g_outputList);
7633       }
7634       // even for undocumented classes, the inner classes can be documented.
7635       cd->writeDocumentationForInnerClasses(*g_outputList);
7636     }
7637   }
7638 }
7639
7640 static void generateClassDocs()
7641 {
7642   generateClassList(*Doxygen::classSDict);
7643   generateClassList(*Doxygen::hiddenClasses);
7644 }
7645
7646 //----------------------------------------------------------------------------
7647
7648 static void inheritDocumentation()
7649 {
7650   MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
7651   MemberName *mn;
7652   //int count=0;
7653   for (;(mn=mnli.current());++mnli)
7654   {
7655     MemberNameIterator mni(*mn);
7656     MemberDef *md;
7657     for (;(md=mni.current());++mni)
7658     {
7659       //printf("%04d Member `%s'\n",count++,md->name().data());
7660       if (md->documentation().isEmpty() && md->briefDescription().isEmpty())
7661       { // no documentation yet
7662         MemberDef *bmd = md->reimplements();
7663         while (bmd && bmd->documentation().isEmpty() && 
7664                       bmd->briefDescription().isEmpty()
7665               )
7666         { // search up the inheritance tree for a documentation member
7667           //printf("bmd=%s class=%s\n",bmd->name().data(),bmd->getClassDef()->name().data());
7668           bmd = bmd->reimplements();
7669         }
7670         if (bmd) // copy the documentation from the reimplemented member
7671         {
7672           md->setInheritsDocsFrom(bmd);
7673           md->setDocumentation(bmd->documentation(),bmd->docFile(),bmd->docLine());
7674           md->setDocsForDefinition(bmd->isDocsForDefinition());
7675           md->setBriefDescription(bmd->briefDescription(),bmd->briefFile(),bmd->briefLine());
7676           md->copyArgumentNames(bmd);
7677           md->setInbodyDocumentation(bmd->inbodyDocumentation(),bmd->inbodyFile(),bmd->inbodyLine());
7678         }
7679       }
7680     }
7681   }
7682 }
7683
7684 //----------------------------------------------------------------------------
7685
7686 static void combineUsingRelations()
7687 {
7688   // for each file
7689   FileNameListIterator fnli(*Doxygen::inputNameList);
7690   FileName *fn;
7691   for (fnli.toFirst();(fn=fnli.current());++fnli)
7692   {
7693     FileNameIterator fni(*fn);
7694     FileDef *fd;
7695     for (fni.toFirst();(fd=fni.current());++fni)
7696     {
7697       fd->visited=FALSE;
7698     }
7699   }
7700   for (fnli.toFirst();(fn=fnli.current());++fnli)
7701   {
7702     FileNameIterator fni(*fn);
7703     FileDef *fd;
7704     for (fni.toFirst();(fd=fni.current());++fni)
7705     {
7706       fd->combineUsingRelations();
7707     }
7708   }
7709
7710   // for each namespace
7711   NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
7712   NamespaceDef *nd;
7713   for (nli.toFirst() ; (nd=nli.current()) ; ++nli )
7714   {
7715     nd->visited=FALSE;
7716   }
7717   for (nli.toFirst() ; (nd=nli.current()) ; ++nli )
7718   {
7719     nd->combineUsingRelations();
7720   }
7721 }
7722
7723 //----------------------------------------------------------------------------
7724   
7725 static void addMembersToMemberGroup()
7726 {
7727   // for each class
7728   ClassSDict::Iterator cli(*Doxygen::classSDict);
7729   ClassDef *cd;
7730   for ( ; (cd=cli.current()) ; ++cli )
7731   {
7732     cd->addMembersToMemberGroup();
7733   }
7734   // for each file
7735   FileName *fn=Doxygen::inputNameList->first();
7736   while (fn)
7737   {
7738     FileDef *fd=fn->first();
7739     while (fd)
7740     {
7741       fd->addMembersToMemberGroup();
7742       fd=fn->next();
7743     }
7744     fn=Doxygen::inputNameList->next();
7745   }
7746   // for each namespace
7747   NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
7748   NamespaceDef *nd;
7749   for ( ; (nd=nli.current()) ; ++nli )
7750   {
7751     nd->addMembersToMemberGroup();
7752   }
7753   // for each group
7754   GroupSDict::Iterator gli(*Doxygen::groupSDict);
7755   GroupDef *gd;
7756   for (gli.toFirst();(gd=gli.current());++gli)
7757   {
7758     gd->addMembersToMemberGroup();
7759   }
7760 }
7761
7762 //----------------------------------------------------------------------------
7763
7764 static void distributeMemberGroupDocumentation()
7765 {
7766   // for each class
7767   ClassSDict::Iterator cli(*Doxygen::classSDict);
7768   ClassDef *cd;
7769   for ( ; (cd=cli.current()) ; ++cli )
7770   {
7771     cd->distributeMemberGroupDocumentation();
7772   }
7773   // for each file
7774   FileName *fn=Doxygen::inputNameList->first();
7775   while (fn)
7776   {
7777     FileDef *fd=fn->first();
7778     while (fd)
7779     {
7780       fd->distributeMemberGroupDocumentation();
7781       fd=fn->next();
7782     }
7783     fn=Doxygen::inputNameList->next();
7784   }
7785   // for each namespace
7786   NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
7787   NamespaceDef *nd;
7788   for ( ; (nd=nli.current()) ; ++nli )
7789   {
7790     nd->distributeMemberGroupDocumentation();
7791   }
7792   // for each group
7793   GroupSDict::Iterator gli(*Doxygen::groupSDict);
7794   GroupDef *gd;
7795   for (gli.toFirst();(gd=gli.current());++gli)
7796   {
7797     gd->distributeMemberGroupDocumentation();
7798   }
7799 }
7800
7801 //----------------------------------------------------------------------------
7802
7803 static void findSectionsInDocumentation()
7804 {
7805   // for each class
7806   ClassSDict::Iterator cli(*Doxygen::classSDict);
7807   ClassDef *cd;
7808   for ( ; (cd=cli.current()) ; ++cli )
7809   {
7810     cd->findSectionsInDocumentation();
7811   }
7812   // for each file
7813   FileName *fn=Doxygen::inputNameList->first();
7814   while (fn)
7815   {
7816     FileDef *fd=fn->first();
7817     while (fd)
7818     {
7819       fd->findSectionsInDocumentation();
7820       fd=fn->next();
7821     }
7822     fn=Doxygen::inputNameList->next();
7823   }
7824   // for each namespace
7825   NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
7826   NamespaceDef *nd;
7827   for ( ; (nd=nli.current()) ; ++nli )
7828   {
7829     nd->findSectionsInDocumentation();
7830   }
7831   // for each group
7832   GroupSDict::Iterator gli(*Doxygen::groupSDict);
7833   GroupDef *gd;
7834   for (gli.toFirst();(gd=gli.current());++gli)
7835   {
7836     gd->findSectionsInDocumentation();
7837   }
7838   // for each page
7839   PageSDict::Iterator pdi(*Doxygen::pageSDict);
7840   PageDef *pd=0;
7841   for (pdi.toFirst();(pd=pdi.current());++pdi)
7842   {
7843     pd->findSectionsInDocumentation();
7844   }
7845   if (Doxygen::mainPage) Doxygen::mainPage->findSectionsInDocumentation();
7846 }
7847
7848 static void flushCachedTemplateRelations()
7849 {
7850   // remove all references to classes from the cache
7851   // as there can be new template instances in the inheritance path
7852   // to this class. Optimization: only remove those classes that
7853   // have inheritance instances as direct or indirect sub classes.
7854   QCacheIterator<LookupInfo> ci(*Doxygen::lookupCache);
7855   LookupInfo *li=0;
7856   for (ci.toFirst();(li=ci.current());++ci)
7857   {
7858     if (li->classDef)
7859     {
7860       Doxygen::lookupCache->remove(ci.currentKey());
7861     }
7862   }
7863   // remove all cached typedef resolutions whose target is a
7864   // template class as this may now be a template instance
7865   MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict);
7866   MemberName *fn;
7867   for (;(fn=fnli.current());++fnli) // for each global function name
7868   {
7869     MemberNameIterator fni(*fn);
7870     MemberDef *fmd;
7871     for (;(fmd=fni.current());++fni) // for each function with that name
7872     {
7873       if (fmd->isTypedefValCached())
7874       {
7875         ClassDef *cd = fmd->getCachedTypedefVal();
7876         if (cd->isTemplate()) fmd->invalidateTypedefValCache();
7877       }
7878     }
7879   }
7880   MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
7881   for (;(fn=mnli.current());++mnli) // for each class method name
7882   {
7883     MemberNameIterator mni(*fn);
7884     MemberDef *fmd;
7885     for (;(fmd=mni.current());++mni) // for each function with that name
7886     {
7887       if (fmd->isTypedefValCached())
7888       {
7889         ClassDef *cd = fmd->getCachedTypedefVal();
7890         if (cd->isTemplate()) fmd->invalidateTypedefValCache();
7891       }
7892     }
7893   }
7894 }
7895
7896 //----------------------------------------------------------------------------
7897
7898 static void flushUnresolvedRelations()
7899 {
7900   // Remove all unresolved references to classes from the cache.
7901   // This is needed before resolving the inheritance relations, since
7902   // it would otherwise not find the inheritance relation
7903   // for C in the example below, as B::I was already found to be unresolvable 
7904   // (which is correct if you igore the inheritance relation between A and B).
7905   // 
7906   // class A { class I {} };
7907   // class B : public A {};
7908   // class C : public B::I {};
7909   //
7910   QCacheIterator<LookupInfo> ci(*Doxygen::lookupCache);
7911   LookupInfo *li=0;
7912   for (ci.toFirst();(li=ci.current());++ci)
7913   {
7914     if (li->classDef==0 && li->typeDef==0)
7915     {
7916       Doxygen::lookupCache->remove(ci.currentKey());
7917     }
7918   }
7919
7920   MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict);
7921   MemberName *fn;
7922   for (;(fn=fnli.current());++fnli) // for each global function name
7923   {
7924     MemberNameIterator fni(*fn);
7925     MemberDef *fmd;
7926     for (;(fmd=fni.current());++fni) // for each function with that name
7927     {
7928       fmd->invalidateCachedArgumentTypes();
7929     }
7930   }
7931   MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
7932   for (;(fn=mnli.current());++mnli) // for each class method name
7933   {
7934     MemberNameIterator mni(*fn);
7935     MemberDef *fmd;
7936     for (;(fmd=mni.current());++mni) // for each function with that name
7937     {
7938       fmd->invalidateCachedArgumentTypes();
7939     }
7940   }
7941
7942 }
7943
7944 //----------------------------------------------------------------------------
7945
7946 static void findDefineDocumentation(EntryNav *rootNav)
7947 {
7948   if ((rootNav->section()==Entry::DEFINEDOC_SEC ||
7949        rootNav->section()==Entry::DEFINE_SEC) && !rootNav->name().isEmpty()
7950      )
7951   {
7952     rootNav->loadEntry(g_storage);
7953     Entry *root = rootNav->entry();
7954     
7955     //printf("found define `%s' `%s' brief=`%s' doc=`%s'\n",
7956     //       root->name.data(),root->args.data(),root->brief.data(),root->doc.data());
7957
7958     if (rootNav->tagInfo() && !root->name.isEmpty()) // define read from a tag file
7959     {
7960       MemberDef *md=new MemberDef("<tagfile>",1,
7961                     "#define",root->name,root->args,0,
7962                     Public,Normal,FALSE,Member,MemberDef::Define,0,0);
7963       md->setTagInfo(rootNav->tagInfo());
7964       md->setLanguage(root->lang);
7965       //printf("Searching for `%s' fd=%p\n",filePathName.data(),fd);
7966       md->setFileDef(rootNav->parent()->fileDef());
7967       //printf("Adding member=%s\n",md->name().data());
7968       MemberName *mn;
7969       if ((mn=Doxygen::functionNameSDict->find(root->name)))
7970       {
7971         mn->append(md);
7972       }
7973       else 
7974       {
7975         mn = new MemberName(root->name);
7976         mn->append(md);
7977         Doxygen::functionNameSDict->append(root->name,mn);
7978       }
7979     }
7980     MemberName *mn=Doxygen::functionNameSDict->find(root->name);
7981     if (mn)
7982     {
7983       int count=0;
7984       MemberDef *md=mn->first();
7985       while (md)
7986       {
7987         if (md->memberType()==MemberDef::Define) count++;
7988         md=mn->next();
7989       }
7990       if (count==1)
7991       {
7992         md=mn->first();
7993         while (md)
7994         {
7995           if (md->memberType()==MemberDef::Define)
7996           {
7997             md->setDocumentation(root->doc,root->docFile,root->docLine);
7998             md->setDocsForDefinition(!root->proto);
7999             md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
8000             if (md->inbodyDocumentation().isEmpty())
8001             {
8002               md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
8003             }
8004             md->setBodySegment(root->bodyLine,root->endBodyLine);
8005             md->setBodyDef(rootNav->fileDef());
8006             md->addSectionsToDefinition(root->anchors);
8007             md->setMaxInitLines(root->initLines);
8008             md->setRefItems(root->sli);
8009             if (root->mGrpId!=-1) md->setMemberGroupId(root->mGrpId);
8010             addMemberToGroups(root,md);
8011           }
8012           md=mn->next();
8013         }
8014       }
8015       else if (count>1 && 
8016                (!root->doc.isEmpty() || 
8017                 !root->brief.isEmpty() || 
8018                 root->bodyLine!=-1
8019                )
8020               ) 
8021         // multiple defines don't know where to add docs
8022         // but maybe they are in different files together with their documentation
8023       {
8024         md=mn->first();
8025         while (md)
8026         {
8027           if (md->memberType()==MemberDef::Define)
8028           {
8029             FileDef *fd=md->getFileDef();
8030             if (fd && fd->absFilePath()==root->fileName) 
8031               // doc and define in the same file assume they belong together.
8032             {
8033 #if 0
8034               if (md->documentation().isEmpty())
8035 #endif
8036               {
8037                 md->setDocumentation(root->doc,root->docFile,root->docLine);
8038                 md->setDocsForDefinition(!root->proto);
8039               }
8040 #if 0
8041               if (md->briefDescription().isEmpty())
8042 #endif
8043               {
8044                 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
8045               }
8046               if (md->inbodyDocumentation().isEmpty())
8047               {
8048                 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
8049               }
8050               md->setBodySegment(root->bodyLine,root->endBodyLine);
8051               md->setBodyDef(rootNav->fileDef());
8052               md->addSectionsToDefinition(root->anchors);
8053               md->setRefItems(root->sli);
8054               md->setLanguage(root->lang);
8055               if (root->mGrpId!=-1) md->setMemberGroupId(root->mGrpId);
8056               addMemberToGroups(root,md);
8057             }
8058           }
8059           md=mn->next();
8060         }
8061         //warn("warning: define %s found in the following files:\n",root->name.data());
8062         //warn("Cannot determine where to add the documentation found "
8063         //     "at line %d of file %s. \n",
8064         //     root->startLine,root->fileName.data());
8065       }
8066     }
8067     else if (!root->doc.isEmpty() || !root->brief.isEmpty()) // define not found
8068     {
8069       static bool preEnabled = Config_getBool("ENABLE_PREPROCESSING");
8070       if (preEnabled)
8071       {
8072         warn(root->fileName,root->startLine,
8073              "warning: documentation for unknown define %s found.\n",
8074              root->name.data()
8075             );
8076       }
8077       else
8078       {
8079         warn(root->fileName,root->startLine,
8080              "warning: found documented #define but ignoring it because "
8081              "ENABLE_PREPROCESSING is NO.\n",
8082              root->name.data()
8083             );
8084       }
8085     }
8086
8087     rootNav->releaseEntry();
8088   }
8089   RECURSE_ENTRYTREE(findDefineDocumentation,rootNav);
8090 }
8091
8092 //----------------------------------------------------------------------------
8093
8094 static void findDirDocumentation(EntryNav *rootNav)
8095 {
8096   if (rootNav->section() == Entry::DIRDOC_SEC)
8097   {
8098     rootNav->loadEntry(g_storage);
8099     Entry *root = rootNav->entry();
8100
8101     QCString normalizedName = root->name;
8102     normalizedName = substitute(normalizedName,"\\","/");
8103     //printf("root->docFile=%s normalizedName=%s\n",
8104     //    root->docFile.data(),normalizedName.data());
8105     if (root->docFile==normalizedName) // current dir?
8106     {
8107       int lastSlashPos=normalizedName.findRev('/'); 
8108       if (lastSlashPos!=-1) // strip file name
8109       {
8110         normalizedName=normalizedName.left(lastSlashPos);
8111       }
8112     }
8113     if (normalizedName.at(normalizedName.length()-1)!='/')
8114     {
8115       normalizedName+='/';
8116     }
8117     DirDef *dir,*matchingDir=0;
8118     SDict<DirDef>::Iterator sdi(*Doxygen::directories);
8119     for (sdi.toFirst();(dir=sdi.current());++sdi)
8120     {
8121       //printf("Dir: %s<->%s\n",dir->name().data(),normalizedName.data());
8122       if (dir->name().right(normalizedName.length())==normalizedName)
8123       {
8124         if (matchingDir)
8125         {
8126            warn(root->fileName,root->startLine,
8127              "warning: \\dir command matches multiple directories.\n"
8128              "  Applying the command for directory %s\n"
8129              "  Ignoring the command for directory %s\n",
8130              matchingDir->name().data(),dir->name().data()
8131            );
8132         }
8133         else
8134         {
8135           matchingDir=dir;
8136         }
8137       }
8138     }
8139     if (matchingDir)
8140     {
8141       //printf("Match for with dir %s\n",matchingDir->name().data());
8142       matchingDir->setBriefDescription(root->brief,root->briefFile,root->briefLine);
8143       matchingDir->setDocumentation(root->doc,root->docFile,root->docLine);
8144       matchingDir->setRefItems(root->sli);
8145       addDirToGroups(root,matchingDir);
8146     }
8147     else
8148     {
8149       warn(root->fileName,root->startLine,"warning: No matching "
8150           "directory found for command \\dir %s\n",normalizedName.data());
8151     }
8152     rootNav->releaseEntry();
8153   }
8154   RECURSE_ENTRYTREE(findDirDocumentation,rootNav);
8155 }
8156
8157
8158 //----------------------------------------------------------------------------
8159 // create a (sorted) list of separate documentation pages
8160
8161 static void buildPageList(EntryNav *rootNav)
8162 {
8163   if (rootNav->section() == Entry::PAGEDOC_SEC)
8164   {
8165     rootNav->loadEntry(g_storage);
8166     Entry *root = rootNav->entry();
8167
8168     if (!root->name.isEmpty())
8169     {
8170       addRelatedPage(rootNav);
8171     }
8172
8173     rootNav->releaseEntry();
8174   }
8175   else if (rootNav->section() == Entry::MAINPAGEDOC_SEC)
8176   {
8177     rootNav->loadEntry(g_storage);
8178     Entry *root = rootNav->entry();
8179
8180     QCString title=root->args.stripWhiteSpace();
8181     if (title.isEmpty()) title=theTranslator->trMainPage();
8182     //QCString name = Config_getBool("GENERATE_TREEVIEW")?"main":"index";
8183     QCString name = "index";
8184     addRefItem(root->sli,
8185                name,
8186                "page",
8187                name,
8188                title,
8189                0
8190                );
8191
8192     rootNav->releaseEntry();
8193   }
8194   RECURSE_ENTRYTREE(buildPageList,rootNav);
8195 }
8196
8197 static void findMainPage(EntryNav *rootNav)
8198 {
8199   if (rootNav->section() == Entry::MAINPAGEDOC_SEC)
8200   {
8201     rootNav->loadEntry(g_storage);
8202     Entry *root = rootNav->entry();
8203
8204     if (Doxygen::mainPage==0)
8205     {
8206       //printf("Found main page! \n======\n%s\n=======\n",root->doc.data());
8207       QCString title=root->args.stripWhiteSpace();
8208       //QCString indexName=Config_getBool("GENERATE_TREEVIEW")?"main":"index";
8209       QCString indexName="index";
8210       Doxygen::mainPage = new PageDef(root->docFile,root->docLine,
8211                               indexName, root->brief+root->doc+root->inbodyDocs,title);
8212       //setFileNameForSections(root->anchors,"index",Doxygen::mainPage);
8213       Doxygen::mainPage->setBriefDescription(root->brief,root->briefFile,root->briefLine);
8214       Doxygen::mainPage->setFileName(indexName);
8215       Doxygen::mainPage->setShowToc(root->stat);
8216       addPageToContext(Doxygen::mainPage,rootNav);
8217           
8218       // a page name is a label as well!
8219       SectionInfo *si=new SectionInfo(
8220           indexName,
8221           Doxygen::mainPage->name(),
8222           Doxygen::mainPage->title(),
8223           SectionInfo::Page,
8224           0); // level 0
8225       Doxygen::sectionDict.append(indexName,si);
8226       Doxygen::mainPage->addSectionsToDefinition(root->anchors);
8227     }
8228     else
8229     {
8230       warn(root->fileName,root->startLine,
8231            "warning: found more than one \\mainpage comment block! Skipping this "
8232            "block."
8233           );
8234     }
8235
8236     rootNav->releaseEntry();
8237   }
8238   RECURSE_ENTRYTREE(findMainPage,rootNav);
8239 }
8240
8241 static void computePageRelations(EntryNav *rootNav)
8242 {
8243   if ((rootNav->section()==Entry::PAGEDOC_SEC || 
8244        rootNav->section()==Entry::MAINPAGEDOC_SEC
8245       )
8246       && !rootNav->name().isEmpty()
8247      )
8248   {
8249     rootNav->loadEntry(g_storage);
8250     Entry *root = rootNav->entry();
8251
8252     PageDef *pd = root->section==Entry::PAGEDOC_SEC ?
8253                     Doxygen::pageSDict->find(root->name) : 
8254                     Doxygen::mainPage; 
8255     if (pd)
8256     {
8257       QListIterator<BaseInfo> bii(*root->extends);
8258       BaseInfo *bi;
8259       for (bii.toFirst();(bi=bii.current());++bii)
8260       {
8261         PageDef *subPd = Doxygen::pageSDict->find(bi->name);
8262         if (subPd)
8263         {
8264           pd->addInnerCompound(subPd);
8265           //printf("*** Added subpage relation: %s->%s\n",
8266           //    pd->name().data(),subPd->name().data());
8267         }
8268       }
8269     }
8270
8271     rootNav->releaseEntry();
8272   }
8273   RECURSE_ENTRYTREE(computePageRelations,rootNav);
8274 }
8275
8276 static void checkPageRelations()
8277 {
8278   PageSDict::Iterator pdi(*Doxygen::pageSDict);
8279   PageDef *pd=0;
8280   for (pdi.toFirst();(pd=pdi.current());++pdi)
8281   {
8282     Definition *ppd = pd->getOuterScope();
8283     while (ppd)
8284     {
8285       if (ppd==pd)
8286       {
8287         err("warning: page defined at line %d of file %s with label %s is a subpage "
8288             "of itself! Please remove this cyclic dependency.\n",
8289             pd->docLine(),pd->docFile().data(),pd->name().data());
8290         exit(1);
8291       }
8292       ppd=ppd->getOuterScope();
8293     }
8294   }
8295 }
8296
8297 //----------------------------------------------------------------------------
8298
8299 static void resolveUserReferences()
8300 {
8301   SDict<SectionInfo>::Iterator sdi(Doxygen::sectionDict);
8302   SectionInfo *si;
8303   for (;(si=sdi.current());++sdi)
8304   {
8305     //printf("si->label=`%s' si->definition=%s si->fileName=`%s'\n",
8306     //        si->label.data(),si->definition?si->definition->name().data():"<none>",
8307     //        si->fileName.data());
8308     PageDef *pd=0;
8309
8310     // hack: the items of a todo/test/bug/deprecated list are all fragments from 
8311     // different files, so the resulting section's all have the wrong file 
8312     // name (not from the todo/test/bug/deprecated list, but from the file in 
8313     // which they are defined). We correct this here by looking at the 
8314     // generated section labels!
8315     QDictIterator<RefList> rli(*Doxygen::xrefLists);
8316     RefList *rl;
8317     for (rli.toFirst();(rl=rli.current());++rli)
8318     {
8319       QCString label="_"+rl->listName(); // "_todo", "_test", ...
8320       if (si->label.left(label.length())==label)
8321       {
8322         si->fileName=rl->listName();
8323         si->generated=TRUE;
8324         break;
8325       }
8326     }
8327
8328     //printf("start: si->label=%s si->fileName=%s\n",si->label.data(),si->fileName.data());
8329     if (!si->generated)
8330     {
8331       // if this section is in a page and the page is in a group, then we
8332       // have to adjust the link file name to point to the group.
8333       if (!si->fileName.isEmpty() && 
8334           (pd=Doxygen::pageSDict->find(si->fileName)) &&
8335           pd->getGroupDef())
8336       {
8337         si->fileName=pd->getGroupDef()->getOutputFileBase().copy();
8338       }
8339
8340       if (si->definition)
8341       {
8342         // TODO: there should be one function in Definition that returns
8343         // the file to link to, so we can avoid the following tests.
8344         GroupDef *gd=0;
8345         if (si->definition->definitionType()==Definition::TypeMember)
8346         {
8347           gd = ((MemberDef *)si->definition)->getGroupDef();
8348         }
8349
8350         if (gd)
8351         {
8352           si->fileName=gd->getOutputFileBase().copy();
8353         }
8354         else
8355         {
8356           //si->fileName=si->definition->getOutputFileBase().copy();
8357           //printf("Setting si->fileName to %s\n",si->fileName.data());
8358         }
8359       }
8360     }
8361     //printf("end: si->label=%s si->fileName=%s\n",si->label.data(),si->fileName.data());
8362   }
8363 }
8364
8365
8366
8367 //----------------------------------------------------------------------------
8368 // generate all separate documentation pages
8369
8370
8371 static void generatePageDocs()
8372 {
8373   //printf("documentedPages=%d real=%d\n",documentedPages,Doxygen::pageSDict->count());
8374   if (documentedPages==0) return;
8375   PageSDict::Iterator pdi(*Doxygen::pageSDict);
8376   PageDef *pd=0;
8377   for (pdi.toFirst();(pd=pdi.current());++pdi)
8378   {
8379     if (!pd->getGroupDef() && !pd->isReference())
8380     {
8381       msg("Generating docs for page %s...\n",pd->name().data());
8382       Doxygen::insideMainPage=TRUE;
8383       pd->writeDocumentation(*g_outputList);
8384       Doxygen::insideMainPage=FALSE;
8385     }
8386   }
8387 }
8388
8389 //----------------------------------------------------------------------------
8390 // create a (sorted) list & dictionary of example pages
8391
8392 static void buildExampleList(EntryNav *rootNav)
8393 {
8394   if (rootNav->section()==Entry::EXAMPLE_SEC && !rootNav->name().isEmpty()) 
8395   {
8396     rootNav->loadEntry(g_storage);
8397     Entry *root = rootNav->entry();
8398
8399     if (Doxygen::exampleSDict->find(root->name))
8400     {
8401       warn(root->fileName,root->startLine,
8402           "warning: Example %s was already documented. Ignoring "
8403           "documentation found here.",
8404           root->name.data()
8405           );
8406     }
8407     else
8408     {
8409       PageDef *pd=new PageDef(root->fileName,root->startLine,
8410           root->name,root->brief+root->doc+root->inbodyDocs,root->args);
8411       pd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
8412       pd->setFileName(convertNameToFile(pd->name()+"-example",FALSE,TRUE));
8413       pd->addSectionsToDefinition(root->anchors);
8414       pd->setLanguage(root->lang);
8415       //pi->addSections(root->anchors);
8416
8417       Doxygen::exampleSDict->inSort(root->name,pd);
8418       //we don't add example to groups 
8419       //addExampleToGroups(root,pd);
8420     }
8421
8422     rootNav->releaseEntry();
8423   }
8424   RECURSE_ENTRYTREE(buildExampleList,rootNav);
8425 }
8426
8427 //----------------------------------------------------------------------------
8428 // prints the Entry tree (for debugging)
8429
8430 void printNavTree(EntryNav *rootNav,int indent)
8431 {
8432   QCString indentStr;
8433   indentStr.fill(' ',indent);
8434   msg("%s%s (sec=0x%x)\n",
8435       indentStr.isEmpty()?"":indentStr.data(),
8436       rootNav->name().isEmpty()?"<empty>":rootNav->name().data(),
8437       rootNav->section());
8438   if (rootNav->children()) 
8439   {
8440     EntryNavListIterator eli(*rootNav->children());
8441     for (;eli.current();++eli) printNavTree(eli.current(),indent+2);
8442   }
8443 }
8444
8445
8446 //----------------------------------------------------------------------------
8447 // generate the example documentation 
8448
8449 static void generateExampleDocs()
8450 {
8451   g_outputList->disable(OutputGenerator::Man);
8452   PageSDict::Iterator pdi(*Doxygen::exampleSDict);
8453   PageDef *pd=0;
8454   for (pdi.toFirst();(pd=pdi.current());++pdi)
8455   {
8456     msg("Generating docs for example %s...\n",pd->name().data());
8457     resetCCodeParserState();
8458     QCString n=pd->getOutputFileBase();
8459     startFile(*g_outputList,n,n,pd->name());
8460     startTitle(*g_outputList,n);
8461     g_outputList->docify(pd->name());
8462     endTitle(*g_outputList,n,0);
8463     g_outputList->startContents();
8464     g_outputList->parseDoc(pd->docFile(),                            // file
8465                          pd->docLine(),                            // startLine
8466                          pd,                                       // context
8467                          0,                                        // memberDef
8468                          pd->documentation()+"\n\n\\include "+pd->name(),          // docs
8469                          TRUE,                                     // index words
8470                          TRUE,                                     // is example
8471                          pd->name()
8472                         );
8473     endFile(*g_outputList); // contains g_outputList->endContents()
8474   }
8475   g_outputList->enable(OutputGenerator::Man);
8476 }
8477
8478 //----------------------------------------------------------------------------
8479 // generate module pages
8480
8481 static void generateGroupDocs()
8482 {
8483   GroupSDict::Iterator gli(*Doxygen::groupSDict);
8484   GroupDef *gd;
8485   for (gli.toFirst();(gd=gli.current());++gli)
8486   {
8487     if (!gd->isReference())
8488     {
8489       gd->writeDocumentation(*g_outputList);
8490     }
8491   }
8492 }
8493
8494 //----------------------------------------------------------------------------
8495
8496 //static void generatePackageDocs()
8497 //{
8498 //  writePackageIndex(*g_outputList);
8499 //  
8500 //  if (Doxygen::packageDict.count()>0)
8501 //  {
8502 //    PackageSDict::Iterator pdi(Doxygen::packageDict);
8503 //    PackageDef *pd;
8504 //    for (pdi.toFirst();(pd=pdi.current());++pdi)
8505 //    {
8506 //      pd->writeDocumentation(*g_outputList);
8507 //    }
8508 //  }
8509 //}
8510
8511 //----------------------------------------------------------------------------
8512 // generate module pages
8513
8514 static void generateNamespaceDocs()
8515 {
8516   //writeNamespaceIndex(*g_outputList);
8517   
8518   NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
8519   NamespaceDef *nd;
8520   // for each namespace...
8521   for (;(nd=nli.current());++nli)
8522   {
8523
8524     if (nd->isLinkableInProject())
8525     {
8526       msg("Generating docs for namespace %s\n",nd->name().data());
8527       nd->writeDocumentation(*g_outputList);
8528     }
8529
8530     // for each class in the namespace...
8531     ClassSDict::Iterator cli(*nd->getClassSDict());
8532     for ( ; cli.current() ; ++cli )
8533     {
8534       ClassDef *cd=cli.current();
8535       if ( ( cd->isLinkableInProject() && 
8536              cd->templateMaster()==0
8537            ) // skip external references, anonymous compounds and 
8538              // template instances and nested classes
8539            && !cd->isHidden() && !cd->isEmbeddedInOuterScope()
8540          )
8541       {
8542         msg("Generating docs for compound %s...\n",cd->name().data());
8543
8544         cd->writeDocumentation(*g_outputList);
8545         cd->writeMemberList(*g_outputList);
8546       }
8547       cd->writeDocumentationForInnerClasses(*g_outputList);
8548     }
8549   }
8550 }
8551
8552 #if defined(_WIN32)
8553 static QCString fixSlashes(QCString &s)
8554 {
8555   QCString result;
8556   uint i;
8557   for (i=0;i<s.length();i++)
8558   {
8559     switch(s.at(i))
8560     {
8561       case '/': 
8562       case '\\': 
8563         result+="\\\\"; 
8564         break;
8565       default:
8566         result+=s.at(i);
8567     }
8568   }
8569   return result;
8570 }
8571 #endif
8572
8573
8574 //----------------------------------------------------------------------------
8575
8576 static bool openOutputFile(const char *outFile,QFile &f)
8577 {
8578   bool fileOpened=FALSE;
8579   bool writeToStdout=(outFile[0]=='-' && outFile[1]=='\0');
8580   if (writeToStdout) // write to stdout
8581   {
8582     fileOpened = f.open(IO_WriteOnly,stdout);
8583   }
8584   else // write to file
8585   {
8586     QFileInfo fi(outFile);
8587     if (fi.exists()) // create a backup
8588     {
8589       QDir dir=fi.dir();
8590       QFileInfo backup(fi.fileName()+".bak");
8591       if (backup.exists()) // remove existing backup
8592         dir.remove(backup.fileName());
8593       dir.rename(fi.fileName(),fi.fileName()+".bak");
8594     } 
8595     f.setName(outFile);
8596     fileOpened = f.open(IO_WriteOnly|IO_Translate);
8597   }
8598   return fileOpened;
8599 }
8600
8601 /*! Generate a template version of the configuration file.
8602  *  If the \a shortList parameter is TRUE a configuration file without
8603  *  comments will be generated.
8604  */
8605 static void generateConfigFile(const char *configFile,bool shortList,
8606                                bool updateOnly=FALSE)
8607 {
8608   QFile f;
8609   bool fileOpened=openOutputFile(configFile,f);
8610   bool writeToStdout=(configFile[0]=='-' && configFile[1]=='\0');
8611   if (fileOpened)
8612   {
8613     FTextStream t(&f);
8614     Config::instance()->writeTemplate(t,shortList,updateOnly);
8615     if (!writeToStdout)
8616     {
8617       if (!updateOnly)
8618       {
8619         msg("\n\nConfiguration file `%s' created.\n\n",configFile);
8620         msg("Now edit the configuration file and enter\n\n");
8621         if (strcmp(configFile,"Doxyfile") || strcmp(configFile,"doxyfile"))
8622           msg("  doxygen %s\n\n",configFile);
8623         else
8624           msg("  doxygen\n\n");
8625         msg("to generate the documentation for your project\n\n");
8626       }
8627       else
8628       {
8629         msg("\n\nConfiguration file `%s' updated.\n\n",configFile);
8630       }
8631     }
8632   }
8633   else
8634   {
8635     err("error: Cannot open file %s for writing\n",configFile);
8636     exit(1);
8637   }
8638 }
8639
8640 //----------------------------------------------------------------------------
8641 // read and parse a tag file
8642
8643 //static bool readLineFromFile(QFile &f,QCString &s)
8644 //{
8645 //  char c=0;
8646 //  s.resize(0);
8647 //  while (!f.atEnd() && (c=f.getch())!='\n') s+=c;
8648 //  return f.atEnd();
8649 //}
8650
8651 //----------------------------------------------------------------------------
8652
8653 static void readTagFile(Entry *root,const char *tl)
8654 {
8655   QCString tagLine = tl;
8656   QCString fileName;
8657   QCString destName;
8658   int eqPos = tagLine.find('=');
8659   if (eqPos!=-1) // tag command contains a destination
8660   {
8661     fileName = tagLine.left(eqPos).stripWhiteSpace();
8662     destName = tagLine.right(tagLine.length()-eqPos-1).stripWhiteSpace();
8663     QFileInfo fi(fileName);
8664     Doxygen::tagDestinationDict.insert(fi.fileName().utf8(),new QCString(destName));
8665     //printf("insert tagDestination %s->%s\n",fi.fileName().data(),destName.data());
8666   }
8667   else
8668   {
8669     fileName = tagLine;
8670   }
8671     
8672   QFileInfo fi(fileName);
8673   if (!fi.exists() || !fi.isFile())
8674   {
8675     err("error: Tag file `%s' does not exist or is not a file. Skipping it...\n",
8676         fileName.data());
8677     return;
8678   }
8679
8680   if (!destName.isEmpty())
8681     msg("Reading tag file `%s', location `%s'...\n",fileName.data(),destName.data());
8682   else
8683     msg("Reading tag file `%s'...\n",fileName.data());
8684
8685   parseTagFile(root,fi.absFilePath().utf8(),fi.fileName().utf8());
8686 }
8687
8688 //----------------------------------------------------------------------------
8689 static void copyStyleSheet()
8690 {
8691   QCString &htmlStyleSheet = Config_getString("HTML_STYLESHEET");
8692   if (!htmlStyleSheet.isEmpty())
8693   {
8694     QFileInfo fi(htmlStyleSheet);
8695     if (!fi.exists())
8696     {
8697       err("Style sheet '%s' specified by HTML_STYLESHEET does not exist!\n",htmlStyleSheet.data());
8698       htmlStyleSheet.resize(0); // revert to the default
8699     }
8700     else
8701     {
8702       QCString destFileName = Config_getString("HTML_OUTPUT")+"/"+fi.fileName().data();
8703       copyFile(htmlStyleSheet,destFileName);
8704     }
8705   }
8706   QCString &htmlExtraStyleSheet = Config_getString("HTML_EXTRA_STYLESHEET");
8707   if (!htmlExtraStyleSheet.isEmpty())
8708   {
8709     QFileInfo fi(htmlExtraStyleSheet);
8710     if (!fi.exists())
8711     {
8712       err("Style sheet '%s' specified by HTML_EXTRA_STYLESHEET does not exist!\n",htmlExtraStyleSheet.data());
8713       htmlExtraStyleSheet.resize(0); // revert to the default
8714     }
8715     else
8716     {
8717       QCString destFileName = Config_getString("HTML_OUTPUT")+"/"+fi.fileName().data();
8718       copyFile(htmlExtraStyleSheet,destFileName);
8719     }
8720   }
8721   
8722 }
8723
8724 static void copyLogo()
8725 {
8726   QCString &projectLogo = Config_getString("PROJECT_LOGO");
8727   if (!projectLogo.isEmpty())
8728   {
8729     QFileInfo fi(projectLogo);
8730     if (!fi.exists())
8731     {
8732       err("Project logo '%s' specified by PROJECT_LOGO does not exist!\n",projectLogo.data());
8733       projectLogo.resize(0); // revert to the default
8734     }
8735     else
8736     {
8737       QCString destFileName = Config_getString("HTML_OUTPUT")+"/"+fi.fileName().data();
8738       copyFile(projectLogo,destFileName);
8739       Doxygen::indexList.addImageFile(fi.fileName().data());
8740     }
8741   }
8742 }
8743
8744 static void copyExtraFiles()
8745 {
8746   QStrList files = Config_getList("HTML_EXTRA_FILES");
8747   uint i;
8748   for (i=0; i<files.count(); ++i)
8749   {
8750     QCString fileName(files.at(i));
8751     
8752     if (!fileName.isEmpty())
8753     {
8754       QFileInfo fi(fileName);
8755       if (!fi.exists()) 
8756       {
8757         err("Extra HTML file '%s' specified in HTML_EXTRA_FILES does not exist!\n", fileName.data());
8758       }
8759       else
8760       {
8761         QCString destFileName = Config_getString("HTML_OUTPUT")+"/"+fi.fileName().data();
8762         Doxygen::indexList.addImageFile(fi.fileName().data());
8763         copyFile(fileName, destFileName);
8764       }
8765     }
8766   }
8767 }
8768
8769 //! parse the list of input files
8770 static void parseFiles(Entry *root,EntryNav *rootNav)
8771 {
8772   QCString *s=g_inputFiles.first();
8773   while (s)
8774   {
8775     QCString fileName=*s;
8776     QCString extension;
8777     int ei = fileName.findRev('.');
8778     if (ei!=-1) extension=fileName.right(fileName.length()-ei);
8779     ParserInterface *parser = Doxygen::parserManager->getParser(extension);
8780
8781     QFileInfo fi(fileName);
8782     BufStr preBuf(fi.size()+4096);
8783
8784     if (Config_getBool("ENABLE_PREPROCESSING") && 
8785         parser->needsPreprocessing(extension))
8786     {
8787       BufStr inBuf(fi.size()+4096);
8788       msg("Preprocessing %s...\n",s->data());
8789       readInputFile(fileName,inBuf);
8790       preprocessFile(fileName,inBuf,preBuf);
8791     }
8792     else // no preprocessing
8793     {
8794       msg("Reading %s...\n",s->data());
8795       readInputFile(fileName,preBuf);
8796     }
8797
8798     BufStr convBuf(preBuf.curPos()+1024);
8799
8800     // convert multi-line C++ comments to C style comments
8801     convertCppComments(&preBuf,&convBuf,fileName);
8802
8803     convBuf.addChar('\0');
8804
8805     // use language parse to parse the file
8806     parser->parseInput(fileName,convBuf.data(),root);
8807
8808     // store the Entry tree in a file and create an index to
8809     // navigate/load entries
8810     bool ambig;
8811     FileDef *fd=findFileDef(Doxygen::inputNameDict,fileName,ambig);
8812     ASSERT(fd!=0);
8813     //printf("root->createNavigationIndex for %s\n",fd->name().data());
8814     root->createNavigationIndex(rootNav,g_storage,fd);
8815
8816     s=g_inputFiles.next();
8817   }
8818 }
8819
8820 // resolves a path that may include symlinks, if a recursive symlink is
8821 // found an empty string is returned.
8822 static QCString resolveSymlink(QCString path)
8823 {
8824   int sepPos=0;
8825   int oldPos=0;
8826   QFileInfo fi;
8827   QDict<void> nonSymlinks;
8828   QDict<void> known;
8829   QCString result = path;
8830   QCString oldPrefix = "/";
8831   do
8832   {
8833 #ifdef WIN32
8834     // UNC path, skip server and share name
8835     if (sepPos==0 && (result.left(2)=="//" || result.left(2)=="\\\\")) 
8836       sepPos = result.find('/',2);
8837     if (sepPos!=-1) 
8838       sepPos = result.find('/',sepPos+1);
8839 #else
8840     sepPos = result.find('/',sepPos+1);
8841 #endif
8842     QCString prefix = sepPos==-1 ? result : result.left(sepPos);
8843     if (nonSymlinks.find(prefix)==0)
8844     {
8845       fi.setFile(prefix);
8846       if (fi.isSymLink())
8847       {
8848         QString target = fi.readLink();
8849         bool isRelative = QFileInfo(target).isRelative();
8850         if (isRelative)
8851         {
8852           target = QDir::cleanDirPath(oldPrefix+"/"+target.data());
8853         }
8854         if (sepPos!=-1)
8855         {
8856           if (fi.isDir() && target.length()>0 && target.at(target.length()-1)!='/')
8857           {
8858             target+='/';
8859           }
8860           target+=result.mid(sepPos);
8861         }
8862         result = QDir::cleanDirPath(target).data();
8863         sepPos = 0;
8864         if (known.find(result)) return QCString(); // recursive symlink!
8865         known.insert(result,(void*)0x8);
8866         if (isRelative)
8867         {
8868           sepPos = oldPos;
8869         }
8870         else // link to absolute path
8871         {
8872           sepPos = 0;
8873           oldPrefix = "/";
8874         }
8875       }
8876       else
8877       {
8878         nonSymlinks.insert(prefix,(void*)0x8);
8879         oldPrefix = prefix;
8880       }
8881       oldPos = sepPos;
8882     }
8883   }
8884   while (sepPos!=-1);
8885   return QDir::cleanDirPath(result).data();
8886 }
8887
8888 static QDict<void> g_pathsVisited(1009);
8889
8890 //----------------------------------------------------------------------------
8891 // Read all files matching at least one pattern in `patList' in the 
8892 // directory represented by `fi'.
8893 // The directory is read iff the recusiveFlag is set.
8894 // The contents of all files is append to the input string
8895
8896 int readDir(QFileInfo *fi,
8897             FileNameList *fnList,
8898             FileNameDict *fnDict,
8899             StringDict  *exclDict,
8900             QStrList *patList,
8901             QStrList *exclPatList,
8902             StringList *resultList,
8903             StringDict *resultDict,
8904             bool errorIfNotExist,
8905             bool recursive,
8906             QDict<void> *killDict
8907            )
8908 {
8909   QCString dirName = fi->absFilePath().utf8();
8910   if (fi->isSymLink())
8911   {
8912     dirName = resolveSymlink(dirName.data());
8913     if (dirName.isEmpty()) return 0;            // recusive symlink
8914     if (g_pathsVisited.find(dirName)) return 0; // already visited path
8915     g_pathsVisited.insert(dirName,(void*)0x8);
8916   }
8917   QDir dir(dirName);
8918   dir.setFilter( QDir::Files | QDir::Dirs | QDir::Hidden );
8919   int totalSize=0;
8920   msg("Searching for files in directory %s\n", fi->absFilePath().data());
8921   //printf("killDict=%p count=%d\n",killDict,killDict->count());
8922   
8923   const QFileInfoList *list = dir.entryInfoList();
8924   if (list)
8925   {
8926     QFileInfoListIterator it( *list );
8927     QFileInfo *cfi;
8928
8929     while ((cfi=it.current()))
8930     {
8931       if (exclDict==0 || exclDict->find(cfi->absFilePath().utf8())==0) 
8932       { // file should not be excluded
8933         //printf("killDict->find(%s)\n",cfi->absFilePath().data());
8934         if (!cfi->exists() || !cfi->isReadable())
8935         {
8936           if (errorIfNotExist)
8937           {
8938             err("warning: source %s is not a readable file or directory... skipping.\n",cfi->absFilePath().data());
8939           }
8940         }
8941         else if (cfi->isFile() && 
8942             (!Config_getBool("EXCLUDE_SYMLINKS") || !cfi->isSymLink()) &&
8943             (patList==0 || patternMatch(*cfi,patList)) && 
8944             !patternMatch(*cfi,exclPatList) &&
8945             (killDict==0 || killDict->find(cfi->absFilePath().utf8())==0)
8946             )
8947         {
8948           totalSize+=cfi->size()+cfi->absFilePath().length()+4;
8949           QCString name=convertToQCString(cfi->fileName());
8950           //printf("New file %s\n",name.data());
8951           if (fnDict)
8952           {
8953             FileDef  *fd=new FileDef(cfi->dirPath().utf8()+"/",name);
8954             FileName *fn=0;
8955             if (!name.isEmpty() && (fn=(*fnDict)[name]))
8956             {
8957               fn->append(fd);
8958             }
8959             else
8960             {
8961               fn = new FileName(cfi->absFilePath().utf8(),name);
8962               fn->append(fd);
8963               if (fnList) fnList->inSort(fn);
8964               fnDict->insert(name,fn);
8965             }
8966           }
8967           QCString *rs=0;
8968           if (resultList || resultDict)
8969           {
8970             rs=new QCString(cfi->absFilePath().utf8());
8971           }
8972           if (resultList) resultList->append(rs);
8973           if (resultDict) resultDict->insert(cfi->absFilePath().utf8(),rs);
8974           if (killDict) killDict->insert(cfi->absFilePath().utf8(),(void *)0x8);
8975         }
8976         else if (recursive &&
8977             (!Config_getBool("EXCLUDE_SYMLINKS") || !cfi->isSymLink()) &&
8978             cfi->isDir() && 
8979             !patternMatch(*cfi,exclPatList) &&
8980             cfi->fileName().at(0)!='.') // skip "." ".." and ".dir"
8981         {
8982           cfi->setFile(cfi->absFilePath());
8983           totalSize+=readDir(cfi,fnList,fnDict,exclDict,
8984               patList,exclPatList,resultList,resultDict,errorIfNotExist,
8985               recursive,killDict);
8986         }
8987       }
8988       ++it;
8989     }
8990   }
8991   return totalSize;
8992 }
8993
8994
8995 //----------------------------------------------------------------------------
8996 // read a file or all files in a directory and append their contents to the
8997 // input string. The names of the files are appended to the `fiList' list.
8998
8999 int readFileOrDirectory(const char *s,
9000                         FileNameList *fnList,
9001                         FileNameDict *fnDict,
9002                         StringDict *exclDict,
9003                         QStrList *patList,
9004                         QStrList *exclPatList,
9005                         StringList *resultList,
9006                         StringDict *resultDict,
9007                         bool recursive,
9008                         bool errorIfNotExist,
9009                         QDict<void> *killDict
9010                        )
9011 {
9012   //printf("killDict=%p count=%d\n",killDict,killDict->count());
9013   // strip trailing slashes
9014   if (s==0) return 0;
9015   QCString fs = s;
9016   char lc = fs.at(fs.length()-1);
9017   if (lc=='/' || lc=='\\') fs = fs.left(fs.length()-1);
9018
9019   QFileInfo fi(fs);
9020   //printf("readFileOrDirectory(%s)\n",s);
9021   int totalSize=0;
9022   {
9023     if (exclDict==0 || exclDict->find(fi.absFilePath().utf8())==0)
9024     {
9025       if (!fi.exists() || !fi.isReadable())
9026       {
9027         if (errorIfNotExist)
9028         {
9029           err("warning: source %s is not a readable file or directory... skipping.\n",s);
9030         }
9031       }
9032       else if (!Config_getBool("EXCLUDE_SYMLINKS") || !fi.isSymLink())
9033       {
9034         if (fi.isFile())
9035         {
9036           //printf("killDict->find(%s)\n",fi.absFilePath().data());
9037           if (killDict==0 || killDict->find(fi.absFilePath().utf8())==0)
9038           {
9039             totalSize+=fi.size()+fi.absFilePath().length()+4; //readFile(&fi,fiList,input); 
9040             //fiList->inSort(new FileInfo(fi));
9041             QCString name=convertToQCString(fi.fileName());
9042             //printf("New file %s\n",name.data());
9043             if (fnDict)
9044             {
9045               FileDef  *fd=new FileDef(fi.dirPath(TRUE).utf8()+"/",name);
9046               FileName *fn=0;
9047               if (!name.isEmpty() && (fn=(*fnDict)[name]))
9048               {
9049                 fn->append(fd);
9050               }
9051               else
9052               {
9053                 fn = new FileName(fi.absFilePath().utf8(),name);
9054                 fn->append(fd);
9055                 if (fnList) fnList->inSort(fn);
9056                 fnDict->insert(name,fn);
9057               }
9058             }
9059             QCString *rs=0;
9060             if (resultList || resultDict)
9061             {
9062               rs=new QCString(fi.absFilePath().utf8());
9063               if (resultList) resultList->append(rs);
9064               if (resultDict) resultDict->insert(fi.absFilePath().utf8(),rs);
9065             }
9066
9067             if (killDict) killDict->insert(fi.absFilePath().utf8(),(void *)0x8);
9068           }
9069         }
9070         else if (fi.isDir()) // readable dir
9071         {
9072           totalSize+=readDir(&fi,fnList,fnDict,exclDict,patList,
9073               exclPatList,resultList,resultDict,errorIfNotExist,
9074               recursive,killDict);
9075         }
9076       }
9077     }
9078   }
9079   return totalSize;
9080 }
9081
9082 //----------------------------------------------------------------------------
9083
9084 void readFormulaRepository()
9085 {
9086   QFile f(Config_getString("HTML_OUTPUT")+"/formula.repository");
9087   if (f.open(IO_ReadOnly)) // open repository
9088   {
9089     msg("Reading formula repository...\n");
9090     QTextStream t(&f);
9091     QCString line;
9092     while (!t.eof())
9093     {
9094       line=t.readLine().utf8();
9095       int se=line.find(':'); // find name and text separator.
9096       if (se==-1)
9097       {
9098         err("warning: formula.repository is corrupted!\n");
9099         break;
9100       }
9101       else
9102       {
9103         QCString formName = line.left(se);
9104         QCString formText = line.right(line.length()-se-1); 
9105         Formula *f=new Formula(formText);
9106         Doxygen::formulaList.append(f);
9107         Doxygen::formulaDict.insert(formText,f);
9108         Doxygen::formulaNameDict.insert(formName,f);
9109       }
9110     }
9111   }
9112 }
9113
9114 //----------------------------------------------------------------------------
9115
9116 static void expandAliases()
9117 {
9118   QDictIterator<QCString> adi(Doxygen::aliasDict);
9119   QCString *s;
9120   for (adi.toFirst();(s=adi.current());++adi)
9121   {
9122     *s = expandAlias(adi.currentKey(),*s);
9123   }
9124 }
9125
9126 //----------------------------------------------------------------------------
9127
9128 static void escapeAliases()
9129 {
9130   QDictIterator<QCString> adi(Doxygen::aliasDict);
9131   QCString *s;
9132   for (adi.toFirst();(s=adi.current());++adi)
9133   {
9134     QCString value=*s,newValue;
9135     int in,p=0;
9136     // for each \n in the alias command value
9137     while ((in=value.find("\\n",p))!=-1)
9138     {
9139       newValue+=value.mid(p,in-p);
9140       // expand \n's except if \n is part of a built-in command.
9141       if (value.mid(in,5)!="\\note" && 
9142           value.mid(in,5)!="\\name" && 
9143           value.mid(in,10)!="\\namespace" && 
9144           value.mid(in,14)!="\\nosubgrouping"
9145          ) 
9146       {
9147         newValue+="\\_linebr ";
9148       }
9149       else 
9150       {
9151         newValue+="\\n";
9152       }
9153       p=in+2;
9154     }
9155     newValue+=value.mid(p,value.length()-p);
9156     *s=newValue;
9157     //printf("Alias %s has value %s\n",adi.currentKey().data(),s->data());
9158   }
9159 }
9160
9161 //----------------------------------------------------------------------------
9162
9163 void readAliases()
9164
9165   // add aliases to a dictionary
9166   Doxygen::aliasDict.setAutoDelete(TRUE);
9167   QStrList &aliasList = Config_getList("ALIASES");
9168   const char *s=aliasList.first();
9169   while (s)
9170   {
9171     if (Doxygen::aliasDict[s]==0)
9172     {
9173       QCString alias=s;
9174       int i=alias.find('=');
9175       if (i>0)
9176       {
9177         QCString name=alias.left(i).stripWhiteSpace();
9178         QCString value=alias.right(alias.length()-i-1);
9179         //printf("Alias: found name=`%s' value=`%s'\n",name.data(),value.data()); 
9180         if (!name.isEmpty())
9181         {
9182           QCString *dn=Doxygen::aliasDict[name];
9183           if (dn==0) // insert new alias
9184           {
9185             Doxygen::aliasDict.insert(name,new QCString(value));
9186           }
9187           else // overwrite previous alias
9188           {
9189             *dn=value;
9190           }
9191         }
9192       }
9193     }
9194     s=aliasList.next();
9195   }
9196   expandAliases();
9197   escapeAliases();
9198 }
9199
9200 //----------------------------------------------------------------------------
9201
9202 static void dumpSymbol(FTextStream &t,Definition *d)
9203 {
9204   QCString anchor;
9205   if (d->definitionType()==Definition::TypeMember)
9206   {
9207     MemberDef *md = (MemberDef *)d;
9208     anchor=":"+md->anchor();
9209   }
9210   QCString scope;
9211   if (d->getOuterScope() && d->getOuterScope()!=Doxygen::globalScope) 
9212   {
9213     scope = d->getOuterScope()->getOutputFileBase()+Doxygen::htmlFileExtension;
9214   }
9215   t << "REPLACE INTO symbols (symbol_id,scope_id,name,file,line) VALUES('"
9216     << d->getOutputFileBase()+Doxygen::htmlFileExtension+anchor << "','"
9217     << scope << "','"
9218     << d->name() << "','"
9219     << d->getDefFileName() << "','"
9220     << d->getDefLine()
9221     << "');" << endl;
9222 }
9223
9224 static void dumpSymbolMap()
9225
9226   QFile f("symbols.sql");
9227   if (f.open(IO_WriteOnly))
9228   {
9229     FTextStream t(&f);
9230     QDictIterator<DefinitionIntf> di(*Doxygen::symbolMap);
9231     DefinitionIntf *intf;
9232     for (;(intf=di.current());++di)
9233     {
9234       if (intf->definitionType()==DefinitionIntf::TypeSymbolList) // list of symbols
9235       {
9236         DefinitionListIterator dli(*(DefinitionList*)intf);
9237         Definition *d;
9238         // for each symbol
9239         for (dli.toFirst();(d=dli.current());++dli)
9240         {
9241           dumpSymbol(t,d);
9242         }
9243       }
9244       else // single symbol
9245       {
9246         Definition *d = (Definition *)intf;
9247         if (d!=Doxygen::globalScope) dumpSymbol(t,d);
9248       }
9249     }
9250   }
9251 }
9252
9253 //----------------------------------------------------------------------------
9254
9255 void dumpConfigAsXML()
9256 {
9257   QFile f("config.xml");
9258   if (f.open(IO_WriteOnly))
9259   {
9260     FTextStream t(&f);
9261     Config::instance()->writeXML(t);
9262   }
9263 }
9264
9265 //----------------------------------------------------------------------------
9266 // print the usage of doxygen
9267
9268 static void usage(const char *name)
9269 {
9270   msg("Doxygen version %s\nCopyright Dimitri van Heesch 1997-2012\n\n",versionString);
9271   msg("You can use doxygen in a number of ways:\n\n");
9272   msg("1) Use doxygen to generate a template configuration file:\n");
9273   msg("    %s [-s] -g [configName]\n\n",name);
9274   msg("    If - is used for configName doxygen will write to standard output.\n\n");
9275   msg("2) Use doxygen to update an old configuration file:\n");
9276   msg("    %s [-s] -u [configName]\n\n",name);
9277   msg("3) Use doxygen to generate documentation using an existing ");
9278   msg("configuration file:\n");
9279   msg("    %s [configName]\n\n",name);
9280   msg("    If - is used for configName doxygen will read from standard input.\n\n");
9281   msg("4) Use doxygen to generate a template file controlling the layout of the\n");
9282   msg("   generated documentation:\n");
9283   msg("    %s -l layoutFileName.xml\n\n",name);
9284   msg("5) Use doxygen to generate a template style sheet file for RTF, HTML or Latex.\n");
9285   msg("    RTF:        %s -w rtf styleSheetFile\n",name);
9286   msg("    HTML:       %s -w html headerFile footerFile styleSheetFile [configFile]\n",name);
9287   msg("    LaTeX:      %s -w latex headerFile footerFile styleSheetFile [configFile]\n\n",name);
9288   msg("6) Use doxygen to generate an rtf extensions file\n");
9289   msg("    RTF:   %s -e rtf extensionsFile\n\n",name);
9290   msg("If -s is specified the comments in the config file will be omitted.\n");
9291   msg("If configName is omitted `Doxyfile' will be used as a default.\n\n");
9292   exit(1);
9293 }
9294
9295 //----------------------------------------------------------------------------
9296 // read the argument of option `c' from the comment argument list and
9297 // update the option index `optind'.
9298
9299 static const char *getArg(int argc,char **argv,int &optind)
9300 {
9301   char *s=0;
9302   if (strlen(&argv[optind][2])>0)
9303     s=&argv[optind][2];
9304   else if (optind+1<argc && argv[optind+1][0]!='-')
9305     s=argv[++optind];
9306   return s;
9307 }
9308
9309 //----------------------------------------------------------------------------
9310
9311 void initDoxygen()
9312 {
9313   const char *lang = portable_getenv("LC_ALL");
9314   if (lang) portable_setenv("LANG",lang);
9315   setlocale(LC_ALL,"");
9316   setlocale(LC_CTYPE,"C"); // to get isspace(0xA0)==0, needed for UTF-8
9317   setlocale(LC_NUMERIC,"C");
9318
9319   //Doxygen::symbolMap->setAutoDelete(TRUE);
9320
9321   Doxygen::runningTime.start();
9322   initPreprocessor();
9323
9324   Doxygen::parserManager = new ParserManager;
9325   Doxygen::parserManager->registerParser("c",       new CLanguageScanner, TRUE);
9326   Doxygen::parserManager->registerParser("python",  new PythonLanguageScanner);
9327   Doxygen::parserManager->registerParser("fortran", new FortranLanguageScanner);
9328   Doxygen::parserManager->registerParser("vhdl",    new VHDLLanguageScanner);
9329   Doxygen::parserManager->registerParser("dbusxml", new DBusXMLScanner);
9330   Doxygen::parserManager->registerParser("tcl",     new TclLanguageScanner);
9331   Doxygen::parserManager->registerParser("md",      new MarkdownFileParser);
9332
9333   // register any additional parsers here...
9334
9335   initDefaultExtensionMapping();
9336   initClassMemberIndices();
9337   initNamespaceMemberIndices();
9338   initFileMemberIndices();
9339
9340   Doxygen::symbolMap     = new QDict<DefinitionIntf>(1000);
9341   Doxygen::inputNameList = new FileNameList;
9342   Doxygen::inputNameList->setAutoDelete(TRUE);
9343   Doxygen::memberNameSDict = new MemberNameSDict(10000);   
9344   Doxygen::memberNameSDict->setAutoDelete(TRUE);
9345   Doxygen::functionNameSDict = new MemberNameSDict(10000);   
9346   Doxygen::functionNameSDict->setAutoDelete(TRUE);
9347   Doxygen::groupSDict = new GroupSDict(17);          
9348   Doxygen::groupSDict->setAutoDelete(TRUE);
9349   Doxygen::globalScope = new NamespaceDef("<globalScope>",1,"<globalScope>");
9350   Doxygen::namespaceSDict = new NamespaceSDict(20);      
9351   Doxygen::namespaceSDict->setAutoDelete(TRUE);
9352   Doxygen::classSDict = new ClassSDict(1009);         
9353   Doxygen::classSDict->setAutoDelete(TRUE);
9354   Doxygen::hiddenClasses = new ClassSDict(257);
9355   Doxygen::hiddenClasses->setAutoDelete(TRUE);
9356   Doxygen::directories = new DirSDict(17);
9357   Doxygen::directories->setAutoDelete(TRUE);
9358   Doxygen::pageSDict = new PageSDict(1009);          // all doc pages
9359   Doxygen::pageSDict->setAutoDelete(TRUE);
9360   Doxygen::exampleSDict = new PageSDict(1009);       // all examples
9361   Doxygen::exampleSDict->setAutoDelete(TRUE);
9362   Doxygen::inputNameDict = new FileNameDict(10007);
9363   Doxygen::includeNameDict = new FileNameDict(10007);
9364   Doxygen::exampleNameDict = new FileNameDict(1009);
9365   Doxygen::exampleNameDict->setAutoDelete(TRUE);
9366   Doxygen::imageNameDict = new FileNameDict(257);
9367   Doxygen::dotFileNameDict = new FileNameDict(257);
9368   Doxygen::mscFileNameDict = new FileNameDict(257);
9369   Doxygen::sectionDict.setAutoDelete(TRUE);
9370   Doxygen::memGrpInfoDict.setAutoDelete(TRUE);
9371   Doxygen::tagDestinationDict.setAutoDelete(TRUE);
9372   Doxygen::dirRelations.setAutoDelete(TRUE);
9373   Doxygen::citeDict = new CiteDict(257);
9374 }
9375
9376 void cleanUpDoxygen()
9377 {
9378   delete Doxygen::inputNameDict;
9379   delete Doxygen::includeNameDict;
9380   delete Doxygen::exampleNameDict;
9381   delete Doxygen::imageNameDict;
9382   delete Doxygen::dotFileNameDict;
9383   delete Doxygen::mscFileNameDict;
9384   delete Doxygen::mainPage;
9385   delete Doxygen::pageSDict;  
9386   delete Doxygen::exampleSDict;
9387   delete Doxygen::globalScope;
9388   delete Doxygen::xrefLists;
9389   delete Doxygen::parserManager;
9390   cleanUpPreprocessor();
9391   delete theTranslator;
9392   delete g_outputList;
9393   Mappers::freeMappers();
9394   codeFreeScanner();
9395
9396   if (Doxygen::symbolMap)
9397   {
9398     // iterate through Doxygen::symbolMap and delete all
9399     // DefinitionList objects, since they have no owner
9400     QDictIterator<DefinitionIntf> dli(*Doxygen::symbolMap);
9401     DefinitionIntf *di;
9402     for (dli.toFirst();(di=dli.current());)
9403     {
9404       if (di->definitionType()==DefinitionIntf::TypeSymbolList)
9405       {
9406         DefinitionIntf *tmp = Doxygen::symbolMap->take(dli.currentKey());
9407         delete (DefinitionList *)tmp;
9408       }
9409       else
9410       {
9411         ++dli;
9412       }
9413     } 
9414   }
9415
9416   delete Doxygen::inputNameList;
9417   delete Doxygen::memberNameSDict;
9418   delete Doxygen::functionNameSDict;
9419   delete Doxygen::groupSDict;
9420   delete Doxygen::classSDict;
9421   delete Doxygen::hiddenClasses;
9422   delete Doxygen::namespaceSDict;
9423   delete Doxygen::directories;
9424
9425   //delete Doxygen::symbolMap; <- we cannot do this unless all static lists 
9426   //                              (such as Doxygen::namespaceSDict)
9427   //                              with objects based on Definition are made
9428   //                              dynamic first
9429 }
9430
9431 static int computeIdealCacheParam(uint v)
9432 {
9433   //printf("computeIdealCacheParam(v=%u)\n",v);
9434
9435   int r=0;
9436   while (v!=0) v>>=1,r++; 
9437   // r = log2(v)
9438
9439   // convert to a valid cache size value
9440   return QMAX(0,QMIN(r-16,9));
9441 }
9442
9443 void readConfiguration(int argc, char **argv)
9444 {
9445   /**************************************************************************
9446    *             Handle arguments                                           *
9447    **************************************************************************/
9448
9449   int optind=1;
9450   const char *configName=0;
9451   const char *layoutName=0;
9452   const char *debugLabel;
9453   const char *formatName;
9454   bool genConfig=FALSE;
9455   bool shortList=FALSE;
9456   bool updateConfig=FALSE;
9457   bool genLayout=FALSE;
9458   while (optind<argc && argv[optind][0]=='-' && 
9459                (isalpha(argv[optind][1]) || argv[optind][1]=='?' || 
9460                 argv[optind][1]=='-')
9461         )
9462   {
9463     switch(argv[optind][1])
9464     {
9465       case 'g':
9466         genConfig=TRUE;
9467         configName=getArg(argc,argv,optind);
9468         if (strcmp(argv[optind+1],"-")==0)
9469         { configName="-"; optind++; }
9470         if (!configName) 
9471         { configName="Doxyfile"; }
9472         break;
9473       case 'l':
9474         genLayout=TRUE;
9475         layoutName=getArg(argc,argv,optind);
9476         if (!layoutName)
9477         { layoutName="DoxygenLayout.xml"; }
9478         break;
9479       case 'd':
9480         debugLabel=getArg(argc,argv,optind);
9481         Debug::setFlag(debugLabel);
9482         break;
9483       case 's':
9484         shortList=TRUE;
9485         break;
9486       case 'u':
9487         updateConfig=TRUE;
9488         break;
9489       case 'e':
9490         formatName=getArg(argc,argv,optind);
9491         if (!formatName)
9492         {
9493           err("error: option -e is missing format specifier rtf.\n");
9494           cleanUpDoxygen();
9495           exit(1);
9496         }
9497         if (stricmp(formatName,"rtf")==0)
9498         {
9499           if (optind+1>=argc)
9500           {
9501             err("error: option \"-e rtf\" is missing an extensions file name\n");
9502             cleanUpDoxygen();
9503             exit(1);
9504           }
9505           QFile f;
9506           if (openOutputFile(argv[optind+1],f))
9507           {
9508             RTFGenerator::writeExtensionsFile(f);
9509           }
9510           cleanUpDoxygen();
9511           exit(1);
9512         }
9513         err("error: option \"-e\" has invalid format specifier.\n");
9514         cleanUpDoxygen();
9515         exit(1);
9516         break; 
9517       case 'w':
9518         formatName=getArg(argc,argv,optind);
9519         if (!formatName)
9520         {
9521           err("error: option -w is missing format specifier rtf, html or latex\n");
9522           cleanUpDoxygen();
9523           exit(1);
9524         } 
9525         if (stricmp(formatName,"rtf")==0)
9526         {
9527           if (optind+1>=argc)
9528           {
9529             err("error: option \"-w rtf\" is missing a style sheet file name\n");
9530             cleanUpDoxygen();
9531             exit(1);
9532           }
9533           QFile f;
9534           if (openOutputFile(argv[optind+1],f))
9535           {
9536             RTFGenerator::writeStyleSheetFile(f);
9537           }
9538           cleanUpDoxygen();
9539           exit(1);
9540         }
9541         else if (stricmp(formatName,"html")==0)
9542         {
9543           if (optind+4<argc || QFileInfo("Doxyfile").exists())
9544           {
9545             QCString df = optind+4<argc ? argv[optind+4] : QCString("Doxyfile");
9546             if (!Config::instance()->parse(df))
9547             {
9548               err("error opening or reading configuration file %s!\n",argv[optind+4]);
9549               cleanUpDoxygen();
9550               exit(1);
9551             }
9552             Config::instance()->substituteEnvironmentVars();
9553             Config::instance()->convertStrToVal();
9554             // avoid bootstrapping issues when the config file already
9555             // refers to the files that we are supposed to parse.
9556             Config_getString("HTML_HEADER")="";
9557             Config_getString("HTML_FOOTER")="";
9558             Config::instance()->check();
9559           }
9560           else
9561           {
9562             Config::instance()->init();
9563           }
9564           if (optind+3>=argc)
9565           {
9566             err("error: option \"-w html\" does not have enough arguments\n");
9567             cleanUpDoxygen();
9568             exit(1);
9569           }
9570
9571           QCString outputLanguage=Config_getEnum("OUTPUT_LANGUAGE");
9572           if (!setTranslator(outputLanguage))
9573           {
9574             err("warning: Output language %s not supported! Using English instead.\n", outputLanguage.data());
9575           }
9576
9577           QFile f;
9578           if (openOutputFile(argv[optind+1],f))
9579           {
9580             HtmlGenerator::writeHeaderFile(f, argv[optind+3]);
9581           }
9582           f.close();
9583           if (openOutputFile(argv[optind+2],f))
9584           {
9585             HtmlGenerator::writeFooterFile(f);
9586           }
9587           f.close();
9588           if (openOutputFile(argv[optind+3],f))
9589           {
9590             HtmlGenerator::writeStyleSheetFile(f);
9591           } 
9592           cleanUpDoxygen();
9593           exit(0);
9594         }
9595         else if (stricmp(formatName,"latex")==0)
9596         {
9597           if (optind+4<argc) // use config file to get settings
9598           {
9599             if (!Config::instance()->parse(argv[optind+4]))
9600             {
9601               err("error opening or reading configuration file %s!\n",argv[optind+4]);
9602               exit(1);
9603             }
9604             Config::instance()->substituteEnvironmentVars();
9605             Config::instance()->convertStrToVal();
9606             Config_getString("LATEX_HEADER")="";
9607             Config::instance()->check();
9608           }
9609           else // use default config
9610           {
9611             Config::instance()->init();
9612           }
9613           if (optind+3>=argc)
9614           {
9615             err("error: option \"-w latex\" does not have enough arguments\n");
9616             cleanUpDoxygen();
9617             exit(1);
9618           }
9619
9620           QCString outputLanguage=Config_getEnum("OUTPUT_LANGUAGE");
9621           if (!setTranslator(outputLanguage))
9622           {
9623             err("warning: Output language %s not supported! Using English instead.\n", outputLanguage.data());
9624           }
9625
9626           QFile f;
9627           if (openOutputFile(argv[optind+1],f))
9628           {
9629             LatexGenerator::writeHeaderFile(f);
9630           }
9631           f.close();
9632           if (openOutputFile(argv[optind+2],f))
9633           {
9634             LatexGenerator::writeFooterFile(f);
9635           }
9636           f.close();
9637           if (openOutputFile(argv[optind+3],f))
9638           {
9639             LatexGenerator::writeStyleSheetFile(f);
9640           }
9641           cleanUpDoxygen();
9642           exit(0);
9643         }
9644         else
9645         {
9646           err("error: Illegal format specifier %s: should be one of rtf, html, latex, or bst\n",formatName);
9647           cleanUpDoxygen();
9648           exit(1);
9649         }
9650         break;
9651       case 'm':
9652         g_dumpSymbolMap = TRUE;
9653         break;
9654       case 'x':
9655         g_dumpConfigAsXML = TRUE;
9656         break;
9657       case '-':
9658         if (strcmp(&argv[optind][2],"help")==0)
9659         {
9660           usage(argv[0]);
9661         }
9662         else if (strcmp(&argv[optind][2],"version")==0)
9663         {
9664           msg("%s\n",versionString); 
9665           cleanUpDoxygen();
9666           exit(0);
9667         }
9668         break;
9669       case 'b':
9670         setvbuf(stdout,NULL,_IONBF,0);
9671         Doxygen::outputToWizard=TRUE;
9672         break;
9673       case 'h':
9674       case '?':
9675         usage(argv[0]);
9676         break;
9677       default:
9678         err("Unknown option -%c\n",argv[optind][1]);
9679         usage(argv[0]);
9680     }
9681     optind++;
9682   }
9683   
9684   /**************************************************************************
9685    *            Parse or generate the config file                           *
9686    **************************************************************************/
9687
9688   Config::instance()->init();
9689
9690   if (genConfig)
9691   {
9692     if (g_dumpConfigAsXML)
9693     {
9694       checkConfiguration();
9695       generateConfigFile(configName,shortList);
9696       dumpConfigAsXML();
9697       exit(0); 
9698     }
9699     else
9700     {
9701       generateConfigFile(configName,shortList);
9702     }
9703     cleanUpDoxygen();
9704     exit(0);
9705   }
9706   if (genLayout)
9707   {
9708     writeDefaultLayoutFile(layoutName);
9709     cleanUpDoxygen();
9710     exit(0);
9711   }
9712
9713   QFileInfo configFileInfo1("Doxyfile"),configFileInfo2("doxyfile");
9714   if (optind>=argc)
9715   { 
9716     if (configFileInfo1.exists()) 
9717     {
9718       configName="Doxyfile";
9719     }
9720     else if (configFileInfo2.exists())
9721     {
9722       configName="doxyfile";
9723     }
9724     else
9725     {
9726       err("Doxyfile not found and no input file specified!\n");
9727       usage(argv[0]);
9728     }
9729   }
9730   else
9731   {
9732     QFileInfo fi(argv[optind]);
9733     if (fi.exists() || strcmp(argv[optind],"-")==0)
9734     {
9735       configName=argv[optind];
9736     }
9737     else
9738     {
9739       err("error: configuration file %s not found!\n",argv[optind]);
9740       usage(argv[0]);
9741     }
9742   }
9743
9744
9745   if (!Config::instance()->parse(configName))
9746   {
9747     err("error: could not open or read configuration file %s!\n",configName);
9748     cleanUpDoxygen();
9749     exit(1);
9750   }
9751
9752   if (updateConfig)
9753   {
9754     generateConfigFile(configName,shortList,TRUE);
9755     cleanUpDoxygen();
9756     exit(0);
9757   }
9758
9759   /* Perlmod wants to know the path to the config file.*/
9760   QFileInfo configFileInfo(configName);
9761   setPerlModDoxyfile(configFileInfo.absFilePath().data());
9762
9763 }
9764
9765 /** check and resolve config options */
9766 void checkConfiguration()
9767 {
9768   
9769   Config::instance()->substituteEnvironmentVars();
9770   Config::instance()->convertStrToVal();
9771   Config::instance()->check();
9772   
9773   initWarningFormat();
9774 }
9775
9776 /** adjust globals that depend on configuration settings. */
9777 void adjustConfiguration()
9778 {
9779   QCString outputLanguage=Config_getEnum("OUTPUT_LANGUAGE");
9780   if (!setTranslator(outputLanguage))
9781   {
9782     err("warning: Output language %s not supported! Using English instead.\n",
9783        outputLanguage.data());
9784   }
9785   QStrList &includePath = Config_getList("INCLUDE_PATH");
9786   char *s=includePath.first();
9787   while (s)
9788   {
9789     QFileInfo fi(s);
9790     addSearchDir(fi.absFilePath().utf8());
9791     s=includePath.next();
9792   }
9793
9794   /* Set the global html file extension. */ 
9795   Doxygen::htmlFileExtension = Config_getString("HTML_FILE_EXTENSION");
9796
9797
9798   Doxygen::xrefLists->setAutoDelete(TRUE);
9799
9800   Doxygen::parseSourcesNeeded = Config_getBool("CALL_GRAPH") || 
9801                                 Config_getBool("CALLER_GRAPH") ||
9802                                 Config_getBool("REFERENCES_RELATION") ||
9803                                 Config_getBool("REFERENCED_BY_RELATION");
9804
9805   Doxygen::markdownSupport = Config_getBool("MARKDOWN_SUPPORT");
9806   
9807   /**************************************************************************
9808    *            Add custom extension mappings
9809    **************************************************************************/
9810
9811   QStrList &extMaps = Config_getList("EXTENSION_MAPPING");
9812   char *mapping = extMaps.first();
9813   while (mapping)
9814   {
9815     QCString mapStr = mapping;
9816     int i;
9817     if ((i=mapStr.find('='))!=-1)
9818     {
9819       QCString ext=mapStr.left(i).stripWhiteSpace().lower();
9820       QCString language=mapStr.mid(i+1).stripWhiteSpace().lower();
9821       if (!updateLanguageMapping(ext,language))
9822       {
9823         err("Failed to map file extension '%s' to unsupported language '%s'.\n"
9824             "Check the EXTENSION_MAPPING setting in the config file.\n", 
9825             ext.data(),language.data());
9826       }
9827       else
9828       {
9829         msg("Adding custom extension mapping: .%s will be treated as language %s\n",
9830             ext.data(),language.data());
9831       }
9832     }
9833     mapping = extMaps.next();
9834   }
9835
9836
9837   // add predefined macro name to a dictionary
9838   QStrList &expandAsDefinedList =Config_getList("EXPAND_AS_DEFINED");
9839   s=expandAsDefinedList.first();
9840   while (s)
9841   {
9842     if (Doxygen::expandAsDefinedDict[s]==0)
9843     {
9844       Doxygen::expandAsDefinedDict.insert(s,(void *)666);
9845     }
9846     s=expandAsDefinedList.next();
9847   }
9848
9849   // read aliases and store them in a dictionary
9850   readAliases();
9851
9852   // store number of spaces in a tab into Doxygen::spaces
9853   int &tabSize = Config_getInt("TAB_SIZE");
9854   Doxygen::spaces.resize(tabSize+1);
9855   int sp;for (sp=0;sp<tabSize;sp++) Doxygen::spaces.at(sp)=' ';
9856   Doxygen::spaces.at(tabSize)='\0';
9857 }
9858
9859 #ifdef HAS_SIGNALS
9860 static void stopDoxygen(int)
9861 {
9862   QDir thisDir;
9863   msg("Cleaning up...\n");
9864   if (!Doxygen::entryDBFileName.isEmpty())
9865   {
9866     thisDir.remove(Doxygen::entryDBFileName);
9867   }
9868   if (!Doxygen::objDBFileName.isEmpty())
9869   {
9870     thisDir.remove(Doxygen::objDBFileName);
9871   }
9872   exit(1);
9873 }
9874 #endif
9875
9876 static void exitDoxygen()
9877 {
9878   if (!g_successfulRun)  // premature exit
9879   {
9880     QDir thisDir;
9881     msg("Exiting...\n");
9882     if (!Doxygen::entryDBFileName.isEmpty())
9883     {
9884       thisDir.remove(Doxygen::entryDBFileName);
9885     }
9886     if (!Doxygen::objDBFileName.isEmpty())
9887     {
9888       thisDir.remove(Doxygen::objDBFileName);
9889     }
9890   }
9891 }
9892
9893 static QCString createOutputDirectory(const QCString &baseDirName,
9894                                   const char *formatDirOption,
9895                                   const char *defaultDirName)
9896 {
9897   // Note the & on the next line, we modify the formatDirOption!
9898   QCString &formatDirName = Config_getString(formatDirOption);
9899   if (formatDirName.isEmpty())
9900   {
9901     formatDirName = baseDirName + defaultDirName;
9902   }
9903   else if (formatDirName[0]!='/' && (formatDirName.length()==1 || formatDirName[1]!=':'))
9904   {
9905     formatDirName.prepend(baseDirName+'/');
9906   }
9907   QDir formatDir(formatDirName);
9908   if (!formatDir.exists() && !formatDir.mkdir(formatDirName))
9909   {
9910     err("Could not create output directory %s\n", formatDirName.data());
9911     cleanUpDoxygen();
9912     exit(1);
9913   }
9914   return formatDirName;
9915 }
9916
9917 static QCString getQchFileName()
9918 {
9919   QCString const & qchFile = Config_getString("QCH_FILE");
9920   if (!qchFile.isEmpty())
9921   {
9922     return qchFile;
9923   }
9924
9925   QCString const & projectName = Config_getString("PROJECT_NAME");
9926   QCString const & versionText = Config_getString("PROJECT_NUMBER");
9927
9928   return QCString("../qch/")
9929       + (projectName.isEmpty() ? QCString("index") : projectName)
9930       + (versionText.isEmpty() ? QCString("") : QCString("-") + versionText)
9931       + QCString(".qch");
9932 }
9933
9934 void searchInputFiles(StringList &inputFiles)
9935 {
9936   QStrList &exclPatterns = Config_getList("EXCLUDE_PATTERNS");
9937   bool alwaysRecursive = Config_getBool("RECURSIVE");
9938   StringDict excludeNameDict(1009);
9939   excludeNameDict.setAutoDelete(TRUE);
9940
9941   // gather names of all files in the include path
9942   msg("Searching for include files...\n");
9943   QStrList &includePathList = Config_getList("INCLUDE_PATH");
9944   char *s=includePathList.first();
9945   while (s)
9946   {
9947     QStrList &pl = Config_getList("INCLUDE_FILE_PATTERNS");
9948     if (pl.count()==0) 
9949     {
9950       pl = Config_getList("FILE_PATTERNS");
9951     }
9952     readFileOrDirectory(s,0,Doxygen::includeNameDict,0,&pl,
9953                         &exclPatterns,0,0,
9954                         alwaysRecursive);
9955     s=includePathList.next(); 
9956   }
9957   
9958   msg("Searching for example files...\n");
9959   QStrList &examplePathList = Config_getList("EXAMPLE_PATH");
9960   s=examplePathList.first();
9961   while (s)
9962   {
9963     readFileOrDirectory(s,0,Doxygen::exampleNameDict,0,
9964                         &Config_getList("EXAMPLE_PATTERNS"),
9965                         0,0,0,
9966                         (alwaysRecursive || Config_getBool("EXAMPLE_RECURSIVE")));
9967     s=examplePathList.next(); 
9968   }
9969
9970   msg("Searching for images...\n");
9971   QStrList &imagePathList=Config_getList("IMAGE_PATH");
9972   s=imagePathList.first();
9973   while (s)
9974   {
9975     readFileOrDirectory(s,0,Doxygen::imageNameDict,0,0,
9976                         0,0,0,
9977                         alwaysRecursive);
9978     s=imagePathList.next(); 
9979   }
9980
9981   msg("Searching for dot files...\n");
9982   QStrList &dotFileList=Config_getList("DOTFILE_DIRS");
9983   s=dotFileList.first();
9984   while (s)
9985   {
9986     readFileOrDirectory(s,0,Doxygen::dotFileNameDict,0,0,
9987                         0,0,0,
9988                         alwaysRecursive);
9989     s=dotFileList.next(); 
9990   }
9991
9992   msg("Searching for msc files...\n");
9993   QStrList &mscFileList=Config_getList("MSCFILE_DIRS");
9994   s=mscFileList.first();
9995   while (s)
9996   {
9997     readFileOrDirectory(s,0,Doxygen::mscFileNameDict,0,0,
9998                         0,0,0,
9999                         alwaysRecursive);
10000     s=mscFileList.next(); 
10001   }
10002
10003
10004   msg("Searching for files to exclude\n");
10005   QStrList &excludeList = Config_getList("EXCLUDE");
10006   s=excludeList.first();
10007   while (s)
10008   {
10009     readFileOrDirectory(s,0,0,0,&Config_getList("FILE_PATTERNS"),
10010                         0,0,&excludeNameDict,
10011                         alwaysRecursive,
10012                         FALSE);
10013     s=excludeList.next();
10014   }
10015
10016   /**************************************************************************
10017    *             Determine Input Files                                      *
10018    **************************************************************************/
10019
10020   msg("Searching for files to process...\n");
10021   QDict<void> *killDict = new QDict<void>(10007);
10022   int inputSize=0;
10023   QStrList &inputList=Config_getList("INPUT");
10024   inputFiles.setAutoDelete(TRUE);
10025   s=inputList.first();
10026   while (s)
10027   {
10028     QCString path=s;
10029     uint l = path.length();
10030     // strip trailing slashes
10031     if (path.at(l-1)=='\\' || path.at(l-1)=='/') path=path.left(l-1);
10032
10033     inputSize+=readFileOrDirectory(
10034         path,
10035         Doxygen::inputNameList,
10036         Doxygen::inputNameDict,
10037         &excludeNameDict,
10038         &Config_getList("FILE_PATTERNS"),
10039         &exclPatterns,
10040         &inputFiles,0,
10041         alwaysRecursive,
10042         TRUE,
10043         killDict);
10044     s=inputList.next();
10045   }
10046   delete killDict;
10047 }
10048
10049   
10050 void parseInput()
10051 {
10052   atexit(exitDoxygen);
10053
10054
10055   /**************************************************************************
10056    *            Make sure the output directory exists
10057    **************************************************************************/
10058   QCString &outputDirectory = Config_getString("OUTPUT_DIRECTORY");
10059   if (outputDirectory.isEmpty()) 
10060   {
10061     outputDirectory=QDir::currentDirPath().utf8();
10062   }
10063   else
10064   {
10065     QDir dir(outputDirectory);
10066     if (!dir.exists())
10067     {
10068       dir.setPath(QDir::currentDirPath());
10069       if (!dir.mkdir(outputDirectory))
10070       {
10071         err("error: tag OUTPUT_DIRECTORY: Output directory `%s' does not "
10072             "exist and cannot be created\n",outputDirectory.data());
10073         cleanUpDoxygen();
10074         exit(1);
10075       }
10076       else if (!Config_getBool("QUIET"))
10077       {
10078         err("Notice: Output directory `%s' does not exist. "
10079             "I have created it for you.\n", outputDirectory.data());
10080       }
10081       dir.cd(outputDirectory);
10082     }
10083     outputDirectory=dir.absPath().utf8();
10084   }
10085
10086   /**************************************************************************
10087    *            Initialize global lists and dictionaries
10088    **************************************************************************/
10089
10090   int cacheSize = Config_getInt("SYMBOL_CACHE_SIZE");
10091   if (cacheSize<0) cacheSize=0;
10092   if (cacheSize>9) cacheSize=9;
10093   Doxygen::symbolCache   = new ObjCache(16+cacheSize); // 16 -> room for 65536 elements, 
10094                                                        //       ~2.0 MByte "overhead"
10095   //Doxygen::symbolCache   = new ObjCache(1);  // only to stress test cache behaviour
10096   Doxygen::symbolStorage = new Store;
10097
10098   // also scale lookup cache with SYMBOL_CACHE_SIZE
10099   cacheSize = Config_getInt("LOOKUP_CACHE_SIZE");
10100   if (cacheSize<0) cacheSize=0;
10101   if (cacheSize>9) cacheSize=9;
10102   uint lookupSize = 65536 << cacheSize;
10103   Doxygen::lookupCache = new QCache<LookupInfo>(lookupSize,lookupSize);
10104   Doxygen::lookupCache->setAutoDelete(TRUE);
10105
10106 #ifdef HAS_SIGNALS
10107   signal(SIGINT, stopDoxygen);
10108 #endif
10109
10110   uint pid = portable_pid();
10111   Doxygen::objDBFileName.sprintf("doxygen_objdb_%d.tmp",pid);
10112   Doxygen::objDBFileName.prepend(outputDirectory+"/");
10113   Doxygen::entryDBFileName.sprintf("doxygen_entrydb_%d.tmp",pid);
10114   Doxygen::entryDBFileName.prepend(outputDirectory+"/");
10115   
10116   if (Doxygen::symbolStorage->open(Doxygen::objDBFileName)==-1)
10117   {
10118     err("Failed to open temporary file %s\n",Doxygen::objDBFileName.data());
10119     exit(1);
10120   }
10121
10122
10123   /**************************************************************************
10124    *            Initialize some global constants
10125    **************************************************************************/
10126   
10127   g_compoundKeywordDict.insert("template class",(void *)8);
10128   g_compoundKeywordDict.insert("template struct",(void *)8);
10129   g_compoundKeywordDict.insert("class",(void *)8);
10130   g_compoundKeywordDict.insert("struct",(void *)8);
10131   g_compoundKeywordDict.insert("union",(void *)8);
10132   g_compoundKeywordDict.insert("interface",(void *)8);
10133   g_compoundKeywordDict.insert("exception",(void *)8);
10134
10135
10136   /**************************************************************************
10137    *            Check/create output directorties                            *
10138    **************************************************************************/
10139
10140   QCString htmlOutput;
10141   bool &generateHtml = Config_getBool("GENERATE_HTML");
10142   if (generateHtml)
10143     htmlOutput = createOutputDirectory(outputDirectory,"HTML_OUTPUT","/html");
10144
10145   QCString xmlOutput;
10146   bool &generateXml = Config_getBool("GENERATE_XML");
10147   if (generateXml)
10148     xmlOutput = createOutputDirectory(outputDirectory,"XML_OUTPUT","/xml");
10149     
10150   QCString latexOutput;
10151   bool &generateLatex = Config_getBool("GENERATE_LATEX");
10152   if (generateLatex)
10153     latexOutput = createOutputDirectory(outputDirectory,"LATEX_OUTPUT","/latex");
10154
10155   QCString rtfOutput;
10156   bool &generateRtf = Config_getBool("GENERATE_RTF");
10157   if (generateRtf)
10158     rtfOutput = createOutputDirectory(outputDirectory,"RTF_OUTPUT","/rtf");
10159
10160   QCString manOutput;
10161   bool &generateMan = Config_getBool("GENERATE_MAN");
10162   if (generateMan)
10163     manOutput = createOutputDirectory(outputDirectory,"MAN_OUTPUT","/man");
10164
10165
10166   if (Config_getBool("HAVE_DOT"))
10167   {
10168     QCString curFontPath = Config_getString("DOT_FONTPATH");
10169     if (curFontPath.isEmpty())
10170     {
10171       portable_getenv("DOTFONTPATH");
10172       QCString newFontPath = ".";
10173       if (!curFontPath.isEmpty())
10174       {
10175         newFontPath+=portable_pathListSeparator();
10176         newFontPath+=curFontPath;
10177       }
10178       portable_setenv("DOTFONTPATH",newFontPath);
10179     }
10180     else
10181     {
10182       portable_setenv("DOTFONTPATH",curFontPath);
10183     }
10184   }
10185
10186
10187
10188   /**************************************************************************
10189    *             Handle layout file                                         *
10190    **************************************************************************/
10191
10192   LayoutDocManager::instance().init();
10193   QCString &layoutFileName = Config_getString("LAYOUT_FILE");
10194   bool defaultLayoutUsed = FALSE;
10195   if (layoutFileName.isEmpty())
10196   {
10197     layoutFileName = "DoxygenLayout.xml";
10198     defaultLayoutUsed = TRUE;
10199   }
10200
10201   QFile layoutFile(layoutFileName);
10202   if (layoutFile.open(IO_ReadOnly))
10203   {
10204     msg("Parsing layout file %s...\n",layoutFileName.data());
10205     QTextStream t(&layoutFile); 
10206     t.setEncoding(QTextStream::Latin1);
10207     LayoutDocManager::instance().parse(t,layoutFileName);
10208   }
10209   else if (!defaultLayoutUsed)
10210   {
10211     err("warning: failed to open layout file '%s' for reading!\n",layoutFileName.data());
10212   }
10213
10214   /**************************************************************************
10215    *             Read and preprocess input                                  *
10216    **************************************************************************/
10217  
10218   // prevent search in the output directories
10219   QStrList &exclPatterns = Config_getList("EXCLUDE_PATTERNS");
10220   if (generateHtml)  exclPatterns.append(htmlOutput);
10221   if (generateXml)   exclPatterns.append(xmlOutput);
10222   if (generateLatex) exclPatterns.append(latexOutput);
10223   if (generateRtf)   exclPatterns.append(rtfOutput);
10224   if (generateMan)   exclPatterns.append(manOutput);
10225
10226
10227   searchInputFiles(g_inputFiles);
10228
10229   // Notice: the order of the function calls below is very important!
10230   
10231   if (Config_getBool("GENERATE_HTML"))
10232   {
10233     readFormulaRepository();
10234   }
10235   
10236   /**************************************************************************
10237    *             Handle Tag Files                                           *
10238    **************************************************************************/
10239
10240   g_storage = new FileStorage;
10241   g_storage->setName(Doxygen::entryDBFileName);
10242   if (!g_storage->open(IO_WriteOnly))
10243   {
10244     err("Failed to create temporary storage file %s\n",
10245         Doxygen::entryDBFileName.data());
10246     exit(1);
10247   }
10248   Entry *root=new Entry;
10249   EntryNav *rootNav = new EntryNav(0,root);
10250   rootNav->setEntry(root);
10251   msg("Reading and parsing tag files\n");
10252   
10253   QStrList &tagFileList = Config_getList("TAGFILES");
10254   char *s=tagFileList.first();
10255   while (s)
10256   {
10257     readTagFile(root,s);
10258     root->createNavigationIndex(rootNav,g_storage,0);
10259     s=tagFileList.next();
10260   }
10261   
10262   /**************************************************************************
10263    *             Parse source files                                         * 
10264    **************************************************************************/
10265
10266   if (Config_getBool("BUILTIN_STL_SUPPORT"))
10267   {
10268     addSTLClasses(rootNav);
10269   }
10270
10271   parseFiles(root,rootNav);
10272   g_storage->close();
10273
10274   // we are done with input scanning now, so free up the buffers used by flex
10275   // (can be around 4MB)
10276   preFreeScanner();
10277   scanFreeScanner();
10278   pyscanFreeScanner();
10279
10280   if (!g_storage->open(IO_ReadOnly))
10281   {
10282     err("Failed to open temporary storage file %s for reading",
10283         Doxygen::entryDBFileName.data());
10284     exit(1);
10285   }
10286
10287   /**************************************************************************
10288    *             Gather information                                         * 
10289    **************************************************************************/
10290   
10291   msg("Building group list...\n");
10292   buildGroupList(rootNav);
10293   organizeSubGroups(rootNav);
10294
10295   msg("Building directory list...\n");
10296   buildDirectories();
10297   findDirDocumentation(rootNav);
10298
10299   msg("Building namespace list...\n");
10300   buildNamespaceList(rootNav);
10301   findUsingDirectives(rootNav);
10302
10303   msg("Building file list...\n");
10304   buildFileList(rootNav);
10305   //generateFileTree();
10306   
10307   msg("Building class list...\n");
10308   buildClassList(rootNav);
10309
10310   msg("Associating documentation with classes...\n");
10311   buildClassDocList(rootNav);
10312
10313   // build list of using declarations here (global list)
10314   buildListOfUsingDecls(rootNav);
10315   
10316   msg("Computing nesting relations for classes...\n");
10317   resolveClassNestingRelations();
10318   distributeClassGroupRelations();
10319
10320   // calling buildClassList may result in cached relations that
10321   // become invalid after resolveClassNestingRelations(), that's why
10322   // we need to clear the cache here
10323   Doxygen::lookupCache->clear();
10324   // we don't need the list of using declaration anymore
10325   g_usingDeclarations.clear();
10326
10327   msg("Building example list...\n");
10328   buildExampleList(rootNav);
10329   
10330   msg("Searching for enumerations...\n");
10331   findEnums(rootNav);
10332   
10333   // Since buildVarList calls isVarWithConstructor
10334   // and this calls getResolvedClass we need to process
10335   // typedefs first so the relations between classes via typedefs
10336   // are properly resolved. See bug 536385 for an example.
10337   msg("Searching for documented typedefs...\n");
10338   buildTypedefList(rootNav);
10339
10340   msg("Searching for members imported via using declarations...\n");
10341   findUsingDeclImports(rootNav);
10342   // this should be after buildTypedefList in order to properly import
10343   // used typedefs
10344   findUsingDeclarations(rootNav);
10345
10346   msg("Searching for included using directives...\n");
10347   findIncludedUsingDirectives();
10348
10349   msg("Searching for documented variables...\n");
10350   buildVarList(rootNav);
10351
10352   msg("Building member list...\n"); // using class info only !
10353   buildFunctionList(rootNav);
10354
10355   msg("Searching for friends...\n");
10356   findFriends();
10357   
10358   msg("Searching for documented defines...\n");
10359   findDefineDocumentation(rootNav); 
10360   
10361   findClassEntries(rootNav);         
10362   msg("Computing class inheritance relations...\n");
10363   findInheritedTemplateInstances();       
10364   msg("Computing class usage relations...\n");
10365   findUsedTemplateInstances();       
10366   if (Config_getBool("INLINE_SIMPLE_STRUCTS"))
10367   {
10368     msg("Searching for tag less structs...\n");
10369     findTagLessClasses();
10370   }
10371
10372   msg("Flushing cached template relations that have become invalid...\n");
10373   flushCachedTemplateRelations();
10374   
10375   msg("Creating members for template instances...\n");
10376   createTemplateInstanceMembers();
10377
10378   msg("Computing class relations...\n");
10379   computeTemplateClassRelations(); 
10380   flushUnresolvedRelations();
10381   if (Config_getBool("OPTIMIZE_OUTPUT_VHDL"))
10382   {
10383     VhdlDocGen::computeVhdlComponentRelations(); 
10384   }
10385   computeClassRelations();        
10386   g_classEntries.clear();          
10387
10388   msg("Add enum values to enums...\n");
10389   addEnumValuesToEnums(rootNav);
10390   findEnumDocumentation(rootNav);
10391
10392   msg("Searching for member function documentation...\n");
10393   findObjCMethodDefinitions(rootNav);
10394   findMemberDocumentation(rootNav); // may introduce new members !
10395
10396   transferRelatedFunctionDocumentation();
10397   transferFunctionDocumentation();
10398   
10399   msg("Building page list...\n");
10400   buildPageList(rootNav);
10401
10402   msg("Search for main page...\n");
10403   findMainPage(rootNav);
10404
10405   msg("Computing page relations...\n");
10406   computePageRelations(rootNav);
10407   checkPageRelations();
10408
10409   msg("Determining the scope of groups...\n");
10410   findGroupScope(rootNav);
10411
10412   msg("Sorting lists...\n");
10413   Doxygen::memberNameSDict->sort();
10414   Doxygen::functionNameSDict->sort();
10415   Doxygen::hiddenClasses->sort();
10416   Doxygen::classSDict->sort();
10417   
10418   msg("Freeing entry tree\n");
10419   delete rootNav;
10420   g_storage->close();
10421   delete g_storage;
10422   g_storage=0;
10423
10424   QDir thisDir;
10425   thisDir.remove(Doxygen::entryDBFileName);
10426   
10427   msg("Determining which enums are documented\n");
10428   findDocumentedEnumValues();
10429
10430   msg("Computing member relations...\n");
10431   mergeCategories();
10432   computeMemberRelations();
10433
10434   msg("Building full member lists recursively...\n");
10435   buildCompleteMemberLists();
10436   
10437   msg("Adding members to member groups.\n");
10438   addMembersToMemberGroup();
10439
10440   if (Config_getBool("DISTRIBUTE_GROUP_DOC"))
10441   {
10442     msg("Distributing member group documentation.\n");
10443     distributeMemberGroupDocumentation();
10444   }
10445   
10446   msg("Computing member references...\n");
10447   computeMemberReferences(); 
10448
10449   if (Config_getBool("INHERIT_DOCS"))
10450   {
10451     msg("Inheriting documentation...\n");
10452     inheritDocumentation();
10453   }
10454
10455   // compute the shortest possible names of all files
10456   // without losing the uniqueness of the file names.
10457   msg("Generating disk names...\n");
10458   Doxygen::inputNameList->generateDiskNames();
10459   
10460   msg("Adding source references...\n");
10461   addSourceReferences();
10462
10463   msg("Adding xrefitems...\n");
10464   addListReferences();
10465   generateXRefPages();
10466
10467   msg("Sorting member lists...\n");
10468   sortMemberLists();
10469
10470   if (Config_getBool("DIRECTORY_GRAPH"))
10471   {
10472     msg("Computing dependencies between directories...\n");
10473     computeDirDependencies();
10474   }
10475
10476   //msg("Resolving citations...\n");
10477   //Doxygen::citeDict->resolve();
10478
10479   msg("Generating citations page...\n");
10480   Doxygen::citeDict->generatePage();
10481
10482   msg("Counting data structures...\n");
10483   countDataStructures();
10484  
10485   msg("Resolving user defined references...\n");
10486   resolveUserReferences();
10487
10488   msg("Finding anchors and sections in the documentation...\n");
10489   findSectionsInDocumentation();
10490
10491   transferFunctionReferences();
10492
10493   msg("Combining using relations...\n");
10494   combineUsingRelations();
10495
10496   msg("Adding members to index pages...\n");
10497   addMembersToIndex();
10498
10499   if (Config_getBool("OPTIMIZE_OUTPUT_VHDL") && 
10500       Config_getBool("HAVE_DOT") &&
10501       Config_getEnum("DOT_IMAGE_FORMAT")=="svg")
10502   {
10503     VhdlDocGen::writeOverview();
10504   }
10505 }
10506
10507 void generateOutput()
10508 {
10509   /**************************************************************************
10510    *            Initialize output generators                                *
10511    **************************************************************************/
10512
10513   //// dump all symbols
10514   if (g_dumpSymbolMap)
10515   {
10516     dumpSymbolMap();
10517     exit(0);
10518   }
10519
10520   initSearchIndexer();
10521
10522   bool generateHtml  = Config_getBool("GENERATE_HTML");
10523   bool generateLatex = Config_getBool("GENERATE_LATEX");
10524   bool generateMan   = Config_getBool("GENERATE_MAN");
10525   bool generateRtf   = Config_getBool("GENERATE_RTF");
10526
10527
10528   g_outputList = new OutputList(TRUE);
10529   if (generateHtml)  
10530   {
10531     g_outputList->add(new HtmlGenerator);
10532     HtmlGenerator::init();
10533
10534     // add HTML indexers that are enabled
10535     bool generateHtmlHelp    = Config_getBool("GENERATE_HTMLHELP");
10536     bool generateEclipseHelp = Config_getBool("GENERATE_ECLIPSEHELP");
10537     bool generateQhp         = Config_getBool("GENERATE_QHP");
10538     bool generateTreeView    = Config_getBool("GENERATE_TREEVIEW");
10539     bool generateDocSet      = Config_getBool("GENERATE_DOCSET");
10540     if (generateEclipseHelp) Doxygen::indexList.addIndex(new EclipseHelp);
10541     if (generateHtmlHelp)    Doxygen::indexList.addIndex(new HtmlHelp);
10542     if (generateQhp)         Doxygen::indexList.addIndex(new Qhp);
10543     if (generateTreeView)    Doxygen::indexList.addIndex(new FTVHelp(TRUE));
10544     if (generateDocSet)      Doxygen::indexList.addIndex(new DocSets);
10545     Doxygen::indexList.initialize();
10546     HtmlGenerator::writeTabData();
10547
10548     // copy static stuff
10549     copyStyleSheet();
10550     copyLogo();
10551     copyExtraFiles();
10552     FTVHelp::generateTreeViewImages();
10553   }
10554   if (generateLatex) 
10555   {
10556     g_outputList->add(new LatexGenerator);
10557     LatexGenerator::init();
10558   }
10559   if (generateMan)
10560   {
10561     g_outputList->add(new ManGenerator);
10562     ManGenerator::init();
10563   }
10564   if (generateRtf)
10565   {
10566     g_outputList->add(new RTFGenerator);
10567     RTFGenerator::init();
10568   }
10569
10570   if (Config_getBool("USE_HTAGS"))
10571   {
10572     Htags::useHtags = TRUE;
10573     QCString htmldir = Config_getString("HTML_OUTPUT");
10574     if (!Htags::execute(htmldir))
10575        err("error: USE_HTAGS is YES but htags(1) failed. \n");
10576     if (!Htags::loadFilemap(htmldir))
10577        err("error: htags(1) ended normally but failed to load the filemap. \n");
10578   }
10579   
10580   /**************************************************************************
10581    *                        Generate documentation                          *
10582    **************************************************************************/
10583
10584   QFile *tag=0;
10585   QCString &generateTagFile = Config_getString("GENERATE_TAGFILE");
10586   if (!generateTagFile.isEmpty())
10587   {
10588     tag=new QFile(generateTagFile);
10589     if (!tag->open(IO_WriteOnly))
10590     {
10591       err("error: cannot open tag file %s for writing\n",
10592           generateTagFile.data()
10593          );
10594       cleanUpDoxygen();
10595       exit(1);
10596     }
10597     Doxygen::tagFile.setDevice(tag);
10598     Doxygen::tagFile << "<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>" << endl;
10599     Doxygen::tagFile << "<tagfile>" << endl;
10600   }
10601
10602   if (generateHtml)  writeDoxFont(Config_getString("HTML_OUTPUT"));
10603   if (generateLatex) writeDoxFont(Config_getString("LATEX_OUTPUT"));
10604   if (generateRtf)   writeDoxFont(Config_getString("RTF_OUTPUT"));
10605
10606   msg("Generating style sheet...\n");
10607   //printf("writing style info\n");
10608   QCString genString = 
10609         theTranslator->trGeneratedAt(dateToString(TRUE),Config_getString("PROJECT_NAME"));
10610   g_outputList->writeStyleInfo(0); // write first part
10611   g_outputList->disableAllBut(OutputGenerator::Latex);
10612   g_outputList->parseText(genString);
10613   g_outputList->writeStyleInfo(1); // write second part
10614   //parseText(*g_outputList,theTranslator->trWrittenBy());
10615   g_outputList->writeStyleInfo(2); // write third part
10616   g_outputList->parseText(genString);
10617   g_outputList->writeStyleInfo(3); // write fourth part
10618   //parseText(*g_outputList,theTranslator->trWrittenBy());
10619   g_outputList->writeStyleInfo(4); // write last part
10620   g_outputList->enableAll();
10621   
10622   static bool searchEngine      = Config_getBool("SEARCHENGINE");
10623   static bool serverBasedSearch = Config_getBool("SERVER_BASED_SEARCH");
10624
10625   // generate search indices (need to do this before writing other HTML
10626   // pages as these contain a drop down menu with options depending on
10627   // what categories we find in this function.
10628   if (generateHtml && searchEngine)
10629   {
10630     msg("Generating search indices...\n");
10631     QCString searchDirName = Config_getString("HTML_OUTPUT")+"/search";
10632     QDir searchDir(searchDirName);
10633     if (!searchDir.exists() && !searchDir.mkdir(searchDirName))
10634     {
10635       err("error: Could not create search results directory '%s' $PWD='%s'\n",
10636           searchDirName.data(),QDir::currentDirPath().data());
10637       exit(1);
10638     }
10639     HtmlGenerator::writeSearchData(searchDirName);
10640     if (!serverBasedSearch) // client side search index
10641     {
10642       writeJavascriptSearchIndex();
10643     }
10644   }
10645
10646   msg("Generating example documentation...\n");
10647   generateExampleDocs();
10648
10649   msg("Generating file sources...\n");
10650   if (!Htags::useHtags)
10651   {
10652     generateFileSources();
10653   }
10654
10655   msg("Generating file documentation...\n");
10656   generateFileDocs();
10657   
10658   msg("Generating page documentation...\n");
10659   generatePageDocs();
10660   
10661   msg("Generating group documentation...\n");
10662   generateGroupDocs();
10663
10664   msg("Generating class documentation...\n");
10665   generateClassDocs();
10666   
10667   msg("Generating namespace index...\n");
10668   generateNamespaceDocs();
10669   
10670   if (Config_getBool("GENERATE_LEGEND"))
10671   {
10672     msg("Generating graph info page...\n");
10673     writeGraphInfo(*g_outputList);
10674   }
10675
10676   msg("Generating directory documentation...\n");
10677   generateDirDocs(*g_outputList);
10678
10679   if (Doxygen::formulaList.count()>0 && generateHtml
10680       && !Config_getBool("USE_MATHJAX"))
10681   {
10682     msg("Generating bitmaps for formulas in HTML...\n");
10683     Doxygen::formulaList.generateBitmaps(Config_getString("HTML_OUTPUT"));
10684   }
10685   
10686   writeMainPageTagFileData();
10687
10688   if (g_outputList->count()>0)
10689   {
10690     writeIndexHierarchy(*g_outputList);
10691   }
10692
10693   msg("finalizing index lists...\n");
10694   Doxygen::indexList.finalize();
10695
10696   if (!generateTagFile.isEmpty())
10697   {
10698     Doxygen::tagFile << "</tagfile>" << endl;
10699     delete tag;
10700   }
10701
10702   if (Config_getBool("DOT_CLEANUP"))
10703   {
10704     if (generateHtml)
10705       removeDoxFont(Config_getString("HTML_OUTPUT"));
10706     if (generateRtf)  
10707       removeDoxFont(Config_getString("RTF_OUTPUT"));
10708     if (generateLatex)  
10709       removeDoxFont(Config_getString("LATEX_OUTPUT"));
10710   }
10711
10712   if (Config_getBool("GENERATE_XML"))
10713   {
10714     msg("Generating XML output...\n");
10715     Doxygen::generatingXmlOutput=TRUE;
10716     generateXML();
10717     Doxygen::generatingXmlOutput=FALSE;
10718   }
10719   if (Config_getBool("GENERATE_AUTOGEN_DEF"))
10720   {
10721     msg("Generating AutoGen DEF output...\n");
10722     generateDEF();
10723   }
10724   if (Config_getBool("GENERATE_PERLMOD"))
10725   {
10726     msg("Generating Perl module output...\n");
10727     generatePerlMod();
10728   }
10729   if (generateHtml && searchEngine && serverBasedSearch)
10730   {
10731     msg("Generating search index\n");
10732     if (Doxygen::searchIndex->kind()==SearchIndexIntf::Internal) // write own search index
10733     {
10734       HtmlGenerator::writeSearchPage();
10735       Doxygen::searchIndex->write(Config_getString("HTML_OUTPUT")+"/search/search.idx");
10736     }
10737     else // write data for external search index
10738     {
10739       Doxygen::searchIndex->write(Config_getString("OUTPUT_DIRECTORY")+"/searchdata.xml");
10740     }
10741   }
10742
10743   if (generateRtf)
10744   {
10745     msg("Combining RTF output...\n");
10746     if (!RTFGenerator::preProcessFileInplace(Config_getString("RTF_OUTPUT"),"refman.rtf"))
10747     {
10748       err("An error occurred during post-processing the RTF files!\n");
10749     }
10750   }
10751
10752   if (Config_getBool("HAVE_DOT"))
10753   {
10754     DotManager::instance()->run();
10755   }
10756
10757   if (generateHtml &&
10758       Config_getBool("GENERATE_HTMLHELP") && 
10759       !Config_getString("HHC_LOCATION").isEmpty())
10760   {
10761     msg("Running html help compiler...\n");
10762     QString oldDir = QDir::currentDirPath();
10763     QDir::setCurrent(Config_getString("HTML_OUTPUT"));
10764     portable_sysTimerStart();
10765     if (portable_system(Config_getString("HHC_LOCATION"), "index.hhp", FALSE))
10766     {
10767       err("error: failed to run html help compiler on index.hhp\n");
10768     }
10769     portable_sysTimerStop();
10770     QDir::setCurrent(oldDir);
10771   }
10772   if ( generateHtml &&
10773        Config_getBool("GENERATE_QHP") && 
10774       !Config_getString("QHG_LOCATION").isEmpty())
10775   {
10776     msg("Running qhelpgenerator...\n");
10777     QCString const qhpFileName = Qhp::getQhpFileName();
10778     QCString const qchFileName = getQchFileName();
10779
10780     QCString const args = QCString().sprintf("%s -o \"%s\"", qhpFileName.data(), qchFileName.data());
10781     QString const oldDir = QDir::currentDirPath();
10782     QDir::setCurrent(Config_getString("HTML_OUTPUT"));
10783     portable_sysTimerStart();
10784     if (portable_system(Config_getString("QHG_LOCATION"), args.data(), FALSE))
10785     {
10786       err("error: failed to run qhelpgenerator on index.qhp\n");
10787     }
10788     portable_sysTimerStop();
10789     QDir::setCurrent(oldDir);
10790   }
10791
10792   int cacheParam;
10793   msg("symbol cache used %d/%d hits=%d misses=%d\n",
10794       Doxygen::symbolCache->count(),
10795       Doxygen::symbolCache->size(),
10796       Doxygen::symbolCache->hits(),
10797       Doxygen::symbolCache->misses());
10798   cacheParam = computeIdealCacheParam(Doxygen::symbolCache->misses());
10799   if (cacheParam>Config_getInt("SYMBOL_CACHE_SIZE"))
10800   {
10801     msg("Note: based on cache misses the ideal setting for SYMBOL_CACHE_SIZE is %d at the cost of higher memory usage.\n",cacheParam);
10802   }
10803   msg("lookup cache used %d/%d hits=%d misses=%d\n",
10804       Doxygen::lookupCache->count(),
10805       Doxygen::lookupCache->size(),
10806       Doxygen::lookupCache->hits(),
10807       Doxygen::lookupCache->misses());
10808   cacheParam = computeIdealCacheParam(Doxygen::lookupCache->misses()*2/3); // part of the cache is flushed, hence the 2/3 correction factor
10809   if (cacheParam>Config_getInt("LOOKUP_CACHE_SIZE"))
10810   {
10811     msg("Note: based on cache misses the ideal setting for LOOKUP_CACHE_SIZE is %d at the cost of higher memory usage.\n",cacheParam);
10812   }
10813
10814   if (Debug::isFlagSet(Debug::Time))
10815   {
10816     msg("Total elapsed time: %.3f seconds\n(of which %.3f seconds waiting for external tools to finish)\n",
10817          ((double)Doxygen::runningTime.elapsed())/1000.0,
10818          portable_getSysElapsedTime()
10819         );
10820   }
10821   else
10822   {
10823     msg("finished...\n");
10824   }
10825
10826   /**************************************************************************
10827    *                        Start cleaning up                               *
10828    **************************************************************************/
10829
10830   cleanUpDoxygen();
10831
10832   finializeSearchIndexer();
10833   Doxygen::symbolStorage->close();
10834   QDir thisDir;
10835   thisDir.remove(Doxygen::objDBFileName);
10836   Config::deleteInstance();
10837   QTextCodec::deleteAllCodecs();
10838   delete Doxygen::symbolCache;
10839   delete Doxygen::symbolMap;
10840   delete Doxygen::symbolStorage;
10841   g_successfulRun=TRUE;
10842 }
10843