Imported Upstream version 1.8.8
[platform/upstream/doxygen.git] / src / doxygen.cpp
1 /******************************************************************************
2  *
3  * Copyright (C) 1997-2014 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 <locale.h>
17
18 #include <qfileinfo.h>
19 #include <qfile.h>
20 #include <qdir.h>
21 #include <qdict.h>
22 #include <qregexp.h>
23 #include <qstrlist.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <sys/stat.h>
27 #include <qtextcodec.h>
28 #include <unistd.h>
29 #include <errno.h>
30 #include <qptrdict.h>
31 #include <qtextstream.h>
32
33 #include "version.h"
34 #include "doxygen.h"
35 #include "scanner.h"
36 #include "entry.h"
37 #include "index.h"
38 #include "logos.h"
39 #include "message.h"
40 #include "config.h"
41 #include "util.h"
42 #include "pre.h"
43 #include "tagreader.h"
44 #include "dot.h"
45 #include "msc.h"
46 #include "docparser.h"
47 #include "dirdef.h"
48 #include "outputlist.h"
49 #include "declinfo.h"
50 #include "htmlgen.h"
51 #include "latexgen.h"
52 #include "mangen.h"
53 #include "language.h"
54 #include "debug.h"
55 #include "htmlhelp.h"
56 #include "qhp.h"
57 #include "ftvhelp.h"
58 #include "defargs.h"
59 #include "rtfgen.h"
60 #include "sqlite3gen.h"
61 #include "xmlgen.h"
62 #include "docbookgen.h"
63 #include "defgen.h"
64 #include "perlmodgen.h"
65 #include "reflist.h"
66 #include "pagedef.h"
67 #include "bufstr.h"
68 #include "commentcnv.h"
69 #include "cmdmapper.h"
70 #include "searchindex.h"
71 #include "parserintf.h"
72 #include "htags.h"
73 #include "pyscanner.h"
74 #include "fortranscanner.h"
75 #include "dbusxmlscanner.h"
76 #include "tclscanner.h"
77 #include "code.h"
78 #include "objcache.h"
79 #include "store.h"
80 #include "marshal.h"
81 #include "portable.h"
82 #include "vhdljjparser.h"
83 #include "vhdldocgen.h"
84 #include "eclipsehelp.h"
85 #include "cite.h"
86 #include "filestorage.h"
87 #include "markdown.h"
88 #include "arguments.h"
89 #include "memberlist.h"
90 #include "layout.h"
91 #include "groupdef.h"
92 #include "classlist.h"
93 #include "namespacedef.h"
94 #include "filename.h"
95 #include "membername.h"
96 #include "membergroup.h"
97 #include "docsets.h"
98 #include "formula.h"
99 #include "settings.h"
100 #include "context.h"
101 #include "fileparser.h"
102
103 #define RECURSE_ENTRYTREE(func,var) \
104   do { if (var->children()) { \
105     EntryNavListIterator eli(*var->children()); \
106     for (;eli.current();++eli) func(eli.current()); \
107   } } while(0) 
108
109
110 #if !defined(_WIN32) || defined(__CYGWIN__)
111 #include <signal.h>
112 #define HAS_SIGNALS
113 #endif
114
115 // globally accessible variables
116 ClassSDict      *Doxygen::classSDict = 0;
117 ClassSDict      *Doxygen::hiddenClasses = 0;
118 NamespaceSDict  *Doxygen::namespaceSDict = 0;
119 MemberNameSDict *Doxygen::memberNameSDict = 0;
120 MemberNameSDict *Doxygen::functionNameSDict = 0;   
121 FileNameList    *Doxygen::inputNameList = 0;       // all input files
122 FileNameDict    *Doxygen::inputNameDict = 0;          
123 GroupSDict      *Doxygen::groupSDict = 0;
124 FormulaList     *Doxygen::formulaList = 0;       // all formulas
125 FormulaDict     *Doxygen::formulaDict = 0;       // all formulas
126 FormulaDict     *Doxygen::formulaNameDict = 0;   // the label name of all formulas
127 PageSDict       *Doxygen::pageSDict = 0;
128 PageSDict       *Doxygen::exampleSDict = 0;
129 SectionDict     *Doxygen::sectionDict = 0;        // all page sections
130 CiteDict        *Doxygen::citeDict=0;              // database of bibliographic references
131 StringDict       Doxygen::aliasDict(257);          // aliases
132 QDict<void>      Doxygen::inputPaths(1009);
133 FileNameDict    *Doxygen::includeNameDict = 0;     // include names
134 FileNameDict    *Doxygen::exampleNameDict = 0;     // examples
135 FileNameDict    *Doxygen::imageNameDict = 0;       // images
136 FileNameDict    *Doxygen::dotFileNameDict = 0;     // dot files
137 FileNameDict    *Doxygen::mscFileNameDict = 0;     // msc files
138 FileNameDict    *Doxygen::diaFileNameDict = 0;     // dia files
139 StringDict       Doxygen::namespaceAliasDict(257); // all namespace aliases
140 StringDict       Doxygen::tagDestinationDict(257); // all tag locations
141 QDict<void>      Doxygen::expandAsDefinedDict(257); // all macros that should be expanded
142 QIntDict<MemberGroupInfo> Doxygen::memGrpInfoDict(1009); // dictionary of the member groups heading
143 PageDef         *Doxygen::mainPage = 0;
144 bool             Doxygen::insideMainPage = FALSE; // are we generating docs for the main page?
145 FTextStream      Doxygen::tagFile;
146 NamespaceDef    *Doxygen::globalScope = 0;
147 QDict<RefList>  *Doxygen::xrefLists = new QDict<RefList>; // dictionary of cross-referenced item lists
148 bool             Doxygen::parseSourcesNeeded = FALSE;
149 QTime            Doxygen::runningTime;
150 SearchIndexIntf *Doxygen::searchIndex=0;
151 QDict<DefinitionIntf> *Doxygen::symbolMap = 0;
152 QDict<Definition> *Doxygen::clangUsrMap = 0;
153 bool             Doxygen::outputToWizard=FALSE;
154 QDict<int> *     Doxygen::htmlDirMap = 0;
155 QCache<LookupInfo> *Doxygen::lookupCache;
156 DirSDict        *Doxygen::directories;
157 SDict<DirRelation> Doxygen::dirRelations(257);
158 ParserManager   *Doxygen::parserManager = 0;
159 QCString Doxygen::htmlFileExtension;
160 bool             Doxygen::suppressDocWarnings = FALSE;
161 Store           *Doxygen::symbolStorage;
162 QCString         Doxygen::objDBFileName;
163 QCString         Doxygen::entryDBFileName;
164 bool             Doxygen::gatherDefines = TRUE;
165 IndexList       *Doxygen::indexList;
166 int              Doxygen::subpageNestingLevel = 0;
167 bool             Doxygen::userComments = FALSE;
168 QCString         Doxygen::spaces;
169 bool             Doxygen::generatingXmlOutput = FALSE;
170 bool             Doxygen::markdownSupport = TRUE;
171 GenericsSDict   *Doxygen::genericsDict;
172
173 // locally accessible globals
174 static QDict<EntryNav>  g_classEntries(1009);
175 static StringList       g_inputFiles;         
176 static QDict<void>      g_compoundKeywordDict(7);  // keywords recognised as compounds
177 static OutputList      *g_outputList = 0;          // list of output generating objects
178 static QDict<FileDef>   g_usingDeclarations(1009); // used classes
179 static FileStorage     *g_storage = 0;
180 static bool             g_successfulRun = FALSE;
181 static bool             g_dumpSymbolMap = FALSE;
182 static bool             g_useOutputTemplate = FALSE; 
183
184 void clearAll()
185 {
186   g_inputFiles.clear();
187   //g_excludeNameDict.clear();
188   //delete g_outputList; g_outputList=0;
189
190   Doxygen::classSDict->clear();
191   Doxygen::namespaceSDict->clear();
192   Doxygen::pageSDict->clear();
193   Doxygen::exampleSDict->clear();
194   Doxygen::inputNameList->clear();
195   Doxygen::formulaList->clear();
196   Doxygen::sectionDict->clear();
197   Doxygen::inputNameDict->clear();
198   Doxygen::includeNameDict->clear();
199   Doxygen::exampleNameDict->clear();
200   Doxygen::imageNameDict->clear();
201   Doxygen::dotFileNameDict->clear();
202   Doxygen::mscFileNameDict->clear();
203   Doxygen::diaFileNameDict->clear();
204   Doxygen::formulaDict->clear();
205   Doxygen::formulaNameDict->clear();
206   Doxygen::tagDestinationDict.clear();
207   delete Doxygen::citeDict;
208   delete Doxygen::mainPage; Doxygen::mainPage=0;
209 }
210
211 class Statistics 
212 {
213   public:
214     Statistics() { stats.setAutoDelete(TRUE); }
215     void begin(const char *name)
216     {
217       msg(name);
218       stat *entry= new stat(name,0);
219       stats.append(entry);
220       time.restart();
221     }
222     void end()
223     {
224       stats.getLast()->elapsed=((double)time.elapsed())/1000.0;
225     }
226     void print()
227     {
228       bool restore=FALSE;
229       if (Debug::isFlagSet(Debug::Time))
230       {
231         Debug::clearFlag("time");
232         restore=TRUE;
233       }
234       msg("----------------------\n");
235       QListIterator<stat> sli(stats);
236       stat *s;
237       for ( sli.toFirst(); (s=sli.current()); ++sli )
238       {
239         msg("Spent %.3f seconds in %s",s->elapsed,s->name);
240       }
241       if (restore) Debug::setFlag("time");
242     }
243   private:
244     struct stat 
245     {
246       const char *name;
247       double elapsed;
248       stat() : name(NULL),elapsed(0) {}
249       stat(const char *n, double el) : name(n),elapsed(el) {}
250     };
251     QList<stat> stats;
252     QTime       time;
253 } g_s;
254
255
256 void statistics()
257 {
258   fprintf(stderr,"--- inputNameDict stats ----\n");
259   Doxygen::inputNameDict->statistics();
260   fprintf(stderr,"--- includeNameDict stats ----\n");
261   Doxygen::includeNameDict->statistics();
262   fprintf(stderr,"--- exampleNameDict stats ----\n");
263   Doxygen::exampleNameDict->statistics();
264   fprintf(stderr,"--- imageNameDict stats ----\n");
265   Doxygen::imageNameDict->statistics();
266   fprintf(stderr,"--- dotFileNameDict stats ----\n");
267   Doxygen::dotFileNameDict->statistics();
268   fprintf(stderr,"--- mscFileNameDict stats ----\n");
269   Doxygen::mscFileNameDict->statistics();
270   fprintf(stderr,"--- diaFileNameDict stats ----\n");
271   Doxygen::diaFileNameDict->statistics();
272   //fprintf(stderr,"--- g_excludeNameDict stats ----\n");
273   //g_excludeNameDict.statistics();
274   fprintf(stderr,"--- aliasDict stats ----\n");
275   Doxygen::aliasDict.statistics();
276   fprintf(stderr,"--- typedefDict stats ----\n");
277   fprintf(stderr,"--- namespaceAliasDict stats ----\n");
278   Doxygen::namespaceAliasDict.statistics();
279   fprintf(stderr,"--- formulaDict stats ----\n");
280   Doxygen::formulaDict->statistics();
281   fprintf(stderr,"--- formulaNameDict stats ----\n");
282   Doxygen::formulaNameDict->statistics();
283   fprintf(stderr,"--- tagDestinationDict stats ----\n");
284   Doxygen::tagDestinationDict.statistics();
285   fprintf(stderr,"--- g_compoundKeywordDict stats ----\n");
286   g_compoundKeywordDict.statistics();
287   fprintf(stderr,"--- expandAsDefinedDict stats ----\n");
288   Doxygen::expandAsDefinedDict.statistics();
289   fprintf(stderr,"--- memGrpInfoDict stats ----\n");
290   Doxygen::memGrpInfoDict.statistics();
291 }
292
293
294
295 static void addMemberDocs(EntryNav *rootNav,MemberDef *md, const char *funcDecl,
296                    ArgumentList *al,bool over_load,NamespaceSDict *nl=0);
297 static void findMember(EntryNav *rootNav,
298                        QCString funcDecl,
299                        bool overloaded,
300                        bool isFunc
301                       );
302
303 enum FindBaseClassRelation_Mode
304 {
305   TemplateInstances,
306   DocumentedOnly,
307   Undocumented
308 };
309
310 static bool findClassRelation(
311                            EntryNav *rootNav,
312                            Definition *context,
313                            ClassDef *cd,
314                            BaseInfo *bi,
315                            QDict<int> *templateNames,
316                            /*bool insertUndocumented*/
317                            FindBaseClassRelation_Mode mode,
318                            bool isArtificial
319                           );
320
321 /** A struct contained the data for an STL class */
322 struct STLInfo
323 {
324   const char *className;
325   const char *baseClass1;
326   const char *baseClass2;
327   const char *templType1;
328   const char *templName1;
329   const char *templType2;
330   const char *templName2;
331   bool virtualInheritance;
332   bool iterators;
333 };
334
335 static STLInfo g_stlinfo[] =
336 {
337   // className              baseClass1                      baseClass2             templType1     templName1     templType2    templName2     virtInheritance  // iterators
338   { "allocator",            0,                              0,                     "T",           "elements",    0,            0,             FALSE,              FALSE },
339   { "array",                0,                              0,                     "T",           "elements",    0,            0,             FALSE,              FALSE }, // C++11
340   { "auto_ptr",             0,                              0,                     "T",           "ptr",         0,            0,             FALSE,              FALSE }, // deprecated
341   { "smart_ptr",            0,                              0,                     "T",           "ptr",         0,            0,             FALSE,              FALSE }, // C++11
342   { "unique_ptr",           0,                              0,                     "T",           "ptr",         0,            0,             FALSE,              FALSE }, // C++11
343   { "weak_ptr",             0,                              0,                     "T",           "ptr",         0,            0,             FALSE,              FALSE }, // C++11
344   { "ios_base",             0,                              0,                     0,             0,             0,            0,             FALSE,              FALSE }, // C++11
345   { "error_code",           0,                              0,                     0,             0,             0,            0,             FALSE,              FALSE }, // C++11
346   { "error_category",       0,                              0,                     0,             0,             0,            0,             FALSE,              FALSE }, // C++11
347   { "system_error",         0,                              0,                     0,             0,             0,            0,             FALSE,              FALSE }, // C++11
348   { "error_condition",      0,                              0,                     0,             0,             0,            0,             FALSE,              FALSE }, // C++11
349   { "thread",               0,                              0,                     0,             0,             0,            0,             FALSE,              FALSE }, // C++11
350   { "basic_ios",            "ios_base",                     0,                     "Char",        0,             0,            0,             FALSE,              FALSE },
351   { "basic_istream",        "basic_ios<Char>",              0,                     "Char",        0,             0,            0,             TRUE,               FALSE },
352   { "basic_ostream",        "basic_ios<Char>",              0,                     "Char",        0,             0,            0,             TRUE,               FALSE },
353   { "basic_iostream",       "basic_istream<Char>",          "basic_ostream<Char>", "Char",        0,             0,            0,             FALSE,              FALSE },
354   { "basic_ifstream",       "basic_istream<Char>",          0,                     "Char",        0,             0,            0,             FALSE,              FALSE },
355   { "basic_ofstream",       "basic_ostream<Char>",          0,                     "Char",        0,             0,            0,             FALSE,              FALSE },
356   { "basic_fstream",        "basic_iostream<Char>",         0,                     "Char",        0,             0,            0,             FALSE,              FALSE },
357   { "basic_istringstream",  "basic_istream<Char>",          0,                     "Char",        0,             0,            0,             FALSE,              FALSE },
358   { "basic_ostringstream",  "basic_ostream<Char>",          0,                     "Char",        0,             0,            0,             FALSE,              FALSE },
359   { "basic_stringstream",   "basic_iostream<Char>",         0,                     "Char",        0,             0,            0,             FALSE,              FALSE },
360   { "ios",                  "basic_ios<char>",              0,                     0,             0,             0,            0,             FALSE,              FALSE },
361   { "wios",                 "basic_ios<wchar_t>",           0,                     0,             0,             0,            0,             FALSE,              FALSE },
362   { "istream",              "basic_istream<char>",          0,                     0,             0,             0,            0,             FALSE,              FALSE },
363   { "wistream",             "basic_istream<wchar_t>",       0,                     0,             0,             0,            0,             FALSE,              FALSE },
364   { "ostream",              "basic_ostream<char>",          0,                     0,             0,             0,            0,             FALSE,              FALSE },
365   { "wostream",             "basic_ostream<wchar_t>",       0,                     0,             0,             0,            0,             FALSE,              FALSE },
366   { "ifstream",             "basic_ifstream<char>",         0,                     0,             0,             0,            0,             FALSE,              FALSE },
367   { "wifstream",            "basic_ifstream<wchar_t>",      0,                     0,             0,             0,            0,             FALSE,              FALSE },
368   { "ofstream",             "basic_ofstream<char>",         0,                     0,             0,             0,            0,             FALSE,              FALSE },
369   { "wofstream",            "basic_ofstream<wchar_t>",      0,                     0,             0,             0,            0,             FALSE,              FALSE },
370   { "fstream",              "basic_fstream<char>",          0,                     0,             0,             0,            0,             FALSE,              FALSE },
371   { "wfstream",             "basic_fstream<wchar_t>",       0,                     0,             0,             0,            0,             FALSE,              FALSE },
372   { "istringstream",        "basic_istringstream<char>",    0,                     0,             0,             0,            0,             FALSE,              FALSE },
373   { "wistringstream",       "basic_istringstream<wchar_t>", 0,                     0,             0,             0,            0,             FALSE,              FALSE },
374   { "ostringstream",        "basic_ostringstream<char>",    0,                     0,             0,             0,            0,             FALSE,              FALSE },
375   { "wostringstream",       "basic_ostringstream<wchar_t>", 0,                     0,             0,             0,            0,             FALSE,              FALSE },
376   { "stringstream",         "basic_stringstream<char>",     0,                     0,             0,             0,            0,             FALSE,              FALSE },
377   { "wstringstream",        "basic_stringstream<wchar_t>",  0,                     0,             0,             0,            0,             FALSE,              FALSE },
378   { "basic_string",         0,                              0,                     "Char",        0,             0,            0,             FALSE,              TRUE  },
379   { "string",               "basic_string<char>",           0,                     0,             0,             0,            0,             FALSE,              TRUE  },
380   { "wstring",              "basic_string<wchar_t>",        0,                     0,             0,             0,            0,             FALSE,              TRUE  },
381   { "complex",              0,                              0,                     0,             0,             0,            0,             FALSE,              FALSE },
382   { "bitset",               0,                              0,                     "Bits",        0,             0,            0,             FALSE,              FALSE },
383   { "deque",                0,                              0,                     "T",           "elements",    0,            0,             FALSE,              TRUE  },
384   { "list",                 0,                              0,                     "T",           "elements",    0,            0,             FALSE,              TRUE  },
385   { "forward_list",         0,                              0,                     "T",           "elements",    0,            0,             FALSE,              TRUE  }, // C++11
386   { "map",                  0,                              0,                     "K",           "keys",        "T",          "elements",    FALSE,              TRUE  },
387   { "unordered_map",        0,                              0,                     "K",           "keys",        "T",          "elements",    FALSE,              TRUE  }, // C++11
388   { "multimap",             0,                              0,                     "K",           "keys",        "T",          "elements",    FALSE,              TRUE  },
389   { "unordered_multimap",   0,                              0,                     "K",           "keys",        "T",          "elements",    FALSE,              TRUE  }, // C++11
390   { "set",                  0,                              0,                     "K",           "keys",        0,            0,             FALSE,              TRUE  },
391   { "unordered_set",        0,                              0,                     "K",           "keys",        0,            0,             FALSE,              TRUE  }, // C++11
392   { "multiset",             0,                              0,                     "K",           "keys",        0,            0,             FALSE,              TRUE  },
393   { "unordered_multiset",   0,                              0,                     "K",           "keys",        0,            0,             FALSE,              TRUE  }, // C++11
394   { "vector",               0,                              0,                     "T",           "elements",    0,            0,             FALSE,              TRUE  },
395   { "queue",                0,                              0,                     "T",           "elements",    0,            0,             FALSE,              FALSE },
396   { "priority_queue",       0,                              0,                     "T",           "elements",    0,            0,             FALSE,              FALSE },
397   { "stack",                0,                              0,                     "T",           "elements",    0,            0,             FALSE,              FALSE },
398   { "valarray",             0,                              0,                     "T",           "elements",    0,            0,             FALSE,              FALSE },
399   { "exception",            0,                              0,                     0,             0,             0,            0,             FALSE,              FALSE },
400   { "bad_alloc",            "exception",                    0,                     0,             0,             0,            0,             FALSE,              FALSE },
401   { "bad_cast",             "exception",                    0,                     0,             0,             0,            0,             FALSE,              FALSE },
402   { "bad_typeid",           "exception",                    0,                     0,             0,             0,            0,             FALSE,              FALSE },
403   { "logic_error",          "exception",                    0,                     0,             0,             0,            0,             FALSE,              FALSE },
404   { "ios_base::failure",    "exception",                    0,                     0,             0,             0,            0,             FALSE,              FALSE },
405   { "runtime_error",        "exception",                    0,                     0,             0,             0,            0,             FALSE,              FALSE },
406   { "bad_exception",        "exception",                    0,                     0,             0,             0,            0,             FALSE,              FALSE },
407   { "domain_error",         "logic_error",                  0,                     0,             0,             0,            0,             FALSE,              FALSE },
408   { "invalid_argument",     "logic_error",                  0,                     0,             0,             0,            0,             FALSE,              FALSE },
409   { "length_error",         "logic_error",                  0,                     0,             0,             0,            0,             FALSE,              FALSE },
410   { "out_of_range",         "logic_error",                  0,                     0,             0,             0,            0,             FALSE,              FALSE },
411   { "range_error",          "runtime_error",                0,                     0,             0,             0,            0,             FALSE,              FALSE },
412   { "overflow_error",       "runtime_error",                0,                     0,             0,             0,            0,             FALSE,              FALSE },
413   { "underflow_error",      "runtime_error",                0,                     0,             0,             0,            0,             FALSE,              FALSE },
414   { 0,                      0,                              0,                     0,             0,             0,            0,             FALSE,              FALSE }
415 };
416
417 static void addSTLMember(EntryNav *rootNav,const char *type,const char *name)
418 {
419   Entry *memEntry = new Entry;
420   memEntry->name       = name;
421   memEntry->type       = type;
422   memEntry->protection = Public;
423   memEntry->section    = Entry::VARIABLE_SEC;
424   memEntry->brief      = "STL member";
425   memEntry->hidden     = FALSE; 
426   memEntry->artificial = TRUE;
427   //memEntry->parent     = root;
428   //root->addSubEntry(memEntry);
429   EntryNav *memEntryNav = new EntryNav(rootNav,memEntry);
430   memEntryNav->setEntry(memEntry);
431   rootNav->addChild(memEntryNav);
432 }
433
434 static void addSTLIterator(EntryNav *classEntryNav,const char *name)
435 {
436   Entry *iteratorClassEntry = new Entry;
437   iteratorClassEntry->fileName  = "[STL]";
438   iteratorClassEntry->startLine = 1;
439   iteratorClassEntry->name      = name;
440   iteratorClassEntry->section   = Entry::CLASS_SEC;
441   iteratorClassEntry->brief     = "STL iterator class";
442   iteratorClassEntry->hidden    = FALSE;
443   iteratorClassEntry->artificial= TRUE;
444   EntryNav *iteratorClassEntryNav = new EntryNav(classEntryNav,iteratorClassEntry);
445   iteratorClassEntryNav->setEntry(iteratorClassEntry);
446   classEntryNav->addChild(iteratorClassEntryNav);
447 }
448
449
450 static void addSTLClasses(EntryNav *rootNav)
451 {
452   Entry *namespaceEntry = new Entry;
453   namespaceEntry->fileName  = "[STL]";
454   namespaceEntry->startLine = 1;
455   //namespaceEntry->parent    = rootNav->entry();
456   namespaceEntry->name      = "std";
457   namespaceEntry->section   = Entry::NAMESPACE_SEC;
458   namespaceEntry->brief     = "STL namespace";
459   namespaceEntry->hidden    = FALSE;
460   namespaceEntry->artificial= TRUE;
461   //root->addSubEntry(namespaceEntry);
462   EntryNav *namespaceEntryNav = new EntryNav(rootNav,namespaceEntry);
463   namespaceEntryNav->setEntry(namespaceEntry);
464   rootNav->addChild(namespaceEntryNav);
465   
466   STLInfo *info = g_stlinfo;
467   while (info->className)
468   {
469     //printf("Adding STL class %s\n",info->className);
470     QCString fullName = info->className;
471     fullName.prepend("std::");
472
473     // add fake Entry for the class
474     Entry *classEntry = new Entry;
475     classEntry->fileName  = "[STL]";
476     classEntry->startLine = 1;
477     classEntry->name      = fullName;
478     //classEntry->parent    = namespaceEntry;
479     classEntry->section   = Entry::CLASS_SEC;
480     classEntry->brief     = "STL class";
481     classEntry->hidden    = FALSE;
482     classEntry->artificial= TRUE;
483     //namespaceEntry->addSubEntry(classEntry);
484     EntryNav *classEntryNav = new EntryNav(namespaceEntryNav,classEntry);
485     classEntryNav->setEntry(classEntry);
486     namespaceEntryNav->addChild(classEntryNav);
487
488     // add template arguments to class
489     if (info->templType1)
490     {
491       ArgumentList *al = new ArgumentList;
492       Argument *a=new Argument;
493       a->type="typename";
494       a->name=info->templType1;
495       al->append(a);
496       if (info->templType2) // another template argument
497       {
498         a=new Argument;
499         a->type="typename";
500         a->name=info->templType2;
501         al->append(a);
502       }
503       classEntry->tArgLists = new QList<ArgumentList>;
504       classEntry->tArgLists->setAutoDelete(TRUE);
505       classEntry->tArgLists->append(al);
506     }
507     // add member variables
508     if (info->templName1)
509     {
510       addSTLMember(classEntryNav,info->templType1,info->templName1);
511     }
512     if (info->templName2)
513     {
514       addSTLMember(classEntryNav,info->templType2,info->templName2);
515     }
516     if (fullName=="std::auto_ptr" || fullName=="std::smart_ptr" ||
517         fullName=="std::unique_ptr" || fullName=="std::weak_ptr")
518     {
519       Entry *memEntry = new Entry;
520       memEntry->name       = "operator->";
521       memEntry->args       = "()";
522       memEntry->type       = "T*";
523       memEntry->protection = Public;
524       memEntry->section    = Entry::FUNCTION_SEC;
525       memEntry->brief      = "STL member";
526       memEntry->hidden     = FALSE; 
527       memEntry->artificial = FALSE;
528       EntryNav *memEntryNav = new EntryNav(classEntryNav,memEntry);
529       memEntryNav->setEntry(memEntry);
530       classEntryNav->addChild(memEntryNav);
531     }
532     if (info->baseClass1)
533     {
534       classEntry->extends->append(new BaseInfo(info->baseClass1,Public,info->virtualInheritance?Virtual:Normal));
535     }
536     if (info->baseClass2)
537     {
538       classEntry->extends->append(new BaseInfo(info->baseClass2,Public,info->virtualInheritance?Virtual:Normal));
539     }
540     if (info->iterators)
541     {
542       // add iterator class
543       addSTLIterator(classEntryNav,fullName+"::iterator");
544       addSTLIterator(classEntryNav,fullName+"::const_iterator");
545       addSTLIterator(classEntryNav,fullName+"::reverse_iterator");
546       addSTLIterator(classEntryNav,fullName+"::const_reverse_iterator");
547     }
548     info++;
549   }
550 }
551
552 //----------------------------------------------------------------------------
553
554 static Definition *findScopeFromQualifiedName(Definition *startScope,const QCString &n,
555                                               FileDef *fileScope,TagInfo *tagInfo);
556
557 static void addPageToContext(PageDef *pd,EntryNav *rootNav)
558 {
559   if (rootNav->parent()) // add the page to it's scope
560   {
561     QCString scope = rootNav->parent()->name();
562     if (rootNav->parent()->section()==Entry::PACKAGEDOC_SEC)
563     {
564       scope=substitute(scope,".","::");
565     }
566     scope = stripAnonymousNamespaceScope(scope);
567     scope+="::"+pd->name();
568     Definition *d = findScopeFromQualifiedName(Doxygen::globalScope,scope,0,rootNav->tagInfo());
569     if (d) 
570     {
571       pd->setPageScope(d);
572     }
573   }
574 }
575
576 static void addRelatedPage(EntryNav *rootNav)
577 {
578   Entry *root = rootNav->entry();
579   GroupDef *gd=0;
580   QListIterator<Grouping> gli(*root->groups);
581   Grouping *g;
582   for (;(g=gli.current());++gli)
583   {
584     if (!g->groupname.isEmpty() && (gd=Doxygen::groupSDict->find(g->groupname))) break;
585   }
586   //printf("---> addRelatedPage() %s gd=%p\n",root->name.data(),gd);
587   QCString doc;
588   if (root->brief.isEmpty())
589   {
590     doc=root->doc+root->inbodyDocs;
591   }
592   else
593   {
594     doc=root->brief+"\n\n"+root->doc+root->inbodyDocs;
595   }
596   PageDef *pd = addRelatedPage(root->name,root->args,doc,root->anchors,
597       root->docFile,root->docLine,
598       root->sli,
599       gd,rootNav->tagInfo(),
600       root->lang
601      );
602   if (pd)
603   {
604     pd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
605     pd->addSectionsToDefinition(root->anchors);
606     pd->setShowToc(root->stat);
607     addPageToContext(pd,rootNav);
608   }
609 }
610
611 static void buildGroupListFiltered(EntryNav *rootNav,bool additional, bool includeExternal)
612 {
613   if (rootNav->section()==Entry::GROUPDOC_SEC && !rootNav->name().isEmpty() && 
614         ((!includeExternal && rootNav->tagInfo()==0) ||
615          ( includeExternal && rootNav->tagInfo()!=0))
616      )
617   {
618     rootNav->loadEntry(g_storage);
619     Entry *root = rootNav->entry();
620
621     if ((root->groupDocType==Entry::GROUPDOC_NORMAL && !additional) ||
622         (root->groupDocType!=Entry::GROUPDOC_NORMAL &&  additional))
623     {
624       GroupDef *gd = Doxygen::groupSDict->find(root->name);
625       //printf("Processing group '%s':'%s' add=%d ext=%d gd=%p\n",
626       //    root->type.data(),root->name.data(),additional,includeExternal,gd);
627
628       if (gd)
629       {
630         if ( !gd->hasGroupTitle() )
631         {
632           gd->setGroupTitle( root->type );
633         }
634         else if ( root->type.length() > 0 && root->name != root->type && gd->groupTitle() != root->type )
635         {
636           warn( root->fileName,root->startLine,
637               "group %s: ignoring title \"%s\" that does not match old title \"%s\"\n",
638               qPrint(root->name), qPrint(root->type), qPrint(gd->groupTitle()) );
639         }
640         gd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
641         gd->setDocumentation( root->doc, root->docFile, root->docLine );
642         gd->setInbodyDocumentation( root->inbodyDocs, root->inbodyFile, root->inbodyLine );
643         gd->addSectionsToDefinition(root->anchors);
644         gd->setRefItems(root->sli);
645         gd->setLanguage(root->lang);
646       }
647       else
648       {
649         if (rootNav->tagInfo())
650         {
651           gd = new GroupDef(root->fileName,root->startLine,root->name,root->type,rootNav->tagInfo()->fileName);
652           gd->setReference(rootNav->tagInfo()->tagName);
653         }
654         else
655         {
656           gd = new GroupDef(root->fileName,root->startLine,root->name,root->type);
657         }
658         gd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
659         // allow empty docs for group
660         gd->setDocumentation(!root->doc.isEmpty() ? root->doc : QCString(" "),root->docFile,root->docLine,FALSE);
661         gd->setInbodyDocumentation( root->inbodyDocs, root->inbodyFile, root->inbodyLine );
662         gd->addSectionsToDefinition(root->anchors);
663         Doxygen::groupSDict->append(root->name,gd);
664         gd->setRefItems(root->sli);
665         gd->setLanguage(root->lang);
666       }
667     }
668
669     rootNav->releaseEntry();
670   }
671   if (rootNav->children())
672   {
673     EntryNavListIterator eli(*rootNav->children());
674     EntryNav *e;
675     for (;(e=eli.current());++eli)
676     {
677       buildGroupListFiltered(e,additional,includeExternal);
678     }
679   }
680 }
681
682 static void buildGroupList(EntryNav *rootNav)
683 {
684   // --- first process only local groups
685   // first process the @defgroups blocks
686   buildGroupListFiltered(rootNav,FALSE,FALSE);
687   // then process the @addtogroup, @weakgroup blocks
688   buildGroupListFiltered(rootNav,TRUE,FALSE);
689
690   // --- then also process external groups
691   // first process the @defgroups blocks
692   buildGroupListFiltered(rootNav,FALSE,TRUE);
693   // then process the @addtogroup, @weakgroup blocks
694   buildGroupListFiltered(rootNav,TRUE,TRUE);
695 }
696
697 static void findGroupScope(EntryNav *rootNav)
698 {
699   if (rootNav->section()==Entry::GROUPDOC_SEC && !rootNav->name().isEmpty() && 
700       rootNav->parent() && !rootNav->parent()->name().isEmpty())
701   {
702     GroupDef *gd;
703     if ((gd=Doxygen::groupSDict->find(rootNav->name())))
704     {
705       QCString scope = rootNav->parent()->name();
706       if (rootNav->parent()->section()==Entry::PACKAGEDOC_SEC)
707       {
708         scope=substitute(scope,".","::");
709       }
710       scope = stripAnonymousNamespaceScope(scope);
711       scope+="::"+gd->name();
712       Definition *d = findScopeFromQualifiedName(Doxygen::globalScope,scope,0,rootNav->tagInfo());
713       if (d) 
714       {
715         gd->setGroupScope(d);
716       }
717     }
718   }
719   RECURSE_ENTRYTREE(findGroupScope,rootNav);
720 }
721
722 static void organizeSubGroupsFiltered(EntryNav *rootNav,bool additional)
723 {
724   if (rootNav->section()==Entry::GROUPDOC_SEC && !rootNav->name().isEmpty())
725   {
726     rootNav->loadEntry(g_storage);
727     Entry *root = rootNav->entry();
728
729     if ((root->groupDocType==Entry::GROUPDOC_NORMAL && !additional) ||
730         (root->groupDocType!=Entry::GROUPDOC_NORMAL && additional))
731     {
732       GroupDef *gd;
733       if ((gd=Doxygen::groupSDict->find(root->name)))
734       {
735         //printf("adding %s to group %s\n",root->name.data(),gd->name().data());
736         addGroupToGroups(root,gd);
737       }
738     }
739
740     rootNav->releaseEntry();
741   }
742   if (rootNav->children())
743   {
744     EntryNavListIterator eli(*rootNav->children());
745     EntryNav *e;
746     for (;(e=eli.current());++eli)
747     {
748       organizeSubGroupsFiltered(e,additional);
749     }
750   }
751 }
752
753 static void organizeSubGroups(EntryNav *rootNav)
754 {
755   //printf("Defining groups\n");
756   // first process the @defgroups blocks
757   organizeSubGroupsFiltered(rootNav,FALSE);
758   //printf("Additional groups\n");
759   // then process the @addtogroup, @weakgroup blocks
760   organizeSubGroupsFiltered(rootNav,TRUE);
761 }
762
763 //----------------------------------------------------------------------
764
765 static void buildFileList(EntryNav *rootNav)
766 {
767   if (((rootNav->section()==Entry::FILEDOC_SEC) ||
768         ((rootNav->section() & Entry::FILE_MASK) && Config_getBool("EXTRACT_ALL"))) &&
769       !rootNav->name().isEmpty() && !rootNav->tagInfo() // skip any file coming from tag files
770      )
771   {
772     rootNav->loadEntry(g_storage);
773     Entry *root = rootNav->entry();
774
775     bool ambig;
776     FileDef *fd=findFileDef(Doxygen::inputNameDict,root->name,ambig);
777     //printf("**************** root->name=%s fd=%p\n",root->name.data(),fd);
778     if (fd && !ambig)
779     {
780 #if 0
781       if ((!root->doc.isEmpty() && !fd->documentation().isEmpty()) ||
782           (!root->brief.isEmpty() && !fd->briefDescription().isEmpty()))
783       {
784         warn(
785             root->fileName,root->startLine,
786             "file %s already documented. "
787             "Skipping documentation.",
788             root->name.data()
789             );
790       }
791       else
792 #endif
793       {
794         //printf("Adding documentation!\n");
795         // using FALSE in setDocumentation is small hack to make sure a file 
796         // is documented even if a \file command is used without further 
797         // documentation
798         fd->setDocumentation(root->doc,root->docFile,root->docLine,FALSE);
799         fd->setBriefDescription(root->brief,root->briefFile,root->briefLine); 
800         fd->addSectionsToDefinition(root->anchors);
801         fd->setRefItems(root->sli);
802         QListIterator<Grouping> gli(*root->groups);
803         Grouping *g;
804         for (;(g=gli.current());++gli)
805         {
806           GroupDef *gd=0;
807           if (!g->groupname.isEmpty() && (gd=Doxygen::groupSDict->find(g->groupname)))
808           {
809             gd->addFile(fd);
810             fd->makePartOfGroup(gd);
811             //printf("File %s: in group %s\n",fd->name().data(),s->data());
812           }
813         }
814       }
815     }
816     else
817     {
818       const char *fn = root->fileName.data();
819       QCString text(4096);
820       text.sprintf("the name `%s' supplied as "
821           "the second argument in the \\file statement ",
822           qPrint(root->name));
823       if (ambig) // name is ambiguous
824       {
825         text+="matches the following input files:\n";
826         text+=showFileDefMatches(Doxygen::inputNameDict,root->name);
827         text+="Please use a more specific name by "
828           "including a (larger) part of the path!";
829       }
830       else // name is not an input file
831       {
832         text+="is not an input file";
833       }
834       warn(fn,root->startLine,text);
835     }
836
837     rootNav->releaseEntry();
838   }
839   RECURSE_ENTRYTREE(buildFileList,rootNav);
840 }
841
842 static void addIncludeFile(ClassDef *cd,FileDef *ifd,Entry *root)
843 {
844   if ( 
845       (!root->doc.stripWhiteSpace().isEmpty() || 
846        !root->brief.stripWhiteSpace().isEmpty() || 
847        Config_getBool("EXTRACT_ALL")
848       ) && root->protection!=Private
849      )
850   { 
851     //printf(">>>>>> includeFile=%s\n",root->includeFile.data());
852
853     bool local=Config_getBool("FORCE_LOCAL_INCLUDES");
854     QCString includeFile = root->includeFile;
855     if (!includeFile.isEmpty() && includeFile.at(0)=='"')
856     {
857       local = TRUE;
858       includeFile=includeFile.mid(1,includeFile.length()-2);
859     }
860     else if (!includeFile.isEmpty() && includeFile.at(0)=='<')
861     {
862       local = FALSE;
863       includeFile=includeFile.mid(1,includeFile.length()-2);
864     }
865
866     bool ambig;
867     FileDef *fd=0;
868     // see if we need to include a verbatim copy of the header file
869     //printf("root->includeFile=%s\n",root->includeFile.data());
870     if (!includeFile.isEmpty() && 
871         (fd=findFileDef(Doxygen::inputNameDict,includeFile,ambig))==0
872        )
873     { // explicit request
874       QCString text;
875       text.sprintf("the name `%s' supplied as "
876                   "the argument of the \\class, \\struct, \\union, or \\include command ",
877                   qPrint(includeFile)
878                  );
879       if (ambig) // name is ambiguous
880       {
881         text+="matches the following input files:\n";
882         text+=showFileDefMatches(Doxygen::inputNameDict,root->includeFile);
883         text+="Please use a more specific name by "
884             "including a (larger) part of the path!";
885       }
886       else // name is not an input file
887       {
888         text+="is not an input file";
889       }
890       warn(root->fileName,root->startLine,text);
891     }
892     else if (includeFile.isEmpty() && ifd &&
893         // see if the file extension makes sense
894         guessSection(ifd->name())==Entry::HEADER_SEC)
895     { // implicit assumption
896       fd=ifd;
897     }
898
899     // if a file is found, we mark it as a source file.
900     if (fd)
901     {
902       QCString iName = !root->includeName.isEmpty() ? 
903                        root->includeName : includeFile;
904       if (!iName.isEmpty()) // user specified include file
905       {
906         if (iName.at(0)=='<') local=FALSE; // explicit override
907         else if (iName.at(0)=='"') local=TRUE;
908         if (iName.at(0)=='"' || iName.at(0)=='<')
909         {
910           iName=iName.mid(1,iName.length()-2); // strip quotes or brackets
911         }
912         if (iName.isEmpty())
913         {
914           iName=fd->name();
915         }
916       }
917       else if (!Config_getList("STRIP_FROM_INC_PATH").isEmpty()) 
918       {
919         iName=stripFromIncludePath(fd->absFilePath());
920       }
921       else // use name of the file containing the class definition
922       {
923         iName=fd->name();
924       }
925       if (fd->generateSourceFile()) // generate code for header
926       {
927         cd->setIncludeFile(fd,iName,local,!root->includeName.isEmpty());
928       }
929       else // put #include in the class documentation without link
930       {
931         cd->setIncludeFile(0,iName,local,TRUE);
932       }
933     }
934   }
935 }
936
937 #if 0
938 static bool addNamespace(Entry *root,ClassDef *cd)
939 {
940   // see if this class is defined inside a namespace
941   if (root->section & Entry::COMPOUND_MASK)
942   {
943     Entry *e = root->parent;
944     while (e)
945     {
946       if (e->section==Entry::NAMESPACE_SEC)
947       {
948         NamespaceDef *nd=0;
949         QCString nsName = stripAnonymousNamespaceScope(e->name);
950         //printf("addNameSpace() trying: %s\n",nsName.data());
951         if (!nsName.isEmpty() && nsName.at(0)!='@' &&
952             (nd=getResolvedNamespace(nsName))
953            )
954         {
955           cd->setNamespace(nd);
956           cd->setOuterScope(nd);
957           nd->insertClass(cd);
958           return TRUE;
959         }
960       }
961       e=e->parent;
962     } 
963   }
964   return FALSE;
965 }
966 #endif
967
968 #if 0
969 static Definition *findScope(Entry *root,int level=0)
970 {
971   if (root==0) return 0;
972   //printf("start findScope name=%s\n",root->name.data());
973   Definition *result=0;
974   if (root->section&Entry::SCOPE_MASK)
975   {
976     result = findScope(root->parent,level+1); // traverse to the root of the tree
977     if (result)
978     {
979       //printf("Found %s inside %s at level %d\n",root->name.data(),result->name().data(),level);
980       // TODO: look at template arguments
981       result = result->findInnerCompound(root->name);
982     }
983     else // reached the global scope
984     {
985       // TODO: look at template arguments
986       result = Doxygen::globalScope->findInnerCompound(root->name);
987       //printf("Found in globalScope %s at level %d\n",result->name().data(),level);
988     }
989   }
990   //printf("end findScope(%s,%d)=%s\n",root->name.data(),
991   //       level,result==0 ? "<none>" : result->name().data());
992   return result;
993 }
994 #endif
995
996 /*! returns the Definition object belonging to the first \a level levels of 
997  *  full qualified name \a name. Creates an artificial scope if the scope is
998  *  not found and set the parent/child scope relation if the scope is found.
999  */
1000 static Definition *buildScopeFromQualifiedName(const QCString name,
1001                                                int level,SrcLangExt lang,TagInfo *tagInfo)
1002 {
1003   //printf("buildScopeFromQualifiedName(%s) level=%d\n",name.data(),level);
1004   int i=0;
1005   int p=0,l;
1006   Definition *prevScope=Doxygen::globalScope;
1007   QCString fullScope;
1008   while (i<level)
1009   {
1010     int idx=getScopeFragment(name,p,&l);
1011     QCString nsName = name.mid(idx,l);
1012     if (nsName.isEmpty()) return prevScope;
1013     if (!fullScope.isEmpty()) fullScope+="::";
1014     fullScope+=nsName;
1015     NamespaceDef *nd=Doxygen::namespaceSDict->find(fullScope);
1016     Definition *innerScope = nd;
1017     ClassDef *cd=0; 
1018     if (nd==0) cd = getClass(fullScope);
1019     if (nd==0 && cd) // scope is a class
1020     {
1021       innerScope = cd;
1022     }
1023     else if (nd==0 && cd==0 && fullScope.find('<')==-1) // scope is not known and could be a namespace!
1024     {
1025       // introduce bogus namespace
1026       //printf("++ adding dummy namespace %s to %s tagInfo=%p\n",nsName.data(),prevScope->name().data(),tagInfo);
1027       nd=new NamespaceDef(
1028         "[generated]",1,1,fullScope,
1029         tagInfo?tagInfo->tagName:QCString(),
1030         tagInfo?tagInfo->fileName:QCString());
1031       nd->setLanguage(lang);
1032
1033       // add namespace to the list
1034       Doxygen::namespaceSDict->inSort(fullScope,nd);
1035       innerScope = nd;
1036     }
1037     else // scope is a namespace
1038     {
1039     }
1040     // make the parent/child scope relation
1041     prevScope->addInnerCompound(innerScope);
1042     innerScope->setOuterScope(prevScope);
1043     // proceed to the next scope fragment
1044     p=idx+l+2;
1045     prevScope=innerScope;
1046     i++;
1047   }
1048   return prevScope;
1049 }
1050
1051 static Definition *findScopeFromQualifiedName(Definition *startScope,const QCString &n,
1052                                               FileDef *fileScope,TagInfo *tagInfo)
1053 {
1054   //printf("<findScopeFromQualifiedName(%s,%s)\n",startScope ? startScope->name().data() : 0, n.data());
1055   Definition *resultScope=startScope;
1056   if (resultScope==0) resultScope=Doxygen::globalScope;
1057   QCString scope=stripTemplateSpecifiersFromScope(n,FALSE);
1058   int l1=0,i1;
1059   i1=getScopeFragment(scope,0,&l1);
1060   if (i1==-1) 
1061   {
1062     //printf(">no fragments!\n");
1063     return resultScope;
1064   }
1065   int p=i1+l1,l2=0,i2;
1066   while ((i2=getScopeFragment(scope,p,&l2))!=-1)
1067   {
1068     QCString nestedNameSpecifier = scope.mid(i1,l1);
1069     Definition *orgScope = resultScope;
1070     //printf("  nestedNameSpecifier=%s\n",nestedNameSpecifier.data());
1071     resultScope = resultScope->findInnerCompound(nestedNameSpecifier);
1072     //printf("  resultScope=%p\n",resultScope);
1073     if (resultScope==0) 
1074     {
1075       NamespaceSDict *usedNamespaces;
1076       if (orgScope==Doxygen::globalScope && fileScope &&
1077           (usedNamespaces = fileScope->getUsedNamespaces())) 
1078         // also search for used namespaces 
1079       {
1080         NamespaceSDict::Iterator ni(*usedNamespaces);
1081         NamespaceDef *nd;
1082         for (ni.toFirst();((nd=ni.current()) && resultScope==0);++ni)
1083         {
1084           // restart search within the used namespace
1085           resultScope = findScopeFromQualifiedName(nd,n,fileScope,tagInfo);
1086         }
1087         if (resultScope) 
1088         {
1089           // for a nested class A::I in used namespace N, we get
1090           // N::A::I while looking for A, so we should compare
1091           // resultScope->name() against scope.left(i2+l2)
1092           //printf("  -> result=%s scope=%s\n",resultScope->name().data(),scope.data());
1093           if (rightScopeMatch(resultScope->name(),scope.left(i2+l2)))
1094           {
1095             break;
1096           }
1097           goto nextFragment;
1098         }
1099       }
1100
1101       // also search for used classes. Complication: we haven't been able 
1102       // to put them in the right scope yet, because we are still resolving
1103       // the scope relations!
1104       // Therefore loop through all used classes and see if there is a right 
1105       // scope match between the used class and nestedNameSpecifier.
1106       QDictIterator<FileDef> ui(g_usingDeclarations);
1107       FileDef *usedFd;
1108       for (ui.toFirst();(usedFd=ui.current());++ui)
1109       {
1110         //printf("Checking using class %s\n",ui.currentKey());
1111         if (rightScopeMatch(ui.currentKey(),nestedNameSpecifier))
1112         {
1113           // ui.currentKey() is the fully qualified name of nestedNameSpecifier
1114           // so use this instead.
1115           QCString fqn = QCString(ui.currentKey())+
1116                          scope.right(scope.length()-p);
1117           resultScope = buildScopeFromQualifiedName(fqn,fqn.contains("::"),
1118                                                     startScope->getLanguage(),0);
1119           //printf("Creating scope from fqn=%s result %p\n",fqn.data(),resultScope);
1120           if (resultScope) 
1121           {
1122             //printf("> Match! resultScope=%s\n",resultScope->name().data());
1123             return resultScope;
1124           }
1125         }
1126       }
1127       
1128       //printf("> name %s not found in scope %s\n",nestedNameSpecifier.data(),orgScope->name().data());
1129       return 0;
1130     }
1131  nextFragment:
1132     i1=i2;
1133     l1=l2;
1134     p=i2+l2;
1135   }
1136   //printf(">findScopeFromQualifiedName scope %s\n",resultScope->name().data());
1137   return resultScope;
1138 }
1139
1140 ArgumentList *getTemplateArgumentsFromName(
1141                   const QCString &name,
1142                   const QList<ArgumentList> *tArgLists)
1143 {
1144   if (tArgLists==0) return 0;
1145   
1146   QListIterator<ArgumentList> ali(*tArgLists);
1147   // for each scope fragment, check if it is a template and advance through
1148   // the list if so.
1149   int i,p=0;
1150   while ((i=name.find("::",p))!=-1)
1151   {
1152     NamespaceDef *nd = Doxygen::namespaceSDict->find(name.left(i));
1153     if (nd==0)
1154     {
1155       ClassDef *cd = getClass(name.left(i));
1156       if (cd)
1157       {
1158         if (cd->templateArguments())
1159         {
1160           ++ali;
1161         }
1162       }
1163     }
1164     p=i+2;
1165   }
1166   return ali.current();
1167 }
1168
1169 static
1170 ClassDef::CompoundType convertToCompoundType(int section,uint64 specifier)
1171 {
1172   ClassDef::CompoundType sec=ClassDef::Class; 
1173   if (specifier&Entry::Struct) 
1174     sec=ClassDef::Struct;
1175   else if (specifier&Entry::Union) 
1176     sec=ClassDef::Union;
1177   else if (specifier&Entry::Category) 
1178     sec=ClassDef::Category;
1179   else if (specifier&Entry::Interface) 
1180     sec=ClassDef::Interface;
1181   else if (specifier&Entry::Protocol) 
1182     sec=ClassDef::Protocol;
1183   else if (specifier&Entry::Exception) 
1184     sec=ClassDef::Exception;
1185   else if (specifier&Entry::Service)
1186     sec=ClassDef::Service;
1187   else if (specifier&Entry::Singleton)
1188     sec=ClassDef::Singleton;
1189
1190   switch(section)
1191   {
1192     //case Entry::UNION_SEC: 
1193     case Entry::UNIONDOC_SEC: 
1194       sec=ClassDef::Union; 
1195       break;
1196       //case Entry::STRUCT_SEC:
1197     case Entry::STRUCTDOC_SEC: 
1198       sec=ClassDef::Struct; 
1199       break;
1200       //case Entry::INTERFACE_SEC:
1201     case Entry::INTERFACEDOC_SEC:
1202       sec=ClassDef::Interface; 
1203       break;
1204       //case Entry::PROTOCOL_SEC:
1205     case Entry::PROTOCOLDOC_SEC:
1206       sec=ClassDef::Protocol; 
1207       break;
1208       //case Entry::CATEGORY_SEC:
1209     case Entry::CATEGORYDOC_SEC:
1210       sec=ClassDef::Category; 
1211       break;
1212       //case Entry::EXCEPTION_SEC:
1213     case Entry::EXCEPTIONDOC_SEC:
1214       sec=ClassDef::Exception; 
1215       break;
1216     case Entry::SERVICEDOC_SEC:
1217       sec=ClassDef::Service;
1218       break;
1219     case Entry::SINGLETONDOC_SEC:
1220       sec=ClassDef::Singleton;
1221       break;
1222   }
1223   return sec;
1224 }
1225
1226
1227 static void addClassToContext(EntryNav *rootNav)
1228 {
1229   //printf("Loading entry for rootNav=%p name=%s\n",rootNav,rootNav->name().data());
1230   rootNav->loadEntry(g_storage);
1231   Entry *root = rootNav->entry();
1232
1233   //NamespaceDef *nd = 0;
1234   FileDef *fd = rootNav->fileDef();
1235
1236   QCString scName;
1237   if (rootNav->parent()->section()&Entry::SCOPE_MASK)
1238   {
1239      scName=rootNav->parent()->name();
1240   }
1241   // name without parent's scope
1242   QCString fullName = root->name;
1243
1244   // strip off any template parameters (but not those for specializations)
1245   fullName=stripTemplateSpecifiersFromScope(fullName);
1246
1247   // name with scope (if not present already)
1248   QCString qualifiedName = fullName;
1249   if (!scName.isEmpty() && !leftScopeMatch(fullName,scName))
1250   {
1251     qualifiedName.prepend(scName+"::");
1252   }
1253
1254   // see if we already found the class before
1255   ClassDef *cd = getClass(qualifiedName);
1256
1257   Debug::print(Debug::Classes,0, "  Found class with name %s (qualifiedName=%s -> cd=%p)\n",
1258       cd ? cd->name().data() : root->name.data(), qualifiedName.data(),cd);
1259
1260   if (cd)
1261   {
1262     fullName=cd->name();
1263     Debug::print(Debug::Classes,0,"  Existing class %s!\n",cd->name().data());
1264     //if (cd->templateArguments()==0)
1265     //{
1266     //  //printf("existing ClassDef tempArgList=%p specScope=%s\n",root->tArgList,root->scopeSpec.data());
1267     //  cd->setTemplateArguments(tArgList);
1268     //}
1269
1270     cd->setDocumentation(root->doc,root->docFile,root->docLine);
1271     cd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1272
1273     if (root->bodyLine!=-1 && cd->getStartBodyLine()==-1)
1274     {
1275       cd->setBodySegment(root->bodyLine,root->endBodyLine);
1276       cd->setBodyDef(fd);
1277     }
1278     //cd->setName(fullName); // change name to match docs
1279
1280     if (cd->templateArguments()==0 || (cd->isForwardDeclared() && (root->spec&Entry::ForwardDecl)==0))
1281     {
1282       // this happens if a template class declared with @class is found
1283       // before the actual definition or if a forward declaration has different template
1284       // parameter names.
1285       ArgumentList *tArgList =
1286         getTemplateArgumentsFromName(cd->name(),root->tArgLists);
1287       cd->setTemplateArguments(tArgList);
1288     }
1289
1290     cd->setCompoundType(convertToCompoundType(root->section,root->spec));
1291   }
1292   else // new class
1293   {
1294     ClassDef::CompoundType sec = convertToCompoundType(root->section,root->spec);
1295
1296     QCString className;
1297     QCString namespaceName;
1298     extractNamespaceName(fullName,className,namespaceName);
1299
1300     //printf("New class: fullname %s namespace `%s' name=`%s' brief=`%s' docs=`%s'\n",
1301     //    fullName.data(),namespaceName.data(),className.data(),root->brief.data(),root->doc.data());
1302
1303     QCString tagName;
1304     QCString refFileName;
1305     TagInfo *tagInfo = rootNav->tagInfo();
1306     if (tagInfo)
1307     {
1308       tagName     = tagInfo->tagName;
1309       refFileName = tagInfo->fileName;
1310       int i;
1311       if ((i=fullName.find("::"))!=-1) 
1312         // symbols imported via tag files may come without the parent scope, 
1313         // so we artificially create it here
1314       {
1315         buildScopeFromQualifiedName(fullName,fullName.contains("::"),root->lang,tagInfo);
1316       }
1317     }
1318     cd=new ClassDef(root->fileName,root->startLine,root->startColumn,
1319         fullName,sec,tagName,refFileName,TRUE,root->spec&Entry::Enum);
1320     Debug::print(Debug::Classes,0,"  New class `%s' (sec=0x%08x)! #tArgLists=%d tagInfo=%p\n",
1321         fullName.data(),sec,root->tArgLists ? (int)root->tArgLists->count() : -1, tagInfo);
1322     cd->setDocumentation(root->doc,root->docFile,root->docLine); // copy docs to definition
1323     cd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1324     cd->setLanguage(root->lang);    
1325     cd->setId(root->id);
1326     cd->setHidden(root->hidden);        
1327     cd->setArtificial(root->artificial);        
1328     cd->setClassSpecifier(root->spec);
1329     cd->setTypeConstraints(root->typeConstr);   
1330     //printf("new ClassDef %s tempArgList=%p specScope=%s\n",fullName.data(),root->tArgList,root->scopeSpec.data());    
1331
1332     ArgumentList *tArgList =    
1333       getTemplateArgumentsFromName(fullName,root->tArgLists);   
1334     //printf("class %s template args=%s\n",fullName.data(),     
1335     //    tArgList ? tempArgListToString(tArgList).data() : "<none>");          
1336     cd->setTemplateArguments(tArgList);         
1337     cd->setProtection(root->protection);        
1338     cd->setIsStatic(root->stat);        
1339
1340     // file definition containing the class cd          
1341     cd->setBodySegment(root->bodyLine,root->endBodyLine);       
1342     cd->setBodyDef(fd);         
1343
1344     // see if the class is found inside a namespace     
1345     //bool found=addNamespace(root,cd);         
1346
1347     cd->insertUsedFile(fd);
1348
1349     // add class to the list
1350     //printf("ClassDict.insert(%s)\n",fullName.data());
1351     Doxygen::classSDict->append(fullName,cd);
1352
1353     if (cd->isGeneric()) // generics are also stored in a separate dictionary for fast lookup of instantions
1354     {
1355       //printf("inserting generic '%s' cd=%p\n",fullName.data(),cd);
1356       Doxygen::genericsDict->insert(fullName,cd);
1357     }
1358   }
1359
1360   cd->addSectionsToDefinition(root->anchors);
1361   if (!root->subGrouping) cd->setSubGrouping(FALSE);
1362   if (cd->hasDocumentation())
1363   {
1364     addIncludeFile(cd,fd,root);
1365   }
1366   if (fd && (root->section & Entry::COMPOUND_MASK)) 
1367   {
1368     //printf(">> Inserting class `%s' in file `%s' (root->fileName=`%s')\n",
1369     //    cd->name().data(),
1370     //    fd->name().data(),
1371     //    root->fileName.data()
1372     //   );
1373     cd->setFileDef(fd);
1374     fd->insertClass(cd);
1375   }
1376   addClassToGroups(root,cd);
1377   cd->setRefItems(root->sli);
1378
1379   rootNav->releaseEntry();
1380 }
1381             
1382 //----------------------------------------------------------------------
1383 // build a list of all classes mentioned in the documentation
1384 // and all classes that have a documentation block before their definition.
1385 static void buildClassList(EntryNav *rootNav)
1386 {
1387   if (
1388         ((rootNav->section() & Entry::COMPOUND_MASK) || 
1389          rootNav->section()==Entry::OBJCIMPL_SEC) && !rootNav->name().isEmpty()
1390      )
1391   {
1392     addClassToContext(rootNav);
1393   }
1394   RECURSE_ENTRYTREE(buildClassList,rootNav);
1395 }
1396
1397 static void buildClassDocList(EntryNav *rootNav)
1398 {
1399   if (
1400        (rootNav->section() & Entry::COMPOUNDDOC_MASK) && !rootNav->name().isEmpty()
1401      )
1402   {
1403     addClassToContext(rootNav);
1404   }
1405   RECURSE_ENTRYTREE(buildClassDocList,rootNav);
1406 }
1407
1408 static void resolveClassNestingRelations()
1409 {
1410   ClassSDict::Iterator cli(*Doxygen::classSDict);
1411   for (cli.toFirst();cli.current();++cli) cli.current()->visited=FALSE;
1412
1413   bool done=FALSE;
1414   int iteration=0;
1415   while (!done)
1416   {
1417     done=TRUE;
1418     ++iteration;
1419     ClassDef *cd=0;
1420     for (cli.toFirst();(cd=cli.current());++cli)
1421     {
1422       if (!cd->visited)
1423       {
1424         QCString name = stripAnonymousNamespaceScope(cd->name());
1425         //printf("processing=%s, iteration=%d\n",cd->name().data(),iteration);
1426         // also add class to the correct structural context 
1427         Definition *d = findScopeFromQualifiedName(Doxygen::globalScope,
1428                                                  name,cd->getFileDef(),0);
1429         if (d)
1430         {
1431           //printf("****** adding %s to scope %s in iteration %d\n",cd->name().data(),d->name().data(),iteration);
1432           d->addInnerCompound(cd);
1433           cd->setOuterScope(d);
1434           cd->visited=TRUE;
1435           done=FALSE;
1436         }
1437         //else
1438         //{
1439         //  printf("****** ignoring %s: scope not (yet) found in iteration %d\n",cd->name().data(),iteration);
1440         //}
1441       }
1442     }
1443   }
1444
1445   //give warnings for unresolved compounds
1446   ClassDef *cd=0;
1447   for (cli.toFirst();(cd=cli.current());++cli)
1448   {
1449     if (!cd->visited)
1450     {
1451       QCString name = stripAnonymousNamespaceScope(cd->name());
1452       //printf("processing unresolved=%s, iteration=%d\n",cd->name().data(),iteration);
1453       /// create the scope artificially
1454       // anyway, so we can at least relate scopes properly.
1455       Definition *d = buildScopeFromQualifiedName(name,name.contains("::"),cd->getLanguage(),0);
1456       if (d!=cd && !cd->getDefFileName().isEmpty()) 
1457                  // avoid recursion in case of redundant scopes, i.e: namespace N { class N::C {}; }
1458                  // for this case doxygen assumes the exitance of a namespace N::N in which C is to be found!
1459                  // also avoid warning for stuff imported via a tagfile.
1460       {
1461         d->addInnerCompound(cd);
1462         cd->setOuterScope(d);
1463         warn(cd->getDefFileName(),cd->getDefLine(),
1464             "Internal inconsistency: scope for class %s not "
1465             "found!",name.data()
1466             );
1467       }
1468     }
1469   }
1470 }
1471
1472 void distributeClassGroupRelations()
1473 {
1474   //static bool inlineGroupedClasses = Config_getBool("INLINE_GROUPED_CLASSES");
1475   //if (!inlineGroupedClasses) return;
1476   //printf("** distributeClassGroupRelations()\n");
1477
1478   ClassSDict::Iterator cli(*Doxygen::classSDict);
1479   for (cli.toFirst();cli.current();++cli) cli.current()->visited=FALSE;
1480
1481   ClassDef *cd;
1482   for (cli.toFirst();(cd=cli.current());++cli)
1483   {
1484     //printf("Checking %s\n",cd->name().data());
1485     // distribute the group to nested classes as well
1486     if (!cd->visited && cd->partOfGroups()!=0 && cd->getClassSDict())
1487     {
1488       //printf("  Candidate for merging\n");
1489       ClassSDict::Iterator ncli(*cd->getClassSDict());
1490       ClassDef *ncd;
1491       GroupDef *gd = cd->partOfGroups()->at(0);
1492       for (ncli.toFirst();(ncd=ncli.current());++ncli)
1493       {
1494         if (ncd->partOfGroups()==0)
1495         {
1496           //printf("  Adding %s to group '%s'\n",ncd->name().data(),
1497           //    gd->groupTitle());
1498           ncd->makePartOfGroup(gd);
1499           gd->addClass(ncd);
1500         }
1501       }
1502       cd->visited=TRUE; // only visit every class once
1503     }
1504   }
1505 }
1506
1507 //----------------------------
1508
1509 static ClassDef *createTagLessInstance(ClassDef *rootCd,ClassDef *templ,const QCString &fieldName)
1510 {
1511   QCString fullName = removeAnonymousScopes(templ->name());
1512   if (fullName.right(2)=="::") fullName=fullName.left(fullName.length()-2);
1513   fullName+="."+fieldName;
1514   ClassDef *cd = new ClassDef(templ->getDefFileName(),
1515                               templ->getDefLine(),
1516                               templ->getDefColumn(),
1517                               fullName,
1518                               templ->compoundType());
1519   cd->setDocumentation(templ->documentation(),templ->docFile(),templ->docLine()); // copy docs to definition
1520   cd->setBriefDescription(templ->briefDescription(),templ->briefFile(),templ->briefLine());
1521   cd->setLanguage(templ->getLanguage());
1522   cd->setBodySegment(templ->getStartBodyLine(),templ->getEndBodyLine());
1523   cd->setBodyDef(templ->getBodyDef());
1524
1525   cd->setOuterScope(rootCd->getOuterScope());
1526   if (rootCd->getOuterScope()!=Doxygen::globalScope)
1527   {
1528     rootCd->getOuterScope()->addInnerCompound(cd);
1529   }
1530
1531   FileDef *fd = templ->getFileDef();
1532   if (fd)
1533   {
1534     cd->setFileDef(fd);
1535     fd->insertClass(cd);
1536   }
1537   GroupList *groups = rootCd->partOfGroups();
1538   if ( groups!=0 )
1539   {
1540     GroupListIterator gli(*groups);
1541     GroupDef *gd;
1542     for (gli.toFirst();(gd=gli.current());++gli)
1543     {
1544       cd->makePartOfGroup(gd);
1545       gd->addClass(cd);
1546     }
1547   }
1548   //printf("** adding class %s based on %s\n",fullName.data(),templ->name().data());
1549   Doxygen::classSDict->append(fullName,cd);
1550
1551   MemberList *ml = templ->getMemberList(MemberListType_pubAttribs);
1552   if (ml)
1553   {
1554     MemberListIterator li(*ml);
1555     MemberDef *md;
1556     for (li.toFirst();(md=li.current());++li)
1557     {
1558       //printf("    Member %s type=%s\n",md->name().data(),md->typeString());
1559       MemberDef *imd = new MemberDef(md->getDefFileName(),md->getDefLine(),md->getDefColumn(),
1560                                      md->typeString(),md->name(),md->argsString(),md->excpString(),
1561                                      md->protection(),md->virtualness(),md->isStatic(),Member,
1562                                      md->memberType(),
1563                                      0,0);
1564       imd->setMemberClass(cd);
1565       imd->setDocumentation(md->documentation(),md->docFile(),md->docLine());
1566       imd->setBriefDescription(md->briefDescription(),md->briefFile(),md->briefLine());
1567       imd->setInbodyDocumentation(md->inbodyDocumentation(),md->inbodyFile(),md->inbodyLine());
1568       imd->setMemberSpecifiers(md->getMemberSpecifiers());
1569       imd->setMemberGroupId(md->getMemberGroupId());
1570       imd->setInitializer(md->initializer());
1571       imd->setMaxInitLines(md->initializerLines());
1572       imd->setBitfields(md->bitfieldString());
1573       imd->setLanguage(md->getLanguage());
1574       cd->insertMember(imd);
1575     }
1576   }
1577   return cd;
1578 }
1579
1580 /** Look through the members of class \a cd and its public members.
1581  *  If there is a member m of a tag less struct/union, 
1582  *  then we create a duplicate of the struct/union with the name of the 
1583  *  member to identify it.
1584  *  So if cd has name S, then the tag less struct/union will get name S.m
1585  *  Since tag less structs can be nested we need to call this function
1586  *  recursively. Later on we need to patch the member types so we keep
1587  *  track of the hierarchy of classes we create.
1588  */
1589 static void processTagLessClasses(ClassDef *rootCd,
1590                                   ClassDef *cd,
1591                                   ClassDef *tagParentCd,
1592                                   const QCString &prefix,int count)
1593 {
1594   //printf("%d: processTagLessClasses %s\n",count,cd->name().data());
1595   //printf("checking members for %s\n",cd->name().data());
1596   if (cd->getClassSDict())
1597   {
1598     MemberList *ml = cd->getMemberList(MemberListType_pubAttribs);
1599     if (ml)
1600     {
1601       MemberListIterator li(*ml);
1602       MemberDef *md;
1603       for (li.toFirst();(md=li.current());++li)
1604       {
1605         QCString type = md->typeString();
1606         if (type.find("::@")!=-1) // member of tag less struct/union
1607         {
1608           ClassSDict::Iterator it(*cd->getClassSDict());
1609           ClassDef *icd;
1610           for (it.toFirst();(icd=it.current());++it)
1611           {
1612             //printf("  member %s: type='%s'\n",md->name().data(),type.data());
1613             //printf("  comparing '%s'<->'%s'\n",type.data(),icd->name().data());
1614             if (type.find(icd->name())!=-1) // matching tag less struct/union
1615             {
1616               QCString name = md->name();
1617               if (name.at(0)=='@') name = "__unnamed__";
1618               if (!prefix.isEmpty()) name.prepend(prefix+".");
1619               //printf("    found %s for class %s\n",name.data(),cd->name().data());
1620               ClassDef *ncd = createTagLessInstance(rootCd,icd,name);
1621               processTagLessClasses(rootCd,icd,ncd,name,count+1);
1622               //printf("    addTagged %s to %s\n",ncd->name().data(),tagParentCd->name().data());
1623               tagParentCd->addTaggedInnerClass(ncd);
1624               ncd->setTagLessReference(icd);
1625
1626               // replace tag-less type for generated/original member
1627               // by newly created class name.
1628               // note the difference between changing cd and tagParentCd.
1629               // for the initial call this is the same pointer, but for 
1630               // recursive calls cd is the original tag-less struct (of which
1631               // there is only one instance) and tagParentCd is the newly
1632               // generated tagged struct of which there can be multiple instances!
1633               MemberList *pml = tagParentCd->getMemberList(MemberListType_pubAttribs);
1634               if (pml)
1635               {
1636                 MemberListIterator pli(*pml);
1637                 MemberDef *pmd;
1638                 for (pli.toFirst();(pmd=pli.current());++pli)
1639                 {
1640                   if (pmd->name()==md->name())
1641                   {
1642                     pmd->setAccessorType(ncd,substitute(pmd->typeString(),icd->name(),ncd->name()));
1643                     //pmd->setType(substitute(pmd->typeString(),icd->name(),ncd->name()));
1644                   }
1645                 }
1646               }
1647             }
1648           }
1649         }
1650       }
1651     }
1652   }
1653 }
1654
1655 static void writeMainPageTagFileData()
1656 {
1657   if (Doxygen::mainPage && !Config_getString("GENERATE_TAGFILE").isEmpty())
1658   {
1659     Doxygen::tagFile << "  <compound kind=\"page\">" << endl
1660                      << "    <name>"
1661                      << convertToXML(Doxygen::mainPage->name())
1662                      << "</name>" << endl
1663                      << "    <title>"
1664                      << convertToXML(Doxygen::mainPage->title())
1665                      << "</title>" << endl
1666                      << "    <filename>"
1667                      << convertToXML(Doxygen::mainPage->getOutputFileBase())
1668                      << "</filename>" << endl;
1669
1670     Doxygen::mainPage->writeDocAnchorsToTagFile();
1671     Doxygen::tagFile << "  </compound>" << endl;
1672   }
1673 }
1674
1675 static void findTagLessClasses(ClassDef *cd)
1676 {
1677   if (cd->getClassSDict())
1678   {
1679     ClassSDict::Iterator it(*cd->getClassSDict());
1680     ClassDef *icd;
1681     for (it.toFirst();(icd=it.current());++it)
1682     {
1683       if (icd->name().find("@")==-1) // process all non-anonymous inner classes
1684       {
1685         findTagLessClasses(icd);
1686       }
1687     }
1688   }
1689
1690   processTagLessClasses(cd,cd,cd,"",0); // process tag less inner struct/classes (if any)
1691 }
1692
1693 static void findTagLessClasses()
1694 {
1695   ClassSDict::Iterator cli(*Doxygen::classSDict);
1696   ClassDef *cd;
1697   for (cli.toFirst();(cd=cli.current());++cli) // for each class
1698   {
1699     Definition *scope = cd->getOuterScope();
1700     if (scope && scope->definitionType()!=Definition::TypeClass) // that is not nested
1701     {
1702       findTagLessClasses(cd);
1703     }
1704   }
1705 }
1706
1707
1708 //----------------------------------------------------------------------
1709 // build a list of all namespaces mentioned in the documentation
1710 // and all namespaces that have a documentation block before their definition.
1711 static void buildNamespaceList(EntryNav *rootNav)
1712 {
1713   if (
1714        (rootNav->section()==Entry::NAMESPACE_SEC ||
1715         rootNav->section()==Entry::NAMESPACEDOC_SEC ||
1716         rootNav->section()==Entry::PACKAGEDOC_SEC
1717        ) && 
1718        !rootNav->name().isEmpty()
1719      )
1720   {
1721     rootNav->loadEntry(g_storage);
1722     Entry *root = rootNav->entry();
1723
1724     //printf("** buildNamespaceList(%s)\n",root->name.data());
1725
1726     QCString fName = root->name;
1727     if (root->section==Entry::PACKAGEDOC_SEC)
1728     {
1729       fName=substitute(fName,".","::");
1730     }
1731
1732     QCString fullName = stripAnonymousNamespaceScope(fName);
1733     if (!fullName.isEmpty())
1734     {
1735       //printf("Found namespace %s in %s at line %d\n",root->name.data(),
1736       //        root->fileName.data(), root->startLine);
1737       NamespaceDef *nd;
1738       if ((nd=Doxygen::namespaceSDict->find(fullName))) // existing namespace
1739       {
1740         nd->setDocumentation(root->doc,root->docFile,root->docLine);
1741         nd->setName(fullName); // change name to match docs
1742         nd->addSectionsToDefinition(root->anchors);
1743         nd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1744         if (nd->getLanguage()==SrcLangExt_Unknown)
1745         {
1746           nd->setLanguage(root->lang);
1747         }
1748
1749         // file definition containing the namespace nd
1750         FileDef *fd=rootNav->fileDef();
1751         // insert the namespace in the file definition
1752         if (fd) fd->insertNamespace(nd);
1753         addNamespaceToGroups(root,nd);
1754         nd->setRefItems(root->sli);
1755       }
1756       else // fresh namespace
1757       {
1758         QCString tagName;
1759         QCString tagFileName;
1760         TagInfo *tagInfo = rootNav->tagInfo();
1761         if (tagInfo)
1762         {
1763           tagName     = tagInfo->tagName;
1764           tagFileName = tagInfo->fileName;
1765         }
1766         //printf("++ new namespace %s lang=%s tagName=%s\n",fullName.data(),langToString(root->lang).data(),tagName.data());
1767         NamespaceDef *nd=new NamespaceDef(root->fileName,root->startLine,
1768                              root->startColumn,fullName,tagName,tagFileName,
1769                              root->type,root->spec&Entry::Published);
1770         nd->setDocumentation(root->doc,root->docFile,root->docLine); // copy docs to definition
1771         nd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1772         nd->addSectionsToDefinition(root->anchors);
1773         nd->setHidden(root->hidden);
1774         nd->setArtificial(root->artificial);
1775         nd->setLanguage(root->lang);
1776         nd->setId(root->id);
1777
1778         //printf("Adding namespace to group\n");
1779         addNamespaceToGroups(root,nd);
1780         nd->setRefItems(root->sli);
1781
1782         // file definition containing the namespace nd
1783         FileDef *fd=rootNav->fileDef();
1784         // insert the namespace in the file definition
1785         if (fd) fd->insertNamespace(nd);
1786
1787         // the empty string test is needed for extract all case
1788         nd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1789         nd->insertUsedFile(fd);
1790         nd->setBodySegment(root->bodyLine,root->endBodyLine);
1791         nd->setBodyDef(fd);
1792         // add class to the list
1793         Doxygen::namespaceSDict->inSort(fullName,nd);
1794
1795         // also add namespace to the correct structural context 
1796         Definition *d = findScopeFromQualifiedName(Doxygen::globalScope,fullName,0,tagInfo);
1797         //printf("adding namespace %s to context %s\n",nd->name().data(),d?d->name().data():"<none>");
1798         if (d==0) // we didn't find anything, create the scope artificially
1799                   // anyway, so we can at least relate scopes properly.
1800         {
1801           Definition *d = buildScopeFromQualifiedName(fullName,fullName.contains("::"),nd->getLanguage(),tagInfo);
1802           d->addInnerCompound(nd);
1803           nd->setOuterScope(d);
1804           // TODO: Due to the order in which the tag file is written
1805           // a nested class can be found before its parent!
1806         }
1807         else
1808         {
1809           d->addInnerCompound(nd);
1810           nd->setOuterScope(d);
1811         }
1812       }
1813     }
1814
1815     rootNav->releaseEntry();
1816   }
1817   RECURSE_ENTRYTREE(buildNamespaceList,rootNav);
1818 }
1819
1820 //----------------------------------------------------------------------
1821
1822 static NamespaceDef *findUsedNamespace(NamespaceSDict *unl,
1823                               const QCString &name)
1824 {
1825   NamespaceDef *usingNd =0;
1826   if (unl)
1827   {
1828     //printf("Found namespace dict %d\n",unl->count());
1829     NamespaceSDict::Iterator unli(*unl);
1830     NamespaceDef *und;
1831     for (unli.toFirst();(und=unli.current());++unli)
1832     {
1833       QCString uScope=und->name()+"::";
1834       usingNd = getResolvedNamespace(uScope+name);
1835       //printf("Also trying with scope=`%s' usingNd=%p\n",(uScope+name).data(),usingNd);
1836     }
1837   }
1838   return usingNd;
1839 }
1840
1841 static void findUsingDirectives(EntryNav *rootNav)
1842 {
1843   if (rootNav->section()==Entry::USINGDIR_SEC)
1844   {
1845     rootNav->loadEntry(g_storage);
1846     Entry *root = rootNav->entry();
1847
1848     //printf("Found using directive %s at line %d of %s\n",
1849     //    root->name.data(),root->startLine,root->fileName.data());
1850     QCString name=substitute(root->name,".","::");
1851     if (name.right(2)=="::")
1852     {
1853       name=name.left(name.length()-2);
1854     }
1855     if (!name.isEmpty())
1856     {
1857       NamespaceDef *usingNd = 0;
1858       NamespaceDef *nd = 0;
1859       FileDef      *fd = rootNav->fileDef();
1860       QCString nsName;
1861
1862       // see if the using statement was found inside a namespace or inside
1863       // the global file scope.
1864       if (rootNav->parent() && rootNav->parent()->section()==Entry::NAMESPACE_SEC &&
1865           (fd==0 || fd->getLanguage()!=SrcLangExt_Java) // not a .java file
1866          )
1867       {
1868         nsName=stripAnonymousNamespaceScope(rootNav->parent()->name());
1869         if (!nsName.isEmpty())
1870         {
1871           nd = getResolvedNamespace(nsName);
1872         }
1873       }
1874
1875       // find the scope in which the `using' namespace is defined by prepending
1876       // the possible scopes in which the using statement was found, starting
1877       // with the most inner scope and going to the most outer scope (i.e. 
1878       // file scope). 
1879       int scopeOffset = nsName.length();
1880       do
1881       {
1882         QCString scope=scopeOffset>0 ? 
1883                       nsName.left(scopeOffset)+"::" : QCString();
1884         usingNd = getResolvedNamespace(scope+name);
1885         //printf("Trying with scope=`%s' usingNd=%p\n",(scope+name).data(),usingNd);
1886         if (scopeOffset==0)
1887         {
1888           scopeOffset=-1;
1889         }
1890         else if ((scopeOffset=nsName.findRev("::",scopeOffset-1))==-1)
1891         {
1892           scopeOffset=0;
1893         }
1894       } while (scopeOffset>=0 && usingNd==0);
1895
1896       if (usingNd==0 && nd) // not found, try used namespaces in this scope
1897                             // or in one of the parent namespace scopes
1898       {
1899         NamespaceDef *pnd = nd;
1900         while (pnd && usingNd==0)
1901         {
1902           // also try with one of the used namespaces found earlier
1903           usingNd = findUsedNamespace(pnd->getUsedNamespaces(),name);
1904
1905           // goto the parent
1906           Definition *s = pnd->getOuterScope();
1907           if (s && s->definitionType()==Definition::TypeNamespace)
1908           {
1909             pnd = (NamespaceDef*)s;
1910           }
1911           else
1912           {
1913             pnd = 0;
1914           }
1915         }
1916       }
1917       if (usingNd==0 && fd) // still nothing, also try used namespace in the
1918                             // global scope
1919       {
1920         usingNd = findUsedNamespace(fd->getUsedNamespaces(),name);
1921       }
1922
1923       //printf("%s -> %s\n",name.data(),usingNd?usingNd->name().data():"<none>");
1924
1925       // add the namespace the correct scope
1926       if (usingNd)
1927       {
1928         //printf("using fd=%p nd=%p\n",fd,nd);
1929         if (nd)
1930         {
1931           //printf("Inside namespace %s\n",nd->name().data());
1932           nd->addUsingDirective(usingNd);
1933         }
1934         else if (fd)
1935         {
1936           //printf("Inside file %s\n",fd->name().data());
1937           fd->addUsingDirective(usingNd);
1938         }
1939       }
1940       else // unknown namespace, but add it anyway.
1941       {
1942         //printf("++ new unknown namespace %s lang=%s\n",name.data(),langToString(root->lang).data());
1943         NamespaceDef *nd=new NamespaceDef(root->fileName,root->startLine,root->startColumn,name);
1944         nd->setDocumentation(root->doc,root->docFile,root->docLine); // copy docs to definition
1945         nd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1946         nd->addSectionsToDefinition(root->anchors);
1947         //printf("** Adding namespace %s hidden=%d\n",name.data(),root->hidden);
1948         nd->setHidden(root->hidden);
1949         nd->setArtificial(TRUE);
1950         nd->setLanguage(root->lang);
1951         nd->setId(root->id);
1952
1953         QListIterator<Grouping> gli(*root->groups);
1954         Grouping *g;
1955         for (;(g=gli.current());++gli)
1956         {
1957           GroupDef *gd=0;
1958           if (!g->groupname.isEmpty() && (gd=Doxygen::groupSDict->find(g->groupname)))
1959             gd->addNamespace(nd);
1960         }
1961
1962         // insert the namespace in the file definition
1963         if (fd) 
1964         {
1965           fd->insertNamespace(nd);
1966           fd->addUsingDirective(nd);
1967         }
1968
1969         // the empty string test is needed for extract all case
1970         nd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1971         nd->insertUsedFile(fd);
1972         // add class to the list
1973         Doxygen::namespaceSDict->inSort(name,nd);
1974         nd->setRefItems(root->sli);
1975       }
1976     }
1977
1978     rootNav->releaseEntry();
1979   }
1980   RECURSE_ENTRYTREE(findUsingDirectives,rootNav);
1981 }
1982
1983 //----------------------------------------------------------------------
1984
1985 static void buildListOfUsingDecls(EntryNav *rootNav)
1986 {
1987   if (rootNav->section()==Entry::USINGDECL_SEC &&
1988       !(rootNav->parent()->section()&Entry::COMPOUND_MASK) // not a class/struct member
1989      )
1990   {
1991     rootNav->loadEntry(g_storage);
1992     Entry *root = rootNav->entry();
1993
1994     QCString name = substitute(root->name,".","::");
1995
1996     if (g_usingDeclarations.find(name)==0)
1997     {
1998       FileDef *fd = rootNav->fileDef();
1999       if (fd)
2000       {
2001         g_usingDeclarations.insert(name,fd);
2002       }
2003     }
2004
2005     rootNav->releaseEntry();
2006   }
2007   RECURSE_ENTRYTREE(buildListOfUsingDecls,rootNav);
2008 }
2009
2010   
2011 static void findUsingDeclarations(EntryNav *rootNav)
2012 {
2013   if (rootNav->section()==Entry::USINGDECL_SEC &&
2014       !(rootNav->parent()->section()&Entry::COMPOUND_MASK) // not a class/struct member
2015      )
2016   {
2017     rootNav->loadEntry(g_storage);
2018     Entry *root = rootNav->entry();
2019
2020     //printf("Found using declaration %s at line %d of %s inside section %x\n",
2021     //   root->name.data(),root->startLine,root->fileName.data(),
2022     //   rootNav->parent()->section());
2023     if (!root->name.isEmpty())
2024     {
2025       ClassDef *usingCd = 0;
2026       NamespaceDef *nd = 0;
2027       FileDef      *fd = rootNav->fileDef();
2028       QCString scName;
2029
2030       // see if the using statement was found inside a namespace or inside
2031       // the global file scope.
2032       if (rootNav->parent()->section() == Entry::NAMESPACE_SEC)
2033       {
2034         scName=rootNav->parent()->name();
2035         if (!scName.isEmpty())
2036         {
2037           nd = getResolvedNamespace(scName);
2038         }
2039       }
2040
2041       // Assume the using statement was used to import a class.
2042       // Find the scope in which the `using' namespace is defined by prepending
2043       // the possible scopes in which the using statement was found, starting
2044       // with the most inner scope and going to the most outer scope (i.e. 
2045       // file scope).
2046
2047       QCString name = substitute(root->name,".","::"); //Java/C# scope->internal
2048       usingCd = getClass(name);
2049       if (usingCd==0)
2050       {
2051         usingCd = Doxygen::hiddenClasses->find(name);
2052       }
2053
2054       //printf("%s -> %p\n",root->name.data(),usingCd);
2055       if (usingCd==0) // definition not in the input => add an artificial class
2056       {
2057         Debug::print(Debug::Classes,0,"  New using class `%s' (sec=0x%08x)! #tArgLists=%d\n",
2058              name.data(),root->section,root->tArgLists ? (int)root->tArgLists->count() : -1);
2059         usingCd = new ClassDef(
2060                      "<using>",1,1,
2061                      name,
2062                      ClassDef::Class);
2063         Doxygen::hiddenClasses->append(root->name,usingCd);
2064         usingCd->setArtificial(TRUE);
2065         usingCd->setLanguage(root->lang);
2066       }
2067       else
2068       {
2069         Debug::print(Debug::Classes,0,"  Found used class %s in scope=%s\n",
2070             usingCd->name().data(),nd?nd->name().data():fd->name().data());
2071       }
2072
2073       if (usingCd) // add the class to the correct scope
2074       {
2075         if (nd)
2076         {
2077           //printf("Inside namespace %s\n",nd->name().data());
2078           nd->addUsingDeclaration(usingCd);
2079         }
2080         else if (fd)
2081         {
2082           //printf("Inside file %s\n",fd->name().data());
2083           fd->addUsingDeclaration(usingCd);
2084         }
2085       }
2086     }
2087
2088     rootNav->releaseEntry();
2089   }
2090   RECURSE_ENTRYTREE(findUsingDeclarations,rootNav);
2091 }
2092
2093 //----------------------------------------------------------------------
2094
2095 static void findUsingDeclImports(EntryNav *rootNav)
2096 {
2097   if (rootNav->section()==Entry::USINGDECL_SEC &&
2098       (rootNav->parent()->section()&Entry::COMPOUND_MASK) // in a class/struct member
2099      )
2100   {
2101     //printf("Found using declaration %s at line %d of %s inside section %x\n",
2102     //    root->name.data(),root->startLine,root->fileName.data(),
2103     //    root->parent->section);
2104     QCString fullName=removeRedundantWhiteSpace(rootNav->parent()->name());
2105     fullName=stripAnonymousNamespaceScope(fullName);
2106     fullName=stripTemplateSpecifiersFromScope(fullName);
2107     ClassDef *cd = getClass(fullName);
2108     if (cd)
2109     {
2110       //printf("found class %s\n",cd->name().data());
2111       int i=rootNav->name().find("::");
2112       if (i!=-1)
2113       {
2114         QCString scope=rootNav->name().left(i);
2115         QCString memName=rootNav->name().right(rootNav->name().length()-i-2);
2116         ClassDef *bcd = getResolvedClass(cd,0,scope); // todo: file in fileScope parameter
2117         if (bcd)
2118         {
2119           //printf("found class %s\n",bcd->name().data());
2120           MemberNameInfoSDict *mndict=bcd->memberNameInfoSDict();
2121           if (mndict)
2122           {
2123             MemberNameInfo *mni = mndict->find(memName);
2124             if (mni)
2125             {
2126               MemberNameInfoIterator mnii(*mni); 
2127               MemberInfo *mi;
2128               for ( ; (mi=mnii.current()) ; ++mnii )
2129               {
2130                 MemberDef *md = mi->memberDef;
2131                 if (md && md->protection()!=Private)
2132                 {
2133
2134                   rootNav->loadEntry(g_storage);
2135                   Entry *root = rootNav->entry();
2136
2137                   //printf("found member %s\n",mni->memberName());
2138                   MemberDef *newMd = 0;
2139                   {
2140                     ArgumentList *templAl = md->templateArguments();
2141                     ArgumentList *al = md->templateArguments();
2142                     newMd = new MemberDef(
2143                       root->fileName,root->startLine,root->startColumn,
2144                       md->typeString(),memName,md->argsString(),
2145                       md->excpString(),root->protection,root->virt,
2146                       md->isStatic(),Member,md->memberType(),
2147                       templAl,al
2148                       );
2149                   }
2150                   newMd->setMemberClass(cd);
2151                   cd->insertMember(newMd);
2152                   if (!root->doc.isEmpty() || !root->brief.isEmpty())
2153                   {
2154                     newMd->setDocumentation(root->doc,root->docFile,root->docLine);
2155                     newMd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
2156                     newMd->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
2157                   }
2158                   else
2159                   {
2160                     newMd->setDocumentation(md->documentation(),md->docFile(),md->docLine());
2161                     newMd->setBriefDescription(md->briefDescription(),md->briefFile(),md->briefLine());
2162                     newMd->setInbodyDocumentation(md->inbodyDocumentation(),md->inbodyFile(),md->inbodyLine());
2163                   }
2164                   newMd->setDefinition(md->definition());
2165                   newMd->enableCallGraph(root->callGraph);
2166                   newMd->enableCallerGraph(root->callerGraph);
2167                   newMd->setBitfields(md->bitfieldString());
2168                   newMd->addSectionsToDefinition(root->anchors);
2169                   newMd->setBodySegment(md->getStartBodyLine(),md->getEndBodyLine());
2170                   newMd->setBodyDef(md->getBodyDef());
2171                   newMd->setInitializer(md->initializer());
2172                   newMd->setMaxInitLines(md->initializerLines());
2173                   newMd->setMemberGroupId(root->mGrpId);
2174                   newMd->setMemberSpecifiers(md->getMemberSpecifiers());
2175                   newMd->setLanguage(root->lang);
2176                   newMd->setId(root->id);
2177
2178                   rootNav->releaseEntry();
2179                 }
2180               }
2181             }
2182           }
2183         }
2184       }
2185     }
2186
2187   }
2188   RECURSE_ENTRYTREE(findUsingDeclImports,rootNav);
2189 }
2190
2191 //----------------------------------------------------------------------
2192
2193 static void findIncludedUsingDirectives()
2194 {
2195   // first mark all files as not visited
2196   FileNameListIterator fnli(*Doxygen::inputNameList); 
2197   FileName *fn;
2198   for (fnli.toFirst();(fn=fnli.current());++fnli)
2199   {
2200     FileNameIterator fni(*fn);
2201     FileDef *fd;
2202     for (;(fd=fni.current());++fni)
2203     {
2204       fd->visited=FALSE;
2205     }
2206   }
2207   // then recursively add using directives found in #include files
2208   // to files that have not been visited.
2209   for (fnli.toFirst();(fn=fnli.current());++fnli)
2210   {
2211     FileNameIterator fni(*fn);
2212     FileDef *fd;
2213     for (fni.toFirst();(fd=fni.current());++fni)
2214     {
2215       if (!fd->visited) 
2216       {
2217         //printf("----- adding using directives for file %s\n",fd->name().data());
2218         fd->addIncludedUsingDirectives();
2219       }
2220     }
2221   }
2222 }
2223
2224 //----------------------------------------------------------------------
2225
2226 static MemberDef *addVariableToClass(
2227     EntryNav *rootNav,
2228     ClassDef *cd,
2229     MemberType mtype,
2230     const QCString &name,
2231     bool fromAnnScope,
2232     MemberDef *fromAnnMemb,
2233     Protection prot,
2234     Relationship related)
2235 {
2236   Entry *root = rootNav->entry();
2237
2238   QCString qualScope = cd->qualifiedNameWithTemplateParameters();
2239   QCString scopeSeparator="::";
2240   SrcLangExt lang = cd->getLanguage();
2241   if (lang==SrcLangExt_Java || lang==SrcLangExt_CSharp)
2242   {
2243     qualScope = substitute(qualScope,"::",".");
2244     scopeSeparator=".";
2245   }
2246   Debug::print(Debug::Variables,0,
2247       "  class variable:\n"
2248       "    `%s' `%s'::`%s' `%s' prot=`%d ann=%d init=`%s'\n",
2249       root->type.data(),
2250       qualScope.data(), 
2251       name.data(),
2252       root->args.data(),
2253       root->protection,
2254       fromAnnScope,
2255       root->initializer.data()
2256               );
2257
2258   QCString def;
2259   if (!root->type.isEmpty())
2260   {
2261     if (related || mtype==MemberType_Friend || Config_getBool("HIDE_SCOPE_NAMES"))
2262     {
2263       if (root->spec&Entry::Alias) // turn 'typedef B A' into 'using A = B'  
2264       {
2265         def="using "+name+" = "+root->type.mid(7);
2266       }
2267       else
2268       {
2269         def=root->type+" "+name+root->args;
2270       }
2271     }
2272     else
2273     {
2274       if (root->spec&Entry::Alias) // turn 'typedef B C::A' into 'using C::A = B'  
2275       {
2276         def="using "+qualScope+scopeSeparator+name+" = "+root->type.mid(7);
2277       }
2278       else
2279       {
2280         def=root->type+" "+qualScope+scopeSeparator+name+root->args;
2281       }
2282     }
2283   }
2284   else
2285   {
2286     if (Config_getBool("HIDE_SCOPE_NAMES"))
2287     {
2288       def=name+root->args;
2289     }
2290     else
2291     {
2292       def=qualScope+scopeSeparator+name+root->args;
2293     }
2294   }
2295   def.stripPrefix("static ");
2296
2297   // see if the member is already found in the same scope
2298   // (this may be the case for a static member that is initialized
2299   //  outside the class)
2300   MemberName *mn=Doxygen::memberNameSDict->find(name);
2301   if (mn)
2302   {
2303     MemberNameIterator mni(*mn);
2304     MemberDef *md;
2305     for (mni.toFirst();(md=mni.current());++mni)
2306     {
2307       //printf("md->getClassDef()=%p cd=%p type=[%s] md->typeString()=[%s]\n",
2308       //    md->getClassDef(),cd,root->type.data(),md->typeString());
2309       if (md->getClassDef()==cd && 
2310           removeRedundantWhiteSpace(root->type)==md->typeString()) 
2311         // member already in the scope
2312       {
2313
2314         if (root->lang==SrcLangExt_ObjC && 
2315             root->mtype==Property && 
2316             md->memberType()==MemberType_Variable)
2317         { // Objective-C 2.0 property
2318           // turn variable into a property
2319           md->setProtection(root->protection);
2320           cd->reclassifyMember(md,MemberType_Property);
2321         }
2322         addMemberDocs(rootNav,md,def,0,FALSE);
2323         //printf("    Member already found!\n");
2324         return md;
2325       }
2326     } 
2327   }
2328
2329   // new member variable, typedef or enum value
2330   MemberDef *md=new MemberDef(
2331       root->fileName,root->startLine,root->startColumn,
2332       root->type,name,root->args,root->exception,
2333       prot,Normal,root->stat,related,
2334       mtype,root->tArgLists ? root->tArgLists->getLast() : 0,0);
2335   md->setTagInfo(rootNav->tagInfo());
2336   md->setMemberClass(cd); // also sets outer scope (i.e. getOuterScope())
2337   //md->setDefFile(root->fileName);
2338   //md->setDefLine(root->startLine);
2339   md->setDocumentation(root->doc,root->docFile,root->docLine);
2340   md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
2341   md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
2342   md->setDefinition(def);
2343   md->setBitfields(root->bitfields);
2344   md->addSectionsToDefinition(root->anchors);
2345   md->setFromAnonymousScope(fromAnnScope);
2346   md->setFromAnonymousMember(fromAnnMemb);
2347   //md->setIndentDepth(indentDepth);
2348   md->setBodySegment(root->bodyLine,root->endBodyLine);
2349   md->setInitializer(root->initializer);
2350   md->setMaxInitLines(root->initLines);
2351   md->setMemberGroupId(root->mGrpId);
2352   md->setMemberSpecifiers(root->spec);
2353   md->setReadAccessor(root->read);
2354   md->setWriteAccessor(root->write);
2355   md->enableCallGraph(root->callGraph);
2356   md->enableCallerGraph(root->callerGraph);
2357   md->setHidden(root->hidden);
2358   md->setArtificial(root->artificial);
2359   md->setLanguage(root->lang);
2360   md->setId(root->id);
2361   addMemberToGroups(root,md);
2362   //if (root->mGrpId!=-1) 
2363   //{
2364   //  printf("memberdef %s in memberGroup %d\n",name.data(),root->mGrpId);
2365   //  md->setMemberGroup(memberGroupDict[root->mGrpId]);
2366   //
2367   md->setBodyDef(rootNav->fileDef());
2368
2369   //printf("    Adding member=%s\n",md->name().data());
2370   // add the member to the global list
2371   if (mn)
2372   {
2373     mn->append(md);
2374   }
2375   else // new variable name
2376   {
2377     mn = new MemberName(name);
2378     mn->append(md);
2379     //printf("Adding memberName=%s\n",mn->memberName());
2380     //Doxygen::memberNameDict.insert(name,mn);
2381     //Doxygen::memberNameList.append(mn);
2382     Doxygen::memberNameSDict->append(name,mn);
2383     // add the member to the class
2384   }
2385   //printf("    New member adding to %s (%p)!\n",cd->name().data(),cd);
2386   cd->insertMember(md);
2387   md->setRefItems(root->sli);
2388
2389   //TODO: insert FileDef instead of filename strings.
2390   cd->insertUsedFile(rootNav->fileDef());
2391   rootNav->changeSection(Entry::EMPTY_SEC);
2392   return md;
2393 }
2394
2395 //----------------------------------------------------------------------
2396
2397 static MemberDef *addVariableToFile(
2398     EntryNav *rootNav,
2399     MemberType mtype,
2400     const QCString &scope,
2401     const QCString &name,
2402     bool fromAnnScope,
2403     /*int indentDepth,*/
2404     MemberDef *fromAnnMemb)
2405 {
2406   Entry *root = rootNav->entry();
2407   Debug::print(Debug::Variables,0,
2408       "  global variable:\n"
2409       "    type=`%s' scope=`%s' name=`%s' args=`%s' prot=`%d mtype=%d lang=%d\n",
2410       root->type.data(),
2411       scope.data(), 
2412       name.data(),
2413       root->args.data(),
2414       root->protection,
2415       mtype,
2416       root->lang
2417               );
2418
2419   FileDef *fd = rootNav->fileDef();
2420
2421   // see if we have a typedef that should hide a struct or union
2422   if (mtype==MemberType_Typedef && Config_getBool("TYPEDEF_HIDES_STRUCT"))
2423   {
2424     QCString type = root->type;
2425     type.stripPrefix("typedef ");
2426     if (type.left(7)=="struct " || type.left(6)=="union ")
2427     {
2428       type.stripPrefix("struct ");
2429       type.stripPrefix("union ");
2430       static QRegExp re("[a-z_A-Z][a-z_A-Z0-9]*");
2431       int l,s;
2432       s = re.match(type,0,&l);
2433       if (s>=0)
2434       {
2435         QCString typeValue = type.mid(s,l);
2436         ClassDef *cd = getClass(typeValue);
2437         if (cd)
2438         {
2439           // this typedef should hide compound name cd, so we
2440           // change the name that is displayed from cd.
2441           cd->setClassName(name);
2442           cd->setDocumentation(root->doc,root->docFile,root->docLine);
2443           cd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
2444           return 0;
2445         }
2446       }
2447     }
2448   }
2449
2450   // see if the function is inside a namespace
2451   NamespaceDef *nd = 0;
2452   QCString nscope;
2453   if (!scope.isEmpty())
2454   {
2455     if (scope.find('@')!=-1) return 0; // anonymous scope!
2456     //nscope=removeAnonymousScopes(scope);
2457     //if (!nscope.isEmpty())
2458     //{
2459     nd = getResolvedNamespace(scope);
2460     //}
2461   }
2462   QCString def;
2463
2464   // determine the definition of the global variable
2465   if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@' && 
2466       !Config_getBool("HIDE_SCOPE_NAMES")
2467      )
2468     // variable is inside a namespace, so put the scope before the name
2469   {
2470     SrcLangExt lang = nd->getLanguage();
2471     QCString sep=getLanguageSpecificSeparator(lang);
2472
2473     if (!root->type.isEmpty())
2474     {
2475       if (root->spec&Entry::Alias) // turn 'typedef B NS::A' into 'using NS::A = B'  
2476       {
2477         def="using "+nd->name()+sep+name+" = "+root->type;
2478       }
2479       else // normal member
2480       {
2481         def=root->type+" "+nd->name()+sep+name+root->args;
2482       }
2483     }
2484     else
2485     {
2486       def=nd->name()+sep+name+root->args;
2487     }
2488   }
2489   else
2490   {
2491     if (!root->type.isEmpty() && !root->name.isEmpty())
2492     {
2493       if (name.at(0)=='@') // dummy variable representing anonymous union
2494       {
2495         def=root->type;
2496       }
2497       else
2498       {
2499         if (root->spec&Entry::Alias) // turn 'typedef B A' into 'using A = B'  
2500         {
2501           def="using "+root->name+" = "+root->type.mid(7);
2502         }
2503         else // normal member
2504         {
2505           def=root->type+" "+name+root->args;
2506         }
2507       }
2508     }
2509     else
2510     {
2511       def=name+root->args;
2512     }
2513   }
2514   def.stripPrefix("static ");
2515
2516   MemberName *mn=Doxygen::functionNameSDict->find(name);
2517   if (mn)
2518   {
2519     //QCString nscope=removeAnonymousScopes(scope);
2520     //NamespaceDef *nd=0;
2521     //if (!nscope.isEmpty())
2522     if (!scope.isEmpty())
2523     {
2524       nd = getResolvedNamespace(scope);
2525     }
2526     MemberNameIterator mni(*mn);
2527     MemberDef *md;
2528     for (mni.toFirst();(md=mni.current());++mni)
2529     {
2530       if (
2531           ((nd==0 && md->getNamespaceDef()==0 && md->getFileDef() && 
2532             root->fileName==md->getFileDef()->absFilePath()
2533            ) // both variable names in the same file
2534            || (nd!=0 && md->getNamespaceDef()==nd) // both in same namespace
2535           )
2536           && !md->isDefine() // function style #define's can be "overloaded" by typedefs or variables
2537           && !md->isEnumerate() // in C# an enum value and enum can have the same name
2538          )
2539         // variable already in the scope
2540       {
2541         bool isPHPArray = md->getLanguage()==SrcLangExt_PHP &&
2542                           md->argsString()!=root->args && 
2543                           root->args.find('[')!=-1;
2544         bool staticsInDifferentFiles = 
2545                           root->stat && md->isStatic() && 
2546                           root->fileName!=md->getDefFileName();
2547
2548         if (md->getFileDef() &&
2549             !isPHPArray && // not a php array
2550             !staticsInDifferentFiles
2551            ) 
2552           // not a php array variable
2553         {
2554
2555           Debug::print(Debug::Variables,0,
2556               "    variable already found: scope=%s\n",md->getOuterScope()->name().data());
2557           addMemberDocs(rootNav,md,def,0,FALSE);
2558           md->setRefItems(root->sli);
2559           return md;
2560         }
2561       }
2562     } 
2563   }
2564   Debug::print(Debug::Variables,0,
2565     "    new variable, nd=%s!\n",nd?nd->name().data():"<global>");
2566   // new global variable, enum value or typedef
2567   MemberDef *md=new MemberDef(
2568       root->fileName,root->startLine,root->startColumn,
2569       root->type,name,root->args,0,
2570       Public, Normal,root->stat,Member,
2571       mtype,root->tArgLists ? root->tArgLists->getLast() : 0,0);
2572   md->setTagInfo(rootNav->tagInfo());
2573   md->setMemberSpecifiers(root->spec);
2574   md->setDocumentation(root->doc,root->docFile,root->docLine);
2575   md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
2576   md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
2577   md->addSectionsToDefinition(root->anchors);
2578   md->setFromAnonymousScope(fromAnnScope);
2579   md->setFromAnonymousMember(fromAnnMemb);
2580   md->setInitializer(root->initializer);
2581   md->setMaxInitLines(root->initLines);
2582   md->setMemberGroupId(root->mGrpId);
2583   md->setDefinition(def);
2584   md->setLanguage(root->lang);
2585   md->setId(root->id);
2586   md->enableCallGraph(root->callGraph);
2587   md->enableCallerGraph(root->callerGraph);
2588   md->setExplicitExternal(root->explicitExternal);
2589   //md->setOuterScope(fd);
2590   if (!root->explicitExternal)
2591   {
2592     md->setBodySegment(root->bodyLine,root->endBodyLine);
2593     md->setBodyDef(fd);
2594   }
2595   addMemberToGroups(root,md);
2596
2597   md->setRefItems(root->sli);
2598   if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@')
2599   {
2600     md->setNamespace(nd);
2601     nd->insertMember(md); 
2602   }
2603
2604   // add member to the file (we do this even if we have already inserted
2605   // it into the namespace. 
2606   if (fd)
2607   {
2608     md->setFileDef(fd); 
2609     fd->insertMember(md);
2610   }
2611
2612   // add member definition to the list of globals 
2613   if (mn)
2614   {
2615     mn->append(md);
2616   }
2617   else
2618   {
2619     mn = new MemberName(name);
2620     mn->append(md);
2621     Doxygen::functionNameSDict->append(name,mn);
2622   }
2623   rootNav->changeSection(Entry::EMPTY_SEC);
2624   return md;
2625 }
2626
2627 /*! See if the return type string \a type is that of a function pointer 
2628  *  \returns -1 if this is not a function pointer variable or
2629  *           the index at which the closing brace of (...*name) was found.
2630  */
2631 static int findFunctionPtr(const QCString &type,int lang, int *pLength=0)
2632 {
2633   if (lang == SrcLangExt_Fortran) return -1; // Fortran does not have function pointers
2634   static const QRegExp re("([^)]*[\\*\\^][^)]*)");
2635   int i=-1,l;
2636   int bb=type.find('<');
2637   int be=type.findRev('>');
2638   if (!type.isEmpty() &&             // return type is non-empty
2639       (i=re.match(type,0,&l))!=-1 && // contains (...*...)
2640       type.find("operator")==-1 &&   // not an operator
2641       (type.find(")(")==-1 || type.find("typedef ")!=-1) &&
2642                                     // not a function pointer return type
2643       !(bb<i && i<be) // bug665855: avoid treating "typedef A<void (T*)> type" as a function pointer
2644      )
2645   {
2646     if (pLength) *pLength=l;
2647     //printf("findFunctionPtr=%d\n",i);
2648     return i;
2649   }
2650   else
2651   {
2652     //printf("findFunctionPtr=%d\n",-1);
2653     return -1;
2654   }
2655 }
2656
2657
2658 /*! Returns TRUE iff \a type is a class within scope \a context.
2659  *  Used to detect variable declarations that look like function prototypes.
2660  */
2661 static bool isVarWithConstructor(EntryNav *rootNav)
2662 {
2663   static QRegExp initChars("[0-9\"'&*!^]+");
2664   static QRegExp idChars("[a-z_A-Z][a-z_A-Z0-9]*");
2665   bool result=FALSE;
2666   bool typeIsClass;
2667   QCString type;
2668   Definition *ctx = 0;
2669   FileDef *fd = 0;
2670   int ti;
2671
2672   //printf("isVarWithConstructor(%s)\n",rootNav->name().data());
2673   rootNav->loadEntry(g_storage);
2674   Entry *root = rootNav->entry();
2675
2676   if (rootNav->parent()->section() & Entry::COMPOUND_MASK)
2677   { // inside a class
2678     result=FALSE;
2679     goto done;
2680   }
2681   else if ((fd = rootNav->fileDef()) &&
2682             (fd->name().right(2)==".c" || fd->name().right(2)==".h")
2683           )
2684   { // inside a .c file
2685     result=FALSE;
2686     goto done;
2687   }
2688   if (root->type.isEmpty()) 
2689   {
2690     result=FALSE;
2691     goto done;
2692   }
2693   if (!rootNav->parent()->name().isEmpty()) 
2694   {
2695     ctx=Doxygen::namespaceSDict->find(rootNav->parent()->name());
2696   }
2697   type = root->type;
2698   // remove qualifiers
2699   findAndRemoveWord(type,"const");
2700   findAndRemoveWord(type,"static");
2701   findAndRemoveWord(type,"volatile");
2702   //if (type.left(6)=="const ") type=type.right(type.length()-6);
2703   typeIsClass=getResolvedClass(ctx,fd,type)!=0;
2704   if (!typeIsClass && (ti=type.find('<'))!=-1)
2705   {
2706     typeIsClass=getResolvedClass(ctx,fd,type.left(ti))!=0;
2707   }
2708   if (typeIsClass) // now we still have to check if the arguments are 
2709                    // types or values. Since we do not have complete type info
2710                    // we need to rely on heuristics :-(
2711   {
2712     //printf("typeIsClass\n");
2713     ArgumentList *al = root->argList;
2714     if (al==0 || al->isEmpty()) 
2715     {
2716       result=FALSE; // empty arg list -> function prototype.
2717       goto done;
2718     }
2719     ArgumentListIterator ali(*al);
2720     Argument *a;
2721     for (ali.toFirst();(a=ali.current());++ali)
2722     {
2723       if (!a->name.isEmpty() || !a->defval.isEmpty()) 
2724       {
2725         if (a->name.find(initChars)==0)
2726         {
2727           result=TRUE;
2728         }
2729         else
2730         {
2731           result=FALSE; // arg has (type,name) pair -> function prototype
2732         }
2733         goto done;
2734       }
2735       if (a->type.isEmpty() || getResolvedClass(ctx,fd,a->type)!=0) 
2736       {
2737         result=FALSE; // arg type is a known type
2738         goto done;
2739       }
2740       if (checkIfTypedef(ctx,fd,a->type))
2741       {
2742          //printf("%s:%d: false (arg is typedef)\n",__FILE__,__LINE__);
2743          result=FALSE; // argument is a typedef
2744          goto done;
2745       }
2746       if (a->type.at(a->type.length()-1)=='*' ||
2747           a->type.at(a->type.length()-1)=='&')  
2748                      // type ends with * or & => pointer or reference
2749       {
2750         result=FALSE;
2751         goto done;
2752       }
2753       if (a->type.find(initChars)==0) 
2754       {
2755         result=TRUE; // argument type starts with typical initializer char
2756         goto done;
2757       }
2758       QCString resType=resolveTypeDef(ctx,a->type);
2759       if (resType.isEmpty()) resType=a->type;
2760       int len;
2761       if (idChars.match(resType,0,&len)==0) // resType starts with identifier
2762       {
2763         resType=resType.left(len);
2764         //printf("resType=%s\n",resType.data());
2765         if (resType=="int"    || resType=="long" || resType=="float" || 
2766             resType=="double" || resType=="char" || resType=="signed" || 
2767             resType=="const"  || resType=="unsigned" || resType=="void") 
2768         {
2769           result=FALSE; // type keyword -> function prototype
2770           goto done;
2771         }
2772       }
2773     }
2774     result=TRUE;
2775   }
2776
2777 done:
2778   //printf("isVarWithConstructor(%s,%s)=%d\n",rootNav->parent()->name().data(),
2779   //                                          root->type.data(),result);
2780   rootNav->releaseEntry();
2781   return result;
2782 }
2783
2784 static void addVariable(EntryNav *rootNav,int isFuncPtr=-1)
2785 {
2786     rootNav->loadEntry(g_storage);
2787     Entry *root = rootNav->entry();
2788
2789     Debug::print(Debug::Variables,0,
2790                   "VARIABLE_SEC: \n"
2791                   "  type=`%s' name=`%s' args=`%s' bodyLine=`%d' mGrpId=%d relates=%s\n",
2792                    root->type.data(),
2793                    root->name.data(),
2794                    root->args.data(),
2795                    root->bodyLine,
2796                    root->mGrpId,
2797                    root->relates.data()
2798                 );
2799     //printf("root->parent->name=%s\n",root->parent->name.data());
2800
2801     if (root->type.isEmpty() && root->name.find("operator")==-1 &&
2802         (root->name.find('*')!=-1 || root->name.find('&')!=-1))
2803     {
2804       // recover from parse error caused by redundant braces 
2805       // like in "int *(var[10]);", which is parsed as
2806       // type="" name="int *" args="(var[10])"
2807
2808       root->type=root->name;
2809       static const QRegExp reName("[a-z_A-Z][a-z_A-Z0-9]*");
2810       int l=0;
2811       int i=root->args.isEmpty() ? -1 : reName.match(root->args,0,&l);
2812       if (i!=-1)
2813       {
2814         root->name=root->args.mid(i,l);
2815         root->args=root->args.mid(i+l,root->args.find(')',i+l)-i-l);
2816       }
2817       //printf("new: type=`%s' name=`%s' args=`%s'\n",
2818       //    root->type.data(),root->name.data(),root->args.data());
2819     }
2820     else
2821     {
2822       int i=isFuncPtr;
2823       if (i==-1 && (root->spec&Entry::Alias)==0) i=findFunctionPtr(root->type,root->lang); // for typedefs isFuncPtr is not yet set
2824       Debug::print(Debug::Variables,0,"  functionPtr? %s\n",i!=-1?"yes":"no");
2825       if (i!=-1) // function pointer
2826       {
2827         int ai = root->type.find('[',i);
2828         if (ai>i) // function pointer array
2829         {
2830           root->args.prepend(root->type.right(root->type.length()-ai));
2831           root->type=root->type.left(ai);
2832         }
2833         else if (root->type.find(')',i)!=-1) // function ptr, not variable like "int (*bla)[10]"
2834         {
2835           root->type=root->type.left(root->type.length()-1);
2836           root->args.prepend(")");
2837           //printf("root->type=%s root->args=%s\n",root->type.data(),root->args.data());
2838         }
2839       }
2840       else if (root->type.find("typedef ")!=-1 && root->type.right(2)=="()") // typedef void (func)(int)
2841       {
2842         root->type=root->type.left(root->type.length()-1);
2843         root->args.prepend(")");
2844       }
2845     }
2846     
2847     QCString scope,name=removeRedundantWhiteSpace(root->name);
2848
2849     // find the scope of this variable 
2850     EntryNav *p = rootNav->parent();
2851     while ((p->section() & Entry::SCOPE_MASK))
2852     {
2853       QCString scopeName = p->name();
2854       if (!scopeName.isEmpty())
2855       {
2856         scope.prepend(scopeName);
2857         break;
2858       }
2859       p=p->parent();
2860     }
2861     
2862     MemberType mtype;
2863     QCString type=root->type.stripWhiteSpace();
2864     ClassDef *cd=0;
2865     bool isRelated=FALSE;
2866     bool isMemberOf=FALSE;
2867
2868     QCString classScope=stripAnonymousNamespaceScope(scope);
2869     classScope=stripTemplateSpecifiersFromScope(classScope,FALSE);
2870     QCString annScopePrefix=scope.left(scope.length()-classScope.length());
2871
2872     if (root->name.findRev("::")!=-1) 
2873     {
2874       if (root->type=="friend class" || root->type=="friend struct" || 
2875           root->type=="friend union")
2876       {
2877          cd=getClass(scope);
2878          if (cd)
2879          {
2880            addVariableToClass(rootNav,  // entry
2881                               cd,    // class to add member to
2882                               MemberType_Friend, // type of member
2883                               name, // name of the member
2884                               FALSE,  // from Anonymous scope
2885                               0,      // anonymous member
2886                               Public, // protection
2887                               Member  // related to a class
2888                              );
2889          }
2890       }
2891       goto nextMember;
2892                /* skip this member, because it is a 
2893                 * static variable definition (always?), which will be
2894                 * found in a class scope as well, but then we know the
2895                 * correct protection level, so only then it will be
2896                 * inserted in the correct list!
2897                 */
2898     }
2899
2900     if (type=="@") 
2901       mtype=MemberType_EnumValue;
2902     else if (type.left(8)=="typedef ") 
2903       mtype=MemberType_Typedef;
2904     else if (type.left(7)=="friend ")
2905       mtype=MemberType_Friend;
2906     else if (root->mtype==Property)
2907       mtype=MemberType_Property;
2908     else if (root->mtype==Event)
2909       mtype=MemberType_Event;
2910     else
2911       mtype=MemberType_Variable;
2912
2913     if (!root->relates.isEmpty()) // related variable
2914     {
2915       isRelated=TRUE;
2916       isMemberOf=(root->relatesType == MemberOf);
2917       if (getClass(root->relates)==0 && !scope.isEmpty())
2918         scope=mergeScopes(scope,root->relates);
2919       else 
2920         scope=root->relates;
2921     }
2922     
2923     cd=getClass(scope);
2924     if (cd==0 && classScope!=scope) cd=getClass(classScope);
2925     if (cd)
2926     {
2927       MemberDef *md=0;
2928
2929       // if cd is an anonymous (=tag less) scope we insert the member 
2930       // into a non-anonymous parent scope as well. This is needed to
2931       // be able to refer to it using \var or \fn
2932
2933       //int indentDepth=0;
2934       int si=scope.find('@');
2935       //int anonyScopes = 0;
2936       //bool added=FALSE;
2937       
2938       static bool inlineSimpleStructs = Config_getBool("INLINE_SIMPLE_STRUCTS");
2939       if (si!=-1 && !inlineSimpleStructs) // anonymous scope or type
2940       {
2941         QCString pScope;
2942         ClassDef *pcd=0;
2943         pScope = scope.left(QMAX(si-2,0)); // scope without tag less parts
2944         if (!pScope.isEmpty())
2945           pScope.prepend(annScopePrefix);
2946         else if (annScopePrefix.length()>2)
2947           pScope=annScopePrefix.left(annScopePrefix.length()-2);
2948         if (name.at(0)!='@')
2949         {
2950           if (!pScope.isEmpty() && (pcd=getClass(pScope)))
2951           {
2952             md=addVariableToClass(rootNav,  // entry
2953                                   pcd,   // class to add member to
2954                                   mtype, // member type
2955                                   name,  // member name
2956                                   TRUE,  // from anonymous scope
2957                                   0,     // from anonymous member
2958                                   root->protection,
2959                                   isMemberOf ? Foreign : isRelated ? Related : Member
2960                                  );
2961             //added=TRUE;
2962           }
2963           else // anonymous scope inside namespace or file => put variable in the global scope
2964           {
2965             if (mtype==MemberType_Variable)
2966             {
2967               md=addVariableToFile(rootNav,mtype,pScope,name,TRUE,0); 
2968             }
2969             //added=TRUE;
2970           }
2971         }
2972       }
2973
2974       //printf("name=`%s' scope=%s scope.right=%s\n",
2975       //                   name.data(),scope.data(),
2976       //                   scope.right(scope.length()-si).data());
2977       addVariableToClass(rootNav,   // entry
2978                          cd,     // class to add member to
2979                          mtype,  // member type
2980                          name,   // name of the member
2981                          FALSE,  // from anonymous scope
2982                          md,     // from anonymous member
2983                          root->protection, 
2984                          isMemberOf ? Foreign : isRelated ? Related : Member);
2985     }
2986     else if (!name.isEmpty()) // global variable
2987     {
2988       //printf("Inserting member in global scope %s!\n",scope.data());
2989       addVariableToFile(rootNav,mtype,scope,name,FALSE,/*0,*/0);
2990     }
2991
2992 nextMember:
2993     rootNav->releaseEntry();
2994 }
2995
2996 //----------------------------------------------------------------------
2997 // Searches the Entry tree for typedef documentation sections.
2998 // If found they are stored in their class or in the global list.
2999 static void buildTypedefList(EntryNav *rootNav)
3000 {
3001   //printf("buildVarList(%s)\n",rootNav->name().data());
3002   if (!rootNav->name().isEmpty() &&
3003       rootNav->section()==Entry::VARIABLE_SEC &&
3004       rootNav->type().find("typedef ")!=-1 // its a typedef
3005      ) 
3006   {
3007     addVariable(rootNav);
3008   }
3009   if (rootNav->children())
3010   {
3011     EntryNavListIterator eli(*rootNav->children());
3012     EntryNav *e;
3013     for (;(e=eli.current());++eli)
3014     {
3015       if (e->section()!=Entry::ENUM_SEC) 
3016       {
3017         buildTypedefList(e);
3018       }
3019     }
3020   }
3021 }
3022
3023 //----------------------------------------------------------------------
3024 // Searches the Entry tree for Variable documentation sections.
3025 // If found they are stored in their class or in the global list.
3026
3027 static void buildVarList(EntryNav *rootNav)
3028 {
3029   //printf("buildVarList(%s) section=%08x\n",rootNav->name().data(),rootNav->section());
3030   int isFuncPtr=-1;
3031   if (!rootNav->name().isEmpty() &&
3032       (rootNav->type().isEmpty() || g_compoundKeywordDict.find(rootNav->type())==0) &&
3033       (
3034        (rootNav->section()==Entry::VARIABLE_SEC    // it's a variable
3035        ) ||
3036        (rootNav->section()==Entry::FUNCTION_SEC && // or maybe a function pointer variable 
3037         (isFuncPtr=findFunctionPtr(rootNav->type(),rootNav->lang()))!=-1
3038        ) ||
3039        (rootNav->section()==Entry::FUNCTION_SEC && // class variable initialized by constructor
3040         isVarWithConstructor(rootNav)
3041        )
3042       ) 
3043      ) // documented variable
3044   {
3045     addVariable(rootNav,isFuncPtr);
3046   }
3047   if (rootNav->children())
3048   {
3049     EntryNavListIterator eli(*rootNav->children());
3050     EntryNav *e;
3051     for (;(e=eli.current());++eli)
3052     {
3053       if (e->section()!=Entry::ENUM_SEC) 
3054       {
3055         buildVarList(e);
3056       }
3057     }
3058   }
3059 }
3060
3061 //----------------------------------------------------------------------
3062 // Searches the Entry tree for Interface sections (UNO IDL only).
3063 // If found they are stored in their service or in the global list.
3064 //
3065
3066 static void addInterfaceOrServiceToServiceOrSingleton(
3067         EntryNav *const rootNav,
3068         ClassDef *const cd,
3069         QCString const& rname)
3070 {
3071   Entry *const root = rootNav->entry();
3072   FileDef *const fd = rootNav->fileDef();
3073   enum MemberType const type = (rootNav->section()==Entry::EXPORTED_INTERFACE_SEC)
3074       ? MemberType_Interface
3075       : MemberType_Service;
3076   MemberDef *const md = new MemberDef(
3077       root->fileName, root->startLine, root->startColumn, root->type, rname,
3078       "", "", root->protection, root->virt, root->stat, Member,
3079       type, 0, root->argList);
3080   md->setTagInfo(rootNav->tagInfo());
3081   md->setMemberClass(cd);
3082   md->setDocumentation(root->doc,root->docFile,root->docLine);
3083   md->setDocsForDefinition(false);
3084   md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
3085   md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
3086   md->setBodySegment(root->bodyLine,root->endBodyLine);
3087   md->setMemberSpecifiers(root->spec);
3088   md->setMemberGroupId(root->mGrpId);
3089   md->setTypeConstraints(root->typeConstr);
3090   md->setLanguage(root->lang);
3091   md->setBodyDef(fd);
3092   md->setFileDef(fd);
3093   md->addSectionsToDefinition(root->anchors);
3094   QCString const def = root->type + " " + rname;
3095   md->setDefinition(def);
3096   md->enableCallGraph(root->callGraph);
3097   md->enableCallerGraph(root->callerGraph);
3098
3099   Debug::print(Debug::Functions,0,
3100       "  Interface Member:\n"
3101       "    `%s' `%s' proto=%d\n"
3102       "    def=`%s'\n",
3103       root->type.data(),
3104       rname.data(),
3105       root->proto,
3106       def.data()
3107               );
3108
3109   // add member to the global list of all members
3110   MemberName *mn;
3111   if ((mn=Doxygen::memberNameSDict->find(rname)))
3112   {
3113     mn->append(md);
3114   }
3115   else
3116   {
3117     mn = new MemberName(rname);
3118     mn->append(md);
3119     Doxygen::memberNameSDict->append(rname,mn);
3120   }
3121
3122   // add member to the class cd
3123   cd->insertMember(md);
3124   // also add the member as a "base" (to get nicer diagrams)
3125   // "optional" interface/service get Protected which turns into dashed line
3126   BaseInfo base(rname,
3127           (root->spec & (Entry::Optional)) ? Protected : Public,Normal);
3128   findClassRelation(rootNav,cd,cd,&base,0,DocumentedOnly,true)
3129   || findClassRelation(rootNav,cd,cd,&base,0,Undocumented,true);
3130   // add file to list of used files
3131   cd->insertUsedFile(fd);
3132
3133   addMemberToGroups(root,md);
3134   rootNav->changeSection(Entry::EMPTY_SEC);
3135   md->setRefItems(root->sli);
3136 }
3137
3138 static void buildInterfaceAndServiceList(EntryNav *const rootNav)
3139 {
3140   if (rootNav->section()==Entry::EXPORTED_INTERFACE_SEC ||
3141       rootNav->section()==Entry::INCLUDED_SERVICE_SEC)
3142   {
3143     rootNav->loadEntry(g_storage);
3144     Entry *const root = rootNav->entry();
3145
3146     Debug::print(Debug::Functions,0,
3147                  "EXPORTED_INTERFACE_SEC:\n"
3148                  "  `%s' `%s'::`%s' `%s' relates=`%s' relatesType=`%d' file=`%s' line=`%d' bodyLine=`%d' #tArgLists=%d mGrpId=%d spec=%lld proto=%d docFile=%s\n",
3149                  root->type.data(),
3150                  rootNav->parent()->name().data(),
3151                  root->name.data(),
3152                  root->args.data(),
3153                  root->relates.data(),
3154                  root->relatesType,
3155                  root->fileName.data(),
3156                  root->startLine,
3157                  root->bodyLine,
3158                  root->tArgLists ? (int)root->tArgLists->count() : -1,
3159                  root->mGrpId,
3160                  root->spec,
3161                  root->proto,
3162                  root->docFile.data()
3163                 );
3164
3165     QCString const rname = removeRedundantWhiteSpace(root->name);
3166
3167     if (!rname.isEmpty())
3168     {
3169       QCString const scope = rootNav->parent()->name();
3170       ClassDef *const cd = getClass(scope);
3171       assert(cd);
3172       if (cd && ((ClassDef::Interface == cd->compoundType()) ||
3173                  (ClassDef::Service   == cd->compoundType()) ||
3174                  (ClassDef::Singleton == cd->compoundType())))
3175       {
3176         addInterfaceOrServiceToServiceOrSingleton(rootNav,cd,rname);
3177       }
3178       else
3179       {
3180         assert(false); // was checked by scanner.l
3181       }
3182     }
3183     else if (rname.isEmpty())
3184     {
3185       warn(root->fileName,root->startLine,
3186            "Illegal member name found.");
3187     }
3188
3189     rootNav->releaseEntry();
3190   }
3191   // can only have these in IDL anyway
3192   switch (rootNav->lang())
3193   {
3194     case SrcLangExt_Unknown: // fall through (root node always is Unknown)
3195     case SrcLangExt_IDL:
3196         RECURSE_ENTRYTREE(buildInterfaceAndServiceList,rootNav);
3197         break;
3198     default:
3199         return; // nothing to do here
3200   }
3201 }
3202
3203
3204 //----------------------------------------------------------------------
3205 // Searches the Entry tree for Function sections.
3206 // If found they are stored in their class or in the global list.
3207
3208 static void addMethodToClass(EntryNav *rootNav,ClassDef *cd,
3209                   const QCString &rname,bool isFriend)
3210 {
3211   Entry *root = rootNav->entry();
3212   FileDef *fd=rootNav->fileDef();
3213
3214   int l;
3215   static QRegExp re("([a-z_A-Z0-9: ]*[ &*]+[ ]*");
3216   int ts=root->type.find('<');
3217   int te=root->type.findRev('>');
3218   int i=re.match(root->type,0,&l);
3219   if (i!=-1 && ts!=-1 && ts<te && ts<i && i<te) // avoid changing A<int(int*)>, see bug 677315
3220   {
3221     i=-1;
3222   }
3223
3224   if (cd->getLanguage()==SrcLangExt_Cpp && // only C has pointers
3225       !root->type.isEmpty() && (root->spec&Entry::Alias)==0 && i!=-1) // function variable
3226   {
3227     root->args+=root->type.right(root->type.length()-i-l);
3228     root->type=root->type.left(i+l);
3229   }
3230
3231   QCString name=removeRedundantWhiteSpace(rname);
3232   if (name.left(2)=="::") name=name.right(name.length()-2);
3233
3234   MemberType mtype;
3235   if (isFriend)                 mtype=MemberType_Friend;
3236   else if (root->mtype==Signal) mtype=MemberType_Signal;
3237   else if (root->mtype==Slot)   mtype=MemberType_Slot;
3238   else if (root->mtype==DCOP)   mtype=MemberType_DCOP;
3239   else                          mtype=MemberType_Function;
3240
3241   // strip redundant template specifier for constructors
3242   if ((fd==0 || fd->getLanguage()==SrcLangExt_Cpp) &&
3243      name.left(9)!="operator " && (i=name.find('<'))!=-1 && name.find('>')!=-1)
3244   {
3245     name=name.left(i); 
3246   }
3247
3248   //printf("root->name=`%s; root->args=`%s' root->argList=`%s'\n", 
3249   //    root->name.data(),root->args.data(),argListToString(root->argList).data()
3250   //   );
3251
3252   // adding class member
3253   MemberDef *md=new MemberDef(
3254       root->fileName,root->startLine,root->startColumn,
3255       root->type,name,root->args,root->exception,
3256       root->protection,root->virt,
3257       root->stat && root->relatesType != MemberOf,
3258       root->relates.isEmpty() ? Member :
3259           root->relatesType == MemberOf ? Foreign : Related,
3260       mtype,root->tArgLists ? root->tArgLists->getLast() : 0,root->argList);
3261   md->setTagInfo(rootNav->tagInfo());
3262   md->setMemberClass(cd);
3263   md->setDocumentation(root->doc,root->docFile,root->docLine);
3264   md->setDocsForDefinition(!root->proto);
3265   md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
3266   md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
3267   md->setBodySegment(root->bodyLine,root->endBodyLine);
3268   md->setMemberSpecifiers(root->spec);
3269   md->setMemberGroupId(root->mGrpId);
3270   md->setTypeConstraints(root->typeConstr);
3271   md->setLanguage(root->lang);
3272   md->setId(root->id);
3273   md->setBodyDef(fd);
3274   md->setFileDef(fd);
3275   //md->setScopeTemplateArguments(root->tArgList);
3276   md->addSectionsToDefinition(root->anchors);
3277   QCString def;
3278   QCString qualScope = cd->qualifiedNameWithTemplateParameters();
3279   SrcLangExt lang = cd->getLanguage();
3280   QCString scopeSeparator=getLanguageSpecificSeparator(lang);
3281   if (scopeSeparator!="::")
3282   {
3283     qualScope = substitute(qualScope,"::",scopeSeparator);
3284   }
3285   if (lang==SrcLangExt_PHP)
3286   {
3287     // for PHP we use Class::method and Namespace\method
3288     scopeSeparator="::";
3289   }
3290   if (!root->relates.isEmpty() || isFriend || Config_getBool("HIDE_SCOPE_NAMES"))
3291   {
3292     if (!root->type.isEmpty())
3293     {
3294       if (root->argList)
3295       {
3296         def=root->type+" "+name;
3297       }
3298       else
3299       {
3300         def=root->type+" "+name+root->args;
3301       }
3302     }
3303     else
3304     {
3305       if (root->argList)
3306       {
3307         def=name;
3308       }
3309       else
3310       {
3311         def=name+root->args;
3312       }
3313     }
3314   }
3315   else
3316   {
3317     if (!root->type.isEmpty())
3318     {
3319       if (root->argList)
3320       {
3321         def=root->type+" "+qualScope+scopeSeparator+name;
3322       }
3323       else
3324       {
3325         def=root->type+" "+qualScope+scopeSeparator+name+root->args;
3326       }
3327     }
3328     else
3329     {
3330       if (root->argList)
3331       {
3332         def=qualScope+scopeSeparator+name;
3333       }
3334       else
3335       {
3336         def=qualScope+scopeSeparator+name+root->args;
3337       }
3338     }
3339   }
3340   if (def.left(7)=="friend ") def=def.right(def.length()-7);
3341   md->setDefinition(def);
3342   md->enableCallGraph(root->callGraph);
3343   md->enableCallerGraph(root->callerGraph);
3344
3345   Debug::print(Debug::Functions,0,
3346       "  Func Member:\n"
3347       "    `%s' `%s'::`%s' `%s' proto=%d\n"
3348       "    def=`%s'\n",
3349       root->type.data(),
3350       qualScope.data(),
3351       rname.data(),
3352       root->args.data(),
3353       root->proto,
3354       def.data()
3355               );
3356
3357   // add member to the global list of all members
3358   //printf("Adding member=%s class=%s\n",md->name().data(),cd->name().data());
3359   MemberName *mn;
3360   if ((mn=Doxygen::memberNameSDict->find(name)))
3361   {
3362     mn->append(md);
3363   }
3364   else
3365   {
3366     mn = new MemberName(name);
3367     mn->append(md);
3368     Doxygen::memberNameSDict->append(name,mn);
3369   }
3370
3371   // add member to the class cd
3372   cd->insertMember(md);
3373   // add file to list of used files
3374   cd->insertUsedFile(fd);
3375
3376   addMemberToGroups(root,md);
3377   rootNav->changeSection(Entry::EMPTY_SEC);
3378   md->setRefItems(root->sli);
3379 }
3380
3381
3382 static void buildFunctionList(EntryNav *rootNav)
3383 {
3384   if (rootNav->section()==Entry::FUNCTION_SEC)
3385   {
3386     rootNav->loadEntry(g_storage);
3387     Entry *root = rootNav->entry();
3388
3389     Debug::print(Debug::Functions,0,
3390                  "FUNCTION_SEC:\n"
3391                  "  `%s' `%s'::`%s' `%s' relates=`%s' relatesType=`%d' file=`%s' line=`%d' bodyLine=`%d' #tArgLists=%d mGrpId=%d spec=%lld proto=%d docFile=%s\n",
3392                  root->type.data(),
3393                  rootNav->parent()->name().data(),
3394                  root->name.data(),
3395                  root->args.data(),
3396                  root->relates.data(),
3397                  root->relatesType,
3398                  root->fileName.data(),
3399                  root->startLine,
3400                  root->bodyLine,
3401                  root->tArgLists ? (int)root->tArgLists->count() : -1,
3402                  root->mGrpId,
3403                  root->spec,
3404                  root->proto,
3405                  root->docFile.data()
3406                 );
3407
3408     bool isFriend=root->type.find("friend ")!=-1;
3409     QCString rname = removeRedundantWhiteSpace(root->name);
3410     //printf("rname=%s\n",rname.data());
3411
3412     QCString scope=rootNav->parent()->name(); //stripAnonymousNamespaceScope(root->parent->name);
3413     if (!rname.isEmpty() && scope.find('@')==-1)
3414     {
3415       ClassDef *cd=0;
3416       // check if this function's parent is a class
3417       scope=stripTemplateSpecifiersFromScope(scope,FALSE);
3418
3419       FileDef *rfd=rootNav->fileDef();
3420
3421       int memIndex=rname.findRev("::");
3422
3423       cd=getClass(scope);
3424       if (cd && scope+"::"==rname.left(scope.length()+2)) // found A::f inside A
3425       {
3426         // strip scope from name
3427         rname=rname.right(rname.length()-rootNav->parent()->name().length()-2); 
3428       }
3429
3430       NamespaceDef *nd = 0;
3431       bool isMember=FALSE;
3432       if (memIndex!=-1)
3433       {
3434         int ts=rname.find('<');
3435         int te=rname.find('>');
3436         if (memIndex>0 && (ts==-1 || te==-1))
3437         {
3438           // note: the following code was replaced by inMember=TRUE to deal with a 
3439           // function rname='X::foo' of class X inside a namespace also called X...
3440           // bug id 548175
3441           //nd = Doxygen::namespaceSDict->find(rname.left(memIndex));
3442           //isMember = nd==0;
3443           //if (nd)
3444           //{
3445           //  // strip namespace scope from name
3446           //  scope=rname.left(memIndex);
3447           //  rname=rname.right(rname.length()-memIndex-2);
3448           //}
3449           isMember = TRUE;
3450         }
3451         else
3452         {
3453           isMember=memIndex<ts || memIndex>te;
3454         }
3455       }
3456
3457       static QRegExp re("([a-z_A-Z0-9: ]*[ &*]+[ ]*");
3458       int ts=root->type.find('<');
3459       int te=root->type.findRev('>');
3460       int ti;
3461       if (!rootNav->parent()->name().isEmpty() &&
3462           (rootNav->parent()->section() & Entry::COMPOUND_MASK) && 
3463           cd &&
3464           // do some fuzzy things to exclude function pointers 
3465           (root->type.isEmpty() || 
3466            ((ti=root->type.find(re,0))==-1 ||      // type does not contain ..(..* 
3467             (ts!=-1 && ts<te && ts<ti && ti<te) || // outside of < ... >
3468            root->args.find(")[")!=-1) ||           // and args not )[.. -> function pointer
3469            root->type.find(")(")!=-1 || root->type.find("operator")!=-1 || // type contains ..)(.. and not "operator"
3470            cd->getLanguage()!=SrcLangExt_Cpp                               // language other than C
3471           )
3472          )
3473       {
3474         Debug::print(Debug::Functions,0,"  --> member %s of class %s!\n",
3475             rname.data(),cd->name().data());
3476         addMethodToClass(rootNav,cd,rname,isFriend);
3477       }
3478       else if (!((rootNav->parent()->section() & Entry::COMPOUND_MASK) 
3479                  || rootNav->parent()->section()==Entry::OBJCIMPL_SEC
3480                 ) &&
3481                !isMember &&
3482                (root->relates.isEmpty() || root->relatesType == Duplicate) &&
3483                root->type.left(7)!="extern " && root->type.left(8)!="typedef " 
3484               )
3485       // no member => unrelated function 
3486       {
3487         /* check the uniqueness of the function name in the file.
3488          * A file could contain a function prototype and a function definition
3489          * or even multiple function prototypes.
3490          */
3491         bool found=FALSE;
3492         MemberName *mn;
3493         MemberDef *md=0;
3494         if ((mn=Doxygen::functionNameSDict->find(rname)))
3495         {
3496           Debug::print(Debug::Functions,0,"  --> function %s already found!\n",rname.data());
3497           MemberNameIterator mni(*mn);
3498           for (mni.toFirst();(!found && (md=mni.current()));++mni)
3499           {
3500             NamespaceDef *mnd = md->getNamespaceDef();
3501             NamespaceDef *rnd = 0;
3502             //printf("root namespace=%s\n",rootNav->parent()->name().data());
3503             QCString fullScope = scope;
3504             QCString parentScope = rootNav->parent()->name();
3505             if (!parentScope.isEmpty() && !leftScopeMatch(parentScope,scope))
3506             {
3507               if (!scope.isEmpty()) fullScope.prepend("::");
3508               fullScope.prepend(parentScope);
3509             }
3510             //printf("fullScope=%s\n",fullScope.data());
3511             rnd = getResolvedNamespace(fullScope);
3512             FileDef *mfd = md->getFileDef();
3513             QCString nsName,rnsName;
3514             if (mnd)  nsName = mnd->name().copy();
3515             if (rnd) rnsName = rnd->name().copy();
3516             //printf("matching arguments for %s%s %s%s\n",
3517             //    md->name().data(),md->argsString(),rname.data(),argListToString(root->argList).data());
3518             ArgumentList *mdAl = md->argumentList();
3519             ArgumentList *mdTempl = md->templateArguments();
3520
3521             // in case of template functions, we need to check if the
3522             // functions have the same number of template parameters
3523             bool sameNumTemplateArgs = TRUE;
3524             bool matchingReturnTypes = TRUE;
3525             if (mdTempl!=0 && root->tArgLists)
3526             {
3527               if (mdTempl->count()!=root->tArgLists->getLast()->count())
3528               {
3529                 sameNumTemplateArgs = FALSE;
3530               }
3531               if (md->typeString()!=removeRedundantWhiteSpace(root->type))
3532               {
3533                 matchingReturnTypes = FALSE;
3534               }
3535             }
3536
3537             bool staticsInDifferentFiles = 
3538                     root->stat && md->isStatic() && root->fileName!=md->getDefFileName();
3539
3540             if (
3541                 matchArguments2(md->getOuterScope(),mfd,mdAl,
3542                                 rnd ? rnd : Doxygen::globalScope,rfd,root->argList,
3543                                 FALSE) &&
3544                 sameNumTemplateArgs && 
3545                 matchingReturnTypes &&
3546                 !staticsInDifferentFiles
3547                )
3548             {
3549               GroupDef *gd=0;
3550               if (root->groups->getFirst()!=0)
3551               {
3552                 gd = Doxygen::groupSDict->find(root->groups->getFirst()->groupname.data());
3553               }
3554               //printf("match!\n");
3555               //printf("mnd=%p rnd=%p nsName=%s rnsName=%s\n",mnd,rnd,nsName.data(),rnsName.data());
3556               // see if we need to create a new member
3557               found=(mnd && rnd && nsName==rnsName) ||   // members are in the same namespace
3558                     ((mnd==0 && rnd==0 && mfd!=0 &&       // no external reference and
3559                       mfd->absFilePath()==root->fileName // prototype in the same file
3560                      )
3561                     );
3562               // otherwise, allow a duplicate global member with the same argument list
3563               if (!found && gd && gd==md->getGroupDef() && nsName==rnsName)
3564               {
3565                 // member is already in the group, so we don't want to add it again.
3566                 found=TRUE;
3567               }
3568
3569               //printf("combining function with prototype found=%d in namespace %s\n",
3570               //    found,nsName.data());
3571
3572               if (found)
3573               {
3574                 // merge argument lists
3575                 mergeArguments(mdAl,root->argList,!root->doc.isEmpty());
3576                 // merge documentation
3577                 if (md->documentation().isEmpty() && !root->doc.isEmpty())
3578                 {
3579                   ArgumentList *argList = new ArgumentList;
3580                   stringToArgumentList(root->args,argList);
3581                   if (root->proto)
3582                   {
3583                     //printf("setDeclArgumentList to %p\n",argList);
3584                     md->setDeclArgumentList(argList);
3585                   }
3586                   else
3587                   {
3588                     md->setArgumentList(argList);
3589                   }
3590                 }
3591
3592                 md->setDocumentation(root->doc,root->docFile,root->docLine);
3593                 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
3594                 md->setDocsForDefinition(!root->proto);
3595                 if (md->getStartBodyLine()==-1 && root->bodyLine!=-1)
3596                 {
3597                   md->setBodySegment(root->bodyLine,root->endBodyLine);
3598                   md->setBodyDef(rfd);
3599                 }
3600
3601                 if (md->briefDescription().isEmpty() && !root->brief.isEmpty())
3602                 {
3603                   md->setArgsString(root->args);
3604                 }
3605                 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
3606
3607                 md->addSectionsToDefinition(root->anchors);
3608
3609                 md->enableCallGraph(md->hasCallGraph() || root->callGraph);
3610                 md->enableCallerGraph(md->hasCallerGraph() || root->callerGraph);
3611
3612                 // merge ingroup specifiers
3613                 if (md->getGroupDef()==0 && root->groups->getFirst()!=0)
3614                 {
3615                   addMemberToGroups(root,md);
3616                 }
3617                 else if (md->getGroupDef()!=0 && root->groups->count()==0)
3618                 {
3619                   //printf("existing member is grouped, new member not\n");
3620                   root->groups->append(new Grouping(md->getGroupDef()->name(), md->getGroupPri()));
3621                 }
3622                 else if (md->getGroupDef()!=0 && root->groups->getFirst()!=0)
3623                 {
3624                   //printf("both members are grouped\n");
3625                 }
3626
3627                 // if md is a declaration and root is the corresponding
3628                 // definition, then turn md into a definition.
3629                 if (md->isPrototype() && !root->proto)
3630                 {
3631                   md->setPrototype(FALSE);
3632                 }
3633               }
3634             }
3635           }
3636         }
3637         if (!found) /* global function is unique with respect to the file */
3638         {
3639           Debug::print(Debug::Functions,0,"  --> new function %s found!\n",rname.data());
3640           //printf("New function type=`%s' name=`%s' args=`%s' bodyLine=%d\n",
3641           //       root->type.data(),rname.data(),root->args.data(),root->bodyLine);
3642
3643           // new global function
3644           ArgumentList *tArgList = root->tArgLists ? root->tArgLists->getLast() : 0;
3645           QCString name=removeRedundantWhiteSpace(rname);
3646           md=new MemberDef(
3647               root->fileName,root->startLine,root->startColumn,
3648               root->type,name,root->args,root->exception,
3649               root->protection,root->virt,root->stat,Member,
3650               MemberType_Function,tArgList,root->argList);
3651
3652           md->setTagInfo(rootNav->tagInfo());
3653           md->setLanguage(root->lang);
3654           md->setId(root->id);
3655           //md->setDefFile(root->fileName);
3656           //md->setDefLine(root->startLine);
3657           md->setDocumentation(root->doc,root->docFile,root->docLine);
3658           md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
3659           md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
3660           md->setPrototype(root->proto);
3661           md->setDocsForDefinition(!root->proto);
3662           md->setTypeConstraints(root->typeConstr);
3663           //md->setBody(root->body);
3664           md->setBodySegment(root->bodyLine,root->endBodyLine);
3665           FileDef *fd=rootNav->fileDef();
3666           md->setBodyDef(fd);
3667           md->addSectionsToDefinition(root->anchors);
3668           md->setMemberSpecifiers(root->spec);
3669           md->setMemberGroupId(root->mGrpId);
3670
3671           // see if the function is inside a namespace that was not part of
3672           // the name already (in that case nd should be non-zero already)
3673           if (nd==0 && rootNav->parent()->section() == Entry::NAMESPACE_SEC )
3674           {
3675             //QCString nscope=removeAnonymousScopes(rootNav->parent()->name());
3676             QCString nscope=rootNav->parent()->name();
3677             if (!nscope.isEmpty())
3678             {
3679               nd = getResolvedNamespace(nscope);
3680             }
3681           }
3682
3683           if (!scope.isEmpty())
3684           {
3685             QCString sep = getLanguageSpecificSeparator(root->lang);
3686             if (sep!="::")
3687             {
3688               scope = substitute(scope,"::",sep);
3689             }
3690             scope+=sep;
3691           }
3692
3693           QCString def;
3694           if (!root->type.isEmpty())
3695           {
3696             if (root->argList)
3697             {
3698               def=root->type+" "+scope+name;
3699             }
3700             else
3701             {
3702               def=root->type+" "+scope+name+root->args;
3703             }
3704           }
3705           else
3706           {
3707             if (root->argList)
3708             {
3709               def=scope+name.copy();
3710             }
3711             else
3712             {
3713               def=scope+name+root->args;
3714             }
3715           }
3716           Debug::print(Debug::Functions,0,
3717                      "  Global Function:\n"
3718                      "    `%s' `%s'::`%s' `%s' proto=%d\n"
3719                      "    def=`%s'\n",
3720                      root->type.data(),
3721                      rootNav->parent()->name().data(),
3722                      rname.data(),
3723                      root->args.data(),
3724                      root->proto,
3725                      def.data()
3726                     );
3727           md->setDefinition(def);
3728           md->enableCallGraph(root->callGraph);
3729           md->enableCallerGraph(root->callerGraph);
3730           //if (root->mGrpId!=-1) 
3731           //{
3732           //  md->setMemberGroup(memberGroupDict[root->mGrpId]);
3733           //}
3734
3735           md->setRefItems(root->sli);
3736           if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@')
3737           {
3738             // add member to namespace
3739             md->setNamespace(nd);
3740             nd->insertMember(md); 
3741           }
3742           if (fd)
3743           {
3744             // add member to the file (we do this even if we have already
3745             // inserted it into the namespace)
3746             md->setFileDef(fd); 
3747             fd->insertMember(md);
3748           }
3749
3750           // add member to the list of file members
3751           //printf("Adding member=%s\n",md->name().data());
3752           MemberName *mn;
3753           if ((mn=Doxygen::functionNameSDict->find(name)))
3754           {
3755             mn->append(md);
3756           }
3757           else 
3758           {
3759             mn = new MemberName(name);
3760             mn->append(md);
3761             Doxygen::functionNameSDict->append(name,mn);
3762           }
3763           addMemberToGroups(root,md);
3764           if (root->relatesType == Simple) // if this is a relatesalso command,
3765                                            // allow find Member to pick it up
3766           {
3767             rootNav->changeSection(Entry::EMPTY_SEC); // Otherwise we have finished 
3768                                                       // with this entry.
3769
3770           }
3771         }
3772         else
3773         {
3774           FileDef *fd=rootNav->fileDef();
3775           if (fd)
3776           {
3777             // add member to the file (we do this even if we have already
3778             // inserted it into the namespace)
3779             fd->insertMember(md);
3780           }
3781         }
3782
3783         //printf("unrelated function %d `%s' `%s' `%s'\n",
3784         //    root->parent->section,root->type.data(),rname.data(),root->args.data());
3785       }
3786       else
3787       {
3788           Debug::print(Debug::Functions,0,"  --> %s not processed!\n",rname.data());
3789       }
3790     }
3791     else if (rname.isEmpty())
3792     {
3793         warn(root->fileName,root->startLine,
3794              "Illegal member name found."
3795             );
3796     }
3797
3798     rootNav->releaseEntry();
3799   }
3800   RECURSE_ENTRYTREE(buildFunctionList,rootNav);
3801 }
3802
3803 //----------------------------------------------------------------------
3804
3805 static void findFriends()
3806 {
3807   //printf("findFriends()\n");
3808   MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict);
3809   MemberName *fn;
3810   for (;(fn=fnli.current());++fnli) // for each global function name
3811   {
3812     //printf("Function name=`%s'\n",fn->memberName());
3813     MemberName *mn;
3814     if ((mn=Doxygen::memberNameSDict->find(fn->memberName())))
3815     { // there are members with the same name
3816       //printf("Function name is also a member name\n");
3817       MemberNameIterator fni(*fn);
3818       MemberDef *fmd;
3819       for (;(fmd=fni.current());++fni) // for each function with that name
3820       {
3821         MemberNameIterator mni(*mn);
3822         MemberDef *mmd;
3823         for (;(mmd=mni.current());++mni) // for each member with that name
3824         {
3825           //printf("Checking for matching arguments 
3826           //        mmd->isRelated()=%d mmd->isFriend()=%d mmd->isFunction()=%d\n",
3827           //    mmd->isRelated(),mmd->isFriend(),mmd->isFunction());
3828           ArgumentList *mmdAl = mmd->argumentList();
3829           ArgumentList *fmdAl = fmd->argumentList();
3830           if ((mmd->isFriend() || (mmd->isRelated() && mmd->isFunction())) &&
3831               matchArguments2(mmd->getOuterScope(), mmd->getFileDef(), mmdAl,
3832                               fmd->getOuterScope(), fmd->getFileDef(), fmdAl,
3833                               TRUE
3834                              )
3835                              
3836              ) // if the member is related and the arguments match then the 
3837                // function is actually a friend.
3838           {
3839             mergeArguments(mmdAl,fmdAl);
3840             if (!fmd->documentation().isEmpty())
3841             {
3842               mmd->setDocumentation(fmd->documentation(),fmd->docFile(),fmd->docLine());
3843             }
3844             else if (!mmd->documentation().isEmpty())
3845             {
3846               fmd->setDocumentation(mmd->documentation(),mmd->docFile(),mmd->docLine());
3847             }
3848             if (mmd->briefDescription().isEmpty() && !fmd->briefDescription().isEmpty())
3849             {
3850               mmd->setBriefDescription(fmd->briefDescription(),fmd->briefFile(),fmd->briefLine());
3851             }
3852             else if (!mmd->briefDescription().isEmpty() && !fmd->briefDescription().isEmpty())
3853             {
3854               fmd->setBriefDescription(mmd->briefDescription(),mmd->briefFile(),mmd->briefLine());
3855             }
3856             if (!fmd->inbodyDocumentation().isEmpty())
3857             {
3858               mmd->setInbodyDocumentation(fmd->inbodyDocumentation(),fmd->inbodyFile(),fmd->inbodyLine());
3859             }
3860             else if (!mmd->inbodyDocumentation().isEmpty())
3861             {
3862               fmd->setInbodyDocumentation(mmd->inbodyDocumentation(),mmd->inbodyFile(),mmd->inbodyLine());
3863             }
3864             //printf("body mmd %d fmd %d\n",mmd->getStartBodyLine(),fmd->getStartBodyLine());
3865             if (mmd->getStartBodyLine()==-1 && fmd->getStartBodyLine()!=-1)
3866             {
3867               mmd->setBodySegment(fmd->getStartBodyLine(),fmd->getEndBodyLine());
3868               mmd->setBodyDef(fmd->getBodyDef());
3869               //mmd->setBodyMember(fmd);
3870             }
3871             else if (mmd->getStartBodyLine()!=-1 && fmd->getStartBodyLine()==-1)
3872             {
3873               fmd->setBodySegment(mmd->getStartBodyLine(),mmd->getEndBodyLine());
3874               fmd->setBodyDef(mmd->getBodyDef());
3875               //fmd->setBodyMember(mmd);
3876             }
3877             mmd->setDocsForDefinition(fmd->isDocsForDefinition());
3878
3879             mmd->enableCallGraph(mmd->hasCallGraph() || fmd->hasCallGraph());
3880             mmd->enableCallerGraph(mmd->hasCallerGraph() || fmd->hasCallerGraph());
3881             fmd->enableCallGraph(mmd->hasCallGraph() || fmd->hasCallGraph());
3882             fmd->enableCallerGraph(mmd->hasCallerGraph() || fmd->hasCallerGraph());
3883           }
3884         }
3885       }
3886     }
3887   }
3888 }
3889
3890 //----------------------------------------------------------------------
3891
3892 static void transferFunctionDocumentation()
3893 {
3894   //printf("---- transferFunctionDocumentation()\n");
3895
3896   // find matching function declaration and definitions.
3897   MemberNameSDict::Iterator mnli(*Doxygen::functionNameSDict);
3898   MemberName *mn;
3899   for (;(mn=mnli.current());++mnli)
3900   {
3901     //printf("memberName=%s count=%d\n",mn->memberName(),mn->count());
3902     MemberDef *mdef=0,*mdec=0;
3903     MemberNameIterator mni1(*mn);
3904     /* find a matching function declaration and definition for this function */
3905     for (;(mdec=mni1.current());++mni1)
3906     {
3907       if (mdec->isPrototype() ||
3908           (mdec->isVariable() && mdec->isExternal()) 
3909          )
3910       {
3911         MemberNameIterator mni2(*mn);
3912         for (;(mdef=mni2.current());++mni2)
3913         {
3914           combineDeclarationAndDefinition(mdec,mdef);
3915         }
3916       }
3917     }
3918   }
3919 }
3920
3921 //----------------------------------------------------------------------
3922
3923 static void transferFunctionReferences()
3924 {
3925   MemberNameSDict::Iterator mnli(*Doxygen::functionNameSDict);
3926   MemberName *mn;
3927   for (;(mn=mnli.current());++mnli)
3928   {
3929     MemberDef *md,*mdef=0,*mdec=0;
3930     MemberNameIterator mni(*mn);
3931     /* find a matching function declaration and definition for this function */
3932     for (;(md=mni.current());++mni)
3933     {
3934       if (md->isPrototype()) 
3935         mdec=md;
3936       else if (md->isVariable() && md->isExternal()) 
3937         mdec=md;
3938       
3939       if (md->isFunction() && !md->isStatic() && !md->isPrototype()) 
3940         mdef=md;
3941       else if (md->isVariable() && !md->isExternal() && !md->isStatic())
3942         mdef=md;
3943     }
3944     if (mdef && mdec)
3945     {
3946       ArgumentList *mdefAl = mdef->argumentList();
3947       ArgumentList *mdecAl = mdec->argumentList();
3948       if (
3949           matchArguments2(mdef->getOuterScope(),mdef->getFileDef(),mdefAl,
3950                           mdec->getOuterScope(),mdec->getFileDef(),mdecAl,
3951                           TRUE
3952             )
3953          ) /* match found */
3954       {
3955         MemberSDict *defDict = mdef->getReferencesMembers();
3956         MemberSDict *decDict = mdec->getReferencesMembers();
3957         if (defDict!=0)
3958         {
3959           MemberSDict::IteratorDict msdi(*defDict);
3960           MemberDef *rmd;
3961           for (msdi.toFirst();(rmd=msdi.current());++msdi)
3962           {
3963             if (decDict==0 || decDict->find(rmd->name())==0)
3964             {
3965               mdec->addSourceReferences(rmd);
3966             }
3967           }
3968         }
3969         if (decDict!=0)
3970         {
3971           MemberSDict::IteratorDict msdi(*decDict);
3972           MemberDef *rmd;
3973           for (msdi.toFirst();(rmd=msdi.current());++msdi)
3974           {
3975             if (defDict==0 || defDict->find(rmd->name())==0)
3976             {
3977               mdef->addSourceReferences(rmd);
3978             }
3979           }
3980         }
3981
3982         defDict = mdef->getReferencedByMembers();
3983         decDict = mdec->getReferencedByMembers();
3984         if (defDict!=0)
3985         {
3986           MemberSDict::IteratorDict msdi(*defDict);
3987           MemberDef *rmd;
3988           for (msdi.toFirst();(rmd=msdi.current());++msdi)
3989           {
3990             if (decDict==0 || decDict->find(rmd->name())==0)
3991             {
3992               mdec->addSourceReferencedBy(rmd);
3993             }
3994           }
3995         }
3996         if (decDict!=0)
3997         {
3998           MemberSDict::IteratorDict msdi(*decDict);
3999           MemberDef *rmd;
4000           for (msdi.toFirst();(rmd=msdi.current());++msdi)
4001           {
4002             if (defDict==0 || defDict->find(rmd->name())==0)
4003             {
4004               mdef->addSourceReferencedBy(rmd);
4005             }
4006           }
4007         }
4008       }
4009     }
4010   }
4011 }
4012
4013 //----------------------------------------------------------------------
4014
4015 static void transferRelatedFunctionDocumentation()
4016 {
4017   // find match between function declaration and definition for 
4018   // related functions
4019   MemberNameSDict::Iterator mnli(*Doxygen::functionNameSDict);
4020   MemberName *mn;
4021   for (mnli.toFirst();(mn=mnli.current());++mnli)
4022   {
4023     MemberDef *md;
4024     MemberNameIterator mni(*mn);
4025     /* find a matching function declaration and definition for this function */
4026     for (mni.toFirst();(md=mni.current());++mni) // for each global function
4027     {
4028       //printf("  Function `%s'\n",md->name().data());
4029       MemberName *rmn;
4030       if ((rmn=Doxygen::memberNameSDict->find(md->name()))) // check if there is a member with the same name
4031       {
4032         //printf("  Member name found\n");
4033         MemberDef *rmd;
4034         MemberNameIterator rmni(*rmn);
4035         for (rmni.toFirst();(rmd=rmni.current());++rmni) // for each member with the same name
4036         {
4037           ArgumentList *mdAl = md->argumentList();
4038           ArgumentList *rmdAl = rmd->argumentList();
4039           //printf("  Member found: related=`%d'\n",rmd->isRelated());
4040           if ((rmd->isRelated() || rmd->isForeign()) && // related function
4041               matchArguments2( md->getOuterScope(), md->getFileDef(), mdAl,
4042                               rmd->getOuterScope(),rmd->getFileDef(),rmdAl,
4043                               TRUE
4044                              )
4045              )
4046           {
4047             //printf("  Found related member `%s'\n",md->name().data());
4048             if (rmd->relatedAlso())
4049               md->setRelatedAlso(rmd->relatedAlso());
4050             else if (rmd->isForeign())
4051               md->makeForeign();
4052             else
4053               md->makeRelated();
4054           } 
4055         }
4056       } 
4057     }
4058   }
4059 }
4060
4061 //----------------------------------------------------------------------
4062
4063 /*! make a dictionary of all template arguments of class cd
4064  * that are part of the base class name. 
4065  * Example: A template class A with template arguments <R,S,T> 
4066  * that inherits from B<T,T,S> will have T and S in the dictionary.
4067  */
4068 static QDict<int> *getTemplateArgumentsInName(ArgumentList *templateArguments,const QCString &name)
4069 {
4070   QDict<int> *templateNames = new QDict<int>(17);
4071   templateNames->setAutoDelete(TRUE);
4072   static QRegExp re("[a-z_A-Z][a-z_A-Z0-9:]*");
4073   if (templateArguments)
4074   {
4075     ArgumentListIterator ali(*templateArguments);
4076     Argument *arg;
4077     int count=0;
4078     for (ali.toFirst();(arg=ali.current());++ali,count++)
4079     {
4080       int i,p=0,l;
4081       while ((i=re.match(name,p,&l))!=-1)
4082       {
4083         QCString n = name.mid(i,l);
4084         if (n==arg->name)
4085         {
4086           if (templateNames->find(n)==0)
4087           {
4088             templateNames->insert(n,new int(count));
4089           }
4090         }
4091         p=i+l;
4092       }
4093     }
4094   }
4095   return templateNames;
4096 }
4097
4098 /*! Searches a class from within \a context and \a cd and returns its
4099  *  definition if found (otherwise 0 is returned).
4100  */
4101 static ClassDef *findClassWithinClassContext(Definition *context,ClassDef *cd,const QCString &name)
4102 {
4103   FileDef *fd=cd->getFileDef();
4104   ClassDef *result=0;
4105   if (context && cd!=context)
4106   {
4107     result = getResolvedClass(context,0,name,0,0,TRUE,TRUE);
4108   }
4109   if (result==0)
4110   {
4111     result = getResolvedClass(cd,fd,name,0,0,TRUE,TRUE);
4112   }
4113   if (result==0) // try direct class, needed for namespaced classes imported via tag files (see bug624095)
4114   {
4115     result = getClass(name);
4116   }
4117   if (result==0 && cd &&
4118       (cd->getLanguage()==SrcLangExt_CSharp || cd->getLanguage()==SrcLangExt_Java) &&
4119       name.find('<')!=-1)
4120   {
4121     result = Doxygen::genericsDict->find(name);
4122   }
4123   //printf("** Trying to find %s within context %s class %s result=%s lookup=%p\n",
4124   //       name.data(),
4125   //       context ? context->name().data() : "<none>",
4126   //       cd      ? cd->name().data()      : "<none>",
4127   //       result  ? result->name().data()  : "<none>",
4128   //       Doxygen::classSDict->find(name)
4129   //      );
4130   return result;
4131 }
4132
4133
4134 static void findUsedClassesForClass(EntryNav *rootNav,
4135                            Definition *context,
4136                            ClassDef *masterCd,
4137                            ClassDef *instanceCd,
4138                            bool isArtificial,
4139                            ArgumentList *actualArgs=0,
4140                            QDict<int> *templateNames=0
4141                            )
4142 {
4143   masterCd->visited=TRUE;
4144   ArgumentList *formalArgs = masterCd->templateArguments();
4145   if (masterCd->memberNameInfoSDict())
4146   {
4147     MemberNameInfoSDict::Iterator mnili(*masterCd->memberNameInfoSDict());
4148     MemberNameInfo *mni;
4149     for (;(mni=mnili.current());++mnili)
4150     {
4151       MemberNameInfoIterator mnii(*mni);
4152       MemberInfo *mi;
4153       for (mnii.toFirst();(mi=mnii.current());++mnii)
4154       {
4155         MemberDef *md=mi->memberDef;
4156         if (md->isVariable() || md->isObjCProperty()) // for each member variable in this class
4157         {
4158           //printf("    Found variable %s in class %s\n",md->name().data(),masterCd->name().data());
4159           QCString type = normalizeNonTemplateArgumentsInString(md->typeString(),masterCd,formalArgs);
4160           QCString typedefValue = resolveTypeDef(masterCd,type);
4161           if (!typedefValue.isEmpty())
4162           {
4163             type = typedefValue;
4164           }
4165           int pos=0;
4166           QCString usedClassName;
4167           QCString templSpec;
4168           bool found=FALSE;
4169           // the type can contain template variables, replace them if present
4170           if (actualArgs)
4171           {
4172             type = substituteTemplateArgumentsInString(type,formalArgs,actualArgs);
4173           }
4174
4175           //printf("      template substitution gives=%s\n",type.data());
4176           while (!found && extractClassNameFromType(type,pos,usedClassName,templSpec,rootNav->lang())!=-1)
4177           {
4178             // find the type (if any) that matches usedClassName
4179             ClassDef *typeCd = getResolvedClass(masterCd,
4180                 masterCd->getFileDef(),
4181                 usedClassName,
4182                 0,0,
4183                 FALSE,TRUE
4184                 );
4185             //printf("====>  usedClassName=%s -> typeCd=%s\n",
4186             //     usedClassName.data(),typeCd?typeCd->name().data():"<none>");
4187             if (typeCd)
4188             {
4189               usedClassName = typeCd->name();
4190             }
4191
4192             int sp=usedClassName.find('<');
4193             if (sp==-1) sp=0;
4194             int si=usedClassName.findRev("::",sp);
4195             if (si!=-1)
4196             {
4197               // replace any namespace aliases
4198               replaceNamespaceAliases(usedClassName,si);
4199             }
4200             // add any template arguments to the class
4201             QCString usedName = removeRedundantWhiteSpace(usedClassName+templSpec);
4202             //printf("    usedName=%s\n",usedName.data());
4203
4204             bool delTempNames=FALSE;
4205             if (templateNames==0)
4206             {
4207               templateNames = getTemplateArgumentsInName(formalArgs,usedName);
4208               delTempNames=TRUE;
4209             }
4210             BaseInfo bi(usedName,Public,Normal);
4211             findClassRelation(rootNav,context,instanceCd,&bi,templateNames,TemplateInstances,isArtificial);
4212
4213             if (masterCd->templateArguments())
4214             {
4215               ArgumentListIterator ali(*masterCd->templateArguments());
4216               Argument *arg;
4217               int count=0;
4218               for (ali.toFirst();(arg=ali.current());++ali,++count)
4219               {
4220                 if (arg->name==usedName) // type is a template argument
4221                 {
4222                   found=TRUE;
4223                   Debug::print(Debug::Classes,0,"    New used class `%s'\n", usedName.data());
4224
4225                   ClassDef *usedCd = Doxygen::hiddenClasses->find(usedName);
4226                   if (usedCd==0)
4227                   {
4228                     usedCd = new ClassDef(
4229                         masterCd->getDefFileName(),masterCd->getDefLine(),
4230                         masterCd->getDefColumn(),
4231                         usedName,
4232                         ClassDef::Class);
4233                     //printf("making %s a template argument!!!\n",usedCd->name().data());
4234                     usedCd->makeTemplateArgument();
4235                     usedCd->setUsedOnly(TRUE);
4236                     usedCd->setLanguage(masterCd->getLanguage());
4237                     Doxygen::hiddenClasses->append(usedName,usedCd);
4238                   }
4239                   if (usedCd)
4240                   {
4241                     if (isArtificial) usedCd->setArtificial(TRUE);
4242                     Debug::print(Debug::Classes,0,"      Adding used class `%s' (1)\n", usedCd->name().data());
4243                     instanceCd->addUsedClass(usedCd,md->name(),md->protection());
4244                     usedCd->addUsedByClass(instanceCd,md->name(),md->protection());
4245                   }
4246                 }
4247               }
4248             }
4249
4250             if (!found)
4251             {
4252               ClassDef *usedCd=findClassWithinClassContext(context,masterCd,usedName);
4253               //printf("Looking for used class %s: result=%s master=%s\n",
4254               //    usedName.data(),usedCd?usedCd->name().data():"<none>",masterCd?masterCd->name().data():"<none>");
4255
4256               if (usedCd) 
4257               {
4258                 found=TRUE;
4259                 Debug::print(Debug::Classes,0,"    Adding used class `%s' (2)\n", usedCd->name().data());
4260                 instanceCd->addUsedClass(usedCd,md->name(),md->protection()); // class exists 
4261                 usedCd->addUsedByClass(instanceCd,md->name(),md->protection());
4262               }
4263             }
4264             if (delTempNames)
4265             {
4266               delete templateNames;
4267               templateNames=0;
4268             }
4269           }
4270           if (!found && !type.isEmpty()) // used class is not documented in any scope
4271           {
4272             ClassDef *usedCd = Doxygen::hiddenClasses->find(type);
4273             if (usedCd==0 && !Config_getBool("HIDE_UNDOC_RELATIONS"))
4274             {
4275               if (type.right(2)=="(*" || type.right(2)=="(^") // type is a function pointer
4276               {
4277                 type+=md->argsString();
4278               }
4279               Debug::print(Debug::Classes,0,"  New undocumented used class `%s'\n", type.data());
4280               usedCd = new ClassDef(
4281                   masterCd->getDefFileName(),masterCd->getDefLine(),
4282                   masterCd->getDefColumn(),
4283                   type,ClassDef::Class);
4284               usedCd->setUsedOnly(TRUE);
4285               usedCd->setLanguage(masterCd->getLanguage());
4286               Doxygen::hiddenClasses->append(type,usedCd);
4287             }
4288             if (usedCd)
4289             {
4290               if (isArtificial) usedCd->setArtificial(TRUE);
4291               Debug::print(Debug::Classes,0,"    Adding used class `%s' (3)\n", usedCd->name().data());
4292               instanceCd->addUsedClass(usedCd,md->name(),md->protection()); 
4293               usedCd->addUsedByClass(instanceCd,md->name(),md->protection());
4294             }
4295           }
4296         }
4297       }
4298     }
4299   }
4300   else
4301   {
4302     //printf("no members for class %s (%p)\n",masterCd->name().data(),masterCd);
4303   }
4304 }
4305
4306 static void findBaseClassesForClass(
4307       EntryNav *rootNav,
4308       Definition *context,
4309       ClassDef *masterCd,
4310       ClassDef *instanceCd,
4311       FindBaseClassRelation_Mode mode,
4312       bool isArtificial,
4313       ArgumentList *actualArgs=0,
4314       QDict<int> *templateNames=0
4315     )
4316 {
4317   Entry *root = rootNav->entry();
4318   //if (masterCd->visited) return;
4319   masterCd->visited=TRUE;
4320   // The base class could ofcouse also be a non-nested class
4321   ArgumentList *formalArgs = masterCd->templateArguments();
4322   QListIterator<BaseInfo> bii(*root->extends);
4323   BaseInfo *bi=0;
4324   for (bii.toFirst();(bi=bii.current());++bii)
4325   {
4326     //printf("masterCd=%s bi->name='%s' #actualArgs=%d\n",
4327     //    masterCd->localName().data(),bi->name.data(),actualArgs?(int)actualArgs->count():-1);
4328     bool delTempNames=FALSE;
4329     if (templateNames==0)
4330     {
4331       templateNames = getTemplateArgumentsInName(formalArgs,bi->name);
4332       delTempNames=TRUE;
4333     }
4334     BaseInfo tbi(bi->name,bi->prot,bi->virt);
4335     if (actualArgs) // substitute the formal template arguments of the base class
4336     {
4337       tbi.name = substituteTemplateArgumentsInString(bi->name,formalArgs,actualArgs);
4338     }
4339     //printf("bi->name=%s tbi.name=%s\n",bi->name.data(),tbi.name.data());
4340
4341     if (mode==DocumentedOnly)
4342     {
4343       // find a documented base class in the correct scope
4344       if (!findClassRelation(rootNav,context,instanceCd,&tbi,templateNames,DocumentedOnly,isArtificial))
4345       {
4346         // 1.8.2: decided to show inheritance relations even if not documented,
4347         //        we do make them artificial, so they do not appear in the index
4348         //if (!Config_getBool("HIDE_UNDOC_RELATIONS")) 
4349         bool b = Config_getBool("HIDE_UNDOC_RELATIONS") ? TRUE : isArtificial;
4350         //{
4351           // no documented base class -> try to find an undocumented one
4352           findClassRelation(rootNav,context,instanceCd,&tbi,templateNames,Undocumented,b);
4353         //}
4354       }
4355     }
4356     else if (mode==TemplateInstances)
4357     {
4358       findClassRelation(rootNav,context,instanceCd,&tbi,templateNames,TemplateInstances,isArtificial);
4359     }
4360     if (delTempNames)
4361     {
4362       delete templateNames;
4363       templateNames=0;
4364     }  
4365   }
4366 }
4367
4368 //----------------------------------------------------------------------
4369
4370 static bool findTemplateInstanceRelation(Entry *root,
4371             Definition *context,
4372             ClassDef *templateClass,const QCString &templSpec,
4373             QDict<int> *templateNames,
4374             bool isArtificial)
4375 {
4376   Debug::print(Debug::Classes,0,"    derived from template %s with parameters %s\n",
4377          templateClass->name().data(),templSpec.data());
4378   //printf("findTemplateInstanceRelation(base=%s templSpec=%s templateNames=",
4379   //    templateClass->name().data(),templSpec.data());
4380   //if (templateNames)
4381   //{
4382   //  QDictIterator<int> qdi(*templateNames);
4383   //  int *tempArgIndex;
4384   //  for (;(tempArgIndex=qdi.current());++qdi)
4385   //  {
4386   //    printf("(%s->%d) ",qdi.currentKey(),*tempArgIndex);
4387   //  }
4388   //}
4389   //printf("\n");
4390   
4391   bool existingClass = (templSpec ==
4392                         tempArgListToString(templateClass->templateArguments())
4393                        );
4394   if (existingClass) return TRUE;
4395
4396   bool freshInstance=FALSE;
4397   ClassDef *instanceClass = templateClass->insertTemplateInstance(
4398                      root->fileName,root->startLine,root->startColumn,templSpec,freshInstance);
4399   if (isArtificial) instanceClass->setArtificial(TRUE);
4400   instanceClass->setLanguage(root->lang);
4401
4402   if (freshInstance)
4403   {
4404     Debug::print(Debug::Classes,0,"      found fresh instance '%s'!\n",instanceClass->name().data());
4405     Doxygen::classSDict->append(instanceClass->name(),instanceClass);
4406     instanceClass->setTemplateBaseClassNames(templateNames);
4407
4408     // search for new template instances caused by base classes of 
4409     // instanceClass 
4410     EntryNav *templateRootNav = g_classEntries.find(templateClass->name());
4411     if (templateRootNav)
4412     {
4413       bool unloadNeeded=FALSE;
4414       Entry *templateRoot = templateRootNav->entry();
4415       if (templateRoot==0) // not yet loaded
4416       {
4417         templateRootNav->loadEntry(g_storage);
4418         templateRoot = templateRootNav->entry();
4419         ASSERT(templateRoot!=0); // now it should really be loaded
4420         unloadNeeded=TRUE;
4421       }
4422
4423       Debug::print(Debug::Classes,0,"        template root found %s templSpec=%s!\n",
4424           templateRoot->name.data(),templSpec.data());
4425       ArgumentList *templArgs = new ArgumentList;
4426       stringToArgumentList(templSpec,templArgs);
4427       findBaseClassesForClass(templateRootNav,context,templateClass,instanceClass,
4428           TemplateInstances,isArtificial,templArgs,templateNames);
4429
4430       findUsedClassesForClass(templateRootNav,context,templateClass,instanceClass,
4431           isArtificial,templArgs,templateNames);
4432       delete templArgs;
4433
4434       if (unloadNeeded) // still cleanup to do
4435       {
4436         templateRootNav->releaseEntry();
4437       }
4438     }
4439     else
4440     {
4441       Debug::print(Debug::Classes,0,"        no template root entry found!\n");
4442       // TODO: what happened if we get here?
4443     }
4444
4445     //Debug::print(Debug::Classes,0,"    Template instance %s : \n",instanceClass->name().data());
4446     //ArgumentList *tl = templateClass->templateArguments();
4447   }
4448   else
4449   {
4450     Debug::print(Debug::Classes,0,"      instance already exists!\n");
4451   }
4452   return TRUE;
4453 }
4454
4455 static bool isRecursiveBaseClass(const QCString &scope,const QCString &name)
4456 {
4457   QCString n=name;
4458   int index=n.find('<');
4459   if (index!=-1)
4460   {
4461     n=n.left(index);
4462   }
4463   bool result = rightScopeMatch(scope,n);
4464   return result;
4465 }
4466
4467 /*! Searches for the end of a template in prototype \a s starting from
4468  *  character position \a startPos. If the end was found the position
4469  *  of the closing \> is returned, otherwise -1 is returned.
4470  *
4471  *  Handles exotic cases such as 
4472  *  \code
4473  *    Class<(id<0)>
4474  *    Class<bits<<2>
4475  *    Class<"<">
4476  *    Class<'<'>
4477  *    Class<(")<")>
4478  *  \endcode
4479  */
4480 static int findEndOfTemplate(const QCString &s,int startPos)
4481 {
4482   // locate end of template
4483   int e=startPos;
4484   int brCount=1;
4485   int roundCount=0;
4486   int len = s.length();
4487   bool insideString=FALSE;
4488   bool insideChar=FALSE;
4489   char pc = 0;
4490   while (e<len && brCount!=0)
4491   {
4492     char c=s.at(e);
4493     switch(c)
4494     {
4495       case '<': 
4496         if (!insideString && !insideChar)
4497         {
4498           if (e<len-1 && s.at(e+1)=='<') 
4499             e++; 
4500           else if (roundCount==0)
4501             brCount++;
4502         }
4503         break;
4504       case '>':
4505         if (!insideString && !insideChar)
4506         {
4507           if (e<len-1 && s.at(e+1)=='>') 
4508             e++; 
4509           else if (roundCount==0)
4510             brCount--;
4511         }
4512         break;
4513       case '(':
4514         if (!insideString && !insideChar) 
4515           roundCount++;
4516         break;
4517       case ')':
4518         if (!insideString && !insideChar) 
4519           roundCount--;
4520         break;
4521       case '"':
4522         if (!insideChar)
4523         {
4524           if (insideString && pc!='\\') 
4525             insideString=FALSE;
4526           else
4527             insideString=TRUE;
4528         }
4529         break;
4530       case '\'':
4531         if (!insideString)
4532         {
4533           if (insideChar && pc!='\\')
4534             insideChar=FALSE;
4535           else
4536             insideChar=TRUE;
4537         }
4538         break;
4539     }
4540     pc = c;
4541     e++;
4542   }
4543   return brCount==0 ? e : -1;
4544 }
4545
4546 static bool findClassRelation(
4547                            EntryNav *rootNav,
4548                            Definition *context,
4549                            ClassDef *cd,
4550                            BaseInfo *bi,
4551                            QDict<int> *templateNames,
4552                            FindBaseClassRelation_Mode mode,
4553                            bool isArtificial
4554                           )
4555 {
4556   //printf("findClassRelation(class=%s base=%s templateNames=",
4557   //    cd->name().data(),bi->name.data());
4558   //if (templateNames)
4559   //{
4560   //  QDictIterator<int> qdi(*templateNames);
4561   //  int *tempArgIndex;
4562   //  for (;(tempArgIndex=qdi.current());++qdi)
4563   //  {
4564   //    printf("(%s->%d) ",qdi.currentKey(),*tempArgIndex);
4565   //  }
4566   //}
4567   //printf("\n");
4568
4569   Entry *root = rootNav->entry();
4570
4571   QCString biName=bi->name;
4572   bool explicitGlobalScope=FALSE;
4573   //printf("findClassRelation: biName=`%s'\n",biName.data());
4574   if (biName.left(2)=="::") // explicit global scope
4575   {
4576      biName=biName.right(biName.length()-2);
4577      explicitGlobalScope=TRUE;
4578   }
4579
4580   EntryNav *parentNode=rootNav->parent();
4581   bool lastParent=FALSE;
4582   do // for each parent scope, starting with the largest scope 
4583      // (in case of nested classes)
4584   {
4585     QCString scopeName= parentNode ? parentNode->name().data() : "";
4586     int scopeOffset=explicitGlobalScope ? 0 : scopeName.length();
4587     do // try all parent scope prefixes, starting with the largest scope
4588     {
4589       //printf("scopePrefix=`%s' biName=`%s'\n",
4590       //    scopeName.left(scopeOffset).data(),biName.data());
4591
4592       QCString baseClassName=biName;
4593       if (scopeOffset>0)
4594       {
4595         baseClassName.prepend(scopeName.left(scopeOffset)+"::");
4596       }
4597       //QCString stripped;
4598       //baseClassName=stripTemplateSpecifiersFromScope
4599       //                    (removeRedundantWhiteSpace(baseClassName),TRUE,
4600       //                    &stripped);
4601       MemberDef *baseClassTypeDef=0;
4602       QCString templSpec;
4603       ClassDef *baseClass=getResolvedClass(explicitGlobalScope ? Doxygen::globalScope : context,
4604                                            cd->getFileDef(), 
4605                                            baseClassName,
4606                                            &baseClassTypeDef,
4607                                            &templSpec,
4608                                            mode==Undocumented,
4609                                            TRUE
4610                                           );
4611       //printf("baseClassName=%s baseClass=%p cd=%p explicitGlobalScope=%d\n",
4612       //    baseClassName.data(),baseClass,cd,explicitGlobalScope);
4613       //printf("    scope=`%s' baseClassName=`%s' baseClass=%s templSpec=%s\n",
4614       //                    cd ? cd->name().data():"<none>",
4615       //                    baseClassName.data(),
4616       //                    baseClass?baseClass->name().data():"<none>",
4617       //                    templSpec.data()
4618       //      );
4619       //if (baseClassName.left(root->name.length())!=root->name ||
4620       //    baseClassName.at(root->name.length())!='<'
4621       //   ) // Check for base class with the same name.
4622       //     // If found then look in the outer scope for a match
4623       //     // and prevent recursion.
4624       if (!isRecursiveBaseClass(rootNav->name(),baseClassName)
4625           || explicitGlobalScope
4626           // sadly isRecursiveBaseClass always true for UNO IDL ifc/svc members
4627           // (i.e. this is needed for addInterfaceOrServiceToServiceOrSingleton)
4628           || (rootNav->lang()==SrcLangExt_IDL &&
4629               (rootNav->section()==Entry::EXPORTED_INTERFACE_SEC ||
4630                rootNav->section()==Entry::INCLUDED_SERVICE_SEC)))
4631       {
4632         Debug::print(
4633             Debug::Classes,0,"    class relation %s inherited/used by %s found (%s and %s) templSpec='%s'\n",
4634             baseClassName.data(),
4635             rootNav->name().data(),
4636             (bi->prot==Private)?"private":((bi->prot==Protected)?"protected":"public"),
4637             (bi->virt==Normal)?"normal":"virtual",
4638             templSpec.data()
4639            );
4640
4641         int i=baseClassName.find('<');
4642         int si=baseClassName.findRev("::",i==-1 ? baseClassName.length() : i);
4643         if (si==-1) si=0;
4644         if (baseClass==0 && (root->lang==SrcLangExt_CSharp || root->lang==SrcLangExt_Java))
4645         {
4646           baseClass = Doxygen::genericsDict->find(baseClassName);
4647           //printf("looking for '%s' result=%p\n",baseClassName.data(),baseClass);
4648         }
4649         if (baseClass==0 && i!=-1) 
4650           // base class has template specifiers
4651         {
4652           // TODO: here we should try to find the correct template specialization
4653           // but for now, we only look for the unspecializated base class.
4654           int e=findEndOfTemplate(baseClassName,i+1);
4655           //printf("baseClass==0 i=%d e=%d\n",i,e);
4656           if (e!=-1) // end of template was found at e
4657           {
4658             templSpec=removeRedundantWhiteSpace(baseClassName.mid(i,e-i));
4659             baseClassName=baseClassName.left(i)+baseClassName.right(baseClassName.length()-e);
4660             baseClass=getResolvedClass(explicitGlobalScope ? Doxygen::globalScope : context,
4661                 cd->getFileDef(),
4662                 baseClassName,
4663                 &baseClassTypeDef,
4664                 0, //&templSpec,
4665                 mode==Undocumented,
4666                 TRUE
4667                 );
4668             //printf("baseClass=%p -> baseClass=%s templSpec=%s\n",
4669             //      baseClass,baseClassName.data(),templSpec.data());
4670           }
4671         }
4672         else if (baseClass && !templSpec.isEmpty()) // we have a known class, but also
4673                                                     // know it is a template, so see if
4674                                                     // we can also link to the explicit
4675                                                     // instance (for instance if a class
4676                                                     // derived from a template argument)
4677         {
4678           //printf("baseClass=%p templSpec=%s\n",baseClass,templSpec.data());
4679           ClassDef *templClass=getClass(baseClass->name()+templSpec);
4680           if (templClass)
4681           {
4682             // use the template instance instead of the template base.
4683             baseClass = templClass;
4684             templSpec.resize(0);
4685           }
4686         }
4687
4688         //printf("cd=%p baseClass=%p\n",cd,baseClass);
4689         bool found=baseClass!=0 && (baseClass!=cd || mode==TemplateInstances);
4690         //printf("1. found=%d\n",found);
4691         if (!found && si!=-1)
4692         {
4693           QCString tmpTemplSpec;
4694           // replace any namespace aliases
4695           replaceNamespaceAliases(baseClassName,si);
4696           baseClass=getResolvedClass(explicitGlobalScope ? Doxygen::globalScope : context,
4697                                      cd->getFileDef(),
4698                                      baseClassName,
4699                                      &baseClassTypeDef,
4700                                      &tmpTemplSpec,
4701                                      mode==Undocumented,
4702                                      TRUE
4703                                     );
4704           found=baseClass!=0 && baseClass!=cd;
4705           if (found) templSpec = tmpTemplSpec;
4706         }
4707         //printf("2. found=%d\n",found);
4708         
4709         //printf("root->name=%s biName=%s baseClassName=%s\n",
4710         //        root->name.data(),biName.data(),baseClassName.data());
4711         //if (cd->isCSharp() && i!=-1) // C# generic -> add internal -g postfix
4712         //{
4713         //  baseClassName+="-g";
4714         //}
4715
4716         if (!found)
4717         {
4718           baseClass=findClassWithinClassContext(context,cd,baseClassName);
4719           //printf("findClassWithinClassContext(%s,%s)=%p\n",
4720           //    cd->name().data(),baseClassName.data(),baseClass);
4721           found = baseClass!=0 && baseClass!=cd;
4722
4723         }
4724         if (!found)
4725         {
4726           // for PHP the "use A\B as C" construct map class C to A::B, so we lookup
4727           // the class name also in the alias mapping.
4728           QCString *aliasName = Doxygen::namespaceAliasDict[baseClassName];
4729           if (aliasName) // see if it is indeed a class.
4730           {
4731             baseClass=getClass(*aliasName);
4732             found = baseClass!=0 && baseClass!=cd;
4733           }
4734         }
4735         bool isATemplateArgument = templateNames!=0 && templateNames->find(biName)!=0;
4736         // make templSpec canonical
4737         // warning: the following line doesn't work for Mixin classes (see bug 560623)
4738         // templSpec = getCanonicalTemplateSpec(cd, cd->getFileDef(), templSpec);
4739
4740         //printf("3. found=%d\n",found);
4741         if (found)
4742         {
4743           Debug::print(Debug::Classes,0,"    Documented base class `%s' templSpec=%s\n",biName.data(),templSpec.isEmpty()?"":templSpec.data());
4744           // add base class to this class
4745
4746           // if templSpec is not empty then we should "instantiate"
4747           // the template baseClass. A new ClassDef should be created
4748           // to represent the instance. To be able to add the (instantiated)
4749           // members and documentation of a template class 
4750           // (inserted in that template class at a later stage), 
4751           // the template should know about its instances. 
4752           // the instantiation process, should be done in a recursive way, 
4753           // since instantiating a template may introduce new inheritance 
4754           // relations.
4755           if (!templSpec.isEmpty() && mode==TemplateInstances)
4756           {
4757             // if baseClass is actually a typedef then we should not
4758             // instantiate it, since typedefs are in a different namespace
4759             // see bug531637 for an example where this would otherwise hang
4760             // doxygen
4761             if (baseClassTypeDef==0)
4762             {
4763               //printf("       => findTemplateInstanceRelation: %p\n",baseClassTypeDef);
4764               findTemplateInstanceRelation(root,context,baseClass,templSpec,templateNames,isArtificial);
4765             }
4766           }
4767           else if (mode==DocumentedOnly || mode==Undocumented)
4768           {
4769             //printf("       => insert base class\n");
4770             QCString usedName;
4771             if (baseClassTypeDef || cd->isCSharp()) 
4772             {
4773               usedName=biName;
4774               //printf("***** usedName=%s templSpec=%s\n",usedName.data(),templSpec.data());
4775             }
4776             static bool sipSupport = Config_getBool("SIP_SUPPORT");
4777             if (sipSupport) bi->prot=Public;
4778             if (!cd->isSubClass(baseClass)) // check for recursion, see bug690787
4779             {
4780               cd->insertBaseClass(baseClass,usedName,bi->prot,bi->virt,templSpec);
4781               // add this class as super class to the base class
4782               baseClass->insertSubClass(cd,bi->prot,bi->virt,templSpec);
4783             }
4784             else
4785             {
4786               warn(root->fileName,root->startLine,
4787                   "Detected potential recursive class relation "
4788                   "between class %s and base class %s!",
4789                   cd->name().data(),baseClass->name().data()
4790                   );
4791             }
4792           }
4793           return TRUE;
4794         }
4795         else if (mode==Undocumented && (scopeOffset==0 || isATemplateArgument))
4796         {
4797           Debug::print(Debug::Classes,0,
4798                        "    New undocumented base class `%s' baseClassName=%s templSpec=%s isArtificial=%d\n",
4799                        biName.data(),baseClassName.data(),templSpec.data(),isArtificial
4800                       );
4801           baseClass=0;
4802           if (isATemplateArgument)
4803           {
4804             baseClass=Doxygen::hiddenClasses->find(baseClassName);
4805             if (baseClass==0)
4806             {
4807               baseClass=new ClassDef(root->fileName,root->startLine,root->startColumn,
4808                                  baseClassName,
4809                                  ClassDef::Class);
4810               Doxygen::hiddenClasses->append(baseClassName,baseClass);
4811               if (isArtificial) baseClass->setArtificial(TRUE);
4812               baseClass->setLanguage(root->lang);
4813             }
4814           }
4815           else
4816           {
4817             baseClass=Doxygen::classSDict->find(baseClassName);
4818             //printf("*** classDDict->find(%s)=%p biName=%s templSpec=%s\n",
4819             //    baseClassName.data(),baseClass,biName.data(),templSpec.data());
4820             if (baseClass==0)
4821             {
4822               baseClass=new ClassDef(root->fileName,root->startLine,root->startColumn,
4823                   baseClassName,
4824                   ClassDef::Class);
4825               Doxygen::classSDict->append(baseClassName,baseClass);
4826               if (isArtificial) baseClass->setArtificial(TRUE);
4827               baseClass->setLanguage(root->lang);
4828               int si = baseClassName.findRev("::");
4829               if (si!=-1) // class is nested
4830               {
4831                 Definition *sd = findScopeFromQualifiedName(Doxygen::globalScope,baseClassName.left(si),0,rootNav->tagInfo());
4832                 if (sd==0 || sd==Doxygen::globalScope) // outer scope not found
4833                 {
4834                   baseClass->setArtificial(TRUE); // see bug678139
4835                 }
4836               }
4837             }
4838           }
4839           if (biName.right(2)=="-p")
4840           {
4841             biName="<"+biName.left(biName.length()-2)+">";
4842           }
4843           // add base class to this class
4844           cd->insertBaseClass(baseClass,biName,bi->prot,bi->virt,templSpec);
4845           // add this class as super class to the base class
4846           baseClass->insertSubClass(cd,bi->prot,bi->virt,templSpec);
4847           // the undocumented base was found in this file
4848           baseClass->insertUsedFile(rootNav->fileDef());
4849           baseClass->setOuterScope(Doxygen::globalScope);
4850           if (baseClassName.right(2)=="-p")
4851           {
4852             baseClass->setCompoundType(ClassDef::Protocol);
4853           }
4854           return TRUE;
4855         }
4856         else
4857         {
4858           Debug::print(Debug::Classes,0,"    Base class `%s' not found\n",biName.data());
4859         }
4860       }
4861       else
4862       {
4863         if (mode!=TemplateInstances)
4864         {
4865           warn(root->fileName,root->startLine,
4866               "Detected potential recursive class relation "
4867               "between class %s and base class %s!\n",
4868               root->name.data(),baseClassName.data()
4869               );
4870         }
4871         // for mode==TemplateInstance this case is quite common and
4872         // indicates a relation between a template class and a template 
4873         // instance with the same name.
4874       }
4875       if (scopeOffset==0)
4876       {
4877         scopeOffset=-1;
4878       }
4879       else if ((scopeOffset=scopeName.findRev("::",scopeOffset-1))==-1)
4880       {
4881         scopeOffset=0;
4882       }
4883       //printf("new scopeOffset=`%d'",scopeOffset);
4884     } while (scopeOffset>=0);
4885
4886     if (parentNode==0)
4887     {
4888       lastParent=TRUE;
4889     }
4890     else
4891     {
4892       parentNode=parentNode->parent();
4893     }
4894   } while (lastParent);
4895
4896   return FALSE;
4897 }
4898
4899 //----------------------------------------------------------------------
4900 // Computes the base and super classes for each class in the tree
4901
4902 static bool isClassSection(EntryNav *rootNav)
4903 {
4904   if ( !rootNav->name().isEmpty() )
4905   {
4906     if (rootNav->section() & Entry::COMPOUND_MASK)
4907          // is it a compound (class, struct, union, interface ...)
4908     {
4909       return TRUE;
4910     }
4911     else if (rootNav->section() & Entry::COMPOUNDDOC_MASK) 
4912          // is it a documentation block with inheritance info.
4913     {
4914       rootNav->loadEntry(g_storage);
4915       Entry *root = rootNav->entry();
4916       bool extends = root->extends->count()>0;
4917       rootNav->releaseEntry(); 
4918       if (extends) return TRUE;
4919     }
4920   }
4921   return FALSE;
4922 }
4923
4924
4925 /*! Builds a dictionary of all entry nodes in the tree starting with \a root
4926  */
4927 static void findClassEntries(EntryNav *rootNav)
4928 {
4929   if (isClassSection(rootNav))
4930   {
4931     g_classEntries.insert(rootNav->name(),rootNav);
4932   }
4933   RECURSE_ENTRYTREE(findClassEntries,rootNav);
4934 }
4935
4936 /*! Using the dictionary build by findClassEntries(), this 
4937  *  function will look for additional template specialization that
4938  *  exists as inheritance relations only. These instances will be
4939  *  added to the template they are derived from.
4940  */
4941 static void findInheritedTemplateInstances()
4942 {
4943   ClassSDict::Iterator cli(*Doxygen::classSDict);
4944   for (cli.toFirst();cli.current();++cli) cli.current()->visited=FALSE;
4945   QDictIterator<EntryNav> edi(g_classEntries);
4946   EntryNav *rootNav;
4947   for (;(rootNav=edi.current());++edi)
4948   {
4949     ClassDef *cd;
4950     // strip any anonymous scopes first 
4951     QCString bName=stripAnonymousNamespaceScope(rootNav->name());
4952     bName=stripTemplateSpecifiersFromScope(bName);
4953     Debug::print(Debug::Classes,0,"  Inheritance: Class %s : \n",bName.data());
4954     if ((cd=getClass(bName)))
4955     {
4956       rootNav->loadEntry(g_storage);
4957       //printf("Class %s %d\n",cd->name().data(),root->extends->count());
4958       findBaseClassesForClass(rootNav,cd,cd,cd,TemplateInstances,FALSE);
4959       rootNav->releaseEntry();
4960     }
4961   }
4962 }
4963
4964 static void findUsedTemplateInstances()
4965 {
4966   ClassSDict::Iterator cli(*Doxygen::classSDict);
4967   for (cli.toFirst();cli.current();++cli) cli.current()->visited=FALSE;
4968   QDictIterator<EntryNav> edi(g_classEntries);
4969   EntryNav *rootNav;
4970   for (;(rootNav=edi.current());++edi)
4971   {
4972     ClassDef *cd;
4973     // strip any anonymous scopes first 
4974     QCString bName=stripAnonymousNamespaceScope(rootNav->name());
4975     bName=stripTemplateSpecifiersFromScope(bName);
4976     Debug::print(Debug::Classes,0,"  Usage: Class %s : \n",bName.data());
4977     if ((cd=getClass(bName)))
4978     {
4979       rootNav->loadEntry(g_storage);
4980       findUsedClassesForClass(rootNav,cd,cd,cd,TRUE);
4981       rootNav->releaseEntry();
4982     }
4983   }
4984 }
4985
4986 static void computeClassRelations()
4987 {
4988   ClassSDict::Iterator cli(*Doxygen::classSDict);
4989   for (cli.toFirst();cli.current();++cli) cli.current()->visited=FALSE;
4990   QDictIterator<EntryNav> edi(g_classEntries);
4991   EntryNav *rootNav;
4992   for (;(rootNav=edi.current());++edi)
4993   {
4994     ClassDef *cd;
4995
4996     rootNav->loadEntry(g_storage);
4997     Entry *root = rootNav->entry();
4998
4999     // strip any anonymous scopes first 
5000     QCString bName=stripAnonymousNamespaceScope(rootNav->name());
5001     bName=stripTemplateSpecifiersFromScope(bName);
5002     Debug::print(Debug::Classes,0,"  Relations: Class %s : \n",bName.data());
5003     if ((cd=getClass(bName)))
5004     {
5005       findBaseClassesForClass(rootNav,cd,cd,cd,DocumentedOnly,FALSE);
5006     }
5007     int numMembers = cd && cd->memberNameInfoSDict() ? cd->memberNameInfoSDict()->count() : 0;
5008     if ((cd==0 || (!cd->hasDocumentation() && !cd->isReference())) && numMembers>0 &&
5009         bName.right(2)!="::")
5010     {
5011       if (!root->name.isEmpty() && root->name.find('@')==-1 && // normal name
5012           (guessSection(root->fileName)==Entry::HEADER_SEC || 
5013            Config_getBool("EXTRACT_LOCAL_CLASSES")) && // not defined in source file
5014            protectionLevelVisible(root->protection) && // hidden by protection
5015            !Config_getBool("HIDE_UNDOC_CLASSES") // undocumented class are visible
5016          )
5017         warn_undoc(
5018                    root->fileName,root->startLine,
5019                    "Compound %s is not documented.",
5020                    root->name.data()
5021              );
5022     }
5023
5024     rootNav->releaseEntry();
5025   }
5026 }
5027
5028 static void computeTemplateClassRelations()
5029 {
5030   QDictIterator<EntryNav> edi(g_classEntries);
5031   EntryNav *rootNav;
5032   for (;(rootNav=edi.current());++edi)
5033   {
5034     rootNav->loadEntry(g_storage);
5035     Entry *root = rootNav->entry();
5036
5037     QCString bName=stripAnonymousNamespaceScope(root->name);
5038     bName=stripTemplateSpecifiersFromScope(bName);
5039     ClassDef *cd=getClass(bName);
5040     // strip any anonymous scopes first 
5041     QDict<ClassDef> *templInstances = 0;
5042     if (cd && (templInstances=cd->getTemplateInstances()))
5043     {
5044       Debug::print(Debug::Classes,0,"  Template class %s : \n",cd->name().data());
5045       QDictIterator<ClassDef> tdi(*templInstances);
5046       ClassDef *tcd;
5047       for (tdi.toFirst();(tcd=tdi.current());++tdi) // for each template instance
5048       {
5049         Debug::print(Debug::Classes,0,"    Template instance %s : \n",tcd->name().data());
5050         QCString templSpec = tdi.currentKey();
5051         ArgumentList *templArgs = new ArgumentList;
5052         stringToArgumentList(templSpec,templArgs);
5053         QList<BaseInfo> *baseList=root->extends;
5054         QListIterator<BaseInfo> it(*baseList);
5055         BaseInfo *bi;
5056         for (;(bi=it.current());++it) // for each base class of the template
5057         {
5058           // check if the base class is a template argument
5059           BaseInfo tbi(bi->name,bi->prot,bi->virt);
5060           ArgumentList *tl = cd->templateArguments();
5061           if (tl)
5062           {
5063             QDict<int> *baseClassNames = tcd->getTemplateBaseClassNames();
5064             QDict<int> *templateNames = getTemplateArgumentsInName(tl,bi->name);
5065             // for each template name that we inherit from we need to
5066             // substitute the formal with the actual arguments
5067             QDict<int> *actualTemplateNames = new QDict<int>(17);
5068             actualTemplateNames->setAutoDelete(TRUE);
5069             QDictIterator<int> qdi(*templateNames);
5070             for (qdi.toFirst();qdi.current();++qdi)
5071             {
5072               int templIndex = *qdi.current();
5073               Argument *actArg = 0;
5074               if (templIndex<(int)templArgs->count()) 
5075               {
5076                 actArg=templArgs->at(templIndex);
5077               }
5078               if (actArg!=0 &&
5079                   baseClassNames!=0 &&
5080                   baseClassNames->find(actArg->type)!=0 &&
5081                   actualTemplateNames->find(actArg->type)==0
5082                  )
5083               {
5084                 actualTemplateNames->insert(actArg->type,new int(templIndex));
5085               }
5086             }
5087             delete templateNames;
5088             
5089             tbi.name = substituteTemplateArgumentsInString(bi->name,tl,templArgs);
5090             // find a documented base class in the correct scope
5091             if (!findClassRelation(rootNav,cd,tcd,&tbi,actualTemplateNames,DocumentedOnly,FALSE))
5092             {
5093               // no documented base class -> try to find an undocumented one
5094               findClassRelation(rootNav,cd,tcd,&tbi,actualTemplateNames,Undocumented,TRUE);
5095             }
5096             delete actualTemplateNames;
5097           }
5098         }
5099         delete templArgs;
5100       } // class has no base classes
5101     }
5102
5103     rootNav->releaseEntry();
5104   }
5105 }
5106
5107 //-----------------------------------------------------------------------
5108 // compute the references (anchors in HTML) for each function in the file
5109
5110 static void computeMemberReferences()
5111 {
5112   ClassSDict::Iterator cli(*Doxygen::classSDict);
5113   ClassDef *cd=0;
5114   for (cli.toFirst();(cd=cli.current());++cli)
5115   {
5116     cd->computeAnchors();
5117   }
5118   FileNameListIterator fnli(*Doxygen::inputNameList);
5119   FileName *fn;
5120   for (fnli.toFirst();(fn=fnli.current());++fnli)
5121   {
5122     FileNameIterator fni(*fn);
5123     FileDef *fd;
5124     for (;(fd=fni.current());++fni)
5125     {
5126       fd->computeAnchors();
5127     }
5128   }
5129   NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
5130   NamespaceDef *nd=0;
5131   for (nli.toFirst();(nd=nli.current());++nli)
5132   {
5133     nd->computeAnchors();
5134   }
5135   GroupSDict::Iterator gli(*Doxygen::groupSDict);
5136   GroupDef *gd;
5137   for (gli.toFirst();(gd=gli.current());++gli)
5138   {
5139     gd->computeAnchors();
5140   }
5141 }
5142
5143 //----------------------------------------------------------------------
5144
5145 static void addListReferences()
5146 {
5147   MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
5148   MemberName *mn=0;
5149   for (mnli.toFirst();(mn=mnli.current());++mnli)
5150   {
5151     MemberNameIterator mni(*mn);
5152     MemberDef *md=0;
5153     for (mni.toFirst();(md=mni.current());++mni)
5154     {
5155       md->visited=FALSE;
5156     }
5157   }
5158   MemberNameSDict::Iterator fmnli(*Doxygen::functionNameSDict);
5159   for (fmnli.toFirst();(mn=fmnli.current());++fmnli)
5160   {
5161     MemberNameIterator mni(*mn);
5162     MemberDef *md=0;
5163     for (mni.toFirst();(md=mni.current());++mni)
5164     {
5165       md->visited=FALSE;
5166     }
5167   }
5168
5169   ClassSDict::Iterator cli(*Doxygen::classSDict);
5170   ClassDef *cd=0;
5171   for (cli.toFirst();(cd=cli.current());++cli)
5172   {
5173     cd->addListReferences();
5174   }
5175
5176   FileNameListIterator fnli(*Doxygen::inputNameList);
5177   FileName *fn;
5178   for (fnli.toFirst();(fn=fnli.current());++fnli)
5179   {
5180     FileNameIterator fni(*fn);
5181     FileDef *fd;
5182     for (;(fd=fni.current());++fni)
5183     {
5184       fd->addListReferences();
5185     }
5186   }
5187
5188   NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
5189   NamespaceDef *nd=0;
5190   for (nli.toFirst();(nd=nli.current());++nli)
5191   {
5192     nd->addListReferences();
5193   }
5194
5195   GroupSDict::Iterator gli(*Doxygen::groupSDict);
5196   GroupDef *gd;
5197   for (gli.toFirst();(gd=gli.current());++gli)
5198   {
5199     gd->addListReferences();
5200   }
5201
5202   PageSDict::Iterator pdi(*Doxygen::pageSDict);
5203   PageDef *pd=0;
5204   for (pdi.toFirst();(pd=pdi.current());++pdi)
5205   {
5206     QCString name = pd->getOutputFileBase();
5207     if (pd->getGroupDef())
5208     {
5209       name = pd->getGroupDef()->getOutputFileBase();
5210     }
5211     {
5212       QList<ListItemInfo> *xrefItems = pd->xrefListItems();
5213       addRefItem(xrefItems,
5214           name,
5215           theTranslator->trPage(TRUE,TRUE),
5216           name,pd->title(),0);
5217     }
5218   }
5219
5220   DirSDict::Iterator ddi(*Doxygen::directories);
5221   DirDef *dd = 0;
5222   for (ddi.toFirst();(dd=ddi.current());++ddi)
5223   {
5224     QCString name = dd->getOutputFileBase();
5225     //if (dd->getGroupDef())
5226     //{
5227     //  name = dd->getGroupDef()->getOutputFileBase();
5228     //}
5229     QList<ListItemInfo> *xrefItems = dd->xrefListItems();
5230     addRefItem(xrefItems,
5231         name,
5232         theTranslator->trDir(TRUE,TRUE),
5233         name,dd->displayName(),0);
5234   }
5235 }
5236
5237 //----------------------------------------------------------------------
5238
5239 static void generateXRefPages()
5240 {
5241   QDictIterator<RefList> di(*Doxygen::xrefLists);
5242   RefList *rl;
5243   for (di.toFirst();(rl=di.current());++di)
5244   {
5245     rl->generatePage();
5246   }
5247 }
5248
5249 //----------------------------------------------------------------------
5250 // Copy the documentation in entry `root' to member definition `md' and
5251 // set the function declaration of the member to `funcDecl'. If the boolean 
5252 // over_load is set the standard overload text is added. 
5253
5254 static void addMemberDocs(EntryNav *rootNav,
5255                    MemberDef *md, const char *funcDecl,
5256                    ArgumentList *al,
5257                    bool over_load,
5258                    NamespaceSDict *
5259                   )
5260 {
5261   Entry *root = rootNav->entry();
5262   //printf("addMemberDocs: `%s'::`%s' `%s' funcDecl=`%s' mSpec=%d\n",
5263   //     root->parent->name.data(),md->name().data(),md->argsString(),funcDecl,root->spec);
5264   QCString fDecl=funcDecl;
5265   // strip extern specifier
5266   fDecl.stripPrefix("extern ");
5267   md->setDefinition(fDecl);
5268   md->enableCallGraph(root->callGraph);
5269   md->enableCallerGraph(root->callerGraph);
5270   ClassDef     *cd=md->getClassDef();
5271   NamespaceDef *nd=md->getNamespaceDef();
5272   QCString fullName;
5273   if (cd) 
5274     fullName = cd->name();
5275   else if (nd) 
5276     fullName = nd->name();
5277
5278   if (!fullName.isEmpty()) fullName+="::";
5279   fullName+=md->name();
5280   FileDef *rfd=rootNav->fileDef();
5281
5282   // TODO determine scope based on root not md
5283   Definition *rscope = md->getOuterScope();
5284
5285   ArgumentList *mdAl = md->argumentList();
5286   if (al)
5287   {
5288     //printf("merging arguments (1) docs=%d\n",root->doc.isEmpty());
5289     mergeArguments(mdAl,al,!root->doc.isEmpty());
5290   }
5291   else
5292   {
5293     if ( 
5294           matchArguments2( md->getOuterScope(), md->getFileDef(), mdAl,
5295                            rscope,rfd,root->argList,
5296                            TRUE
5297                          )
5298        ) 
5299     {
5300       //printf("merging arguments (2)\n");
5301       mergeArguments(mdAl,root->argList,!root->doc.isEmpty());
5302     }
5303   }
5304   if (over_load)  // the \overload keyword was used
5305   {
5306     QCString doc=getOverloadDocs();
5307     if (!root->doc.isEmpty())
5308     {
5309       doc+="<p>";
5310       doc+=root->doc;
5311     }
5312     md->setDocumentation(doc,root->docFile,root->docLine); 
5313     md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
5314     md->setDocsForDefinition(!root->proto);
5315   }
5316   else  
5317   {
5318     //printf("overwrite!\n");
5319     md->setDocumentation(root->doc,root->docFile,root->docLine);
5320     md->setDocsForDefinition(!root->proto);
5321
5322     //printf("overwrite!\n");
5323     md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
5324
5325     if (
5326         (md->inbodyDocumentation().isEmpty() ||
5327          !rootNav->parent()->name().isEmpty()
5328         ) && !root->inbodyDocs.isEmpty()
5329        )
5330     {
5331       md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
5332     }
5333   }
5334
5335   //printf("initializer: '%s'(isEmpty=%d) '%s'(isEmpty=%d)\n",
5336   //    md->initializer().data(),md->initializer().isEmpty(),
5337   //    root->initializer.data(),root->initializer.isEmpty()
5338   //   );
5339   if (md->initializer().isEmpty() && !root->initializer.isEmpty())
5340   {
5341     //printf("setInitializer\n");
5342     md->setInitializer(root->initializer);
5343   }
5344
5345   md->setMaxInitLines(root->initLines);
5346
5347   if (rfd)
5348   {
5349     if ((md->getStartBodyLine()==-1 && root->bodyLine!=-1) 
5350        )
5351     {
5352       //printf("Setting new body segment [%d,%d]\n",root->bodyLine,root->endBodyLine);
5353       md->setBodySegment(root->bodyLine,root->endBodyLine);
5354       md->setBodyDef(rfd);
5355     }
5356
5357     md->setRefItems(root->sli);
5358   }
5359
5360   md->enableCallGraph(md->hasCallGraph() || root->callGraph);
5361   md->enableCallerGraph(md->hasCallerGraph() || root->callerGraph);
5362
5363   md->mergeMemberSpecifiers(root->spec);
5364   md->addSectionsToDefinition(root->anchors);
5365   addMemberToGroups(root,md);
5366   if (cd) cd->insertUsedFile(rfd);
5367   //printf("root->mGrpId=%d\n",root->mGrpId);
5368   if (root->mGrpId!=-1)
5369   {
5370     if (md->getMemberGroupId()!=-1)
5371     {
5372       if (md->getMemberGroupId()!=root->mGrpId)
5373       {
5374         warn(
5375              root->fileName,root->startLine,
5376              "member %s belongs to two different groups. The second "
5377              "one found here will be ignored.",
5378              md->name().data()
5379             );
5380       }
5381     }
5382     else // set group id
5383     {
5384       //printf("setMemberGroupId=%d md=%s\n",root->mGrpId,md->name().data());
5385       md->setMemberGroupId(root->mGrpId);
5386     }
5387   }
5388 }
5389
5390 //----------------------------------------------------------------------
5391 // find a class definition given the scope name and (optionally) a 
5392 // template list specifier
5393
5394 static ClassDef *findClassDefinition(FileDef *fd,NamespaceDef *nd,
5395                          const char *scopeName)
5396 {
5397   ClassDef *tcd = getResolvedClass(nd,fd,scopeName,0,0,TRUE,TRUE);
5398   return tcd;
5399 }
5400
5401
5402 //----------------------------------------------------------------------
5403 // Adds the documentation contained in `root' to a global function
5404 // with name `name' and argument list `args' (for overloading) and
5405 // function declaration `decl' to the corresponding member definition.
5406
5407 static bool findGlobalMember(EntryNav *rootNav, 
5408                            const QCString &namespaceName,
5409                            const char *type,
5410                            const char *name, 
5411                            const char *tempArg,
5412                            const char *, 
5413                            const char *decl)
5414 {
5415   Entry *root = rootNav->entry();
5416   Debug::print(Debug::FindMembers,0,
5417        "2. findGlobalMember(namespace=%s,type=%s,name=%s,tempArg=%s,decl=%s)\n",
5418           namespaceName.data(),type,name,tempArg,decl);
5419   QCString n=name;
5420   if (n.isEmpty()) return FALSE;
5421   if (n.find("::")!=-1) return FALSE; // skip undefined class members
5422   MemberName *mn=Doxygen::functionNameSDict->find(n+tempArg); // look in function dictionary
5423   if (mn==0)
5424   {
5425     mn=Doxygen::functionNameSDict->find(n); // try without template arguments
5426   }
5427   if (mn) // function name defined
5428   {
5429     Debug::print(Debug::FindMembers,0,"3. Found symbol scope\n");
5430     //int count=0;
5431     MemberNameIterator mni(*mn);
5432     MemberDef *md;
5433     bool found=FALSE;
5434     for (mni.toFirst();(md=mni.current()) && !found;++mni)
5435     {
5436       NamespaceDef *nd=md->getNamespaceDef();
5437
5438       //printf("Namespace namespaceName=%s nd=%s\n",
5439       //    namespaceName.data(),nd ? nd->name().data() : "<none>");
5440
5441       FileDef *fd=rootNav->fileDef();
5442       //printf("File %s\n",fd ? fd->name().data() : "<none>");
5443       NamespaceSDict *nl = fd ? fd->getUsedNamespaces() : 0;
5444       //SDict<Definition> *cl = fd ? fd->getUsedClasses()    : 0;
5445       //printf("NamespaceList %p\n",nl);
5446
5447       // search in the list of namespaces that are imported via a 
5448       // using declaration
5449       bool viaUsingDirective = nl && nd && nl->find(nd->qualifiedName())!=0;
5450
5451       if ((namespaceName.isEmpty() && nd==0) ||  // not in a namespace
5452           (nd && nd->name()==namespaceName) ||   // or in the same namespace 
5453           viaUsingDirective                      // member in `using' namespace
5454          )     
5455       {
5456         Debug::print(Debug::FindMembers,0,"4. Try to add member `%s' to scope `%s'\n",
5457             md->name().data(),namespaceName.data());
5458         QCString nsName = nd ? nd->name().data() : "";
5459
5460         NamespaceDef *rnd = 0;
5461         if (!namespaceName.isEmpty()) rnd = Doxygen::namespaceSDict->find(namespaceName);
5462
5463         ArgumentList *mdAl = md->argumentList();
5464         bool matching=
5465           (mdAl==0 && root->argList->count()==0) ||
5466           md->isVariable() || md->isTypedef() || /* in case of function pointers */
5467           matchArguments2(md->getOuterScope(),md->getFileDef(),mdAl,
5468                           rnd ? rnd : Doxygen::globalScope,fd,root->argList,
5469                           FALSE);
5470
5471         // for template members we need to check if the number of
5472         // template arguments is the same, otherwise we are dealing with
5473         // different functions.
5474         if (matching && root->tArgLists)
5475         {
5476           ArgumentList *mdTempl = md->templateArguments();
5477           if (mdTempl)
5478           {
5479             if (root->tArgLists->getLast()->count()!=mdTempl->count())
5480             {
5481               matching=FALSE;
5482             }
5483           }
5484         }
5485
5486         //printf("%s<->%s\n",
5487         //    argListToString(md->argumentList()).data(),
5488         //    argListToString(root->argList).data());
5489
5490         // for static members we also check if the comment block was found in 
5491         // the same file. This is needed because static members with the same
5492         // name can be in different files. Thus it would be wrong to just
5493         // put the comment block at the first syntactically matching member.
5494         if (matching && md->isStatic() && 
5495             md->getDefFileName()!=root->fileName && 
5496             mn->count()>1)
5497         {
5498           matching = FALSE;
5499         }
5500
5501         // for template member we also need to check the return type
5502         if (md->templateArguments()!=0 && root->tArgLists!=0)
5503         {
5504           //printf("Comparing return types '%s'<->'%s'\n",
5505           //    md->typeString(),type);
5506           if (md->templateArguments()->count()!=root->tArgLists->getLast()->count() ||
5507               qstrcmp(md->typeString(),type)!=0)
5508           {
5509             //printf(" ---> no matching\n");
5510             matching = FALSE;
5511           }
5512         }
5513
5514         if (matching) // add docs to the member
5515         {
5516           Debug::print(Debug::FindMembers,0,"5. Match found\n");
5517           addMemberDocs(rootNav,md,decl,root->argList,FALSE);
5518           found=TRUE;
5519         }
5520       }
5521     } 
5522     if (!found && root->relatesType != Duplicate && root->section==Entry::FUNCTION_SEC) // no match
5523     {
5524       QCString fullFuncDecl=decl;
5525       if (root->argList) fullFuncDecl+=argListToString(root->argList,TRUE);
5526       QCString warnMsg =
5527          QCString("no matching file member found for \n")+substitute(fullFuncDecl,"%","%%");
5528       if (mn->count()>0)
5529       {
5530         warnMsg+="\nPossible candidates:\n";
5531         for (mni.toFirst();(md=mni.current());++mni)
5532         {
5533           warnMsg+=" '";
5534           warnMsg+=substitute(md->declaration(),"%","%%");
5535           warnMsg+="' at line "+QCString().setNum(md->getDefLine())+
5536                    " of file"+md->getDefFileName()+"\n";
5537         }
5538       }
5539       warn(root->fileName,root->startLine,warnMsg);
5540     }
5541   }
5542   else // got docs for an undefined member!
5543   {
5544     if (root->type!="friend class" && 
5545         root->type!="friend struct" &&
5546         root->type!="friend union" &&
5547         (!Config_getBool("TYPEDEF_HIDES_STRUCT") || 
5548          root->type.find("typedef ")==-1)
5549        )
5550     {
5551       warn(root->fileName,root->startLine,
5552            "documented symbol `%s' was not declared or defined.",decl
5553           );
5554     }
5555   }
5556   return TRUE;
5557 }
5558
5559 static bool isSpecialization(
5560                   const QList<ArgumentList> &srcTempArgLists,
5561                   const QList<ArgumentList> &dstTempArgLists
5562     )
5563 {
5564     QListIterator<ArgumentList> srclali(srcTempArgLists);
5565     QListIterator<ArgumentList> dstlali(dstTempArgLists);
5566     for (;srclali.current();++srclali,++dstlali)
5567     {
5568       ArgumentList *sal = srclali.current();
5569       ArgumentList *dal = dstlali.current();
5570       if (!(sal && dal && sal->count()==dal->count())) return TRUE;
5571     }
5572     return FALSE;
5573 }
5574
5575 static bool scopeIsTemplate(Definition *d)
5576 {
5577   bool result=FALSE;
5578   if (d && d->definitionType()==Definition::TypeClass)
5579   {
5580     result = ((ClassDef*)d)->templateArguments() || scopeIsTemplate(d->getOuterScope());
5581   }
5582   return result;
5583 }
5584
5585 static QCString substituteTemplatesInString(
5586     const QList<ArgumentList> &srcTempArgLists,
5587     const QList<ArgumentList> &dstTempArgLists,
5588     ArgumentList *funcTempArgList, // can be used to match template specializations
5589     const QCString &src
5590     )
5591 {
5592   QCString dst;
5593   QRegExp re( "[A-Za-z_][A-Za-z_0-9]*");
5594   //printf("type=%s\n",sa->type.data());
5595   int i,p=0,l; 
5596   while ((i=re.match(src,p,&l))!=-1) // for each word in srcType
5597   {
5598     bool found=FALSE;
5599     dst+=src.mid(p,i-p);
5600     QCString name=src.mid(i,l);
5601
5602     QListIterator<ArgumentList> srclali(srcTempArgLists);
5603     QListIterator<ArgumentList> dstlali(dstTempArgLists);
5604     for (;srclali.current() && !found;++srclali,++dstlali)
5605     {
5606       ArgumentListIterator tsali(*srclali.current());
5607       ArgumentListIterator tdali(*dstlali.current());
5608       ArgumentListIterator *fali=0;
5609       Argument *tsa =0,*tda=0, *fa=0;
5610       if (funcTempArgList)
5611       {
5612         fali = new ArgumentListIterator(*funcTempArgList);
5613         fa = fali->current();
5614       }
5615
5616       for (tsali.toFirst();(tsa=tsali.current()) && !found;++tsali)
5617       {
5618         tda = tdali.current();
5619         //if (tda) printf("tsa=%s|%s tda=%s|%s\n",
5620         //    tsa->type.data(),tsa->name.data(),
5621         //    tda->type.data(),tda->name.data());
5622         if (name==tsa->name)
5623         {
5624           if (tda && tda->name.isEmpty())
5625           {
5626             int vc=0;
5627             if (tda->type.left(6)=="class ") vc=6;
5628             else if (tda->type.left(9)=="typename ") vc=9;
5629             if (vc>0) // convert type=="class T" to type=="class" name=="T"
5630             {
5631               tda->name = tda->type.mid(vc);
5632               tda->type = tda->type.left(vc-1);
5633             }
5634           }
5635           if (tda && !tda->name.isEmpty())
5636           {
5637             name=tda->name; // substitute
5638             found=TRUE;
5639           }
5640           else if (fa)
5641           {
5642             name=fa->type;
5643             found=TRUE;
5644           }
5645         }
5646         if (tda)
5647           ++tdali;
5648         else if (fali)
5649         { ++(*fali); fa=fali->current(); }
5650       }
5651
5652       delete fali;
5653       //printf("   srcList='%s' dstList='%s faList='%s'\n",
5654       //  argListToString(srclali.current()).data(),
5655       //  argListToString(dstlali.current()).data(),
5656       //  funcTempArgList ? argListToString(funcTempArgList).data() : "<none>");
5657     }
5658     dst+=name; 
5659     p=i+l;
5660   }
5661   dst+=src.right(src.length()-p);
5662   //printf("  substituteTemplatesInString(%s)=%s\n",
5663   //    src.data(),dst.data());
5664   return dst;
5665 }
5666
5667 static void substituteTemplatesInArgList(
5668                   const QList<ArgumentList> &srcTempArgLists,
5669                   const QList<ArgumentList> &dstTempArgLists,
5670                   ArgumentList *src,
5671                   ArgumentList *dst,
5672                   ArgumentList *funcTempArgs = 0
5673                  )
5674 {
5675   ArgumentListIterator sali(*src);
5676   ArgumentListIterator dali(*dst);
5677   Argument *sa=0;
5678   Argument *da=dali.current();
5679
5680   for (sali.toFirst();(sa=sali.current());++sali) // for each member argument
5681   {
5682     QCString dstType = substituteTemplatesInString(
5683                                   srcTempArgLists,dstTempArgLists,funcTempArgs,
5684                                   sa->type);
5685     QCString dstArray = substituteTemplatesInString(
5686                                   srcTempArgLists,dstTempArgLists,funcTempArgs,
5687                                   sa->array);
5688     if (da==0)
5689     {
5690       da=new Argument(*sa);
5691       dst->append(da);
5692       da->type=dstType;
5693       da->array=dstArray;
5694       da=0;
5695     }
5696     else
5697     {
5698       da->type=dstType;
5699       da->type=dstArray;
5700       ++dali;
5701       da=dali.current();
5702     }
5703   }
5704   dst->constSpecifier     = src->constSpecifier;
5705   dst->volatileSpecifier  = src->volatileSpecifier;
5706   dst->pureSpecifier      = src->pureSpecifier;
5707   dst->trailingReturnType = substituteTemplatesInString(
5708                              srcTempArgLists,dstTempArgLists,
5709                              funcTempArgs,src->trailingReturnType);
5710   //printf("substituteTemplatesInArgList: replacing %s with %s\n",
5711   //    argListToString(src).data(),argListToString(dst).data()
5712   //    );
5713 }
5714
5715
5716
5717 /*! This function tries to find a member (in a documented class/file/namespace) 
5718  * that corresponds to the function/variable declaration given in \a funcDecl.
5719  *
5720  * The boolean \a overloaded is used to specify whether or not a standard
5721  * overload documentation line should be generated.
5722  *
5723  * The boolean \a isFunc is a hint that indicates that this is a function
5724  * instead of a variable or typedef.
5725  */
5726 static void findMember(EntryNav *rootNav,
5727                        QCString funcDecl,
5728                        bool overloaded,
5729                        bool isFunc
5730                       )
5731 {
5732   Entry *root = rootNav->entry();
5733
5734   Debug::print(Debug::FindMembers,0,
5735                "findMember(root=%p,funcDecl=`%s',related=`%s',overload=%d,"
5736                "isFunc=%d mGrpId=%d tArgList=%p (#=%d) "
5737                "spec=%lld lang=%x\n",
5738                root,funcDecl.data(),root->relates.data(),overloaded,isFunc,root->mGrpId,
5739                root->tArgLists,root->tArgLists ? root->tArgLists->count() : 0,
5740                root->spec,root->lang
5741               );
5742
5743   QCString scopeName;
5744   QCString className;
5745   QCString namespaceName;
5746   QCString funcType;
5747   QCString funcName;
5748   QCString funcArgs;
5749   QCString funcTempList;
5750   QCString exceptions;
5751   QCString funcSpec;
5752   bool isRelated=FALSE;
5753   bool isMemberOf=FALSE;
5754   bool isFriend=FALSE;
5755   bool done;
5756   do
5757   {
5758     done=TRUE;
5759     if (funcDecl.stripPrefix("friend ")) // treat friends as related members
5760     {
5761       isFriend=TRUE;
5762       done=FALSE;
5763     }
5764     if (funcDecl.stripPrefix("inline "))
5765     {
5766       root->spec|=Entry::Inline;
5767       done=FALSE;
5768     }
5769     if (funcDecl.stripPrefix("explicit "))
5770     {
5771       root->spec|=Entry::Explicit;
5772       done=FALSE;
5773     }
5774     if (funcDecl.stripPrefix("mutable "))
5775     {
5776       root->spec|=Entry::Mutable;
5777       done=FALSE;
5778     }
5779     if (funcDecl.stripPrefix("virtual "))
5780     {
5781       done=FALSE;
5782     }
5783   } while (!done);
5784
5785   // delete any ; from the function declaration
5786   int sep;
5787   while ((sep=funcDecl.find(';'))!=-1)
5788   {
5789     funcDecl=(funcDecl.left(sep)+funcDecl.right(funcDecl.length()-sep-1)).stripWhiteSpace();
5790   }
5791   
5792   // make sure the first character is a space to simplify searching.
5793   if (!funcDecl.isEmpty() && funcDecl[0]!=' ') funcDecl.prepend(" ");
5794   
5795   // remove some superfluous spaces
5796   funcDecl= substitute(
5797               substitute(
5798                 substitute(funcDecl,"~ ","~"),
5799                 ":: ","::"
5800               ),
5801               " ::","::"
5802             ).stripWhiteSpace();
5803   
5804   //printf("funcDecl=`%s'\n",funcDecl.data());
5805   if (isFriend && funcDecl.left(6)=="class ")
5806   {
5807     //printf("friend class\n");
5808     funcDecl=funcDecl.right(funcDecl.length()-6);
5809     funcName = funcDecl.copy();
5810   }
5811   else if (isFriend && funcDecl.left(7)=="struct ")
5812   {
5813     funcDecl=funcDecl.right(funcDecl.length()-7);
5814     funcName = funcDecl.copy();
5815   }
5816   else
5817   {
5818     // extract information from the declarations
5819     parseFuncDecl(funcDecl,root->lang==SrcLangExt_ObjC,scopeName,funcType,funcName,
5820                 funcArgs,funcTempList,exceptions
5821                );
5822   }
5823   //printf("scopeName=`%s' funcType=`%s' funcName=`%s' funcArgs=`%s'\n",
5824   //    scopeName.data(),funcType.data(),funcName.data(),funcArgs.data());
5825
5826   // the class name can also be a namespace name, we decide this later.
5827   // if a related class name is specified and the class name could
5828   // not be derived from the function declaration, then use the
5829   // related field.
5830   //printf("scopeName=`%s' className=`%s' namespaceName=`%s'\n",
5831   //    scopeName.data(),className.data(),namespaceName.data());
5832   if (!root->relates.isEmpty()) 
5833   {                             // related member, prefix user specified scope
5834     isRelated=TRUE;
5835     isMemberOf=(root->relatesType == MemberOf);
5836     if (getClass(root->relates)==0 && !scopeName.isEmpty())
5837     {
5838       scopeName= mergeScopes(scopeName,root->relates);
5839     }
5840     else 
5841     {
5842       scopeName = root->relates;
5843     }
5844   }
5845
5846   if (root->relates.isEmpty() && rootNav->parent() && 
5847       ((rootNav->parent()->section()&Entry::SCOPE_MASK) ||
5848        (rootNav->parent()->section()==Entry::OBJCIMPL_SEC)
5849       ) &&
5850       !rootNav->parent()->name().isEmpty()) // see if we can combine scopeName 
5851                                      // with the scope in which it was found
5852   {
5853     QCString joinedName = rootNav->parent()->name()+"::"+scopeName;
5854     if (!scopeName.isEmpty() && 
5855         (getClass(joinedName) || Doxygen::namespaceSDict->find(joinedName)))
5856     {
5857       scopeName = joinedName;
5858     }
5859     else
5860     {
5861       scopeName = mergeScopes(rootNav->parent()->name(),scopeName);
5862     }
5863   }
5864   else // see if we can prefix a namespace or class that is used from the file
5865   {
5866      FileDef *fd=rootNav->fileDef();
5867      if (fd)
5868      {
5869        NamespaceSDict *fnl = fd->getUsedNamespaces();
5870        if (fnl)
5871        {
5872          QCString joinedName;
5873          NamespaceDef *fnd;
5874          NamespaceSDict::Iterator nsdi(*fnl);
5875          for (nsdi.toFirst();(fnd=nsdi.current());++nsdi)
5876          {
5877            joinedName = fnd->name()+"::"+scopeName;
5878            if (Doxygen::namespaceSDict->find(joinedName))
5879            {
5880              scopeName=joinedName;
5881              break;
5882            }
5883          }
5884        }
5885      }
5886   }
5887   scopeName=stripTemplateSpecifiersFromScope(
5888       removeRedundantWhiteSpace(scopeName),FALSE,&funcSpec); 
5889
5890   // funcSpec contains the last template specifiers of the given scope.
5891   // If this method does not have any template arguments or they are 
5892   // empty while funcSpec is not empty we assume this is a 
5893   // specialization of a method. If not, we clear the funcSpec and treat
5894   // this as a normal method of a template class.
5895   if (!(root->tArgLists && 
5896         root->tArgLists->count()>0 &&
5897         root->tArgLists->getFirst()->count()==0
5898        )
5899      ) 
5900   {
5901     funcSpec.resize(0);
5902   }
5903   
5904   // split scope into a namespace and a class part
5905   extractNamespaceName(scopeName,className,namespaceName,TRUE);
5906   //printf("scopeName=`%s' className=`%s' namespaceName=`%s'\n",
5907   //       scopeName.data(),className.data(),namespaceName.data());
5908   
5909   //namespaceName=removeAnonymousScopes(namespaceName);
5910   if (namespaceName.find('@')!=-1) return; // skip stuff in anonymous namespace...
5911
5912   //printf("namespaceName=`%s' className=`%s'\n",namespaceName.data(),className.data());
5913   // merge class and namespace scopes again
5914   scopeName.resize(0);
5915   if (!namespaceName.isEmpty())
5916   {
5917     if (className.isEmpty())
5918     {
5919       scopeName=namespaceName;
5920     }
5921     else if (!root->relates.isEmpty() || // relates command with explicit scope
5922              !getClass(className)) // class name only exists in a namespace
5923     {
5924       scopeName=namespaceName+"::"+className;
5925     }
5926     else
5927     {
5928       scopeName=className;
5929     }
5930   }
5931   else if (!className.isEmpty())
5932   {
5933     scopeName=className;
5934   }
5935   //printf("new scope=`%s'\n",scopeName.data());
5936
5937   QCString tempScopeName=scopeName;
5938   ClassDef *cd=getClass(scopeName);
5939   if (cd)
5940   {
5941     if (funcSpec.isEmpty())
5942     {
5943       int argListIndex=0;
5944       tempScopeName=cd->qualifiedNameWithTemplateParameters(root->tArgLists,&argListIndex);
5945     }
5946     else
5947     {
5948       tempScopeName=scopeName+funcSpec;
5949     }
5950   }
5951   //printf("scopeName=%s cd=%p root->tArgLists=%p result=%s\n",
5952   //    scopeName.data(),cd,root->tArgLists,tempScopeName.data());
5953
5954   //printf("scopeName=`%s' className=`%s'\n",scopeName.data(),className.data());
5955   // rebuild the function declaration (needed to get the scope right).
5956   if (!scopeName.isEmpty() && !isRelated && !isFriend && !Config_getBool("HIDE_SCOPE_NAMES"))
5957   {
5958     if (!funcType.isEmpty())
5959     {
5960       if (isFunc) // a function -> we use argList for the arguments
5961       {
5962         funcDecl=funcType+" "+tempScopeName+"::"+funcName+funcTempList;
5963       }
5964       else
5965       {
5966         funcDecl=funcType+" "+tempScopeName+"::"+funcName+funcArgs;
5967       }
5968     }
5969     else
5970     {
5971       if (isFunc) // a function => we use argList for the arguments
5972       {
5973         funcDecl=tempScopeName+"::"+funcName+funcTempList;
5974       }
5975       else // variable => add `argument' list
5976       {
5977         funcDecl=tempScopeName+"::"+funcName+funcArgs;
5978       }
5979     }
5980   }
5981   else // build declaration without scope
5982   {
5983     if (!funcType.isEmpty()) // but with a type
5984     {
5985       if (isFunc) // function => omit argument list
5986       {
5987         funcDecl=funcType+" "+funcName+funcTempList;
5988       }
5989       else // variable => add `argument' list
5990       {
5991         funcDecl=funcType+" "+funcName+funcArgs;
5992       }
5993     }
5994     else // no type
5995     {
5996       if (isFunc)
5997       {
5998         funcDecl=funcName+funcTempList;
5999       }
6000       else
6001       {
6002         funcDecl=funcName+funcArgs;
6003       }
6004     }
6005   }
6006   
6007   if (funcType=="template class" && !funcTempList.isEmpty())
6008     return;   // ignore explicit template instantiations
6009   
6010   Debug::print(Debug::FindMembers,0,
6011            "findMember() Parse results:\n"
6012            "  namespaceName=`%s'\n"
6013            "  className=`%s`\n"
6014            "  funcType=`%s'\n"
6015            "  funcSpec=`%s'\n"
6016            "  funcName=`%s'\n"
6017            "  funcArgs=`%s'\n"
6018            "  funcTempList=`%s'\n"
6019            "  funcDecl=`%s'\n"
6020            "  related=`%s'\n" 
6021            "  exceptions=`%s'\n"
6022            "  isRelated=%d\n"
6023            "  isMemberOf=%d\n"
6024            "  isFriend=%d\n"
6025            "  isFunc=%d\n\n",
6026            namespaceName.data(),className.data(),
6027            funcType.data(),funcSpec.data(),funcName.data(),funcArgs.data(),funcTempList.data(),
6028            funcDecl.data(),root->relates.data(),exceptions.data(),isRelated,isMemberOf,isFriend,
6029            isFunc
6030           );
6031
6032   MemberName *mn=0;
6033   if (!funcName.isEmpty()) // function name is valid
6034   { 
6035     Debug::print(Debug::FindMembers,0,
6036                  "1. funcName=`%s'\n",funcName.data());
6037     if (funcName.left(9)=="operator ") // strip class scope from cast operator
6038     {
6039       funcName = substitute(funcName,className+"::","");
6040     }
6041     if (!funcTempList.isEmpty()) // try with member specialization
6042     {
6043       mn=Doxygen::memberNameSDict->find(funcName+funcTempList);
6044     }
6045     if (mn==0) // try without specialization
6046     {
6047       mn=Doxygen::memberNameSDict->find(funcName);
6048     }
6049     if (!isRelated && mn) // function name already found
6050     {
6051       Debug::print(Debug::FindMembers,0,
6052                    "2. member name exists (%d members with this name)\n",mn->count());
6053       if (!className.isEmpty()) // class name is valid
6054       {
6055         if (funcSpec.isEmpty()) // not a member specialization
6056         {
6057           int count=0;
6058           int noMatchCount=0;
6059           MemberNameIterator mni(*mn);
6060           MemberDef *md;
6061           bool memFound=FALSE;
6062           for (mni.toFirst();!memFound && (md=mni.current());++mni)
6063           {
6064             ClassDef *cd=md->getClassDef();
6065             Debug::print(Debug::FindMembers,0,
6066                 "3. member definition found, "
6067                 "scope needed=`%s' scope=`%s' args=`%s' fileName=%s\n",
6068                 scopeName.data(),cd ? cd->name().data() : "<none>",
6069                 md->argsString(),
6070                 root->fileName.data());
6071             //printf("Member %s (member scopeName=%s) (this scopeName=%s) classTempList=%s\n",md->name().data(),cd->name().data(),scopeName.data(),classTempList.data());
6072             FileDef *fd=rootNav->fileDef();
6073             NamespaceDef *nd=0;
6074             if (!namespaceName.isEmpty()) nd=getResolvedNamespace(namespaceName);
6075
6076             //printf("scopeName %s->%s\n",scopeName.data(),
6077             //       stripTemplateSpecifiersFromScope(scopeName,FALSE).data());
6078
6079             ClassDef *tcd=findClassDefinition(fd,nd,scopeName);
6080             if (tcd==0 && stripAnonymousNamespaceScope(cd->name())==scopeName)
6081             {
6082               // don't be fooled by anonymous scopes
6083               tcd=cd;
6084             }
6085             //printf("Looking for %s inside nd=%s result=%p (%s) cd=%p\n",
6086             //    scopeName.data(),nd?nd->name().data():"<none>",tcd,tcd?tcd->name().data():"",cd);
6087
6088             if (cd && tcd==cd) // member's classes match
6089             {
6090               Debug::print(Debug::FindMembers,0,
6091                   "4. class definition %s found\n",cd->name().data());
6092
6093               // get the template parameter lists found at the member declaration
6094               QList<ArgumentList> declTemplArgs;
6095               cd->getTemplateParameterLists(declTemplArgs);
6096               ArgumentList *templAl = md->templateArguments();
6097               if (templAl)
6098               {
6099                 declTemplArgs.append(templAl);
6100               }
6101
6102               // get the template parameter lists found at the member definition
6103               QList<ArgumentList> *defTemplArgs = root->tArgLists;
6104               //printf("defTemplArgs=%p\n",defTemplArgs);
6105
6106               // do we replace the decl argument lists with the def argument lists?
6107               bool substDone=FALSE;
6108               ArgumentList *argList=0;
6109
6110               /* substitute the occurrences of class template names in the 
6111                * argument list before matching 
6112                */
6113               ArgumentList *mdAl = md->argumentList();
6114               if (declTemplArgs.count()>0 && defTemplArgs &&
6115                   declTemplArgs.count()==defTemplArgs->count() &&
6116                   mdAl
6117                  )
6118               {
6119                 /* the function definition has template arguments
6120                  * and the class definition also has template arguments, so
6121                  * we must substitute the template names of the class by that
6122                  * of the function definition before matching.
6123                  */
6124                 argList = new ArgumentList;
6125                 substituteTemplatesInArgList(declTemplArgs,*defTemplArgs,
6126                     mdAl,argList);
6127
6128                 substDone=TRUE;
6129               }
6130               else /* no template arguments, compare argument lists directly */
6131               {
6132                 argList = mdAl;
6133               }
6134
6135               Debug::print(Debug::FindMembers,0,
6136                   "5. matching `%s'<=>`%s' className=%s namespaceName=%s\n",
6137                   argListToString(argList,TRUE).data(),argListToString(root->argList,TRUE).data(),
6138                   className.data(),namespaceName.data()
6139                   );
6140
6141               bool matching=
6142                 md->isVariable() || md->isTypedef() || // needed for function pointers
6143                 (mdAl==0 && root->argList->count()==0) || 
6144                 matchArguments2(
6145                     md->getClassDef(),md->getFileDef(),argList, 
6146                     cd,fd,root->argList,
6147                     TRUE);
6148
6149               if (md->getLanguage()==SrcLangExt_ObjC && md->isVariable() && (root->section&Entry::FUNCTION_SEC))
6150               {
6151                 matching = FALSE; // don't match methods and attributes with the same name
6152               }
6153
6154               // for template member we also need to check the return type
6155               if (md->templateArguments()!=0 && root->tArgLists!=0)
6156               {
6157                 QCString memType = md->typeString();
6158                 memType.stripPrefix("static "); // see bug700696
6159                 funcType=substitute(stripTemplateSpecifiersFromScope(funcType,TRUE),
6160                                     className+"::",""); // see bug700693 & bug732594
6161                 Debug::print(Debug::FindMembers,0,
6162                    "5b. Comparing return types '%s'<->'%s' #args %d<->%d\n",
6163                     md->typeString(),funcType.data(),
6164                     md->templateArguments()->count(),root->tArgLists->getLast()->count());
6165                 if (md->templateArguments()->count()!=root->tArgLists->getLast()->count() ||
6166                     qstrcmp(memType,funcType))
6167                 {
6168                   //printf(" ---> no matching\n");
6169                   matching = FALSE;
6170                 }
6171               }
6172               bool rootIsUserDoc = (root->section&Entry::MEMBERDOC_SEC)!=0;
6173               bool classIsTemplate = scopeIsTemplate(md->getClassDef());
6174               bool mdIsTemplate    = md->templateArguments()!=0;
6175               bool classOrMdIsTemplate = mdIsTemplate || classIsTemplate;
6176               bool rootIsTemplate  = root->tArgLists!=0;
6177               //printf("classIsTemplate=%d mdIsTemplate=%d rootIsTemplate=%d\n",classIsTemplate,mdIsTemplate,rootIsTemplate);
6178               if (!rootIsUserDoc && // don't check out-of-line @fn references, see bug722457
6179                   (mdIsTemplate || rootIsTemplate) && // either md or root is a template
6180                   ((classOrMdIsTemplate && !rootIsTemplate) || (!classOrMdIsTemplate && rootIsTemplate))
6181                  )
6182               {
6183                 // Method with template return type does not match method without return type
6184                 // even if the parameters are the same. See also bug709052
6185                 Debug::print(Debug::FindMembers,0,
6186                     "5b. Comparing return types: template v.s. non-template\n");
6187                 matching = FALSE;
6188               }
6189
6190
6191               Debug::print(Debug::FindMembers,0,
6192                   "6. match results of matchArguments2 = %d\n",matching);
6193
6194               if (substDone) // found a new argument list
6195               {
6196                 if (matching) // replace member's argument list
6197                 {
6198                   md->setDefinitionTemplateParameterLists(root->tArgLists);
6199                   md->setArgumentList(argList); // new owner of the list => no delete
6200                 }
6201                 else // no match 
6202                 {
6203                   if (!funcTempList.isEmpty() && 
6204                       isSpecialization(declTemplArgs,*defTemplArgs))
6205                   {
6206                     // check if we are dealing with a partial template
6207                     // specialization. In this case we add it to the class
6208                     // even though the member arguments do not match.
6209                     
6210                     // TODO: copy other aspects?
6211                     root->protection=md->protection(); // copy protection level
6212                     addMethodToClass(rootNav,cd,md->name(),isFriend);
6213                     return;
6214                   }
6215                   delete argList;
6216                 }
6217               }
6218               if (matching) 
6219               {
6220                 addMemberDocs(rootNav,md,funcDecl,0,overloaded,0/* TODO */);
6221                 count++;
6222                 memFound=TRUE;
6223               }
6224             } 
6225             else if (cd && cd!=tcd) // we did find a class with the same name as cd
6226                                     // but in a different namespace
6227             {
6228               noMatchCount++;
6229             }
6230           } 
6231           if (count==0 && rootNav->parent() && 
6232               rootNav->parent()->section()==Entry::OBJCIMPL_SEC)
6233           {
6234             goto localObjCMethod;
6235           }
6236           if (count==0 && !(isFriend && funcType=="class"))
6237           {
6238             int candidates=0;
6239             ClassDef *ecd = 0, *ucd = 0;
6240             MemberDef *emd = 0, *umd = 0;
6241             if (mn->count()>0)
6242             {
6243               //printf("Assume template class\n");
6244               for (mni.toFirst();(md=mni.current());++mni)
6245               {
6246                 ClassDef *ccd=md->getClassDef();
6247                 MemberDef *cmd=md;
6248                 //printf("ccd->name()==%s className=%s\n",ccd->name().data(),className.data());
6249                 if (ccd!=0 && rightScopeMatch(ccd->name(),className)) 
6250                 {
6251                   ArgumentList *templAl = md->templateArguments();
6252                   if (root->tArgLists && templAl!=0 &&
6253                       root->tArgLists->getLast()->count()<=templAl->count())
6254                   { 
6255                     addMethodToClass(rootNav,ccd,md->name(),isFriend);
6256                     return;
6257                   }
6258                   if (md->argsString()==argListToString(root->argList,TRUE,FALSE))
6259                   { // exact argument list match -> remember
6260                     ucd = ecd = ccd;
6261                     umd = emd = cmd;
6262                     Debug::print(Debug::FindMembers,0,
6263                      "7. new candidate className=%s scope=%s args=%s exact match\n",
6264                          className.data(),ccd->name().data(),md->argsString());
6265                   }
6266                   else // arguments do not match, but member name and scope do -> remember
6267                   {
6268                     ucd = ccd;
6269                     umd = cmd;
6270                     Debug::print(Debug::FindMembers,0,
6271                      "7. new candidate className=%s scope=%s args=%s no match\n",
6272                          className.data(),ccd->name().data(),md->argsString());
6273                   }
6274                   candidates++;
6275                 }
6276               }
6277             }
6278             static bool strictProtoMatching = Config_getBool("STRICT_PROTO_MATCHING");
6279             if (!strictProtoMatching)
6280             {
6281               if (candidates==1 && ucd && umd)
6282               {
6283                 // we didn't find an actual match on argument lists, but there is only 1 member with this
6284                 // name in the same scope, so that has to be the one. 
6285                 addMemberDocs(rootNav,umd,funcDecl,0,overloaded,0);
6286                 return;
6287               }
6288               else if (candidates>1 && ecd && emd)
6289               {
6290                 // we didn't find a unique match using type resolution, 
6291                 // but one of the matches has the exact same signature so
6292                 // we take that one.
6293                 addMemberDocs(rootNav,emd,funcDecl,0,overloaded,0);
6294                 return;
6295               }
6296             }
6297
6298             QCString warnMsg = "no ";
6299             if (noMatchCount>1) warnMsg+="uniquely ";
6300             warnMsg+="matching class member found for \n";
6301
6302             if (root->tArgLists)
6303             {
6304               QListIterator<ArgumentList> alli(*root->tArgLists);
6305               ArgumentList *al;
6306               for (;(al=alli.current());++alli)
6307               {
6308                 warnMsg+="  template ";
6309                 warnMsg+=tempArgListToString(al);
6310                 warnMsg+='\n';
6311               }
6312             }
6313             QCString fullFuncDecl=funcDecl.copy();
6314             if (isFunc) fullFuncDecl+=argListToString(root->argList,TRUE);
6315
6316             warnMsg+="  ";
6317             warnMsg+=fullFuncDecl;
6318             warnMsg+='\n';
6319
6320             if (candidates>0)
6321             {
6322               warnMsg+="Possible candidates:\n";
6323               for (mni.toFirst();(md=mni.current());++mni)
6324               {
6325                 ClassDef *cd=md->getClassDef();
6326                 if (cd!=0 && rightScopeMatch(cd->name(),className))
6327                 {
6328                   ArgumentList *templAl = md->templateArguments();
6329                   if (templAl!=0)
6330                   {
6331                     warnMsg+="  'template ";
6332                     warnMsg+=tempArgListToString(templAl);
6333                     warnMsg+='\n';
6334                   }
6335                   warnMsg+="  ";
6336                   if (md->typeString()) 
6337                   {
6338                     warnMsg+=md->typeString();
6339                     warnMsg+=' ';
6340                   }
6341                   QCString qScope = cd->qualifiedNameWithTemplateParameters();
6342                   if (!qScope.isEmpty()) 
6343                     warnMsg+=qScope+"::"+md->name();
6344                   if (md->argsString()) 
6345                     warnMsg+=md->argsString();
6346                   if (noMatchCount>1) 
6347                   {
6348                     warnMsg+="' at line "+QCString().setNum(md->getDefLine()) +
6349                              " of file "+md->getDefFileName();
6350                   }
6351
6352                   warnMsg+='\n';
6353                 }
6354               }
6355             }
6356             warn_simple(root->fileName,root->startLine,warnMsg);
6357           }
6358         }
6359         else if (cd) // member specialization
6360         {
6361           MemberNameIterator mni(*mn);
6362           MemberDef *declMd=0;
6363           MemberDef *md=0;
6364           for (mni.toFirst();(md=mni.current());++mni)
6365           {
6366             if (md->getClassDef()==cd) 
6367             {
6368               // TODO: we should probably also check for matching arguments
6369               declMd = md;
6370               break;
6371             }
6372           }
6373           MemberType mtype=MemberType_Function;
6374           ArgumentList *tArgList = new ArgumentList;
6375           //  getTemplateArgumentsFromName(cd->name()+"::"+funcName,root->tArgLists);
6376           md=new MemberDef(
6377               root->fileName,root->startLine,root->startColumn,
6378               funcType,funcName,funcArgs,exceptions,
6379               declMd ? declMd->protection() : root->protection,
6380               root->virt,root->stat,Member,
6381               mtype,tArgList,root->argList);
6382           //printf("new specialized member %s args=`%s'\n",md->name().data(),funcArgs.data());
6383           md->setTagInfo(rootNav->tagInfo());
6384           md->setLanguage(root->lang);
6385           md->setId(root->id);
6386           md->setMemberClass(cd);
6387           md->setTemplateSpecialization(TRUE);
6388           md->setTypeConstraints(root->typeConstr);
6389           md->setDefinition(funcDecl);
6390           md->enableCallGraph(root->callGraph);
6391           md->enableCallerGraph(root->callerGraph);
6392           md->setDocumentation(root->doc,root->docFile,root->docLine);
6393           md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
6394           md->setDocsForDefinition(!root->proto);
6395           md->setPrototype(root->proto);
6396           md->addSectionsToDefinition(root->anchors);
6397           md->setBodySegment(root->bodyLine,root->endBodyLine);
6398           FileDef *fd=rootNav->fileDef();
6399           md->setBodyDef(fd);
6400           md->setMemberSpecifiers(root->spec);
6401           md->setMemberGroupId(root->mGrpId);
6402           mn->append(md);
6403           cd->insertMember(md);
6404           md->setRefItems(root->sli);
6405           delete tArgList;
6406         }
6407         else
6408         {
6409           //printf("*** Specialized member %s of unknown scope %s%s found!\n",
6410           //        scopeName.data(),funcName.data(),funcArgs.data());
6411         }
6412       }
6413       else if (overloaded) // check if the function belongs to only one class 
6414       {
6415         // for unique overloaded member we allow the class to be
6416         // omitted, this is to be Qt compatible. Using this should 
6417         // however be avoided, because it is error prone
6418         MemberNameIterator mni(*mn);
6419         MemberDef *md=mni.toFirst();
6420         ASSERT(md);
6421         ClassDef *cd=md->getClassDef();
6422         ASSERT(cd);
6423         QCString className=cd->name().copy();
6424         ++mni;
6425         bool unique=TRUE;
6426         for (;(md=mni.current());++mni)
6427         {
6428           ClassDef *cd=md->getClassDef();
6429           if (className!=cd->name()) unique=FALSE; 
6430         } 
6431         if (unique)
6432         {
6433           MemberType mtype;
6434           if      (root->mtype==Signal)  mtype=MemberType_Signal;
6435           else if (root->mtype==Slot)    mtype=MemberType_Slot;
6436           else if (root->mtype==DCOP)    mtype=MemberType_DCOP;
6437           else                           mtype=MemberType_Function;
6438           
6439           // new overloaded member function
6440           ArgumentList *tArgList = 
6441             getTemplateArgumentsFromName(cd->name()+"::"+funcName,root->tArgLists);
6442           //printf("new related member %s args=`%s'\n",md->name().data(),funcArgs.data());
6443           MemberDef *md=new MemberDef(
6444               root->fileName,root->startLine,root->startColumn,
6445               funcType,funcName,funcArgs,exceptions,
6446               root->protection,root->virt,root->stat,Related,
6447               mtype,tArgList,root->argList);
6448           md->setTagInfo(rootNav->tagInfo());
6449           md->setLanguage(root->lang);
6450           md->setId(root->id);
6451           md->setTypeConstraints(root->typeConstr);
6452           md->setMemberClass(cd);
6453           md->setDefinition(funcDecl);
6454           md->enableCallGraph(root->callGraph);
6455           md->enableCallerGraph(root->callerGraph);
6456           QCString doc=getOverloadDocs();
6457           doc+="<p>";
6458           doc+=root->doc;
6459           md->setDocumentation(doc,root->docFile,root->docLine);
6460           md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
6461           md->setDocsForDefinition(!root->proto);
6462           md->setPrototype(root->proto);
6463           md->addSectionsToDefinition(root->anchors);
6464           md->setBodySegment(root->bodyLine,root->endBodyLine);
6465           FileDef *fd=rootNav->fileDef();
6466           md->setBodyDef(fd);
6467           md->setMemberSpecifiers(root->spec);
6468           md->setMemberGroupId(root->mGrpId);
6469           mn->append(md);
6470           cd->insertMember(md);
6471           cd->insertUsedFile(fd);
6472           md->setRefItems(root->sli);
6473         }
6474       }
6475       else // unrelated function with the same name as a member
6476       {
6477         if (!findGlobalMember(rootNav,namespaceName,funcType,funcName,funcTempList,funcArgs,funcDecl))
6478         {
6479           QCString fullFuncDecl=funcDecl.copy();
6480           if (isFunc) fullFuncDecl+=argListToString(root->argList,TRUE);
6481           warn(root->fileName,root->startLine,
6482                "Cannot determine class for function\n%s",
6483                fullFuncDecl.data()
6484               );   
6485         }
6486       }
6487     }
6488     else if (isRelated && !root->relates.isEmpty())
6489     {
6490       Debug::print(Debug::FindMembers,0,"2. related function\n"
6491               "  scopeName=%s className=%s\n",scopeName.data(),className.data());
6492       if (className.isEmpty()) className=root->relates;
6493       ClassDef *cd;
6494       //printf("scopeName=`%s' className=`%s'\n",scopeName.data(),className.data());
6495       if ((cd=getClass(scopeName)))
6496       {
6497         bool newMember=TRUE; // assume we have a new member
6498         bool newMemberName=FALSE; 
6499         MemberDef *mdDefine=0;
6500         bool isDefine=FALSE;
6501         {
6502           MemberName *mn = Doxygen::functionNameSDict->find(funcName);
6503           if (mn)
6504           {
6505             MemberNameIterator mni(*mn);
6506             mdDefine = mni.current();
6507             while (mdDefine && !isDefine)
6508             {
6509               isDefine = isDefine || mdDefine->isDefine();
6510               if (!isDefine) { ++mni; mdDefine=mni.current(); }
6511             }
6512           }
6513         }
6514
6515         FileDef *fd=rootNav->fileDef();
6516
6517         if ((mn=Doxygen::memberNameSDict->find(funcName))==0)
6518         {
6519           mn=new MemberName(funcName);
6520           newMemberName=TRUE; // we create a new member name
6521         }
6522         else
6523         {
6524           MemberNameIterator mni(*mn);
6525           MemberDef *rmd;
6526           while ((rmd=mni.current()) && newMember) // see if we got another member with matching arguments
6527           {
6528             ArgumentList *rmdAl = rmd->argumentList();
6529
6530             newMember=
6531               className!=rmd->getOuterScope()->name() ||
6532               !matchArguments2(rmd->getOuterScope(),rmd->getFileDef(),rmdAl,
6533                                cd,fd,root->argList,
6534                                TRUE);
6535             if (newMember) ++mni;
6536           }
6537           if (!newMember && rmd) // member already exists as rmd -> add docs
6538           {
6539             //printf("addMemberDocs for related member %s\n",root->name.data());
6540             //rmd->setMemberDefTemplateArguments(root->mtArgList);
6541             addMemberDocs(rootNav,rmd,funcDecl,0,overloaded);
6542           }
6543         }
6544
6545         if (newMember) // need to create a new member
6546         {
6547           MemberType mtype;
6548           if (isDefine)
6549             mtype=MemberType_Define;
6550           else if (root->mtype==Signal)  
6551             mtype=MemberType_Signal;
6552           else if (root->mtype==Slot) 
6553             mtype=MemberType_Slot;
6554           else if (root->mtype==DCOP)
6555             mtype=MemberType_DCOP;
6556           else
6557             mtype=MemberType_Function;
6558
6559           if (isDefine && mdDefine)
6560           {
6561             mdDefine->setHidden(TRUE);
6562             funcType="#define";
6563             funcArgs=mdDefine->argsString();
6564             funcDecl=funcType + " " + funcName;
6565           } 
6566
6567           //printf("New related name `%s' `%d'\n",funcName.data(),
6568           //    root->argList ? (int)root->argList->count() : -1);
6569
6570           // first note that we pass:
6571           //   (root->tArgLists ? root->tArgLists->last() : 0)
6572           // for the template arguments fo the new "member."
6573           // this accurately reflects the template arguments of
6574           // the related function, which don't have to do with
6575           // those of the related class.
6576           MemberDef *md=new MemberDef(
6577               root->fileName,root->startLine,root->startColumn,
6578               funcType,funcName,funcArgs,exceptions,
6579               root->protection,root->virt,
6580               root->stat && !isMemberOf,
6581               isMemberOf ? Foreign : isRelated ? Related : Member,
6582               mtype,
6583               (root->tArgLists ? root->tArgLists->getLast() : 0),
6584               funcArgs.isEmpty() ? 0 : root->argList);
6585
6586           if (isDefine && mdDefine)
6587           {
6588             md->setInitializer(mdDefine->initializer());
6589           }
6590
6591           // 
6592           // we still have the problem that
6593           // MemberDef::writeDocumentation() in memberdef.cpp
6594           // writes the template argument list for the class,
6595           // as if this member is a member of the class.
6596           // fortunately, MemberDef::writeDocumentation() has
6597           // a special mechanism that allows us to totally
6598           // override the set of template argument lists that
6599           // are printed.  We use that and set it to the
6600           // template argument lists of the related function.
6601           //
6602           md->setDefinitionTemplateParameterLists(root->tArgLists);
6603
6604           md->setTagInfo(rootNav->tagInfo());
6605
6606
6607
6608           //printf("Related member name=`%s' decl=`%s' bodyLine=`%d'\n",
6609           //       funcName.data(),funcDecl.data(),root->bodyLine);
6610
6611           // try to find the matching line number of the body from the
6612           // global function list 
6613           bool found=FALSE;
6614           if (root->bodyLine==-1)
6615           {
6616             MemberName *rmn=Doxygen::functionNameSDict->find(funcName);
6617             if (rmn)
6618             {
6619               MemberNameIterator rmni(*rmn);
6620               MemberDef *rmd;
6621               while ((rmd=rmni.current()) && !found) // see if we got another member with matching arguments
6622               {
6623                 ArgumentList *rmdAl = rmd->argumentList();
6624                 // check for matching argument lists
6625                 if (
6626                     matchArguments2(rmd->getOuterScope(),rmd->getFileDef(),rmdAl,
6627                                     cd,fd,root->argList,
6628                                     TRUE)
6629                    )
6630                 {
6631                   found=TRUE;
6632                 }
6633                 if (!found) ++rmni;
6634               }
6635               if (rmd) // member found -> copy line number info
6636               {
6637                 md->setBodySegment(rmd->getStartBodyLine(),rmd->getEndBodyLine());
6638                 md->setBodyDef(rmd->getBodyDef());
6639                 //md->setBodyMember(rmd);
6640               }
6641             }
6642           }
6643           if (!found) // line number could not be found or is available in this
6644                       // entry
6645           {
6646             md->setBodySegment(root->bodyLine,root->endBodyLine);
6647             md->setBodyDef(fd);
6648           }
6649
6650           //if (root->mGrpId!=-1) 
6651           //{
6652           //  md->setMemberGroup(memberGroupDict[root->mGrpId]);
6653           //}
6654           md->setMemberClass(cd);
6655           md->setMemberSpecifiers(root->spec);
6656           md->setDefinition(funcDecl);
6657           md->enableCallGraph(root->callGraph);
6658           md->enableCallerGraph(root->callerGraph);
6659           md->setDocumentation(root->doc,root->docFile,root->docLine);
6660           md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
6661           md->setDocsForDefinition(!root->proto);
6662           md->setPrototype(root->proto);
6663           md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
6664           md->addSectionsToDefinition(root->anchors);
6665           md->setMemberGroupId(root->mGrpId);
6666           md->setLanguage(root->lang);
6667           md->setId(root->id);
6668           //md->setMemberDefTemplateArguments(root->mtArgList);
6669           mn->append(md);
6670           cd->insertMember(md);
6671           cd->insertUsedFile(fd);
6672           md->setRefItems(root->sli);
6673           if (root->relatesType == Duplicate) md->setRelatedAlso(cd);
6674           if (!isDefine)
6675           {
6676             addMemberToGroups(root,md);
6677           }
6678           //printf("Adding member=%s\n",md->name().data());
6679           if (newMemberName)
6680           {
6681             //Doxygen::memberNameList.append(mn);
6682             //Doxygen::memberNameDict.insert(funcName,mn);
6683             Doxygen::memberNameSDict->append(funcName,mn);
6684           }
6685         }
6686         if (root->relatesType == Duplicate)
6687         {
6688           if (!findGlobalMember(rootNav,namespaceName,funcType,funcName,funcTempList,funcArgs,funcDecl))
6689           {
6690             QCString fullFuncDecl=funcDecl.copy();
6691             if (isFunc) fullFuncDecl+=argListToString(root->argList,TRUE);
6692             warn(root->fileName,root->startLine,
6693                "Cannot determine file/namespace for relatedalso function\n%s",
6694                fullFuncDecl.data()
6695               );   
6696           }
6697         }
6698       }
6699       else
6700       {
6701         warn_undoc(root->fileName,root->startLine,
6702                    "class `%s' for related function `%s' is not "
6703                    "documented.", 
6704                    className.data(),funcName.data()
6705                   );
6706       }
6707     }
6708     else if (rootNav->parent() && rootNav->parent()->section()==Entry::OBJCIMPL_SEC)
6709     {
6710 localObjCMethod:
6711       ClassDef *cd;
6712       //printf("scopeName=`%s' className=`%s'\n",scopeName.data(),className.data());
6713       if (Config_getBool("EXTRACT_LOCAL_METHODS") && (cd=getClass(scopeName)))
6714       {
6715         Debug::print(Debug::FindMembers,0,"4. Local objective C method %s\n"
6716               "  scopeName=%s className=%s\n",root->name.data(),scopeName.data(),className.data());
6717         //printf("Local objective C method `%s' of class `%s' found\n",root->name.data(),cd->name().data());
6718         MemberDef *md=new MemberDef(
6719             root->fileName,root->startLine,root->startColumn,
6720             funcType,funcName,funcArgs,exceptions,
6721             root->protection,root->virt,root->stat,Member,
6722             MemberType_Function,0,root->argList);
6723         md->setTagInfo(rootNav->tagInfo());
6724         md->setLanguage(root->lang);
6725         md->setId(root->id);
6726         md->makeImplementationDetail();
6727         md->setMemberClass(cd);
6728         md->setDefinition(funcDecl);
6729         md->enableCallGraph(root->callGraph);
6730         md->enableCallerGraph(root->callerGraph);
6731         md->setDocumentation(root->doc,root->docFile,root->docLine);
6732         md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
6733         md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
6734         md->setDocsForDefinition(!root->proto);
6735         md->setPrototype(root->proto);
6736         md->addSectionsToDefinition(root->anchors);
6737         md->setBodySegment(root->bodyLine,root->endBodyLine);
6738         FileDef *fd=rootNav->fileDef();
6739         md->setBodyDef(fd);
6740         md->setMemberSpecifiers(root->spec);
6741         md->setMemberGroupId(root->mGrpId);
6742         cd->insertMember(md);
6743         cd->insertUsedFile(fd);
6744         md->setRefItems(root->sli);
6745         if ((mn=Doxygen::memberNameSDict->find(root->name)))
6746         {
6747           mn->append(md);
6748         }
6749         else 
6750         {
6751           mn = new MemberName(root->name);
6752           mn->append(md);
6753           Doxygen::memberNameSDict->append(root->name,mn);
6754         }
6755       }
6756       else
6757       {
6758         // local objective C method found for class without interface
6759       }
6760     }
6761     else // unrelated not overloaded member found
6762     {
6763       bool globMem = findGlobalMember(rootNav,namespaceName,funcType,funcName,funcTempList,funcArgs,funcDecl);
6764       if (className.isEmpty() && !globMem)
6765       {
6766         warn(root->fileName,root->startLine,
6767              "class for member `%s' cannot "
6768              "be found.", funcName.data()
6769             ); 
6770       }
6771       else if (!className.isEmpty() && !globMem)
6772       {
6773         warn(root->fileName,root->startLine,
6774              "member `%s' of class `%s' cannot be found",
6775              funcName.data(),className.data());
6776       }
6777     }
6778   }
6779   else
6780   {
6781     // this should not be called
6782     warn(root->fileName,root->startLine,
6783          "member with no name found.");
6784   }
6785   return;
6786
6787
6788 //----------------------------------------------------------------------
6789 // find the members corresponding to the different documentation blocks
6790 // that are extracted from the sources.
6791
6792 static void filterMemberDocumentation(EntryNav *rootNav)
6793 {
6794   Entry *root = rootNav->entry();
6795   int i=-1,l;
6796   Debug::print(Debug::FindMembers,0,
6797       "findMemberDocumentation(): root->type=`%s' root->inside=`%s' root->name=`%s' root->args=`%s' section=%x root->spec=%lld root->mGrpId=%d\n",
6798       root->type.data(),root->inside.data(),root->name.data(),root->args.data(),root->section,root->spec,root->mGrpId
6799       );
6800   //printf("rootNav->parent()->name()=%s\n",rootNav->parent()->name().data());
6801   bool isFunc=TRUE;
6802
6803   if (root->relatesType == Duplicate && !root->relates.isEmpty())
6804   {
6805     QCString tmp = root->relates;
6806     root->relates.resize(0);
6807     filterMemberDocumentation(rootNav);
6808     root->relates = tmp;
6809   }
6810
6811   if ( // detect func variable/typedef to func ptr
6812       (i=findFunctionPtr(root->type,root->lang,&l))!=-1 
6813      )
6814   {
6815     //printf("Fixing function pointer!\n");
6816     // fix type and argument
6817     root->args.prepend(root->type.right(root->type.length()-i-l));
6818     root->type=root->type.left(i+l);
6819     //printf("Results type=%s,name=%s,args=%s\n",root->type.data(),root->name.data(),root->args.data());
6820     isFunc=FALSE;
6821   }
6822   else if ((root->type.left(8)=="typedef " && root->args.find('(')!=-1)) 
6823     // detect function types marked as functions
6824   {
6825     isFunc=FALSE;
6826   }
6827
6828   //printf("Member %s isFunc=%d\n",root->name.data(),isFunc);
6829   if (root->section==Entry::MEMBERDOC_SEC)
6830   {
6831     //printf("Documentation for inline member `%s' found args=`%s'\n",
6832     //    root->name.data(),root->args.data());
6833     //if (root->relates.length()) printf("  Relates %s\n",root->relates.data());
6834     if (root->type.isEmpty())
6835     {
6836       findMember(rootNav,root->name+root->args+root->exception,FALSE,isFunc);
6837     }
6838     else
6839     {
6840       findMember(rootNav,root->type+" "+root->name+root->args+root->exception,FALSE,isFunc);
6841     }
6842   }
6843   else if (root->section==Entry::OVERLOADDOC_SEC) 
6844   {
6845     //printf("Overloaded member %s found\n",root->name.data());
6846     findMember(rootNav,root->name,TRUE,isFunc);
6847   }
6848   else if 
6849     ((root->section==Entry::FUNCTION_SEC      // function
6850       ||   
6851       (root->section==Entry::VARIABLE_SEC &&  // variable
6852        !root->type.isEmpty() &&                // with a type
6853        g_compoundKeywordDict.find(root->type)==0 // that is not a keyword 
6854        // (to skip forward declaration of class etc.)
6855       )
6856      ) 
6857     )
6858     {
6859       //printf("Documentation for member `%s' found args=`%s' excp=`%s'\n",
6860       //    root->name.data(),root->args.data(),root->exception.data());
6861       //if (root->relates.length()) printf("  Relates %s\n",root->relates.data());
6862       //printf("Inside=%s\n Relates=%s\n",root->inside.data(),root->relates.data());
6863       if (root->type=="friend class" || root->type=="friend struct" || 
6864           root->type=="friend union")
6865       {
6866         findMember(rootNav,
6867             root->type+" "+
6868             root->name,
6869             FALSE,FALSE);
6870
6871       }
6872       else if (!root->type.isEmpty())
6873       {
6874         findMember(rootNav,
6875             root->type+" "+
6876             root->inside+
6877             root->name+
6878             root->args+
6879             root->exception,
6880             FALSE,isFunc);
6881       }
6882       else
6883       {
6884         findMember(rootNav,
6885             root->inside+
6886             root->name+
6887             root->args+
6888             root->exception,
6889             FALSE,isFunc);
6890       }
6891     }
6892   else if (root->section==Entry::DEFINE_SEC && !root->relates.isEmpty())
6893   {
6894     findMember(rootNav,root->name+root->args,FALSE,!root->args.isEmpty());
6895   }
6896   else if (root->section==Entry::VARIABLEDOC_SEC)
6897   {
6898     //printf("Documentation for variable %s found\n",root->name.data());
6899     //if (!root->relates.isEmpty()) printf("  Relates %s\n",root->relates.data());
6900     findMember(rootNav,root->name,FALSE,FALSE);
6901   }
6902   else if (root->section==Entry::EXPORTED_INTERFACE_SEC ||
6903            root->section==Entry::INCLUDED_SERVICE_SEC)
6904   {
6905     findMember(rootNav,root->type + " " + root->name,FALSE,FALSE);
6906   }
6907   else
6908   {
6909     // skip section 
6910     //printf("skip section\n");
6911   }
6912 }
6913
6914 static void findMemberDocumentation(EntryNav *rootNav)
6915 {
6916   if (rootNav->section()==Entry::MEMBERDOC_SEC ||
6917       rootNav->section()==Entry::OVERLOADDOC_SEC ||
6918       rootNav->section()==Entry::FUNCTION_SEC ||
6919       rootNav->section()==Entry::VARIABLE_SEC ||
6920       rootNav->section()==Entry::VARIABLEDOC_SEC ||
6921       rootNav->section()==Entry::DEFINE_SEC ||
6922       rootNav->section()==Entry::INCLUDED_SERVICE_SEC ||
6923       rootNav->section()==Entry::EXPORTED_INTERFACE_SEC
6924      )
6925   {
6926     rootNav->loadEntry(g_storage);
6927
6928     filterMemberDocumentation(rootNav);
6929
6930     rootNav->releaseEntry();
6931   }
6932   if (rootNav->children())
6933   {
6934     EntryNavListIterator eli(*rootNav->children());
6935     EntryNav *e;
6936     for (;(e=eli.current());++eli)
6937     {
6938       if (e->section()!=Entry::ENUM_SEC) findMemberDocumentation(e);
6939     }
6940   }
6941 }
6942
6943 //----------------------------------------------------------------------
6944
6945 static void findObjCMethodDefinitions(EntryNav *rootNav)
6946 {
6947   if (rootNav->children())
6948   {
6949     EntryNavListIterator eli(*rootNav->children());
6950     EntryNav *objCImplNav;
6951     for (;(objCImplNav=eli.current());++eli)
6952     {
6953       if (objCImplNav->section()==Entry::OBJCIMPL_SEC && objCImplNav->children())
6954       {
6955         EntryNavListIterator seli(*objCImplNav->children());
6956         EntryNav *objCMethodNav;
6957         for (;(objCMethodNav=seli.current());++seli)
6958         {
6959           if (objCMethodNav->section()==Entry::FUNCTION_SEC)
6960           {
6961             objCMethodNav->loadEntry(g_storage);
6962             Entry *objCMethod = objCMethodNav->entry();
6963
6964             //Printf("  Found ObjC method definition %s\n",objCMethod->name.data());
6965             findMember(objCMethodNav, objCMethod->type+" "+objCImplNav->name()+"::"+
6966                        objCMethod->name+" "+objCMethod->args, FALSE,TRUE);
6967             objCMethod->section=Entry::EMPTY_SEC;
6968
6969             objCMethodNav->releaseEntry();
6970           }
6971         }
6972       }
6973     }
6974   }
6975 }
6976
6977 //----------------------------------------------------------------------
6978 // find and add the enumeration to their classes, namespaces or files
6979
6980 static void findEnums(EntryNav *rootNav)
6981 {
6982   if (rootNav->section()==Entry::ENUM_SEC)
6983   {
6984     rootNav->loadEntry(g_storage);
6985     Entry *root = rootNav->entry();
6986
6987     MemberDef      *md=0;
6988     ClassDef       *cd=0;
6989     FileDef        *fd=0;
6990     NamespaceDef   *nd=0;
6991     MemberNameSDict *mnsd=0;
6992     bool isGlobal;
6993     bool isRelated=FALSE;
6994     bool isMemberOf=FALSE;
6995     //printf("Found enum with name `%s' relates=%s\n",root->name.data(),root->relates.data());
6996     int i;
6997
6998     QCString name;
6999     QCString scope;
7000
7001     if ((i=root->name.findRev("::"))!=-1) // scope is specified
7002     {
7003       scope=root->name.left(i); // extract scope
7004       name=root->name.right(root->name.length()-i-2); // extract name
7005       if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope);
7006     }
7007     else // no scope, check the scope in which the docs where found
7008     {
7009       if (( rootNav->parent()->section() & Entry::SCOPE_MASK )
7010           && !rootNav->parent()->name().isEmpty()
7011          ) // found enum docs inside a compound
7012       {
7013         scope=rootNav->parent()->name();
7014         if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope);
7015       }
7016       name=root->name;
7017     }
7018
7019     if (!root->relates.isEmpty()) 
7020     {   // related member, prefix user specified scope
7021       isRelated=TRUE;
7022       isMemberOf=(root->relatesType == MemberOf);
7023       if (getClass(root->relates)==0 && !scope.isEmpty())
7024         scope=mergeScopes(scope,root->relates);
7025       else 
7026         scope=root->relates.copy();
7027       if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope);
7028     }
7029
7030     if (cd && !name.isEmpty()) // found a enum inside a compound
7031     {
7032       //printf("Enum `%s'::`%s'\n",cd->name(),name.data());
7033       fd=0;
7034       mnsd=Doxygen::memberNameSDict;
7035       isGlobal=FALSE;
7036     }
7037     else if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@') // found enum inside namespace
7038     {
7039       mnsd=Doxygen::functionNameSDict;
7040       isGlobal=TRUE;
7041     }
7042     else // found a global enum
7043     {
7044       fd=rootNav->fileDef();
7045       mnsd=Doxygen::functionNameSDict;
7046       isGlobal=TRUE;
7047     }
7048
7049     if (!name.isEmpty())
7050     {
7051       // new enum type
7052       md = new MemberDef(
7053           root->fileName,root->startLine,root->startColumn,
7054           0,name,0,0,
7055           root->protection,Normal,FALSE,
7056           isMemberOf ? Foreign : isRelated ? Related : Member,
7057           MemberType_Enumeration,
7058           0,0);
7059       md->setTagInfo(rootNav->tagInfo());
7060       md->setLanguage(root->lang);
7061       md->setId(root->id);
7062       if (!isGlobal) md->setMemberClass(cd); else md->setFileDef(fd);
7063       md->setBodySegment(root->bodyLine,root->endBodyLine);
7064       md->setBodyDef(rootNav->fileDef());
7065       md->setMemberSpecifiers(root->spec); // UNO IDL "published"
7066       md->setEnumBaseType(root->args);
7067       //printf("Enum %s definition at line %d of %s: protection=%d\n",
7068       //    root->name.data(),root->bodyLine,root->fileName.data(),root->protection);
7069       md->addSectionsToDefinition(root->anchors);
7070       md->setMemberGroupId(root->mGrpId);
7071       md->enableCallGraph(root->callGraph);
7072       md->enableCallerGraph(root->callerGraph);
7073       //printf("%s::setRefItems(%d)\n",md->name().data(),root->sli?root->sli->count():-1);
7074       md->setRefItems(root->sli);
7075       //printf("found enum %s nd=%p\n",name.data(),nd);
7076       bool defSet=FALSE;
7077
7078       QCString baseType = root->args;
7079       if (!baseType.isEmpty())
7080       {
7081         baseType.prepend(" : ");
7082       }
7083
7084       if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@')
7085       {
7086         if (isRelated || Config_getBool("HIDE_SCOPE_NAMES"))
7087         {
7088           md->setDefinition(name+baseType);  
7089         }
7090         else
7091         {
7092           md->setDefinition(nd->name()+"::"+name+baseType);  
7093         }
7094         //printf("definition=%s\n",md->definition());
7095         defSet=TRUE;
7096         md->setNamespace(nd);
7097         nd->insertMember(md);
7098       }
7099
7100       // even if we have already added the enum to a namespace, we still
7101       // also want to add it to other appropriate places such as file
7102       // or class.
7103       if (isGlobal)
7104       {
7105         if (!defSet) md->setDefinition(name+baseType);
7106         if (fd==0 && rootNav->parent())
7107         {
7108           fd=rootNav->parent()->fileDef();
7109         }
7110         if (fd) 
7111         {
7112           md->setFileDef(fd);
7113           fd->insertMember(md);
7114         }
7115       }
7116       else if (cd)
7117       {
7118         if (isRelated || Config_getBool("HIDE_SCOPE_NAMES"))
7119         {
7120           md->setDefinition(name+baseType);  
7121         }
7122         else
7123         {
7124           md->setDefinition(cd->name()+"::"+name+baseType);  
7125         }
7126         cd->insertMember(md);
7127         cd->insertUsedFile(fd);
7128       }
7129       md->setDocumentation(root->doc,root->docFile,root->docLine);
7130       md->setDocsForDefinition(!root->proto);
7131       md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
7132       md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
7133
7134       //printf("Adding member=%s\n",md->name().data());
7135       MemberName *mn;
7136       if ((mn=(*mnsd)[name]))
7137       {
7138         // this is used if the same enum is in multiple namespaces/classes
7139         mn->append(md);
7140       }
7141       else // new enum name
7142       {
7143         mn = new MemberName(name);
7144         mn->append(md);
7145         mnsd->append(name,mn);
7146         //printf("add %s to new memberName. Now %d members\n",
7147         //       name.data(),mn->count());
7148       }
7149       addMemberToGroups(root,md);
7150     }
7151     rootNav->releaseEntry();
7152   }
7153   else
7154   {
7155     RECURSE_ENTRYTREE(findEnums,rootNav);
7156   }
7157 }
7158
7159 //----------------------------------------------------------------------
7160
7161 static void addEnumValuesToEnums(EntryNav *rootNav)
7162 {
7163   if (rootNav->section()==Entry::ENUM_SEC)
7164     // non anonymous enumeration
7165   {
7166     rootNav->loadEntry(g_storage);
7167     Entry *root = rootNav->entry();
7168
7169     ClassDef       *cd=0;
7170     FileDef        *fd=0;
7171     NamespaceDef   *nd=0;
7172     MemberNameSDict *mnsd=0;
7173     bool isGlobal;
7174     bool isRelated=FALSE;
7175     //printf("Found enum with name `%s' relates=%s\n",root->name.data(),root->relates.data());
7176     int i;
7177
7178     QCString name;
7179     QCString scope;
7180
7181     if ((i=root->name.findRev("::"))!=-1) // scope is specified
7182     {
7183       scope=root->name.left(i); // extract scope
7184       name=root->name.right(root->name.length()-i-2); // extract name
7185       if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope);
7186     }
7187     else // no scope, check the scope in which the docs where found
7188     {
7189       if (( rootNav->parent()->section() & Entry::SCOPE_MASK )
7190           && !rootNav->parent()->name().isEmpty()
7191          ) // found enum docs inside a compound
7192       {
7193         scope=rootNav->parent()->name();
7194         if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope);
7195       }
7196       name=root->name;
7197     }
7198
7199     if (!root->relates.isEmpty()) 
7200     {   // related member, prefix user specified scope
7201       isRelated=TRUE;
7202       if (getClass(root->relates)==0 && !scope.isEmpty())
7203         scope=mergeScopes(scope,root->relates);
7204       else 
7205         scope=root->relates.copy();
7206       if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope);
7207     }
7208
7209     if (cd && !name.isEmpty()) // found a enum inside a compound
7210     {
7211       //printf("Enum in class `%s'::`%s'\n",cd->name().data(),name.data());
7212       fd=0;
7213       mnsd=Doxygen::memberNameSDict;
7214       isGlobal=FALSE;
7215     }
7216     else if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@') // found enum inside namespace
7217     {
7218       //printf("Enum in namespace `%s'::`%s'\n",nd->name().data(),name.data());
7219       mnsd=Doxygen::functionNameSDict;
7220       isGlobal=TRUE;
7221     }
7222     else // found a global enum
7223     {
7224       fd=rootNav->fileDef();
7225       //printf("Enum in file `%s': `%s'\n",fd->name().data(),name.data());
7226       mnsd=Doxygen::functionNameSDict;
7227       isGlobal=TRUE;
7228     }
7229
7230     if (!name.isEmpty())
7231     {
7232       //printf("** name=%s\n",name.data());
7233       MemberName *mn = mnsd->find(name); // for all members with this name
7234       if (mn)
7235       {
7236         MemberNameIterator mni(*mn);
7237         MemberDef *md;
7238         for (mni.toFirst(); (md=mni.current()) ; ++mni)  // for each enum in this list
7239         {
7240           if (md->isEnumerate() && rootNav->children())
7241           {
7242             //printf("   enum with %d children\n",rootNav->children()->count());
7243             EntryNavListIterator eli(*rootNav->children()); // for each enum value
7244             EntryNav *e;
7245             for (;(e=eli.current());++eli)
7246             {
7247               SrcLangExt sle;
7248               if (
7249                    (sle=rootNav->lang())==SrcLangExt_CSharp || 
7250                    sle==SrcLangExt_Java || 
7251                    sle==SrcLangExt_XML ||
7252                    (root->spec&Entry::Strong)
7253                  )
7254               {
7255                 // Unlike classic C/C++ enums, for C++11, C# & Java enum 
7256                 // values are only visible inside the enum scope, so we must create 
7257                 // them here and only add them to the enum
7258                 e->loadEntry(g_storage);
7259                 Entry *root = e->entry();
7260                 //printf("md->qualifiedName()=%s rootNav->name()=%s tagInfo=%p name=%s\n",
7261                 //    md->qualifiedName().data(),rootNav->name().data(),rootNav->tagInfo(),root->name.data());
7262                 if (substitute(md->qualifiedName(),"::",".")== // TODO: add function to get canonical representation
7263                     substitute(rootNav->name(),"::",".") ||    // enum value scope matches that of the enum
7264                     rootNav->tagInfo()                         // be less strict for tag files as members can have incomplete scope
7265                    ) 
7266                 {
7267                   MemberDef *fmd=new MemberDef(
7268                       root->fileName,root->startLine,root->startColumn,
7269                       root->type,root->name,root->args,0,
7270                       Public, Normal,root->stat,Member,
7271                       MemberType_EnumValue,0,0);
7272                   if      (md->getClassDef())     fmd->setMemberClass(md->getClassDef());
7273                   else if (md->getNamespaceDef()) fmd->setNamespace(md->getNamespaceDef());
7274                   else if (md->getFileDef())      fmd->setFileDef(md->getFileDef());
7275                   fmd->setOuterScope(md->getOuterScope());
7276                   fmd->setTagInfo(e->tagInfo());
7277                   fmd->setLanguage(root->lang);
7278                   fmd->setId(root->id);
7279                   fmd->setDocumentation(root->doc,root->docFile,root->docLine);
7280                   fmd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
7281                   fmd->addSectionsToDefinition(root->anchors);
7282                   fmd->setInitializer(root->initializer);
7283                   fmd->setMaxInitLines(root->initLines);
7284                   fmd->setMemberGroupId(root->mGrpId);
7285                   fmd->setExplicitExternal(root->explicitExternal);
7286                   fmd->setRefItems(root->sli);
7287                   fmd->setAnchor();
7288                   md->insertEnumField(fmd);
7289                   fmd->setEnumScope(md,TRUE);
7290                   MemberName *mn=mnsd->find(root->name);
7291                   if (mn)
7292                   {
7293                     mn->append(fmd);
7294                   }
7295                   else 
7296                   {
7297                     mn = new MemberName(root->name);
7298                     mn->append(fmd);
7299                     mnsd->append(root->name,mn);
7300                   }
7301                 }
7302                 e->releaseEntry();
7303               }
7304               else
7305               {
7306                 //printf("e->name=%s isRelated=%d\n",e->name().data(),isRelated);
7307                 MemberName *fmn=0;
7308                 MemberNameSDict *emnsd = isRelated ? Doxygen::functionNameSDict : mnsd;
7309                 if (!e->name().isEmpty() && (fmn=(*emnsd)[e->name()])) 
7310                   // get list of members with the same name as the field
7311                 {
7312                   MemberNameIterator fmni(*fmn);
7313                   MemberDef *fmd;
7314                   for (fmni.toFirst(); (fmd=fmni.current()) ; ++fmni) 
7315                   {
7316                     if (fmd->isEnumValue() && fmd->getOuterScope()==md->getOuterScope()) // in same scope
7317                     {
7318                       //printf("found enum value with same name %s in scope %s\n",
7319                       //    fmd->name().data(),fmd->getOuterScope()->name().data());
7320                       if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@')
7321                       {
7322                         NamespaceDef *fnd=fmd->getNamespaceDef();
7323                         if (fnd==nd) // enum value is inside a namespace
7324                         {
7325                           md->insertEnumField(fmd);
7326                           fmd->setEnumScope(md);
7327                         }
7328                       }
7329                       else if (isGlobal)
7330                       {
7331                         FileDef *ffd=fmd->getFileDef();
7332                         if (ffd==fd) // enum value has file scope
7333                         {
7334                           md->insertEnumField(fmd);
7335                           fmd->setEnumScope(md);
7336                         }
7337                       }
7338                       else if (isRelated && cd) // reparent enum value to
7339                                                 // match the enum's scope
7340                       {
7341                         md->insertEnumField(fmd);   // add field def to list
7342                         fmd->setEnumScope(md);      // cross ref with enum name
7343                         fmd->setEnumClassScope(cd); // cross ref with enum name
7344                         fmd->setOuterScope(cd);
7345                         fmd->makeRelated();
7346                         cd->insertMember(fmd);
7347                       }
7348                       else
7349                       {
7350                         ClassDef *fcd=fmd->getClassDef();
7351                         if (fcd==cd) // enum value is inside a class
7352                         {
7353                           //printf("Inserting enum field %s in enum scope %s\n",
7354                           //    fmd->name().data(),md->name().data());
7355                           md->insertEnumField(fmd); // add field def to list
7356                           fmd->setEnumScope(md);    // cross ref with enum name
7357                         }
7358                       }
7359                     } 
7360                   }
7361                 }
7362               }
7363             }
7364           }
7365         }
7366       }
7367     }
7368
7369     rootNav->releaseEntry();
7370   }
7371   else
7372   {
7373     RECURSE_ENTRYTREE(addEnumValuesToEnums,rootNav);
7374   }
7375 }
7376
7377
7378 //----------------------------------------------------------------------
7379 // find the documentation blocks for the enumerations
7380
7381 static void findEnumDocumentation(EntryNav *rootNav)
7382 {
7383   if (rootNav->section()==Entry::ENUMDOC_SEC
7384       && !rootNav->name().isEmpty()
7385       && rootNav->name().at(0)!='@'        // skip anonymous enums
7386      )
7387   {
7388     rootNav->loadEntry(g_storage);
7389     Entry *root = rootNav->entry();
7390
7391     //printf("Found docs for enum with name `%s' in context %s\n",
7392     //    root->name.data(),root->parent->name.data());
7393     int i;
7394     QCString name;
7395     QCString scope;
7396     if ((i=root->name.findRev("::"))!=-1) // scope is specified as part of the name
7397     {
7398       name=root->name.right(root->name.length()-i-2); // extract name
7399       scope=root->name.left(i); // extract scope
7400       //printf("Scope=`%s' Name=`%s'\n",scope.data(),name.data());
7401     }
7402     else // just the name
7403     {
7404       name=root->name;
7405     }
7406     if (( rootNav->parent()->section() & Entry::SCOPE_MASK )
7407         && !rootNav->parent()->name().isEmpty()
7408        ) // found enum docs inside a compound
7409     {
7410       if (!scope.isEmpty()) scope.prepend("::");
7411       scope.prepend(rootNav->parent()->name());
7412     }
7413     ClassDef *cd=getClass(scope);
7414
7415     if (!name.isEmpty())
7416     {
7417       bool found=FALSE;
7418       if (cd)
7419       {
7420         //printf("Enum: scope=`%s' name=`%s'\n",cd->name(),name.data());
7421         QCString className=cd->name().copy();
7422         MemberName *mn=Doxygen::memberNameSDict->find(name);
7423         if (mn)
7424         {
7425           MemberNameIterator mni(*mn);
7426           MemberDef *md;
7427           for (mni.toFirst();(md=mni.current()) && !found;++mni)
7428           {
7429             ClassDef *cd=md->getClassDef();
7430             if (cd && cd->name()==className && md->isEnumerate())
7431             {
7432               // documentation outside a compound overrides the documentation inside it
7433 #if 0
7434               if (!md->documentation() || rootNav->parent()->name().isEmpty()) 
7435 #endif
7436               {
7437                 md->setDocumentation(root->doc,root->docFile,root->docLine);
7438                 md->setDocsForDefinition(!root->proto);
7439               }
7440
7441               // brief descriptions inside a compound override the documentation 
7442               // outside it
7443 #if 0
7444               if (!md->briefDescription() || !rootNav->parent()->name().isEmpty())
7445 #endif
7446               {
7447                 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
7448               }
7449
7450               if (!md->inbodyDocumentation() || !rootNav->parent()->name().isEmpty())
7451               {
7452                 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
7453               }
7454
7455               if (root->mGrpId!=-1 && md->getMemberGroupId()==-1)
7456               {
7457                 md->setMemberGroupId(root->mGrpId);
7458               }
7459
7460               md->addSectionsToDefinition(root->anchors);
7461               md->setRefItems(root->sli);
7462
7463               GroupDef *gd=md->getGroupDef();
7464               if (gd==0 &&root->groups->getFirst()!=0) // member not grouped but out-of-line documentation is
7465               {
7466                 addMemberToGroups(root,md);
7467               }
7468
7469               found=TRUE;
7470             }
7471           }
7472         }
7473         else
7474         {
7475           //printf("MemberName %s not found!\n",name.data());
7476         }
7477       }
7478       else // enum outside class 
7479       {
7480         //printf("Enum outside class: %s grpId=%d\n",name.data(),root->mGrpId);
7481         MemberName *mn=Doxygen::functionNameSDict->find(name);
7482         if (mn)
7483         {
7484           MemberNameIterator mni(*mn);
7485           MemberDef *md;
7486           for (mni.toFirst();(md=mni.current()) && !found;++mni)
7487           {
7488             if (md->isEnumerate())
7489             {
7490               md->setDocumentation(root->doc,root->docFile,root->docLine);
7491               md->setDocsForDefinition(!root->proto);
7492               md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
7493               md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
7494               md->addSectionsToDefinition(root->anchors);
7495               md->setMemberGroupId(root->mGrpId);
7496
7497               GroupDef *gd=md->getGroupDef();
7498               if (gd==0 && root->groups->getFirst()!=0) // member not grouped but out-of-line documentation is
7499               {
7500                 addMemberToGroups(root,md);
7501               }
7502
7503               found=TRUE;
7504             }
7505           }
7506         }
7507       } 
7508       if (!found)
7509       {
7510         warn(root->fileName,root->startLine,
7511              "Documentation for undefined enum `%s' found.",
7512              name.data()
7513             );
7514       }
7515     }
7516
7517     rootNav->releaseEntry();
7518   }
7519   RECURSE_ENTRYTREE(findEnumDocumentation,rootNav);
7520 }
7521
7522 // search for each enum (member or function) in mnl if it has documented 
7523 // enum values.
7524 static void findDEV(const MemberNameSDict &mnsd)
7525 {
7526   MemberName *mn;
7527   MemberNameSDict::Iterator mnli(mnsd);
7528   // for each member name
7529   for (mnli.toFirst();(mn=mnli.current());++mnli)
7530   {
7531     MemberDef *md;
7532     MemberNameIterator mni(*mn);
7533     // for each member definition
7534     for (mni.toFirst();(md=mni.current());++mni)
7535     {
7536       if (md->isEnumerate()) // member is an enum
7537       {
7538         MemberList *fmdl = md->enumFieldList();
7539         int documentedEnumValues=0;
7540         if (fmdl) // enum has values
7541         {
7542           MemberListIterator fmni(*fmdl);
7543           MemberDef *fmd;
7544           // for each enum value
7545           for (fmni.toFirst();(fmd=fmni.current());++fmni)
7546           {
7547             if (fmd->isLinkableInProject()) documentedEnumValues++;
7548           }
7549         }
7550         // at least one enum value is documented
7551         if (documentedEnumValues>0) md->setDocumentedEnumValues(TRUE);
7552       }
7553     }
7554   }
7555 }
7556
7557 // search for each enum (member or function) if it has documented enum 
7558 // values.
7559 static void findDocumentedEnumValues()
7560 {
7561   findDEV(*Doxygen::memberNameSDict);
7562   findDEV(*Doxygen::functionNameSDict); 
7563 }
7564
7565 //----------------------------------------------------------------------
7566
7567 static void addMembersToIndex()
7568 {
7569   MemberName *mn;
7570   MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
7571   // for each member name
7572   for (mnli.toFirst();(mn=mnli.current());++mnli)
7573   {
7574     MemberDef *md;
7575     MemberNameIterator mni(*mn);
7576     // for each member definition
7577     for (mni.toFirst();(md=mni.current());++mni)
7578     {
7579       addClassMemberNameToIndex(md);
7580     }
7581   }
7582   MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict);
7583   // for each member name
7584   for (fnli.toFirst();(mn=fnli.current());++fnli)
7585   {
7586     MemberDef *md;
7587     MemberNameIterator mni(*mn);
7588     // for each member definition
7589     for (mni.toFirst();(md=mni.current());++mni)
7590     {
7591       if (md->getNamespaceDef())
7592       {
7593         addNamespaceMemberNameToIndex(md);
7594       }
7595       else
7596       {
7597         addFileMemberNameToIndex(md);
7598       }
7599     }
7600   }
7601 }
7602
7603 //----------------------------------------------------------------------
7604 // computes the relation between all members. For each member `m'
7605 // the members that override the implementation of `m' are searched and
7606 // the member that `m' overrides is searched.
7607
7608 static void computeMemberRelations()
7609 {
7610   MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
7611   MemberName *mn;
7612   for ( ; (mn=mnli.current()) ; ++mnli ) // for each member name
7613   {
7614     MemberNameIterator mdi(*mn);
7615     MemberNameIterator bmdi(*mn);
7616     MemberDef *md;
7617     MemberDef *bmd;
7618     for ( ; (md=mdi.current()) ; ++mdi ) // for each member with a specific name
7619     {
7620       for ( bmdi.toFirst() ; (bmd=bmdi.current()); ++bmdi ) // for each other member with the same name
7621       {
7622         ClassDef *mcd  = md->getClassDef();
7623         if (mcd && mcd->baseClasses())
7624         {
7625           ClassDef *bmcd = bmd->getClassDef();
7626           //printf("Check relation between `%s'::`%s' (%p) and `%s'::`%s' (%p)\n",
7627           //      mcd->name().data(),md->name().data(),md,
7628           //       bmcd->name().data(),bmd->name().data(),bmd
7629           //      );
7630           if (md!=bmd && bmcd && mcd && bmcd!=mcd &&
7631               (bmd->virtualness()!=Normal || 
7632                bmcd->compoundType()==ClassDef::Interface || 
7633                bmcd->compoundType()==ClassDef::Protocol
7634               ) &&
7635               md->isFunction() && 
7636               mcd->isLinkable() && 
7637               bmcd->isLinkable() &&
7638               mcd->isBaseClass(bmcd,TRUE))
7639           {
7640             //printf("  derived scope\n");
7641             ArgumentList *bmdAl = bmd->argumentList();
7642             ArgumentList *mdAl =  md->argumentList();
7643             //printf(" Base argList=`%s'\n Super argList=`%s'\n",
7644             //        argListToString(bmdAl.pointer()).data(),
7645             //        argListToString(mdAl.pointer()).data()
7646             //      );
7647             if ( 
7648                 matchArguments2(bmd->getOuterScope(),bmd->getFileDef(),bmdAl,
7649                   md->getOuterScope(), md->getFileDef(), mdAl,
7650                   TRUE
7651                   ) 
7652                )
7653             {
7654               MemberDef *rmd;
7655               if ((rmd=md->reimplements())==0 ||
7656                   minClassDistance(mcd,bmcd)<minClassDistance(mcd,rmd->getClassDef())
7657                  )
7658               {
7659                 //printf("setting (new) reimplements member\n");
7660                 md->setReimplements(bmd);
7661               }
7662               //printf("%s: add reimplementedBy member %s\n",bmcd->name().data(),mcd->name().data());
7663               bmd->insertReimplementedBy(md);
7664             }
7665           }
7666         }
7667       }
7668     }
7669   }
7670 }
7671
7672
7673 //----------------------------------------------------------------------------
7674 //static void computeClassImplUsageRelations()
7675 //{
7676 //  ClassDef *cd;
7677 //  ClassSDict::Iterator cli(*Doxygen::classSDict);
7678 //  for (;(cd=cli.current());++cli)
7679 //  {
7680 //    cd->determineImplUsageRelation();
7681 //  }
7682 //}
7683
7684 //----------------------------------------------------------------------------
7685
7686 static void createTemplateInstanceMembers()
7687 {
7688   ClassSDict::Iterator cli(*Doxygen::classSDict);
7689   ClassDef *cd;
7690   // for each class
7691   for (cli.toFirst();(cd=cli.current());++cli)
7692   {
7693     // that is a template
7694     QDict<ClassDef> *templInstances = cd->getTemplateInstances();
7695     if (templInstances)
7696     {
7697       QDictIterator<ClassDef> qdi(*templInstances);
7698       ClassDef *tcd=0;
7699       // for each instance of the template
7700       for (qdi.toFirst();(tcd=qdi.current());++qdi)
7701       {
7702         tcd->addMembersToTemplateInstance(cd,qdi.currentKey());
7703       }
7704     }
7705   }
7706 }
7707
7708 //----------------------------------------------------------------------------
7709
7710 static void mergeCategories()
7711 {
7712   ClassDef *cd;
7713   ClassSDict::Iterator cli(*Doxygen::classSDict);
7714   // merge members of categories into the class they extend
7715   for (cli.toFirst();(cd=cli.current());++cli)
7716   {
7717     int i=cd->name().find('(');
7718     if (i!=-1) // it is an Objective-C category
7719     {
7720       QCString baseName=cd->name().left(i);
7721       ClassDef *baseClass=Doxygen::classSDict->find(baseName);
7722       if (baseClass)
7723       {
7724         //printf("*** merging members of category %s into %s\n",
7725         //    cd->name().data(),baseClass->name().data());
7726         baseClass->mergeCategory(cd);
7727       }
7728     }
7729   }
7730 }
7731
7732 // builds the list of all members for each class
7733
7734 static void buildCompleteMemberLists()
7735 {
7736   ClassDef *cd;
7737   ClassSDict::Iterator cli(*Doxygen::classSDict);
7738   // merge the member list of base classes into the inherited classes.
7739   for (cli.toFirst();(cd=cli.current());++cli)
7740   {
7741     if (// !cd->isReference() && // not an external class
7742          cd->subClasses()==0 && // is a root of the hierarchy
7743          cd->baseClasses()) // and has at least one base class
7744     {
7745       //printf("*** merging members for %s\n",cd->name().data());
7746       cd->mergeMembers();
7747     }
7748   }
7749   // now sort the member list of all classes.
7750   for (cli.toFirst();(cd=cli.current());++cli)
7751   {
7752     if (cd->memberNameInfoSDict()) cd->memberNameInfoSDict()->sort();
7753   }
7754 }
7755
7756 //----------------------------------------------------------------------------
7757
7758 static void generateFileSources()
7759 {
7760   if (Doxygen::inputNameList->count()>0)
7761   {
7762 #if USE_LIBCLANG
7763     static bool clangAssistedParsing = Config_getBool("CLANG_ASSISTED_PARSING");
7764     if (clangAssistedParsing)
7765     {
7766       QDict<void> g_processedFiles(10007);
7767
7768       // create a dictionary with files to process
7769       QDict<void> g_filesToProcess(10007);
7770       FileNameListIterator fnli(*Doxygen::inputNameList); 
7771       FileName *fn;
7772       for (fnli.toFirst();(fn=fnli.current());++fnli)
7773       {
7774         FileNameIterator fni(*fn);
7775         FileDef *fd;
7776         for (;(fd=fni.current());++fni)
7777         {
7778           g_filesToProcess.insert(fd->absFilePath(),(void*)0x8);
7779         }
7780       }
7781       // process source files (and their include dependencies)
7782       for (fnli.toFirst();(fn=fnli.current());++fnli)
7783       {
7784         FileNameIterator fni(*fn);
7785         FileDef *fd;
7786         for (;(fd=fni.current());++fni)
7787         {
7788           if (fd->isSource() && !fd->isReference())
7789           {
7790             QStrList filesInSameTu;
7791             fd->getAllIncludeFilesRecursively(filesInSameTu);
7792             fd->startParsing();
7793             if (fd->generateSourceFile()) // sources need to be shown in the output
7794             {
7795               msg("Generating code for file %s...\n",fd->docName().data());
7796               fd->writeSource(*g_outputList,FALSE,filesInSameTu);
7797
7798             }
7799             else if (!fd->isReference() && Doxygen::parseSourcesNeeded)
7800               // we needed to parse the sources even if we do not show them
7801             {
7802               msg("Parsing code for file %s...\n",fd->docName().data());
7803               fd->parseSource(FALSE,filesInSameTu);
7804             }
7805
7806             char *incFile = filesInSameTu.first();
7807             while (incFile && g_filesToProcess.find(incFile))
7808             {
7809               if (fd->absFilePath()!=incFile && !g_processedFiles.find(incFile))
7810               {
7811                 QStrList moreFiles;
7812                 bool ambig;
7813                 FileDef *ifd=findFileDef(Doxygen::inputNameDict,incFile,ambig);
7814                 if (ifd && !ifd->isReference())
7815                 {
7816                   if (ifd->generateSourceFile()) // sources need to be shown in the output
7817                   {
7818                     msg(" Generating code for file %s...\n",ifd->docName().data());
7819                     ifd->writeSource(*g_outputList,TRUE,moreFiles);
7820
7821                   }
7822                   else if (!ifd->isReference() && Doxygen::parseSourcesNeeded)
7823                     // we needed to parse the sources even if we do not show them
7824                   {
7825                     msg(" Parsing code for file %s...\n",ifd->docName().data());
7826                     ifd->parseSource(TRUE,moreFiles);
7827                   }
7828                   g_processedFiles.insert(incFile,(void*)0x8);
7829                 }
7830               }
7831               incFile = filesInSameTu.next();
7832             }
7833             fd->finishParsing();
7834             g_processedFiles.insert(fd->absFilePath(),(void*)0x8);
7835           }
7836         }
7837       }
7838       // process remaining files
7839       for (fnli.toFirst();(fn=fnli.current());++fnli)
7840       {
7841         FileNameIterator fni(*fn);
7842         FileDef *fd;
7843         for (;(fd=fni.current());++fni)
7844         {
7845           if (!g_processedFiles.find(fd->absFilePath())) // not yet processed
7846           {
7847             QStrList filesInSameTu;
7848             fd->startParsing();
7849             if (fd->generateSourceFile()) // sources need to be shown in the output
7850             {
7851               msg("Generating code for file %s...\n",fd->docName().data());
7852               fd->writeSource(*g_outputList,FALSE,filesInSameTu);
7853
7854             }
7855             else if (!fd->isReference() && Doxygen::parseSourcesNeeded)
7856               // we needed to parse the sources even if we do not show them
7857             {
7858               msg("Parsing code for file %s...\n",fd->docName().data());
7859               fd->parseSource(FALSE,filesInSameTu);
7860             }
7861             fd->finishParsing();
7862           }
7863         }
7864       }
7865     }
7866     else
7867 #endif
7868     {
7869       FileNameListIterator fnli(*Doxygen::inputNameList); 
7870       FileName *fn;
7871       for (;(fn=fnli.current());++fnli)
7872       {
7873         FileNameIterator fni(*fn);
7874         FileDef *fd;
7875         for (;(fd=fni.current());++fni)
7876         {
7877           QStrList filesInSameTu;
7878           fd->startParsing();
7879           if (fd->generateSourceFile()) // sources need to be shown in the output
7880           {
7881             msg("Generating code for file %s...\n",fd->docName().data());
7882             fd->writeSource(*g_outputList,FALSE,filesInSameTu);
7883
7884           }
7885           else if (!fd->isReference() && Doxygen::parseSourcesNeeded)
7886             // we needed to parse the sources even if we do not show them
7887           {
7888             msg("Parsing code for file %s...\n",fd->docName().data());
7889             fd->parseSource(FALSE,filesInSameTu);
7890           }
7891           fd->finishParsing();
7892         }
7893       }
7894     }
7895   }
7896 }
7897
7898 //----------------------------------------------------------------------------
7899
7900 static void generateFileDocs()
7901 {
7902   if (documentedHtmlFiles==0) return;
7903   
7904   if (Doxygen::inputNameList->count()>0)
7905   {
7906     FileNameListIterator fnli(*Doxygen::inputNameList);
7907     FileName *fn;
7908     for (fnli.toFirst();(fn=fnli.current());++fnli)
7909     {
7910       FileNameIterator fni(*fn);
7911       FileDef *fd;
7912       for (fni.toFirst();(fd=fni.current());++fni)
7913       {
7914         bool doc = fd->isLinkableInProject();
7915         if (doc)
7916         {
7917           msg("Generating docs for file %s...\n",fd->docName().data());
7918           fd->writeDocumentation(*g_outputList);
7919         }
7920       }
7921     }
7922   }
7923 }
7924
7925 //----------------------------------------------------------------------------
7926
7927 static void addSourceReferences()
7928 {
7929   // add source references for class definitions
7930   ClassSDict::Iterator cli(*Doxygen::classSDict);
7931   ClassDef *cd=0;
7932   for (cli.toFirst();(cd=cli.current());++cli)
7933   {
7934     FileDef *fd=cd->getBodyDef();
7935     if (fd && cd->isLinkableInProject() && cd->getStartBodyLine()!=-1)
7936     {
7937       fd->addSourceRef(cd->getStartBodyLine(),cd,0);
7938     }
7939   }
7940   // add source references for namespace definitions
7941   NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
7942   NamespaceDef *nd=0;
7943   for (nli.toFirst();(nd=nli.current());++nli)
7944   {
7945     FileDef *fd=nd->getBodyDef();
7946     if (fd && nd->isLinkableInProject() && nd->getStartBodyLine()!=-1)
7947     {
7948       fd->addSourceRef(nd->getStartBodyLine(),nd,0);
7949     }
7950   }
7951   
7952   // add source references for member names
7953   MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
7954   MemberName *mn=0;
7955   for (mnli.toFirst();(mn=mnli.current());++mnli)
7956   {
7957     MemberNameIterator mni(*mn);
7958     MemberDef *md=0;
7959     for (mni.toFirst();(md=mni.current());++mni)
7960     {
7961       //printf("class member %s: def=%s body=%d link?=%d\n",
7962       //    md->name().data(),
7963       //    md->getBodyDef()?md->getBodyDef()->name().data():"<none>",
7964       //    md->getStartBodyLine(),md->isLinkableInProject());
7965       FileDef *fd=md->getBodyDef();
7966       if (fd && 
7967           md->getStartBodyLine()!=-1 &&
7968           md->isLinkableInProject() &&
7969           (fd->generateSourceFile() || Doxygen::parseSourcesNeeded)
7970          )
7971       {
7972         //printf("Found member `%s' in file `%s' at line `%d' def=%s\n",
7973         //    md->name().data(),fd->name().data(),md->getStartBodyLine(),md->getOuterScope()->name().data()); 
7974         fd->addSourceRef(md->getStartBodyLine(),md->getOuterScope(),md);
7975       }
7976     }
7977   }
7978   MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict);
7979   for (fnli.toFirst();(mn=fnli.current());++fnli)
7980   {
7981     MemberNameIterator mni(*mn);
7982     MemberDef *md=0;
7983     for (mni.toFirst();(md=mni.current());++mni)
7984     {
7985       FileDef *fd=md->getBodyDef();
7986       //printf("member %s body=[%d,%d] fd=%p link=%d parseSources=%d\n",
7987       //    md->name().data(),
7988       //    md->getStartBodyLine(),md->getEndBodyLine(),fd,
7989       //    md->isLinkableInProject(),
7990       //    Doxygen::parseSourcesNeeded);
7991       if (fd && 
7992           md->getStartBodyLine()!=-1 && 
7993           md->isLinkableInProject() && 
7994           (fd->generateSourceFile() || Doxygen::parseSourcesNeeded)
7995          )
7996       {
7997         //printf("Found member `%s' in file `%s' at line `%d' def=%s\n",
7998         //    md->name().data(),fd->name().data(),md->getStartBodyLine(),md->getOuterScope()->name().data()); 
7999         fd->addSourceRef(md->getStartBodyLine(),md->getOuterScope(),md);
8000       }  
8001     }
8002   }
8003 }
8004
8005 //----------------------------------------------------------------------------
8006
8007 static void sortMemberLists()
8008 {
8009   // sort class member lists
8010   ClassSDict::Iterator cli(*Doxygen::classSDict);
8011   ClassDef *cd=0;
8012   for (cli.toFirst();(cd=cli.current());++cli)
8013   {
8014     cd->sortMemberLists();
8015   }
8016
8017   // sort namespace member lists
8018   NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
8019   NamespaceDef *nd=0;
8020   for (nli.toFirst();(nd=nli.current());++nli)
8021   {
8022     nd->sortMemberLists();
8023   }
8024
8025   // sort file member lists
8026   FileNameListIterator fnli(*Doxygen::inputNameList); 
8027   FileName *fn;
8028   for (;(fn=fnli.current());++fnli)
8029   {
8030     FileNameIterator fni(*fn);
8031     FileDef *fd;
8032     for (;(fd=fni.current());++fni)
8033     {
8034       fd->sortMemberLists();
8035     }
8036   }
8037
8038   // sort group member lists
8039   GroupSDict::Iterator gli(*Doxygen::groupSDict);
8040   GroupDef *gd;
8041   for (gli.toFirst();(gd=gli.current());++gli)
8042   {
8043     gd->sortMemberLists();
8044   }
8045 }
8046
8047 //----------------------------------------------------------------------------
8048 // generate the documentation of all classes
8049   
8050 static void generateClassList(ClassSDict &classSDict)
8051 {
8052   ClassSDict::Iterator cli(classSDict);
8053   for ( ; cli.current() ; ++cli )
8054   {
8055     ClassDef *cd=cli.current();
8056    
8057     //printf("cd=%s getOuterScope=%p global=%p\n",cd->name().data(),cd->getOuterScope(),Doxygen::globalScope);
8058     if ((cd->getOuterScope()==0 || // <-- should not happen, but can if we read an old tag file
8059          cd->getOuterScope()==Doxygen::globalScope // only look at global classes
8060         ) && !cd->isHidden() && !cd->isEmbeddedInOuterScope()
8061        ) 
8062     {
8063       // skip external references, anonymous compounds and 
8064       // template instances 
8065       if ( cd->isLinkableInProject() && cd->templateMaster()==0)
8066       {
8067         msg("Generating docs for compound %s...\n",cd->name().data());
8068
8069         cd->writeDocumentation(*g_outputList);
8070         cd->writeMemberList(*g_outputList);
8071       }
8072       // even for undocumented classes, the inner classes can be documented.
8073       cd->writeDocumentationForInnerClasses(*g_outputList);
8074     }
8075   }
8076 }
8077
8078 static void generateClassDocs()
8079 {
8080   generateClassList(*Doxygen::classSDict);
8081   generateClassList(*Doxygen::hiddenClasses);
8082 }
8083
8084 //----------------------------------------------------------------------------
8085
8086 static void inheritDocumentation()
8087 {
8088   MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
8089   MemberName *mn;
8090   //int count=0;
8091   for (;(mn=mnli.current());++mnli)
8092   {
8093     MemberNameIterator mni(*mn);
8094     MemberDef *md;
8095     for (;(md=mni.current());++mni)
8096     {
8097       //printf("%04d Member `%s'\n",count++,md->name().data());
8098       if (md->documentation().isEmpty() && md->briefDescription().isEmpty())
8099       { // no documentation yet
8100         MemberDef *bmd = md->reimplements();
8101         while (bmd && bmd->documentation().isEmpty() && 
8102                       bmd->briefDescription().isEmpty()
8103               )
8104         { // search up the inheritance tree for a documentation member
8105           //printf("bmd=%s class=%s\n",bmd->name().data(),bmd->getClassDef()->name().data());
8106           bmd = bmd->reimplements();
8107         }
8108         if (bmd) // copy the documentation from the reimplemented member
8109         {
8110           md->setInheritsDocsFrom(bmd);
8111           md->setDocumentation(bmd->documentation(),bmd->docFile(),bmd->docLine());
8112           md->setDocsForDefinition(bmd->isDocsForDefinition());
8113           md->setBriefDescription(bmd->briefDescription(),bmd->briefFile(),bmd->briefLine());
8114           md->copyArgumentNames(bmd);
8115           md->setInbodyDocumentation(bmd->inbodyDocumentation(),bmd->inbodyFile(),bmd->inbodyLine());
8116         }
8117       }
8118     }
8119   }
8120 }
8121
8122 //----------------------------------------------------------------------------
8123
8124 static void combineUsingRelations()
8125 {
8126   // for each file
8127   FileNameListIterator fnli(*Doxygen::inputNameList);
8128   FileName *fn;
8129   for (fnli.toFirst();(fn=fnli.current());++fnli)
8130   {
8131     FileNameIterator fni(*fn);
8132     FileDef *fd;
8133     for (fni.toFirst();(fd=fni.current());++fni)
8134     {
8135       fd->visited=FALSE;
8136     }
8137   }
8138   for (fnli.toFirst();(fn=fnli.current());++fnli)
8139   {
8140     FileNameIterator fni(*fn);
8141     FileDef *fd;
8142     for (fni.toFirst();(fd=fni.current());++fni)
8143     {
8144       fd->combineUsingRelations();
8145     }
8146   }
8147
8148   // for each namespace
8149   NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
8150   NamespaceDef *nd;
8151   for (nli.toFirst() ; (nd=nli.current()) ; ++nli )
8152   {
8153     nd->visited=FALSE;
8154   }
8155   for (nli.toFirst() ; (nd=nli.current()) ; ++nli )
8156   {
8157     nd->combineUsingRelations();
8158   }
8159 }
8160
8161 //----------------------------------------------------------------------------
8162   
8163 static void addMembersToMemberGroup()
8164 {
8165   // for each class
8166   ClassSDict::Iterator cli(*Doxygen::classSDict);
8167   ClassDef *cd;
8168   for ( ; (cd=cli.current()) ; ++cli )
8169   {
8170     cd->addMembersToMemberGroup();
8171   }
8172   // for each file
8173   FileNameListIterator fnli(*Doxygen::inputNameList);
8174   FileName *fn;
8175   for (fnli.toFirst();(fn=fnli.current());++fnli)
8176   {
8177     FileNameIterator fni(*fn);
8178     FileDef *fd;
8179     for (fni.toFirst();(fd=fni.current());++fni)
8180     {
8181       fd->addMembersToMemberGroup();
8182     }
8183   }
8184   // for each namespace
8185   NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
8186   NamespaceDef *nd;
8187   for ( ; (nd=nli.current()) ; ++nli )
8188   {
8189     nd->addMembersToMemberGroup();
8190   }
8191   // for each group
8192   GroupSDict::Iterator gli(*Doxygen::groupSDict);
8193   GroupDef *gd;
8194   for (gli.toFirst();(gd=gli.current());++gli)
8195   {
8196     gd->addMembersToMemberGroup();
8197   }
8198 }
8199
8200 //----------------------------------------------------------------------------
8201
8202 static void distributeMemberGroupDocumentation()
8203 {
8204   // for each class
8205   ClassSDict::Iterator cli(*Doxygen::classSDict);
8206   ClassDef *cd;
8207   for ( ; (cd=cli.current()) ; ++cli )
8208   {
8209     cd->distributeMemberGroupDocumentation();
8210   }
8211   // for each file
8212   FileNameListIterator fnli(*Doxygen::inputNameList);
8213   FileName *fn;
8214   for (fnli.toFirst();(fn=fnli.current());++fnli)
8215   {
8216     FileNameIterator fni(*fn);
8217     FileDef *fd;
8218     for (fni.toFirst();(fd=fni.current());++fni)
8219     {
8220       fd->distributeMemberGroupDocumentation();
8221     }
8222   }
8223   // for each namespace
8224   NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
8225   NamespaceDef *nd;
8226   for ( ; (nd=nli.current()) ; ++nli )
8227   {
8228     nd->distributeMemberGroupDocumentation();
8229   }
8230   // for each group
8231   GroupSDict::Iterator gli(*Doxygen::groupSDict);
8232   GroupDef *gd;
8233   for (gli.toFirst();(gd=gli.current());++gli)
8234   {
8235     gd->distributeMemberGroupDocumentation();
8236   }
8237 }
8238
8239 //----------------------------------------------------------------------------
8240
8241 static void findSectionsInDocumentation()
8242 {
8243   // for each class
8244   ClassSDict::Iterator cli(*Doxygen::classSDict);
8245   ClassDef *cd;
8246   for ( ; (cd=cli.current()) ; ++cli )
8247   {
8248     cd->findSectionsInDocumentation();
8249   }
8250   // for each file
8251   FileNameListIterator fnli(*Doxygen::inputNameList);
8252   FileName *fn;
8253   for (fnli.toFirst();(fn=fnli.current());++fnli)
8254   {
8255     FileNameIterator fni(*fn);
8256     FileDef *fd;
8257     for (fni.toFirst();(fd=fni.current());++fni)
8258     {
8259       fd->findSectionsInDocumentation();
8260     }
8261   }
8262   // for each namespace
8263   NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
8264   NamespaceDef *nd;
8265   for ( ; (nd=nli.current()) ; ++nli )
8266   {
8267     nd->findSectionsInDocumentation();
8268   }
8269   // for each group
8270   GroupSDict::Iterator gli(*Doxygen::groupSDict);
8271   GroupDef *gd;
8272   for (gli.toFirst();(gd=gli.current());++gli)
8273   {
8274     gd->findSectionsInDocumentation();
8275   }
8276   // for each page
8277   PageSDict::Iterator pdi(*Doxygen::pageSDict);
8278   PageDef *pd=0;
8279   for (pdi.toFirst();(pd=pdi.current());++pdi)
8280   {
8281     pd->findSectionsInDocumentation();
8282   }
8283   if (Doxygen::mainPage) Doxygen::mainPage->findSectionsInDocumentation();
8284 }
8285
8286 static void flushCachedTemplateRelations()
8287 {
8288   // remove all references to classes from the cache
8289   // as there can be new template instances in the inheritance path
8290   // to this class. Optimization: only remove those classes that
8291   // have inheritance instances as direct or indirect sub classes.
8292   QCacheIterator<LookupInfo> ci(*Doxygen::lookupCache);
8293   LookupInfo *li=0;
8294   for (ci.toFirst();(li=ci.current());++ci)
8295   {
8296     if (li->classDef)
8297     {
8298       Doxygen::lookupCache->remove(ci.currentKey());
8299     }
8300   }
8301   // remove all cached typedef resolutions whose target is a
8302   // template class as this may now be a template instance
8303   MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict);
8304   MemberName *fn;
8305   for (;(fn=fnli.current());++fnli) // for each global function name
8306   {
8307     MemberNameIterator fni(*fn);
8308     MemberDef *fmd;
8309     for (;(fmd=fni.current());++fni) // for each function with that name
8310     {
8311       if (fmd->isTypedefValCached())
8312       {
8313         ClassDef *cd = fmd->getCachedTypedefVal();
8314         if (cd->isTemplate()) fmd->invalidateTypedefValCache();
8315       }
8316     }
8317   }
8318   MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
8319   for (;(fn=mnli.current());++mnli) // for each class method name
8320   {
8321     MemberNameIterator mni(*fn);
8322     MemberDef *fmd;
8323     for (;(fmd=mni.current());++mni) // for each function with that name
8324     {
8325       if (fmd->isTypedefValCached())
8326       {
8327         ClassDef *cd = fmd->getCachedTypedefVal();
8328         if (cd->isTemplate()) fmd->invalidateTypedefValCache();
8329       }
8330     }
8331   }
8332 }
8333
8334 //----------------------------------------------------------------------------
8335
8336 static void flushUnresolvedRelations()
8337 {
8338   // Remove all unresolved references to classes from the cache.
8339   // This is needed before resolving the inheritance relations, since
8340   // it would otherwise not find the inheritance relation
8341   // for C in the example below, as B::I was already found to be unresolvable 
8342   // (which is correct if you igore the inheritance relation between A and B).
8343   // 
8344   // class A { class I {} };
8345   // class B : public A {};
8346   // class C : public B::I {};
8347   //
8348   QCacheIterator<LookupInfo> ci(*Doxygen::lookupCache);
8349   LookupInfo *li=0;
8350   for (ci.toFirst();(li=ci.current());++ci)
8351   {
8352     if (li->classDef==0 && li->typeDef==0)
8353     {
8354       Doxygen::lookupCache->remove(ci.currentKey());
8355     }
8356   }
8357
8358   MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict);
8359   MemberName *fn;
8360   for (;(fn=fnli.current());++fnli) // for each global function name
8361   {
8362     MemberNameIterator fni(*fn);
8363     MemberDef *fmd;
8364     for (;(fmd=fni.current());++fni) // for each function with that name
8365     {
8366       fmd->invalidateCachedArgumentTypes();
8367     }
8368   }
8369   MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
8370   for (;(fn=mnli.current());++mnli) // for each class method name
8371   {
8372     MemberNameIterator mni(*fn);
8373     MemberDef *fmd;
8374     for (;(fmd=mni.current());++mni) // for each function with that name
8375     {
8376       fmd->invalidateCachedArgumentTypes();
8377     }
8378   }
8379
8380 }
8381
8382 //----------------------------------------------------------------------------
8383
8384 static void findDefineDocumentation(EntryNav *rootNav)
8385 {
8386   if ((rootNav->section()==Entry::DEFINEDOC_SEC ||
8387        rootNav->section()==Entry::DEFINE_SEC) && !rootNav->name().isEmpty()
8388      )
8389   {
8390     rootNav->loadEntry(g_storage);
8391     Entry *root = rootNav->entry();
8392     
8393     //printf("found define `%s' `%s' brief=`%s' doc=`%s'\n",
8394     //       root->name.data(),root->args.data(),root->brief.data(),root->doc.data());
8395
8396     if (rootNav->tagInfo() && !root->name.isEmpty()) // define read from a tag file
8397     {
8398       MemberDef *md=new MemberDef("<tagfile>",1,1,
8399                     "#define",root->name,root->args,0,
8400                     Public,Normal,FALSE,Member,MemberType_Define,0,0);
8401       md->setTagInfo(rootNav->tagInfo());
8402       md->setLanguage(root->lang);
8403       //printf("Searching for `%s' fd=%p\n",filePathName.data(),fd);
8404       md->setFileDef(rootNav->parent()->fileDef());
8405       //printf("Adding member=%s\n",md->name().data());
8406       MemberName *mn;
8407       if ((mn=Doxygen::functionNameSDict->find(root->name)))
8408       {
8409         mn->append(md);
8410       }
8411       else 
8412       {
8413         mn = new MemberName(root->name);
8414         mn->append(md);
8415         Doxygen::functionNameSDict->append(root->name,mn);
8416       }
8417     }
8418     MemberName *mn=Doxygen::functionNameSDict->find(root->name);
8419     if (mn)
8420     {
8421       MemberNameIterator mni(*mn);
8422       MemberDef *md;
8423       int count=0;
8424       for (;(md=mni.current());++mni)
8425       {
8426         if (md->memberType()==MemberType_Define) count++;
8427       }
8428       if (count==1)
8429       {
8430         for (mni.toFirst();(md=mni.current());++mni)
8431         {
8432           if (md->memberType()==MemberType_Define)
8433           {
8434             md->setDocumentation(root->doc,root->docFile,root->docLine);
8435             md->setDocsForDefinition(!root->proto);
8436             md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
8437             if (md->inbodyDocumentation().isEmpty())
8438             {
8439               md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
8440             }
8441             md->setBodySegment(root->bodyLine,root->endBodyLine);
8442             md->setBodyDef(rootNav->fileDef());
8443             md->addSectionsToDefinition(root->anchors);
8444             md->setMaxInitLines(root->initLines);
8445             md->setRefItems(root->sli);
8446             if (root->mGrpId!=-1) md->setMemberGroupId(root->mGrpId);
8447             addMemberToGroups(root,md);
8448           }
8449         }
8450       }
8451       else if (count>1 &&
8452                (!root->doc.isEmpty() ||
8453                 !root->brief.isEmpty() ||
8454                 root->bodyLine!=-1
8455                )
8456               )
8457         // multiple defines don't know where to add docs
8458         // but maybe they are in different files together with their documentation
8459       {
8460         for (mni.toFirst();(md=mni.current());++mni)
8461         {
8462           if (md->memberType()==MemberType_Define)
8463           {
8464             FileDef *fd=md->getFileDef();
8465             if (fd && fd->absFilePath()==root->fileName) 
8466               // doc and define in the same file assume they belong together.
8467             {
8468 #if 0
8469               if (md->documentation().isEmpty())
8470 #endif
8471               {
8472                 md->setDocumentation(root->doc,root->docFile,root->docLine);
8473                 md->setDocsForDefinition(!root->proto);
8474               }
8475 #if 0
8476               if (md->briefDescription().isEmpty())
8477 #endif
8478               {
8479                 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
8480               }
8481               if (md->inbodyDocumentation().isEmpty())
8482               {
8483                 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
8484               }
8485               md->setBodySegment(root->bodyLine,root->endBodyLine);
8486               md->setBodyDef(rootNav->fileDef());
8487               md->addSectionsToDefinition(root->anchors);
8488               md->setRefItems(root->sli);
8489               md->setLanguage(root->lang);
8490               if (root->mGrpId!=-1) md->setMemberGroupId(root->mGrpId);
8491               addMemberToGroups(root,md);
8492             }
8493           }
8494         }
8495         //warn("define %s found in the following files:\n",root->name.data());
8496         //warn("Cannot determine where to add the documentation found "
8497         //     "at line %d of file %s. \n",
8498         //     root->startLine,root->fileName.data());
8499       }
8500     }
8501     else if (!root->doc.isEmpty() || !root->brief.isEmpty()) // define not found
8502     {
8503       static bool preEnabled = Config_getBool("ENABLE_PREPROCESSING");
8504       if (preEnabled)
8505       {
8506         warn(root->fileName,root->startLine,
8507              "documentation for unknown define %s found.\n",
8508              root->name.data()
8509             );
8510       }
8511       else
8512       {
8513         warn(root->fileName,root->startLine,
8514              "found documented #define but ignoring it because "
8515              "ENABLE_PREPROCESSING is NO.\n",
8516              root->name.data()
8517             );
8518       }
8519     }
8520
8521     rootNav->releaseEntry();
8522   }
8523   RECURSE_ENTRYTREE(findDefineDocumentation,rootNav);
8524 }
8525
8526 //----------------------------------------------------------------------------
8527
8528 static void findDirDocumentation(EntryNav *rootNav)
8529 {
8530   if (rootNav->section() == Entry::DIRDOC_SEC)
8531   {
8532     rootNav->loadEntry(g_storage);
8533     Entry *root = rootNav->entry();
8534
8535     QCString normalizedName = root->name;
8536     normalizedName = substitute(normalizedName,"\\","/");
8537     //printf("root->docFile=%s normalizedName=%s\n",
8538     //    root->docFile.data(),normalizedName.data());
8539     if (root->docFile==normalizedName) // current dir?
8540     {
8541       int lastSlashPos=normalizedName.findRev('/'); 
8542       if (lastSlashPos!=-1) // strip file name
8543       {
8544         normalizedName=normalizedName.left(lastSlashPos);
8545       }
8546     }
8547     if (normalizedName.at(normalizedName.length()-1)!='/')
8548     {
8549       normalizedName+='/';
8550     }
8551     DirDef *dir,*matchingDir=0;
8552     SDict<DirDef>::Iterator sdi(*Doxygen::directories);
8553     for (sdi.toFirst();(dir=sdi.current());++sdi)
8554     {
8555       //printf("Dir: %s<->%s\n",dir->name().data(),normalizedName.data());
8556       if (dir->name().right(normalizedName.length())==normalizedName)
8557       {
8558         if (matchingDir)
8559         {
8560            warn(root->fileName,root->startLine,
8561              "\\dir command matches multiple directories.\n"
8562              "  Applying the command for directory %s\n"
8563              "  Ignoring the command for directory %s\n",
8564              matchingDir->name().data(),dir->name().data()
8565            );
8566         }
8567         else
8568         {
8569           matchingDir=dir;
8570         }
8571       }
8572     }
8573     if (matchingDir)
8574     {
8575       //printf("Match for with dir %s\n",matchingDir->name().data());
8576       matchingDir->setBriefDescription(root->brief,root->briefFile,root->briefLine);
8577       matchingDir->setDocumentation(root->doc,root->docFile,root->docLine);
8578       matchingDir->setRefItems(root->sli);
8579       addDirToGroups(root,matchingDir);
8580     }
8581     else
8582     {
8583       warn(root->fileName,root->startLine,"No matching "
8584           "directory found for command \\dir %s\n",normalizedName.data());
8585     }
8586     rootNav->releaseEntry();
8587   }
8588   RECURSE_ENTRYTREE(findDirDocumentation,rootNav);
8589 }
8590
8591
8592 //----------------------------------------------------------------------------
8593 // create a (sorted) list of separate documentation pages
8594
8595 static void buildPageList(EntryNav *rootNav)
8596 {
8597   if (rootNav->section() == Entry::PAGEDOC_SEC)
8598   {
8599     rootNav->loadEntry(g_storage);
8600     Entry *root = rootNav->entry();
8601
8602     if (!root->name.isEmpty())
8603     {
8604       addRelatedPage(rootNav);
8605     }
8606
8607     rootNav->releaseEntry();
8608   }
8609   else if (rootNav->section() == Entry::MAINPAGEDOC_SEC)
8610   {
8611     rootNav->loadEntry(g_storage);
8612     Entry *root = rootNav->entry();
8613
8614     QCString title=root->args.stripWhiteSpace();
8615     if (title.isEmpty()) title=theTranslator->trMainPage();
8616     //QCString name = Config_getBool("GENERATE_TREEVIEW")?"main":"index";
8617     QCString name = "index";
8618     addRefItem(root->sli,
8619                name,
8620                "page",
8621                name,
8622                title,
8623                0
8624                );
8625
8626     rootNav->releaseEntry();
8627   }
8628   RECURSE_ENTRYTREE(buildPageList,rootNav);
8629 }
8630
8631 // search for the main page defined in this project
8632 static void findMainPage(EntryNav *rootNav)
8633 {
8634   if (rootNav->section() == Entry::MAINPAGEDOC_SEC)
8635   {
8636     rootNav->loadEntry(g_storage);
8637
8638     if (Doxygen::mainPage==0 && rootNav->tagInfo()==0)
8639     {
8640       Entry *root = rootNav->entry();
8641       //printf("Found main page! \n======\n%s\n=======\n",root->doc.data());
8642       QCString title=root->args.stripWhiteSpace();
8643       //QCString indexName=Config_getBool("GENERATE_TREEVIEW")?"main":"index";
8644       QCString indexName="index";
8645       Doxygen::mainPage = new PageDef(root->docFile,root->docLine,
8646                               indexName, root->brief+root->doc+root->inbodyDocs,title);
8647       //setFileNameForSections(root->anchors,"index",Doxygen::mainPage);
8648       Doxygen::mainPage->setBriefDescription(root->brief,root->briefFile,root->briefLine);
8649       Doxygen::mainPage->setFileName(indexName,TRUE);
8650       Doxygen::mainPage->setShowToc(root->stat);
8651       addPageToContext(Doxygen::mainPage,rootNav);
8652
8653       SectionInfo *si = Doxygen::sectionDict->find(Doxygen::mainPage->name());
8654       if (si)
8655       {
8656         if (si->lineNr != -1)
8657         {
8658           warn(root->fileName,root->startLine,"multiple use of section label '%s' for main page, (first occurrence: %s, line %d)",Doxygen::mainPage->name().data(),si->fileName.data(),si->lineNr);
8659         }
8660         else
8661         {
8662           warn(root->fileName,root->startLine,"multiple use of section label '%s' for main page, (first occurrence: %s)",Doxygen::mainPage->name().data(),si->fileName.data());
8663         }
8664       }
8665       else
8666       {
8667         // a page name is a label as well! but should no be double either
8668         si=new SectionInfo(
8669           indexName, root->startLine,
8670           Doxygen::mainPage->name(),
8671           Doxygen::mainPage->title(),
8672           SectionInfo::Page,
8673           0); // level 0
8674         Doxygen::sectionDict->append(indexName,si);
8675         Doxygen::mainPage->addSectionsToDefinition(root->anchors);
8676       }
8677     }
8678     else if (rootNav->tagInfo()==0)
8679     {
8680       Entry *root = rootNav->entry();
8681       warn(root->fileName,root->startLine,
8682           "found more than one \\mainpage comment block! Skipping this "
8683           "block."
8684           );
8685     }
8686
8687     rootNav->releaseEntry();
8688   }
8689   RECURSE_ENTRYTREE(findMainPage,rootNav);
8690 }
8691
8692 // search for the main page imported via tag files and add only the section labels
8693 static void findMainPageTagFiles(EntryNav *rootNav)
8694 {
8695   if (rootNav->section() == Entry::MAINPAGEDOC_SEC)
8696   {
8697     rootNav->loadEntry(g_storage);
8698
8699     if (Doxygen::mainPage && rootNav->tagInfo())
8700     {
8701       Entry *root = rootNav->entry();
8702       Doxygen::mainPage->addSectionsToDefinition(root->anchors);
8703     }
8704   }
8705   RECURSE_ENTRYTREE(findMainPageTagFiles,rootNav);
8706 }
8707
8708 static void computePageRelations(EntryNav *rootNav)
8709 {
8710   if ((rootNav->section()==Entry::PAGEDOC_SEC || 
8711        rootNav->section()==Entry::MAINPAGEDOC_SEC
8712       )
8713       && !rootNav->name().isEmpty()
8714      )
8715   {
8716     rootNav->loadEntry(g_storage);
8717     Entry *root = rootNav->entry();
8718
8719     PageDef *pd = root->section==Entry::PAGEDOC_SEC ?
8720                     Doxygen::pageSDict->find(root->name) : 
8721                     Doxygen::mainPage; 
8722     if (pd)
8723     {
8724       QListIterator<BaseInfo> bii(*root->extends);
8725       BaseInfo *bi;
8726       for (bii.toFirst();(bi=bii.current());++bii)
8727       {
8728         PageDef *subPd = Doxygen::pageSDict->find(bi->name);
8729         if (subPd)
8730         {
8731           pd->addInnerCompound(subPd);
8732           //printf("*** Added subpage relation: %s->%s\n",
8733           //    pd->name().data(),subPd->name().data());
8734         }
8735       }
8736     }
8737
8738     rootNav->releaseEntry();
8739   }
8740   RECURSE_ENTRYTREE(computePageRelations,rootNav);
8741 }
8742
8743 static void checkPageRelations()
8744 {
8745   PageSDict::Iterator pdi(*Doxygen::pageSDict);
8746   PageDef *pd=0;
8747   for (pdi.toFirst();(pd=pdi.current());++pdi)
8748   {
8749     Definition *ppd = pd->getOuterScope();
8750     while (ppd)
8751     {
8752       if (ppd==pd)
8753       {
8754         err("page defined at line %d of file %s with label %s is a subpage "
8755             "of itself! Please remove this cyclic dependency.\n",
8756             pd->docLine(),pd->docFile().data(),pd->name().data());
8757         exit(1);
8758       }
8759       ppd=ppd->getOuterScope();
8760     }
8761   }
8762 }
8763
8764 //----------------------------------------------------------------------------
8765
8766 static void resolveUserReferences()
8767 {
8768   SDict<SectionInfo>::Iterator sdi(*Doxygen::sectionDict);
8769   SectionInfo *si;
8770   for (;(si=sdi.current());++sdi)
8771   {
8772     //printf("si->label=`%s' si->definition=%s si->fileName=`%s'\n",
8773     //        si->label.data(),si->definition?si->definition->name().data():"<none>",
8774     //        si->fileName.data());
8775     PageDef *pd=0;
8776
8777     // hack: the items of a todo/test/bug/deprecated list are all fragments from 
8778     // different files, so the resulting section's all have the wrong file 
8779     // name (not from the todo/test/bug/deprecated list, but from the file in 
8780     // which they are defined). We correct this here by looking at the 
8781     // generated section labels!
8782     QDictIterator<RefList> rli(*Doxygen::xrefLists);
8783     RefList *rl;
8784     for (rli.toFirst();(rl=rli.current());++rli)
8785     {
8786       QCString label="_"+rl->listName(); // "_todo", "_test", ...
8787       if (si->label.left(label.length())==label)
8788       {
8789         si->fileName=rl->listName();
8790         si->generated=TRUE;
8791         break;
8792       }
8793     }
8794
8795     //printf("start: si->label=%s si->fileName=%s\n",si->label.data(),si->fileName.data());
8796     if (!si->generated)
8797     {
8798       // if this section is in a page and the page is in a group, then we
8799       // have to adjust the link file name to point to the group.
8800       if (!si->fileName.isEmpty() && 
8801           (pd=Doxygen::pageSDict->find(si->fileName)) &&
8802           pd->getGroupDef())
8803       {
8804         si->fileName=pd->getGroupDef()->getOutputFileBase().copy();
8805       }
8806
8807       if (si->definition)
8808       {
8809         // TODO: there should be one function in Definition that returns
8810         // the file to link to, so we can avoid the following tests.
8811         GroupDef *gd=0;
8812         if (si->definition->definitionType()==Definition::TypeMember)
8813         {
8814           gd = ((MemberDef *)si->definition)->getGroupDef();
8815         }
8816
8817         if (gd)
8818         {
8819           si->fileName=gd->getOutputFileBase().copy();
8820         }
8821         else
8822         {
8823           //si->fileName=si->definition->getOutputFileBase().copy();
8824           //printf("Setting si->fileName to %s\n",si->fileName.data());
8825         }
8826       }
8827     }
8828     //printf("end: si->label=%s si->fileName=%s\n",si->label.data(),si->fileName.data());
8829   }
8830 }
8831
8832
8833
8834 //----------------------------------------------------------------------------
8835 // generate all separate documentation pages
8836
8837
8838 static void generatePageDocs()
8839 {
8840   //printf("documentedPages=%d real=%d\n",documentedPages,Doxygen::pageSDict->count());
8841   if (documentedPages==0) return;
8842   PageSDict::Iterator pdi(*Doxygen::pageSDict);
8843   PageDef *pd=0;
8844   for (pdi.toFirst();(pd=pdi.current());++pdi)
8845   {
8846     if (!pd->getGroupDef() && !pd->isReference())
8847     {
8848       msg("Generating docs for page %s...\n",pd->name().data());
8849       Doxygen::insideMainPage=TRUE;
8850       pd->writeDocumentation(*g_outputList);
8851       Doxygen::insideMainPage=FALSE;
8852     }
8853   }
8854 }
8855
8856 //----------------------------------------------------------------------------
8857 // create a (sorted) list & dictionary of example pages
8858
8859 static void buildExampleList(EntryNav *rootNav)
8860 {
8861   if (rootNav->section()==Entry::EXAMPLE_SEC && !rootNav->name().isEmpty()) 
8862   {
8863     rootNav->loadEntry(g_storage);
8864     Entry *root = rootNav->entry();
8865
8866     if (Doxygen::exampleSDict->find(root->name))
8867     {
8868       warn(root->fileName,root->startLine,
8869           "Example %s was already documented. Ignoring "
8870           "documentation found here.",
8871           root->name.data()
8872           );
8873     }
8874     else
8875     {
8876       PageDef *pd=new PageDef(root->fileName,root->startLine,
8877           root->name,root->brief+root->doc+root->inbodyDocs,root->args);
8878       pd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
8879       pd->setFileName(convertNameToFile(pd->name()+"-example",FALSE,TRUE),FALSE);
8880       pd->addSectionsToDefinition(root->anchors);
8881       pd->setLanguage(root->lang);
8882       //pi->addSections(root->anchors);
8883
8884       Doxygen::exampleSDict->inSort(root->name,pd);
8885       //we don't add example to groups 
8886       //addExampleToGroups(root,pd);
8887     }
8888
8889     rootNav->releaseEntry();
8890   }
8891   RECURSE_ENTRYTREE(buildExampleList,rootNav);
8892 }
8893
8894 //----------------------------------------------------------------------------
8895 // prints the Entry tree (for debugging)
8896
8897 void printNavTree(EntryNav *rootNav,int indent)
8898 {
8899   QCString indentStr;
8900   indentStr.fill(' ',indent);
8901   msg("%s%s (sec=0x%x)\n",
8902       indentStr.isEmpty()?"":indentStr.data(),
8903       rootNav->name().isEmpty()?"<empty>":rootNav->name().data(),
8904       rootNav->section());
8905   if (rootNav->children()) 
8906   {
8907     EntryNavListIterator eli(*rootNav->children());
8908     for (;eli.current();++eli) printNavTree(eli.current(),indent+2);
8909   }
8910 }
8911
8912
8913 //----------------------------------------------------------------------------
8914 // generate the example documentation 
8915
8916 static void generateExampleDocs()
8917 {
8918   g_outputList->disable(OutputGenerator::Man);
8919   PageSDict::Iterator pdi(*Doxygen::exampleSDict);
8920   PageDef *pd=0;
8921   for (pdi.toFirst();(pd=pdi.current());++pdi)
8922   {
8923     msg("Generating docs for example %s...\n",pd->name().data());
8924     resetCCodeParserState();
8925     QCString n=pd->getOutputFileBase();
8926     startFile(*g_outputList,n,n,pd->name());
8927     startTitle(*g_outputList,n);
8928     g_outputList->docify(pd->name());
8929     endTitle(*g_outputList,n,0);
8930     g_outputList->startContents();
8931     g_outputList->generateDoc(pd->docFile(),                            // file
8932                          pd->docLine(),                            // startLine
8933                          pd,                                       // context
8934                          0,                                        // memberDef
8935                          pd->documentation()+"\n\n\\include "+pd->name(),          // docs
8936                          TRUE,                                     // index words
8937                          TRUE,                                     // is example
8938                          pd->name()
8939                         );
8940     endFile(*g_outputList); // contains g_outputList->endContents()
8941   }
8942   g_outputList->enable(OutputGenerator::Man);
8943 }
8944
8945 //----------------------------------------------------------------------------
8946 // generate module pages
8947
8948 static void generateGroupDocs()
8949 {
8950   GroupSDict::Iterator gli(*Doxygen::groupSDict);
8951   GroupDef *gd;
8952   for (gli.toFirst();(gd=gli.current());++gli)
8953   {
8954     if (!gd->isReference())
8955     {
8956       gd->writeDocumentation(*g_outputList);
8957     }
8958   }
8959 }
8960
8961 //----------------------------------------------------------------------------
8962
8963 //static void generatePackageDocs()
8964 //{
8965 //  writePackageIndex(*g_outputList);
8966 //  
8967 //  if (Doxygen::packageDict.count()>0)
8968 //  {
8969 //    PackageSDict::Iterator pdi(Doxygen::packageDict);
8970 //    PackageDef *pd;
8971 //    for (pdi.toFirst();(pd=pdi.current());++pdi)
8972 //    {
8973 //      pd->writeDocumentation(*g_outputList);
8974 //    }
8975 //  }
8976 //}
8977
8978 //----------------------------------------------------------------------------
8979 // generate module pages
8980
8981 static void generateNamespaceDocs()
8982 {
8983   //writeNamespaceIndex(*g_outputList);
8984   
8985   NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
8986   NamespaceDef *nd;
8987   // for each namespace...
8988   for (;(nd=nli.current());++nli)
8989   {
8990
8991     if (nd->isLinkableInProject())
8992     {
8993       msg("Generating docs for namespace %s\n",nd->name().data());
8994       nd->writeDocumentation(*g_outputList);
8995     }
8996
8997     // for each class in the namespace...
8998     ClassSDict::Iterator cli(*nd->getClassSDict());
8999     for ( ; cli.current() ; ++cli )
9000     {
9001       ClassDef *cd=cli.current();
9002       if ( ( cd->isLinkableInProject() && 
9003              cd->templateMaster()==0
9004            ) // skip external references, anonymous compounds and 
9005              // template instances and nested classes
9006            && !cd->isHidden() && !cd->isEmbeddedInOuterScope()
9007          )
9008       {
9009         msg("Generating docs for compound %s...\n",cd->name().data());
9010
9011         cd->writeDocumentation(*g_outputList);
9012         cd->writeMemberList(*g_outputList);
9013       }
9014       cd->writeDocumentationForInnerClasses(*g_outputList);
9015     }
9016   }
9017 }
9018
9019 #if defined(_WIN32)
9020 static QCString fixSlashes(QCString &s)
9021 {
9022   QCString result;
9023   uint i;
9024   for (i=0;i<s.length();i++)
9025   {
9026     switch(s.at(i))
9027     {
9028       case '/': 
9029       case '\\': 
9030         result+="\\\\"; 
9031         break;
9032       default:
9033         result+=s.at(i);
9034     }
9035   }
9036   return result;
9037 }
9038 #endif
9039
9040
9041 //----------------------------------------------------------------------------
9042
9043 static bool openOutputFile(const char *outFile,QFile &f)
9044 {
9045   bool fileOpened=FALSE;
9046   bool writeToStdout=(outFile[0]=='-' && outFile[1]=='\0');
9047   if (writeToStdout) // write to stdout
9048   {
9049     fileOpened = f.open(IO_WriteOnly,stdout);
9050   }
9051   else // write to file
9052   {
9053     QFileInfo fi(outFile);
9054     if (fi.exists()) // create a backup
9055     {
9056       QDir dir=fi.dir();
9057       QFileInfo backup(fi.fileName()+".bak");
9058       if (backup.exists()) // remove existing backup
9059         dir.remove(backup.fileName());
9060       dir.rename(fi.fileName(),fi.fileName()+".bak");
9061     } 
9062     f.setName(outFile);
9063     fileOpened = f.open(IO_WriteOnly|IO_Translate);
9064   }
9065   return fileOpened;
9066 }
9067
9068 /*! Generate a template version of the configuration file.
9069  *  If the \a shortList parameter is TRUE a configuration file without
9070  *  comments will be generated.
9071  */
9072 static void generateConfigFile(const char *configFile,bool shortList,
9073                                bool updateOnly=FALSE)
9074 {
9075   QFile f;
9076   bool fileOpened=openOutputFile(configFile,f);
9077   bool writeToStdout=(configFile[0]=='-' && configFile[1]=='\0');
9078   if (fileOpened)
9079   {
9080     FTextStream t(&f);
9081     Config::instance()->writeTemplate(t,shortList,updateOnly);
9082     if (!writeToStdout)
9083     {
9084       if (!updateOnly)
9085       {
9086         msg("\n\nConfiguration file `%s' created.\n\n",configFile);
9087         msg("Now edit the configuration file and enter\n\n");
9088         if (qstrcmp(configFile,"Doxyfile") || qstrcmp(configFile,"doxyfile"))
9089           msg("  doxygen %s\n\n",configFile);
9090         else
9091           msg("  doxygen\n\n");
9092         msg("to generate the documentation for your project\n\n");
9093       }
9094       else
9095       {
9096         msg("\n\nConfiguration file `%s' updated.\n\n",configFile);
9097       }
9098     }
9099   }
9100   else
9101   {
9102     err("Cannot open file %s for writing\n",configFile);
9103     exit(1);
9104   }
9105 }
9106
9107 //----------------------------------------------------------------------------
9108 // read and parse a tag file
9109
9110 //static bool readLineFromFile(QFile &f,QCString &s)
9111 //{
9112 //  char c=0;
9113 //  s.resize(0);
9114 //  while (!f.atEnd() && (c=f.getch())!='\n') s+=c;
9115 //  return f.atEnd();
9116 //}
9117
9118 //----------------------------------------------------------------------------
9119
9120 static void readTagFile(Entry *root,const char *tl)
9121 {
9122   QCString tagLine = tl;
9123   QCString fileName;
9124   QCString destName;
9125   int eqPos = tagLine.find('=');
9126   if (eqPos!=-1) // tag command contains a destination
9127   {
9128     fileName = tagLine.left(eqPos).stripWhiteSpace();
9129     destName = tagLine.right(tagLine.length()-eqPos-1).stripWhiteSpace();
9130     QFileInfo fi(fileName);
9131     Doxygen::tagDestinationDict.insert(fi.absFilePath().utf8(),new QCString(destName));
9132     //printf("insert tagDestination %s->%s\n",fi.fileName().data(),destName.data());
9133   }
9134   else
9135   {
9136     fileName = tagLine;
9137   }
9138     
9139   QFileInfo fi(fileName);
9140   if (!fi.exists() || !fi.isFile())
9141   {
9142     err("Tag file `%s' does not exist or is not a file. Skipping it...\n",
9143         fileName.data());
9144     return;
9145   }
9146
9147   if (!destName.isEmpty())
9148     msg("Reading tag file `%s', location `%s'...\n",fileName.data(),destName.data());
9149   else
9150     msg("Reading tag file `%s'...\n",fileName.data());
9151
9152   parseTagFile(root,fi.absFilePath().utf8());
9153 }
9154
9155 //----------------------------------------------------------------------------
9156 static void copyStyleSheet()
9157 {
9158   QCString &htmlStyleSheet = Config_getString("HTML_STYLESHEET");
9159   if (!htmlStyleSheet.isEmpty())
9160   {
9161     QFileInfo fi(htmlStyleSheet);
9162     if (!fi.exists())
9163     {
9164       err("Style sheet '%s' specified by HTML_STYLESHEET does not exist!\n",htmlStyleSheet.data());
9165       htmlStyleSheet.resize(0); // revert to the default
9166     }
9167     else
9168     {
9169       QCString destFileName = Config_getString("HTML_OUTPUT")+"/"+fi.fileName().data();
9170       copyFile(htmlStyleSheet,destFileName);
9171     }
9172   }
9173   QStrList htmlExtraStyleSheet = Config_getList("HTML_EXTRA_STYLESHEET");
9174   for (uint i=0; i<htmlExtraStyleSheet.count(); ++i)
9175   {
9176     QCString fileName(htmlExtraStyleSheet.at(i));
9177     if (!fileName.isEmpty())
9178     {
9179       QFileInfo fi(fileName);
9180       if (!fi.exists())
9181       {
9182         err("Style sheet '%s' specified by HTML_EXTRA_STYLESHEET does not exist!\n",fileName.data());
9183       }
9184       else
9185       {
9186         QCString destFileName = Config_getString("HTML_OUTPUT")+"/"+fi.fileName().data();
9187         copyFile(fileName, destFileName);
9188       }
9189     }
9190   }
9191 }
9192
9193 static void copyLogo()
9194 {
9195   QCString &projectLogo = Config_getString("PROJECT_LOGO");
9196   if (!projectLogo.isEmpty())
9197   {
9198     QFileInfo fi(projectLogo);
9199     if (!fi.exists())
9200     {
9201       err("Project logo '%s' specified by PROJECT_LOGO does not exist!\n",projectLogo.data());
9202       projectLogo.resize(0); // revert to the default
9203     }
9204     else
9205     {
9206       QCString destFileName = Config_getString("HTML_OUTPUT")+"/"+fi.fileName().data();
9207       copyFile(projectLogo,destFileName);
9208       Doxygen::indexList->addImageFile(fi.fileName().data());
9209     }
9210   }
9211 }
9212
9213 static void copyExtraFiles(const QCString& filesOption,const QCString &outputOption)
9214 {
9215   QStrList files = Config_getList(filesOption);
9216   uint i;
9217   for (i=0; i<files.count(); ++i)
9218   {
9219     QCString fileName(files.at(i));
9220     
9221     if (!fileName.isEmpty())
9222     {
9223       QFileInfo fi(fileName);
9224       if (!fi.exists()) 
9225       {
9226         err("Extra file '%s' specified in " + filesOption + " does not exist!\n", fileName.data());
9227       }
9228       else
9229       {
9230         QCString destFileName = Config_getString(outputOption)+"/"+fi.fileName().data();
9231         Doxygen::indexList->addImageFile(fi.fileName().utf8());
9232         copyFile(fileName, destFileName);
9233       }
9234     }
9235   }
9236 }
9237
9238 //----------------------------------------------------------------------------
9239
9240 static ParserInterface *getParserForFile(const char *fn)
9241 {
9242   QCString fileName=fn;
9243   QCString extension;
9244   int ei = fileName.findRev('.');
9245   if (ei!=-1)
9246   {
9247     extension=fileName.right(fileName.length()-ei);
9248   }
9249   else
9250   {
9251     extension = ".no_extension";
9252   }
9253
9254   return Doxygen::parserManager->getParser(extension);
9255 }
9256
9257 static void parseFile(ParserInterface *parser,
9258                       Entry *root,EntryNav *rootNav,FileDef *fd,const char *fn,
9259                       bool sameTu,QStrList &filesInSameTu)
9260 {
9261 #if USE_LIBCLANG
9262   static bool clangAssistedParsing = Config_getBool("CLANG_ASSISTED_PARSING");
9263 #else
9264   static bool clangAssistedParsing = FALSE;
9265 #endif
9266   QCString fileName=fn;
9267   QCString extension;
9268   int ei = fileName.findRev('.');
9269   if (ei!=-1)
9270   {
9271     extension=fileName.right(fileName.length()-ei);
9272   }
9273   else
9274   {
9275     extension = ".no_extension";
9276   }
9277
9278   QFileInfo fi(fileName);
9279   BufStr preBuf(fi.size()+4096);
9280
9281   if (Config_getBool("ENABLE_PREPROCESSING") && 
9282       parser->needsPreprocessing(extension))
9283   {
9284     BufStr inBuf(fi.size()+4096);
9285     msg("Preprocessing %s...\n",fn);
9286     readInputFile(fileName,inBuf);
9287     preprocessFile(fileName,inBuf,preBuf);
9288   }
9289   else // no preprocessing
9290   {
9291     msg("Reading %s...\n",fn);
9292     readInputFile(fileName,preBuf);
9293   }
9294
9295   BufStr convBuf(preBuf.curPos()+1024);
9296
9297   // convert multi-line C++ comments to C style comments
9298   convertCppComments(&preBuf,&convBuf,fileName);
9299
9300   convBuf.addChar('\0');
9301
9302   if (clangAssistedParsing && !sameTu)
9303   {
9304     fd->getAllIncludeFilesRecursively(filesInSameTu);
9305   }
9306
9307   // use language parse to parse the file
9308   parser->parseInput(fileName,convBuf.data(),root,sameTu,filesInSameTu);
9309
9310   // store the Entry tree in a file and create an index to
9311   // navigate/load entries
9312   //printf("root->createNavigationIndex for %s\n",fd->name().data());
9313   root->createNavigationIndex(rootNav,g_storage,fd);
9314 }
9315
9316 //! parse the list of input files
9317 static void parseFiles(Entry *root,EntryNav *rootNav)
9318 {
9319 #if USE_LIBCLANG
9320   static bool clangAssistedParsing = Config_getBool("CLANG_ASSISTED_PARSING");
9321   if (clangAssistedParsing)
9322   {
9323     QDict<void> g_processedFiles(10007);
9324
9325     // create a dictionary with files to process
9326     QDict<void> g_filesToProcess(10007);
9327     StringListIterator it(g_inputFiles);
9328     QCString *s;
9329     for (;(s=it.current());++it)
9330     {
9331       g_filesToProcess.insert(*s,(void*)0x8);
9332     }
9333
9334     // process source files (and their include dependencies)
9335     for (it.toFirst();(s=it.current());++it)
9336     {
9337       bool ambig;
9338       FileDef *fd=findFileDef(Doxygen::inputNameDict,s->data(),ambig);
9339       ASSERT(fd!=0);
9340       if (fd->isSource() && !fd->isReference()) // this is a source file
9341       {
9342         QStrList filesInSameTu;
9343         ParserInterface * parser = getParserForFile(s->data());
9344         parser->startTranslationUnit(s->data());
9345         parseFile(parser,root,rootNav,fd,s->data(),FALSE,filesInSameTu);
9346         //printf("  got %d extra files in tu\n",filesInSameTu.count());
9347
9348         // Now process any include files in the same translation unit 
9349         // first. When libclang is used this is much more efficient.
9350         char *incFile = filesInSameTu.first();
9351         while (incFile && g_filesToProcess.find(incFile))
9352         {
9353           if (qstrcmp(incFile,s->data()) && !g_processedFiles.find(incFile))
9354           {
9355             FileDef *ifd=findFileDef(Doxygen::inputNameDict,incFile,ambig);
9356             if (ifd && !ifd->isReference())
9357             {
9358               QStrList moreFiles;
9359               //printf("  Processing %s in same translation unit as %s\n",incFile,s->data());
9360               parseFile(parser,root,rootNav,ifd,incFile,TRUE,moreFiles);
9361               g_processedFiles.insert(incFile,(void*)0x8);
9362             }
9363           }
9364           incFile = filesInSameTu.next();
9365         }
9366         parser->finishTranslationUnit();
9367         g_processedFiles.insert(*s,(void*)0x8);
9368       }
9369     }
9370     // process remaining files
9371     for (it.toFirst();(s=it.current());++it)
9372     {
9373       if (!g_processedFiles.find(*s)) // not yet processed
9374       {
9375         bool ambig;
9376         QStrList filesInSameTu;
9377         FileDef *fd=findFileDef(Doxygen::inputNameDict,s->data(),ambig);
9378         ASSERT(fd!=0);
9379         ParserInterface * parser = getParserForFile(s->data());
9380         parser->startTranslationUnit(s->data());
9381         parseFile(parser,root,rootNav,fd,s->data(),FALSE,filesInSameTu);
9382         parser->finishTranslationUnit();
9383         g_processedFiles.insert(*s,(void*)0x8);
9384       }
9385     }
9386   }
9387   else // normal pocessing
9388 #endif
9389   {
9390     StringListIterator it(g_inputFiles);
9391     QCString *s;
9392     for (;(s=it.current());++it)
9393     {
9394       bool ambig;
9395       QStrList filesInSameTu;
9396       FileDef *fd=findFileDef(Doxygen::inputNameDict,s->data(),ambig);
9397       ASSERT(fd!=0);
9398       ParserInterface * parser = getParserForFile(s->data());
9399       parser->startTranslationUnit(s->data());
9400       parseFile(parser,root,rootNav,fd,s->data(),FALSE,filesInSameTu);
9401     }
9402   }
9403 }
9404
9405 // resolves a path that may include symlinks, if a recursive symlink is
9406 // found an empty string is returned.
9407 static QCString resolveSymlink(QCString path)
9408 {
9409   int sepPos=0;
9410   int oldPos=0;
9411   QFileInfo fi;
9412   QDict<void> nonSymlinks;
9413   QDict<void> known;
9414   QCString result = path;
9415   QCString oldPrefix = "/";
9416   do
9417   {
9418 #ifdef WIN32
9419     // UNC path, skip server and share name
9420     if (sepPos==0 && (result.left(2)=="//" || result.left(2)=="\\\\")) 
9421       sepPos = result.find('/',2);
9422     if (sepPos!=-1) 
9423       sepPos = result.find('/',sepPos+1);
9424 #else
9425     sepPos = result.find('/',sepPos+1);
9426 #endif
9427     QCString prefix = sepPos==-1 ? result : result.left(sepPos);
9428     if (nonSymlinks.find(prefix)==0)
9429     {
9430       fi.setFile(prefix);
9431       if (fi.isSymLink())
9432       {
9433         QString target = fi.readLink();
9434         bool isRelative = QFileInfo(target).isRelative();
9435         if (isRelative)
9436         {
9437           target = QDir::cleanDirPath(oldPrefix+"/"+target.data());
9438         }
9439         if (sepPos!=-1)
9440         {
9441           if (fi.isDir() && target.length()>0 && target.at(target.length()-1)!='/')
9442           {
9443             target+='/';
9444           }
9445           target+=result.mid(sepPos);
9446         }
9447         result = QDir::cleanDirPath(target).data();
9448         sepPos = 0;
9449         if (known.find(result)) return QCString(); // recursive symlink!
9450         known.insert(result,(void*)0x8);
9451         if (isRelative)
9452         {
9453           sepPos = oldPos;
9454         }
9455         else // link to absolute path
9456         {
9457           sepPos = 0;
9458           oldPrefix = "/";
9459         }
9460       }
9461       else
9462       {
9463         nonSymlinks.insert(prefix,(void*)0x8);
9464         oldPrefix = prefix;
9465       }
9466       oldPos = sepPos;
9467     }
9468   }
9469   while (sepPos!=-1);
9470   return QDir::cleanDirPath(result).data();
9471 }
9472
9473 static QDict<void> g_pathsVisited(1009);
9474
9475 //----------------------------------------------------------------------------
9476 // Read all files matching at least one pattern in `patList' in the 
9477 // directory represented by `fi'.
9478 // The directory is read iff the recusiveFlag is set.
9479 // The contents of all files is append to the input string
9480
9481 int readDir(QFileInfo *fi,
9482             FileNameList *fnList,
9483             FileNameDict *fnDict,
9484             StringDict  *exclDict,
9485             QStrList *patList,
9486             QStrList *exclPatList,
9487             StringList *resultList,
9488             StringDict *resultDict,
9489             bool errorIfNotExist,
9490             bool recursive,
9491             QDict<void> *killDict,
9492             QDict<void> *paths
9493            )
9494 {
9495   QCString dirName = fi->absFilePath().utf8();
9496   if (paths && paths->find(dirName)==0)
9497   {
9498     paths->insert(dirName,(void*)0x8);
9499   }
9500   if (fi->isSymLink())
9501   {
9502     dirName = resolveSymlink(dirName.data());
9503     if (dirName.isEmpty()) return 0;            // recusive symlink
9504     if (g_pathsVisited.find(dirName)) return 0; // already visited path
9505     g_pathsVisited.insert(dirName,(void*)0x8);
9506   }
9507   QDir dir(dirName);
9508   dir.setFilter( QDir::Files | QDir::Dirs | QDir::Hidden );
9509   int totalSize=0;
9510   msg("Searching for files in directory %s\n", fi->absFilePath().data());
9511   //printf("killDict=%p count=%d\n",killDict,killDict->count());
9512   
9513   const QFileInfoList *list = dir.entryInfoList();
9514   if (list)
9515   {
9516     QFileInfoListIterator it( *list );
9517     QFileInfo *cfi;
9518
9519     while ((cfi=it.current()))
9520     {
9521       if (exclDict==0 || exclDict->find(cfi->absFilePath().utf8())==0) 
9522       { // file should not be excluded
9523         //printf("killDict->find(%s)\n",cfi->absFilePath().data());
9524         if (!cfi->exists() || !cfi->isReadable())
9525         {
9526           if (errorIfNotExist)
9527           {
9528             warn_uncond("source %s is not a readable file or directory... skipping.\n",cfi->absFilePath().data());
9529           }
9530         }
9531         else if (cfi->isFile() && 
9532             (!Config_getBool("EXCLUDE_SYMLINKS") || !cfi->isSymLink()) &&
9533             (patList==0 || patternMatch(*cfi,patList)) && 
9534             !patternMatch(*cfi,exclPatList) &&
9535             (killDict==0 || killDict->find(cfi->absFilePath().utf8())==0)
9536             )
9537         {
9538           totalSize+=cfi->size()+cfi->absFilePath().length()+4;
9539           QCString name=cfi->fileName().utf8();
9540           //printf("New file %s\n",name.data());
9541           if (fnDict)
9542           {
9543             FileDef  *fd=new FileDef(cfi->dirPath().utf8()+"/",name);
9544             FileName *fn=0;
9545             if (!name.isEmpty() && (fn=(*fnDict)[name]))
9546             {
9547               fn->append(fd);
9548             }
9549             else
9550             {
9551               fn = new FileName(cfi->absFilePath().utf8(),name);
9552               fn->append(fd);
9553               if (fnList) fnList->inSort(fn);
9554               fnDict->insert(name,fn);
9555             }
9556           }
9557           QCString *rs=0;
9558           if (resultList || resultDict)
9559           {
9560             rs=new QCString(cfi->absFilePath().utf8());
9561           }
9562           if (resultList) resultList->append(rs);
9563           if (resultDict) resultDict->insert(cfi->absFilePath().utf8(),rs);
9564           if (killDict) killDict->insert(cfi->absFilePath().utf8(),(void *)0x8);
9565         }
9566         else if (recursive &&
9567             (!Config_getBool("EXCLUDE_SYMLINKS") || !cfi->isSymLink()) &&
9568             cfi->isDir() && 
9569             !patternMatch(*cfi,exclPatList) &&
9570             cfi->fileName().at(0)!='.') // skip "." ".." and ".dir"
9571         {
9572           cfi->setFile(cfi->absFilePath());
9573           totalSize+=readDir(cfi,fnList,fnDict,exclDict,
9574               patList,exclPatList,resultList,resultDict,errorIfNotExist,
9575               recursive,killDict,paths);
9576         }
9577       }
9578       ++it;
9579     }
9580   }
9581   return totalSize;
9582 }
9583
9584
9585 //----------------------------------------------------------------------------
9586 // read a file or all files in a directory and append their contents to the
9587 // input string. The names of the files are appended to the `fiList' list.
9588
9589 int readFileOrDirectory(const char *s,
9590                         FileNameList *fnList,
9591                         FileNameDict *fnDict,
9592                         StringDict *exclDict,
9593                         QStrList *patList,
9594                         QStrList *exclPatList,
9595                         StringList *resultList,
9596                         StringDict *resultDict,
9597                         bool recursive,
9598                         bool errorIfNotExist,
9599                         QDict<void> *killDict,
9600                         QDict<void> *paths
9601                        )
9602 {
9603   //printf("killDict=%p count=%d\n",killDict,killDict->count());
9604   // strip trailing slashes
9605   if (s==0) return 0;
9606   QCString fs = s;
9607   char lc = fs.at(fs.length()-1);
9608   if (lc=='/' || lc=='\\') fs = fs.left(fs.length()-1);
9609
9610   QFileInfo fi(fs);
9611   //printf("readFileOrDirectory(%s)\n",s);
9612   int totalSize=0;
9613   {
9614     if (exclDict==0 || exclDict->find(fi.absFilePath().utf8())==0)
9615     {
9616       if (!fi.exists() || !fi.isReadable())
9617       {
9618         if (errorIfNotExist)
9619         {
9620           warn_uncond("source %s is not a readable file or directory... skipping.\n",s);
9621         }
9622       }
9623       else if (!Config_getBool("EXCLUDE_SYMLINKS") || !fi.isSymLink())
9624       {
9625         if (fi.isFile())
9626         {
9627           QCString dirPath = fi.dirPath(TRUE).utf8();
9628           QCString filePath = fi.absFilePath().utf8();
9629           if (paths && paths->find(dirPath))
9630           {
9631             paths->insert(dirPath,(void*)0x8);
9632           }
9633           //printf("killDict->find(%s)\n",fi.absFilePath().data());
9634           if (killDict==0 || killDict->find(filePath)==0)
9635           {
9636             totalSize+=fi.size()+fi.absFilePath().length()+4; //readFile(&fi,fiList,input); 
9637             //fiList->inSort(new FileInfo(fi));
9638             QCString name=fi.fileName().utf8();
9639             //printf("New file %s\n",name.data());
9640             if (fnDict)
9641             {
9642               FileDef  *fd=new FileDef(dirPath+"/",name);
9643               FileName *fn=0;
9644               if (!name.isEmpty() && (fn=(*fnDict)[name]))
9645               {
9646                 fn->append(fd);
9647               }
9648               else
9649               {
9650                 fn = new FileName(filePath,name);
9651                 fn->append(fd);
9652                 if (fnList) fnList->inSort(fn);
9653                 fnDict->insert(name,fn);
9654               }
9655             }
9656             QCString *rs=0;
9657             if (resultList || resultDict)
9658             {
9659               rs=new QCString(filePath);
9660               if (resultList) resultList->append(rs);
9661               if (resultDict) resultDict->insert(filePath,rs);
9662             }
9663
9664             if (killDict) killDict->insert(fi.absFilePath().utf8(),(void *)0x8);
9665           }
9666         }
9667         else if (fi.isDir()) // readable dir
9668         {
9669           totalSize+=readDir(&fi,fnList,fnDict,exclDict,patList,
9670               exclPatList,resultList,resultDict,errorIfNotExist,
9671               recursive,killDict,paths);
9672         }
9673       }
9674     }
9675   }
9676   return totalSize;
9677 }
9678
9679 //----------------------------------------------------------------------------
9680
9681 void readFormulaRepository()
9682 {
9683   QFile f(Config_getString("HTML_OUTPUT")+"/formula.repository");
9684   if (f.open(IO_ReadOnly)) // open repository
9685   {
9686     msg("Reading formula repository...\n");
9687     QTextStream t(&f);
9688     QCString line;
9689     while (!t.eof())
9690     {
9691       line=t.readLine().utf8();
9692       int se=line.find(':'); // find name and text separator.
9693       if (se==-1)
9694       {
9695         warn_uncond("formula.repository is corrupted!\n");
9696         break;
9697       }
9698       else
9699       {
9700         QCString formName = line.left(se);
9701         QCString formText = line.right(line.length()-se-1); 
9702         Formula *f=new Formula(formText);
9703         Doxygen::formulaList->setAutoDelete(TRUE);
9704         Doxygen::formulaList->append(f);
9705         Doxygen::formulaDict->insert(formText,f);
9706         Doxygen::formulaNameDict->insert(formName,f);
9707       }
9708     }
9709   }
9710 }
9711
9712 //----------------------------------------------------------------------------
9713
9714 static void expandAliases()
9715 {
9716   QDictIterator<QCString> adi(Doxygen::aliasDict);
9717   QCString *s;
9718   for (adi.toFirst();(s=adi.current());++adi)
9719   {
9720     *s = expandAlias(adi.currentKey(),*s);
9721   }
9722 }
9723
9724 //----------------------------------------------------------------------------
9725
9726 static void escapeAliases()
9727 {
9728   QDictIterator<QCString> adi(Doxygen::aliasDict);
9729   QCString *s;
9730   for (adi.toFirst();(s=adi.current());++adi)
9731   {
9732     QCString value=*s,newValue;
9733     int in,p=0;
9734     // for each \n in the alias command value
9735     while ((in=value.find("\\n",p))!=-1)
9736     {
9737       newValue+=value.mid(p,in-p);
9738       // expand \n's except if \n is part of a built-in command.
9739       if (value.mid(in,5)!="\\note" && 
9740           value.mid(in,5)!="\\name" && 
9741           value.mid(in,10)!="\\namespace" && 
9742           value.mid(in,14)!="\\nosubgrouping"
9743          ) 
9744       {
9745         newValue+="\\_linebr ";
9746       }
9747       else 
9748       {
9749         newValue+="\\n";
9750       }
9751       p=in+2;
9752     }
9753     newValue+=value.mid(p,value.length()-p);
9754     *s=newValue;
9755     //printf("Alias %s has value %s\n",adi.currentKey().data(),s->data());
9756   }
9757 }
9758
9759 //----------------------------------------------------------------------------
9760
9761 void readAliases()
9762
9763   // add aliases to a dictionary
9764   Doxygen::aliasDict.setAutoDelete(TRUE);
9765   QStrList &aliasList = Config_getList("ALIASES");
9766   const char *s=aliasList.first();
9767   while (s)
9768   {
9769     if (Doxygen::aliasDict[s]==0)
9770     {
9771       QCString alias=s;
9772       int i=alias.find('=');
9773       if (i>0)
9774       {
9775         QCString name=alias.left(i).stripWhiteSpace();
9776         QCString value=alias.right(alias.length()-i-1);
9777         //printf("Alias: found name=`%s' value=`%s'\n",name.data(),value.data()); 
9778         if (!name.isEmpty())
9779         {
9780           QCString *dn=Doxygen::aliasDict[name];
9781           if (dn==0) // insert new alias
9782           {
9783             Doxygen::aliasDict.insert(name,new QCString(value));
9784           }
9785           else // overwrite previous alias
9786           {
9787             *dn=value;
9788           }
9789         }
9790       }
9791     }
9792     s=aliasList.next();
9793   }
9794   expandAliases();
9795   escapeAliases();
9796 }
9797
9798 //----------------------------------------------------------------------------
9799
9800 static void dumpSymbol(FTextStream &t,Definition *d)
9801 {
9802   QCString anchor;
9803   if (d->definitionType()==Definition::TypeMember)
9804   {
9805     MemberDef *md = (MemberDef *)d;
9806     anchor=":"+md->anchor();
9807   }
9808   QCString scope;
9809   if (d->getOuterScope() && d->getOuterScope()!=Doxygen::globalScope) 
9810   {
9811     scope = d->getOuterScope()->getOutputFileBase()+Doxygen::htmlFileExtension;
9812   }
9813   t << "REPLACE INTO symbols (symbol_id,scope_id,name,file,line) VALUES('"
9814     << d->getOutputFileBase()+Doxygen::htmlFileExtension+anchor << "','"
9815     << scope << "','"
9816     << d->name() << "','"
9817     << d->getDefFileName() << "','"
9818     << d->getDefLine()
9819     << "');" << endl;
9820 }
9821
9822 static void dumpSymbolMap()
9823
9824   QFile f("symbols.sql");
9825   if (f.open(IO_WriteOnly))
9826   {
9827     FTextStream t(&f);
9828     QDictIterator<DefinitionIntf> di(*Doxygen::symbolMap);
9829     DefinitionIntf *intf;
9830     for (;(intf=di.current());++di)
9831     {
9832       if (intf->definitionType()==DefinitionIntf::TypeSymbolList) // list of symbols
9833       {
9834         DefinitionListIterator dli(*(DefinitionList*)intf);
9835         Definition *d;
9836         // for each symbol
9837         for (dli.toFirst();(d=dli.current());++dli)
9838         {
9839           dumpSymbol(t,d);
9840         }
9841       }
9842       else // single symbol
9843       {
9844         Definition *d = (Definition *)intf;
9845         if (d!=Doxygen::globalScope) dumpSymbol(t,d);
9846       }
9847     }
9848   }
9849 }
9850
9851 // print developer options of doxygen
9852 static void devUsage()
9853 {
9854   msg("Developer parameters:\n");
9855   msg("  -m          dump symbol map\n");
9856   msg("  -b          output to wizard\n");
9857   msg("  -T          activates output generation via Django like template\n");
9858   msg("  -d <level>  enable a debug level, such as (multiple invocations of -d are possible):\n");
9859   Debug::printFlags();
9860 }
9861
9862
9863 //----------------------------------------------------------------------------
9864 // print the usage of doxygen
9865
9866 static void usage(const char *name)
9867 {
9868   msg("Doxygen version %s\nCopyright Dimitri van Heesch 1997-2014\n\n",versionString);
9869   msg("You can use doxygen in a number of ways:\n\n");
9870   msg("1) Use doxygen to generate a template configuration file:\n");
9871   msg("    %s [-s] -g [configName]\n\n",name);
9872   msg("    If - is used for configName doxygen will write to standard output.\n\n");
9873   msg("2) Use doxygen to update an old configuration file:\n");
9874   msg("    %s [-s] -u [configName]\n\n",name);
9875   msg("3) Use doxygen to generate documentation using an existing ");
9876   msg("configuration file:\n");
9877   msg("    %s [configName]\n\n",name);
9878   msg("    If - is used for configName doxygen will read from standard input.\n\n");
9879   msg("4) Use doxygen to generate a template file controlling the layout of the\n");
9880   msg("   generated documentation:\n");
9881   msg("    %s -l layoutFileName.xml\n\n",name);
9882   msg("5) Use doxygen to generate a template style sheet file for RTF, HTML or Latex.\n");
9883   msg("    RTF:        %s -w rtf styleSheetFile\n",name);
9884   msg("    HTML:       %s -w html headerFile footerFile styleSheetFile [configFile]\n",name);
9885   msg("    LaTeX:      %s -w latex headerFile footerFile styleSheetFile [configFile]\n\n",name);
9886   msg("6) Use doxygen to generate a rtf extensions file\n");
9887   msg("    RTF:   %s -e rtf extensionsFile\n\n",name);
9888   msg("If -s is specified the comments of the configuration items in the config file will be omitted.\n");
9889   msg("If configName is omitted `Doxyfile' will be used as a default.\n\n");
9890   msg("-v print version string\n");
9891 }
9892
9893 //----------------------------------------------------------------------------
9894 // read the argument of option `c' from the comment argument list and
9895 // update the option index `optind'.
9896
9897 static const char *getArg(int argc,char **argv,int &optind)
9898 {
9899   char *s=0;
9900   if (qstrlen(&argv[optind][2])>0)
9901     s=&argv[optind][2];
9902   else if (optind+1<argc && argv[optind+1][0]!='-')
9903     s=argv[++optind];
9904   return s;
9905 }
9906
9907 //----------------------------------------------------------------------------
9908
9909 void initDoxygen()
9910 {
9911   const char *lang = portable_getenv("LC_ALL");
9912   if (lang) portable_setenv("LANG",lang);
9913   setlocale(LC_ALL,"");
9914   setlocale(LC_CTYPE,"C"); // to get isspace(0xA0)==0, needed for UTF-8
9915   setlocale(LC_NUMERIC,"C");
9916
9917   Doxygen::runningTime.start();
9918   initPreprocessor();
9919
9920   Doxygen::parserManager = new ParserManager;
9921   Doxygen::parserManager->registerDefaultParser(         new FileParser);
9922   Doxygen::parserManager->registerParser("c",            new CLanguageScanner);
9923   Doxygen::parserManager->registerParser("python",       new PythonLanguageScanner);
9924   Doxygen::parserManager->registerParser("fortran",      new FortranLanguageScanner);
9925   Doxygen::parserManager->registerParser("fortranfree",  new FortranLanguageScannerFree);
9926   Doxygen::parserManager->registerParser("fortranfixed", new FortranLanguageScannerFixed);
9927   Doxygen::parserManager->registerParser("vhdl",         new VHDLLanguageScanner);
9928   Doxygen::parserManager->registerParser("dbusxml",      new DBusXMLScanner);
9929   Doxygen::parserManager->registerParser("tcl",          new TclLanguageScanner);
9930   Doxygen::parserManager->registerParser("md",           new MarkdownFileParser);
9931
9932   // register any additional parsers here...
9933
9934   initDefaultExtensionMapping();
9935   initClassMemberIndices();
9936   initNamespaceMemberIndices();
9937   initFileMemberIndices();
9938
9939   Doxygen::symbolMap     = new QDict<DefinitionIntf>(50177);
9940 #ifdef USE_LIBCLANG
9941   Doxygen::clangUsrMap   = new QDict<Definition>(50177);
9942 #endif
9943   Doxygen::inputNameList = new FileNameList;
9944   Doxygen::inputNameList->setAutoDelete(TRUE);
9945   Doxygen::memberNameSDict = new MemberNameSDict(10000);   
9946   Doxygen::memberNameSDict->setAutoDelete(TRUE);
9947   Doxygen::functionNameSDict = new MemberNameSDict(10000);   
9948   Doxygen::functionNameSDict->setAutoDelete(TRUE);
9949   Doxygen::groupSDict = new GroupSDict(17);          
9950   Doxygen::groupSDict->setAutoDelete(TRUE);
9951   Doxygen::globalScope = new NamespaceDef("<globalScope>",1,1,"<globalScope>");
9952   Doxygen::namespaceSDict = new NamespaceSDict(20);      
9953   Doxygen::namespaceSDict->setAutoDelete(TRUE);
9954   Doxygen::classSDict = new ClassSDict(1009);         
9955   Doxygen::classSDict->setAutoDelete(TRUE);
9956   Doxygen::hiddenClasses = new ClassSDict(257);
9957   Doxygen::hiddenClasses->setAutoDelete(TRUE);
9958   Doxygen::directories = new DirSDict(17);
9959   Doxygen::directories->setAutoDelete(TRUE);
9960   Doxygen::pageSDict = new PageSDict(1009);          // all doc pages
9961   Doxygen::pageSDict->setAutoDelete(TRUE);
9962   Doxygen::exampleSDict = new PageSDict(1009);       // all examples
9963   Doxygen::exampleSDict->setAutoDelete(TRUE);
9964   Doxygen::inputNameDict = new FileNameDict(10007);
9965   Doxygen::includeNameDict = new FileNameDict(10007);
9966   Doxygen::exampleNameDict = new FileNameDict(1009);
9967   Doxygen::exampleNameDict->setAutoDelete(TRUE);
9968   Doxygen::imageNameDict = new FileNameDict(257);
9969   Doxygen::imageNameDict->setAutoDelete(TRUE);
9970   Doxygen::dotFileNameDict = new FileNameDict(257);
9971   Doxygen::mscFileNameDict = new FileNameDict(257);
9972   Doxygen::diaFileNameDict = new FileNameDict(257);
9973   Doxygen::memGrpInfoDict.setAutoDelete(TRUE);
9974   Doxygen::tagDestinationDict.setAutoDelete(TRUE);
9975   Doxygen::dirRelations.setAutoDelete(TRUE);
9976   Doxygen::citeDict = new CiteDict(257);
9977   Doxygen::genericsDict = new GenericsSDict;
9978   Doxygen::indexList = new IndexList;
9979   Doxygen::formulaList = new FormulaList;
9980   Doxygen::formulaDict = new FormulaDict(1009);
9981   Doxygen::formulaNameDict = new FormulaDict(1009);
9982   Doxygen::sectionDict = new SectionDict(257);
9983   Doxygen::sectionDict->setAutoDelete(TRUE);
9984
9985   /**************************************************************************
9986    *            Initialize some global constants
9987    **************************************************************************/
9988   
9989   g_compoundKeywordDict.insert("template class",(void *)8);
9990   g_compoundKeywordDict.insert("template struct",(void *)8);
9991   g_compoundKeywordDict.insert("class",(void *)8);
9992   g_compoundKeywordDict.insert("struct",(void *)8);
9993   g_compoundKeywordDict.insert("union",(void *)8);
9994   g_compoundKeywordDict.insert("interface",(void *)8);
9995   g_compoundKeywordDict.insert("exception",(void *)8);
9996
9997 }
9998
9999 void cleanUpDoxygen()
10000 {
10001   delete Doxygen::sectionDict;
10002   delete Doxygen::formulaNameDict;
10003   delete Doxygen::formulaDict;
10004   delete Doxygen::formulaList;
10005   delete Doxygen::indexList;
10006   delete Doxygen::genericsDict;
10007   delete Doxygen::inputNameDict;
10008   delete Doxygen::includeNameDict;
10009   delete Doxygen::exampleNameDict;
10010   delete Doxygen::imageNameDict;
10011   delete Doxygen::dotFileNameDict;
10012   delete Doxygen::mscFileNameDict;
10013   delete Doxygen::diaFileNameDict;
10014   delete Doxygen::mainPage;
10015   delete Doxygen::pageSDict;  
10016   delete Doxygen::exampleSDict;
10017   delete Doxygen::globalScope;
10018   delete Doxygen::xrefLists;
10019   delete Doxygen::parserManager;
10020   cleanUpPreprocessor();
10021   delete theTranslator;
10022   delete g_outputList;
10023   Mappers::freeMappers();
10024   codeFreeScanner();
10025
10026   if (Doxygen::symbolMap)
10027   {
10028     // iterate through Doxygen::symbolMap and delete all
10029     // DefinitionList objects, since they have no owner
10030     QDictIterator<DefinitionIntf> dli(*Doxygen::symbolMap);
10031     DefinitionIntf *di;
10032     for (dli.toFirst();(di=dli.current());)
10033     {
10034       if (di->definitionType()==DefinitionIntf::TypeSymbolList)
10035       {
10036         DefinitionIntf *tmp = Doxygen::symbolMap->take(dli.currentKey());
10037         delete (DefinitionList *)tmp;
10038       }
10039       else
10040       {
10041         ++dli;
10042       }
10043     } 
10044   }
10045
10046   delete Doxygen::inputNameList;
10047   delete Doxygen::memberNameSDict;
10048   delete Doxygen::functionNameSDict;
10049   delete Doxygen::groupSDict;
10050   delete Doxygen::classSDict;
10051   delete Doxygen::hiddenClasses;
10052   delete Doxygen::namespaceSDict;
10053   delete Doxygen::directories;
10054
10055   //delete Doxygen::symbolMap; <- we cannot do this unless all static lists 
10056   //                              (such as Doxygen::namespaceSDict)
10057   //                              with objects based on Definition are made
10058   //                              dynamic first
10059 }
10060
10061 static int computeIdealCacheParam(uint v)
10062 {
10063   //printf("computeIdealCacheParam(v=%u)\n",v);
10064
10065   int r=0;
10066   while (v!=0) v>>=1,r++; 
10067   // r = log2(v)
10068
10069   // convert to a valid cache size value
10070   return QMAX(0,QMIN(r-16,9));
10071 }
10072
10073 void readConfiguration(int argc, char **argv)
10074 {
10075   /**************************************************************************
10076    *             Handle arguments                                           *
10077    **************************************************************************/
10078
10079   int optind=1;
10080   const char *configName=0;
10081   const char *layoutName=0;
10082   const char *debugLabel;
10083   const char *formatName;
10084   bool genConfig=FALSE;
10085   bool shortList=FALSE;
10086   bool updateConfig=FALSE;
10087   bool genLayout=FALSE;
10088   int retVal;
10089   while (optind<argc && argv[optind][0]=='-' && 
10090                (isalpha(argv[optind][1]) || argv[optind][1]=='?' || 
10091                 argv[optind][1]=='-')
10092         )
10093   {
10094     switch(argv[optind][1])
10095     {
10096       case 'g':
10097         genConfig=TRUE;
10098         configName=getArg(argc,argv,optind);
10099         if (optind+1<argc && qstrcmp(argv[optind+1],"-")==0)
10100         { configName="-"; optind++; }
10101         if (!configName) 
10102         { configName="Doxyfile"; }
10103         break;
10104       case 'l':
10105         genLayout=TRUE;
10106         layoutName=getArg(argc,argv,optind);
10107         if (!layoutName)
10108         { layoutName="DoxygenLayout.xml"; }
10109         break;
10110       case 'd':
10111         debugLabel=getArg(argc,argv,optind);
10112         if (!debugLabel)
10113         {
10114           err("option \"-d\" is missing debug specifier.\n");
10115           devUsage();
10116           cleanUpDoxygen();
10117           exit(1);
10118         }
10119         retVal = Debug::setFlag(debugLabel);
10120         if (!retVal)
10121         {
10122           err("option \"-d\" has unknown debug specifier: \"%s\".\n",debugLabel);
10123           cleanUpDoxygen();
10124           exit(1);
10125         }
10126         break;
10127       case 's':
10128         shortList=TRUE;
10129         break;
10130       case 'u':
10131         updateConfig=TRUE;
10132         break;
10133       case 'e':
10134         formatName=getArg(argc,argv,optind);
10135         if (!formatName)
10136         {
10137           err("option \"-e\" is missing format specifier rtf.\n");
10138           cleanUpDoxygen();
10139           exit(1);
10140         }
10141         if (qstricmp(formatName,"rtf")==0)
10142         {
10143           if (optind+1>=argc)
10144           {
10145             err("option \"-e rtf\" is missing an extensions file name\n");
10146             cleanUpDoxygen();
10147             exit(1);
10148           }
10149           QFile f;
10150           if (openOutputFile(argv[optind+1],f))
10151           {
10152             RTFGenerator::writeExtensionsFile(f);
10153           }
10154           cleanUpDoxygen();
10155           exit(0);
10156         }
10157         err("option \"-e\" has invalid format specifier.\n");
10158         cleanUpDoxygen();
10159         exit(1);
10160         break; 
10161       case 'w':
10162         formatName=getArg(argc,argv,optind);
10163         if (!formatName)
10164         {
10165           err("option \"-w\" is missing format specifier rtf, html or latex\n");
10166           cleanUpDoxygen();
10167           exit(1);
10168         } 
10169         if (qstricmp(formatName,"rtf")==0)
10170         {
10171           if (optind+1>=argc)
10172           {
10173             err("option \"-w rtf\" is missing a style sheet file name\n");
10174             cleanUpDoxygen();
10175             exit(1);
10176           }
10177           QFile f;
10178           if (openOutputFile(argv[optind+1],f))
10179           {
10180             RTFGenerator::writeStyleSheetFile(f);
10181           }
10182           cleanUpDoxygen();
10183           exit(1);
10184         }
10185         else if (qstricmp(formatName,"html")==0)
10186         {
10187           if (optind+4<argc || QFileInfo("Doxyfile").exists())
10188           {
10189             QCString df = optind+4<argc ? argv[optind+4] : QCString("Doxyfile");
10190             if (!Config::instance()->parse(df))
10191             {
10192               err("error opening or reading configuration file %s!\n",argv[optind+4]);
10193               cleanUpDoxygen();
10194               exit(1);
10195             }
10196             Config::instance()->substituteEnvironmentVars();
10197             Config::instance()->convertStrToVal();
10198             // avoid bootstrapping issues when the config file already
10199             // refers to the files that we are supposed to parse.
10200             Config_getString("HTML_HEADER")="";
10201             Config_getString("HTML_FOOTER")="";
10202             Config::instance()->check();
10203           }
10204           else
10205           {
10206             Config::instance()->init();
10207           }
10208           if (optind+3>=argc)
10209           {
10210             err("option \"-w html\" does not have enough arguments\n");
10211             cleanUpDoxygen();
10212             exit(1);
10213           }
10214
10215           QCString outputLanguage=Config_getEnum("OUTPUT_LANGUAGE");
10216           if (!setTranslator(outputLanguage))
10217           {
10218             warn_uncond("Output language %s not supported! Using English instead.\n", outputLanguage.data());
10219           }
10220
10221           QFile f;
10222           if (openOutputFile(argv[optind+1],f))
10223           {
10224             HtmlGenerator::writeHeaderFile(f, argv[optind+3]);
10225           }
10226           f.close();
10227           if (openOutputFile(argv[optind+2],f))
10228           {
10229             HtmlGenerator::writeFooterFile(f);
10230           }
10231           f.close();
10232           if (openOutputFile(argv[optind+3],f))
10233           {
10234             HtmlGenerator::writeStyleSheetFile(f);
10235           } 
10236           cleanUpDoxygen();
10237           exit(0);
10238         }
10239         else if (qstricmp(formatName,"latex")==0)
10240         {
10241           if (optind+4<argc) // use config file to get settings
10242           {
10243             if (!Config::instance()->parse(argv[optind+4]))
10244             {
10245               err("error opening or reading configuration file %s!\n",argv[optind+4]);
10246               exit(1);
10247             }
10248             Config::instance()->substituteEnvironmentVars();
10249             Config::instance()->convertStrToVal();
10250             Config_getString("LATEX_HEADER")="";
10251             Config::instance()->check();
10252           }
10253           else // use default config
10254           {
10255             Config::instance()->init();
10256           }
10257           if (optind+3>=argc)
10258           {
10259             err("option \"-w latex\" does not have enough arguments\n");
10260             cleanUpDoxygen();
10261             exit(1);
10262           }
10263
10264           QCString outputLanguage=Config_getEnum("OUTPUT_LANGUAGE");
10265           if (!setTranslator(outputLanguage))
10266           {
10267             warn_uncond("Output language %s not supported! Using English instead.\n", outputLanguage.data());
10268           }
10269
10270           QFile f;
10271           if (openOutputFile(argv[optind+1],f))
10272           {
10273             LatexGenerator::writeHeaderFile(f);
10274           }
10275           f.close();
10276           if (openOutputFile(argv[optind+2],f))
10277           {
10278             LatexGenerator::writeFooterFile(f);
10279           }
10280           f.close();
10281           if (openOutputFile(argv[optind+3],f))
10282           {
10283             LatexGenerator::writeStyleSheetFile(f);
10284           }
10285           cleanUpDoxygen();
10286           exit(0);
10287         }
10288         else
10289         {
10290           err("Illegal format specifier \"%s\": should be one of rtf, html or latex\n",formatName);
10291           cleanUpDoxygen();
10292           exit(1);
10293         }
10294         break;
10295       case 'm':
10296         g_dumpSymbolMap = TRUE;
10297         break;
10298       case 'v':
10299         msg("%s\n",versionString); 
10300         cleanUpDoxygen();
10301         exit(0);
10302         break;
10303       case '-':
10304         if (qstrcmp(&argv[optind][2],"help")==0)
10305         {
10306           usage(argv[0]);
10307           exit(0);
10308         }
10309         else if (qstrcmp(&argv[optind][2],"version")==0)
10310         {
10311           msg("%s\n",versionString); 
10312           cleanUpDoxygen();
10313           exit(0);
10314         }
10315         else
10316         {
10317           err("Unknown option \"-%s\"\n",&argv[optind][1]);
10318           usage(argv[0]);
10319           exit(1);
10320         }
10321         break;
10322       case 'b':
10323         setvbuf(stdout,NULL,_IONBF,0);
10324         Doxygen::outputToWizard=TRUE;
10325         break;
10326       case 'T':
10327         msg("Warning: this option activates output generation via Django like template files. "
10328             "This option is scheduled for doxygen 2.0, is currently incomplete and highly experimental! "
10329             "Only use if you are a doxygen developer\n");
10330         g_useOutputTemplate=TRUE;
10331         break;
10332       case 'h':
10333       case '?':
10334         usage(argv[0]);
10335         exit(0);
10336         break;
10337       default:
10338         err("Unknown option \"-%c\"\n",argv[optind][1]);
10339         usage(argv[0]);
10340         exit(1);
10341     }
10342     optind++;
10343   }
10344   
10345   /**************************************************************************
10346    *            Parse or generate the config file                           *
10347    **************************************************************************/
10348
10349   Config::instance()->init();
10350
10351   if (genConfig)
10352   {
10353     generateConfigFile(configName,shortList);
10354     cleanUpDoxygen();
10355     exit(0);
10356   }
10357   if (genLayout)
10358   {
10359     writeDefaultLayoutFile(layoutName);
10360     cleanUpDoxygen();
10361     exit(0);
10362   }
10363
10364   QFileInfo configFileInfo1("Doxyfile"),configFileInfo2("doxyfile");
10365   if (optind>=argc)
10366   { 
10367     if (configFileInfo1.exists()) 
10368     {
10369       configName="Doxyfile";
10370     }
10371     else if (configFileInfo2.exists())
10372     {
10373       configName="doxyfile";
10374     }
10375     else
10376     {
10377       err("Doxyfile not found and no input file specified!\n");
10378       usage(argv[0]);
10379       exit(1);
10380     }
10381   }
10382   else
10383   {
10384     QFileInfo fi(argv[optind]);
10385     if (fi.exists() || qstrcmp(argv[optind],"-")==0)
10386     {
10387       configName=argv[optind];
10388     }
10389     else
10390     {
10391       err("configuration file %s not found!\n",argv[optind]);
10392       usage(argv[0]);
10393       exit(1);
10394     }
10395   }
10396
10397
10398   if (!Config::instance()->parse(configName,updateConfig))
10399   {
10400     err("could not open or read configuration file %s!\n",configName);
10401     cleanUpDoxygen();
10402     exit(1);
10403   }
10404
10405   if (updateConfig)
10406   {
10407     generateConfigFile(configName,shortList,TRUE);
10408     cleanUpDoxygen();
10409     exit(0);
10410   }
10411
10412   /* Perlmod wants to know the path to the config file.*/
10413   QFileInfo configFileInfo(configName);
10414   setPerlModDoxyfile(configFileInfo.absFilePath().data());
10415
10416 }
10417
10418 /** check and resolve config options */
10419 void checkConfiguration()
10420 {
10421   
10422   Config::instance()->substituteEnvironmentVars();
10423   Config::instance()->convertStrToVal();
10424   Config::instance()->check();
10425   
10426   initWarningFormat();
10427 }
10428
10429 /** adjust globals that depend on configuration settings. */
10430 void adjustConfiguration()
10431 {
10432   QCString outputLanguage=Config_getEnum("OUTPUT_LANGUAGE");
10433   if (!setTranslator(outputLanguage))
10434   {
10435     warn_uncond("Output language %s not supported! Using English instead.\n",
10436        outputLanguage.data());
10437   }
10438   QStrList &includePath = Config_getList("INCLUDE_PATH");
10439   char *s=includePath.first();
10440   while (s)
10441   {
10442     QFileInfo fi(s);
10443     addSearchDir(fi.absFilePath().utf8());
10444     s=includePath.next();
10445   }
10446
10447   /* Set the global html file extension. */ 
10448   Doxygen::htmlFileExtension = Config_getString("HTML_FILE_EXTENSION");
10449
10450
10451   Doxygen::xrefLists->setAutoDelete(TRUE);
10452
10453   Doxygen::parseSourcesNeeded = Config_getBool("CALL_GRAPH") || 
10454                                 Config_getBool("CALLER_GRAPH") ||
10455                                 Config_getBool("REFERENCES_RELATION") ||
10456                                 Config_getBool("REFERENCED_BY_RELATION");
10457
10458   Doxygen::markdownSupport = Config_getBool("MARKDOWN_SUPPORT");
10459   
10460   /**************************************************************************
10461    *            Add custom extension mappings
10462    **************************************************************************/
10463
10464   QStrList &extMaps = Config_getList("EXTENSION_MAPPING");
10465   char *mapping = extMaps.first();
10466   while (mapping)
10467   {
10468     QCString mapStr = mapping;
10469     int i;
10470     if ((i=mapStr.find('='))!=-1)
10471     {
10472       QCString ext=mapStr.left(i).stripWhiteSpace().lower();
10473       QCString language=mapStr.mid(i+1).stripWhiteSpace().lower();
10474       if (!updateLanguageMapping(ext,language))
10475       {
10476         err("Failed to map file extension '%s' to unsupported language '%s'.\n"
10477             "Check the EXTENSION_MAPPING setting in the config file.\n", 
10478             ext.data(),language.data());
10479       }
10480       else
10481       {
10482         msg("Adding custom extension mapping: .%s will be treated as language %s\n",
10483             ext.data(),language.data());
10484       }
10485     }
10486     mapping = extMaps.next();
10487   }
10488
10489
10490   // add predefined macro name to a dictionary
10491   QStrList &expandAsDefinedList =Config_getList("EXPAND_AS_DEFINED");
10492   s=expandAsDefinedList.first();
10493   while (s)
10494   {
10495     if (Doxygen::expandAsDefinedDict[s]==0)
10496     {
10497       Doxygen::expandAsDefinedDict.insert(s,(void *)666);
10498     }
10499     s=expandAsDefinedList.next();
10500   }
10501
10502   // read aliases and store them in a dictionary
10503   readAliases();
10504
10505   // store number of spaces in a tab into Doxygen::spaces
10506   int &tabSize = Config_getInt("TAB_SIZE");
10507   Doxygen::spaces.resize(tabSize+1);
10508   int sp;for (sp=0;sp<tabSize;sp++) Doxygen::spaces.at(sp)=' ';
10509   Doxygen::spaces.at(tabSize)='\0';
10510 }
10511
10512 #ifdef HAS_SIGNALS
10513 static void stopDoxygen(int)
10514 {
10515   QDir thisDir;
10516   msg("Cleaning up...\n");
10517   if (!Doxygen::entryDBFileName.isEmpty())
10518   {
10519     thisDir.remove(Doxygen::entryDBFileName);
10520   }
10521   if (!Doxygen::objDBFileName.isEmpty())
10522   {
10523     thisDir.remove(Doxygen::objDBFileName);
10524   }
10525   killpg(0,SIGINT);
10526   exit(1);
10527 }
10528 #endif
10529
10530 static void exitDoxygen()
10531 {
10532   if (!g_successfulRun)  // premature exit
10533   {
10534     QDir thisDir;
10535     msg("Exiting...\n");
10536     if (!Doxygen::entryDBFileName.isEmpty())
10537     {
10538       thisDir.remove(Doxygen::entryDBFileName);
10539     }
10540     if (!Doxygen::objDBFileName.isEmpty())
10541     {
10542       thisDir.remove(Doxygen::objDBFileName);
10543     }
10544   }
10545 }
10546
10547 static QCString createOutputDirectory(const QCString &baseDirName,
10548                                   const char *formatDirOption,
10549                                   const char *defaultDirName)
10550 {
10551   // Note the & on the next line, we modify the formatDirOption!
10552   QCString &formatDirName = Config_getString(formatDirOption);
10553   if (formatDirName.isEmpty())
10554   {
10555     formatDirName = baseDirName + defaultDirName;
10556   }
10557   else if (formatDirName[0]!='/' && (formatDirName.length()==1 || formatDirName[1]!=':'))
10558   {
10559     formatDirName.prepend(baseDirName+'/');
10560   }
10561   QDir formatDir(formatDirName);
10562   if (!formatDir.exists() && !formatDir.mkdir(formatDirName))
10563   {
10564     err("Could not create output directory %s\n", formatDirName.data());
10565     cleanUpDoxygen();
10566     exit(1);
10567   }
10568   return formatDirName;
10569 }
10570
10571 static QCString getQchFileName()
10572 {
10573   QCString const & qchFile = Config_getString("QCH_FILE");
10574   if (!qchFile.isEmpty())
10575   {
10576     return qchFile;
10577   }
10578
10579   QCString const & projectName = Config_getString("PROJECT_NAME");
10580   QCString const & versionText = Config_getString("PROJECT_NUMBER");
10581
10582   return QCString("../qch/")
10583       + (projectName.isEmpty() ? QCString("index") : projectName)
10584       + (versionText.isEmpty() ? QCString("") : QCString("-") + versionText)
10585       + QCString(".qch");
10586 }
10587
10588 void searchInputFiles()
10589 {
10590   QStrList &exclPatterns = Config_getList("EXCLUDE_PATTERNS");
10591   bool alwaysRecursive = Config_getBool("RECURSIVE");
10592   StringDict excludeNameDict(1009);
10593   excludeNameDict.setAutoDelete(TRUE);
10594
10595   // gather names of all files in the include path
10596   g_s.begin("Searching for include files...\n");
10597   QStrList &includePathList = Config_getList("INCLUDE_PATH");
10598   char *s=includePathList.first();
10599   while (s)
10600   {
10601     QStrList &pl = Config_getList("INCLUDE_FILE_PATTERNS");
10602     if (pl.count()==0) 
10603     {
10604       pl = Config_getList("FILE_PATTERNS");
10605     }
10606     readFileOrDirectory(s,0,Doxygen::includeNameDict,0,&pl,
10607                         &exclPatterns,0,0,
10608                         alwaysRecursive);
10609     s=includePathList.next(); 
10610   }
10611   g_s.end();
10612
10613   g_s.begin("Searching for example files...\n");
10614   QStrList &examplePathList = Config_getList("EXAMPLE_PATH");
10615   s=examplePathList.first();
10616   while (s)
10617   {
10618     readFileOrDirectory(s,0,Doxygen::exampleNameDict,0,
10619                         &Config_getList("EXAMPLE_PATTERNS"),
10620                         0,0,0,
10621                         (alwaysRecursive || Config_getBool("EXAMPLE_RECURSIVE")));
10622     s=examplePathList.next(); 
10623   }
10624   g_s.end();
10625
10626   g_s.begin("Searching for images...\n");
10627   QStrList &imagePathList=Config_getList("IMAGE_PATH");
10628   s=imagePathList.first();
10629   while (s)
10630   {
10631     readFileOrDirectory(s,0,Doxygen::imageNameDict,0,0,
10632                         0,0,0,
10633                         alwaysRecursive);
10634     s=imagePathList.next(); 
10635   }
10636   g_s.end();
10637
10638   g_s.begin("Searching for dot files...\n");
10639   QStrList &dotFileList=Config_getList("DOTFILE_DIRS");
10640   s=dotFileList.first();
10641   while (s)
10642   {
10643     readFileOrDirectory(s,0,Doxygen::dotFileNameDict,0,0,
10644                         0,0,0,
10645                         alwaysRecursive);
10646     s=dotFileList.next(); 
10647   }
10648   g_s.end();
10649
10650   g_s.begin("Searching for msc files...\n");
10651   QStrList &mscFileList=Config_getList("MSCFILE_DIRS");
10652   s=mscFileList.first();
10653   while (s)
10654   {
10655     readFileOrDirectory(s,0,Doxygen::mscFileNameDict,0,0,
10656                         0,0,0,
10657                         alwaysRecursive);
10658     s=mscFileList.next(); 
10659   }
10660   g_s.end();
10661
10662   g_s.begin("Searching for dia files...\n");
10663   QStrList &diaFileList=Config_getList("DIAFILE_DIRS");
10664   s=diaFileList.first();
10665   while (s)
10666   {
10667     readFileOrDirectory(s,0,Doxygen::diaFileNameDict,0,0,
10668                         0,0,0,
10669                         alwaysRecursive);
10670     s=diaFileList.next();
10671   }
10672   g_s.end();
10673
10674   g_s.begin("Searching for files to exclude\n");
10675   QStrList &excludeList = Config_getList("EXCLUDE");
10676   s=excludeList.first();
10677   while (s)
10678   {
10679     readFileOrDirectory(s,0,0,0,&Config_getList("FILE_PATTERNS"),
10680                         0,0,&excludeNameDict,
10681                         alwaysRecursive,
10682                         FALSE);
10683     s=excludeList.next();
10684   }
10685   g_s.end();
10686
10687   /**************************************************************************
10688    *             Determine Input Files                                      *
10689    **************************************************************************/
10690
10691   g_s.begin("Searching for files to process...\n");
10692   QDict<void> *killDict = new QDict<void>(10007);
10693   int inputSize=0;
10694   QStrList &inputList=Config_getList("INPUT");
10695   g_inputFiles.setAutoDelete(TRUE);
10696   s=inputList.first();
10697   while (s)
10698   {
10699     QCString path=s;
10700     uint l = path.length();
10701     if (l>0)
10702     {
10703       // strip trailing slashes
10704       if (path.at(l-1)=='\\' || path.at(l-1)=='/') path=path.left(l-1);
10705   
10706       inputSize+=readFileOrDirectory(
10707           path,
10708           Doxygen::inputNameList,
10709           Doxygen::inputNameDict,
10710           &excludeNameDict,
10711           &Config_getList("FILE_PATTERNS"),
10712           &exclPatterns,
10713           &g_inputFiles,0,
10714           alwaysRecursive,
10715           TRUE,
10716           killDict,
10717           &Doxygen::inputPaths);
10718     }
10719     s=inputList.next();
10720   }
10721   delete killDict;
10722   g_s.end();
10723 }
10724
10725   
10726 void parseInput()
10727 {
10728   atexit(exitDoxygen);
10729
10730
10731   /**************************************************************************
10732    *            Make sure the output directory exists
10733    **************************************************************************/
10734   QCString &outputDirectory = Config_getString("OUTPUT_DIRECTORY");
10735   if (outputDirectory.isEmpty()) 
10736   {
10737     outputDirectory=QDir::currentDirPath().utf8();
10738   }
10739   else
10740   {
10741     QDir dir(outputDirectory);
10742     if (!dir.exists())
10743     {
10744       dir.setPath(QDir::currentDirPath());
10745       if (!dir.mkdir(outputDirectory))
10746       {
10747         err("tag OUTPUT_DIRECTORY: Output directory `%s' does not "
10748             "exist and cannot be created\n",outputDirectory.data());
10749         cleanUpDoxygen();
10750         exit(1);
10751       }
10752       else
10753       {
10754         msg("Notice: Output directory `%s' does not exist. "
10755             "I have created it for you.\n", outputDirectory.data());
10756       }
10757       dir.cd(outputDirectory);
10758     }
10759     outputDirectory=dir.absPath().utf8();
10760   }
10761
10762   /**************************************************************************
10763    *            Initialize global lists and dictionaries
10764    **************************************************************************/
10765
10766   Doxygen::symbolStorage = new Store;
10767
10768   // also scale lookup cache with SYMBOL_CACHE_SIZE
10769   int cacheSize = Config_getInt("LOOKUP_CACHE_SIZE");
10770   if (cacheSize<0) cacheSize=0;
10771   if (cacheSize>9) cacheSize=9;
10772   uint lookupSize = 65536 << cacheSize;
10773   Doxygen::lookupCache = new QCache<LookupInfo>(lookupSize,lookupSize);
10774   Doxygen::lookupCache->setAutoDelete(TRUE);
10775
10776 #ifdef HAS_SIGNALS
10777   signal(SIGINT, stopDoxygen);
10778 #endif
10779
10780   uint pid = portable_pid();
10781   Doxygen::objDBFileName.sprintf("doxygen_objdb_%d.tmp",pid);
10782   Doxygen::objDBFileName.prepend(outputDirectory+"/");
10783   Doxygen::entryDBFileName.sprintf("doxygen_entrydb_%d.tmp",pid);
10784   Doxygen::entryDBFileName.prepend(outputDirectory+"/");
10785   
10786   if (Doxygen::symbolStorage->open(Doxygen::objDBFileName)==-1)
10787   {
10788     err("Failed to open temporary file %s\n",Doxygen::objDBFileName.data());
10789     exit(1);
10790   }
10791
10792
10793
10794   /**************************************************************************
10795    *            Check/create output directorties                            *
10796    **************************************************************************/
10797
10798   QCString htmlOutput;
10799   bool &generateHtml = Config_getBool("GENERATE_HTML");
10800   if (generateHtml)
10801     htmlOutput = createOutputDirectory(outputDirectory,"HTML_OUTPUT","/html");
10802
10803   QCString docbookOutput;
10804   bool &generateDocbook = Config_getBool("GENERATE_DOCBOOK");
10805   if (generateDocbook)
10806     docbookOutput = createOutputDirectory(outputDirectory,"DOCBOOK_OUTPUT","/docbook");
10807
10808   QCString xmlOutput;
10809   bool &generateXml = Config_getBool("GENERATE_XML");
10810   if (generateXml)
10811     xmlOutput = createOutputDirectory(outputDirectory,"XML_OUTPUT","/xml");
10812     
10813   QCString latexOutput;
10814   bool &generateLatex = Config_getBool("GENERATE_LATEX");
10815   if (generateLatex)
10816     latexOutput = createOutputDirectory(outputDirectory,"LATEX_OUTPUT","/latex");
10817
10818   QCString rtfOutput;
10819   bool &generateRtf = Config_getBool("GENERATE_RTF");
10820   if (generateRtf)
10821     rtfOutput = createOutputDirectory(outputDirectory,"RTF_OUTPUT","/rtf");
10822
10823   QCString manOutput;
10824   bool &generateMan = Config_getBool("GENERATE_MAN");
10825   if (generateMan)
10826     manOutput = createOutputDirectory(outputDirectory,"MAN_OUTPUT","/man");
10827
10828   //QCString sqlOutput;
10829   //bool &generateSql = Config_getBool("GENERATE_SQLITE3");
10830   //if (generateSql)
10831   //  sqlOutput = createOutputDirectory(outputDirectory,"SQLITE3_OUTPUT","/sqlite3");
10832
10833   if (Config_getBool("HAVE_DOT"))
10834   {
10835     QCString curFontPath = Config_getString("DOT_FONTPATH");
10836     if (curFontPath.isEmpty())
10837     {
10838       portable_getenv("DOTFONTPATH");
10839       QCString newFontPath = ".";
10840       if (!curFontPath.isEmpty())
10841       {
10842         newFontPath+=portable_pathListSeparator();
10843         newFontPath+=curFontPath;
10844       }
10845       portable_setenv("DOTFONTPATH",newFontPath);
10846     }
10847     else
10848     {
10849       portable_setenv("DOTFONTPATH",curFontPath);
10850     }
10851   }
10852
10853
10854
10855   /**************************************************************************
10856    *             Handle layout file                                         *
10857    **************************************************************************/
10858
10859   LayoutDocManager::instance().init();
10860   QCString &layoutFileName = Config_getString("LAYOUT_FILE");
10861   bool defaultLayoutUsed = FALSE;
10862   if (layoutFileName.isEmpty())
10863   {
10864     layoutFileName = "DoxygenLayout.xml";
10865     defaultLayoutUsed = TRUE;
10866   }
10867
10868   QFile layoutFile(layoutFileName);
10869   if (layoutFile.open(IO_ReadOnly))
10870   {
10871     msg("Parsing layout file %s...\n",layoutFileName.data());
10872     QTextStream t(&layoutFile); 
10873     t.setEncoding(QTextStream::Latin1);
10874     LayoutDocManager::instance().parse(t,layoutFileName);
10875   }
10876   else if (!defaultLayoutUsed)
10877   {
10878     warn_uncond("failed to open layout file '%s' for reading!\n",layoutFileName.data());
10879   }
10880
10881   /**************************************************************************
10882    *             Read and preprocess input                                  *
10883    **************************************************************************/
10884  
10885   // prevent search in the output directories
10886   QStrList &exclPatterns = Config_getList("EXCLUDE_PATTERNS");
10887   if (generateHtml)    exclPatterns.append(htmlOutput);
10888   if (generateDocbook) exclPatterns.append(docbookOutput);
10889   if (generateXml)     exclPatterns.append(xmlOutput);
10890   if (generateLatex)   exclPatterns.append(latexOutput);
10891   if (generateRtf)     exclPatterns.append(rtfOutput);
10892   if (generateMan)     exclPatterns.append(manOutput);
10893
10894   searchInputFiles();
10895
10896   // Notice: the order of the function calls below is very important!
10897   
10898   if (Config_getBool("GENERATE_HTML"))
10899   {
10900     readFormulaRepository();
10901   }
10902   
10903   /**************************************************************************
10904    *             Handle Tag Files                                           *
10905    **************************************************************************/
10906
10907   g_storage = new FileStorage;
10908   g_storage->setName(Doxygen::entryDBFileName);
10909   if (!g_storage->open(IO_WriteOnly))
10910   {
10911     err("Failed to create temporary storage file %s\n",
10912         Doxygen::entryDBFileName.data());
10913     exit(1);
10914   }
10915   Entry *root=new Entry;
10916   EntryNav *rootNav = new EntryNav(0,root);
10917   rootNav->setEntry(root);
10918   msg("Reading and parsing tag files\n");
10919   
10920   QStrList &tagFileList = Config_getList("TAGFILES");
10921   char *s=tagFileList.first();
10922   while (s)
10923   {
10924     readTagFile(root,s);
10925     root->createNavigationIndex(rootNav,g_storage,0);
10926     s=tagFileList.next();
10927   }
10928   
10929   /**************************************************************************
10930    *             Parse source files                                         * 
10931    **************************************************************************/
10932
10933   if (Config_getBool("BUILTIN_STL_SUPPORT"))
10934   {
10935     addSTLClasses(rootNav);
10936   }
10937
10938   g_s.begin("Parsing files\n");
10939   parseFiles(root,rootNav);
10940   g_storage->close();
10941   g_s.end();
10942
10943   // we are done with input scanning now, so free up the buffers used by flex
10944   // (can be around 4MB)
10945   preFreeScanner();
10946   scanFreeScanner();
10947   pyscanFreeScanner();
10948
10949   if (!g_storage->open(IO_ReadOnly))
10950   {
10951     err("Failed to open temporary storage file %s for reading",
10952         Doxygen::entryDBFileName.data());
10953     exit(1);
10954   }
10955
10956   /**************************************************************************
10957    *             Gather information                                         * 
10958    **************************************************************************/
10959
10960   g_s.begin("Building group list...\n");
10961   buildGroupList(rootNav);
10962   organizeSubGroups(rootNav);
10963   g_s.end();
10964
10965   g_s.begin("Building directory list...\n");
10966   buildDirectories();
10967   findDirDocumentation(rootNav);
10968   g_s.end();
10969
10970   g_s.begin("Building namespace list...\n");
10971   buildNamespaceList(rootNav);
10972   findUsingDirectives(rootNav);
10973   g_s.end();
10974
10975   g_s.begin("Building file list...\n");
10976   buildFileList(rootNav);
10977   g_s.end();
10978   //generateFileTree();
10979
10980   g_s.begin("Building class list...\n");
10981   buildClassList(rootNav);
10982   g_s.end();
10983
10984   g_s.begin("Associating documentation with classes...\n");
10985   buildClassDocList(rootNav);
10986
10987   // build list of using declarations here (global list)
10988   buildListOfUsingDecls(rootNav);
10989   g_s.end();
10990
10991   g_s.begin("Computing nesting relations for classes...\n");
10992   resolveClassNestingRelations();
10993   g_s.end();
10994   // 1.8.2-20121111: no longer add nested classes to the group as well
10995   //distributeClassGroupRelations(); 
10996
10997   // calling buildClassList may result in cached relations that
10998   // become invalid after resolveClassNestingRelations(), that's why
10999   // we need to clear the cache here
11000   Doxygen::lookupCache->clear();
11001   // we don't need the list of using declaration anymore
11002   g_usingDeclarations.clear();
11003
11004   g_s.begin("Building example list...\n");
11005   buildExampleList(rootNav);
11006   g_s.end();
11007
11008   g_s.begin("Searching for enumerations...\n");
11009   findEnums(rootNav);
11010   g_s.end();
11011
11012   // Since buildVarList calls isVarWithConstructor
11013   // and this calls getResolvedClass we need to process
11014   // typedefs first so the relations between classes via typedefs
11015   // are properly resolved. See bug 536385 for an example.
11016   g_s.begin("Searching for documented typedefs...\n");
11017   buildTypedefList(rootNav);
11018   g_s.end();
11019
11020   g_s.begin("Searching for members imported via using declarations...\n");
11021   findUsingDeclImports(rootNav);
11022   // this should be after buildTypedefList in order to properly import
11023   // used typedefs
11024   findUsingDeclarations(rootNav);
11025   g_s.end();
11026
11027   g_s.begin("Searching for included using directives...\n");
11028   findIncludedUsingDirectives();
11029   g_s.end();
11030
11031   g_s.begin("Searching for documented variables...\n");
11032   buildVarList(rootNav);
11033   g_s.end();
11034
11035   g_s.begin("Building interface member list...\n");
11036   buildInterfaceAndServiceList(rootNav); // UNO IDL
11037
11038   g_s.begin("Building member list...\n"); // using class info only !
11039   buildFunctionList(rootNav);
11040   g_s.end();
11041
11042   g_s.begin("Searching for friends...\n");
11043   findFriends();
11044   g_s.end();
11045
11046   g_s.begin("Searching for documented defines...\n");
11047   findDefineDocumentation(rootNav);
11048   g_s.end();
11049
11050   g_s.begin("Computing class inheritance relations...\n");
11051   findClassEntries(rootNav);
11052   findInheritedTemplateInstances();
11053   g_s.end();
11054
11055   g_s.begin("Computing class usage relations...\n");
11056   findUsedTemplateInstances();
11057   g_s.end();
11058
11059   if (Config_getBool("INLINE_SIMPLE_STRUCTS"))
11060   {
11061     g_s.begin("Searching for tag less structs...\n");
11062     findTagLessClasses();
11063     g_s.end();
11064   }
11065
11066   g_s.begin("Flushing cached template relations that have become invalid...\n");
11067   flushCachedTemplateRelations();
11068   g_s.end();
11069
11070   g_s.begin("Creating members for template instances...\n");
11071   createTemplateInstanceMembers();
11072   g_s.end();
11073
11074   g_s.begin("Computing class relations...\n");
11075   computeTemplateClassRelations();
11076   flushUnresolvedRelations();
11077   if (Config_getBool("OPTIMIZE_OUTPUT_VHDL"))
11078   {
11079     VhdlDocGen::computeVhdlComponentRelations();
11080   }
11081   computeClassRelations();
11082   g_classEntries.clear();
11083   g_s.end();
11084
11085   g_s.begin("Add enum values to enums...\n");
11086   addEnumValuesToEnums(rootNav);
11087   findEnumDocumentation(rootNav);
11088   g_s.end();
11089
11090   g_s.begin("Searching for member function documentation...\n");
11091   findObjCMethodDefinitions(rootNav);
11092   findMemberDocumentation(rootNav); // may introduce new members !
11093
11094   transferRelatedFunctionDocumentation();
11095   transferFunctionDocumentation();
11096   g_s.end();
11097
11098   g_s.begin("Building page list...\n");
11099   buildPageList(rootNav);
11100   g_s.end();
11101
11102   g_s.begin("Search for main page...\n");
11103   findMainPage(rootNav);
11104   findMainPageTagFiles(rootNav);
11105   g_s.end();
11106
11107   g_s.begin("Computing page relations...\n");
11108   computePageRelations(rootNav);
11109   checkPageRelations();
11110   g_s.end();
11111
11112   g_s.begin("Determining the scope of groups...\n");
11113   findGroupScope(rootNav);
11114   g_s.end();
11115
11116   g_s.begin("Sorting lists...\n");
11117   Doxygen::memberNameSDict->sort();
11118   Doxygen::functionNameSDict->sort();
11119   Doxygen::hiddenClasses->sort();
11120   Doxygen::classSDict->sort();
11121   g_s.end();
11122
11123   msg("Freeing entry tree\n");
11124   delete rootNav;
11125   g_storage->close();
11126   delete g_storage;
11127   g_storage=0;
11128
11129   QDir thisDir;
11130   thisDir.remove(Doxygen::entryDBFileName);
11131
11132   g_s.begin("Determining which enums are documented\n");
11133   findDocumentedEnumValues();
11134   g_s.end();
11135
11136   g_s.begin("Computing member relations...\n");
11137   mergeCategories();
11138   computeMemberRelations();
11139   g_s.end();
11140
11141   g_s.begin("Building full member lists recursively...\n");
11142   buildCompleteMemberLists();
11143   g_s.end();
11144
11145   g_s.begin("Adding members to member groups.\n");
11146   addMembersToMemberGroup();
11147   g_s.end();
11148
11149   if (Config_getBool("DISTRIBUTE_GROUP_DOC"))
11150   {
11151     g_s.begin("Distributing member group documentation.\n");
11152     distributeMemberGroupDocumentation();
11153     g_s.end();
11154   }
11155
11156   g_s.begin("Computing member references...\n");
11157   computeMemberReferences();
11158   g_s.end();
11159
11160   if (Config_getBool("INHERIT_DOCS"))
11161   {
11162     g_s.begin("Inheriting documentation...\n");
11163     inheritDocumentation();
11164     g_s.end();
11165   }
11166
11167   // compute the shortest possible names of all files
11168   // without losing the uniqueness of the file names.
11169   g_s.begin("Generating disk names...\n");
11170   Doxygen::inputNameList->generateDiskNames();
11171   g_s.end();
11172
11173   g_s.begin("Adding source references...\n");
11174   addSourceReferences();
11175   g_s.end();
11176
11177   g_s.begin("Adding xrefitems...\n");
11178   addListReferences();
11179   generateXRefPages();
11180   g_s.end();
11181
11182   g_s.begin("Sorting member lists...\n");
11183   sortMemberLists();
11184   g_s.end();
11185
11186   if (Config_getBool("DIRECTORY_GRAPH"))
11187   {
11188     g_s.begin("Computing dependencies between directories...\n");
11189     computeDirDependencies();
11190     g_s.end();
11191   }
11192
11193   //g_s.begin("Resolving citations...\n");
11194   //Doxygen::citeDict->resolve();
11195
11196   g_s.begin("Generating citations page...\n");
11197   Doxygen::citeDict->generatePage();
11198   g_s.end();
11199
11200   g_s.begin("Counting data structures...\n");
11201   countDataStructures();
11202   g_s.end();
11203
11204   g_s.begin("Resolving user defined references...\n");
11205   resolveUserReferences();
11206   g_s.end();
11207
11208   g_s.begin("Finding anchors and sections in the documentation...\n");
11209   findSectionsInDocumentation();
11210   g_s.end();
11211
11212   g_s.begin("Transferring function references...\n");
11213   transferFunctionReferences();
11214   g_s.end();
11215
11216   g_s.begin("Combining using relations...\n");
11217   combineUsingRelations();
11218   g_s.end();
11219
11220   g_s.begin("Adding members to index pages...\n");
11221   addMembersToIndex();
11222   g_s.end();
11223 }
11224
11225 void generateOutput()
11226 {
11227   /**************************************************************************
11228    *            Initialize output generators                                *
11229    **************************************************************************/
11230
11231   //// dump all symbols
11232   if (g_dumpSymbolMap)
11233   {
11234     dumpSymbolMap();
11235     exit(0);
11236   }
11237
11238   initSearchIndexer();
11239
11240   bool generateHtml  = Config_getBool("GENERATE_HTML");
11241   bool generateLatex = Config_getBool("GENERATE_LATEX");
11242   bool generateMan   = Config_getBool("GENERATE_MAN");
11243   bool generateRtf   = Config_getBool("GENERATE_RTF");
11244
11245
11246   g_outputList = new OutputList(TRUE);
11247   if (generateHtml)  
11248   {
11249     g_outputList->add(new HtmlGenerator);
11250     HtmlGenerator::init();
11251
11252     // add HTML indexers that are enabled
11253     bool generateHtmlHelp    = Config_getBool("GENERATE_HTMLHELP");
11254     bool generateEclipseHelp = Config_getBool("GENERATE_ECLIPSEHELP");
11255     bool generateQhp         = Config_getBool("GENERATE_QHP");
11256     bool generateTreeView    = Config_getBool("GENERATE_TREEVIEW");
11257     bool generateDocSet      = Config_getBool("GENERATE_DOCSET");
11258     if (generateEclipseHelp) Doxygen::indexList->addIndex(new EclipseHelp);
11259     if (generateHtmlHelp)    Doxygen::indexList->addIndex(new HtmlHelp);
11260     if (generateQhp)         Doxygen::indexList->addIndex(new Qhp);
11261     if (generateTreeView)    Doxygen::indexList->addIndex(new FTVHelp(TRUE));
11262     if (generateDocSet)      Doxygen::indexList->addIndex(new DocSets);
11263     Doxygen::indexList->initialize();
11264     HtmlGenerator::writeTabData();
11265
11266     // copy static stuff
11267     copyStyleSheet();
11268     copyLogo();
11269     copyExtraFiles("HTML_EXTRA_FILES","HTML_OUTPUT");
11270     FTVHelp::generateTreeViewImages();
11271   }
11272   if (generateLatex) 
11273   {
11274     g_outputList->add(new LatexGenerator);
11275     LatexGenerator::init();
11276
11277     // copy static stuff
11278     copyExtraFiles("LATEX_EXTRA_FILES","LATEX_OUTPUT");
11279   }
11280   if (generateMan)
11281   {
11282     g_outputList->add(new ManGenerator);
11283     ManGenerator::init();
11284   }
11285   if (generateRtf)
11286   {
11287     g_outputList->add(new RTFGenerator);
11288     RTFGenerator::init();
11289   }
11290   if (Config_getBool("USE_HTAGS"))
11291   {
11292     Htags::useHtags = TRUE;
11293     QCString htmldir = Config_getString("HTML_OUTPUT");
11294     if (!Htags::execute(htmldir))
11295        err("USE_HTAGS is YES but htags(1) failed. \n");
11296     if (!Htags::loadFilemap(htmldir))
11297        err("htags(1) ended normally but failed to load the filemap. \n");
11298   }
11299   
11300   /**************************************************************************
11301    *                        Generate documentation                          *
11302    **************************************************************************/
11303
11304   QFile *tag=0;
11305   QCString &generateTagFile = Config_getString("GENERATE_TAGFILE");
11306   if (!generateTagFile.isEmpty())
11307   {
11308     tag=new QFile(generateTagFile);
11309     if (!tag->open(IO_WriteOnly))
11310     {
11311       err("cannot open tag file %s for writing\n",
11312           generateTagFile.data()
11313          );
11314       cleanUpDoxygen();
11315       exit(1);
11316     }
11317     Doxygen::tagFile.setDevice(tag);
11318     Doxygen::tagFile << "<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>" << endl;
11319     Doxygen::tagFile << "<tagfile>" << endl;
11320   }
11321
11322   if (generateHtml)  writeDoxFont(Config_getString("HTML_OUTPUT"));
11323   if (generateLatex) writeDoxFont(Config_getString("LATEX_OUTPUT"));
11324   if (generateRtf)   writeDoxFont(Config_getString("RTF_OUTPUT"));
11325
11326   g_s.begin("Generating style sheet...\n");
11327   //printf("writing style info\n");
11328   g_outputList->writeStyleInfo(0); // write first part
11329   g_s.end();
11330
11331   static bool searchEngine      = Config_getBool("SEARCHENGINE");
11332   static bool serverBasedSearch = Config_getBool("SERVER_BASED_SEARCH");
11333
11334   // generate search indices (need to do this before writing other HTML
11335   // pages as these contain a drop down menu with options depending on
11336   // what categories we find in this function.
11337   if (generateHtml && searchEngine)
11338   {
11339     g_s.begin("Generating search indices...\n");
11340     QCString searchDirName = Config_getString("HTML_OUTPUT")+"/search";
11341     QDir searchDir(searchDirName);
11342     if (!searchDir.exists() && !searchDir.mkdir(searchDirName))
11343     {
11344       err("Could not create search results directory '%s' $PWD='%s'\n",
11345           searchDirName.data(),QDir::currentDirPath().data());
11346       exit(1);
11347     }
11348     HtmlGenerator::writeSearchData(searchDirName);
11349     if (!serverBasedSearch) // client side search index
11350     {
11351       writeJavascriptSearchIndex();
11352     }
11353     g_s.end();
11354   }
11355
11356   g_s.begin("Generating example documentation...\n");
11357   generateExampleDocs();
11358   g_s.end();
11359
11360   if (!Htags::useHtags)
11361   {
11362     g_s.begin("Generating file sources...\n");
11363     generateFileSources();
11364     g_s.end();
11365   }
11366
11367   g_s.begin("Generating file documentation...\n");
11368   generateFileDocs();
11369   g_s.end();
11370
11371   g_s.begin("Generating page documentation...\n");
11372   generatePageDocs();
11373   g_s.end();
11374
11375   g_s.begin("Generating group documentation...\n");
11376   generateGroupDocs();
11377   g_s.end();
11378
11379   g_s.begin("Generating class documentation...\n");
11380   generateClassDocs();
11381   g_s.end();
11382
11383   g_s.begin("Generating namespace index...\n");
11384   generateNamespaceDocs();
11385   g_s.end();
11386
11387   if (Config_getBool("GENERATE_LEGEND"))
11388   {
11389     g_s.begin("Generating graph info page...\n");
11390     writeGraphInfo(*g_outputList);
11391     g_s.end();
11392   }
11393
11394   g_s.begin("Generating directory documentation...\n");
11395   generateDirDocs(*g_outputList);
11396   g_s.end();
11397
11398   if (Doxygen::formulaList->count()>0 && generateHtml
11399       && !Config_getBool("USE_MATHJAX"))
11400   {
11401     g_s.begin("Generating bitmaps for formulas in HTML...\n");
11402     Doxygen::formulaList->generateBitmaps(Config_getString("HTML_OUTPUT"));
11403     g_s.end();
11404   }
11405
11406   if (Config_getBool("SORT_GROUP_NAMES"))
11407   {
11408     Doxygen::groupSDict->sort();
11409     GroupSDict::Iterator gli(*Doxygen::groupSDict);
11410     GroupDef *gd;
11411     for (gli.toFirst();(gd=gli.current());++gli)
11412     {
11413       gd->sortSubGroups();
11414     }
11415   }
11416   
11417   writeMainPageTagFileData();
11418
11419   if (g_outputList->count()>0)
11420   {
11421     writeIndexHierarchy(*g_outputList);
11422   }
11423
11424   g_s.begin("finalizing index lists...\n");
11425   Doxygen::indexList->finalize();
11426   g_s.end();
11427
11428   if (!generateTagFile.isEmpty())
11429   {
11430     Doxygen::tagFile << "</tagfile>" << endl;
11431     delete tag;
11432   }
11433
11434   if (Config_getBool("DOT_CLEANUP"))
11435   {
11436     if (generateHtml)
11437       removeDoxFont(Config_getString("HTML_OUTPUT"));
11438     if (generateRtf)  
11439       removeDoxFont(Config_getString("RTF_OUTPUT"));
11440     if (generateLatex)  
11441       removeDoxFont(Config_getString("LATEX_OUTPUT"));
11442   }
11443
11444   if (Config_getBool("GENERATE_XML"))
11445   {
11446     g_s.begin("Generating XML output...\n");
11447     Doxygen::generatingXmlOutput=TRUE;
11448     generateXML();
11449     Doxygen::generatingXmlOutput=FALSE;
11450     g_s.end();
11451   }
11452   if (USE_SQLITE3)
11453   {
11454     g_s.begin("Generating SQLITE3 output...\n");
11455     generateSqlite3();
11456     g_s.end();
11457   }
11458
11459   if (Config_getBool("GENERATE_DOCBOOK"))
11460   {
11461     g_s.begin("Generating Docbook output...\n");
11462     generateDocbook();
11463     g_s.end();
11464   }
11465
11466   if (Config_getBool("GENERATE_AUTOGEN_DEF"))
11467   {
11468     g_s.begin("Generating AutoGen DEF output...\n");
11469     generateDEF();
11470     g_s.end();
11471   }
11472   if (Config_getBool("GENERATE_PERLMOD"))
11473   {
11474     g_s.begin("Generating Perl module output...\n");
11475     generatePerlMod();
11476     g_s.end();
11477   }
11478   if (generateHtml && searchEngine && serverBasedSearch)
11479   {
11480     g_s.begin("Generating search index\n");
11481     if (Doxygen::searchIndex->kind()==SearchIndexIntf::Internal) // write own search index
11482     {
11483       HtmlGenerator::writeSearchPage();
11484       Doxygen::searchIndex->write(Config_getString("HTML_OUTPUT")+"/search/search.idx");
11485     }
11486     else // write data for external search index
11487     {
11488       HtmlGenerator::writeExternalSearchPage();
11489       QCString searchDataFile = Config_getString("SEARCHDATA_FILE");
11490       if (searchDataFile.isEmpty())
11491       {
11492         searchDataFile="searchdata.xml";
11493       }
11494       if (!portable_isAbsolutePath(searchDataFile))
11495       {
11496         searchDataFile.prepend(Config_getString("OUTPUT_DIRECTORY")+"/");
11497       }
11498       Doxygen::searchIndex->write(searchDataFile);
11499     }
11500     g_s.end();
11501   }
11502
11503   if (g_useOutputTemplate) generateOutputViaTemplate();
11504
11505   if (generateRtf)
11506   {
11507     g_s.begin("Combining RTF output...\n");
11508     if (!RTFGenerator::preProcessFileInplace(Config_getString("RTF_OUTPUT"),"refman.rtf"))
11509     {
11510       err("An error occurred during post-processing the RTF files!\n");
11511     }
11512     g_s.end();
11513   }
11514
11515   if (Config_getBool("HAVE_DOT"))
11516   {
11517     g_s.begin("Running dot...\n");
11518     DotManager::instance()->run();
11519     g_s.end();
11520   }
11521
11522   if (generateHtml &&
11523       Config_getBool("GENERATE_HTMLHELP") && 
11524       !Config_getString("HHC_LOCATION").isEmpty())
11525   {
11526     g_s.begin("Running html help compiler...\n");
11527     QString oldDir = QDir::currentDirPath();
11528     QDir::setCurrent(Config_getString("HTML_OUTPUT"));
11529     portable_sysTimerStart();
11530     if (portable_system(Config_getString("HHC_LOCATION"), "index.hhp", FALSE))
11531     {
11532       err("failed to run html help compiler on index.hhp\n");
11533     }
11534     portable_sysTimerStop();
11535     QDir::setCurrent(oldDir);
11536     g_s.end();
11537   }
11538   if ( generateHtml &&
11539        Config_getBool("GENERATE_QHP") && 
11540       !Config_getString("QHG_LOCATION").isEmpty())
11541   {
11542     g_s.begin("Running qhelpgenerator...\n");
11543     QCString const qhpFileName = Qhp::getQhpFileName();
11544     QCString const qchFileName = getQchFileName();
11545
11546     QCString const args = QCString().sprintf("%s -o \"%s\"", qhpFileName.data(), qchFileName.data());
11547     QString const oldDir = QDir::currentDirPath();
11548     QDir::setCurrent(Config_getString("HTML_OUTPUT"));
11549     portable_sysTimerStart();
11550     if (portable_system(Config_getString("QHG_LOCATION"), args.data(), FALSE))
11551     {
11552       err("failed to run qhelpgenerator on index.qhp\n");
11553     }
11554     portable_sysTimerStop();
11555     QDir::setCurrent(oldDir);
11556     g_s.end();
11557   }
11558
11559   int cacheParam;
11560   msg("lookup cache used %d/%d hits=%d misses=%d\n",
11561       Doxygen::lookupCache->count(),
11562       Doxygen::lookupCache->size(),
11563       Doxygen::lookupCache->hits(),
11564       Doxygen::lookupCache->misses());
11565   cacheParam = computeIdealCacheParam(Doxygen::lookupCache->misses()*2/3); // part of the cache is flushed, hence the 2/3 correction factor
11566   if (cacheParam>Config_getInt("LOOKUP_CACHE_SIZE"))
11567   {
11568     msg("Note: based on cache misses the ideal setting for LOOKUP_CACHE_SIZE is %d at the cost of higher memory usage.\n",cacheParam);
11569   }
11570
11571   if (Debug::isFlagSet(Debug::Time))
11572   {
11573     msg("Total elapsed time: %.3f seconds\n(of which %.3f seconds waiting for external tools to finish)\n",
11574          ((double)Doxygen::runningTime.elapsed())/1000.0,
11575          portable_getSysElapsedTime()
11576         );
11577     g_s.print();
11578   }
11579   else
11580   {
11581     msg("finished...\n");
11582   }
11583
11584
11585   /**************************************************************************
11586    *                        Start cleaning up                               *
11587    **************************************************************************/
11588
11589   cleanUpDoxygen();
11590
11591   finializeSearchIndexer();
11592   Doxygen::symbolStorage->close();
11593   QDir thisDir;
11594   thisDir.remove(Doxygen::objDBFileName);
11595   Config::deleteInstance();
11596   QTextCodec::deleteAllCodecs();
11597   delete Doxygen::symbolMap;
11598   delete Doxygen::clangUsrMap;
11599   delete Doxygen::symbolStorage;
11600   g_successfulRun=TRUE;
11601 }
11602