26eda84b95c9243212ae48794d743caadfdbdec8
[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 "vhdlscanner.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
102 #define RECURSE_ENTRYTREE(func,var) \
103   do { if (var->children()) { \
104     EntryNavListIterator eli(*var->children()); \
105     for (;eli.current();++eli) func(eli.current()); \
106   } } while(0) 
107
108
109 #if !defined(_WIN32) || defined(__CYGWIN__)
110 #include <signal.h>
111 #define HAS_SIGNALS
112 #endif
113
114 // globally accessible variables
115 ClassSDict      *Doxygen::classSDict = 0;
116 ClassSDict      *Doxygen::hiddenClasses = 0;
117 NamespaceSDict  *Doxygen::namespaceSDict = 0;
118 MemberNameSDict *Doxygen::memberNameSDict = 0;
119 MemberNameSDict *Doxygen::functionNameSDict = 0;   
120 FileNameList    *Doxygen::inputNameList = 0;       // all input files
121 FileNameDict    *Doxygen::inputNameDict = 0;          
122 GroupSDict      *Doxygen::groupSDict = 0;
123 FormulaList     *Doxygen::formulaList = 0;       // all formulas
124 FormulaDict     *Doxygen::formulaDict = 0;       // all formulas
125 FormulaDict     *Doxygen::formulaNameDict = 0;   // the label name of all formulas
126 PageSDict       *Doxygen::pageSDict = 0;
127 PageSDict       *Doxygen::exampleSDict = 0;
128 SectionDict     *Doxygen::sectionDict = 0;        // all page sections
129 CiteDict        *Doxygen::citeDict=0;              // database of bibliographic references
130 StringDict       Doxygen::aliasDict(257);          // aliases
131 QDict<void>      Doxygen::inputPaths(1009);
132 FileNameDict    *Doxygen::includeNameDict = 0;     // include names
133 FileNameDict    *Doxygen::exampleNameDict = 0;     // examples
134 FileNameDict    *Doxygen::imageNameDict = 0;       // images
135 FileNameDict    *Doxygen::dotFileNameDict = 0;     // dot files
136 FileNameDict    *Doxygen::mscFileNameDict = 0;     // msc files
137 FileNameDict    *Doxygen::diaFileNameDict = 0;     // dia files
138 StringDict       Doxygen::namespaceAliasDict(257); // all namespace aliases
139 StringDict       Doxygen::tagDestinationDict(257); // all tag locations
140 QDict<void>      Doxygen::expandAsDefinedDict(257); // all macros that should be expanded
141 QIntDict<MemberGroupInfo> Doxygen::memGrpInfoDict(1009); // dictionary of the member groups heading
142 PageDef         *Doxygen::mainPage = 0;
143 bool             Doxygen::insideMainPage = FALSE; // are we generating docs for the main page?
144 FTextStream      Doxygen::tagFile;
145 NamespaceDef    *Doxygen::globalScope = 0;
146 QDict<RefList>  *Doxygen::xrefLists = new QDict<RefList>; // dictionary of cross-referenced item lists
147 bool             Doxygen::parseSourcesNeeded = FALSE;
148 QTime            Doxygen::runningTime;
149 SearchIndexIntf *Doxygen::searchIndex=0;
150 QDict<DefinitionIntf> *Doxygen::symbolMap = 0;
151 QDict<Definition> *Doxygen::clangUsrMap = 0;
152 bool             Doxygen::outputToWizard=FALSE;
153 QDict<int> *     Doxygen::htmlDirMap = 0;
154 QCache<LookupInfo> *Doxygen::lookupCache;
155 DirSDict        *Doxygen::directories;
156 SDict<DirRelation> Doxygen::dirRelations(257);
157 ParserManager   *Doxygen::parserManager = 0;
158 QCString Doxygen::htmlFileExtension;
159 bool             Doxygen::suppressDocWarnings = FALSE;
160 Store           *Doxygen::symbolStorage;
161 QCString         Doxygen::objDBFileName;
162 QCString         Doxygen::entryDBFileName;
163 bool             Doxygen::gatherDefines = TRUE;
164 IndexList       *Doxygen::indexList;
165 int              Doxygen::subpageNestingLevel = 0;
166 bool             Doxygen::userComments = FALSE;
167 QCString         Doxygen::spaces;
168 bool             Doxygen::generatingXmlOutput = FALSE;
169 bool             Doxygen::markdownSupport = TRUE;
170 GenericsSDict   *Doxygen::genericsDict;
171
172 // locally accessible globals
173 static QDict<EntryNav>  g_classEntries(1009);
174 static StringList       g_inputFiles;         
175 static QDict<void>      g_compoundKeywordDict(7);  // keywords recognised as compounds
176 static OutputList      *g_outputList = 0;          // list of output generating objects
177 static QDict<FileDef>   g_usingDeclarations(1009); // used classes
178 static FileStorage     *g_storage = 0;
179 static bool             g_successfulRun = FALSE;
180 static bool             g_dumpSymbolMap = FALSE;
181 static bool             g_useOutputTemplate = FALSE; 
182
183 void clearAll()
184 {
185   g_inputFiles.clear();
186   //g_excludeNameDict.clear();
187   //delete g_outputList; g_outputList=0;
188
189   Doxygen::classSDict->clear();
190   Doxygen::namespaceSDict->clear();
191   Doxygen::pageSDict->clear();
192   Doxygen::exampleSDict->clear();
193   Doxygen::inputNameList->clear();
194   Doxygen::formulaList->clear();
195   Doxygen::sectionDict->clear();
196   Doxygen::inputNameDict->clear();
197   Doxygen::includeNameDict->clear();
198   Doxygen::exampleNameDict->clear();
199   Doxygen::imageNameDict->clear();
200   Doxygen::dotFileNameDict->clear();
201   Doxygen::mscFileNameDict->clear();
202   Doxygen::diaFileNameDict->clear();
203   Doxygen::formulaDict->clear();
204   Doxygen::formulaNameDict->clear();
205   Doxygen::tagDestinationDict.clear();
206   delete Doxygen::citeDict;
207   delete Doxygen::mainPage; Doxygen::mainPage=0;
208 }
209
210 class Statistics 
211 {
212   public:
213     Statistics() { stats.setAutoDelete(TRUE); }
214     void begin(const char *name)
215     {
216       msg(name);
217       stat *entry= new stat(name,0);
218       stats.append(entry);
219       time.restart();
220     }
221     void end()
222     {
223       stats.getLast()->elapsed=((double)time.elapsed())/1000.0;
224     }
225     void print()
226     {
227       bool restore=FALSE;
228       if (Debug::isFlagSet(Debug::Time))
229       {
230         Debug::clearFlag("time");
231         restore=TRUE;
232       }
233       msg("----------------------\n");
234       QListIterator<stat> sli(stats);
235       stat *s;
236       for ( sli.toFirst(); (s=sli.current()); ++sli )
237       {
238         msg("Spent %.3f seconds in %s",s->elapsed,s->name);
239       }
240       if (restore) Debug::setFlag("time");
241     }
242   private:
243     struct stat 
244     {
245       const char *name;
246       double elapsed;
247       stat() : name(NULL),elapsed(0) {}
248       stat(const char *n, double el) : name(n),elapsed(el) {}
249     };
250     QList<stat> stats;
251     QTime       time;
252 } g_s;
253
254
255 void statistics()
256 {
257   fprintf(stderr,"--- inputNameDict stats ----\n");
258   Doxygen::inputNameDict->statistics();
259   fprintf(stderr,"--- includeNameDict stats ----\n");
260   Doxygen::includeNameDict->statistics();
261   fprintf(stderr,"--- exampleNameDict stats ----\n");
262   Doxygen::exampleNameDict->statistics();
263   fprintf(stderr,"--- imageNameDict stats ----\n");
264   Doxygen::imageNameDict->statistics();
265   fprintf(stderr,"--- dotFileNameDict stats ----\n");
266   Doxygen::dotFileNameDict->statistics();
267   fprintf(stderr,"--- mscFileNameDict stats ----\n");
268   Doxygen::mscFileNameDict->statistics();
269   fprintf(stderr,"--- diaFileNameDict stats ----\n");
270   Doxygen::diaFileNameDict->statistics();
271   //fprintf(stderr,"--- g_excludeNameDict stats ----\n");
272   //g_excludeNameDict.statistics();
273   fprintf(stderr,"--- aliasDict stats ----\n");
274   Doxygen::aliasDict.statistics();
275   fprintf(stderr,"--- typedefDict stats ----\n");
276   fprintf(stderr,"--- namespaceAliasDict stats ----\n");
277   Doxygen::namespaceAliasDict.statistics();
278   fprintf(stderr,"--- formulaDict stats ----\n");
279   Doxygen::formulaDict->statistics();
280   fprintf(stderr,"--- formulaNameDict stats ----\n");
281   Doxygen::formulaNameDict->statistics();
282   fprintf(stderr,"--- tagDestinationDict stats ----\n");
283   Doxygen::tagDestinationDict.statistics();
284   fprintf(stderr,"--- g_compoundKeywordDict stats ----\n");
285   g_compoundKeywordDict.statistics();
286   fprintf(stderr,"--- expandAsDefinedDict stats ----\n");
287   Doxygen::expandAsDefinedDict.statistics();
288   fprintf(stderr,"--- memGrpInfoDict stats ----\n");
289   Doxygen::memGrpInfoDict.statistics();
290 }
291
292
293
294 static void addMemberDocs(EntryNav *rootNav,MemberDef *md, const char *funcDecl,
295                    ArgumentList *al,bool over_load,NamespaceSDict *nl=0);
296 static void findMember(EntryNav *rootNav,
297                        QCString funcDecl,
298                        bool overloaded,
299                        bool isFunc
300                       );
301
302 enum FindBaseClassRelation_Mode
303 {
304   TemplateInstances,
305   DocumentedOnly,
306   Undocumented
307 };
308
309 static bool findClassRelation(
310                            EntryNav *rootNav,
311                            Definition *context,
312                            ClassDef *cd,
313                            BaseInfo *bi,
314                            QDict<int> *templateNames,
315                            /*bool insertUndocumented*/
316                            FindBaseClassRelation_Mode mode,
317                            bool isArtificial
318                           );
319
320 /** A struct contained the data for an STL class */
321 struct STLInfo
322 {
323   const char *className;
324   const char *baseClass1;
325   const char *baseClass2;
326   const char *templType1;
327   const char *templName1;
328   const char *templType2;
329   const char *templName2;
330   bool virtualInheritance;
331   bool iterators;
332 };
333
334 static STLInfo g_stlinfo[] =
335 {
336   // className              baseClass1                      baseClass2             templType1     templName1     templType2    templName2     virtInheritance  // iterators
337   { "allocator",            0,                              0,                     "T",           "elements",    0,            0,             FALSE,              FALSE },
338   { "array",                0,                              0,                     "T",           "elements",    0,            0,             FALSE,              FALSE }, // C++11
339   { "auto_ptr",             0,                              0,                     "T",           "ptr",         0,            0,             FALSE,              FALSE }, // deprecated
340   { "smart_ptr",            0,                              0,                     "T",           "ptr",         0,            0,             FALSE,              FALSE }, // C++11
341   { "unique_ptr",           0,                              0,                     "T",           "ptr",         0,            0,             FALSE,              FALSE }, // C++11
342   { "weak_ptr",             0,                              0,                     "T",           "ptr",         0,            0,             FALSE,              FALSE }, // C++11
343   { "ios_base",             0,                              0,                     0,             0,             0,            0,             FALSE,              FALSE }, // C++11
344   { "error_code",           0,                              0,                     0,             0,             0,            0,             FALSE,              FALSE }, // C++11
345   { "error_category",       0,                              0,                     0,             0,             0,            0,             FALSE,              FALSE }, // C++11
346   { "system_error",         0,                              0,                     0,             0,             0,            0,             FALSE,              FALSE }, // C++11
347   { "error_condition",      0,                              0,                     0,             0,             0,            0,             FALSE,              FALSE }, // C++11
348   { "thread",               0,                              0,                     0,             0,             0,            0,             FALSE,              FALSE }, // C++11
349   { "basic_ios",            "ios_base",                     0,                     "Char",        0,             0,            0,             FALSE,              FALSE },
350   { "basic_istream",        "basic_ios<Char>",              0,                     "Char",        0,             0,            0,             TRUE,               FALSE },
351   { "basic_ostream",        "basic_ios<Char>",              0,                     "Char",        0,             0,            0,             TRUE,               FALSE },
352   { "basic_iostream",       "basic_istream<Char>",          "basic_ostream<Char>", "Char",        0,             0,            0,             FALSE,              FALSE },
353   { "basic_ifstream",       "basic_istream<Char>",          0,                     "Char",        0,             0,            0,             FALSE,              FALSE },
354   { "basic_ofstream",       "basic_ostream<Char>",          0,                     "Char",        0,             0,            0,             FALSE,              FALSE },
355   { "basic_fstream",        "basic_iostream<Char>",         0,                     "Char",        0,             0,            0,             FALSE,              FALSE },
356   { "basic_istringstream",  "basic_istream<Char>",          0,                     "Char",        0,             0,            0,             FALSE,              FALSE },
357   { "basic_ostringstream",  "basic_ostream<Char>",          0,                     "Char",        0,             0,            0,             FALSE,              FALSE },
358   { "basic_stringstream",   "basic_iostream<Char>",         0,                     "Char",        0,             0,            0,             FALSE,              FALSE },
359   { "ios",                  "basic_ios<char>",              0,                     0,             0,             0,            0,             FALSE,              FALSE },
360   { "wios",                 "basic_ios<wchar_t>",           0,                     0,             0,             0,            0,             FALSE,              FALSE },
361   { "istream",              "basic_istream<char>",          0,                     0,             0,             0,            0,             FALSE,              FALSE },
362   { "wistream",             "basic_istream<wchar_t>",       0,                     0,             0,             0,            0,             FALSE,              FALSE },
363   { "ostream",              "basic_ostream<char>",          0,                     0,             0,             0,            0,             FALSE,              FALSE },
364   { "wostream",             "basic_ostream<wchar_t>",       0,                     0,             0,             0,            0,             FALSE,              FALSE },
365   { "ifstream",             "basic_ifstream<char>",         0,                     0,             0,             0,            0,             FALSE,              FALSE },
366   { "wifstream",            "basic_ifstream<wchar_t>",      0,                     0,             0,             0,            0,             FALSE,              FALSE },
367   { "ofstream",             "basic_ofstream<char>",         0,                     0,             0,             0,            0,             FALSE,              FALSE },
368   { "wofstream",            "basic_ofstream<wchar_t>",      0,                     0,             0,             0,            0,             FALSE,              FALSE },
369   { "fstream",              "basic_fstream<char>",          0,                     0,             0,             0,            0,             FALSE,              FALSE },
370   { "wfstream",             "basic_fstream<wchar_t>",       0,                     0,             0,             0,            0,             FALSE,              FALSE },
371   { "istringstream",        "basic_istringstream<char>",    0,                     0,             0,             0,            0,             FALSE,              FALSE },
372   { "wistringstream",       "basic_istringstream<wchar_t>", 0,                     0,             0,             0,            0,             FALSE,              FALSE },
373   { "ostringstream",        "basic_ostringstream<char>",    0,                     0,             0,             0,            0,             FALSE,              FALSE },
374   { "wostringstream",       "basic_ostringstream<wchar_t>", 0,                     0,             0,             0,            0,             FALSE,              FALSE },
375   { "stringstream",         "basic_stringstream<char>",     0,                     0,             0,             0,            0,             FALSE,              FALSE },
376   { "wstringstream",        "basic_stringstream<wchar_t>",  0,                     0,             0,             0,            0,             FALSE,              FALSE },
377   { "basic_string",         0,                              0,                     "Char",        0,             0,            0,             FALSE,              TRUE  },
378   { "string",               "basic_string<char>",           0,                     0,             0,             0,            0,             FALSE,              TRUE  },
379   { "wstring",              "basic_string<wchar_t>",        0,                     0,             0,             0,            0,             FALSE,              TRUE  },
380   { "complex",              0,                              0,                     0,             0,             0,            0,             FALSE,              FALSE },
381   { "bitset",               0,                              0,                     "Bits",        0,             0,            0,             FALSE,              FALSE },
382   { "deque",                0,                              0,                     "T",           "elements",    0,            0,             FALSE,              TRUE  },
383   { "list",                 0,                              0,                     "T",           "elements",    0,            0,             FALSE,              TRUE  },
384   { "forward_list",         0,                              0,                     "T",           "elements",    0,            0,             FALSE,              TRUE  }, // C++11
385   { "map",                  0,                              0,                     "K",           "keys",        "T",          "elements",    FALSE,              TRUE  },
386   { "unordered_map",        0,                              0,                     "K",           "keys",        "T",          "elements",    FALSE,              TRUE  }, // C++11
387   { "multimap",             0,                              0,                     "K",           "keys",        "T",          "elements",    FALSE,              TRUE  },
388   { "unordered_multimap",   0,                              0,                     "K",           "keys",        "T",          "elements",    FALSE,              TRUE  }, // C++11
389   { "set",                  0,                              0,                     "K",           "keys",        0,            0,             FALSE,              TRUE  },
390   { "unordered_set",        0,                              0,                     "K",           "keys",        0,            0,             FALSE,              TRUE  }, // C++11
391   { "multiset",             0,                              0,                     "K",           "keys",        0,            0,             FALSE,              TRUE  },
392   { "unordered_multiset",   0,                              0,                     "K",           "keys",        0,            0,             FALSE,              TRUE  }, // C++11
393   { "vector",               0,                              0,                     "T",           "elements",    0,            0,             FALSE,              TRUE  },
394   { "queue",                0,                              0,                     "T",           "elements",    0,            0,             FALSE,              FALSE },
395   { "priority_queue",       0,                              0,                     "T",           "elements",    0,            0,             FALSE,              FALSE },
396   { "stack",                0,                              0,                     "T",           "elements",    0,            0,             FALSE,              FALSE },
397   { "valarray",             0,                              0,                     "T",           "elements",    0,            0,             FALSE,              FALSE },
398   { "exception",            0,                              0,                     0,             0,             0,            0,             FALSE,              FALSE },
399   { "bad_alloc",            "exception",                    0,                     0,             0,             0,            0,             FALSE,              FALSE },
400   { "bad_cast",             "exception",                    0,                     0,             0,             0,            0,             FALSE,              FALSE },
401   { "bad_typeid",           "exception",                    0,                     0,             0,             0,            0,             FALSE,              FALSE },
402   { "logic_error",          "exception",                    0,                     0,             0,             0,            0,             FALSE,              FALSE },
403   { "ios_base::failure",    "exception",                    0,                     0,             0,             0,            0,             FALSE,              FALSE },
404   { "runtime_error",        "exception",                    0,                     0,             0,             0,            0,             FALSE,              FALSE },
405   { "bad_exception",        "exception",                    0,                     0,             0,             0,            0,             FALSE,              FALSE },
406   { "domain_error",         "logic_error",                  0,                     0,             0,             0,            0,             FALSE,              FALSE },
407   { "invalid_argument",     "logic_error",                  0,                     0,             0,             0,            0,             FALSE,              FALSE },
408   { "length_error",         "logic_error",                  0,                     0,             0,             0,            0,             FALSE,              FALSE },
409   { "out_of_range",         "logic_error",                  0,                     0,             0,             0,            0,             FALSE,              FALSE },
410   { "range_error",          "runtime_error",                0,                     0,             0,             0,            0,             FALSE,              FALSE },
411   { "overflow_error",       "runtime_error",                0,                     0,             0,             0,            0,             FALSE,              FALSE },
412   { "underflow_error",      "runtime_error",                0,                     0,             0,             0,            0,             FALSE,              FALSE },
413   { 0,                      0,                              0,                     0,             0,             0,            0,             FALSE,              FALSE }
414 };
415
416 static void addSTLMember(EntryNav *rootNav,const char *type,const char *name)
417 {
418   Entry *memEntry = new Entry;
419   memEntry->name       = name;
420   memEntry->type       = type;
421   memEntry->protection = Public;
422   memEntry->section    = Entry::VARIABLE_SEC;
423   memEntry->brief      = "STL member";
424   memEntry->hidden     = FALSE; 
425   memEntry->artificial = TRUE;
426   //memEntry->parent     = root;
427   //root->addSubEntry(memEntry);
428   EntryNav *memEntryNav = new EntryNav(rootNav,memEntry);
429   memEntryNav->setEntry(memEntry);
430   rootNav->addChild(memEntryNav);
431 }
432
433 static void addSTLIterator(EntryNav *classEntryNav,const char *name)
434 {
435   Entry *iteratorClassEntry = new Entry;
436   iteratorClassEntry->fileName  = "[STL]";
437   iteratorClassEntry->startLine = 1;
438   iteratorClassEntry->name      = name;
439   iteratorClassEntry->section   = Entry::CLASS_SEC;
440   iteratorClassEntry->brief     = "STL iterator class";
441   iteratorClassEntry->hidden    = FALSE;
442   iteratorClassEntry->artificial= TRUE;
443   EntryNav *iteratorClassEntryNav = new EntryNav(classEntryNav,iteratorClassEntry);
444   iteratorClassEntryNav->setEntry(iteratorClassEntry);
445   classEntryNav->addChild(iteratorClassEntryNav);
446 }
447
448
449 static void addSTLClasses(EntryNav *rootNav)
450 {
451   Entry *namespaceEntry = new Entry;
452   namespaceEntry->fileName  = "[STL]";
453   namespaceEntry->startLine = 1;
454   //namespaceEntry->parent    = rootNav->entry();
455   namespaceEntry->name      = "std";
456   namespaceEntry->section   = Entry::NAMESPACE_SEC;
457   namespaceEntry->brief     = "STL namespace";
458   namespaceEntry->hidden    = FALSE;
459   namespaceEntry->artificial= TRUE;
460   //root->addSubEntry(namespaceEntry);
461   EntryNav *namespaceEntryNav = new EntryNav(rootNav,namespaceEntry);
462   namespaceEntryNav->setEntry(namespaceEntry);
463   rootNav->addChild(namespaceEntryNav);
464   
465   STLInfo *info = g_stlinfo;
466   while (info->className)
467   {
468     //printf("Adding STL class %s\n",info->className);
469     QCString fullName = info->className;
470     fullName.prepend("std::");
471
472     // add fake Entry for the class
473     Entry *classEntry = new Entry;
474     classEntry->fileName  = "[STL]";
475     classEntry->startLine = 1;
476     classEntry->name      = fullName;
477     //classEntry->parent    = namespaceEntry;
478     classEntry->section   = Entry::CLASS_SEC;
479     classEntry->brief     = "STL class";
480     classEntry->hidden    = FALSE;
481     classEntry->artificial= TRUE;
482     //namespaceEntry->addSubEntry(classEntry);
483     EntryNav *classEntryNav = new EntryNav(namespaceEntryNav,classEntry);
484     classEntryNav->setEntry(classEntry);
485     namespaceEntryNav->addChild(classEntryNav);
486
487     // add template arguments to class
488     if (info->templType1)
489     {
490       ArgumentList *al = new ArgumentList;
491       Argument *a=new Argument;
492       a->type="typename";
493       a->name=info->templType1;
494       al->append(a);
495       if (info->templType2) // another template argument
496       {
497         a=new Argument;
498         a->type="typename";
499         a->name=info->templType2;
500         al->append(a);
501       }
502       classEntry->tArgLists = new QList<ArgumentList>;
503       classEntry->tArgLists->setAutoDelete(TRUE);
504       classEntry->tArgLists->append(al);
505     }
506     // add member variables
507     if (info->templName1)
508     {
509       addSTLMember(classEntryNav,info->templType1,info->templName1);
510     }
511     if (info->templName2)
512     {
513       addSTLMember(classEntryNav,info->templType2,info->templName2);
514     }
515     if (fullName=="std::auto_ptr" || fullName=="std::smart_ptr" ||
516         fullName=="std::unique_ptr" || fullName=="std::weak_ptr")
517     {
518       Entry *memEntry = new Entry;
519       memEntry->name       = "operator->";
520       memEntry->args       = "()";
521       memEntry->type       = "T*";
522       memEntry->protection = Public;
523       memEntry->section    = Entry::FUNCTION_SEC;
524       memEntry->brief      = "STL member";
525       memEntry->hidden     = FALSE; 
526       memEntry->artificial = FALSE;
527       EntryNav *memEntryNav = new EntryNav(classEntryNav,memEntry);
528       memEntryNav->setEntry(memEntry);
529       classEntryNav->addChild(memEntryNav);
530     }
531     if (info->baseClass1)
532     {
533       classEntry->extends->append(new BaseInfo(info->baseClass1,Public,info->virtualInheritance?Virtual:Normal));
534     }
535     if (info->baseClass2)
536     {
537       classEntry->extends->append(new BaseInfo(info->baseClass2,Public,info->virtualInheritance?Virtual:Normal));
538     }
539     if (info->iterators)
540     {
541       // add iterator class
542       addSTLIterator(classEntryNav,fullName+"::iterator");
543       addSTLIterator(classEntryNav,fullName+"::const_iterator");
544       addSTLIterator(classEntryNav,fullName+"::reverse_iterator");
545       addSTLIterator(classEntryNav,fullName+"::const_reverse_iterator");
546     }
547     info++;
548   }
549 }
550
551 //----------------------------------------------------------------------------
552
553 static Definition *findScopeFromQualifiedName(Definition *startScope,const QCString &n,
554                                               FileDef *fileScope=0);
555
556 static void addPageToContext(PageDef *pd,EntryNav *rootNav)
557 {
558   if (rootNav->parent()) // add the page to it's scope
559   {
560     QCString scope = rootNav->parent()->name();
561     if (rootNav->parent()->section()==Entry::PACKAGEDOC_SEC)
562     {
563       scope=substitute(scope,".","::");
564     }
565     scope = stripAnonymousNamespaceScope(scope);
566     scope+="::"+pd->name();
567     Definition *d = findScopeFromQualifiedName(Doxygen::globalScope,scope);
568     if (d) 
569     {
570       pd->setPageScope(d);
571     }
572   }
573 }
574
575 static void addRelatedPage(EntryNav *rootNav)
576 {
577   Entry *root = rootNav->entry();
578   GroupDef *gd=0;
579   QListIterator<Grouping> gli(*root->groups);
580   Grouping *g;
581   for (;(g=gli.current());++gli)
582   {
583     if (!g->groupname.isEmpty() && (gd=Doxygen::groupSDict->find(g->groupname))) break;
584   }
585   //printf("---> addRelatedPage() %s gd=%p\n",root->name.data(),gd);
586   QCString doc;
587   if (root->brief.isEmpty())
588   {
589     doc=root->doc+root->inbodyDocs;
590   }
591   else
592   {
593     doc=root->brief+"\n\n"+root->doc+root->inbodyDocs;
594   }
595   PageDef *pd = addRelatedPage(root->name,root->args,doc,root->anchors,
596       root->docFile,root->docLine,
597       root->sli,
598       gd,rootNav->tagInfo(),
599       root->lang
600      );
601   if (pd)
602   {
603     pd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
604     pd->addSectionsToDefinition(root->anchors);
605     pd->setShowToc(root->stat);
606     addPageToContext(pd,rootNav);
607   }
608 }
609
610 static void buildGroupListFiltered(EntryNav *rootNav,bool additional, bool includeExternal)
611 {
612   if (rootNav->section()==Entry::GROUPDOC_SEC && !rootNav->name().isEmpty() && 
613         ((!includeExternal && rootNav->tagInfo()==0) ||
614          ( includeExternal && rootNav->tagInfo()!=0))
615      )
616   {
617     rootNav->loadEntry(g_storage);
618     Entry *root = rootNav->entry();
619
620     if ((root->groupDocType==Entry::GROUPDOC_NORMAL && !additional) ||
621         (root->groupDocType!=Entry::GROUPDOC_NORMAL &&  additional))
622     {
623       GroupDef *gd = Doxygen::groupSDict->find(root->name);
624       //printf("Processing group '%s':'%s' add=%d ext=%d gd=%p\n",
625       //    root->type.data(),root->name.data(),additional,includeExternal,gd);
626
627       if (gd)
628       {
629         if ( !gd->hasGroupTitle() )
630         {
631           gd->setGroupTitle( root->type );
632         }
633         else if ( root->type.length() > 0 && root->name != root->type && gd->groupTitle() != root->type )
634         {
635           warn( root->fileName,root->startLine,
636               "group %s: ignoring title \"%s\" that does not match old title \"%s\"\n",
637               qPrint(root->name), qPrint(root->type), qPrint(gd->groupTitle()) );
638         }
639         gd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
640         gd->setDocumentation( root->doc, root->docFile, root->docLine );
641         gd->setInbodyDocumentation( root->inbodyDocs, root->inbodyFile, root->inbodyLine );
642         gd->addSectionsToDefinition(root->anchors);
643         gd->setRefItems(root->sli);
644         gd->setLanguage(root->lang);
645       }
646       else
647       {
648         if (rootNav->tagInfo())
649         {
650           gd = new GroupDef(root->fileName,root->startLine,root->name,root->type,rootNav->tagInfo()->fileName);
651           gd->setReference(rootNav->tagInfo()->tagName);
652         }
653         else
654         {
655           gd = new GroupDef(root->fileName,root->startLine,root->name,root->type);
656         }
657         gd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
658         // allow empty docs for group
659         gd->setDocumentation(!root->doc.isEmpty() ? root->doc : QCString(" "),root->docFile,root->docLine,FALSE);
660         gd->setInbodyDocumentation( root->inbodyDocs, root->inbodyFile, root->inbodyLine );
661         gd->addSectionsToDefinition(root->anchors);
662         Doxygen::groupSDict->append(root->name,gd);
663         gd->setRefItems(root->sli);
664         gd->setLanguage(root->lang);
665       }
666     }
667
668     rootNav->releaseEntry();
669   }
670   if (rootNav->children())
671   {
672     EntryNavListIterator eli(*rootNav->children());
673     EntryNav *e;
674     for (;(e=eli.current());++eli)
675     {
676       buildGroupListFiltered(e,additional,includeExternal);
677     }
678   }
679 }
680
681 static void buildGroupList(EntryNav *rootNav)
682 {
683   // --- first process only local groups
684   // first process the @defgroups blocks
685   buildGroupListFiltered(rootNav,FALSE,FALSE);
686   // then process the @addtogroup, @weakgroup blocks
687   buildGroupListFiltered(rootNav,TRUE,FALSE);
688
689   // --- then also process external groups
690   // first process the @defgroups blocks
691   buildGroupListFiltered(rootNav,FALSE,TRUE);
692   // then process the @addtogroup, @weakgroup blocks
693   buildGroupListFiltered(rootNav,TRUE,TRUE);
694 }
695
696 static void findGroupScope(EntryNav *rootNav)
697 {
698   if (rootNav->section()==Entry::GROUPDOC_SEC && !rootNav->name().isEmpty() && 
699       rootNav->parent() && !rootNav->parent()->name().isEmpty())
700   {
701     GroupDef *gd;
702     if ((gd=Doxygen::groupSDict->find(rootNav->name())))
703     {
704       QCString scope = rootNav->parent()->name();
705       if (rootNav->parent()->section()==Entry::PACKAGEDOC_SEC)
706       {
707         scope=substitute(scope,".","::");
708       }
709       scope = stripAnonymousNamespaceScope(scope);
710       scope+="::"+gd->name();
711       Definition *d = findScopeFromQualifiedName(Doxygen::globalScope,scope);
712       if (d) 
713       {
714         gd->setGroupScope(d);
715       }
716     }
717   }
718   RECURSE_ENTRYTREE(findGroupScope,rootNav);
719 }
720
721 static void organizeSubGroupsFiltered(EntryNav *rootNav,bool additional)
722 {
723   if (rootNav->section()==Entry::GROUPDOC_SEC && !rootNav->name().isEmpty())
724   {
725     rootNav->loadEntry(g_storage);
726     Entry *root = rootNav->entry();
727
728     if ((root->groupDocType==Entry::GROUPDOC_NORMAL && !additional) ||
729         (root->groupDocType!=Entry::GROUPDOC_NORMAL && additional))
730     {
731       GroupDef *gd;
732       if ((gd=Doxygen::groupSDict->find(root->name)))
733       {
734         //printf("adding %s to group %s\n",root->name.data(),gd->name().data());
735         addGroupToGroups(root,gd);
736       }
737     }
738
739     rootNav->releaseEntry();
740   }
741   if (rootNav->children())
742   {
743     EntryNavListIterator eli(*rootNav->children());
744     EntryNav *e;
745     for (;(e=eli.current());++eli)
746     {
747       organizeSubGroupsFiltered(e,additional);
748     }
749   }
750 }
751
752 static void organizeSubGroups(EntryNav *rootNav)
753 {
754   //printf("Defining groups\n");
755   // first process the @defgroups blocks
756   organizeSubGroupsFiltered(rootNav,FALSE);
757   //printf("Additional groups\n");
758   // then process the @addtogroup, @weakgroup blocks
759   organizeSubGroupsFiltered(rootNav,TRUE);
760 }
761
762 //----------------------------------------------------------------------
763
764 static void buildFileList(EntryNav *rootNav)
765 {
766   if (((rootNav->section()==Entry::FILEDOC_SEC) ||
767         ((rootNav->section() & Entry::FILE_MASK) && Config_getBool("EXTRACT_ALL"))) &&
768       !rootNav->name().isEmpty() && !rootNav->tagInfo() // skip any file coming from tag files
769      )
770   {
771     rootNav->loadEntry(g_storage);
772     Entry *root = rootNav->entry();
773
774     bool ambig;
775     FileDef *fd=findFileDef(Doxygen::inputNameDict,root->name,ambig);
776     //printf("**************** root->name=%s fd=%p\n",root->name.data(),fd);
777     if (fd && !ambig)
778     {
779 #if 0
780       if ((!root->doc.isEmpty() && !fd->documentation().isEmpty()) ||
781           (!root->brief.isEmpty() && !fd->briefDescription().isEmpty()))
782       {
783         warn(
784             root->fileName,root->startLine,
785             "file %s already documented. "
786             "Skipping documentation.",
787             root->name.data()
788             );
789       }
790       else
791 #endif
792       {
793         //printf("Adding documentation!\n");
794         // using FALSE in setDocumentation is small hack to make sure a file 
795         // is documented even if a \file command is used without further 
796         // documentation
797         fd->setDocumentation(root->doc,root->docFile,root->docLine,FALSE);
798         fd->setBriefDescription(root->brief,root->briefFile,root->briefLine); 
799         fd->addSectionsToDefinition(root->anchors);
800         fd->setRefItems(root->sli);
801         QListIterator<Grouping> gli(*root->groups);
802         Grouping *g;
803         for (;(g=gli.current());++gli)
804         {
805           GroupDef *gd=0;
806           if (!g->groupname.isEmpty() && (gd=Doxygen::groupSDict->find(g->groupname)))
807           {
808             gd->addFile(fd);
809             fd->makePartOfGroup(gd);
810             //printf("File %s: in group %s\n",fd->name().data(),s->data());
811           }
812         }
813       }
814     }
815     else
816     {
817       const char *fn = root->fileName.data();
818       QCString text(4096);
819       text.sprintf("the name `%s' supplied as "
820           "the second argument in the \\file statement ",
821           qPrint(root->name));
822       if (ambig) // name is ambiguous
823       {
824         text+="matches the following input files:\n";
825         text+=showFileDefMatches(Doxygen::inputNameDict,root->name);
826         text+="Please use a more specific name by "
827           "including a (larger) part of the path!";
828       }
829       else // name is not an input file
830       {
831         text+="is not an input file";
832       }
833       warn(fn,root->startLine,text);
834     }
835
836     rootNav->releaseEntry();
837   }
838   RECURSE_ENTRYTREE(buildFileList,rootNav);
839 }
840
841 static void addIncludeFile(ClassDef *cd,FileDef *ifd,Entry *root)
842 {
843   if ( 
844       (!root->doc.stripWhiteSpace().isEmpty() || 
845        !root->brief.stripWhiteSpace().isEmpty() || 
846        Config_getBool("EXTRACT_ALL")
847       ) && root->protection!=Private
848      )
849   { 
850     //printf(">>>>>> includeFile=%s\n",root->includeFile.data());
851
852     bool local=Config_getBool("FORCE_LOCAL_INCLUDES");
853     QCString includeFile = root->includeFile;
854     if (!includeFile.isEmpty() && includeFile.at(0)=='"')
855     {
856       local = TRUE;
857       includeFile=includeFile.mid(1,includeFile.length()-2);
858     }
859     else if (!includeFile.isEmpty() && includeFile.at(0)=='<')
860     {
861       local = FALSE;
862       includeFile=includeFile.mid(1,includeFile.length()-2);
863     }
864
865     bool ambig;
866     FileDef *fd=0;
867     // see if we need to include a verbatim copy of the header file
868     //printf("root->includeFile=%s\n",root->includeFile.data());
869     if (!includeFile.isEmpty() && 
870         (fd=findFileDef(Doxygen::inputNameDict,includeFile,ambig))==0
871        )
872     { // explicit request
873       QCString text;
874       text.sprintf("the name `%s' supplied as "
875                   "the argument of the \\class, \\struct, \\union, or \\include command ",
876                   qPrint(includeFile)
877                  );
878       if (ambig) // name is ambiguous
879       {
880         text+="matches the following input files:\n";
881         text+=showFileDefMatches(Doxygen::inputNameDict,root->includeFile);
882         text+="Please use a more specific name by "
883             "including a (larger) part of the path!";
884       }
885       else // name is not an input file
886       {
887         text+="is not an input file";
888       }
889       warn(root->fileName,root->startLine,text);
890     }
891     else if (includeFile.isEmpty() && ifd &&
892         // see if the file extension makes sense
893         guessSection(ifd->name())==Entry::HEADER_SEC)
894     { // implicit assumption
895       fd=ifd;
896     }
897
898     // if a file is found, we mark it as a source file.
899     if (fd)
900     {
901       QCString iName = !root->includeName.isEmpty() ? 
902                        root->includeName : includeFile;
903       if (!iName.isEmpty()) // user specified include file
904       {
905         if (iName.at(0)=='<') local=FALSE; // explicit override
906         else if (iName.at(0)=='"') local=TRUE;
907         if (iName.at(0)=='"' || iName.at(0)=='<')
908         {
909           iName=iName.mid(1,iName.length()-2); // strip quotes or brackets
910         }
911         if (iName.isEmpty())
912         {
913           iName=fd->name();
914         }
915       }
916       else if (!Config_getList("STRIP_FROM_INC_PATH").isEmpty()) 
917       {
918         iName=stripFromIncludePath(fd->absFilePath());
919       }
920       else // use name of the file containing the class definition
921       {
922         iName=fd->name();
923       }
924       if (fd->generateSourceFile()) // generate code for header
925       {
926         cd->setIncludeFile(fd,iName,local,!root->includeName.isEmpty());
927       }
928       else // put #include in the class documentation without link
929       {
930         cd->setIncludeFile(0,iName,local,TRUE);
931       }
932     }
933   }
934 }
935
936 #if 0
937 static bool addNamespace(Entry *root,ClassDef *cd)
938 {
939   // see if this class is defined inside a namespace
940   if (root->section & Entry::COMPOUND_MASK)
941   {
942     Entry *e = root->parent;
943     while (e)
944     {
945       if (e->section==Entry::NAMESPACE_SEC)
946       {
947         NamespaceDef *nd=0;
948         QCString nsName = stripAnonymousNamespaceScope(e->name);
949         //printf("addNameSpace() trying: %s\n",nsName.data());
950         if (!nsName.isEmpty() && nsName.at(0)!='@' &&
951             (nd=getResolvedNamespace(nsName))
952            )
953         {
954           cd->setNamespace(nd);
955           cd->setOuterScope(nd);
956           nd->insertClass(cd);
957           return TRUE;
958         }
959       }
960       e=e->parent;
961     } 
962   }
963   return FALSE;
964 }
965 #endif
966
967 #if 0
968 static Definition *findScope(Entry *root,int level=0)
969 {
970   if (root==0) return 0;
971   //printf("start findScope name=%s\n",root->name.data());
972   Definition *result=0;
973   if (root->section&Entry::SCOPE_MASK)
974   {
975     result = findScope(root->parent,level+1); // traverse to the root of the tree
976     if (result)
977     {
978       //printf("Found %s inside %s at level %d\n",root->name.data(),result->name().data(),level);
979       // TODO: look at template arguments
980       result = result->findInnerCompound(root->name);
981     }
982     else // reached the global scope
983     {
984       // TODO: look at template arguments
985       result = Doxygen::globalScope->findInnerCompound(root->name);
986       //printf("Found in globalScope %s at level %d\n",result->name().data(),level);
987     }
988   }
989   //printf("end findScope(%s,%d)=%s\n",root->name.data(),
990   //       level,result==0 ? "<none>" : result->name().data());
991   return result;
992 }
993 #endif
994
995 /*! returns the Definition object belonging to the first \a level levels of 
996  *  full qualified name \a name. Creates an artificial scope if the scope is
997  *  not found and set the parent/child scope relation if the scope is found.
998  */
999 static Definition *buildScopeFromQualifiedName(const QCString name,int level,SrcLangExt lang,TagInfo *tagInfo)
1000 {
1001   //printf("buildScopeFromQualifiedName(%s) level=%d\n",name.data(),level);
1002   int i=0;
1003   int p=0,l;
1004   Definition *prevScope=Doxygen::globalScope;
1005   QCString fullScope;
1006   while (i<level)
1007   {
1008     int idx=getScopeFragment(name,p,&l);
1009     QCString nsName = name.mid(idx,l);
1010     if (nsName.isEmpty()) return prevScope;
1011     if (!fullScope.isEmpty()) fullScope+="::";
1012     fullScope+=nsName;
1013     NamespaceDef *nd=Doxygen::namespaceSDict->find(fullScope);
1014     Definition *innerScope = nd;
1015     ClassDef *cd=0; 
1016     if (nd==0) cd = getClass(fullScope);
1017     if (nd==0 && cd) // scope is a class
1018     {
1019       innerScope = cd;
1020     }
1021     else if (nd==0 && cd==0) // scope is not known!
1022     {
1023       // introduce bogus namespace
1024       //printf("++ adding dummy namespace %s to %s tagInfo=%p\n",nsName.data(),prevScope->name().data(),tagInfo);
1025       nd=new NamespaceDef(
1026         "[generated]",1,1,fullScope,
1027         tagInfo?tagInfo->tagName:QCString(),
1028         tagInfo?tagInfo->fileName:QCString());
1029       nd->setLanguage(lang);
1030
1031       // add namespace to the list
1032       Doxygen::namespaceSDict->inSort(fullScope,nd);
1033       innerScope = nd;
1034     }
1035     else // scope is a namespace
1036     {
1037     }
1038     // make the parent/child scope relation
1039     prevScope->addInnerCompound(innerScope);
1040     innerScope->setOuterScope(prevScope);
1041     // proceed to the next scope fragment
1042     p=idx+l+2;
1043     prevScope=innerScope;
1044     i++;
1045   }
1046   return prevScope;
1047 }
1048
1049 static Definition *findScopeFromQualifiedName(Definition *startScope,const QCString &n,
1050                                               FileDef *fileScope)
1051 {
1052   //printf("<findScopeFromQualifiedName(%s,%s)\n",startScope ? startScope->name().data() : 0, n.data());
1053   Definition *resultScope=startScope;
1054   if (resultScope==0) resultScope=Doxygen::globalScope;
1055   QCString scope=stripTemplateSpecifiersFromScope(n,FALSE);
1056   int l1=0,i1;
1057   i1=getScopeFragment(scope,0,&l1);
1058   if (i1==-1) 
1059   {
1060     //printf(">no fragments!\n");
1061     return resultScope;
1062   }
1063   int p=i1+l1,l2=0,i2;
1064   while ((i2=getScopeFragment(scope,p,&l2))!=-1)
1065   {
1066     QCString nestedNameSpecifier = scope.mid(i1,l1);
1067     Definition *orgScope = resultScope;
1068     //printf("  nestedNameSpecifier=%s\n",nestedNameSpecifier.data());
1069     resultScope = resultScope->findInnerCompound(nestedNameSpecifier);
1070     //printf("  resultScope=%p\n",resultScope);
1071     if (resultScope==0) 
1072     {
1073       NamespaceSDict *usedNamespaces;
1074       if (orgScope==Doxygen::globalScope && fileScope &&
1075           (usedNamespaces = fileScope->getUsedNamespaces())) 
1076         // also search for used namespaces 
1077       {
1078         NamespaceSDict::Iterator ni(*usedNamespaces);
1079         NamespaceDef *nd;
1080         for (ni.toFirst();((nd=ni.current()) && resultScope==0);++ni)
1081         {
1082           // restart search within the used namespace
1083           resultScope = findScopeFromQualifiedName(nd,n,fileScope);
1084         }
1085         if (resultScope) 
1086         {
1087           // for a nested class A::I in used namespace N, we get
1088           // N::A::I while looking for A, so we should compare
1089           // resultScope->name() against scope.left(i2+l2)
1090           //printf("  -> result=%s scope=%s\n",resultScope->name().data(),scope.data());
1091           if (rightScopeMatch(resultScope->name(),scope.left(i2+l2)))
1092           {
1093             break;
1094           }
1095           goto nextFragment;
1096         }
1097       }
1098
1099       // also search for used classes. Complication: we haven't been able 
1100       // to put them in the right scope yet, because we are still resolving
1101       // the scope relations!
1102       // Therefore loop through all used classes and see if there is a right 
1103       // scope match between the used class and nestedNameSpecifier.
1104       QDictIterator<FileDef> ui(g_usingDeclarations);
1105       FileDef *usedFd;
1106       for (ui.toFirst();(usedFd=ui.current());++ui)
1107       {
1108         //printf("Checking using class %s\n",ui.currentKey());
1109         if (rightScopeMatch(ui.currentKey(),nestedNameSpecifier))
1110         {
1111           // ui.currentKey() is the fully qualified name of nestedNameSpecifier
1112           // so use this instead.
1113           QCString fqn = QCString(ui.currentKey())+
1114                          scope.right(scope.length()-p);
1115           resultScope = buildScopeFromQualifiedName(fqn,fqn.contains("::"),startScope->getLanguage(),0);
1116           //printf("Creating scope from fqn=%s result %p\n",fqn.data(),resultScope);
1117           if (resultScope) 
1118           {
1119             //printf("> Match! resultScope=%s\n",resultScope->name().data());
1120             return resultScope;
1121           }
1122         }
1123       }
1124       
1125       //printf("> name %s not found in scope %s\n",nestedNameSpecifier.data(),orgScope->name().data());
1126       return 0;
1127     }
1128  nextFragment:
1129     i1=i2;
1130     l1=l2;
1131     p=i2+l2;
1132   }
1133   //printf(">findScopeFromQualifiedName scope %s\n",resultScope->name().data());
1134   return resultScope;
1135 }
1136
1137 ArgumentList *getTemplateArgumentsFromName(
1138                   const QCString &name,
1139                   const QList<ArgumentList> *tArgLists)
1140 {
1141   if (tArgLists==0) return 0;
1142   
1143   QListIterator<ArgumentList> ali(*tArgLists);
1144   // for each scope fragment, check if it is a template and advance through
1145   // the list if so.
1146   int i,p=0;
1147   while ((i=name.find("::",p))!=-1)
1148   {
1149     NamespaceDef *nd = Doxygen::namespaceSDict->find(name.left(i));
1150     if (nd==0)
1151     {
1152       ClassDef *cd = getClass(name.left(i));
1153       if (cd)
1154       {
1155         if (cd->templateArguments())
1156         {
1157           ++ali;
1158         }
1159       }
1160     }
1161     p=i+2;
1162   }
1163   return ali.current();
1164 }
1165
1166 static
1167 ClassDef::CompoundType convertToCompoundType(int section,uint64 specifier)
1168 {
1169   ClassDef::CompoundType sec=ClassDef::Class; 
1170   if (specifier&Entry::Struct) 
1171     sec=ClassDef::Struct;
1172   else if (specifier&Entry::Union) 
1173     sec=ClassDef::Union;
1174   else if (specifier&Entry::Category) 
1175     sec=ClassDef::Category;
1176   else if (specifier&Entry::Interface) 
1177     sec=ClassDef::Interface;
1178   else if (specifier&Entry::Protocol) 
1179     sec=ClassDef::Protocol;
1180   else if (specifier&Entry::Exception) 
1181     sec=ClassDef::Exception;
1182   else if (specifier&Entry::Service)
1183     sec=ClassDef::Service;
1184   else if (specifier&Entry::Singleton)
1185     sec=ClassDef::Singleton;
1186
1187   switch(section)
1188   {
1189     //case Entry::UNION_SEC: 
1190     case Entry::UNIONDOC_SEC: 
1191       sec=ClassDef::Union; 
1192       break;
1193       //case Entry::STRUCT_SEC:
1194     case Entry::STRUCTDOC_SEC: 
1195       sec=ClassDef::Struct; 
1196       break;
1197       //case Entry::INTERFACE_SEC:
1198     case Entry::INTERFACEDOC_SEC:
1199       sec=ClassDef::Interface; 
1200       break;
1201       //case Entry::PROTOCOL_SEC:
1202     case Entry::PROTOCOLDOC_SEC:
1203       sec=ClassDef::Protocol; 
1204       break;
1205       //case Entry::CATEGORY_SEC:
1206     case Entry::CATEGORYDOC_SEC:
1207       sec=ClassDef::Category; 
1208       break;
1209       //case Entry::EXCEPTION_SEC:
1210     case Entry::EXCEPTIONDOC_SEC:
1211       sec=ClassDef::Exception; 
1212       break;
1213     case Entry::SERVICEDOC_SEC:
1214       sec=ClassDef::Service;
1215       break;
1216     case Entry::SINGLETONDOC_SEC:
1217       sec=ClassDef::Singleton;
1218       break;
1219   }
1220   return sec;
1221 }
1222
1223
1224 static void addClassToContext(EntryNav *rootNav)
1225 {
1226   //printf("Loading entry for rootNav=%p name=%s\n",rootNav,rootNav->name().data());
1227   rootNav->loadEntry(g_storage);
1228   Entry *root = rootNav->entry();
1229
1230   //NamespaceDef *nd = 0;
1231   FileDef *fd = rootNav->fileDef();
1232
1233   QCString scName;
1234   if (rootNav->parent()->section()&Entry::SCOPE_MASK)
1235   {
1236      scName=rootNav->parent()->name();
1237   }
1238   // name without parent's scope
1239   QCString fullName = root->name;
1240
1241   // strip off any template parameters (but not those for specializations)
1242   fullName=stripTemplateSpecifiersFromScope(fullName);
1243
1244   // name with scope (if not present already)
1245   QCString qualifiedName = fullName;
1246   if (!scName.isEmpty() && !leftScopeMatch(fullName,scName))
1247   {
1248     qualifiedName.prepend(scName+"::");
1249   }
1250
1251   // see if we already found the class before
1252   ClassDef *cd = getClass(qualifiedName);
1253
1254   Debug::print(Debug::Classes,0, "  Found class with name %s (qualifiedName=%s -> cd=%p)\n",
1255       cd ? cd->name().data() : root->name.data(), qualifiedName.data(),cd);
1256
1257   if (cd) 
1258   {
1259     fullName=cd->name();
1260     Debug::print(Debug::Classes,0,"  Existing class %s!\n",cd->name().data());
1261     //if (cd->templateArguments()==0)
1262     //{
1263     //  //printf("existing ClassDef tempArgList=%p specScope=%s\n",root->tArgList,root->scopeSpec.data());
1264     //  cd->setTemplateArguments(tArgList);
1265     //}
1266
1267     cd->setDocumentation(root->doc,root->docFile,root->docLine);
1268     cd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1269
1270     if (root->bodyLine!=-1 && cd->getStartBodyLine()==-1)
1271     {
1272       cd->setBodySegment(root->bodyLine,root->endBodyLine);
1273       cd->setBodyDef(fd);
1274     }
1275     //cd->setName(fullName); // change name to match docs
1276
1277     if (cd->templateArguments()==0) 
1278     {
1279       // this happens if a template class declared with @class is found
1280       // before the actual definition.
1281       ArgumentList *tArgList = 
1282         getTemplateArgumentsFromName(cd->name(),root->tArgLists);
1283       cd->setTemplateArguments(tArgList);
1284     }
1285
1286     cd->setCompoundType(convertToCompoundType(root->section,root->spec));
1287   }
1288   else // new class
1289   {
1290     ClassDef::CompoundType sec = convertToCompoundType(root->section,root->spec);
1291
1292     QCString className;
1293     QCString namespaceName;
1294     extractNamespaceName(fullName,className,namespaceName);
1295
1296     //printf("New class: fullname %s namespace `%s' name=`%s' brief=`%s' docs=`%s'\n",
1297     //    fullName.data(),namespaceName.data(),className.data(),root->brief.data(),root->doc.data());
1298
1299     QCString tagName;
1300     QCString refFileName;
1301     TagInfo *tagInfo = rootNav->tagInfo();
1302     if (tagInfo)
1303     {
1304       tagName     = tagInfo->tagName;
1305       refFileName = tagInfo->fileName;
1306       int i;
1307       if ((i=fullName.find("::"))!=-1) 
1308         // symbols imported via tag files may come without the parent scope, 
1309         // so we artificially create it here
1310       {
1311         buildScopeFromQualifiedName(fullName,fullName.contains("::"),root->lang,tagInfo);
1312       }
1313     }
1314     cd=new ClassDef(root->fileName,root->startLine,root->startColumn,
1315         fullName,sec,tagName,refFileName,TRUE,root->spec&Entry::Enum);
1316     Debug::print(Debug::Classes,0,"  New class `%s' (sec=0x%08x)! #tArgLists=%d tagInfo=%p\n",
1317         fullName.data(),sec,root->tArgLists ? (int)root->tArgLists->count() : -1, tagInfo);
1318     cd->setDocumentation(root->doc,root->docFile,root->docLine); // copy docs to definition
1319     cd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1320     cd->setLanguage(root->lang);    
1321     cd->setId(root->id);
1322     cd->setHidden(root->hidden);        
1323     cd->setArtificial(root->artificial);        
1324     cd->setClassSpecifier(root->spec);
1325     cd->setTypeConstraints(root->typeConstr);   
1326     //printf("new ClassDef %s tempArgList=%p specScope=%s\n",fullName.data(),root->tArgList,root->scopeSpec.data());    
1327
1328     ArgumentList *tArgList =    
1329       getTemplateArgumentsFromName(fullName,root->tArgLists);   
1330     //printf("class %s template args=%s\n",fullName.data(),     
1331     //    tArgList ? tempArgListToString(tArgList).data() : "<none>");          
1332     cd->setTemplateArguments(tArgList);         
1333     cd->setProtection(root->protection);        
1334     cd->setIsStatic(root->stat);        
1335
1336     // file definition containing the class cd          
1337     cd->setBodySegment(root->bodyLine,root->endBodyLine);       
1338     cd->setBodyDef(fd);         
1339
1340     // see if the class is found inside a namespace     
1341     //bool found=addNamespace(root,cd);         
1342
1343     cd->insertUsedFile(fd);
1344
1345     // add class to the list
1346     //printf("ClassDict.insert(%s)\n",resolveDefines(fullName).data());
1347     Doxygen::classSDict->append(fullName,cd);
1348
1349     if (cd->isGeneric()) // generics are also stored in a separate dictionary for fast lookup of instantions
1350     {
1351       Doxygen::genericsDict->insert(fullName,cd);
1352     }
1353   }
1354
1355   cd->addSectionsToDefinition(root->anchors);
1356   if (!root->subGrouping) cd->setSubGrouping(FALSE);
1357   if (cd->hasDocumentation())
1358   {
1359     addIncludeFile(cd,fd,root);
1360   }
1361   if (fd && (root->section & Entry::COMPOUND_MASK)) 
1362   {
1363     //printf(">> Inserting class `%s' in file `%s' (root->fileName=`%s')\n",
1364     //    cd->name().data(),
1365     //    fd->name().data(),
1366     //    root->fileName.data()
1367     //   );
1368     cd->setFileDef(fd);
1369     fd->insertClass(cd);
1370   }
1371   addClassToGroups(root,cd);
1372   cd->setRefItems(root->sli);
1373
1374   rootNav->releaseEntry();
1375 }
1376             
1377 //----------------------------------------------------------------------
1378 // build a list of all classes mentioned in the documentation
1379 // and all classes that have a documentation block before their definition.
1380 static void buildClassList(EntryNav *rootNav)
1381 {
1382   if (
1383         ((rootNav->section() & Entry::COMPOUND_MASK) || 
1384          rootNav->section()==Entry::OBJCIMPL_SEC) && !rootNav->name().isEmpty()
1385      )
1386   {
1387     addClassToContext(rootNav);
1388   }
1389   RECURSE_ENTRYTREE(buildClassList,rootNav);
1390 }
1391
1392 static void buildClassDocList(EntryNav *rootNav)
1393 {
1394   if (
1395        (rootNav->section() & Entry::COMPOUNDDOC_MASK) && !rootNav->name().isEmpty()
1396      )
1397   {
1398     addClassToContext(rootNav);
1399   }
1400   RECURSE_ENTRYTREE(buildClassDocList,rootNav);
1401 }
1402
1403 static void resolveClassNestingRelations()
1404 {
1405   ClassSDict::Iterator cli(*Doxygen::classSDict);
1406   for (cli.toFirst();cli.current();++cli) cli.current()->visited=FALSE;
1407
1408   bool done=FALSE;
1409   int iteration=0;
1410   while (!done)
1411   {
1412     done=TRUE;
1413     ++iteration;
1414     ClassDef *cd=0;
1415     for (cli.toFirst();(cd=cli.current());++cli)
1416     {
1417       if (!cd->visited)
1418       {
1419         QCString name = stripAnonymousNamespaceScope(cd->name());
1420         //printf("processing=%s, iteration=%d\n",cd->name().data(),iteration);
1421         // also add class to the correct structural context 
1422         Definition *d = findScopeFromQualifiedName(Doxygen::globalScope,
1423                                                  name,cd->getFileDef());
1424         if (d)
1425         {
1426           //printf("****** adding %s to scope %s in iteration %d\n",cd->name().data(),d->name().data(),iteration);
1427           d->addInnerCompound(cd);
1428           cd->setOuterScope(d);
1429           cd->visited=TRUE;
1430           done=FALSE;
1431         }
1432         //else
1433         //{
1434         //  printf("****** ignoring %s: scope not (yet) found in iteration %d\n",cd->name().data(),iteration);
1435         //}
1436       }
1437     }
1438   }
1439
1440   //give warnings for unresolved compounds
1441   ClassDef *cd=0;
1442   for (cli.toFirst();(cd=cli.current());++cli)
1443   {
1444     if (!cd->visited)
1445     {
1446       QCString name = stripAnonymousNamespaceScope(cd->name());
1447       //printf("processing unresolved=%s, iteration=%d\n",cd->name().data(),iteration);
1448       /// create the scope artificially
1449       // anyway, so we can at least relate scopes properly.
1450       Definition *d = buildScopeFromQualifiedName(name,name.contains("::"),cd->getLanguage(),0);
1451       if (d!=cd && !cd->getDefFileName().isEmpty()) 
1452                  // avoid recursion in case of redundant scopes, i.e: namespace N { class N::C {}; }
1453                  // for this case doxygen assumes the exitance of a namespace N::N in which C is to be found!
1454                  // also avoid warning for stuff imported via a tagfile.
1455       {
1456         d->addInnerCompound(cd);
1457         cd->setOuterScope(d);
1458         warn(cd->getDefFileName(),cd->getDefLine(),
1459             "Internal inconsistency: scope for class %s not "
1460             "found!",name.data()
1461             );
1462       }
1463     }
1464   }
1465 }
1466
1467 void distributeClassGroupRelations()
1468 {
1469   //static bool inlineGroupedClasses = Config_getBool("INLINE_GROUPED_CLASSES");
1470   //if (!inlineGroupedClasses) return;
1471   //printf("** distributeClassGroupRelations()\n");
1472
1473   ClassSDict::Iterator cli(*Doxygen::classSDict);
1474   for (cli.toFirst();cli.current();++cli) cli.current()->visited=FALSE;
1475
1476   ClassDef *cd;
1477   for (cli.toFirst();(cd=cli.current());++cli)
1478   {
1479     //printf("Checking %s\n",cd->name().data());
1480     // distribute the group to nested classes as well
1481     if (!cd->visited && cd->partOfGroups()!=0 && cd->getClassSDict())
1482     {
1483       //printf("  Candidate for merging\n");
1484       ClassSDict::Iterator ncli(*cd->getClassSDict());
1485       ClassDef *ncd;
1486       GroupDef *gd = cd->partOfGroups()->at(0);
1487       for (ncli.toFirst();(ncd=ncli.current());++ncli)
1488       {
1489         if (ncd->partOfGroups()==0)
1490         {
1491           //printf("  Adding %s to group '%s'\n",ncd->name().data(),
1492           //    gd->groupTitle());
1493           ncd->makePartOfGroup(gd);
1494           gd->addClass(ncd);
1495         }
1496       }
1497       cd->visited=TRUE; // only visit every class once
1498     }
1499   }
1500 }
1501
1502 //----------------------------
1503
1504 static ClassDef *createTagLessInstance(ClassDef *rootCd,ClassDef *templ,const QCString &fieldName)
1505 {
1506   QCString fullName = removeAnonymousScopes(templ->name());
1507   if (fullName.right(2)=="::") fullName=fullName.left(fullName.length()-2);
1508   fullName+="."+fieldName;
1509   ClassDef *cd = new ClassDef(templ->getDefFileName(),
1510                               templ->getDefLine(),
1511                               templ->getDefColumn(),
1512                               fullName,
1513                               templ->compoundType());
1514   cd->setDocumentation(templ->documentation(),templ->docFile(),templ->docLine()); // copy docs to definition
1515   cd->setBriefDescription(templ->briefDescription(),templ->briefFile(),templ->briefLine());
1516   cd->setLanguage(templ->getLanguage());
1517   cd->setBodySegment(templ->getStartBodyLine(),templ->getEndBodyLine());
1518   cd->setBodyDef(templ->getBodyDef());
1519
1520   cd->setOuterScope(rootCd->getOuterScope());
1521   if (rootCd->getOuterScope()!=Doxygen::globalScope)
1522   {
1523     rootCd->getOuterScope()->addInnerCompound(cd);
1524   }
1525
1526   FileDef *fd = templ->getFileDef();
1527   if (fd)
1528   {
1529     cd->setFileDef(fd);
1530     fd->insertClass(cd);
1531   }
1532   GroupList *groups = rootCd->partOfGroups();
1533   if ( groups!=0 )
1534   {
1535     GroupListIterator gli(*groups);
1536     GroupDef *gd;
1537     for (gli.toFirst();(gd=gli.current());++gli)
1538     {
1539       cd->makePartOfGroup(gd);
1540       gd->addClass(cd);
1541     }
1542   }
1543   //printf("** adding class %s based on %s\n",fullName.data(),templ->name().data());
1544   Doxygen::classSDict->append(fullName,cd);
1545
1546   MemberList *ml = templ->getMemberList(MemberListType_pubAttribs);
1547   if (ml)
1548   {
1549     MemberListIterator li(*ml);
1550     MemberDef *md;
1551     for (li.toFirst();(md=li.current());++li)
1552     {
1553       //printf("    Member %s type=%s\n",md->name().data(),md->typeString());
1554       MemberDef *imd = new MemberDef(md->getDefFileName(),md->getDefLine(),md->getDefColumn(),
1555                                      md->typeString(),md->name(),md->argsString(),md->excpString(),
1556                                      md->protection(),md->virtualness(),md->isStatic(),Member,
1557                                      md->memberType(),
1558                                      0,0);
1559       imd->setMemberClass(cd);
1560       imd->setDocumentation(md->documentation(),md->docFile(),md->docLine());
1561       imd->setBriefDescription(md->briefDescription(),md->briefFile(),md->briefLine());
1562       imd->setInbodyDocumentation(md->inbodyDocumentation(),md->inbodyFile(),md->inbodyLine());
1563       imd->setMemberSpecifiers(md->getMemberSpecifiers());
1564       imd->setMemberGroupId(md->getMemberGroupId());
1565       imd->setInitializer(md->initializer());
1566       imd->setMaxInitLines(md->initializerLines());
1567       imd->setBitfields(md->bitfieldString());
1568       imd->setLanguage(md->getLanguage());
1569       cd->insertMember(imd);
1570     }
1571   }
1572   return cd;
1573 }
1574
1575 /** Look through the members of class \a cd and its public members.
1576  *  If there is a member m of a tag less struct/union, 
1577  *  then we create a duplicate of the struct/union with the name of the 
1578  *  member to identify it.
1579  *  So if cd has name S, then the tag less struct/union will get name S.m
1580  *  Since tag less structs can be nested we need to call this function
1581  *  recursively. Later on we need to patch the member types so we keep
1582  *  track of the hierarchy of classes we create.
1583  */
1584 static void processTagLessClasses(ClassDef *rootCd,
1585                                   ClassDef *cd,
1586                                   ClassDef *tagParentCd,
1587                                   const QCString &prefix,int count)
1588 {
1589   //printf("%d: processTagLessClasses %s\n",count,cd->name().data());
1590   //printf("checking members for %s\n",cd->name().data());
1591   if (cd->getClassSDict())
1592   {
1593     MemberList *ml = cd->getMemberList(MemberListType_pubAttribs);
1594     if (ml)
1595     {
1596       MemberListIterator li(*ml);
1597       MemberDef *md;
1598       for (li.toFirst();(md=li.current());++li)
1599       {
1600         QCString type = md->typeString();
1601         if (type.find("::@")!=-1) // member of tag less struct/union
1602         {
1603           ClassSDict::Iterator it(*cd->getClassSDict());
1604           ClassDef *icd;
1605           for (it.toFirst();(icd=it.current());++it)
1606           {
1607             //printf("  member %s: type='%s'\n",md->name().data(),type.data());
1608             //printf("  comparing '%s'<->'%s'\n",type.data(),icd->name().data());
1609             if (type.find(icd->name())!=-1) // matching tag less struct/union
1610             {
1611               QCString name = md->name();
1612               if (name.at(0)=='@') name = "__unnamed__";
1613               if (!prefix.isEmpty()) name.prepend(prefix+".");
1614               //printf("    found %s for class %s\n",name.data(),cd->name().data());
1615               ClassDef *ncd = createTagLessInstance(rootCd,icd,name);
1616               processTagLessClasses(rootCd,icd,ncd,name,count+1);
1617               //printf("    addTagged %s to %s\n",ncd->name().data(),tagParentCd->name().data());
1618               tagParentCd->addTaggedInnerClass(ncd);
1619               ncd->setTagLessReference(icd);
1620
1621               // replace tag-less type for generated/original member
1622               // by newly created class name.
1623               // note the difference between changing cd and tagParentCd.
1624               // for the initial call this is the same pointer, but for 
1625               // recursive calls cd is the original tag-less struct (of which
1626               // there is only one instance) and tagParentCd is the newly
1627               // generated tagged struct of which there can be multiple instances!
1628               MemberList *pml = tagParentCd->getMemberList(MemberListType_pubAttribs);
1629               if (pml)
1630               {
1631                 MemberListIterator pli(*pml);
1632                 MemberDef *pmd;
1633                 for (pli.toFirst();(pmd=pli.current());++pli)
1634                 {
1635                   if (pmd->name()==md->name())
1636                   {
1637                     pmd->setAccessorType(ncd,substitute(pmd->typeString(),icd->name(),ncd->name()));
1638                     //pmd->setType(substitute(pmd->typeString(),icd->name(),ncd->name()));
1639                   }
1640                 }
1641               }
1642             }
1643           }
1644         }
1645       }
1646     }
1647   }
1648 }
1649
1650 static void writeMainPageTagFileData()
1651 {
1652   if (Doxygen::mainPage && !Config_getString("GENERATE_TAGFILE").isEmpty())
1653   {
1654     Doxygen::tagFile << "  <compound kind=\"page\">" << endl
1655                      << "    <name>"
1656                      << convertToXML(Doxygen::mainPage->name())
1657                      << "</name>" << endl
1658                      << "    <title>"
1659                      << convertToXML(Doxygen::mainPage->title())
1660                      << "</title>" << endl
1661                      << "    <filename>"
1662                      << convertToXML(Doxygen::mainPage->getOutputFileBase())
1663                      << "</filename>" << endl;
1664
1665     Doxygen::mainPage->writeDocAnchorsToTagFile();
1666     Doxygen::tagFile << "  </compound>" << endl;
1667   }
1668 }
1669
1670 static void findTagLessClasses(ClassDef *cd)
1671 {
1672   if (cd->getClassSDict())
1673   {
1674     ClassSDict::Iterator it(*cd->getClassSDict());
1675     ClassDef *icd;
1676     for (it.toFirst();(icd=it.current());++it)
1677     {
1678       if (icd->name().find("@")==-1) // process all non-anonymous inner classes
1679       {
1680         findTagLessClasses(icd);
1681       }
1682     }
1683   }
1684
1685   processTagLessClasses(cd,cd,cd,"",0); // process tag less inner struct/classes (if any)
1686 }
1687
1688 static void findTagLessClasses()
1689 {
1690   ClassSDict::Iterator cli(*Doxygen::classSDict);
1691   ClassDef *cd;
1692   for (cli.toFirst();(cd=cli.current());++cli) // for each class
1693   {
1694     Definition *scope = cd->getOuterScope();
1695     if (scope && scope->definitionType()!=Definition::TypeClass) // that is not nested
1696     {
1697       findTagLessClasses(cd);
1698     }
1699   }
1700 }
1701
1702
1703 //----------------------------------------------------------------------
1704 // build a list of all namespaces mentioned in the documentation
1705 // and all namespaces that have a documentation block before their definition.
1706 static void buildNamespaceList(EntryNav *rootNav)
1707 {
1708   if (
1709        (rootNav->section()==Entry::NAMESPACE_SEC ||
1710         rootNav->section()==Entry::NAMESPACEDOC_SEC ||
1711         rootNav->section()==Entry::PACKAGEDOC_SEC
1712        ) && 
1713        !rootNav->name().isEmpty()
1714      )
1715   {
1716     rootNav->loadEntry(g_storage);
1717     Entry *root = rootNav->entry();
1718
1719     //printf("** buildNamespaceList(%s)\n",root->name.data());
1720
1721     QCString fName = root->name;
1722     if (root->section==Entry::PACKAGEDOC_SEC)
1723     {
1724       fName=substitute(fName,".","::");
1725     }
1726
1727     QCString fullName = stripAnonymousNamespaceScope(fName);
1728     if (!fullName.isEmpty())
1729     {
1730       //printf("Found namespace %s in %s at line %d\n",root->name.data(),
1731       //        root->fileName.data(), root->startLine);
1732       NamespaceDef *nd;
1733       if ((nd=Doxygen::namespaceSDict->find(fullName))) // existing namespace
1734       {
1735         nd->setDocumentation(root->doc,root->docFile,root->docLine);
1736         nd->setName(fullName); // change name to match docs
1737         nd->addSectionsToDefinition(root->anchors);
1738         nd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1739         if (nd->getLanguage()==SrcLangExt_Unknown)
1740         {
1741           nd->setLanguage(root->lang);
1742         }
1743
1744         // file definition containing the namespace nd
1745         FileDef *fd=rootNav->fileDef();
1746         // insert the namespace in the file definition
1747         if (fd) fd->insertNamespace(nd);
1748         addNamespaceToGroups(root,nd);
1749         nd->setRefItems(root->sli);
1750       }
1751       else // fresh namespace
1752       {
1753         QCString tagName;
1754         QCString tagFileName;
1755         TagInfo *tagInfo = rootNav->tagInfo();
1756         if (tagInfo)
1757         {
1758           tagName     = tagInfo->tagName;
1759           tagFileName = tagInfo->fileName;
1760         }
1761         //printf("++ new namespace %s lang=%s tagName=%s\n",fullName.data(),langToString(root->lang).data(),tagName.data());
1762         NamespaceDef *nd=new NamespaceDef(root->fileName,root->startLine,
1763                              root->startColumn,fullName,tagName,tagFileName,
1764                              root->type,root->spec&Entry::Published);
1765         nd->setDocumentation(root->doc,root->docFile,root->docLine); // copy docs to definition
1766         nd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1767         nd->addSectionsToDefinition(root->anchors);
1768         nd->setHidden(root->hidden);
1769         nd->setArtificial(root->artificial);
1770         nd->setLanguage(root->lang);
1771         nd->setId(root->id);
1772
1773         //printf("Adding namespace to group\n");
1774         addNamespaceToGroups(root,nd);
1775         nd->setRefItems(root->sli);
1776
1777         // file definition containing the namespace nd
1778         FileDef *fd=rootNav->fileDef();
1779         // insert the namespace in the file definition
1780         if (fd) fd->insertNamespace(nd);
1781
1782         // the empty string test is needed for extract all case
1783         nd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1784         nd->insertUsedFile(fd);
1785         nd->setBodySegment(root->bodyLine,root->endBodyLine);
1786         nd->setBodyDef(fd);
1787         // add class to the list
1788         Doxygen::namespaceSDict->inSort(fullName,nd);
1789
1790         // also add namespace to the correct structural context 
1791         Definition *d = findScopeFromQualifiedName(Doxygen::globalScope,fullName);
1792         //printf("adding namespace %s to context %s\n",nd->name().data(),d?d->name().data():"<none>");
1793         if (d==0) // we didn't find anything, create the scope artificially
1794                   // anyway, so we can at least relate scopes properly.
1795         {
1796           Definition *d = buildScopeFromQualifiedName(fullName,fullName.contains("::"),nd->getLanguage(),tagInfo);
1797           d->addInnerCompound(nd);
1798           nd->setOuterScope(d);
1799           // TODO: Due to the order in which the tag file is written
1800           // a nested class can be found before its parent!
1801         }
1802         else
1803         {
1804           d->addInnerCompound(nd);
1805           nd->setOuterScope(d);
1806         }
1807       }
1808     }
1809
1810     rootNav->releaseEntry();
1811   }
1812   RECURSE_ENTRYTREE(buildNamespaceList,rootNav);
1813 }
1814
1815 //----------------------------------------------------------------------
1816
1817 static NamespaceDef *findUsedNamespace(NamespaceSDict *unl,
1818                               const QCString &name)
1819 {
1820   NamespaceDef *usingNd =0;
1821   if (unl)
1822   {
1823     //printf("Found namespace dict %d\n",unl->count());
1824     NamespaceSDict::Iterator unli(*unl);
1825     NamespaceDef *und;
1826     for (unli.toFirst();(und=unli.current());++unli)
1827     {
1828       QCString uScope=und->name()+"::";
1829       usingNd = getResolvedNamespace(uScope+name);
1830       //printf("Also trying with scope=`%s' usingNd=%p\n",(uScope+name).data(),usingNd);
1831     }
1832   }
1833   return usingNd;
1834 }
1835
1836 static void findUsingDirectives(EntryNav *rootNav)
1837 {
1838   if (rootNav->section()==Entry::USINGDIR_SEC)
1839   {
1840     rootNav->loadEntry(g_storage);
1841     Entry *root = rootNav->entry();
1842
1843     //printf("Found using directive %s at line %d of %s\n",
1844     //    root->name.data(),root->startLine,root->fileName.data());
1845     QCString name=substitute(root->name,".","::");
1846     if (name.right(2)=="::")
1847     {
1848       name=name.left(name.length()-2);
1849     }
1850     if (!name.isEmpty())
1851     {
1852       NamespaceDef *usingNd = 0;
1853       NamespaceDef *nd = 0;
1854       FileDef      *fd = rootNav->fileDef();
1855       QCString nsName;
1856
1857       // see if the using statement was found inside a namespace or inside
1858       // the global file scope.
1859       if (rootNav->parent() && rootNav->parent()->section()==Entry::NAMESPACE_SEC &&
1860           (fd==0 || fd->getLanguage()!=SrcLangExt_Java) // not a .java file
1861          )
1862       {
1863         nsName=stripAnonymousNamespaceScope(rootNav->parent()->name());
1864         if (!nsName.isEmpty())
1865         {
1866           nd = getResolvedNamespace(nsName);
1867         }
1868       }
1869
1870       // find the scope in which the `using' namespace is defined by prepending
1871       // the possible scopes in which the using statement was found, starting
1872       // with the most inner scope and going to the most outer scope (i.e. 
1873       // file scope). 
1874       int scopeOffset = nsName.length();
1875       do
1876       {
1877         QCString scope=scopeOffset>0 ? 
1878                       nsName.left(scopeOffset)+"::" : QCString();
1879         usingNd = getResolvedNamespace(scope+name);
1880         //printf("Trying with scope=`%s' usingNd=%p\n",(scope+name).data(),usingNd);
1881         if (scopeOffset==0)
1882         {
1883           scopeOffset=-1;
1884         }
1885         else if ((scopeOffset=nsName.findRev("::",scopeOffset-1))==-1)
1886         {
1887           scopeOffset=0;
1888         }
1889       } while (scopeOffset>=0 && usingNd==0);
1890
1891       if (usingNd==0 && nd) // not found, try used namespaces in this scope
1892                             // or in one of the parent namespace scopes
1893       {
1894         NamespaceDef *pnd = nd;
1895         while (pnd && usingNd==0)
1896         {
1897           // also try with one of the used namespaces found earlier
1898           usingNd = findUsedNamespace(pnd->getUsedNamespaces(),name);
1899
1900           // goto the parent
1901           Definition *s = pnd->getOuterScope();
1902           if (s && s->definitionType()==Definition::TypeNamespace)
1903           {
1904             pnd = (NamespaceDef*)s;
1905           }
1906           else
1907           {
1908             pnd = 0;
1909           }
1910         }
1911       }
1912       if (usingNd==0 && fd) // still nothing, also try used namespace in the
1913                             // global scope
1914       {
1915         usingNd = findUsedNamespace(fd->getUsedNamespaces(),name);
1916       }
1917
1918       //printf("%s -> %s\n",name.data(),usingNd?usingNd->name().data():"<none>");
1919
1920       // add the namespace the correct scope
1921       if (usingNd)
1922       {
1923         //printf("using fd=%p nd=%p\n",fd,nd);
1924         if (nd)
1925         {
1926           //printf("Inside namespace %s\n",nd->name().data());
1927           nd->addUsingDirective(usingNd);
1928         }
1929         else if (fd)
1930         {
1931           //printf("Inside file %s\n",fd->name().data());
1932           fd->addUsingDirective(usingNd);
1933         }
1934       }
1935       else // unknown namespace, but add it anyway.
1936       {
1937         //printf("++ new unknown namespace %s lang=%s\n",name.data(),langToString(root->lang).data());
1938         NamespaceDef *nd=new NamespaceDef(root->fileName,root->startLine,root->startColumn,name);
1939         nd->setDocumentation(root->doc,root->docFile,root->docLine); // copy docs to definition
1940         nd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1941         nd->addSectionsToDefinition(root->anchors);
1942         //printf("** Adding namespace %s hidden=%d\n",name.data(),root->hidden);
1943         nd->setHidden(root->hidden);
1944         nd->setArtificial(TRUE);
1945         nd->setLanguage(root->lang);
1946         nd->setId(root->id);
1947
1948         QListIterator<Grouping> gli(*root->groups);
1949         Grouping *g;
1950         for (;(g=gli.current());++gli)
1951         {
1952           GroupDef *gd=0;
1953           if (!g->groupname.isEmpty() && (gd=Doxygen::groupSDict->find(g->groupname)))
1954             gd->addNamespace(nd);
1955         }
1956
1957         // insert the namespace in the file definition
1958         if (fd) 
1959         {
1960           fd->insertNamespace(nd);
1961           fd->addUsingDirective(nd);
1962         }
1963
1964         // the empty string test is needed for extract all case
1965         nd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1966         nd->insertUsedFile(fd);
1967         // add class to the list
1968         Doxygen::namespaceSDict->inSort(name,nd);
1969         nd->setRefItems(root->sli);
1970       }
1971     }
1972
1973     rootNav->releaseEntry();
1974   }
1975   RECURSE_ENTRYTREE(findUsingDirectives,rootNav);
1976 }
1977
1978 //----------------------------------------------------------------------
1979
1980 static void buildListOfUsingDecls(EntryNav *rootNav)
1981 {
1982   if (rootNav->section()==Entry::USINGDECL_SEC &&
1983       !(rootNav->parent()->section()&Entry::COMPOUND_MASK) // not a class/struct member
1984      )
1985   {
1986     rootNav->loadEntry(g_storage);
1987     Entry *root = rootNav->entry();
1988
1989     QCString name = substitute(root->name,".","::");
1990
1991     if (g_usingDeclarations.find(name)==0)
1992     {
1993       FileDef *fd = rootNav->fileDef();
1994       if (fd)
1995       {
1996         g_usingDeclarations.insert(name,fd);
1997       }
1998     }
1999
2000     rootNav->releaseEntry();
2001   }
2002   RECURSE_ENTRYTREE(buildListOfUsingDecls,rootNav);
2003 }
2004
2005   
2006 static void findUsingDeclarations(EntryNav *rootNav)
2007 {
2008   if (rootNav->section()==Entry::USINGDECL_SEC &&
2009       !(rootNav->parent()->section()&Entry::COMPOUND_MASK) // not a class/struct member
2010      )
2011   {
2012     rootNav->loadEntry(g_storage);
2013     Entry *root = rootNav->entry();
2014
2015     //printf("Found using declaration %s at line %d of %s inside section %x\n",
2016     //   root->name.data(),root->startLine,root->fileName.data(),
2017     //   rootNav->parent()->section());
2018     if (!root->name.isEmpty())
2019     {
2020       ClassDef *usingCd = 0;
2021       NamespaceDef *nd = 0;
2022       FileDef      *fd = rootNav->fileDef();
2023       QCString scName;
2024
2025       // see if the using statement was found inside a namespace or inside
2026       // the global file scope.
2027       if (rootNav->parent()->section() == Entry::NAMESPACE_SEC)
2028       {
2029         scName=rootNav->parent()->name();
2030         if (!scName.isEmpty())
2031         {
2032           nd = getResolvedNamespace(scName);
2033         }
2034       }
2035
2036       // Assume the using statement was used to import a class.
2037       // Find the scope in which the `using' namespace is defined by prepending
2038       // the possible scopes in which the using statement was found, starting
2039       // with the most inner scope and going to the most outer scope (i.e. 
2040       // file scope).
2041
2042       QCString name = substitute(root->name,".","::"); //Java/C# scope->internal
2043       usingCd = getClass(name);
2044       if (usingCd==0)
2045       {
2046         usingCd = Doxygen::hiddenClasses->find(name);
2047       }
2048
2049       //printf("%s -> %p\n",root->name.data(),usingCd);
2050       if (usingCd==0) // definition not in the input => add an artificial class
2051       {
2052         Debug::print(Debug::Classes,0,"  New using class `%s' (sec=0x%08x)! #tArgLists=%d\n",
2053              name.data(),root->section,root->tArgLists ? (int)root->tArgLists->count() : -1);
2054         usingCd = new ClassDef(
2055                      "<using>",1,1,
2056                      name,
2057                      ClassDef::Class);
2058         Doxygen::hiddenClasses->append(root->name,usingCd);
2059         usingCd->setArtificial(TRUE);
2060         usingCd->setLanguage(root->lang);
2061       }
2062       else
2063       {
2064         Debug::print(Debug::Classes,0,"  Found used class %s in scope=%s\n",
2065             usingCd->name().data(),nd?nd->name().data():fd->name().data());
2066       }
2067
2068       if (usingCd) // add the class to the correct scope
2069       {
2070         if (nd)
2071         {
2072           //printf("Inside namespace %s\n",nd->name().data());
2073           nd->addUsingDeclaration(usingCd);
2074         }
2075         else if (fd)
2076         {
2077           //printf("Inside file %s\n",fd->name().data());
2078           fd->addUsingDeclaration(usingCd);
2079         }
2080       }
2081     }
2082
2083     rootNav->releaseEntry();
2084   }
2085   RECURSE_ENTRYTREE(findUsingDeclarations,rootNav);
2086 }
2087
2088 //----------------------------------------------------------------------
2089
2090 static void findUsingDeclImports(EntryNav *rootNav)
2091 {
2092   if (rootNav->section()==Entry::USINGDECL_SEC &&
2093       (rootNav->parent()->section()&Entry::COMPOUND_MASK) // in a class/struct member
2094      )
2095   {
2096     //printf("Found using declaration %s at line %d of %s inside section %x\n",
2097     //    root->name.data(),root->startLine,root->fileName.data(),
2098     //    root->parent->section);
2099     QCString fullName=removeRedundantWhiteSpace(rootNav->parent()->name());
2100     fullName=stripAnonymousNamespaceScope(fullName);
2101     fullName=stripTemplateSpecifiersFromScope(fullName);
2102     ClassDef *cd = getClass(fullName);
2103     if (cd)
2104     {
2105       //printf("found class %s\n",cd->name().data());
2106       int i=rootNav->name().find("::");
2107       if (i!=-1)
2108       {
2109         QCString scope=rootNav->name().left(i);
2110         QCString memName=rootNav->name().right(rootNav->name().length()-i-2);
2111         ClassDef *bcd = getResolvedClass(cd,0,scope); // todo: file in fileScope parameter
2112         if (bcd)
2113         {
2114           //printf("found class %s\n",bcd->name().data());
2115           MemberNameInfoSDict *mndict=bcd->memberNameInfoSDict();
2116           if (mndict)
2117           {
2118             MemberNameInfo *mni = mndict->find(memName);
2119             if (mni)
2120             {
2121               MemberNameInfoIterator mnii(*mni); 
2122               MemberInfo *mi;
2123               for ( ; (mi=mnii.current()) ; ++mnii )
2124               {
2125                 MemberDef *md = mi->memberDef;
2126                 if (md && md->protection()!=Private)
2127                 {
2128
2129                   rootNav->loadEntry(g_storage);
2130                   Entry *root = rootNav->entry();
2131
2132                   //printf("found member %s\n",mni->memberName());
2133                   MemberDef *newMd = 0;
2134                   {
2135                     ArgumentList *templAl = md->templateArguments();
2136                     ArgumentList *al = md->templateArguments();
2137                     newMd = new MemberDef(
2138                       root->fileName,root->startLine,root->startColumn,
2139                       md->typeString(),memName,md->argsString(),
2140                       md->excpString(),root->protection,root->virt,
2141                       md->isStatic(),Member,md->memberType(),
2142                       templAl,al
2143                       );
2144                   }
2145                   newMd->setMemberClass(cd);
2146                   cd->insertMember(newMd);
2147                   if (!root->doc.isEmpty() || !root->brief.isEmpty())
2148                   {
2149                     newMd->setDocumentation(root->doc,root->docFile,root->docLine);
2150                     newMd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
2151                     newMd->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
2152                   }
2153                   else
2154                   {
2155                     newMd->setDocumentation(md->documentation(),md->docFile(),md->docLine());
2156                     newMd->setBriefDescription(md->briefDescription(),md->briefFile(),md->briefLine());
2157                     newMd->setInbodyDocumentation(md->inbodyDocumentation(),md->inbodyFile(),md->inbodyLine());
2158                   }
2159                   newMd->setDefinition(md->definition());
2160                   newMd->enableCallGraph(root->callGraph);
2161                   newMd->enableCallerGraph(root->callerGraph);
2162                   newMd->setBitfields(md->bitfieldString());
2163                   newMd->addSectionsToDefinition(root->anchors);
2164                   newMd->setBodySegment(md->getStartBodyLine(),md->getEndBodyLine());
2165                   newMd->setBodyDef(md->getBodyDef());
2166                   newMd->setInitializer(md->initializer());
2167                   newMd->setMaxInitLines(md->initializerLines());
2168                   newMd->setMemberGroupId(root->mGrpId);
2169                   newMd->setMemberSpecifiers(md->getMemberSpecifiers());
2170                   newMd->setLanguage(root->lang);
2171                   newMd->setId(root->id);
2172
2173                   rootNav->releaseEntry();
2174                 }
2175               }
2176             }
2177           }
2178         }
2179       }
2180     }
2181
2182   }
2183   RECURSE_ENTRYTREE(findUsingDeclImports,rootNav);
2184 }
2185
2186 //----------------------------------------------------------------------
2187
2188 static void findIncludedUsingDirectives()
2189 {
2190   // first mark all files as not visited
2191   FileNameListIterator fnli(*Doxygen::inputNameList); 
2192   FileName *fn;
2193   for (fnli.toFirst();(fn=fnli.current());++fnli)
2194   {
2195     FileNameIterator fni(*fn);
2196     FileDef *fd;
2197     for (;(fd=fni.current());++fni)
2198     {
2199       fd->visited=FALSE;
2200     }
2201   }
2202   // then recursively add using directives found in #include files
2203   // to files that have not been visited.
2204   for (fnli.toFirst();(fn=fnli.current());++fnli)
2205   {
2206     FileNameIterator fni(*fn);
2207     FileDef *fd;
2208     for (fni.toFirst();(fd=fni.current());++fni)
2209     {
2210       if (!fd->visited) 
2211       {
2212         //printf("----- adding using directives for file %s\n",fd->name().data());
2213         fd->addIncludedUsingDirectives();
2214       }
2215     }
2216   }
2217 }
2218
2219 //----------------------------------------------------------------------
2220
2221 static MemberDef *addVariableToClass(
2222     EntryNav *rootNav,
2223     ClassDef *cd,
2224     MemberType mtype,
2225     const QCString &name,
2226     bool fromAnnScope,
2227     MemberDef *fromAnnMemb,
2228     Protection prot,
2229     Relationship related)
2230 {
2231   Entry *root = rootNav->entry();
2232
2233   QCString qualScope = cd->qualifiedNameWithTemplateParameters();
2234   QCString scopeSeparator="::";
2235   SrcLangExt lang = cd->getLanguage();
2236   if (lang==SrcLangExt_Java || lang==SrcLangExt_CSharp)
2237   {
2238     qualScope = substitute(qualScope,"::",".");
2239     scopeSeparator=".";
2240   }
2241   Debug::print(Debug::Variables,0,
2242       "  class variable:\n"
2243       "    `%s' `%s'::`%s' `%s' prot=`%d ann=%d init=`%s'\n",
2244       root->type.data(),
2245       qualScope.data(), 
2246       name.data(),
2247       root->args.data(),
2248       root->protection,
2249       fromAnnScope,
2250       root->initializer.data()
2251               );
2252
2253   QCString def;
2254   if (!root->type.isEmpty())
2255   {
2256     if (related || mtype==MemberType_Friend || Config_getBool("HIDE_SCOPE_NAMES"))
2257     {
2258       if (root->spec&Entry::Alias) // turn 'typedef B A' into 'using A = B'  
2259       {
2260         def="using "+name+" = "+root->type.mid(7);
2261       }
2262       else
2263       {
2264         def=root->type+" "+name+root->args;
2265       }
2266     }
2267     else
2268     {
2269       if (root->spec&Entry::Alias) // turn 'typedef B C::A' into 'using C::A = B'  
2270       {
2271         def="using "+qualScope+scopeSeparator+name+" = "+root->type.mid(7);
2272       }
2273       else
2274       {
2275         def=root->type+" "+qualScope+scopeSeparator+name+root->args;
2276       }
2277     }
2278   }
2279   else
2280   {
2281     if (Config_getBool("HIDE_SCOPE_NAMES"))
2282     {
2283       def=name+root->args;
2284     }
2285     else
2286     {
2287       def=qualScope+scopeSeparator+name+root->args;
2288     }
2289   }
2290   def.stripPrefix("static ");
2291
2292   // see if the member is already found in the same scope
2293   // (this may be the case for a static member that is initialized
2294   //  outside the class)
2295   MemberName *mn=Doxygen::memberNameSDict->find(name);
2296   if (mn)
2297   {
2298     MemberNameIterator mni(*mn);
2299     MemberDef *md;
2300     for (mni.toFirst();(md=mni.current());++mni)
2301     {
2302       //printf("md->getClassDef()=%p cd=%p type=[%s] md->typeString()=[%s]\n",
2303       //    md->getClassDef(),cd,root->type.data(),md->typeString());
2304       if (md->getClassDef()==cd && 
2305           removeRedundantWhiteSpace(root->type)==md->typeString()) 
2306         // member already in the scope
2307       {
2308
2309         if (root->lang==SrcLangExt_ObjC && 
2310             root->mtype==Property && 
2311             md->memberType()==MemberType_Variable)
2312         { // Objective-C 2.0 property
2313           // turn variable into a property
2314           md->setProtection(root->protection);
2315           cd->reclassifyMember(md,MemberType_Property);
2316         }
2317         addMemberDocs(rootNav,md,def,0,FALSE);
2318         //printf("    Member already found!\n");
2319         return md;
2320       }
2321     } 
2322   }
2323
2324   // new member variable, typedef or enum value
2325   MemberDef *md=new MemberDef(
2326       root->fileName,root->startLine,root->startColumn,
2327       root->type,name,root->args,root->exception,
2328       prot,Normal,root->stat,related,
2329       mtype,root->tArgLists ? root->tArgLists->getLast() : 0,0);
2330   md->setTagInfo(rootNav->tagInfo());
2331   md->setMemberClass(cd); // also sets outer scope (i.e. getOuterScope())
2332   //md->setDefFile(root->fileName);
2333   //md->setDefLine(root->startLine);
2334   md->setDocumentation(root->doc,root->docFile,root->docLine);
2335   md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
2336   md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
2337   md->setDefinition(def);
2338   md->setBitfields(root->bitfields);
2339   md->addSectionsToDefinition(root->anchors);
2340   md->setFromAnonymousScope(fromAnnScope);
2341   md->setFromAnonymousMember(fromAnnMemb);
2342   //md->setIndentDepth(indentDepth);
2343   md->setBodySegment(root->bodyLine,root->endBodyLine);
2344   md->setInitializer(root->initializer);
2345   md->setMaxInitLines(root->initLines);
2346   md->setMemberGroupId(root->mGrpId);
2347   md->setMemberSpecifiers(root->spec);
2348   md->setReadAccessor(root->read);
2349   md->setWriteAccessor(root->write);
2350   md->enableCallGraph(root->callGraph);
2351   md->enableCallerGraph(root->callerGraph);
2352   md->setHidden(root->hidden);
2353   md->setArtificial(root->artificial);
2354   md->setLanguage(root->lang);
2355   md->setId(root->id);
2356   addMemberToGroups(root,md);
2357   //if (root->mGrpId!=-1) 
2358   //{
2359   //  printf("memberdef %s in memberGroup %d\n",name.data(),root->mGrpId);
2360   //  md->setMemberGroup(memberGroupDict[root->mGrpId]);
2361   //
2362   md->setBodyDef(rootNav->fileDef());
2363
2364   //printf("    Adding member=%s\n",md->name().data());
2365   // add the member to the global list
2366   if (mn)
2367   {
2368     mn->append(md);
2369   }
2370   else // new variable name
2371   {
2372     mn = new MemberName(name);
2373     mn->append(md);
2374     //printf("Adding memberName=%s\n",mn->memberName());
2375     //Doxygen::memberNameDict.insert(name,mn);
2376     //Doxygen::memberNameList.append(mn);
2377     Doxygen::memberNameSDict->append(name,mn);
2378     // add the member to the class
2379   }
2380   //printf("    New member adding to %s (%p)!\n",cd->name().data(),cd);
2381   cd->insertMember(md);
2382   md->setRefItems(root->sli);
2383
2384   //TODO: insert FileDef instead of filename strings.
2385   cd->insertUsedFile(rootNav->fileDef());
2386   rootNav->changeSection(Entry::EMPTY_SEC);
2387   return md;
2388 }
2389
2390 //----------------------------------------------------------------------
2391
2392 static MemberDef *addVariableToFile(
2393     EntryNav *rootNav,
2394     MemberType mtype,
2395     const QCString &scope,
2396     const QCString &name,
2397     bool fromAnnScope,
2398     /*int indentDepth,*/
2399     MemberDef *fromAnnMemb)
2400 {
2401   Entry *root = rootNav->entry();
2402   Debug::print(Debug::Variables,0,
2403       "  global variable:\n"
2404       "    type=`%s' scope=`%s' name=`%s' args=`%s' prot=`%d mtype=%d lang=%d\n",
2405       root->type.data(),
2406       scope.data(), 
2407       name.data(),
2408       root->args.data(),
2409       root->protection,
2410       mtype,
2411       root->lang
2412               );
2413
2414   FileDef *fd = rootNav->fileDef();
2415
2416   // see if we have a typedef that should hide a struct or union
2417   if (mtype==MemberType_Typedef && Config_getBool("TYPEDEF_HIDES_STRUCT"))
2418   {
2419     QCString type = root->type;
2420     type.stripPrefix("typedef ");
2421     if (type.left(7)=="struct " || type.left(6)=="union ")
2422     {
2423       type.stripPrefix("struct ");
2424       type.stripPrefix("union ");
2425       static QRegExp re("[a-z_A-Z][a-z_A-Z0-9]*");
2426       int l,s;
2427       s = re.match(type,0,&l);
2428       if (s>=0)
2429       {
2430         QCString typeValue = type.mid(s,l);
2431         ClassDef *cd = getClass(typeValue);
2432         if (cd)
2433         {
2434           // this typedef should hide compound name cd, so we
2435           // change the name that is displayed from cd.
2436           cd->setClassName(name);
2437           cd->setDocumentation(root->doc,root->docFile,root->docLine);
2438           cd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
2439           return 0;
2440         }
2441       }
2442     }
2443   }
2444
2445   // see if the function is inside a namespace
2446   NamespaceDef *nd = 0;
2447   QCString nscope;
2448   if (!scope.isEmpty())
2449   {
2450     if (scope.find('@')!=-1) return 0; // anonymous scope!
2451     //nscope=removeAnonymousScopes(scope);
2452     //if (!nscope.isEmpty())
2453     //{
2454     nd = getResolvedNamespace(scope);
2455     //}
2456   }
2457   QCString def;
2458
2459   // determine the definition of the global variable
2460   if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@' && 
2461       !Config_getBool("HIDE_SCOPE_NAMES")
2462      )
2463     // variable is inside a namespace, so put the scope before the name
2464   {
2465     SrcLangExt lang = nd->getLanguage();
2466     QCString sep=getLanguageSpecificSeparator(lang);
2467
2468     if (!root->type.isEmpty())
2469     {
2470       if (root->spec&Entry::Alias) // turn 'typedef B NS::A' into 'using NS::A = B'  
2471       {
2472         def="using "+nd->name()+sep+name+" = "+root->type;
2473       }
2474       else // normal member
2475       {
2476         def=root->type+" "+nd->name()+sep+name+root->args;
2477       }
2478     }
2479     else
2480     {
2481       def=nd->name()+sep+name+root->args;
2482     }
2483   }
2484   else
2485   {
2486     if (!root->type.isEmpty() && !root->name.isEmpty())
2487     {
2488       if (name.at(0)=='@') // dummy variable representing anonymous union
2489       {
2490         def=root->type;
2491       }
2492       else
2493       {
2494         if (root->spec&Entry::Alias) // turn 'typedef B A' into 'using A = B'  
2495         {
2496           def="using "+root->name+" = "+root->type.mid(7);
2497         }
2498         else // normal member
2499         {
2500           def=root->type+" "+name+root->args;
2501         }
2502       }
2503     }
2504     else
2505     {
2506       def=name+root->args;
2507     }
2508   }
2509   def.stripPrefix("static ");
2510
2511   MemberName *mn=Doxygen::functionNameSDict->find(name);
2512   if (mn)
2513   {
2514     //QCString nscope=removeAnonymousScopes(scope);
2515     //NamespaceDef *nd=0;
2516     //if (!nscope.isEmpty())
2517     if (!scope.isEmpty())
2518     {
2519       nd = getResolvedNamespace(scope);
2520     }
2521     MemberNameIterator mni(*mn);
2522     MemberDef *md;
2523     for (mni.toFirst();(md=mni.current());++mni)
2524     {
2525       if (
2526           ((nd==0 && md->getNamespaceDef()==0 && md->getFileDef() && 
2527             root->fileName==md->getFileDef()->absFilePath()
2528            ) // both variable names in the same file
2529            || (nd!=0 && md->getNamespaceDef()==nd) // both in same namespace
2530           )
2531           && !md->isDefine() // function style #define's can be "overloaded" by typedefs or variables
2532           && !md->isEnumerate() // in C# an enum value and enum can have the same name
2533          )
2534         // variable already in the scope
2535       {
2536         bool isPHPArray = md->getLanguage()==SrcLangExt_PHP &&
2537                           md->argsString()!=root->args && 
2538                           root->args.find('[')!=-1;
2539         bool staticsInDifferentFiles = 
2540                           root->stat && md->isStatic() && 
2541                           root->fileName!=md->getDefFileName();
2542
2543         if (md->getFileDef() &&
2544             !isPHPArray && // not a php array
2545             !staticsInDifferentFiles
2546            ) 
2547           // not a php array variable
2548         {
2549
2550           Debug::print(Debug::Variables,0,
2551               "    variable already found: scope=%s\n",md->getOuterScope()->name().data());
2552           addMemberDocs(rootNav,md,def,0,FALSE);
2553           md->setRefItems(root->sli);
2554           return md;
2555         }
2556       }
2557     } 
2558   }
2559   Debug::print(Debug::Variables,0,
2560     "    new variable, nd=%s!\n",nd?nd->name().data():"<global>");
2561   // new global variable, enum value or typedef
2562   MemberDef *md=new MemberDef(
2563       root->fileName,root->startLine,root->startColumn,
2564       root->type,name,root->args,0,
2565       Public, Normal,root->stat,Member,
2566       mtype,root->tArgLists ? root->tArgLists->getLast() : 0,0);
2567   md->setTagInfo(rootNav->tagInfo());
2568   md->setMemberSpecifiers(root->spec);
2569   md->setDocumentation(root->doc,root->docFile,root->docLine);
2570   md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
2571   md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
2572   md->addSectionsToDefinition(root->anchors);
2573   md->setFromAnonymousScope(fromAnnScope);
2574   md->setFromAnonymousMember(fromAnnMemb);
2575   md->setInitializer(root->initializer);
2576   md->setMaxInitLines(root->initLines);
2577   md->setMemberGroupId(root->mGrpId);
2578   md->setDefinition(def);
2579   md->setLanguage(root->lang);
2580   md->setId(root->id);
2581   md->enableCallGraph(root->callGraph);
2582   md->enableCallerGraph(root->callerGraph);
2583   md->setExplicitExternal(root->explicitExternal);
2584   //md->setOuterScope(fd);
2585   if (!root->explicitExternal)
2586   {
2587     md->setBodySegment(root->bodyLine,root->endBodyLine);
2588     md->setBodyDef(fd);
2589   }
2590   addMemberToGroups(root,md);
2591
2592   md->setRefItems(root->sli);
2593   if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@')
2594   {
2595     md->setNamespace(nd);
2596     nd->insertMember(md); 
2597   }
2598
2599   // add member to the file (we do this even if we have already inserted
2600   // it into the namespace. 
2601   if (fd)
2602   {
2603     md->setFileDef(fd); 
2604     fd->insertMember(md);
2605   }
2606
2607   // add member definition to the list of globals 
2608   if (mn)
2609   {
2610     mn->append(md);
2611   }
2612   else
2613   {
2614     mn = new MemberName(name);
2615     mn->append(md);
2616     Doxygen::functionNameSDict->append(name,mn);
2617   }
2618   rootNav->changeSection(Entry::EMPTY_SEC);
2619   return md;
2620 }
2621
2622 /*! See if the return type string \a type is that of a function pointer 
2623  *  \returns -1 if this is not a function pointer variable or
2624  *           the index at which the closing brace of (...*name) was found.
2625  */
2626 static int findFunctionPtr(const QCString &type,int lang, int *pLength=0)
2627 {
2628   if (lang == SrcLangExt_Fortran) return -1; // Fortran does not have function pointers
2629   static const QRegExp re("([^)]*[\\*\\^][^)]*)");
2630   int i=-1,l;
2631   int bb=type.find('<');
2632   int be=type.findRev('>');
2633   if (!type.isEmpty() &&             // return type is non-empty
2634       (i=re.match(type,0,&l))!=-1 && // contains (...*...)
2635       type.find("operator")==-1 &&   // not an operator
2636       (type.find(")(")==-1 || type.find("typedef ")!=-1) &&
2637                                     // not a function pointer return type
2638       !(bb<i && i<be) // bug665855: avoid treating "typedef A<void (T*)> type" as a function pointer
2639      )
2640   {
2641     if (pLength) *pLength=l;
2642     //printf("findFunctionPtr=%d\n",i);
2643     return i;
2644   }
2645   else
2646   {
2647     //printf("findFunctionPtr=%d\n",-1);
2648     return -1;
2649   }
2650 }
2651
2652
2653 /*! Returns TRUE iff \a type is a class within scope \a context.
2654  *  Used to detect variable declarations that look like function prototypes.
2655  */
2656 static bool isVarWithConstructor(EntryNav *rootNav)
2657 {
2658   static QRegExp initChars("[0-9\"'&*!^]+");
2659   static QRegExp idChars("[a-z_A-Z][a-z_A-Z0-9]*");
2660   bool result=FALSE;
2661   bool typeIsClass;
2662   QCString type;
2663   Definition *ctx = 0;
2664   FileDef *fd = 0;
2665   int ti;
2666
2667   //printf("isVarWithConstructor(%s)\n",rootNav->name().data());
2668   rootNav->loadEntry(g_storage);
2669   Entry *root = rootNav->entry();
2670
2671   if (rootNav->parent()->section() & Entry::COMPOUND_MASK)
2672   { // inside a class
2673     result=FALSE;
2674     goto done;
2675   }
2676   else if ((fd = rootNav->fileDef()) &&
2677             (fd->name().right(2)==".c" || fd->name().right(2)==".h")
2678           )
2679   { // inside a .c file
2680     result=FALSE;
2681     goto done;
2682   }
2683   if (root->type.isEmpty()) 
2684   {
2685     result=FALSE;
2686     goto done;
2687   }
2688   if (!rootNav->parent()->name().isEmpty()) 
2689   {
2690     ctx=Doxygen::namespaceSDict->find(rootNav->parent()->name());
2691   }
2692   type = root->type;
2693   // remove qualifiers
2694   findAndRemoveWord(type,"const");
2695   findAndRemoveWord(type,"static");
2696   findAndRemoveWord(type,"volatile");
2697   //if (type.left(6)=="const ") type=type.right(type.length()-6);
2698   typeIsClass=getResolvedClass(ctx,fd,type)!=0;
2699   if (!typeIsClass && (ti=type.find('<'))!=-1)
2700   {
2701     typeIsClass=getResolvedClass(ctx,fd,type.left(ti))!=0;
2702   }
2703   if (typeIsClass) // now we still have to check if the arguments are 
2704                    // types or values. Since we do not have complete type info
2705                    // we need to rely on heuristics :-(
2706   {
2707     //printf("typeIsClass\n");
2708     ArgumentList *al = root->argList;
2709     if (al==0 || al->isEmpty()) 
2710     {
2711       result=FALSE; // empty arg list -> function prototype.
2712       goto done;
2713     }
2714     ArgumentListIterator ali(*al);
2715     Argument *a;
2716     for (ali.toFirst();(a=ali.current());++ali)
2717     {
2718       if (!a->name.isEmpty() || !a->defval.isEmpty()) 
2719       {
2720         if (a->name.find(initChars)==0)
2721         {
2722           result=TRUE;
2723         }
2724         else
2725         {
2726           result=FALSE; // arg has (type,name) pair -> function prototype
2727         }
2728         goto done;
2729       }
2730       if (a->type.isEmpty() || getResolvedClass(ctx,fd,a->type)!=0) 
2731       {
2732         result=FALSE; // arg type is a known type
2733         goto done;
2734       }
2735       if (checkIfTypedef(ctx,fd,a->type))
2736       {
2737          //printf("%s:%d: false (arg is typedef)\n",__FILE__,__LINE__);
2738          result=FALSE; // argument is a typedef
2739          goto done;
2740       }
2741       if (a->type.at(a->type.length()-1)=='*' ||
2742           a->type.at(a->type.length()-1)=='&')  
2743                      // type ends with * or & => pointer or reference
2744       {
2745         result=FALSE;
2746         goto done;
2747       }
2748       if (a->type.find(initChars)==0) 
2749       {
2750         result=TRUE; // argument type starts with typical initializer char
2751         goto done;
2752       }
2753       QCString resType=resolveTypeDef(ctx,a->type);
2754       if (resType.isEmpty()) resType=a->type;
2755       int len;
2756       if (idChars.match(resType,0,&len)==0) // resType starts with identifier
2757       {
2758         resType=resType.left(len);
2759         //printf("resType=%s\n",resType.data());
2760         if (resType=="int"    || resType=="long" || resType=="float" || 
2761             resType=="double" || resType=="char" || resType=="signed" || 
2762             resType=="const"  || resType=="unsigned" || resType=="void") 
2763         {
2764           result=FALSE; // type keyword -> function prototype
2765           goto done;
2766         }
2767       }
2768     }
2769     result=TRUE;
2770   }
2771
2772 done:
2773   //printf("isVarWithConstructor(%s,%s)=%d\n",rootNav->parent()->name().data(),
2774   //                                          root->type.data(),result);
2775   rootNav->releaseEntry();
2776   return result;
2777 }
2778
2779 static void addVariable(EntryNav *rootNav,int isFuncPtr=-1)
2780 {
2781     rootNav->loadEntry(g_storage);
2782     Entry *root = rootNav->entry();
2783
2784     Debug::print(Debug::Variables,0,
2785                   "VARIABLE_SEC: \n"
2786                   "  type=`%s' name=`%s' args=`%s' bodyLine=`%d' mGrpId=%d relates=%s\n",
2787                    root->type.data(),
2788                    root->name.data(),
2789                    root->args.data(),
2790                    root->bodyLine,
2791                    root->mGrpId,
2792                    root->relates.data()
2793                 );
2794     //printf("root->parent->name=%s\n",root->parent->name.data());
2795
2796     if (root->type.isEmpty() && root->name.find("operator")==-1 &&
2797         (root->name.find('*')!=-1 || root->name.find('&')!=-1))
2798     {
2799       // recover from parse error caused by redundant braces 
2800       // like in "int *(var[10]);", which is parsed as
2801       // type="" name="int *" args="(var[10])"
2802
2803       root->type=root->name;
2804       static const QRegExp reName("[a-z_A-Z][a-z_A-Z0-9]*");
2805       int l=0;
2806       int i=root->args.isEmpty() ? -1 : reName.match(root->args,0,&l);
2807       if (i!=-1)
2808       {
2809         root->name=root->args.mid(i,l);
2810         root->args=root->args.mid(i+l,root->args.find(')',i+l)-i-l);
2811       }
2812       //printf("new: type=`%s' name=`%s' args=`%s'\n",
2813       //    root->type.data(),root->name.data(),root->args.data());
2814     }
2815     else
2816     {
2817       int i=isFuncPtr;
2818       if (i==-1 && (root->spec&Entry::Alias)==0) i=findFunctionPtr(root->type,root->lang); // for typedefs isFuncPtr is not yet set
2819       Debug::print(Debug::Variables,0,"  functionPtr? %s\n",i!=-1?"yes":"no");
2820       if (i!=-1) // function pointer
2821       {
2822         int ai = root->type.find('[',i);
2823         if (ai>i) // function pointer array
2824         {
2825           root->args.prepend(root->type.right(root->type.length()-ai));
2826           root->type=root->type.left(ai);
2827         }
2828         else if (root->type.find(')',i)!=-1) // function ptr, not variable like "int (*bla)[10]"
2829         {
2830           root->type=root->type.left(root->type.length()-1);
2831           root->args.prepend(")");
2832           //printf("root->type=%s root->args=%s\n",root->type.data(),root->args.data());
2833         }
2834       }
2835       else if (root->type.find("typedef ")!=-1 && root->type.right(2)=="()") // typedef void (func)(int)
2836       {
2837         root->type=root->type.left(root->type.length()-1);
2838         root->args.prepend(")");
2839       }
2840     }
2841     
2842     QCString scope,name=removeRedundantWhiteSpace(root->name);
2843
2844     // find the scope of this variable 
2845     EntryNav *p = rootNav->parent();
2846     while ((p->section() & Entry::SCOPE_MASK))
2847     {
2848       QCString scopeName = p->name();
2849       if (!scopeName.isEmpty())
2850       {
2851         scope.prepend(scopeName);
2852         break;
2853       }
2854       p=p->parent();
2855     }
2856     
2857     MemberType mtype;
2858     QCString type=root->type.stripWhiteSpace();
2859     ClassDef *cd=0;
2860     bool isRelated=FALSE;
2861     bool isMemberOf=FALSE;
2862
2863     QCString classScope=stripAnonymousNamespaceScope(scope);
2864     classScope=stripTemplateSpecifiersFromScope(classScope,FALSE);
2865     QCString annScopePrefix=scope.left(scope.length()-classScope.length());
2866
2867     if (root->name.findRev("::")!=-1) 
2868     {
2869       if (root->type=="friend class" || root->type=="friend struct" || 
2870           root->type=="friend union")
2871       {
2872          cd=getClass(scope);
2873          if (cd)
2874          {
2875            addVariableToClass(rootNav,  // entry
2876                               cd,    // class to add member to
2877                               MemberType_Friend, // type of member
2878                               name, // name of the member
2879                               FALSE,  // from Anonymous scope
2880                               0,      // anonymous member
2881                               Public, // protection
2882                               Member  // related to a class
2883                              );
2884          }
2885       }
2886       goto nextMember;
2887                /* skip this member, because it is a 
2888                 * static variable definition (always?), which will be
2889                 * found in a class scope as well, but then we know the
2890                 * correct protection level, so only then it will be
2891                 * inserted in the correct list!
2892                 */
2893     }
2894
2895     if (type=="@") 
2896       mtype=MemberType_EnumValue;
2897     else if (type.left(8)=="typedef ") 
2898       mtype=MemberType_Typedef;
2899     else if (type.left(7)=="friend ")
2900       mtype=MemberType_Friend;
2901     else if (root->mtype==Property)
2902       mtype=MemberType_Property;
2903     else if (root->mtype==Event)
2904       mtype=MemberType_Event;
2905     else
2906       mtype=MemberType_Variable;
2907
2908     if (!root->relates.isEmpty()) // related variable
2909     {
2910       isRelated=TRUE;
2911       isMemberOf=(root->relatesType == MemberOf);
2912       if (getClass(root->relates)==0 && !scope.isEmpty())
2913         scope=mergeScopes(scope,root->relates);
2914       else 
2915         scope=root->relates;
2916     }
2917     
2918     cd=getClass(scope);
2919     if (cd==0 && classScope!=scope) cd=getClass(classScope);
2920     if (cd)
2921     {
2922       MemberDef *md=0;
2923
2924       // if cd is an anonymous (=tag less) scope we insert the member 
2925       // into a non-anonymous parent scope as well. This is needed to
2926       // be able to refer to it using \var or \fn
2927
2928       //int indentDepth=0;
2929       int si=scope.find('@');
2930       //int anonyScopes = 0;
2931       //bool added=FALSE;
2932       
2933       static bool inlineSimpleStructs = Config_getBool("INLINE_SIMPLE_STRUCTS");
2934       if (si!=-1 && !inlineSimpleStructs) // anonymous scope or type
2935       {
2936         QCString pScope;
2937         ClassDef *pcd=0;
2938         pScope = scope.left(QMAX(si-2,0)); // scope without tag less parts
2939         if (!pScope.isEmpty())
2940           pScope.prepend(annScopePrefix);
2941         else if (annScopePrefix.length()>2)
2942           pScope=annScopePrefix.left(annScopePrefix.length()-2);
2943         if (name.at(0)!='@')
2944         {
2945           if (!pScope.isEmpty() && (pcd=getClass(pScope)))
2946           {
2947             md=addVariableToClass(rootNav,  // entry
2948                                   pcd,   // class to add member to
2949                                   mtype, // member type
2950                                   name,  // member name
2951                                   TRUE,  // from anonymous scope
2952                                   0,     // from anonymous member
2953                                   root->protection,
2954                                   isMemberOf ? Foreign : isRelated ? Related : Member
2955                                  );
2956             //added=TRUE;
2957           }
2958           else // anonymous scope inside namespace or file => put variable in the global scope
2959           {
2960             if (mtype==MemberType_Variable)
2961             {
2962               md=addVariableToFile(rootNav,mtype,pScope,name,TRUE,0); 
2963             }
2964             //added=TRUE;
2965           }
2966         }
2967       }
2968
2969       //printf("name=`%s' scope=%s scope.right=%s\n",
2970       //                   name.data(),scope.data(),
2971       //                   scope.right(scope.length()-si).data());
2972       addVariableToClass(rootNav,   // entry
2973                          cd,     // class to add member to
2974                          mtype,  // member type
2975                          name,   // name of the member
2976                          FALSE,  // from anonymous scope
2977                          md,     // from anonymous member
2978                          root->protection, 
2979                          isMemberOf ? Foreign : isRelated ? Related : Member);
2980     }
2981     else if (!name.isEmpty()) // global variable
2982     {
2983       //printf("Inserting member in global scope %s!\n",scope.data());
2984       addVariableToFile(rootNav,mtype,scope,name,FALSE,/*0,*/0);
2985     }
2986
2987 nextMember:
2988     rootNav->releaseEntry();
2989 }
2990
2991 //----------------------------------------------------------------------
2992 // Searches the Entry tree for typedef documentation sections.
2993 // If found they are stored in their class or in the global list.
2994 static void buildTypedefList(EntryNav *rootNav)
2995 {
2996   //printf("buildVarList(%s)\n",rootNav->name().data());
2997   if (!rootNav->name().isEmpty() &&
2998       rootNav->section()==Entry::VARIABLE_SEC &&
2999       rootNav->type().find("typedef ")!=-1 // its a typedef
3000      ) 
3001   {
3002     addVariable(rootNav);
3003   }
3004   if (rootNav->children())
3005   {
3006     EntryNavListIterator eli(*rootNav->children());
3007     EntryNav *e;
3008     for (;(e=eli.current());++eli)
3009     {
3010       if (e->section()!=Entry::ENUM_SEC) 
3011       {
3012         buildTypedefList(e);
3013       }
3014     }
3015   }
3016 }
3017
3018 //----------------------------------------------------------------------
3019 // Searches the Entry tree for Variable documentation sections.
3020 // If found they are stored in their class or in the global list.
3021
3022 static void buildVarList(EntryNav *rootNav)
3023 {
3024   //printf("buildVarList(%s) section=%08x\n",rootNav->name().data(),rootNav->section());
3025   int isFuncPtr=-1;
3026   if (!rootNav->name().isEmpty() &&
3027       (rootNav->type().isEmpty() || g_compoundKeywordDict.find(rootNav->type())==0) &&
3028       (
3029        (rootNav->section()==Entry::VARIABLE_SEC    // it's a variable
3030        ) ||
3031        (rootNav->section()==Entry::FUNCTION_SEC && // or maybe a function pointer variable 
3032         (isFuncPtr=findFunctionPtr(rootNav->type(),rootNav->lang()))!=-1
3033        ) ||
3034        (rootNav->section()==Entry::FUNCTION_SEC && // class variable initialized by constructor
3035         isVarWithConstructor(rootNav)
3036        )
3037       ) 
3038      ) // documented variable
3039   {
3040     addVariable(rootNav,isFuncPtr);
3041   }
3042   if (rootNav->children())
3043   {
3044     EntryNavListIterator eli(*rootNav->children());
3045     EntryNav *e;
3046     for (;(e=eli.current());++eli)
3047     {
3048       if (e->section()!=Entry::ENUM_SEC) 
3049       {
3050         buildVarList(e);
3051       }
3052     }
3053   }
3054 }
3055
3056 //----------------------------------------------------------------------
3057 // Searches the Entry tree for Interface sections (UNO IDL only).
3058 // If found they are stored in their service or in the global list.
3059 //
3060
3061 static void addInterfaceOrServiceToServiceOrSingleton(
3062         EntryNav *const rootNav,
3063         ClassDef *const cd,
3064         QCString const& rname)
3065 {
3066   Entry *const root = rootNav->entry();
3067   FileDef *const fd = rootNav->fileDef();
3068   enum MemberType const type = (rootNav->section()==Entry::EXPORTED_INTERFACE_SEC)
3069       ? MemberType_Interface
3070       : MemberType_Service;
3071   MemberDef *const md = new MemberDef(
3072       root->fileName, root->startLine, root->startColumn, root->type, rname,
3073       "", "", root->protection, root->virt, root->stat, Member,
3074       type, 0, root->argList);
3075   md->setTagInfo(rootNav->tagInfo());
3076   md->setMemberClass(cd);
3077   md->setDocumentation(root->doc,root->docFile,root->docLine);
3078   md->setDocsForDefinition(false);
3079   md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
3080   md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
3081   md->setBodySegment(root->bodyLine,root->endBodyLine);
3082   md->setMemberSpecifiers(root->spec);
3083   md->setMemberGroupId(root->mGrpId);
3084   md->setTypeConstraints(root->typeConstr);
3085   md->setLanguage(root->lang);
3086   md->setBodyDef(fd);
3087   md->setFileDef(fd);
3088   md->addSectionsToDefinition(root->anchors);
3089   QCString const def = root->type + " " + rname;
3090   md->setDefinition(def);
3091   md->enableCallGraph(root->callGraph);
3092   md->enableCallerGraph(root->callerGraph);
3093
3094   Debug::print(Debug::Functions,0,
3095       "  Interface Member:\n"
3096       "    `%s' `%s' proto=%d\n"
3097       "    def=`%s'\n",
3098       root->type.data(),
3099       rname.data(),
3100       root->proto,
3101       def.data()
3102               );
3103
3104   // add member to the global list of all members
3105   MemberName *mn;
3106   if ((mn=Doxygen::memberNameSDict->find(rname)))
3107   {
3108     mn->append(md);
3109   }
3110   else
3111   {
3112     mn = new MemberName(rname);
3113     mn->append(md);
3114     Doxygen::memberNameSDict->append(rname,mn);
3115   }
3116
3117   // add member to the class cd
3118   cd->insertMember(md);
3119   // also add the member as a "base" (to get nicer diagrams)
3120   // "optional" interface/service get Protected which turns into dashed line
3121   BaseInfo base(rname,
3122           (root->spec & (Entry::Optional)) ? Protected : Public,Normal);
3123   findClassRelation(rootNav,cd,cd,&base,0,DocumentedOnly,true)
3124   || findClassRelation(rootNav,cd,cd,&base,0,Undocumented,true);
3125   // add file to list of used files
3126   cd->insertUsedFile(fd);
3127
3128   addMemberToGroups(root,md);
3129   rootNav->changeSection(Entry::EMPTY_SEC);
3130   md->setRefItems(root->sli);
3131 }
3132
3133 static void buildInterfaceAndServiceList(EntryNav *const rootNav)
3134 {
3135   if (rootNav->section()==Entry::EXPORTED_INTERFACE_SEC ||
3136       rootNav->section()==Entry::INCLUDED_SERVICE_SEC)
3137   {
3138     rootNav->loadEntry(g_storage);
3139     Entry *const root = rootNav->entry();
3140
3141     Debug::print(Debug::Functions,0,
3142                  "EXPORTED_INTERFACE_SEC:\n"
3143                  "  `%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",
3144                  root->type.data(),
3145                  rootNav->parent()->name().data(),
3146                  root->name.data(),
3147                  root->args.data(),
3148                  root->relates.data(),
3149                  root->relatesType,
3150                  root->fileName.data(),
3151                  root->startLine,
3152                  root->bodyLine,
3153                  root->tArgLists ? (int)root->tArgLists->count() : -1,
3154                  root->mGrpId,
3155                  root->spec,
3156                  root->proto,
3157                  root->docFile.data()
3158                 );
3159
3160     QCString const rname = removeRedundantWhiteSpace(root->name);
3161
3162     if (!rname.isEmpty())
3163     {
3164       QCString const scope = rootNav->parent()->name();
3165       ClassDef *const cd = getClass(scope);
3166       assert(cd);
3167       if (cd && ((ClassDef::Interface == cd->compoundType()) ||
3168                  (ClassDef::Service   == cd->compoundType()) ||
3169                  (ClassDef::Singleton == cd->compoundType())))
3170       {
3171         addInterfaceOrServiceToServiceOrSingleton(rootNav,cd,rname);
3172       }
3173       else
3174       {
3175         assert(false); // was checked by scanner.l
3176       }
3177     }
3178     else if (rname.isEmpty())
3179     {
3180       warn(root->fileName,root->startLine,
3181            "Illegal member name found.");
3182     }
3183
3184     rootNav->releaseEntry();
3185   }
3186   // can only have these in IDL anyway
3187   switch (rootNav->lang())
3188   {
3189     case SrcLangExt_Unknown: // fall through (root node always is Unknown)
3190     case SrcLangExt_IDL:
3191         RECURSE_ENTRYTREE(buildInterfaceAndServiceList,rootNav);
3192         break;
3193     default:
3194         return; // nothing to do here
3195   }
3196 }
3197
3198
3199 //----------------------------------------------------------------------
3200 // Searches the Entry tree for Function sections.
3201 // If found they are stored in their class or in the global list.
3202
3203 static void addMethodToClass(EntryNav *rootNav,ClassDef *cd,
3204                   const QCString &rname,bool isFriend)
3205 {
3206   Entry *root = rootNav->entry();
3207   FileDef *fd=rootNav->fileDef();
3208
3209   int l;
3210   static QRegExp re("([a-z_A-Z0-9: ]*[ &*]+[ ]*");
3211   int ts=root->type.find('<');
3212   int te=root->type.findRev('>');
3213   int i=re.match(root->type,0,&l);
3214   if (i!=-1 && ts!=-1 && ts<te && ts<i && i<te) // avoid changing A<int(int*)>, see bug 677315
3215   {
3216     i=-1;
3217   }
3218
3219   if (cd->getLanguage()==SrcLangExt_Cpp && // only C has pointers
3220       !root->type.isEmpty() && (root->spec&Entry::Alias)==0 && i!=-1) // function variable
3221   {
3222     root->args+=root->type.right(root->type.length()-i-l);
3223     root->type=root->type.left(i+l);
3224   }
3225
3226   QCString name=removeRedundantWhiteSpace(rname);
3227   if (name.left(2)=="::") name=name.right(name.length()-2);
3228
3229   MemberType mtype;
3230   if (isFriend)                 mtype=MemberType_Friend;
3231   else if (root->mtype==Signal) mtype=MemberType_Signal;
3232   else if (root->mtype==Slot)   mtype=MemberType_Slot;
3233   else if (root->mtype==DCOP)   mtype=MemberType_DCOP;
3234   else                          mtype=MemberType_Function;
3235
3236   // strip redundant template specifier for constructors
3237   if ((fd==0 || fd->getLanguage()==SrcLangExt_Cpp) &&
3238      name.left(9)!="operator " && (i=name.find('<'))!=-1 && name.find('>')!=-1)
3239   {
3240     name=name.left(i); 
3241   }
3242
3243   //printf("root->name=`%s; root->args=`%s' root->argList=`%s'\n", 
3244   //    root->name.data(),root->args.data(),argListToString(root->argList).data()
3245   //   );
3246
3247   // adding class member
3248   MemberDef *md=new MemberDef(
3249       root->fileName,root->startLine,root->startColumn,
3250       root->type,name,root->args,root->exception,
3251       root->protection,root->virt,
3252       root->stat && root->relatesType != MemberOf,
3253       root->relates.isEmpty() ? Member :
3254           root->relatesType == MemberOf ? Foreign : Related,
3255       mtype,root->tArgLists ? root->tArgLists->getLast() : 0,root->argList);
3256   md->setTagInfo(rootNav->tagInfo());
3257   md->setMemberClass(cd);
3258   md->setDocumentation(root->doc,root->docFile,root->docLine);
3259   md->setDocsForDefinition(!root->proto);
3260   md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
3261   md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
3262   md->setBodySegment(root->bodyLine,root->endBodyLine);
3263   md->setMemberSpecifiers(root->spec);
3264   md->setMemberGroupId(root->mGrpId);
3265   md->setTypeConstraints(root->typeConstr);
3266   md->setLanguage(root->lang);
3267   md->setId(root->id);
3268   md->setBodyDef(fd);
3269   md->setFileDef(fd);
3270   //md->setScopeTemplateArguments(root->tArgList);
3271   md->addSectionsToDefinition(root->anchors);
3272   QCString def;
3273   QCString qualScope = cd->qualifiedNameWithTemplateParameters();
3274   SrcLangExt lang = cd->getLanguage();
3275   QCString scopeSeparator=getLanguageSpecificSeparator(lang);
3276   if (scopeSeparator!="::")
3277   {
3278     qualScope = substitute(qualScope,"::",scopeSeparator);
3279   }
3280   if (lang==SrcLangExt_PHP)
3281   {
3282     // for PHP we use Class::method and Namespace\method
3283     scopeSeparator="::";
3284   }
3285   if (!root->relates.isEmpty() || isFriend || Config_getBool("HIDE_SCOPE_NAMES"))
3286   {
3287     if (!root->type.isEmpty())
3288     {
3289       if (root->argList)
3290       {
3291         def=root->type+" "+name;
3292       }
3293       else
3294       {
3295         def=root->type+" "+name+root->args;
3296       }
3297     }
3298     else
3299     {
3300       if (root->argList)
3301       {
3302         def=name;
3303       }
3304       else
3305       {
3306         def=name+root->args;
3307       }
3308     }
3309   }
3310   else
3311   {
3312     if (!root->type.isEmpty())
3313     {
3314       if (root->argList)
3315       {
3316         def=root->type+" "+qualScope+scopeSeparator+name;
3317       }
3318       else
3319       {
3320         def=root->type+" "+qualScope+scopeSeparator+name+root->args;
3321       }
3322     }
3323     else
3324     {
3325       if (root->argList)
3326       {
3327         def=qualScope+scopeSeparator+name;
3328       }
3329       else
3330       {
3331         def=qualScope+scopeSeparator+name+root->args;
3332       }
3333     }
3334   }
3335   if (def.left(7)=="friend ") def=def.right(def.length()-7);
3336   md->setDefinition(def);
3337   md->enableCallGraph(root->callGraph);
3338   md->enableCallerGraph(root->callerGraph);
3339
3340   Debug::print(Debug::Functions,0,
3341       "  Func Member:\n"
3342       "    `%s' `%s'::`%s' `%s' proto=%d\n"
3343       "    def=`%s'\n",
3344       root->type.data(),
3345       qualScope.data(),
3346       rname.data(),
3347       root->args.data(),
3348       root->proto,
3349       def.data()
3350               );
3351
3352   // add member to the global list of all members
3353   //printf("Adding member=%s class=%s\n",md->name().data(),cd->name().data());
3354   MemberName *mn;
3355   if ((mn=Doxygen::memberNameSDict->find(name)))
3356   {
3357     mn->append(md);
3358   }
3359   else
3360   {
3361     mn = new MemberName(name);
3362     mn->append(md);
3363     Doxygen::memberNameSDict->append(name,mn);
3364   }
3365
3366   // add member to the class cd
3367   cd->insertMember(md);
3368   // add file to list of used files
3369   cd->insertUsedFile(fd);
3370
3371   addMemberToGroups(root,md);
3372   rootNav->changeSection(Entry::EMPTY_SEC);
3373   md->setRefItems(root->sli);
3374 }
3375
3376
3377 static void buildFunctionList(EntryNav *rootNav)
3378 {
3379   if (rootNav->section()==Entry::FUNCTION_SEC)
3380   {
3381     rootNav->loadEntry(g_storage);
3382     Entry *root = rootNav->entry();
3383
3384     Debug::print(Debug::Functions,0,
3385                  "FUNCTION_SEC:\n"
3386                  "  `%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",
3387                  root->type.data(),
3388                  rootNav->parent()->name().data(),
3389                  root->name.data(),
3390                  root->args.data(),
3391                  root->relates.data(),
3392                  root->relatesType,
3393                  root->fileName.data(),
3394                  root->startLine,
3395                  root->bodyLine,
3396                  root->tArgLists ? (int)root->tArgLists->count() : -1,
3397                  root->mGrpId,
3398                  root->spec,
3399                  root->proto,
3400                  root->docFile.data()
3401                 );
3402
3403     bool isFriend=root->type.find("friend ")!=-1;
3404     QCString rname = removeRedundantWhiteSpace(root->name);
3405     //printf("rname=%s\n",rname.data());
3406
3407     QCString scope=rootNav->parent()->name(); //stripAnonymousNamespaceScope(root->parent->name);
3408     if (!rname.isEmpty() && scope.find('@')==-1)
3409     {
3410       ClassDef *cd=0;
3411       // check if this function's parent is a class
3412       scope=stripTemplateSpecifiersFromScope(scope,FALSE);
3413
3414       FileDef *rfd=rootNav->fileDef();
3415
3416       int memIndex=rname.findRev("::");
3417
3418       cd=getClass(scope);
3419       if (cd && scope+"::"==rname.left(scope.length()+2)) // found A::f inside A
3420       {
3421         // strip scope from name
3422         rname=rname.right(rname.length()-rootNav->parent()->name().length()-2); 
3423       }
3424
3425       NamespaceDef *nd = 0;
3426       bool isMember=FALSE;
3427       if (memIndex!=-1)
3428       {
3429         int ts=rname.find('<');
3430         int te=rname.find('>');
3431         if (memIndex>0 && (ts==-1 || te==-1))
3432         {
3433           // note: the following code was replaced by inMember=TRUE to deal with a 
3434           // function rname='X::foo' of class X inside a namespace also called X...
3435           // bug id 548175
3436           //nd = Doxygen::namespaceSDict->find(rname.left(memIndex));
3437           //isMember = nd==0;
3438           //if (nd)
3439           //{
3440           //  // strip namespace scope from name
3441           //  scope=rname.left(memIndex);
3442           //  rname=rname.right(rname.length()-memIndex-2);
3443           //}
3444           isMember = TRUE;
3445         }
3446         else
3447         {
3448           isMember=memIndex<ts || memIndex>te;
3449         }
3450       }
3451
3452       static QRegExp re("([a-z_A-Z0-9: ]*[ &*]+[ ]*");
3453       int ts=root->type.find('<');
3454       int te=root->type.findRev('>');
3455       int ti;
3456       if (!rootNav->parent()->name().isEmpty() &&
3457           (rootNav->parent()->section() & Entry::COMPOUND_MASK) && 
3458           cd &&
3459           // do some fuzzy things to exclude function pointers 
3460           (root->type.isEmpty() || 
3461            ((ti=root->type.find(re,0))==-1 ||      // type does not contain ..(..* 
3462             (ts!=-1 && ts<te && ts<ti && ti<te) || // outside of < ... >
3463            root->args.find(")[")!=-1) ||           // and args not )[.. -> function pointer
3464            root->type.find(")(")!=-1 || root->type.find("operator")!=-1 || // type contains ..)(.. and not "operator"
3465            cd->getLanguage()!=SrcLangExt_Cpp                               // language other than C
3466           )
3467          )
3468       {
3469         Debug::print(Debug::Functions,0,"  --> member %s of class %s!\n",
3470             rname.data(),cd->name().data());
3471         addMethodToClass(rootNav,cd,rname,isFriend);
3472       }
3473       else if (!((rootNav->parent()->section() & Entry::COMPOUND_MASK) 
3474                  || rootNav->parent()->section()==Entry::OBJCIMPL_SEC
3475                 ) &&
3476                !isMember &&
3477                (root->relates.isEmpty() || root->relatesType == Duplicate) &&
3478                root->type.left(7)!="extern " && root->type.left(8)!="typedef " 
3479               )
3480       // no member => unrelated function 
3481       {
3482         /* check the uniqueness of the function name in the file.
3483          * A file could contain a function prototype and a function definition
3484          * or even multiple function prototypes.
3485          */
3486         bool found=FALSE;
3487         MemberName *mn;
3488         MemberDef *md=0;
3489         if ((mn=Doxygen::functionNameSDict->find(rname)))
3490         {
3491           Debug::print(Debug::Functions,0,"  --> function %s already found!\n",rname.data());
3492           MemberNameIterator mni(*mn);
3493           for (mni.toFirst();(!found && (md=mni.current()));++mni)
3494           {
3495             NamespaceDef *mnd = md->getNamespaceDef();
3496             NamespaceDef *rnd = 0;
3497             //printf("root namespace=%s\n",rootNav->parent()->name().data());
3498             QCString fullScope = scope;
3499             QCString parentScope = rootNav->parent()->name();
3500             if (!parentScope.isEmpty() && !leftScopeMatch(parentScope,scope))
3501             {
3502               if (!scope.isEmpty()) fullScope.prepend("::");
3503               fullScope.prepend(parentScope);
3504             }
3505             //printf("fullScope=%s\n",fullScope.data());
3506             rnd = getResolvedNamespace(fullScope);
3507             FileDef *mfd = md->getFileDef();
3508             QCString nsName,rnsName;
3509             if (mnd)  nsName = mnd->name().copy();
3510             if (rnd) rnsName = rnd->name().copy();
3511             //printf("matching arguments for %s%s %s%s\n",
3512             //    md->name().data(),md->argsString(),rname.data(),argListToString(root->argList).data());
3513             ArgumentList *mdAl = md->argumentList();
3514             ArgumentList *mdTempl = md->templateArguments();
3515
3516             // in case of template functions, we need to check if the
3517             // functions have the same number of template parameters
3518             bool sameNumTemplateArgs = TRUE;
3519             bool matchingReturnTypes = TRUE;
3520             if (mdTempl!=0 && root->tArgLists)
3521             {
3522               if (mdTempl->count()!=root->tArgLists->getLast()->count())
3523               {
3524                 sameNumTemplateArgs = FALSE;
3525               }
3526               if (md->typeString()!=removeRedundantWhiteSpace(root->type))
3527               {
3528                 matchingReturnTypes = FALSE;
3529               }
3530             }
3531
3532             bool staticsInDifferentFiles = 
3533                     root->stat && md->isStatic() && root->fileName!=md->getDefFileName();
3534
3535             if (
3536                 matchArguments2(md->getOuterScope(),mfd,mdAl,
3537                                 rnd ? rnd : Doxygen::globalScope,rfd,root->argList,
3538                                 FALSE) &&
3539                 sameNumTemplateArgs && 
3540                 matchingReturnTypes &&
3541                 !staticsInDifferentFiles
3542                )
3543             {
3544               GroupDef *gd=0;
3545               if (root->groups->getFirst()!=0)
3546               {
3547                 gd = Doxygen::groupSDict->find(root->groups->getFirst()->groupname.data());
3548               }
3549               //printf("match!\n");
3550               //printf("mnd=%p rnd=%p nsName=%s rnsName=%s\n",mnd,rnd,nsName.data(),rnsName.data());
3551               // see if we need to create a new member
3552               found=(mnd && rnd && nsName==rnsName) ||   // members are in the same namespace
3553                     ((mnd==0 && rnd==0 && mfd!=0 &&       // no external reference and
3554                       mfd->absFilePath()==root->fileName // prototype in the same file
3555                      )
3556                     );
3557               // otherwise, allow a duplicate global member with the same argument list
3558               if (!found && gd && gd==md->getGroupDef() && nsName==rnsName)
3559               {
3560                 // member is already in the group, so we don't want to add it again.
3561                 found=TRUE;
3562               }
3563
3564               //printf("combining function with prototype found=%d in namespace %s\n",
3565               //    found,nsName.data());
3566
3567               if (found)
3568               {
3569                 // merge argument lists
3570                 mergeArguments(mdAl,root->argList,!root->doc.isEmpty());
3571                 // merge documentation
3572                 if (md->documentation().isEmpty() && !root->doc.isEmpty())
3573                 {
3574                   ArgumentList *argList = new ArgumentList;
3575                   stringToArgumentList(root->args,argList);
3576                   if (root->proto)
3577                   {
3578                     //printf("setDeclArgumentList to %p\n",argList);
3579                     md->setDeclArgumentList(argList);
3580                   }
3581                   else
3582                   {
3583                     md->setArgumentList(argList);
3584                   }
3585                 }
3586
3587                 md->setDocumentation(root->doc,root->docFile,root->docLine);
3588                 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
3589                 md->setDocsForDefinition(!root->proto);
3590                 if (md->getStartBodyLine()==-1 && root->bodyLine!=-1)
3591                 {
3592                   md->setBodySegment(root->bodyLine,root->endBodyLine);
3593                   md->setBodyDef(rfd);
3594                 }
3595
3596                 if (md->briefDescription().isEmpty() && !root->brief.isEmpty())
3597                 {
3598                   md->setArgsString(root->args);
3599                 }
3600                 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
3601
3602                 md->addSectionsToDefinition(root->anchors);
3603
3604                 md->enableCallGraph(md->hasCallGraph() || root->callGraph);
3605                 md->enableCallerGraph(md->hasCallerGraph() || root->callerGraph);
3606
3607                 // merge ingroup specifiers
3608                 if (md->getGroupDef()==0 && root->groups->getFirst()!=0)
3609                 {
3610                   addMemberToGroups(root,md);
3611                 }
3612                 else if (md->getGroupDef()!=0 && root->groups->count()==0)
3613                 {
3614                   //printf("existing member is grouped, new member not\n");
3615                   root->groups->append(new Grouping(md->getGroupDef()->name(), md->getGroupPri()));
3616                 }
3617                 else if (md->getGroupDef()!=0 && root->groups->getFirst()!=0)
3618                 {
3619                   //printf("both members are grouped\n");
3620                 }
3621
3622                 // if md is a declaration and root is the corresponding
3623                 // definition, then turn md into a definition.
3624                 if (md->isPrototype() && !root->proto)
3625                 {
3626                   md->setPrototype(FALSE);
3627                 }
3628               }
3629             }
3630           }
3631         }
3632         if (!found) /* global function is unique with respect to the file */
3633         {
3634           Debug::print(Debug::Functions,0,"  --> new function %s found!\n",rname.data());
3635           //printf("New function type=`%s' name=`%s' args=`%s' bodyLine=%d\n",
3636           //       root->type.data(),rname.data(),root->args.data(),root->bodyLine);
3637
3638           // new global function
3639           ArgumentList *tArgList = root->tArgLists ? root->tArgLists->getLast() : 0;
3640           QCString name=removeRedundantWhiteSpace(rname);
3641           md=new MemberDef(
3642               root->fileName,root->startLine,root->startColumn,
3643               root->type,name,root->args,root->exception,
3644               root->protection,root->virt,root->stat,Member,
3645               MemberType_Function,tArgList,root->argList);
3646
3647           md->setTagInfo(rootNav->tagInfo());
3648           md->setLanguage(root->lang);
3649           md->setId(root->id);
3650           //md->setDefFile(root->fileName);
3651           //md->setDefLine(root->startLine);
3652           md->setDocumentation(root->doc,root->docFile,root->docLine);
3653           md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
3654           md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
3655           md->setPrototype(root->proto);
3656           md->setDocsForDefinition(!root->proto);
3657           md->setTypeConstraints(root->typeConstr);
3658           //md->setBody(root->body);
3659           md->setBodySegment(root->bodyLine,root->endBodyLine);
3660           FileDef *fd=rootNav->fileDef();
3661           md->setBodyDef(fd);
3662           md->addSectionsToDefinition(root->anchors);
3663           md->setMemberSpecifiers(root->spec);
3664           md->setMemberGroupId(root->mGrpId);
3665
3666           // see if the function is inside a namespace that was not part of
3667           // the name already (in that case nd should be non-zero already)
3668           if (nd==0 && rootNav->parent()->section() == Entry::NAMESPACE_SEC )
3669           {
3670             //QCString nscope=removeAnonymousScopes(rootNav->parent()->name());
3671             QCString nscope=rootNav->parent()->name();
3672             if (!nscope.isEmpty())
3673             {
3674               nd = getResolvedNamespace(nscope);
3675             }
3676           }
3677
3678           if (!scope.isEmpty())
3679           {
3680             QCString sep = getLanguageSpecificSeparator(root->lang);
3681             if (sep!="::")
3682             {
3683               scope = substitute(scope,"::",sep);
3684             }
3685             scope+=sep;
3686           }
3687
3688           QCString def;
3689           if (!root->type.isEmpty())
3690           {
3691             if (root->argList)
3692             {
3693               def=root->type+" "+scope+name;
3694             }
3695             else
3696             {
3697               def=root->type+" "+scope+name+root->args;
3698             }
3699           }
3700           else
3701           {
3702             if (root->argList)
3703             {
3704               def=scope+name.copy();
3705             }
3706             else
3707             {
3708               def=scope+name+root->args;
3709             }
3710           }
3711           Debug::print(Debug::Functions,0,
3712                      "  Global Function:\n"
3713                      "    `%s' `%s'::`%s' `%s' proto=%d\n"
3714                      "    def=`%s'\n",
3715                      root->type.data(),
3716                      rootNav->parent()->name().data(),
3717                      rname.data(),
3718                      root->args.data(),
3719                      root->proto,
3720                      def.data()
3721                     );
3722           md->setDefinition(def);
3723           md->enableCallGraph(root->callGraph);
3724           md->enableCallerGraph(root->callerGraph);
3725           //if (root->mGrpId!=-1) 
3726           //{
3727           //  md->setMemberGroup(memberGroupDict[root->mGrpId]);
3728           //}
3729
3730           md->setRefItems(root->sli);
3731           if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@')
3732           {
3733             // add member to namespace
3734             md->setNamespace(nd);
3735             nd->insertMember(md); 
3736           }
3737           if (fd)
3738           {
3739             // add member to the file (we do this even if we have already
3740             // inserted it into the namespace)
3741             md->setFileDef(fd); 
3742             fd->insertMember(md);
3743           }
3744
3745           // add member to the list of file members
3746           //printf("Adding member=%s\n",md->name().data());
3747           MemberName *mn;
3748           if ((mn=Doxygen::functionNameSDict->find(name)))
3749           {
3750             mn->append(md);
3751           }
3752           else 
3753           {
3754             mn = new MemberName(name);
3755             mn->append(md);
3756             Doxygen::functionNameSDict->append(name,mn);
3757           }
3758           addMemberToGroups(root,md);
3759           if (root->relatesType == Simple) // if this is a relatesalso command,
3760                                            // allow find Member to pick it up
3761           {
3762             rootNav->changeSection(Entry::EMPTY_SEC); // Otherwise we have finished 
3763                                                       // with this entry.
3764
3765           }
3766         }
3767         else
3768         {
3769           FileDef *fd=rootNav->fileDef();
3770           if (fd)
3771           {
3772             // add member to the file (we do this even if we have already
3773             // inserted it into the namespace)
3774             fd->insertMember(md);
3775           }
3776         }
3777
3778         //printf("unrelated function %d `%s' `%s' `%s'\n",
3779         //    root->parent->section,root->type.data(),rname.data(),root->args.data());
3780       }
3781       else
3782       {
3783           Debug::print(Debug::Functions,0,"  --> %s not processed!\n",rname.data());
3784       }
3785     }
3786     else if (rname.isEmpty())
3787     {
3788         warn(root->fileName,root->startLine,
3789              "Illegal member name found."
3790             );
3791     }
3792
3793     rootNav->releaseEntry();
3794   }
3795   RECURSE_ENTRYTREE(buildFunctionList,rootNav);
3796 }
3797
3798 //----------------------------------------------------------------------
3799
3800 static void findFriends()
3801 {
3802   //printf("findFriends()\n");
3803   MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict);
3804   MemberName *fn;
3805   for (;(fn=fnli.current());++fnli) // for each global function name
3806   {
3807     //printf("Function name=`%s'\n",fn->memberName());
3808     MemberName *mn;
3809     if ((mn=Doxygen::memberNameSDict->find(fn->memberName())))
3810     { // there are members with the same name
3811       //printf("Function name is also a member name\n");
3812       MemberNameIterator fni(*fn);
3813       MemberDef *fmd;
3814       for (;(fmd=fni.current());++fni) // for each function with that name
3815       {
3816         MemberNameIterator mni(*mn);
3817         MemberDef *mmd;
3818         for (;(mmd=mni.current());++mni) // for each member with that name
3819         {
3820           //printf("Checking for matching arguments 
3821           //        mmd->isRelated()=%d mmd->isFriend()=%d mmd->isFunction()=%d\n",
3822           //    mmd->isRelated(),mmd->isFriend(),mmd->isFunction());
3823           ArgumentList *mmdAl = mmd->argumentList();
3824           ArgumentList *fmdAl = fmd->argumentList();
3825           if ((mmd->isFriend() || (mmd->isRelated() && mmd->isFunction())) &&
3826               matchArguments2(mmd->getOuterScope(), mmd->getFileDef(), mmdAl,
3827                               fmd->getOuterScope(), fmd->getFileDef(), fmdAl,
3828                               TRUE
3829                              )
3830                              
3831              ) // if the member is related and the arguments match then the 
3832                // function is actually a friend.
3833           {
3834             mergeArguments(mmdAl,fmdAl);
3835             if (!fmd->documentation().isEmpty())
3836             {
3837               mmd->setDocumentation(fmd->documentation(),fmd->docFile(),fmd->docLine());
3838             }
3839             else if (!mmd->documentation().isEmpty())
3840             {
3841               fmd->setDocumentation(mmd->documentation(),mmd->docFile(),mmd->docLine());
3842             }
3843             if (mmd->briefDescription().isEmpty() && !fmd->briefDescription().isEmpty())
3844             {
3845               mmd->setBriefDescription(fmd->briefDescription(),fmd->briefFile(),fmd->briefLine());
3846             }
3847             else if (!mmd->briefDescription().isEmpty() && !fmd->briefDescription().isEmpty())
3848             {
3849               fmd->setBriefDescription(mmd->briefDescription(),mmd->briefFile(),mmd->briefLine());
3850             }
3851             if (!fmd->inbodyDocumentation().isEmpty())
3852             {
3853               mmd->setInbodyDocumentation(fmd->inbodyDocumentation(),fmd->inbodyFile(),fmd->inbodyLine());
3854             }
3855             else if (!mmd->inbodyDocumentation().isEmpty())
3856             {
3857               fmd->setInbodyDocumentation(mmd->inbodyDocumentation(),mmd->inbodyFile(),mmd->inbodyLine());
3858             }
3859             //printf("body mmd %d fmd %d\n",mmd->getStartBodyLine(),fmd->getStartBodyLine());
3860             if (mmd->getStartBodyLine()==-1 && fmd->getStartBodyLine()!=-1)
3861             {
3862               mmd->setBodySegment(fmd->getStartBodyLine(),fmd->getEndBodyLine());
3863               mmd->setBodyDef(fmd->getBodyDef());
3864               //mmd->setBodyMember(fmd);
3865             }
3866             else if (mmd->getStartBodyLine()!=-1 && fmd->getStartBodyLine()==-1)
3867             {
3868               fmd->setBodySegment(mmd->getStartBodyLine(),mmd->getEndBodyLine());
3869               fmd->setBodyDef(mmd->getBodyDef());
3870               //fmd->setBodyMember(mmd);
3871             }
3872             mmd->setDocsForDefinition(fmd->isDocsForDefinition());
3873
3874             mmd->enableCallGraph(mmd->hasCallGraph() || fmd->hasCallGraph());
3875             mmd->enableCallerGraph(mmd->hasCallerGraph() || fmd->hasCallerGraph());
3876             fmd->enableCallGraph(mmd->hasCallGraph() || fmd->hasCallGraph());
3877             fmd->enableCallerGraph(mmd->hasCallerGraph() || fmd->hasCallerGraph());
3878           }
3879         }
3880       }
3881     }
3882   }
3883 }
3884
3885 //----------------------------------------------------------------------
3886
3887 static void transferFunctionDocumentation()
3888 {
3889   //printf("---- transferFunctionDocumentation()\n");
3890
3891   // find matching function declaration and definitions.
3892   MemberNameSDict::Iterator mnli(*Doxygen::functionNameSDict);
3893   MemberName *mn;
3894   for (;(mn=mnli.current());++mnli)
3895   {
3896     //printf("memberName=%s count=%d\n",mn->memberName(),mn->count());
3897     MemberDef *mdef=0,*mdec=0;
3898     MemberNameIterator mni1(*mn);
3899     /* find a matching function declaration and definition for this function */
3900     for (;(mdec=mni1.current());++mni1)
3901     {
3902       if (mdec->isPrototype() ||
3903           (mdec->isVariable() && mdec->isExternal()) 
3904          )
3905       {
3906         MemberNameIterator mni2(*mn);
3907         for (;(mdef=mni2.current());++mni2)
3908         {
3909           combineDeclarationAndDefinition(mdec,mdef);
3910         }
3911       }
3912     }
3913   }
3914 }
3915
3916 //----------------------------------------------------------------------
3917
3918 static void transferFunctionReferences()
3919 {
3920   MemberNameSDict::Iterator mnli(*Doxygen::functionNameSDict);
3921   MemberName *mn;
3922   for (;(mn=mnli.current());++mnli)
3923   {
3924     MemberDef *md,*mdef=0,*mdec=0;
3925     MemberNameIterator mni(*mn);
3926     /* find a matching function declaration and definition for this function */
3927     for (;(md=mni.current());++mni)
3928     {
3929       if (md->isPrototype()) 
3930         mdec=md;
3931       else if (md->isVariable() && md->isExternal()) 
3932         mdec=md;
3933       
3934       if (md->isFunction() && !md->isStatic() && !md->isPrototype()) 
3935         mdef=md;
3936       else if (md->isVariable() && !md->isExternal() && !md->isStatic())
3937         mdef=md;
3938     }
3939     if (mdef && mdec)
3940     {
3941       ArgumentList *mdefAl = mdef->argumentList();
3942       ArgumentList *mdecAl = mdec->argumentList();
3943       if (
3944           matchArguments2(mdef->getOuterScope(),mdef->getFileDef(),mdefAl,
3945                           mdec->getOuterScope(),mdec->getFileDef(),mdecAl,
3946                           TRUE
3947             )
3948          ) /* match found */
3949       {
3950         MemberSDict *defDict = mdef->getReferencesMembers();
3951         MemberSDict *decDict = mdec->getReferencesMembers();
3952         if (defDict!=0)
3953         {
3954           MemberSDict::IteratorDict msdi(*defDict);
3955           MemberDef *rmd;
3956           for (msdi.toFirst();(rmd=msdi.current());++msdi)
3957           {
3958             if (decDict==0 || decDict->find(rmd->name())==0)
3959             {
3960               mdec->addSourceReferences(rmd);
3961             }
3962           }
3963         }
3964         if (decDict!=0)
3965         {
3966           MemberSDict::IteratorDict msdi(*decDict);
3967           MemberDef *rmd;
3968           for (msdi.toFirst();(rmd=msdi.current());++msdi)
3969           {
3970             if (defDict==0 || defDict->find(rmd->name())==0)
3971             {
3972               mdef->addSourceReferences(rmd);
3973             }
3974           }
3975         }
3976
3977         defDict = mdef->getReferencedByMembers();
3978         decDict = mdec->getReferencedByMembers();
3979         if (defDict!=0)
3980         {
3981           MemberSDict::IteratorDict msdi(*defDict);
3982           MemberDef *rmd;
3983           for (msdi.toFirst();(rmd=msdi.current());++msdi)
3984           {
3985             if (decDict==0 || decDict->find(rmd->name())==0)
3986             {
3987               mdec->addSourceReferencedBy(rmd);
3988             }
3989           }
3990         }
3991         if (decDict!=0)
3992         {
3993           MemberSDict::IteratorDict msdi(*decDict);
3994           MemberDef *rmd;
3995           for (msdi.toFirst();(rmd=msdi.current());++msdi)
3996           {
3997             if (defDict==0 || defDict->find(rmd->name())==0)
3998             {
3999               mdef->addSourceReferencedBy(rmd);
4000             }
4001           }
4002         }
4003       }
4004     }
4005   }
4006 }
4007
4008 //----------------------------------------------------------------------
4009
4010 static void transferRelatedFunctionDocumentation()
4011 {
4012   // find match between function declaration and definition for 
4013   // related functions
4014   MemberNameSDict::Iterator mnli(*Doxygen::functionNameSDict);
4015   MemberName *mn;
4016   for (mnli.toFirst();(mn=mnli.current());++mnli)
4017   {
4018     MemberDef *md;
4019     MemberNameIterator mni(*mn);
4020     /* find a matching function declaration and definition for this function */
4021     for (mni.toFirst();(md=mni.current());++mni) // for each global function
4022     {
4023       //printf("  Function `%s'\n",md->name().data());
4024       MemberName *rmn;
4025       if ((rmn=Doxygen::memberNameSDict->find(md->name()))) // check if there is a member with the same name
4026       {
4027         //printf("  Member name found\n");
4028         MemberDef *rmd;
4029         MemberNameIterator rmni(*rmn);
4030         for (rmni.toFirst();(rmd=rmni.current());++rmni) // for each member with the same name
4031         {
4032           ArgumentList *mdAl = md->argumentList();
4033           ArgumentList *rmdAl = rmd->argumentList();
4034           //printf("  Member found: related=`%d'\n",rmd->isRelated());
4035           if ((rmd->isRelated() || rmd->isForeign()) && // related function
4036               matchArguments2( md->getOuterScope(), md->getFileDef(), mdAl,
4037                               rmd->getOuterScope(),rmd->getFileDef(),rmdAl,
4038                               TRUE
4039                              )
4040              )
4041           {
4042             //printf("  Found related member `%s'\n",md->name().data());
4043             if (rmd->relatedAlso())
4044               md->setRelatedAlso(rmd->relatedAlso());
4045             else if (rmd->isForeign())
4046               md->makeForeign();
4047             else
4048               md->makeRelated();
4049           } 
4050         }
4051       } 
4052     }
4053   }
4054 }
4055
4056 //----------------------------------------------------------------------
4057
4058 /*! make a dictionary of all template arguments of class cd
4059  * that are part of the base class name. 
4060  * Example: A template class A with template arguments <R,S,T> 
4061  * that inherits from B<T,T,S> will have T and S in the dictionary.
4062  */
4063 static QDict<int> *getTemplateArgumentsInName(ArgumentList *templateArguments,const QCString &name)
4064 {
4065   QDict<int> *templateNames = new QDict<int>(17);
4066   templateNames->setAutoDelete(TRUE);
4067   static QRegExp re("[a-z_A-Z][a-z_A-Z0-9:]*");
4068   if (templateArguments)
4069   {
4070     ArgumentListIterator ali(*templateArguments);
4071     Argument *arg;
4072     int count=0;
4073     for (ali.toFirst();(arg=ali.current());++ali,count++)
4074     {
4075       int i,p=0,l;
4076       while ((i=re.match(name,p,&l))!=-1)
4077       {
4078         QCString n = name.mid(i,l);
4079         if (n==arg->name)
4080         {
4081           if (templateNames->find(n)==0)
4082           {
4083             templateNames->insert(n,new int(count));
4084           }
4085         }
4086         p=i+l;
4087       }
4088     }
4089   }
4090   return templateNames;
4091 }
4092
4093 /*! Searches a class from within \a context and \a cd and returns its
4094  *  definition if found (otherwise 0 is returned).
4095  */
4096 static ClassDef *findClassWithinClassContext(Definition *context,ClassDef *cd,const QCString &name)
4097 {
4098   FileDef *fd=cd->getFileDef();
4099   ClassDef *result=0;
4100   if (context && cd!=context)
4101   {
4102     result = getResolvedClass(context,0,name,0,0,TRUE,TRUE);
4103   }
4104   if (result==0)
4105   {
4106     result = getResolvedClass(cd,fd,name,0,0,TRUE,TRUE);
4107   }
4108   if (result==0) // try direct class, needed for namespaced classes imported via tag files (see bug624095)
4109   {
4110     result = getClass(name);
4111   }
4112   if (result==0 && cd && cd->getLanguage()==SrcLangExt_CSharp && name.find('<')!=-1)
4113   {
4114     result = Doxygen::genericsDict->find(name);
4115   }
4116   //printf("** Trying to find %s within context %s class %s result=%s lookup=%p\n",
4117   //       name.data(),
4118   //       context ? context->name().data() : "<none>",
4119   //       cd      ? cd->name().data()      : "<none>",
4120   //       result  ? result->name().data()  : "<none>",
4121   //       Doxygen::classSDict->find(name)
4122   //      );
4123   return result;
4124 }
4125
4126
4127 static void findUsedClassesForClass(EntryNav *rootNav,
4128                            Definition *context,
4129                            ClassDef *masterCd,
4130                            ClassDef *instanceCd,
4131                            bool isArtificial,
4132                            ArgumentList *actualArgs=0,
4133                            QDict<int> *templateNames=0
4134                            )
4135 {
4136   masterCd->visited=TRUE;
4137   ArgumentList *formalArgs = masterCd->templateArguments();
4138   if (masterCd->memberNameInfoSDict())
4139   {
4140     MemberNameInfoSDict::Iterator mnili(*masterCd->memberNameInfoSDict());
4141     MemberNameInfo *mni;
4142     for (;(mni=mnili.current());++mnili)
4143     {
4144       MemberNameInfoIterator mnii(*mni);
4145       MemberInfo *mi;
4146       for (mnii.toFirst();(mi=mnii.current());++mnii)
4147       {
4148         MemberDef *md=mi->memberDef;
4149         if (md->isVariable() || md->isObjCProperty()) // for each member variable in this class
4150         {
4151           //printf("    Found variable %s in class %s\n",md->name().data(),masterCd->name().data());
4152           QCString type = normalizeNonTemplateArgumentsInString(md->typeString(),masterCd,formalArgs);
4153           QCString typedefValue = resolveTypeDef(masterCd,type);
4154           if (!typedefValue.isEmpty())
4155           {
4156             type = typedefValue;
4157           }
4158           int pos=0;
4159           QCString usedClassName;
4160           QCString templSpec;
4161           bool found=FALSE;
4162           // the type can contain template variables, replace them if present
4163           if (actualArgs)
4164           {
4165             type = substituteTemplateArgumentsInString(type,formalArgs,actualArgs);
4166           }
4167
4168           //printf("      template substitution gives=%s\n",type.data());
4169           while (!found && extractClassNameFromType(type,pos,usedClassName,templSpec,rootNav->lang())!=-1)
4170           {
4171             // find the type (if any) that matches usedClassName
4172             ClassDef *typeCd = getResolvedClass(masterCd,
4173                 masterCd->getFileDef(),
4174                 usedClassName,
4175                 0,0,
4176                 FALSE,TRUE
4177                 );
4178             //printf("====>  usedClassName=%s -> typeCd=%s\n",
4179             //     usedClassName.data(),typeCd?typeCd->name().data():"<none>");
4180             if (typeCd)
4181             {
4182               usedClassName = typeCd->name();
4183             }
4184
4185             int sp=usedClassName.find('<');
4186             if (sp==-1) sp=0;
4187             int si=usedClassName.findRev("::",sp);
4188             if (si!=-1)
4189             {
4190               // replace any namespace aliases
4191               replaceNamespaceAliases(usedClassName,si);
4192             }
4193             // add any template arguments to the class
4194             QCString usedName = removeRedundantWhiteSpace(usedClassName+templSpec);
4195             //printf("    usedName=%s\n",usedName.data());
4196
4197             bool delTempNames=FALSE;
4198             if (templateNames==0)
4199             {
4200               templateNames = getTemplateArgumentsInName(formalArgs,usedName);
4201               delTempNames=TRUE;
4202             }
4203             BaseInfo bi(usedName,Public,Normal);
4204             findClassRelation(rootNav,context,instanceCd,&bi,templateNames,TemplateInstances,isArtificial);
4205
4206             if (masterCd->templateArguments())
4207             {
4208               ArgumentListIterator ali(*masterCd->templateArguments());
4209               Argument *arg;
4210               int count=0;
4211               for (ali.toFirst();(arg=ali.current());++ali,++count)
4212               {
4213                 if (arg->name==usedName) // type is a template argument
4214                 {
4215                   found=TRUE;
4216                   Debug::print(Debug::Classes,0,"    New used class `%s'\n", usedName.data());
4217
4218                   ClassDef *usedCd = Doxygen::hiddenClasses->find(usedName);
4219                   if (usedCd==0)
4220                   {
4221                     usedCd = new ClassDef(
4222                         masterCd->getDefFileName(),masterCd->getDefLine(),
4223                         masterCd->getDefColumn(),
4224                         usedName,
4225                         ClassDef::Class);
4226                     //printf("making %s a template argument!!!\n",usedCd->name().data());
4227                     usedCd->makeTemplateArgument();
4228                     usedCd->setUsedOnly(TRUE);
4229                     usedCd->setLanguage(masterCd->getLanguage());
4230                     Doxygen::hiddenClasses->append(usedName,usedCd);
4231                   }
4232                   if (usedCd)
4233                   {
4234                     if (isArtificial) usedCd->setArtificial(TRUE);
4235                     Debug::print(Debug::Classes,0,"      Adding used class `%s' (1)\n", usedCd->name().data());
4236                     instanceCd->addUsedClass(usedCd,md->name(),md->protection());
4237                     usedCd->addUsedByClass(instanceCd,md->name(),md->protection());
4238                   }
4239                 }
4240               }
4241             }
4242
4243             if (!found)
4244             {
4245               ClassDef *usedCd=findClassWithinClassContext(context,masterCd,usedName);
4246               //printf("Looking for used class %s: result=%s master=%s\n",
4247               //    usedName.data(),usedCd?usedCd->name().data():"<none>",masterCd?masterCd->name().data():"<none>");
4248
4249               if (usedCd) 
4250               {
4251                 found=TRUE;
4252                 Debug::print(Debug::Classes,0,"    Adding used class `%s' (2)\n", usedCd->name().data());
4253                 instanceCd->addUsedClass(usedCd,md->name(),md->protection()); // class exists 
4254                 usedCd->addUsedByClass(instanceCd,md->name(),md->protection());
4255               }
4256             }
4257             if (delTempNames)
4258             {
4259               delete templateNames;
4260               templateNames=0;
4261             }
4262           }
4263           if (!found && !type.isEmpty()) // used class is not documented in any scope
4264           {
4265             ClassDef *usedCd = Doxygen::hiddenClasses->find(type);
4266             if (usedCd==0 && !Config_getBool("HIDE_UNDOC_RELATIONS"))
4267             {
4268               if (type.right(2)=="(*" || type.right(2)=="(^") // type is a function pointer
4269               {
4270                 type+=md->argsString();
4271               }
4272               Debug::print(Debug::Classes,0,"  New undocumented used class `%s'\n", type.data());
4273               usedCd = new ClassDef(
4274                   masterCd->getDefFileName(),masterCd->getDefLine(),
4275                   masterCd->getDefColumn(),
4276                   type,ClassDef::Class);
4277               usedCd->setUsedOnly(TRUE);
4278               usedCd->setLanguage(masterCd->getLanguage());
4279               Doxygen::hiddenClasses->append(type,usedCd);
4280             }
4281             if (usedCd)
4282             {
4283               if (isArtificial) usedCd->setArtificial(TRUE);
4284               Debug::print(Debug::Classes,0,"    Adding used class `%s' (3)\n", usedCd->name().data());
4285               instanceCd->addUsedClass(usedCd,md->name(),md->protection()); 
4286               usedCd->addUsedByClass(instanceCd,md->name(),md->protection());
4287             }
4288           }
4289         }
4290       }
4291     }
4292   }
4293   else
4294   {
4295     //printf("no members for class %s (%p)\n",masterCd->name().data(),masterCd);
4296   }
4297 }
4298
4299 static void findBaseClassesForClass(
4300       EntryNav *rootNav,
4301       Definition *context,
4302       ClassDef *masterCd,
4303       ClassDef *instanceCd,
4304       FindBaseClassRelation_Mode mode,
4305       bool isArtificial,
4306       ArgumentList *actualArgs=0,
4307       QDict<int> *templateNames=0
4308     )
4309 {
4310   Entry *root = rootNav->entry();
4311   //if (masterCd->visited) return;
4312   masterCd->visited=TRUE;
4313   // The base class could ofcouse also be a non-nested class
4314   ArgumentList *formalArgs = masterCd->templateArguments();
4315   QListIterator<BaseInfo> bii(*root->extends);
4316   BaseInfo *bi=0;
4317   for (bii.toFirst();(bi=bii.current());++bii)
4318   {
4319     //printf("masterCd=%s bi->name='%s' #actualArgs=%d\n",
4320     //    masterCd->localName().data(),bi->name.data(),actualArgs?(int)actualArgs->count():-1);
4321     bool delTempNames=FALSE;
4322     if (templateNames==0)
4323     {
4324       templateNames = getTemplateArgumentsInName(formalArgs,bi->name);
4325       delTempNames=TRUE;
4326     }
4327     BaseInfo tbi(bi->name,bi->prot,bi->virt);
4328     if (actualArgs) // substitute the formal template arguments of the base class
4329     {
4330       tbi.name = substituteTemplateArgumentsInString(bi->name,formalArgs,actualArgs);
4331     }
4332     //printf("bi->name=%s tbi.name=%s\n",bi->name.data(),tbi.name.data());
4333
4334     if (mode==DocumentedOnly)
4335     {
4336       // find a documented base class in the correct scope
4337       if (!findClassRelation(rootNav,context,instanceCd,&tbi,templateNames,DocumentedOnly,isArtificial))
4338       {
4339         // 1.8.2: decided to show inheritance relations even if not documented,
4340         //        we do make them artificial, so they do not appear in the index
4341         //if (!Config_getBool("HIDE_UNDOC_RELATIONS")) 
4342         bool b = Config_getBool("HIDE_UNDOC_RELATIONS") ? TRUE : isArtificial;
4343         //{
4344           // no documented base class -> try to find an undocumented one
4345           findClassRelation(rootNav,context,instanceCd,&tbi,templateNames,Undocumented,b);
4346         //}
4347       }
4348     }
4349     else if (mode==TemplateInstances)
4350     {
4351       findClassRelation(rootNav,context,instanceCd,&tbi,templateNames,TemplateInstances,isArtificial);
4352     }
4353     if (delTempNames)
4354     {
4355       delete templateNames;
4356       templateNames=0;
4357     }  
4358   }
4359 }
4360
4361 //----------------------------------------------------------------------
4362
4363 static bool findTemplateInstanceRelation(Entry *root,
4364             Definition *context,
4365             ClassDef *templateClass,const QCString &templSpec,
4366             QDict<int> *templateNames,
4367             bool isArtificial)
4368 {
4369   Debug::print(Debug::Classes,0,"    derived from template %s with parameters %s\n",
4370          templateClass->name().data(),templSpec.data());
4371   //printf("findTemplateInstanceRelation(base=%s templSpec=%s templateNames=",
4372   //    templateClass->name().data(),templSpec.data());
4373   //if (templateNames)
4374   //{
4375   //  QDictIterator<int> qdi(*templateNames);
4376   //  int *tempArgIndex;
4377   //  for (;(tempArgIndex=qdi.current());++qdi)
4378   //  {
4379   //    printf("(%s->%d) ",qdi.currentKey(),*tempArgIndex);
4380   //  }
4381   //}
4382   //printf("\n");
4383   
4384   bool existingClass = (templSpec ==
4385                         tempArgListToString(templateClass->templateArguments())
4386                        );
4387   if (existingClass) return TRUE;
4388
4389   bool freshInstance=FALSE;
4390   ClassDef *instanceClass = templateClass->insertTemplateInstance(
4391                      root->fileName,root->startLine,root->startColumn,templSpec,freshInstance);
4392   if (isArtificial) instanceClass->setArtificial(TRUE);
4393   instanceClass->setLanguage(root->lang);
4394
4395   if (freshInstance)
4396   {
4397     Debug::print(Debug::Classes,0,"      found fresh instance '%s'!\n",instanceClass->name().data());
4398     Doxygen::classSDict->append(instanceClass->name(),instanceClass);
4399     instanceClass->setTemplateBaseClassNames(templateNames);
4400
4401     // search for new template instances caused by base classes of 
4402     // instanceClass 
4403     EntryNav *templateRootNav = g_classEntries.find(templateClass->name());
4404     if (templateRootNav)
4405     {
4406       bool unloadNeeded=FALSE;
4407       Entry *templateRoot = templateRootNav->entry();
4408       if (templateRoot==0) // not yet loaded
4409       {
4410         templateRootNav->loadEntry(g_storage);
4411         templateRoot = templateRootNav->entry();
4412         ASSERT(templateRoot!=0); // now it should really be loaded
4413         unloadNeeded=TRUE;
4414       }
4415
4416       Debug::print(Debug::Classes,0,"        template root found %s templSpec=%s!\n",
4417           templateRoot->name.data(),templSpec.data());
4418       ArgumentList *templArgs = new ArgumentList;
4419       stringToArgumentList(templSpec,templArgs);
4420       findBaseClassesForClass(templateRootNav,context,templateClass,instanceClass,
4421           TemplateInstances,isArtificial,templArgs,templateNames);
4422
4423       findUsedClassesForClass(templateRootNav,context,templateClass,instanceClass,
4424           isArtificial,templArgs,templateNames);
4425       delete templArgs;
4426
4427       if (unloadNeeded) // still cleanup to do
4428       {
4429         templateRootNav->releaseEntry();
4430       }
4431     }
4432     else
4433     {
4434       Debug::print(Debug::Classes,0,"        no template root entry found!\n");
4435       // TODO: what happened if we get here?
4436     }
4437
4438     //Debug::print(Debug::Classes,0,"    Template instance %s : \n",instanceClass->name().data());
4439     //ArgumentList *tl = templateClass->templateArguments();
4440   }
4441   else
4442   {
4443     Debug::print(Debug::Classes,0,"      instance already exists!\n");
4444   }
4445   return TRUE;
4446 }
4447
4448 static bool isRecursiveBaseClass(const QCString &scope,const QCString &name)
4449 {
4450   QCString n=name;
4451   int index=n.find('<');
4452   if (index!=-1)
4453   {
4454     n=n.left(index);
4455   }
4456   bool result = rightScopeMatch(scope,n);
4457   return result;
4458 }
4459
4460 /*! Searches for the end of a template in prototype \a s starting from
4461  *  character position \a startPos. If the end was found the position
4462  *  of the closing \> is returned, otherwise -1 is returned.
4463  *
4464  *  Handles exotic cases such as 
4465  *  \code
4466  *    Class<(id<0)>
4467  *    Class<bits<<2>
4468  *    Class<"<">
4469  *    Class<'<'>
4470  *    Class<(")<")>
4471  *  \endcode
4472  */
4473 static int findEndOfTemplate(const QCString &s,int startPos)
4474 {
4475   // locate end of template
4476   int e=startPos;
4477   int brCount=1;
4478   int roundCount=0;
4479   int len = s.length();
4480   bool insideString=FALSE;
4481   bool insideChar=FALSE;
4482   char pc = 0;
4483   while (e<len && brCount!=0)
4484   {
4485     char c=s.at(e);
4486     switch(c)
4487     {
4488       case '<': 
4489         if (!insideString && !insideChar)
4490         {
4491           if (e<len-1 && s.at(e+1)=='<') 
4492             e++; 
4493           else if (roundCount==0)
4494             brCount++;
4495         }
4496         break;
4497       case '>':
4498         if (!insideString && !insideChar)
4499         {
4500           if (e<len-1 && s.at(e+1)=='>') 
4501             e++; 
4502           else if (roundCount==0)
4503             brCount--;
4504         }
4505         break;
4506       case '(':
4507         if (!insideString && !insideChar) 
4508           roundCount++;
4509         break;
4510       case ')':
4511         if (!insideString && !insideChar) 
4512           roundCount--;
4513         break;
4514       case '"':
4515         if (!insideChar)
4516         {
4517           if (insideString && pc!='\\') 
4518             insideString=FALSE;
4519           else
4520             insideString=TRUE;
4521         }
4522         break;
4523       case '\'':
4524         if (!insideString)
4525         {
4526           if (insideChar && pc!='\\')
4527             insideChar=FALSE;
4528           else
4529             insideChar=TRUE;
4530         }
4531         break;
4532     }
4533     pc = c;
4534     e++;
4535   }
4536   return brCount==0 ? e : -1;
4537 }
4538
4539 static bool findClassRelation(
4540                            EntryNav *rootNav,
4541                            Definition *context,
4542                            ClassDef *cd,
4543                            BaseInfo *bi,
4544                            QDict<int> *templateNames,
4545                            FindBaseClassRelation_Mode mode,
4546                            bool isArtificial
4547                           )
4548 {
4549   //printf("findClassRelation(class=%s base=%s templateNames=",
4550   //    cd->name().data(),bi->name.data());
4551   //if (templateNames)
4552   //{
4553   //  QDictIterator<int> qdi(*templateNames);
4554   //  int *tempArgIndex;
4555   //  for (;(tempArgIndex=qdi.current());++qdi)
4556   //  {
4557   //    printf("(%s->%d) ",qdi.currentKey(),*tempArgIndex);
4558   //  }
4559   //}
4560   //printf("\n");
4561
4562   Entry *root = rootNav->entry();
4563
4564   QCString biName=bi->name;
4565   bool explicitGlobalScope=FALSE;
4566   //printf("findClassRelation: biName=`%s'\n",biName.data());
4567   if (biName.left(2)=="::") // explicit global scope
4568   {
4569      biName=biName.right(biName.length()-2);
4570      explicitGlobalScope=TRUE;
4571   }
4572
4573   EntryNav *parentNode=rootNav->parent();
4574   bool lastParent=FALSE;
4575   do // for each parent scope, starting with the largest scope 
4576      // (in case of nested classes)
4577   {
4578     QCString scopeName= parentNode ? parentNode->name().data() : "";
4579     int scopeOffset=explicitGlobalScope ? 0 : scopeName.length();
4580     do // try all parent scope prefixes, starting with the largest scope
4581     {
4582       //printf("scopePrefix=`%s' biName=`%s'\n",
4583       //    scopeName.left(scopeOffset).data(),biName.data());
4584
4585       QCString baseClassName=biName;
4586       if (scopeOffset>0)
4587       {
4588         baseClassName.prepend(scopeName.left(scopeOffset)+"::");
4589       }
4590       //QCString stripped;
4591       //baseClassName=stripTemplateSpecifiersFromScope
4592       //                    (removeRedundantWhiteSpace(baseClassName),TRUE,
4593       //                    &stripped);
4594       MemberDef *baseClassTypeDef=0;
4595       QCString templSpec;
4596       ClassDef *baseClass=getResolvedClass(explicitGlobalScope ? Doxygen::globalScope : context,
4597                                            cd->getFileDef(), 
4598                                            baseClassName,
4599                                            &baseClassTypeDef,
4600                                            &templSpec,
4601                                            mode==Undocumented,
4602                                            TRUE
4603                                           );
4604       //printf("baseClassName=%s baseClass=%p cd=%p explicitGlobalScope=%d\n",
4605       //    baseClassName.data(),baseClass,cd,explicitGlobalScope);
4606       //printf("    scope=`%s' baseClassName=`%s' baseClass=%s templSpec=%s\n",
4607       //                    cd ? cd->name().data():"<none>",
4608       //                    baseClassName.data(),
4609       //                    baseClass?baseClass->name().data():"<none>",
4610       //                    templSpec.data()
4611       //      );
4612       //if (baseClassName.left(root->name.length())!=root->name ||
4613       //    baseClassName.at(root->name.length())!='<'
4614       //   ) // Check for base class with the same name.
4615       //     // If found then look in the outer scope for a match
4616       //     // and prevent recursion.
4617       if (!isRecursiveBaseClass(rootNav->name(),baseClassName)
4618           || explicitGlobalScope
4619           // sadly isRecursiveBaseClass always true for UNO IDL ifc/svc members
4620           // (i.e. this is needed for addInterfaceOrServiceToServiceOrSingleton)
4621           || (rootNav->lang()==SrcLangExt_IDL &&
4622               (rootNav->section()==Entry::EXPORTED_INTERFACE_SEC ||
4623                rootNav->section()==Entry::INCLUDED_SERVICE_SEC)))
4624       {
4625         Debug::print(
4626             Debug::Classes,0,"    class relation %s inherited/used by %s found (%s and %s) templSpec='%s'\n",
4627             baseClassName.data(),
4628             rootNav->name().data(),
4629             (bi->prot==Private)?"private":((bi->prot==Protected)?"protected":"public"),
4630             (bi->virt==Normal)?"normal":"virtual",
4631             templSpec.data()
4632            );
4633
4634         int i=baseClassName.find('<');
4635         int si=baseClassName.findRev("::",i==-1 ? baseClassName.length() : i);
4636         if (si==-1) si=0;
4637         if (baseClass==0 && i!=-1) 
4638           // base class has template specifiers
4639         {
4640           if (root->lang == SrcLangExt_CSharp)
4641           {
4642             baseClass = Doxygen::genericsDict->find(baseClassName);
4643           }
4644           else
4645           {
4646             // TODO: here we should try to find the correct template specialization
4647             // but for now, we only look for the unspecializated base class.
4648             int e=findEndOfTemplate(baseClassName,i+1);
4649             //printf("baseClass==0 i=%d e=%d\n",i,e);
4650             if (e!=-1) // end of template was found at e
4651             {
4652               templSpec=removeRedundantWhiteSpace(baseClassName.mid(i,e-i));
4653               baseClassName=baseClassName.left(i)+baseClassName.right(baseClassName.length()-e);
4654               baseClass=getResolvedClass(explicitGlobalScope ? Doxygen::globalScope : context,
4655                   cd->getFileDef(),
4656                   baseClassName,
4657                   &baseClassTypeDef,
4658                   0, //&templSpec,
4659                   mode==Undocumented,
4660                   TRUE
4661                   );
4662               //printf("baseClass=%p -> baseClass=%s templSpec=%s\n",
4663               //      baseClass,baseClassName.data(),templSpec.data());
4664             }
4665           }
4666         }
4667         else if (baseClass && !templSpec.isEmpty()) // we have a known class, but also
4668                                                     // know it is a template, so see if
4669                                                     // we can also link to the explicit
4670                                                     // instance (for instance if a class
4671                                                     // derived from a template argument)
4672         {
4673           //printf("baseClass=%p templSpec=%s\n",baseClass,templSpec.data());
4674           ClassDef *templClass=getClass(baseClass->name()+templSpec);
4675           if (templClass)
4676           {
4677             // use the template instance instead of the template base.
4678             baseClass = templClass;
4679             templSpec.resize(0);
4680           }
4681         }
4682
4683         //printf("cd=%p baseClass=%p\n",cd,baseClass);
4684         bool found=baseClass!=0 && (baseClass!=cd || mode==TemplateInstances);
4685         //printf("1. found=%d\n",found);
4686         if (!found && si!=-1)
4687         {
4688           QCString tmpTemplSpec;
4689           // replace any namespace aliases
4690           replaceNamespaceAliases(baseClassName,si);
4691           baseClass=getResolvedClass(explicitGlobalScope ? Doxygen::globalScope : context,
4692                                      cd->getFileDef(),
4693                                      baseClassName,
4694                                      &baseClassTypeDef,
4695                                      &tmpTemplSpec,
4696                                      mode==Undocumented,
4697                                      TRUE
4698                                     );
4699           found=baseClass!=0 && baseClass!=cd;
4700           if (found) templSpec = tmpTemplSpec;
4701         }
4702         //printf("2. found=%d\n",found);
4703         
4704         //printf("root->name=%s biName=%s baseClassName=%s\n",
4705         //        root->name.data(),biName.data(),baseClassName.data());
4706         //if (cd->isCSharp() && i!=-1) // C# generic -> add internal -g postfix
4707         //{
4708         //  baseClassName+="-g";
4709         //}
4710
4711         if (!found)
4712         {
4713           baseClass=findClassWithinClassContext(context,cd,baseClassName);
4714           //printf("findClassWithinClassContext(%s,%s)=%p\n",
4715           //    cd->name().data(),baseClassName.data(),baseClass);
4716           found = baseClass!=0 && baseClass!=cd;
4717
4718         }
4719         if (!found)
4720         {
4721           // for PHP the "use A\B as C" construct map class C to A::B, so we lookup
4722           // the class name also in the alias mapping.
4723           QCString *aliasName = Doxygen::namespaceAliasDict[baseClassName];
4724           if (aliasName) // see if it is indeed a class.
4725           {
4726             baseClass=getClass(*aliasName);
4727             found = baseClass!=0 && baseClass!=cd;
4728           }
4729         }
4730         bool isATemplateArgument = templateNames!=0 && templateNames->find(biName)!=0;
4731         // make templSpec canonical
4732         // warning: the following line doesn't work for Mixin classes (see bug 560623)
4733         // templSpec = getCanonicalTemplateSpec(cd, cd->getFileDef(), templSpec);
4734
4735         //printf("3. found=%d\n",found);
4736         if (found)
4737         {
4738           Debug::print(Debug::Classes,0,"    Documented base class `%s' templSpec=%s\n",biName.data(),templSpec.isEmpty()?"":templSpec.data());
4739           // add base class to this class
4740
4741           // if templSpec is not empty then we should "instantiate"
4742           // the template baseClass. A new ClassDef should be created
4743           // to represent the instance. To be able to add the (instantiated)
4744           // members and documentation of a template class 
4745           // (inserted in that template class at a later stage), 
4746           // the template should know about its instances. 
4747           // the instantiation process, should be done in a recursive way, 
4748           // since instantiating a template may introduce new inheritance 
4749           // relations.
4750           if (!templSpec.isEmpty() && mode==TemplateInstances)
4751           {
4752             // if baseClass is actually a typedef then we should not
4753             // instantiate it, since typedefs are in a different namespace
4754             // see bug531637 for an example where this would otherwise hang
4755             // doxygen
4756             if (baseClassTypeDef==0)
4757             {
4758               //printf("       => findTemplateInstanceRelation: %p\n",baseClassTypeDef);
4759               findTemplateInstanceRelation(root,context,baseClass,templSpec,templateNames,isArtificial);
4760             }
4761           }
4762           else if (mode==DocumentedOnly || mode==Undocumented)
4763           {
4764             //printf("       => insert base class\n");
4765             QCString usedName;
4766             if (baseClassTypeDef || cd->isCSharp()) 
4767             {
4768               usedName=biName;
4769               //printf("***** usedName=%s templSpec=%s\n",usedName.data(),templSpec.data());
4770             }
4771             static bool sipSupport = Config_getBool("SIP_SUPPORT");
4772             if (sipSupport) bi->prot=Public;
4773             if (!cd->isSubClass(baseClass)) // check for recursion, see bug690787
4774             {
4775               cd->insertBaseClass(baseClass,usedName,bi->prot,bi->virt,templSpec);
4776               // add this class as super class to the base class
4777               baseClass->insertSubClass(cd,bi->prot,bi->virt,templSpec);
4778             }
4779             else
4780             {
4781               warn(root->fileName,root->startLine,
4782                   "Detected potential recursive class relation "
4783                   "between class %s and base class %s!",
4784                   cd->name().data(),baseClass->name().data()
4785                   );
4786             }
4787           }
4788           return TRUE;
4789         }
4790         else if (mode==Undocumented && (scopeOffset==0 || isATemplateArgument))
4791         {
4792           Debug::print(Debug::Classes,0,
4793                        "    New undocumented base class `%s' baseClassName=%s templSpec=%s isArtificial=%d\n",
4794                        biName.data(),baseClassName.data(),templSpec.data(),isArtificial
4795                       );
4796           baseClass=0;
4797           if (isATemplateArgument)
4798           {
4799             baseClass=Doxygen::hiddenClasses->find(baseClassName);
4800             if (baseClass==0)
4801             {
4802               baseClass=new ClassDef(root->fileName,root->startLine,root->startColumn,
4803                                  baseClassName,
4804                                  ClassDef::Class);
4805               Doxygen::hiddenClasses->append(baseClassName,baseClass);
4806               if (isArtificial) baseClass->setArtificial(TRUE);
4807               baseClass->setLanguage(root->lang);
4808             }
4809           }
4810           else
4811           {
4812             baseClass=Doxygen::classSDict->find(baseClassName);
4813             //printf("*** classDDict->find(%s)=%p biName=%s templSpec=%s\n",
4814             //    baseClassName.data(),baseClass,biName.data(),templSpec.data());
4815             if (baseClass==0)
4816             {
4817               baseClass=new ClassDef(root->fileName,root->startLine,root->startColumn,
4818                   baseClassName,
4819                   ClassDef::Class);
4820               Doxygen::classSDict->append(baseClassName,baseClass);
4821               if (isArtificial) baseClass->setArtificial(TRUE);
4822               baseClass->setLanguage(root->lang);
4823               int si = baseClassName.findRev("::");
4824               if (si!=-1) // class is nested
4825               {
4826                 Definition *sd = findScopeFromQualifiedName(Doxygen::globalScope,baseClassName.left(si));
4827                 if (sd==0 || sd==Doxygen::globalScope) // outer scope not found
4828                 {
4829                   baseClass->setArtificial(TRUE); // see bug678139
4830                 }
4831               }
4832             }
4833           }
4834           if (biName.right(2)=="-p")
4835           {
4836             biName="<"+biName.left(biName.length()-2)+">";
4837           }
4838           // add base class to this class
4839           cd->insertBaseClass(baseClass,biName,bi->prot,bi->virt,templSpec);
4840           // add this class as super class to the base class
4841           baseClass->insertSubClass(cd,bi->prot,bi->virt,templSpec);
4842           // the undocumented base was found in this file
4843           baseClass->insertUsedFile(rootNav->fileDef());
4844           baseClass->setOuterScope(Doxygen::globalScope);
4845           if (baseClassName.right(2)=="-p")
4846           {
4847             baseClass->setCompoundType(ClassDef::Protocol);
4848           }
4849           return TRUE;
4850         }
4851         else
4852         {
4853           Debug::print(Debug::Classes,0,"    Base class `%s' not found\n",biName.data());
4854         }
4855       }
4856       else
4857       {
4858         if (mode!=TemplateInstances)
4859         {
4860           warn(root->fileName,root->startLine,
4861               "Detected potential recursive class relation "
4862               "between class %s and base class %s!\n",
4863               root->name.data(),baseClassName.data()
4864               );
4865         }
4866         // for mode==TemplateInstance this case is quite common and
4867         // indicates a relation between a template class and a template 
4868         // instance with the same name.
4869       }
4870       if (scopeOffset==0)
4871       {
4872         scopeOffset=-1;
4873       }
4874       else if ((scopeOffset=scopeName.findRev("::",scopeOffset-1))==-1)
4875       {
4876         scopeOffset=0;
4877       }
4878       //printf("new scopeOffset=`%d'",scopeOffset);
4879     } while (scopeOffset>=0);
4880
4881     if (parentNode==0)
4882     {
4883       lastParent=TRUE;
4884     }
4885     else
4886     {
4887       parentNode=parentNode->parent();
4888     }
4889   } while (lastParent);
4890
4891   return FALSE;
4892 }
4893
4894 //----------------------------------------------------------------------
4895 // Computes the base and super classes for each class in the tree
4896
4897 static bool isClassSection(EntryNav *rootNav)
4898 {
4899   if ( !rootNav->name().isEmpty() )
4900   {
4901     if (rootNav->section() & Entry::COMPOUND_MASK)
4902          // is it a compound (class, struct, union, interface ...)
4903     {
4904       return TRUE;
4905     }
4906     else if (rootNav->section() & Entry::COMPOUNDDOC_MASK) 
4907          // is it a documentation block with inheritance info.
4908     {
4909       rootNav->loadEntry(g_storage);
4910       Entry *root = rootNav->entry();
4911       bool extends = root->extends->count()>0;
4912       rootNav->releaseEntry(); 
4913       if (extends) return TRUE;
4914     }
4915   }
4916   return FALSE;
4917 }
4918
4919
4920 /*! Builds a dictionary of all entry nodes in the tree starting with \a root
4921  */
4922 static void findClassEntries(EntryNav *rootNav)
4923 {
4924   if (isClassSection(rootNav))
4925   {
4926     g_classEntries.insert(rootNav->name(),rootNav);
4927   }
4928   RECURSE_ENTRYTREE(findClassEntries,rootNav);
4929 }
4930
4931 /*! Using the dictionary build by findClassEntries(), this 
4932  *  function will look for additional template specialization that
4933  *  exists as inheritance relations only. These instances will be
4934  *  added to the template they are derived from.
4935  */
4936 static void findInheritedTemplateInstances()
4937 {
4938   ClassSDict::Iterator cli(*Doxygen::classSDict);
4939   for (cli.toFirst();cli.current();++cli) cli.current()->visited=FALSE;
4940   QDictIterator<EntryNav> edi(g_classEntries);
4941   EntryNav *rootNav;
4942   for (;(rootNav=edi.current());++edi)
4943   {
4944     ClassDef *cd;
4945     // strip any anonymous scopes first 
4946     QCString bName=stripAnonymousNamespaceScope(rootNav->name());
4947     bName=stripTemplateSpecifiersFromScope(bName);
4948     Debug::print(Debug::Classes,0,"  Inheritance: Class %s : \n",bName.data());
4949     if ((cd=getClass(bName)))
4950     {
4951       rootNav->loadEntry(g_storage);
4952       //printf("Class %s %d\n",cd->name().data(),root->extends->count());
4953       findBaseClassesForClass(rootNav,cd,cd,cd,TemplateInstances,FALSE);
4954       rootNav->releaseEntry();
4955     }
4956   }
4957 }
4958
4959 static void findUsedTemplateInstances()
4960 {
4961   ClassSDict::Iterator cli(*Doxygen::classSDict);
4962   for (cli.toFirst();cli.current();++cli) cli.current()->visited=FALSE;
4963   QDictIterator<EntryNav> edi(g_classEntries);
4964   EntryNav *rootNav;
4965   for (;(rootNav=edi.current());++edi)
4966   {
4967     ClassDef *cd;
4968     // strip any anonymous scopes first 
4969     QCString bName=stripAnonymousNamespaceScope(rootNav->name());
4970     bName=stripTemplateSpecifiersFromScope(bName);
4971     Debug::print(Debug::Classes,0,"  Usage: Class %s : \n",bName.data());
4972     if ((cd=getClass(bName)))
4973     {
4974       rootNav->loadEntry(g_storage);
4975       findUsedClassesForClass(rootNav,cd,cd,cd,TRUE);
4976       rootNav->releaseEntry();
4977     }
4978   }
4979 }
4980
4981 static void computeClassRelations()
4982 {
4983   ClassSDict::Iterator cli(*Doxygen::classSDict);
4984   for (cli.toFirst();cli.current();++cli) cli.current()->visited=FALSE;
4985   QDictIterator<EntryNav> edi(g_classEntries);
4986   EntryNav *rootNav;
4987   for (;(rootNav=edi.current());++edi)
4988   {
4989     ClassDef *cd;
4990
4991     rootNav->loadEntry(g_storage);
4992     Entry *root = rootNav->entry();
4993
4994     // strip any anonymous scopes first 
4995     QCString bName=stripAnonymousNamespaceScope(rootNav->name());
4996     bName=stripTemplateSpecifiersFromScope(bName);
4997     Debug::print(Debug::Classes,0,"  Relations: Class %s : \n",bName.data());
4998     if ((cd=getClass(bName)))
4999     {
5000       findBaseClassesForClass(rootNav,cd,cd,cd,DocumentedOnly,FALSE);
5001     }
5002     int numMembers = cd && cd->memberNameInfoSDict() ? cd->memberNameInfoSDict()->count() : 0;
5003     if ((cd==0 || (!cd->hasDocumentation() && !cd->isReference())) && numMembers>0 &&
5004         bName.right(2)!="::")
5005     {
5006       if (!root->name.isEmpty() && root->name.find('@')==-1 && // normal name
5007           (guessSection(root->fileName)==Entry::HEADER_SEC || 
5008            Config_getBool("EXTRACT_LOCAL_CLASSES")) && // not defined in source file
5009            protectionLevelVisible(root->protection) && // hidden by protection
5010            !Config_getBool("HIDE_UNDOC_CLASSES") // undocumented class are visible
5011          )
5012         warn_undoc(
5013                    root->fileName,root->startLine,
5014                    "Compound %s is not documented.",
5015                    root->name.data()
5016              );
5017     }
5018
5019     rootNav->releaseEntry();
5020   }
5021 }
5022
5023 static void computeTemplateClassRelations()
5024 {
5025   QDictIterator<EntryNav> edi(g_classEntries);
5026   EntryNav *rootNav;
5027   for (;(rootNav=edi.current());++edi)
5028   {
5029     rootNav->loadEntry(g_storage);
5030     Entry *root = rootNav->entry();
5031
5032     QCString bName=stripAnonymousNamespaceScope(root->name);
5033     bName=stripTemplateSpecifiersFromScope(bName);
5034     ClassDef *cd=getClass(bName);
5035     // strip any anonymous scopes first 
5036     QDict<ClassDef> *templInstances = 0;
5037     if (cd && (templInstances=cd->getTemplateInstances()))
5038     {
5039       Debug::print(Debug::Classes,0,"  Template class %s : \n",cd->name().data());
5040       QDictIterator<ClassDef> tdi(*templInstances);
5041       ClassDef *tcd;
5042       for (tdi.toFirst();(tcd=tdi.current());++tdi) // for each template instance
5043       {
5044         Debug::print(Debug::Classes,0,"    Template instance %s : \n",tcd->name().data());
5045         QCString templSpec = tdi.currentKey();
5046         ArgumentList *templArgs = new ArgumentList;
5047         stringToArgumentList(templSpec,templArgs);
5048         QList<BaseInfo> *baseList=root->extends;
5049         QListIterator<BaseInfo> it(*baseList);
5050         BaseInfo *bi;
5051         for (;(bi=it.current());++it) // for each base class of the template
5052         {
5053           // check if the base class is a template argument
5054           BaseInfo tbi(bi->name,bi->prot,bi->virt);
5055           ArgumentList *tl = cd->templateArguments();
5056           if (tl)
5057           {
5058             QDict<int> *baseClassNames = tcd->getTemplateBaseClassNames();
5059             QDict<int> *templateNames = getTemplateArgumentsInName(tl,bi->name);
5060             // for each template name that we inherit from we need to
5061             // substitute the formal with the actual arguments
5062             QDict<int> *actualTemplateNames = new QDict<int>(17);
5063             actualTemplateNames->setAutoDelete(TRUE);
5064             QDictIterator<int> qdi(*templateNames);
5065             for (qdi.toFirst();qdi.current();++qdi)
5066             {
5067               int templIndex = *qdi.current();
5068               Argument *actArg = 0;
5069               if (templIndex<(int)templArgs->count()) 
5070               {
5071                 actArg=templArgs->at(templIndex);
5072               }
5073               if (actArg!=0 &&
5074                   baseClassNames!=0 &&
5075                   baseClassNames->find(actArg->type)!=0 &&
5076                   actualTemplateNames->find(actArg->type)==0
5077                  )
5078               {
5079                 actualTemplateNames->insert(actArg->type,new int(templIndex));
5080               }
5081             }
5082             delete templateNames;
5083             
5084             tbi.name = substituteTemplateArgumentsInString(bi->name,tl,templArgs);
5085             // find a documented base class in the correct scope
5086             if (!findClassRelation(rootNav,cd,tcd,&tbi,actualTemplateNames,DocumentedOnly,FALSE))
5087             {
5088               // no documented base class -> try to find an undocumented one
5089               findClassRelation(rootNav,cd,tcd,&tbi,actualTemplateNames,Undocumented,TRUE);
5090             }
5091             delete actualTemplateNames;
5092           }
5093         }
5094         delete templArgs;
5095       } // class has no base classes
5096     }
5097
5098     rootNav->releaseEntry();
5099   }
5100 }
5101
5102 //-----------------------------------------------------------------------
5103 // compute the references (anchors in HTML) for each function in the file
5104
5105 static void computeMemberReferences()
5106 {
5107   ClassSDict::Iterator cli(*Doxygen::classSDict);
5108   ClassDef *cd=0;
5109   for (cli.toFirst();(cd=cli.current());++cli)
5110   {
5111     cd->computeAnchors();
5112   }
5113   FileNameListIterator fnli(*Doxygen::inputNameList);
5114   FileName *fn;
5115   for (fnli.toFirst();(fn=fnli.current());++fnli)
5116   {
5117     FileNameIterator fni(*fn);
5118     FileDef *fd;
5119     for (;(fd=fni.current());++fni)
5120     {
5121       fd->computeAnchors();
5122     }
5123   }
5124   NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
5125   NamespaceDef *nd=0;
5126   for (nli.toFirst();(nd=nli.current());++nli)
5127   {
5128     nd->computeAnchors();
5129   }
5130   GroupSDict::Iterator gli(*Doxygen::groupSDict);
5131   GroupDef *gd;
5132   for (gli.toFirst();(gd=gli.current());++gli)
5133   {
5134     gd->computeAnchors();
5135   }
5136 }
5137
5138 //----------------------------------------------------------------------
5139
5140 static void addListReferences()
5141 {
5142   MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
5143   MemberName *mn=0;
5144   for (mnli.toFirst();(mn=mnli.current());++mnli)
5145   {
5146     MemberNameIterator mni(*mn);
5147     MemberDef *md=0;
5148     for (mni.toFirst();(md=mni.current());++mni)
5149     {
5150       md->visited=FALSE;
5151     }
5152   }
5153   MemberNameSDict::Iterator fmnli(*Doxygen::functionNameSDict);
5154   for (fmnli.toFirst();(mn=fmnli.current());++fmnli)
5155   {
5156     MemberNameIterator mni(*mn);
5157     MemberDef *md=0;
5158     for (mni.toFirst();(md=mni.current());++mni)
5159     {
5160       md->visited=FALSE;
5161     }
5162   }
5163
5164   ClassSDict::Iterator cli(*Doxygen::classSDict);
5165   ClassDef *cd=0;
5166   for (cli.toFirst();(cd=cli.current());++cli)
5167   {
5168     cd->addListReferences();
5169   }
5170
5171   FileNameListIterator fnli(*Doxygen::inputNameList);
5172   FileName *fn;
5173   for (fnli.toFirst();(fn=fnli.current());++fnli)
5174   {
5175     FileNameIterator fni(*fn);
5176     FileDef *fd;
5177     for (;(fd=fni.current());++fni)
5178     {
5179       fd->addListReferences();
5180     }
5181   }
5182
5183   NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
5184   NamespaceDef *nd=0;
5185   for (nli.toFirst();(nd=nli.current());++nli)
5186   {
5187     nd->addListReferences();
5188   }
5189
5190   GroupSDict::Iterator gli(*Doxygen::groupSDict);
5191   GroupDef *gd;
5192   for (gli.toFirst();(gd=gli.current());++gli)
5193   {
5194     gd->addListReferences();
5195   }
5196
5197   PageSDict::Iterator pdi(*Doxygen::pageSDict);
5198   PageDef *pd=0;
5199   for (pdi.toFirst();(pd=pdi.current());++pdi)
5200   {
5201     QCString name = pd->getOutputFileBase();
5202     if (pd->getGroupDef())
5203     {
5204       name = pd->getGroupDef()->getOutputFileBase();
5205     }
5206     {
5207       QList<ListItemInfo> *xrefItems = pd->xrefListItems();
5208       addRefItem(xrefItems,
5209           name,
5210           theTranslator->trPage(TRUE,TRUE),
5211           name,pd->title(),0);
5212     }
5213   }
5214
5215   DirSDict::Iterator ddi(*Doxygen::directories);
5216   DirDef *dd = 0;
5217   for (ddi.toFirst();(dd=ddi.current());++ddi)
5218   {
5219     QCString name = dd->getOutputFileBase();
5220     //if (dd->getGroupDef())
5221     //{
5222     //  name = dd->getGroupDef()->getOutputFileBase();
5223     //}
5224     QList<ListItemInfo> *xrefItems = dd->xrefListItems();
5225     addRefItem(xrefItems,
5226         name,
5227         theTranslator->trDir(TRUE,TRUE),
5228         name,dd->displayName(),0);
5229   }
5230 }
5231
5232 //----------------------------------------------------------------------
5233
5234 static void generateXRefPages()
5235 {
5236   QDictIterator<RefList> di(*Doxygen::xrefLists);
5237   RefList *rl;
5238   for (di.toFirst();(rl=di.current());++di)
5239   {
5240     rl->generatePage();
5241   }
5242 }
5243
5244 //----------------------------------------------------------------------
5245 // Copy the documentation in entry `root' to member definition `md' and
5246 // set the function declaration of the member to `funcDecl'. If the boolean 
5247 // over_load is set the standard overload text is added. 
5248
5249 static void addMemberDocs(EntryNav *rootNav,
5250                    MemberDef *md, const char *funcDecl,
5251                    ArgumentList *al,
5252                    bool over_load,
5253                    NamespaceSDict *
5254                   )
5255 {
5256   Entry *root = rootNav->entry();
5257   //printf("addMemberDocs: `%s'::`%s' `%s' funcDecl=`%s' mSpec=%d\n",
5258   //     root->parent->name.data(),md->name().data(),md->argsString(),funcDecl,root->spec);
5259   QCString fDecl=funcDecl;
5260   // strip extern specifier
5261   fDecl.stripPrefix("extern ");
5262   md->setDefinition(fDecl);
5263   md->enableCallGraph(root->callGraph);
5264   md->enableCallerGraph(root->callerGraph);
5265   ClassDef     *cd=md->getClassDef();
5266   NamespaceDef *nd=md->getNamespaceDef();
5267   QCString fullName;
5268   if (cd) 
5269     fullName = cd->name();
5270   else if (nd) 
5271     fullName = nd->name();
5272
5273   if (!fullName.isEmpty()) fullName+="::";
5274   fullName+=md->name();
5275   FileDef *rfd=rootNav->fileDef();
5276
5277   // TODO determine scope based on root not md
5278   Definition *rscope = md->getOuterScope();
5279
5280   ArgumentList *mdAl = md->argumentList();
5281   if (al)
5282   {
5283     //printf("merging arguments (1) docs=%d\n",root->doc.isEmpty());
5284     mergeArguments(mdAl,al,!root->doc.isEmpty());
5285   }
5286   else
5287   {
5288     if ( 
5289           matchArguments2( md->getOuterScope(), md->getFileDef(), mdAl,
5290                            rscope,rfd,root->argList,
5291                            TRUE
5292                          )
5293        ) 
5294     {
5295       //printf("merging arguments (2)\n");
5296       mergeArguments(mdAl,root->argList,!root->doc.isEmpty());
5297     }
5298   }
5299   if (over_load)  // the \overload keyword was used
5300   {
5301     QCString doc=getOverloadDocs();
5302     if (!root->doc.isEmpty())
5303     {
5304       doc+="<p>";
5305       doc+=root->doc;
5306     }
5307     md->setDocumentation(doc,root->docFile,root->docLine); 
5308     md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
5309     md->setDocsForDefinition(!root->proto);
5310   }
5311   else  
5312   {
5313     //printf("overwrite!\n");
5314     md->setDocumentation(root->doc,root->docFile,root->docLine);
5315     md->setDocsForDefinition(!root->proto);
5316
5317     //printf("overwrite!\n");
5318     md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
5319
5320     if (
5321         (md->inbodyDocumentation().isEmpty() ||
5322          !rootNav->parent()->name().isEmpty()
5323         ) && !root->inbodyDocs.isEmpty()
5324        )
5325     {
5326       md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
5327     }
5328   }
5329
5330   //printf("initializer: '%s'(isEmpty=%d) '%s'(isEmpty=%d)\n",
5331   //    md->initializer().data(),md->initializer().isEmpty(),
5332   //    root->initializer.data(),root->initializer.isEmpty()
5333   //   );
5334   if (md->initializer().isEmpty() && !root->initializer.isEmpty())
5335   {
5336     //printf("setInitializer\n");
5337     md->setInitializer(root->initializer);
5338   }
5339
5340   md->setMaxInitLines(root->initLines);
5341
5342   if (rfd)
5343   {
5344     if ((md->getStartBodyLine()==-1 && root->bodyLine!=-1) 
5345        )
5346     {
5347       //printf("Setting new body segment [%d,%d]\n",root->bodyLine,root->endBodyLine);
5348       md->setBodySegment(root->bodyLine,root->endBodyLine);
5349       md->setBodyDef(rfd);
5350     }
5351
5352     md->setRefItems(root->sli);
5353   }
5354
5355   md->enableCallGraph(md->hasCallGraph() || root->callGraph);
5356   md->enableCallerGraph(md->hasCallerGraph() || root->callerGraph);
5357
5358   md->mergeMemberSpecifiers(root->spec);
5359   md->addSectionsToDefinition(root->anchors);
5360   addMemberToGroups(root,md);
5361   if (cd) cd->insertUsedFile(rfd);
5362   //printf("root->mGrpId=%d\n",root->mGrpId);
5363   if (root->mGrpId!=-1)
5364   {
5365     if (md->getMemberGroupId()!=-1)
5366     {
5367       if (md->getMemberGroupId()!=root->mGrpId)
5368       {
5369         warn(
5370              root->fileName,root->startLine,
5371              "member %s belongs to two different groups. The second "
5372              "one found here will be ignored.",
5373              md->name().data()
5374             );
5375       }
5376     }
5377     else // set group id
5378     {
5379       //printf("setMemberGroupId=%d md=%s\n",root->mGrpId,md->name().data());
5380       md->setMemberGroupId(root->mGrpId);
5381     }
5382   }
5383 }
5384
5385 //----------------------------------------------------------------------
5386 // find a class definition given the scope name and (optionally) a 
5387 // template list specifier
5388
5389 static ClassDef *findClassDefinition(FileDef *fd,NamespaceDef *nd,
5390                          const char *scopeName)
5391 {
5392   ClassDef *tcd = getResolvedClass(nd,fd,scopeName,0,0,TRUE,TRUE);
5393   return tcd;
5394 }
5395
5396
5397 //----------------------------------------------------------------------
5398 // Adds the documentation contained in `root' to a global function
5399 // with name `name' and argument list `args' (for overloading) and
5400 // function declaration `decl' to the corresponding member definition.
5401
5402 static bool findGlobalMember(EntryNav *rootNav, 
5403                            const QCString &namespaceName,
5404                            const char *type,
5405                            const char *name, 
5406                            const char *tempArg,
5407                            const char *, 
5408                            const char *decl)
5409 {
5410   Entry *root = rootNav->entry();
5411   Debug::print(Debug::FindMembers,0,
5412        "2. findGlobalMember(namespace=%s,type=%s,name=%s,tempArg=%s,decl=%s)\n",
5413           namespaceName.data(),type,name,tempArg,decl);
5414   QCString n=name;
5415   if (n.isEmpty()) return FALSE;
5416   if (n.find("::")!=-1) return FALSE; // skip undefined class members
5417   MemberName *mn=Doxygen::functionNameSDict->find(n+tempArg); // look in function dictionary
5418   if (mn==0)
5419   {
5420     mn=Doxygen::functionNameSDict->find(n); // try without template arguments
5421   }
5422   if (mn) // function name defined
5423   {
5424     Debug::print(Debug::FindMembers,0,"3. Found symbol scope\n");
5425     //int count=0;
5426     MemberNameIterator mni(*mn);
5427     MemberDef *md;
5428     bool found=FALSE;
5429     for (mni.toFirst();(md=mni.current()) && !found;++mni)
5430     {
5431       NamespaceDef *nd=md->getNamespaceDef();
5432
5433       //printf("Namespace namespaceName=%s nd=%s\n",
5434       //    namespaceName.data(),nd ? nd->name().data() : "<none>");
5435
5436       FileDef *fd=rootNav->fileDef();
5437       //printf("File %s\n",fd ? fd->name().data() : "<none>");
5438       NamespaceSDict *nl = fd ? fd->getUsedNamespaces() : 0;
5439       //SDict<Definition> *cl = fd ? fd->getUsedClasses()    : 0;
5440       //printf("NamespaceList %p\n",nl);
5441
5442       // search in the list of namespaces that are imported via a 
5443       // using declaration
5444       bool viaUsingDirective = nl && nd && nl->find(nd->qualifiedName())!=0;
5445
5446       if ((namespaceName.isEmpty() && nd==0) ||  // not in a namespace
5447           (nd && nd->name()==namespaceName) ||   // or in the same namespace 
5448           viaUsingDirective                      // member in `using' namespace
5449          )     
5450       {
5451         Debug::print(Debug::FindMembers,0,"4. Try to add member `%s' to scope `%s'\n",
5452             md->name().data(),namespaceName.data());
5453         QCString nsName = nd ? nd->name().data() : "";
5454
5455         NamespaceDef *rnd = 0;
5456         if (!namespaceName.isEmpty()) rnd = Doxygen::namespaceSDict->find(namespaceName);
5457
5458         ArgumentList *mdAl = md->argumentList();
5459         bool matching=
5460           (mdAl==0 && root->argList->count()==0) ||
5461           md->isVariable() || md->isTypedef() || /* in case of function pointers */
5462           matchArguments2(md->getOuterScope(),md->getFileDef(),mdAl,
5463                           rnd ? rnd : Doxygen::globalScope,fd,root->argList,
5464                           FALSE);
5465
5466         // for template members we need to check if the number of
5467         // template arguments is the same, otherwise we are dealing with
5468         // different functions.
5469         if (matching && root->tArgLists)
5470         {
5471           ArgumentList *mdTempl = md->templateArguments();
5472           if (mdTempl)
5473           {
5474             if (root->tArgLists->getLast()->count()!=mdTempl->count())
5475             {
5476               matching=FALSE;
5477             }
5478           }
5479         }
5480
5481         //printf("%s<->%s\n",
5482         //    argListToString(md->argumentList()).data(),
5483         //    argListToString(root->argList).data());
5484
5485         // for static members we also check if the comment block was found in 
5486         // the same file. This is needed because static members with the same
5487         // name can be in different files. Thus it would be wrong to just
5488         // put the comment block at the first syntactically matching member.
5489         if (matching && md->isStatic() && 
5490             md->getDefFileName()!=root->fileName && 
5491             mn->count()>1)
5492         {
5493           matching = FALSE;
5494         }
5495
5496         // for template member we also need to check the return type
5497         if (md->templateArguments()!=0 && root->tArgLists!=0)
5498         {
5499           //printf("Comparing return types '%s'<->'%s'\n",
5500           //    md->typeString(),type);
5501           if (md->templateArguments()->count()!=root->tArgLists->getLast()->count() ||
5502               qstrcmp(md->typeString(),type)!=0)
5503           {
5504             //printf(" ---> no matching\n");
5505             matching = FALSE;
5506           }
5507         }
5508
5509         if (matching) // add docs to the member
5510         {
5511           Debug::print(Debug::FindMembers,0,"5. Match found\n");
5512           addMemberDocs(rootNav,md,decl,root->argList,FALSE);
5513           found=TRUE;
5514         }
5515       }
5516     } 
5517     if (!found && root->relatesType != Duplicate && root->section==Entry::FUNCTION_SEC) // no match
5518     {
5519       QCString fullFuncDecl=decl;
5520       if (root->argList) fullFuncDecl+=argListToString(root->argList,TRUE);
5521       QCString warnMsg =
5522          QCString("no matching file member found for \n")+substitute(fullFuncDecl,"%","%%");
5523       if (mn->count()>0)
5524       {
5525         warnMsg+="\nPossible candidates:\n";
5526         for (mni.toFirst();(md=mni.current());++mni)
5527         {
5528           warnMsg+=" '";
5529           warnMsg+=substitute(md->declaration(),"%","%%");
5530           warnMsg+="' at line "+QCString().setNum(md->getDefLine())+
5531                    " of file"+md->getDefFileName()+"\n";
5532         }
5533       }
5534       warn(root->fileName,root->startLine,warnMsg);
5535     }
5536   }
5537   else // got docs for an undefined member!
5538   {
5539     if (root->type!="friend class" && 
5540         root->type!="friend struct" &&
5541         root->type!="friend union" &&
5542         (!Config_getBool("TYPEDEF_HIDES_STRUCT") || 
5543          root->type.find("typedef ")==-1)
5544        )
5545     {
5546       warn(root->fileName,root->startLine,
5547            "documented symbol `%s' was not declared or defined.",decl
5548           );
5549     }
5550   }
5551   return TRUE;
5552 }
5553
5554 static bool isSpecialization(
5555                   const QList<ArgumentList> &srcTempArgLists,
5556                   const QList<ArgumentList> &dstTempArgLists
5557     )
5558 {
5559     QListIterator<ArgumentList> srclali(srcTempArgLists);
5560     QListIterator<ArgumentList> dstlali(dstTempArgLists);
5561     for (;srclali.current();++srclali,++dstlali)
5562     {
5563       ArgumentList *sal = srclali.current();
5564       ArgumentList *dal = dstlali.current();
5565       if (!(sal && dal && sal->count()==dal->count())) return TRUE;
5566     }
5567     return FALSE;
5568 }
5569
5570 static bool scopeIsTemplate(Definition *d)
5571 {
5572   bool result=FALSE;
5573   if (d && d->definitionType()==Definition::TypeClass)
5574   {
5575     result = ((ClassDef*)d)->templateArguments() || scopeIsTemplate(d->getOuterScope());
5576   }
5577   return result;
5578 }
5579
5580 static QCString substituteTemplatesInString(
5581     const QList<ArgumentList> &srcTempArgLists,
5582     const QList<ArgumentList> &dstTempArgLists,
5583     ArgumentList *funcTempArgList, // can be used to match template specializations
5584     const QCString &src
5585     )
5586 {
5587   QCString dst;
5588   QRegExp re( "[A-Za-z_][A-Za-z_0-9]*");
5589   //printf("type=%s\n",sa->type.data());
5590   int i,p=0,l; 
5591   while ((i=re.match(src,p,&l))!=-1) // for each word in srcType
5592   {
5593     bool found=FALSE;
5594     dst+=src.mid(p,i-p);
5595     QCString name=src.mid(i,l);
5596
5597     QListIterator<ArgumentList> srclali(srcTempArgLists);
5598     QListIterator<ArgumentList> dstlali(dstTempArgLists);
5599     for (;srclali.current() && !found;++srclali,++dstlali)
5600     {
5601       ArgumentListIterator tsali(*srclali.current());
5602       ArgumentListIterator tdali(*dstlali.current());
5603       ArgumentListIterator *fali=0;
5604       Argument *tsa =0,*tda=0, *fa=0;
5605       if (funcTempArgList)
5606       {
5607         fali = new ArgumentListIterator(*funcTempArgList);
5608         fa = fali->current();
5609       }
5610
5611       for (tsali.toFirst();(tsa=tsali.current()) && !found;++tsali)
5612       {
5613         tda = tdali.current();
5614         //if (tda) printf("tsa=%s|%s tda=%s|%s\n",
5615         //    tsa->type.data(),tsa->name.data(),
5616         //    tda->type.data(),tda->name.data());
5617         if (name==tsa->name)
5618         {
5619           if (tda && tda->name.isEmpty())
5620           {
5621             int vc=0;
5622             if (tda->type.left(6)=="class ") vc=6;
5623             else if (tda->type.left(9)=="typename ") vc=9;
5624             if (vc>0) // convert type=="class T" to type=="class" name=="T"
5625             {
5626               tda->name = tda->type.mid(vc);
5627               tda->type = tda->type.left(vc-1);
5628             }
5629           }
5630           if (tda && !tda->name.isEmpty())
5631           {
5632             name=tda->name; // substitute
5633             found=TRUE;
5634           }
5635           else if (fa)
5636           {
5637             name=fa->type;
5638             found=TRUE;
5639           }
5640         }
5641         if (tda)
5642           ++tdali;
5643         else if (fali)
5644         { ++(*fali); fa=fali->current(); }
5645       }
5646
5647       delete fali;
5648       //printf("   srcList='%s' dstList='%s faList='%s'\n",
5649       //  argListToString(srclali.current()).data(),
5650       //  argListToString(dstlali.current()).data(),
5651       //  funcTempArgList ? argListToString(funcTempArgList).data() : "<none>");
5652     }
5653     dst+=name; 
5654     p=i+l;
5655   }
5656   dst+=src.right(src.length()-p);
5657   //printf("  substituteTemplatesInString(%s)=%s\n",
5658   //    src.data(),dst.data());
5659   return dst;
5660 }
5661
5662 static void substituteTemplatesInArgList(
5663                   const QList<ArgumentList> &srcTempArgLists,
5664                   const QList<ArgumentList> &dstTempArgLists,
5665                   ArgumentList *src,
5666                   ArgumentList *dst,
5667                   ArgumentList *funcTempArgs = 0
5668                  )
5669 {
5670   ArgumentListIterator sali(*src);
5671   ArgumentListIterator dali(*dst);
5672   Argument *sa=0;
5673   Argument *da=dali.current();
5674
5675   for (sali.toFirst();(sa=sali.current());++sali) // for each member argument
5676   {
5677     QCString dstType = substituteTemplatesInString(
5678                                   srcTempArgLists,dstTempArgLists,funcTempArgs,
5679                                   sa->type);
5680     QCString dstArray = substituteTemplatesInString(
5681                                   srcTempArgLists,dstTempArgLists,funcTempArgs,
5682                                   sa->array);
5683     if (da==0)
5684     {
5685       da=new Argument(*sa);
5686       dst->append(da);
5687       da->type=dstType;
5688       da->array=dstArray;
5689       da=0;
5690     }
5691     else
5692     {
5693       da->type=dstType;
5694       da->type=dstArray;
5695       ++dali;
5696       da=dali.current();
5697     }
5698   }
5699   dst->constSpecifier     = src->constSpecifier;
5700   dst->volatileSpecifier  = src->volatileSpecifier;
5701   dst->pureSpecifier      = src->pureSpecifier;
5702   dst->trailingReturnType = substituteTemplatesInString(
5703                              srcTempArgLists,dstTempArgLists,
5704                              funcTempArgs,src->trailingReturnType);
5705   //printf("substituteTemplatesInArgList: replacing %s with %s\n",
5706   //    argListToString(src).data(),argListToString(dst).data()
5707   //    );
5708 }
5709
5710
5711
5712 /*! This function tries to find a member (in a documented class/file/namespace) 
5713  * that corresponds to the function/variable declaration given in \a funcDecl.
5714  *
5715  * The boolean \a overloaded is used to specify whether or not a standard
5716  * overload documentation line should be generated.
5717  *
5718  * The boolean \a isFunc is a hint that indicates that this is a function
5719  * instead of a variable or typedef.
5720  */
5721 static void findMember(EntryNav *rootNav,
5722                        QCString funcDecl,
5723                        bool overloaded,
5724                        bool isFunc
5725                       )
5726 {
5727   Entry *root = rootNav->entry();
5728
5729   Debug::print(Debug::FindMembers,0,
5730                "findMember(root=%p,funcDecl=`%s',related=`%s',overload=%d,"
5731                "isFunc=%d mGrpId=%d tArgList=%p (#=%d) "
5732                "spec=%lld lang=%x\n",
5733                root,funcDecl.data(),root->relates.data(),overloaded,isFunc,root->mGrpId,
5734                root->tArgLists,root->tArgLists ? root->tArgLists->count() : 0,
5735                root->spec,root->lang
5736               );
5737
5738   QCString scopeName;
5739   QCString className;
5740   QCString namespaceName;
5741   QCString funcType;
5742   QCString funcName;
5743   QCString funcArgs;
5744   QCString funcTempList;
5745   QCString exceptions;
5746   QCString funcSpec;
5747   bool isRelated=FALSE;
5748   bool isMemberOf=FALSE;
5749   bool isFriend=FALSE;
5750   bool done;
5751   do
5752   {
5753     done=TRUE;
5754     if (funcDecl.stripPrefix("friend ")) // treat friends as related members
5755     {
5756       isFriend=TRUE;
5757       done=FALSE;
5758     }
5759     if (funcDecl.stripPrefix("inline "))
5760     {
5761       root->spec|=Entry::Inline;
5762       done=FALSE;
5763     }
5764     if (funcDecl.stripPrefix("explicit "))
5765     {
5766       root->spec|=Entry::Explicit;
5767       done=FALSE;
5768     }
5769     if (funcDecl.stripPrefix("mutable "))
5770     {
5771       root->spec|=Entry::Mutable;
5772       done=FALSE;
5773     }
5774     if (funcDecl.stripPrefix("virtual "))
5775     {
5776       done=FALSE;
5777     }
5778   } while (!done);
5779
5780   // delete any ; from the function declaration
5781   int sep;
5782   while ((sep=funcDecl.find(';'))!=-1)
5783   {
5784     funcDecl=(funcDecl.left(sep)+funcDecl.right(funcDecl.length()-sep-1)).stripWhiteSpace();
5785   }
5786   
5787   // make sure the first character is a space to simplify searching.
5788   if (!funcDecl.isEmpty() && funcDecl[0]!=' ') funcDecl.prepend(" ");
5789   
5790   // remove some superfluous spaces
5791   funcDecl= substitute(
5792               substitute(
5793                 substitute(funcDecl,"~ ","~"),
5794                 ":: ","::"
5795               ),
5796               " ::","::"
5797             ).stripWhiteSpace();
5798   
5799   //printf("funcDecl=`%s'\n",funcDecl.data());
5800   if (isFriend && funcDecl.left(6)=="class ")
5801   {
5802     //printf("friend class\n");
5803     funcDecl=funcDecl.right(funcDecl.length()-6);
5804     funcName = funcDecl.copy();
5805   }
5806   else if (isFriend && funcDecl.left(7)=="struct ")
5807   {
5808     funcDecl=funcDecl.right(funcDecl.length()-7);
5809     funcName = funcDecl.copy();
5810   }
5811   else
5812   {
5813     // extract information from the declarations
5814     parseFuncDecl(funcDecl,root->lang==SrcLangExt_ObjC,scopeName,funcType,funcName,
5815                 funcArgs,funcTempList,exceptions
5816                );
5817   }
5818   //printf("scopeName=`%s' funcType=`%s' funcName=`%s' funcArgs=`%s'\n",
5819   //    scopeName.data(),funcType.data(),funcName.data(),funcArgs.data());
5820
5821   // the class name can also be a namespace name, we decide this later.
5822   // if a related class name is specified and the class name could
5823   // not be derived from the function declaration, then use the
5824   // related field.
5825   //printf("scopeName=`%s' className=`%s' namespaceName=`%s'\n",
5826   //    scopeName.data(),className.data(),namespaceName.data());
5827   if (!root->relates.isEmpty()) 
5828   {                             // related member, prefix user specified scope
5829     isRelated=TRUE;
5830     isMemberOf=(root->relatesType == MemberOf);
5831     if (getClass(root->relates)==0 && !scopeName.isEmpty())
5832     {
5833       scopeName= mergeScopes(scopeName,root->relates);
5834     }
5835     else 
5836     {
5837       scopeName = root->relates;
5838     }
5839   }
5840
5841   if (root->relates.isEmpty() && rootNav->parent() && 
5842       ((rootNav->parent()->section()&Entry::SCOPE_MASK) ||
5843        (rootNav->parent()->section()==Entry::OBJCIMPL_SEC)
5844       ) &&
5845       !rootNav->parent()->name().isEmpty()) // see if we can combine scopeName 
5846                                      // with the scope in which it was found
5847   {
5848     QCString joinedName = rootNav->parent()->name()+"::"+scopeName;
5849     if (!scopeName.isEmpty() && 
5850         (getClass(joinedName) || Doxygen::namespaceSDict->find(joinedName)))
5851     {
5852       scopeName = joinedName;
5853     }
5854     else
5855     {
5856       scopeName = mergeScopes(rootNav->parent()->name(),scopeName);
5857     }
5858   }
5859   else // see if we can prefix a namespace or class that is used from the file
5860   {
5861      FileDef *fd=rootNav->fileDef();
5862      if (fd)
5863      {
5864        NamespaceSDict *fnl = fd->getUsedNamespaces();
5865        if (fnl)
5866        {
5867          QCString joinedName;
5868          NamespaceDef *fnd;
5869          NamespaceSDict::Iterator nsdi(*fnl);
5870          for (nsdi.toFirst();(fnd=nsdi.current());++nsdi)
5871          {
5872            joinedName = fnd->name()+"::"+scopeName;
5873            if (Doxygen::namespaceSDict->find(joinedName))
5874            {
5875              scopeName=joinedName;
5876              break;
5877            }
5878          }
5879        }
5880      }
5881   }
5882   scopeName=stripTemplateSpecifiersFromScope(
5883       removeRedundantWhiteSpace(scopeName),FALSE,&funcSpec); 
5884
5885   // funcSpec contains the last template specifiers of the given scope.
5886   // If this method does not have any template arguments or they are 
5887   // empty while funcSpec is not empty we assume this is a 
5888   // specialization of a method. If not, we clear the funcSpec and treat
5889   // this as a normal method of a template class.
5890   if (!(root->tArgLists && 
5891         root->tArgLists->count()>0 &&
5892         root->tArgLists->getFirst()->count()==0
5893        )
5894      ) 
5895   {
5896     funcSpec.resize(0);
5897   }
5898   
5899   // split scope into a namespace and a class part
5900   extractNamespaceName(scopeName,className,namespaceName,TRUE);
5901   //printf("scopeName=`%s' className=`%s' namespaceName=`%s'\n",
5902   //       scopeName.data(),className.data(),namespaceName.data());
5903   
5904   //namespaceName=removeAnonymousScopes(namespaceName);
5905   if (namespaceName.find('@')!=-1) return; // skip stuff in anonymous namespace...
5906
5907   //printf("namespaceName=`%s' className=`%s'\n",namespaceName.data(),className.data());
5908   // merge class and namespace scopes again
5909   scopeName.resize(0);
5910   if (!namespaceName.isEmpty())
5911   {
5912     if (className.isEmpty())
5913     {
5914       scopeName=namespaceName;
5915     }
5916     else if (!root->relates.isEmpty() || // relates command with explicit scope
5917              !getClass(className)) // class name only exists in a namespace
5918     {
5919       scopeName=namespaceName+"::"+className;
5920     }
5921     else
5922     {
5923       scopeName=className;
5924     }
5925   }
5926   else if (!className.isEmpty())
5927   {
5928     scopeName=className;
5929   }
5930   //printf("new scope=`%s'\n",scopeName.data());
5931
5932   QCString tempScopeName=scopeName;
5933   ClassDef *cd=getClass(scopeName);
5934   if (cd)
5935   {
5936     if (funcSpec.isEmpty())
5937     {
5938       int argListIndex=0;
5939       tempScopeName=cd->qualifiedNameWithTemplateParameters(root->tArgLists,&argListIndex);
5940     }
5941     else
5942     {
5943       tempScopeName=scopeName+funcSpec;
5944     }
5945   }
5946   //printf("scopeName=%s cd=%p root->tArgLists=%p result=%s\n",
5947   //    scopeName.data(),cd,root->tArgLists,tempScopeName.data());
5948
5949   //printf("scopeName=`%s' className=`%s'\n",scopeName.data(),className.data());
5950   // rebuild the function declaration (needed to get the scope right).
5951   if (!scopeName.isEmpty() && !isRelated && !isFriend && !Config_getBool("HIDE_SCOPE_NAMES"))
5952   {
5953     if (!funcType.isEmpty())
5954     {
5955       if (isFunc) // a function -> we use argList for the arguments
5956       {
5957         funcDecl=funcType+" "+tempScopeName+"::"+funcName+funcTempList;
5958       }
5959       else
5960       {
5961         funcDecl=funcType+" "+tempScopeName+"::"+funcName+funcArgs;
5962       }
5963     }
5964     else
5965     {
5966       if (isFunc) // a function => we use argList for the arguments
5967       {
5968         funcDecl=tempScopeName+"::"+funcName+funcTempList;
5969       }
5970       else // variable => add `argument' list
5971       {
5972         funcDecl=tempScopeName+"::"+funcName+funcArgs;
5973       }
5974     }
5975   }
5976   else // build declaration without scope
5977   {
5978     if (!funcType.isEmpty()) // but with a type
5979     {
5980       if (isFunc) // function => omit argument list
5981       {
5982         funcDecl=funcType+" "+funcName+funcTempList;
5983       }
5984       else // variable => add `argument' list
5985       {
5986         funcDecl=funcType+" "+funcName+funcArgs;
5987       }
5988     }
5989     else // no type
5990     {
5991       if (isFunc)
5992       {
5993         funcDecl=funcName+funcTempList;
5994       }
5995       else
5996       {
5997         funcDecl=funcName+funcArgs;
5998       }
5999     }
6000   }
6001   
6002   if (funcType=="template class" && !funcTempList.isEmpty())
6003     return;   // ignore explicit template instantiations
6004   
6005   Debug::print(Debug::FindMembers,0,
6006            "findMember() Parse results:\n"
6007            "  namespaceName=`%s'\n"
6008            "  className=`%s`\n"
6009            "  funcType=`%s'\n"
6010            "  funcSpec=`%s'\n"
6011            "  funcName=`%s'\n"
6012            "  funcArgs=`%s'\n"
6013            "  funcTempList=`%s'\n"
6014            "  funcDecl=`%s'\n"
6015            "  related=`%s'\n" 
6016            "  exceptions=`%s'\n"
6017            "  isRelated=%d\n"
6018            "  isMemberOf=%d\n"
6019            "  isFriend=%d\n"
6020            "  isFunc=%d\n\n",
6021            namespaceName.data(),className.data(),
6022            funcType.data(),funcSpec.data(),funcName.data(),funcArgs.data(),funcTempList.data(),
6023            funcDecl.data(),root->relates.data(),exceptions.data(),isRelated,isMemberOf,isFriend,
6024            isFunc
6025           );
6026
6027   MemberName *mn=0;
6028   if (!funcName.isEmpty()) // function name is valid
6029   { 
6030     Debug::print(Debug::FindMembers,0,
6031                  "1. funcName=`%s'\n",funcName.data());
6032     if (funcName.left(9)=="operator ") // strip class scope from cast operator
6033     {
6034       funcName = substitute(funcName,className+"::","");
6035     }
6036     if (!funcTempList.isEmpty()) // try with member specialization
6037     {
6038       mn=Doxygen::memberNameSDict->find(funcName+funcTempList);
6039     }
6040     if (mn==0) // try without specialization
6041     {
6042       mn=Doxygen::memberNameSDict->find(funcName);
6043     }
6044     if (!isRelated && mn) // function name already found
6045     {
6046       Debug::print(Debug::FindMembers,0,
6047                    "2. member name exists (%d members with this name)\n",mn->count());
6048       if (!className.isEmpty()) // class name is valid
6049       {
6050         if (funcSpec.isEmpty()) // not a member specialization
6051         {
6052           int count=0;
6053           int noMatchCount=0;
6054           MemberNameIterator mni(*mn);
6055           MemberDef *md;
6056           bool memFound=FALSE;
6057           for (mni.toFirst();!memFound && (md=mni.current());++mni)
6058           {
6059             ClassDef *cd=md->getClassDef();
6060             Debug::print(Debug::FindMembers,0,
6061                 "3. member definition found, "
6062                 "scope needed=`%s' scope=`%s' args=`%s' fileName=%s\n",
6063                 scopeName.data(),cd ? cd->name().data() : "<none>",
6064                 md->argsString(),
6065                 root->fileName.data());
6066             //printf("Member %s (member scopeName=%s) (this scopeName=%s) classTempList=%s\n",md->name().data(),cd->name().data(),scopeName.data(),classTempList.data());
6067             FileDef *fd=rootNav->fileDef();
6068             NamespaceDef *nd=0;
6069             if (!namespaceName.isEmpty()) nd=getResolvedNamespace(namespaceName);
6070
6071             //printf("scopeName %s->%s\n",scopeName.data(),
6072             //       stripTemplateSpecifiersFromScope(scopeName,FALSE).data());
6073
6074             ClassDef *tcd=findClassDefinition(fd,nd,scopeName);
6075             if (tcd==0 && stripAnonymousNamespaceScope(cd->name())==scopeName)
6076             {
6077               // don't be fooled by anonymous scopes
6078               tcd=cd;
6079             }
6080             //printf("Looking for %s inside nd=%s result=%p (%s) cd=%p\n",
6081             //    scopeName.data(),nd?nd->name().data():"<none>",tcd,tcd?tcd->name().data():"",cd);
6082
6083             if (cd && tcd==cd) // member's classes match
6084             {
6085               Debug::print(Debug::FindMembers,0,
6086                   "4. class definition %s found\n",cd->name().data());
6087
6088               // get the template parameter lists found at the member declaration
6089               QList<ArgumentList> declTemplArgs;
6090               cd->getTemplateParameterLists(declTemplArgs);
6091               ArgumentList *templAl = md->templateArguments();
6092               if (templAl)
6093               {
6094                 declTemplArgs.append(templAl);
6095               }
6096
6097               // get the template parameter lists found at the member definition
6098               QList<ArgumentList> *defTemplArgs = root->tArgLists;
6099               //printf("defTemplArgs=%p\n",defTemplArgs);
6100
6101               // do we replace the decl argument lists with the def argument lists?
6102               bool substDone=FALSE;
6103               ArgumentList *argList=0;
6104
6105               /* substitute the occurrences of class template names in the 
6106                * argument list before matching 
6107                */
6108               ArgumentList *mdAl = md->argumentList();
6109               if (declTemplArgs.count()>0 && defTemplArgs &&
6110                   declTemplArgs.count()==defTemplArgs->count() &&
6111                   mdAl
6112                  )
6113               {
6114                 /* the function definition has template arguments
6115                  * and the class definition also has template arguments, so
6116                  * we must substitute the template names of the class by that
6117                  * of the function definition before matching.
6118                  */
6119                 argList = new ArgumentList;
6120                 substituteTemplatesInArgList(declTemplArgs,*defTemplArgs,
6121                     mdAl,argList);
6122
6123                 substDone=TRUE;
6124               }
6125               else /* no template arguments, compare argument lists directly */
6126               {
6127                 argList = mdAl;
6128               }
6129
6130               Debug::print(Debug::FindMembers,0,
6131                   "5. matching `%s'<=>`%s' className=%s namespaceName=%s\n",
6132                   argListToString(argList,TRUE).data(),argListToString(root->argList,TRUE).data(),
6133                   className.data(),namespaceName.data()
6134                   );
6135
6136               bool matching=
6137                 md->isVariable() || md->isTypedef() || // needed for function pointers
6138                 (mdAl==0 && root->argList->count()==0) || 
6139                 matchArguments2(
6140                     md->getClassDef(),md->getFileDef(),argList, 
6141                     cd,fd,root->argList,
6142                     TRUE);
6143
6144               if (md->getLanguage()==SrcLangExt_ObjC && md->isVariable() && (root->section&Entry::FUNCTION_SEC))
6145               {
6146                 matching = FALSE; // don't match methods and attributes with the same name
6147               }
6148
6149               // for template member we also need to check the return type
6150               if (md->templateArguments()!=0 && root->tArgLists!=0)
6151               {
6152                 QCString memType = md->typeString();
6153                 memType.stripPrefix("static "); // see bug700696
6154                 funcType=substitute(funcType,className+"::",""); // see bug700693
6155                 Debug::print(Debug::FindMembers,0,
6156                    "5b. Comparing return types '%s'<->'%s' #args %d<->%d\n",
6157                     md->typeString(),funcType.data(),
6158                     md->templateArguments()->count(),root->tArgLists->getLast()->count());
6159                 if (md->templateArguments()->count()!=root->tArgLists->getLast()->count() ||
6160                     qstrcmp(memType,funcType))
6161                 {
6162                   //printf(" ---> no matching\n");
6163                   matching = FALSE;
6164                 }
6165               }
6166               bool rootIsUserDoc = (root->section&Entry::MEMBERDOC_SEC)!=0;
6167               bool classIsTemplate = scopeIsTemplate(md->getClassDef());
6168               bool mdIsTemplate    = md->templateArguments()!=0;
6169               bool classOrMdIsTemplate = mdIsTemplate || classIsTemplate;
6170               bool rootIsTemplate  = root->tArgLists!=0;
6171               //printf("classIsTemplate=%d mdIsTemplate=%d rootIsTemplate=%d\n",classIsTemplate,mdIsTemplate,rootIsTemplate);
6172               if (!rootIsUserDoc && // don't check out-of-line @fn references, see bug722457
6173                   (mdIsTemplate || rootIsTemplate) && // either md or root is a template
6174                   ((classOrMdIsTemplate && !rootIsTemplate) || (!classOrMdIsTemplate && rootIsTemplate))
6175                  )
6176               {
6177                 // Method with template return type does not match method without return type
6178                 // even if the parameters are the same. See also bug709052
6179                 Debug::print(Debug::FindMembers,0,
6180                     "5b. Comparing return types: template v.s. non-template\n");
6181                 matching = FALSE;
6182               }
6183
6184
6185               Debug::print(Debug::FindMembers,0,
6186                   "6. match results of matchArguments2 = %d\n",matching);
6187
6188               if (substDone) // found a new argument list
6189               {
6190                 if (matching) // replace member's argument list
6191                 {
6192                   md->setDefinitionTemplateParameterLists(root->tArgLists);
6193                   md->setArgumentList(argList); // new owner of the list => no delete
6194                 }
6195                 else // no match 
6196                 {
6197                   if (!funcTempList.isEmpty() && 
6198                       isSpecialization(declTemplArgs,*defTemplArgs))
6199                   {
6200                     // check if we are dealing with a partial template
6201                     // specialization. In this case we add it to the class
6202                     // even though the member arguments do not match.
6203                     
6204                     // TODO: copy other aspects?
6205                     root->protection=md->protection(); // copy protection level
6206                     addMethodToClass(rootNav,cd,md->name(),isFriend);
6207                     return;
6208                   }
6209                   delete argList;
6210                 }
6211               }
6212               if (matching) 
6213               {
6214                 addMemberDocs(rootNav,md,funcDecl,0,overloaded,0/* TODO */);
6215                 count++;
6216                 memFound=TRUE;
6217               }
6218             } 
6219             else if (cd && cd!=tcd) // we did find a class with the same name as cd
6220                                     // but in a different namespace
6221             {
6222               noMatchCount++;
6223             }
6224           } 
6225           if (count==0 && rootNav->parent() && 
6226               rootNav->parent()->section()==Entry::OBJCIMPL_SEC)
6227           {
6228             goto localObjCMethod;
6229           }
6230           if (count==0 && !(isFriend && funcType=="class"))
6231           {
6232             int candidates=0;
6233             ClassDef *ecd = 0, *ucd = 0;
6234             MemberDef *emd = 0, *umd = 0;
6235             if (mn->count()>0)
6236             {
6237               //printf("Assume template class\n");
6238               for (mni.toFirst();(md=mni.current());++mni)
6239               {
6240                 ClassDef *ccd=md->getClassDef();
6241                 MemberDef *cmd=md;
6242                 //printf("ccd->name()==%s className=%s\n",ccd->name().data(),className.data());
6243                 if (ccd!=0 && rightScopeMatch(ccd->name(),className)) 
6244                 {
6245                   ArgumentList *templAl = md->templateArguments();
6246                   if (root->tArgLists && templAl!=0 &&
6247                       root->tArgLists->getLast()->count()<=templAl->count())
6248                   { 
6249                     addMethodToClass(rootNav,ccd,md->name(),isFriend);
6250                     return;
6251                   }
6252                   if (md->argsString()==argListToString(root->argList,TRUE,FALSE))
6253                   { // exact argument list match -> remember
6254                     ucd = ecd = ccd;
6255                     umd = emd = cmd;
6256                     Debug::print(Debug::FindMembers,0,
6257                      "7. new candidate className=%s scope=%s args=%s exact match\n",
6258                          className.data(),ccd->name().data(),md->argsString());
6259                   }
6260                   else // arguments do not match, but member name and scope do -> remember
6261                   {
6262                     ucd = ccd;
6263                     umd = cmd;
6264                     Debug::print(Debug::FindMembers,0,
6265                      "7. new candidate className=%s scope=%s args=%s no match\n",
6266                          className.data(),ccd->name().data(),md->argsString());
6267                   }
6268                   candidates++;
6269                 }
6270               }
6271             }
6272             static bool strictProtoMatching = Config_getBool("STRICT_PROTO_MATCHING");
6273             if (!strictProtoMatching)
6274             {
6275               if (candidates==1 && ucd && umd)
6276               {
6277                 // we didn't find an actual match on argument lists, but there is only 1 member with this
6278                 // name in the same scope, so that has to be the one. 
6279                 addMemberDocs(rootNav,umd,funcDecl,0,overloaded,0);
6280                 return;
6281               }
6282               else if (candidates>1 && ecd && emd)
6283               {
6284                 // we didn't find a unique match using type resolution, 
6285                 // but one of the matches has the exact same signature so
6286                 // we take that one.
6287                 addMemberDocs(rootNav,emd,funcDecl,0,overloaded,0);
6288                 return;
6289               }
6290             }
6291
6292             QCString warnMsg = "no ";
6293             if (noMatchCount>1) warnMsg+="uniquely ";
6294             warnMsg+="matching class member found for \n";
6295
6296             if (root->tArgLists)
6297             {
6298               QListIterator<ArgumentList> alli(*root->tArgLists);
6299               ArgumentList *al;
6300               for (;(al=alli.current());++alli)
6301               {
6302                 warnMsg+="  template ";
6303                 warnMsg+=tempArgListToString(al);
6304                 warnMsg+='\n';
6305               }
6306             }
6307             QCString fullFuncDecl=funcDecl.copy();
6308             if (isFunc) fullFuncDecl+=argListToString(root->argList,TRUE);
6309
6310             warnMsg+="  ";
6311             warnMsg+=fullFuncDecl;
6312             warnMsg+='\n';
6313
6314             if (candidates>0)
6315             {
6316               warnMsg+="Possible candidates:\n";
6317               for (mni.toFirst();(md=mni.current());++mni)
6318               {
6319                 ClassDef *cd=md->getClassDef();
6320                 if (cd!=0 && rightScopeMatch(cd->name(),className))
6321                 {
6322                   ArgumentList *templAl = md->templateArguments();
6323                   if (templAl!=0)
6324                   {
6325                     warnMsg+="  'template ";
6326                     warnMsg+=tempArgListToString(templAl);
6327                     warnMsg+='\n';
6328                   }
6329                   warnMsg+="  ";
6330                   if (md->typeString()) 
6331                   {
6332                     warnMsg+=md->typeString();
6333                     warnMsg+=' ';
6334                   }
6335                   QCString qScope = cd->qualifiedNameWithTemplateParameters();
6336                   if (!qScope.isEmpty()) 
6337                     warnMsg+=qScope+"::"+md->name();
6338                   if (md->argsString()) 
6339                     warnMsg+=md->argsString();
6340                   if (noMatchCount>1) 
6341                   {
6342                     warnMsg+="' at line "+QCString().setNum(md->getDefLine()) +
6343                              " of file "+md->getDefFileName();
6344                   }
6345
6346                   warnMsg+='\n';
6347                 }
6348               }
6349             }
6350             warn_simple(root->fileName,root->startLine,warnMsg);
6351           }
6352         }
6353         else if (cd) // member specialization
6354         {
6355           MemberNameIterator mni(*mn);
6356           MemberDef *declMd=0;
6357           MemberDef *md=0;
6358           for (mni.toFirst();(md=mni.current());++mni)
6359           {
6360             if (md->getClassDef()==cd) 
6361             {
6362               // TODO: we should probably also check for matching arguments
6363               declMd = md;
6364               break;
6365             }
6366           }
6367           MemberType mtype=MemberType_Function;
6368           ArgumentList *tArgList = new ArgumentList;
6369           //  getTemplateArgumentsFromName(cd->name()+"::"+funcName,root->tArgLists);
6370           md=new MemberDef(
6371               root->fileName,root->startLine,root->startColumn,
6372               funcType,funcName,funcArgs,exceptions,
6373               declMd ? declMd->protection() : root->protection,
6374               root->virt,root->stat,Member,
6375               mtype,tArgList,root->argList);
6376           //printf("new specialized member %s args=`%s'\n",md->name().data(),funcArgs.data());
6377           md->setTagInfo(rootNav->tagInfo());
6378           md->setLanguage(root->lang);
6379           md->setId(root->id);
6380           md->setMemberClass(cd);
6381           md->setTemplateSpecialization(TRUE);
6382           md->setTypeConstraints(root->typeConstr);
6383           md->setDefinition(funcDecl);
6384           md->enableCallGraph(root->callGraph);
6385           md->enableCallerGraph(root->callerGraph);
6386           md->setDocumentation(root->doc,root->docFile,root->docLine);
6387           md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
6388           md->setDocsForDefinition(!root->proto);
6389           md->setPrototype(root->proto);
6390           md->addSectionsToDefinition(root->anchors);
6391           md->setBodySegment(root->bodyLine,root->endBodyLine);
6392           FileDef *fd=rootNav->fileDef();
6393           md->setBodyDef(fd);
6394           md->setMemberSpecifiers(root->spec);
6395           md->setMemberGroupId(root->mGrpId);
6396           mn->append(md);
6397           cd->insertMember(md);
6398           md->setRefItems(root->sli);
6399           delete tArgList;
6400         }
6401         else
6402         {
6403           //printf("*** Specialized member %s of unknown scope %s%s found!\n",
6404           //        scopeName.data(),funcName.data(),funcArgs.data());
6405         }
6406       }
6407       else if (overloaded) // check if the function belongs to only one class 
6408       {
6409         // for unique overloaded member we allow the class to be
6410         // omitted, this is to be Qt compatible. Using this should 
6411         // however be avoided, because it is error prone
6412         MemberNameIterator mni(*mn);
6413         MemberDef *md=mni.toFirst();
6414         ASSERT(md);
6415         ClassDef *cd=md->getClassDef();
6416         ASSERT(cd);
6417         QCString className=cd->name().copy();
6418         ++mni;
6419         bool unique=TRUE;
6420         for (;(md=mni.current());++mni)
6421         {
6422           ClassDef *cd=md->getClassDef();
6423           if (className!=cd->name()) unique=FALSE; 
6424         } 
6425         if (unique)
6426         {
6427           MemberType mtype;
6428           if      (root->mtype==Signal)  mtype=MemberType_Signal;
6429           else if (root->mtype==Slot)    mtype=MemberType_Slot;
6430           else if (root->mtype==DCOP)    mtype=MemberType_DCOP;
6431           else                           mtype=MemberType_Function;
6432           
6433           // new overloaded member function
6434           ArgumentList *tArgList = 
6435             getTemplateArgumentsFromName(cd->name()+"::"+funcName,root->tArgLists);
6436           //printf("new related member %s args=`%s'\n",md->name().data(),funcArgs.data());
6437           MemberDef *md=new MemberDef(
6438               root->fileName,root->startLine,root->startColumn,
6439               funcType,funcName,funcArgs,exceptions,
6440               root->protection,root->virt,root->stat,Related,
6441               mtype,tArgList,root->argList);
6442           md->setTagInfo(rootNav->tagInfo());
6443           md->setLanguage(root->lang);
6444           md->setId(root->id);
6445           md->setTypeConstraints(root->typeConstr);
6446           md->setMemberClass(cd);
6447           md->setDefinition(funcDecl);
6448           md->enableCallGraph(root->callGraph);
6449           md->enableCallerGraph(root->callerGraph);
6450           QCString doc=getOverloadDocs();
6451           doc+="<p>";
6452           doc+=root->doc;
6453           md->setDocumentation(doc,root->docFile,root->docLine);
6454           md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
6455           md->setDocsForDefinition(!root->proto);
6456           md->setPrototype(root->proto);
6457           md->addSectionsToDefinition(root->anchors);
6458           md->setBodySegment(root->bodyLine,root->endBodyLine);
6459           FileDef *fd=rootNav->fileDef();
6460           md->setBodyDef(fd);
6461           md->setMemberSpecifiers(root->spec);
6462           md->setMemberGroupId(root->mGrpId);
6463           mn->append(md);
6464           cd->insertMember(md);
6465           cd->insertUsedFile(fd);
6466           md->setRefItems(root->sli);
6467         }
6468       }
6469       else // unrelated function with the same name as a member
6470       {
6471         if (!findGlobalMember(rootNav,namespaceName,funcType,funcName,funcTempList,funcArgs,funcDecl))
6472         {
6473           QCString fullFuncDecl=funcDecl.copy();
6474           if (isFunc) fullFuncDecl+=argListToString(root->argList,TRUE);
6475           warn(root->fileName,root->startLine,
6476                "Cannot determine class for function\n%s",
6477                fullFuncDecl.data()
6478               );   
6479         }
6480       }
6481     }
6482     else if (isRelated && !root->relates.isEmpty())
6483     {
6484       Debug::print(Debug::FindMembers,0,"2. related function\n"
6485               "  scopeName=%s className=%s\n",scopeName.data(),className.data());
6486       if (className.isEmpty()) className=root->relates;
6487       ClassDef *cd;
6488       //printf("scopeName=`%s' className=`%s'\n",scopeName.data(),className.data());
6489       if ((cd=getClass(scopeName)))
6490       {
6491         bool newMember=TRUE; // assume we have a new member
6492         bool newMemberName=FALSE; 
6493         MemberDef *mdDefine=0;
6494         bool isDefine=FALSE;
6495         {
6496           MemberName *mn = Doxygen::functionNameSDict->find(funcName);
6497           if (mn)
6498           {
6499             MemberNameIterator mni(*mn);
6500             mdDefine = mni.current();
6501             while (mdDefine && !isDefine)
6502             {
6503               isDefine = isDefine || mdDefine->isDefine();
6504               if (!isDefine) { ++mni; mdDefine=mni.current(); }
6505             }
6506           }
6507         }
6508
6509         FileDef *fd=rootNav->fileDef();
6510
6511         if ((mn=Doxygen::memberNameSDict->find(funcName))==0)
6512         {
6513           mn=new MemberName(funcName);
6514           newMemberName=TRUE; // we create a new member name
6515         }
6516         else
6517         {
6518           MemberNameIterator mni(*mn);
6519           MemberDef *rmd;
6520           while ((rmd=mni.current()) && newMember) // see if we got another member with matching arguments
6521           {
6522             ArgumentList *rmdAl = rmd->argumentList();
6523
6524             newMember=
6525               className!=rmd->getOuterScope()->name() ||
6526               !matchArguments2(rmd->getOuterScope(),rmd->getFileDef(),rmdAl,
6527                                cd,fd,root->argList,
6528                                TRUE);
6529             if (newMember) ++mni;
6530           }
6531           if (!newMember && rmd) // member already exists as rmd -> add docs
6532           {
6533             //printf("addMemberDocs for related member %s\n",root->name.data());
6534             //rmd->setMemberDefTemplateArguments(root->mtArgList);
6535             addMemberDocs(rootNav,rmd,funcDecl,0,overloaded);
6536           }
6537         }
6538
6539         if (newMember) // need to create a new member
6540         {
6541           MemberType mtype;
6542           if (isDefine)
6543             mtype=MemberType_Define;
6544           else if (root->mtype==Signal)  
6545             mtype=MemberType_Signal;
6546           else if (root->mtype==Slot) 
6547             mtype=MemberType_Slot;
6548           else if (root->mtype==DCOP)
6549             mtype=MemberType_DCOP;
6550           else
6551             mtype=MemberType_Function;
6552
6553           if (isDefine && mdDefine)
6554           {
6555             mdDefine->setHidden(TRUE);
6556             funcType="#define";
6557             funcArgs=mdDefine->argsString();
6558             funcDecl=funcType + " " + funcName;
6559           } 
6560
6561           //printf("New related name `%s' `%d'\n",funcName.data(),
6562           //    root->argList ? (int)root->argList->count() : -1);
6563
6564           // first note that we pass:
6565           //   (root->tArgLists ? root->tArgLists->last() : 0)
6566           // for the template arguments fo the new "member."
6567           // this accurately reflects the template arguments of
6568           // the related function, which don't have to do with
6569           // those of the related class.
6570           MemberDef *md=new MemberDef(
6571               root->fileName,root->startLine,root->startColumn,
6572               funcType,funcName,funcArgs,exceptions,
6573               root->protection,root->virt,
6574               root->stat && !isMemberOf,
6575               isMemberOf ? Foreign : isRelated ? Related : Member,
6576               mtype,
6577               (root->tArgLists ? root->tArgLists->getLast() : 0),
6578               funcArgs.isEmpty() ? 0 : root->argList);
6579
6580           if (isDefine && mdDefine)
6581           {
6582             md->setInitializer(mdDefine->initializer());
6583           }
6584
6585           // 
6586           // we still have the problem that
6587           // MemberDef::writeDocumentation() in memberdef.cpp
6588           // writes the template argument list for the class,
6589           // as if this member is a member of the class.
6590           // fortunately, MemberDef::writeDocumentation() has
6591           // a special mechanism that allows us to totally
6592           // override the set of template argument lists that
6593           // are printed.  We use that and set it to the
6594           // template argument lists of the related function.
6595           //
6596           md->setDefinitionTemplateParameterLists(root->tArgLists);
6597
6598           md->setTagInfo(rootNav->tagInfo());
6599
6600
6601
6602           //printf("Related member name=`%s' decl=`%s' bodyLine=`%d'\n",
6603           //       funcName.data(),funcDecl.data(),root->bodyLine);
6604
6605           // try to find the matching line number of the body from the
6606           // global function list 
6607           bool found=FALSE;
6608           if (root->bodyLine==-1)
6609           {
6610             MemberName *rmn=Doxygen::functionNameSDict->find(funcName);
6611             if (rmn)
6612             {
6613               MemberNameIterator rmni(*rmn);
6614               MemberDef *rmd;
6615               while ((rmd=rmni.current()) && !found) // see if we got another member with matching arguments
6616               {
6617                 ArgumentList *rmdAl = rmd->argumentList();
6618                 // check for matching argument lists
6619                 if (
6620                     matchArguments2(rmd->getOuterScope(),rmd->getFileDef(),rmdAl,
6621                                     cd,fd,root->argList,
6622                                     TRUE)
6623                    )
6624                 {
6625                   found=TRUE;
6626                 }
6627                 if (!found) ++rmni;
6628               }
6629               if (rmd) // member found -> copy line number info
6630               {
6631                 md->setBodySegment(rmd->getStartBodyLine(),rmd->getEndBodyLine());
6632                 md->setBodyDef(rmd->getBodyDef());
6633                 //md->setBodyMember(rmd);
6634               }
6635             }
6636           }
6637           if (!found) // line number could not be found or is available in this
6638                       // entry
6639           {
6640             md->setBodySegment(root->bodyLine,root->endBodyLine);
6641             md->setBodyDef(fd);
6642           }
6643
6644           //if (root->mGrpId!=-1) 
6645           //{
6646           //  md->setMemberGroup(memberGroupDict[root->mGrpId]);
6647           //}
6648           md->setMemberClass(cd);
6649           md->setMemberSpecifiers(root->spec);
6650           md->setDefinition(funcDecl);
6651           md->enableCallGraph(root->callGraph);
6652           md->enableCallerGraph(root->callerGraph);
6653           md->setDocumentation(root->doc,root->docFile,root->docLine);
6654           md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
6655           md->setDocsForDefinition(!root->proto);
6656           md->setPrototype(root->proto);
6657           md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
6658           md->addSectionsToDefinition(root->anchors);
6659           md->setMemberGroupId(root->mGrpId);
6660           md->setLanguage(root->lang);
6661           md->setId(root->id);
6662           //md->setMemberDefTemplateArguments(root->mtArgList);
6663           mn->append(md);
6664           cd->insertMember(md);
6665           cd->insertUsedFile(fd);
6666           md->setRefItems(root->sli);
6667           if (root->relatesType == Duplicate) md->setRelatedAlso(cd);
6668           if (!isDefine)
6669           {
6670             addMemberToGroups(root,md);
6671           }
6672           //printf("Adding member=%s\n",md->name().data());
6673           if (newMemberName)
6674           {
6675             //Doxygen::memberNameList.append(mn);
6676             //Doxygen::memberNameDict.insert(funcName,mn);
6677             Doxygen::memberNameSDict->append(funcName,mn);
6678           }
6679         }
6680         if (root->relatesType == Duplicate)
6681         {
6682           if (!findGlobalMember(rootNav,namespaceName,funcType,funcName,funcTempList,funcArgs,funcDecl))
6683           {
6684             QCString fullFuncDecl=funcDecl.copy();
6685             if (isFunc) fullFuncDecl+=argListToString(root->argList,TRUE);
6686             warn(root->fileName,root->startLine,
6687                "Cannot determine file/namespace for relatedalso function\n%s",
6688                fullFuncDecl.data()
6689               );   
6690           }
6691         }
6692       }
6693       else
6694       {
6695         warn_undoc(root->fileName,root->startLine,
6696                    "class `%s' for related function `%s' is not "
6697                    "documented.", 
6698                    className.data(),funcName.data()
6699                   );
6700       }
6701     }
6702     else if (rootNav->parent() && rootNav->parent()->section()==Entry::OBJCIMPL_SEC)
6703     {
6704 localObjCMethod:
6705       ClassDef *cd;
6706       //printf("scopeName=`%s' className=`%s'\n",scopeName.data(),className.data());
6707       if (Config_getBool("EXTRACT_LOCAL_METHODS") && (cd=getClass(scopeName)))
6708       {
6709         Debug::print(Debug::FindMembers,0,"4. Local objective C method %s\n"
6710               "  scopeName=%s className=%s\n",root->name.data(),scopeName.data(),className.data());
6711         //printf("Local objective C method `%s' of class `%s' found\n",root->name.data(),cd->name().data());
6712         MemberDef *md=new MemberDef(
6713             root->fileName,root->startLine,root->startColumn,
6714             funcType,funcName,funcArgs,exceptions,
6715             root->protection,root->virt,root->stat,Member,
6716             MemberType_Function,0,root->argList);
6717         md->setTagInfo(rootNav->tagInfo());
6718         md->setLanguage(root->lang);
6719         md->setId(root->id);
6720         md->makeImplementationDetail();
6721         md->setMemberClass(cd);
6722         md->setDefinition(funcDecl);
6723         md->enableCallGraph(root->callGraph);
6724         md->enableCallerGraph(root->callerGraph);
6725         md->setDocumentation(root->doc,root->docFile,root->docLine);
6726         md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
6727         md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
6728         md->setDocsForDefinition(!root->proto);
6729         md->setPrototype(root->proto);
6730         md->addSectionsToDefinition(root->anchors);
6731         md->setBodySegment(root->bodyLine,root->endBodyLine);
6732         FileDef *fd=rootNav->fileDef();
6733         md->setBodyDef(fd);
6734         md->setMemberSpecifiers(root->spec);
6735         md->setMemberGroupId(root->mGrpId);
6736         cd->insertMember(md);
6737         cd->insertUsedFile(fd);
6738         md->setRefItems(root->sli);
6739         if ((mn=Doxygen::memberNameSDict->find(root->name)))
6740         {
6741           mn->append(md);
6742         }
6743         else 
6744         {
6745           mn = new MemberName(root->name);
6746           mn->append(md);
6747           Doxygen::memberNameSDict->append(root->name,mn);
6748         }
6749       }
6750       else
6751       {
6752         // local objective C method found for class without interface
6753       }
6754     }
6755     else // unrelated not overloaded member found
6756     {
6757       bool globMem = findGlobalMember(rootNav,namespaceName,funcType,funcName,funcTempList,funcArgs,funcDecl);
6758       if (className.isEmpty() && !globMem)
6759       {
6760         warn(root->fileName,root->startLine,
6761              "class for member `%s' cannot "
6762              "be found.", funcName.data()
6763             ); 
6764       }
6765       else if (!className.isEmpty() && !globMem)
6766       {
6767         warn(root->fileName,root->startLine,
6768              "member `%s' of class `%s' cannot be found",
6769              funcName.data(),className.data());
6770       }
6771     }
6772   }
6773   else
6774   {
6775     // this should not be called
6776     warn(root->fileName,root->startLine,
6777          "member with no name found.");
6778   }
6779   return;
6780
6781
6782 //----------------------------------------------------------------------
6783 // find the members corresponding to the different documentation blocks
6784 // that are extracted from the sources.
6785
6786 static void filterMemberDocumentation(EntryNav *rootNav)
6787 {
6788   Entry *root = rootNav->entry();
6789   int i=-1,l;
6790   Debug::print(Debug::FindMembers,0,
6791       "findMemberDocumentation(): root->type=`%s' root->inside=`%s' root->name=`%s' root->args=`%s' section=%x root->spec=%lld root->mGrpId=%d\n",
6792       root->type.data(),root->inside.data(),root->name.data(),root->args.data(),root->section,root->spec,root->mGrpId
6793       );
6794   //printf("rootNav->parent()->name()=%s\n",rootNav->parent()->name().data());
6795   bool isFunc=TRUE;
6796
6797   if (root->relatesType == Duplicate && !root->relates.isEmpty())
6798   {
6799     QCString tmp = root->relates;
6800     root->relates.resize(0);
6801     filterMemberDocumentation(rootNav);
6802     root->relates = tmp;
6803   }
6804
6805   if ( // detect func variable/typedef to func ptr
6806       (i=findFunctionPtr(root->type,root->lang,&l))!=-1 
6807      )
6808   {
6809     //printf("Fixing function pointer!\n");
6810     // fix type and argument
6811     root->args.prepend(root->type.right(root->type.length()-i-l));
6812     root->type=root->type.left(i+l);
6813     //printf("Results type=%s,name=%s,args=%s\n",root->type.data(),root->name.data(),root->args.data());
6814     isFunc=FALSE;
6815   }
6816   else if ((root->type.left(8)=="typedef " && root->args.find('(')!=-1)) 
6817     // detect function types marked as functions
6818   {
6819     isFunc=FALSE;
6820   }
6821
6822   //printf("Member %s isFunc=%d\n",root->name.data(),isFunc);
6823   if (root->section==Entry::MEMBERDOC_SEC)
6824   {
6825     //printf("Documentation for inline member `%s' found args=`%s'\n",
6826     //    root->name.data(),root->args.data());
6827     //if (root->relates.length()) printf("  Relates %s\n",root->relates.data());
6828     if (root->type.isEmpty())
6829     {
6830       findMember(rootNav,root->name+root->args+root->exception,FALSE,isFunc);
6831     }
6832     else
6833     {
6834       findMember(rootNav,root->type+" "+root->name+root->args+root->exception,FALSE,isFunc);
6835     }
6836   }
6837   else if (root->section==Entry::OVERLOADDOC_SEC) 
6838   {
6839     //printf("Overloaded member %s found\n",root->name.data());
6840     findMember(rootNav,root->name,TRUE,isFunc);
6841   }
6842   else if 
6843     ((root->section==Entry::FUNCTION_SEC      // function
6844       ||   
6845       (root->section==Entry::VARIABLE_SEC &&  // variable
6846        !root->type.isEmpty() &&                // with a type
6847        g_compoundKeywordDict.find(root->type)==0 // that is not a keyword 
6848        // (to skip forward declaration of class etc.)
6849       )
6850      ) 
6851     )
6852     {
6853       //printf("Documentation for member `%s' found args=`%s' excp=`%s'\n",
6854       //    root->name.data(),root->args.data(),root->exception.data());
6855       //if (root->relates.length()) printf("  Relates %s\n",root->relates.data());
6856       //printf("Inside=%s\n Relates=%s\n",root->inside.data(),root->relates.data());
6857       if (root->type=="friend class" || root->type=="friend struct" || 
6858           root->type=="friend union")
6859       {
6860         findMember(rootNav,
6861             root->type+" "+
6862             root->name,
6863             FALSE,FALSE);
6864
6865       }
6866       else if (!root->type.isEmpty())
6867       {
6868         findMember(rootNav,
6869             root->type+" "+
6870             root->inside+
6871             root->name+
6872             root->args+
6873             root->exception,
6874             FALSE,isFunc);
6875       }
6876       else
6877       {
6878         findMember(rootNav,
6879             root->inside+
6880             root->name+
6881             root->args+
6882             root->exception,
6883             FALSE,isFunc);
6884       }
6885     }
6886   else if (root->section==Entry::DEFINE_SEC && !root->relates.isEmpty())
6887   {
6888     findMember(rootNav,root->name+root->args,FALSE,!root->args.isEmpty());
6889   }
6890   else if (root->section==Entry::VARIABLEDOC_SEC)
6891   {
6892     //printf("Documentation for variable %s found\n",root->name.data());
6893     //if (!root->relates.isEmpty()) printf("  Relates %s\n",root->relates.data());
6894     findMember(rootNav,root->name,FALSE,FALSE);
6895   }
6896   else if (root->section==Entry::EXPORTED_INTERFACE_SEC ||
6897            root->section==Entry::INCLUDED_SERVICE_SEC)
6898   {
6899     findMember(rootNav,root->type + " " + root->name,FALSE,FALSE);
6900   }
6901   else
6902   {
6903     // skip section 
6904     //printf("skip section\n");
6905   }
6906 }
6907
6908 static void findMemberDocumentation(EntryNav *rootNav)
6909 {
6910   if (rootNav->section()==Entry::MEMBERDOC_SEC ||
6911       rootNav->section()==Entry::OVERLOADDOC_SEC ||
6912       rootNav->section()==Entry::FUNCTION_SEC ||
6913       rootNav->section()==Entry::VARIABLE_SEC ||
6914       rootNav->section()==Entry::VARIABLEDOC_SEC ||
6915       rootNav->section()==Entry::DEFINE_SEC ||
6916       rootNav->section()==Entry::INCLUDED_SERVICE_SEC ||
6917       rootNav->section()==Entry::EXPORTED_INTERFACE_SEC
6918      )
6919   {
6920     rootNav->loadEntry(g_storage);
6921
6922     filterMemberDocumentation(rootNav);
6923
6924     rootNav->releaseEntry();
6925   }
6926   if (rootNav->children())
6927   {
6928     EntryNavListIterator eli(*rootNav->children());
6929     EntryNav *e;
6930     for (;(e=eli.current());++eli)
6931     {
6932       if (e->section()!=Entry::ENUM_SEC) findMemberDocumentation(e);
6933     }
6934   }
6935 }
6936
6937 //----------------------------------------------------------------------
6938
6939 static void findObjCMethodDefinitions(EntryNav *rootNav)
6940 {
6941   if (rootNav->children())
6942   {
6943     EntryNavListIterator eli(*rootNav->children());
6944     EntryNav *objCImplNav;
6945     for (;(objCImplNav=eli.current());++eli)
6946     {
6947       if (objCImplNav->section()==Entry::OBJCIMPL_SEC && objCImplNav->children())
6948       {
6949         EntryNavListIterator seli(*objCImplNav->children());
6950         EntryNav *objCMethodNav;
6951         for (;(objCMethodNav=seli.current());++seli)
6952         {
6953           if (objCMethodNav->section()==Entry::FUNCTION_SEC)
6954           {
6955             objCMethodNav->loadEntry(g_storage);
6956             Entry *objCMethod = objCMethodNav->entry();
6957
6958             //Printf("  Found ObjC method definition %s\n",objCMethod->name.data());
6959             findMember(objCMethodNav, objCMethod->type+" "+objCImplNav->name()+"::"+
6960                        objCMethod->name+" "+objCMethod->args, FALSE,TRUE);
6961             objCMethod->section=Entry::EMPTY_SEC;
6962
6963             objCMethodNav->releaseEntry();
6964           }
6965         }
6966       }
6967     }
6968   }
6969 }
6970
6971 //----------------------------------------------------------------------
6972 // find and add the enumeration to their classes, namespaces or files
6973
6974 static void findEnums(EntryNav *rootNav)
6975 {
6976   if (rootNav->section()==Entry::ENUM_SEC)
6977   {
6978     rootNav->loadEntry(g_storage);
6979     Entry *root = rootNav->entry();
6980
6981     MemberDef      *md=0;
6982     ClassDef       *cd=0;
6983     FileDef        *fd=0;
6984     NamespaceDef   *nd=0;
6985     MemberNameSDict *mnsd=0;
6986     bool isGlobal;
6987     bool isRelated=FALSE;
6988     bool isMemberOf=FALSE;
6989     //printf("Found enum with name `%s' relates=%s\n",root->name.data(),root->relates.data());
6990     int i;
6991
6992     QCString name;
6993     QCString scope;
6994
6995     if ((i=root->name.findRev("::"))!=-1) // scope is specified
6996     {
6997       scope=root->name.left(i); // extract scope
6998       name=root->name.right(root->name.length()-i-2); // extract name
6999       if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope);
7000     }
7001     else // no scope, check the scope in which the docs where found
7002     {
7003       if (( rootNav->parent()->section() & Entry::SCOPE_MASK )
7004           && !rootNav->parent()->name().isEmpty()
7005          ) // found enum docs inside a compound
7006       {
7007         scope=rootNav->parent()->name();
7008         if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope);
7009       }
7010       name=root->name;
7011     }
7012
7013     if (!root->relates.isEmpty()) 
7014     {   // related member, prefix user specified scope
7015       isRelated=TRUE;
7016       isMemberOf=(root->relatesType == MemberOf);
7017       if (getClass(root->relates)==0 && !scope.isEmpty())
7018         scope=mergeScopes(scope,root->relates);
7019       else 
7020         scope=root->relates.copy();
7021       if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope);
7022     }
7023
7024     if (cd && !name.isEmpty()) // found a enum inside a compound
7025     {
7026       //printf("Enum `%s'::`%s'\n",cd->name(),name.data());
7027       fd=0;
7028       mnsd=Doxygen::memberNameSDict;
7029       isGlobal=FALSE;
7030     }
7031     else if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@') // found enum inside namespace
7032     {
7033       mnsd=Doxygen::functionNameSDict;
7034       isGlobal=TRUE;
7035     }
7036     else // found a global enum
7037     {
7038       fd=rootNav->fileDef();
7039       mnsd=Doxygen::functionNameSDict;
7040       isGlobal=TRUE;
7041     }
7042
7043     if (!name.isEmpty())
7044     {
7045       // new enum type
7046       md = new MemberDef(
7047           root->fileName,root->startLine,root->startColumn,
7048           0,name,0,0,
7049           root->protection,Normal,FALSE,
7050           isMemberOf ? Foreign : isRelated ? Related : Member,
7051           MemberType_Enumeration,
7052           0,0);
7053       md->setTagInfo(rootNav->tagInfo());
7054       md->setLanguage(root->lang);
7055       md->setId(root->id);
7056       if (!isGlobal) md->setMemberClass(cd); else md->setFileDef(fd);
7057       md->setBodySegment(root->bodyLine,root->endBodyLine);
7058       md->setBodyDef(rootNav->fileDef());
7059       md->setMemberSpecifiers(root->spec); // UNO IDL "published"
7060       md->setEnumBaseType(root->args);
7061       //printf("Enum %s definition at line %d of %s: protection=%d\n",
7062       //    root->name.data(),root->bodyLine,root->fileName.data(),root->protection);
7063       md->addSectionsToDefinition(root->anchors);
7064       md->setMemberGroupId(root->mGrpId);
7065       md->enableCallGraph(root->callGraph);
7066       md->enableCallerGraph(root->callerGraph);
7067       //printf("%s::setRefItems(%d)\n",md->name().data(),root->sli?root->sli->count():-1);
7068       md->setRefItems(root->sli);
7069       //printf("found enum %s nd=%p\n",name.data(),nd);
7070       bool defSet=FALSE;
7071
7072       QCString baseType = root->args;
7073       if (!baseType.isEmpty())
7074       {
7075         baseType.prepend(" : ");
7076       }
7077
7078       if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@')
7079       {
7080         if (isRelated || Config_getBool("HIDE_SCOPE_NAMES"))
7081         {
7082           md->setDefinition(name+baseType);  
7083         }
7084         else
7085         {
7086           md->setDefinition(nd->name()+"::"+name+baseType);  
7087         }
7088         //printf("definition=%s\n",md->definition());
7089         defSet=TRUE;
7090         md->setNamespace(nd);
7091         nd->insertMember(md);
7092       }
7093
7094       // even if we have already added the enum to a namespace, we still
7095       // also want to add it to other appropriate places such as file
7096       // or class.
7097       if (isGlobal)
7098       {
7099         if (!defSet) md->setDefinition(name+baseType);
7100         if (fd==0 && rootNav->parent())
7101         {
7102           fd=rootNav->parent()->fileDef();
7103         }
7104         if (fd) 
7105         {
7106           md->setFileDef(fd);
7107           fd->insertMember(md);
7108         }
7109       }
7110       else if (cd)
7111       {
7112         if (isRelated || Config_getBool("HIDE_SCOPE_NAMES"))
7113         {
7114           md->setDefinition(name+baseType);  
7115         }
7116         else
7117         {
7118           md->setDefinition(cd->name()+"::"+name+baseType);  
7119         }
7120         cd->insertMember(md);
7121         cd->insertUsedFile(fd);
7122       }
7123       md->setDocumentation(root->doc,root->docFile,root->docLine);
7124       md->setDocsForDefinition(!root->proto);
7125       md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
7126       md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
7127
7128       //printf("Adding member=%s\n",md->name().data());
7129       MemberName *mn;
7130       if ((mn=(*mnsd)[name]))
7131       {
7132         // this is used if the same enum is in multiple namespaces/classes
7133         mn->append(md);
7134       }
7135       else // new enum name
7136       {
7137         mn = new MemberName(name);
7138         mn->append(md);
7139         mnsd->append(name,mn);
7140         //printf("add %s to new memberName. Now %d members\n",
7141         //       name.data(),mn->count());
7142       }
7143       addMemberToGroups(root,md);
7144     }
7145     rootNav->releaseEntry();
7146   }
7147   else
7148   {
7149     RECURSE_ENTRYTREE(findEnums,rootNav);
7150   }
7151 }
7152
7153 //----------------------------------------------------------------------
7154
7155 static void addEnumValuesToEnums(EntryNav *rootNav)
7156 {
7157   if (rootNav->section()==Entry::ENUM_SEC)
7158     // non anonymous enumeration
7159   {
7160     rootNav->loadEntry(g_storage);
7161     Entry *root = rootNav->entry();
7162
7163     ClassDef       *cd=0;
7164     FileDef        *fd=0;
7165     NamespaceDef   *nd=0;
7166     MemberNameSDict *mnsd=0;
7167     bool isGlobal;
7168     bool isRelated=FALSE;
7169     //printf("Found enum with name `%s' relates=%s\n",root->name.data(),root->relates.data());
7170     int i;
7171
7172     QCString name;
7173     QCString scope;
7174
7175     if ((i=root->name.findRev("::"))!=-1) // scope is specified
7176     {
7177       scope=root->name.left(i); // extract scope
7178       name=root->name.right(root->name.length()-i-2); // extract name
7179       if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope);
7180     }
7181     else // no scope, check the scope in which the docs where found
7182     {
7183       if (( rootNav->parent()->section() & Entry::SCOPE_MASK )
7184           && !rootNav->parent()->name().isEmpty()
7185          ) // found enum docs inside a compound
7186       {
7187         scope=rootNav->parent()->name();
7188         if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope);
7189       }
7190       name=root->name;
7191     }
7192
7193     if (!root->relates.isEmpty()) 
7194     {   // related member, prefix user specified scope
7195       isRelated=TRUE;
7196       if (getClass(root->relates)==0 && !scope.isEmpty())
7197         scope=mergeScopes(scope,root->relates);
7198       else 
7199         scope=root->relates.copy();
7200       if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope);
7201     }
7202
7203     if (cd && !name.isEmpty()) // found a enum inside a compound
7204     {
7205       //printf("Enum in class `%s'::`%s'\n",cd->name().data(),name.data());
7206       fd=0;
7207       mnsd=Doxygen::memberNameSDict;
7208       isGlobal=FALSE;
7209     }
7210     else if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@') // found enum inside namespace
7211     {
7212       //printf("Enum in namespace `%s'::`%s'\n",nd->name().data(),name.data());
7213       mnsd=Doxygen::functionNameSDict;
7214       isGlobal=TRUE;
7215     }
7216     else // found a global enum
7217     {
7218       fd=rootNav->fileDef();
7219       //printf("Enum in file `%s': `%s'\n",fd->name().data(),name.data());
7220       mnsd=Doxygen::functionNameSDict;
7221       isGlobal=TRUE;
7222     }
7223
7224     if (!name.isEmpty())
7225     {
7226       //printf("** name=%s\n",name.data());
7227       MemberName *mn = mnsd->find(name); // for all members with this name
7228       if (mn)
7229       {
7230         MemberNameIterator mni(*mn);
7231         MemberDef *md;
7232         for (mni.toFirst(); (md=mni.current()) ; ++mni)  // for each enum in this list
7233         {
7234           if (md->isEnumerate() && rootNav->children())
7235           {
7236             //printf("   enum with %d children\n",rootNav->children()->count());
7237             EntryNavListIterator eli(*rootNav->children()); // for each enum value
7238             EntryNav *e;
7239             for (;(e=eli.current());++eli)
7240             {
7241               SrcLangExt sle;
7242               if (
7243                    (sle=rootNav->lang())==SrcLangExt_CSharp || 
7244                    sle==SrcLangExt_Java || 
7245                    sle==SrcLangExt_XML ||
7246                    (root->spec&Entry::Strong)
7247                  )
7248               {
7249                 // Unlike classic C/C++ enums, for C++11, C# & Java enum 
7250                 // values are only visible inside the enum scope, so we must create 
7251                 // them here and only add them to the enum
7252                 e->loadEntry(g_storage);
7253                 Entry *root = e->entry();
7254                 //printf("md->qualifiedName()=%s rootNav->name()=%s tagInfo=%p name=%s\n",
7255                 //    md->qualifiedName().data(),rootNav->name().data(),rootNav->tagInfo(),root->name.data());
7256                 if (substitute(md->qualifiedName(),"::",".")== // TODO: add function to get canonical representation
7257                     substitute(rootNav->name(),"::",".") ||    // enum value scope matches that of the enum
7258                     rootNav->tagInfo()                         // be less strict for tag files as members can have incomplete scope
7259                    ) 
7260                 {
7261                   MemberDef *fmd=new MemberDef(
7262                       root->fileName,root->startLine,root->startColumn,
7263                       root->type,root->name,root->args,0,
7264                       Public, Normal,root->stat,Member,
7265                       MemberType_EnumValue,0,0);
7266                   if      (md->getClassDef())     fmd->setMemberClass(md->getClassDef());
7267                   else if (md->getNamespaceDef()) fmd->setNamespace(md->getNamespaceDef());
7268                   else if (md->getFileDef())      fmd->setFileDef(md->getFileDef());
7269                   fmd->setOuterScope(md->getOuterScope());
7270                   fmd->setTagInfo(e->tagInfo());
7271                   fmd->setLanguage(root->lang);
7272                   fmd->setId(root->id);
7273                   fmd->setDocumentation(root->doc,root->docFile,root->docLine);
7274                   fmd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
7275                   fmd->addSectionsToDefinition(root->anchors);
7276                   fmd->setInitializer(root->initializer);
7277                   fmd->setMaxInitLines(root->initLines);
7278                   fmd->setMemberGroupId(root->mGrpId);
7279                   fmd->setExplicitExternal(root->explicitExternal);
7280                   fmd->setRefItems(root->sli);
7281                   fmd->setAnchor();
7282                   md->insertEnumField(fmd);
7283                   fmd->setEnumScope(md,TRUE);
7284                   MemberName *mn=mnsd->find(root->name);
7285                   if (mn)
7286                   {
7287                     mn->append(fmd);
7288                   }
7289                   else 
7290                   {
7291                     mn = new MemberName(root->name);
7292                     mn->append(fmd);
7293                     mnsd->append(root->name,mn);
7294                   }
7295                 }
7296                 e->releaseEntry();
7297               }
7298               else
7299               {
7300                 //printf("e->name=%s isRelated=%d\n",e->name().data(),isRelated);
7301                 MemberName *fmn=0;
7302                 MemberNameSDict *emnsd = isRelated ? Doxygen::functionNameSDict : mnsd;
7303                 if (!e->name().isEmpty() && (fmn=(*emnsd)[e->name()])) 
7304                   // get list of members with the same name as the field
7305                 {
7306                   MemberNameIterator fmni(*fmn);
7307                   MemberDef *fmd;
7308                   for (fmni.toFirst(); (fmd=fmni.current()) ; ++fmni) 
7309                   {
7310                     if (fmd->isEnumValue() && fmd->getOuterScope()==md->getOuterScope()) // in same scope
7311                     {
7312                       //printf("found enum value with same name %s in scope %s\n",
7313                       //    fmd->name().data(),fmd->getOuterScope()->name().data());
7314                       if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@')
7315                       {
7316                         NamespaceDef *fnd=fmd->getNamespaceDef();
7317                         if (fnd==nd) // enum value is inside a namespace
7318                         {
7319                           md->insertEnumField(fmd);
7320                           fmd->setEnumScope(md);
7321                         }
7322                       }
7323                       else if (isGlobal)
7324                       {
7325                         FileDef *ffd=fmd->getFileDef();
7326                         if (ffd==fd) // enum value has file scope
7327                         {
7328                           md->insertEnumField(fmd);
7329                           fmd->setEnumScope(md);
7330                         }
7331                       }
7332                       else if (isRelated && cd) // reparent enum value to
7333                                                 // match the enum's scope
7334                       {
7335                         md->insertEnumField(fmd);   // add field def to list
7336                         fmd->setEnumScope(md);      // cross ref with enum name
7337                         fmd->setEnumClassScope(cd); // cross ref with enum name
7338                         fmd->setOuterScope(cd);
7339                         fmd->makeRelated();
7340                         cd->insertMember(fmd);
7341                       }
7342                       else
7343                       {
7344                         ClassDef *fcd=fmd->getClassDef();
7345                         if (fcd==cd) // enum value is inside a class
7346                         {
7347                           //printf("Inserting enum field %s in enum scope %s\n",
7348                           //    fmd->name().data(),md->name().data());
7349                           md->insertEnumField(fmd); // add field def to list
7350                           fmd->setEnumScope(md);    // cross ref with enum name
7351                         }
7352                       }
7353                     } 
7354                   }
7355                 }
7356               }
7357             }
7358           }
7359         }
7360       }
7361     }
7362
7363     rootNav->releaseEntry();
7364   }
7365   else
7366   {
7367     RECURSE_ENTRYTREE(addEnumValuesToEnums,rootNav);
7368   }
7369 }
7370
7371
7372 //----------------------------------------------------------------------
7373 // find the documentation blocks for the enumerations
7374
7375 static void findEnumDocumentation(EntryNav *rootNav)
7376 {
7377   if (rootNav->section()==Entry::ENUMDOC_SEC
7378       && !rootNav->name().isEmpty()
7379       && rootNav->name().at(0)!='@'        // skip anonymous enums
7380      )
7381   {
7382     rootNav->loadEntry(g_storage);
7383     Entry *root = rootNav->entry();
7384
7385     //printf("Found docs for enum with name `%s' in context %s\n",
7386     //    root->name.data(),root->parent->name.data());
7387     int i;
7388     QCString name;
7389     QCString scope;
7390     if ((i=root->name.findRev("::"))!=-1) // scope is specified as part of the name
7391     {
7392       name=root->name.right(root->name.length()-i-2); // extract name
7393       scope=root->name.left(i); // extract scope
7394       //printf("Scope=`%s' Name=`%s'\n",scope.data(),name.data());
7395     }
7396     else // just the name
7397     {
7398       name=root->name;
7399     }
7400     if (( rootNav->parent()->section() & Entry::SCOPE_MASK )
7401         && !rootNav->parent()->name().isEmpty()
7402        ) // found enum docs inside a compound
7403     {
7404       if (!scope.isEmpty()) scope.prepend("::");
7405       scope.prepend(rootNav->parent()->name());
7406     }
7407     ClassDef *cd=getClass(scope);
7408
7409     if (!name.isEmpty())
7410     {
7411       bool found=FALSE;
7412       if (cd)
7413       {
7414         //printf("Enum: scope=`%s' name=`%s'\n",cd->name(),name.data());
7415         QCString className=cd->name().copy();
7416         MemberName *mn=Doxygen::memberNameSDict->find(name);
7417         if (mn)
7418         {
7419           MemberNameIterator mni(*mn);
7420           MemberDef *md;
7421           for (mni.toFirst();(md=mni.current()) && !found;++mni)
7422           {
7423             ClassDef *cd=md->getClassDef();
7424             if (cd && cd->name()==className && md->isEnumerate())
7425             {
7426               // documentation outside a compound overrides the documentation inside it
7427 #if 0
7428               if (!md->documentation() || rootNav->parent()->name().isEmpty()) 
7429 #endif
7430               {
7431                 md->setDocumentation(root->doc,root->docFile,root->docLine);
7432                 md->setDocsForDefinition(!root->proto);
7433               }
7434
7435               // brief descriptions inside a compound override the documentation 
7436               // outside it
7437 #if 0
7438               if (!md->briefDescription() || !rootNav->parent()->name().isEmpty())
7439 #endif
7440               {
7441                 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
7442               }
7443
7444               if (!md->inbodyDocumentation() || !rootNav->parent()->name().isEmpty())
7445               {
7446                 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
7447               }
7448
7449               if (root->mGrpId!=-1 && md->getMemberGroupId()==-1)
7450               {
7451                 md->setMemberGroupId(root->mGrpId);
7452               }
7453
7454               md->addSectionsToDefinition(root->anchors);
7455               md->setRefItems(root->sli);
7456
7457               GroupDef *gd=md->getGroupDef();
7458               if (gd==0 &&root->groups->getFirst()!=0) // member not grouped but out-of-line documentation is
7459               {
7460                 addMemberToGroups(root,md);
7461               }
7462
7463               found=TRUE;
7464             }
7465           }
7466         }
7467         else
7468         {
7469           //printf("MemberName %s not found!\n",name.data());
7470         }
7471       }
7472       else // enum outside class 
7473       {
7474         //printf("Enum outside class: %s grpId=%d\n",name.data(),root->mGrpId);
7475         MemberName *mn=Doxygen::functionNameSDict->find(name);
7476         if (mn)
7477         {
7478           MemberNameIterator mni(*mn);
7479           MemberDef *md;
7480           for (mni.toFirst();(md=mni.current()) && !found;++mni)
7481           {
7482             if (md->isEnumerate())
7483             {
7484               md->setDocumentation(root->doc,root->docFile,root->docLine);
7485               md->setDocsForDefinition(!root->proto);
7486               md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
7487               md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
7488               md->addSectionsToDefinition(root->anchors);
7489               md->setMemberGroupId(root->mGrpId);
7490
7491               GroupDef *gd=md->getGroupDef();
7492               if (gd==0 && root->groups->getFirst()!=0) // member not grouped but out-of-line documentation is
7493               {
7494                 addMemberToGroups(root,md);
7495               }
7496
7497               found=TRUE;
7498             }
7499           }
7500         }
7501       } 
7502       if (!found)
7503       {
7504         warn(root->fileName,root->startLine,
7505              "Documentation for undefined enum `%s' found.",
7506              name.data()
7507             );
7508       }
7509     }
7510
7511     rootNav->releaseEntry();
7512   }
7513   RECURSE_ENTRYTREE(findEnumDocumentation,rootNav);
7514 }
7515
7516 // search for each enum (member or function) in mnl if it has documented 
7517 // enum values.
7518 static void findDEV(const MemberNameSDict &mnsd)
7519 {
7520   MemberName *mn;
7521   MemberNameSDict::Iterator mnli(mnsd);
7522   // for each member name
7523   for (mnli.toFirst();(mn=mnli.current());++mnli)
7524   {
7525     MemberDef *md;
7526     MemberNameIterator mni(*mn);
7527     // for each member definition
7528     for (mni.toFirst();(md=mni.current());++mni)
7529     {
7530       if (md->isEnumerate()) // member is an enum
7531       {
7532         MemberList *fmdl = md->enumFieldList();
7533         int documentedEnumValues=0;
7534         if (fmdl) // enum has values
7535         {
7536           MemberListIterator fmni(*fmdl);
7537           MemberDef *fmd;
7538           // for each enum value
7539           for (fmni.toFirst();(fmd=fmni.current());++fmni)
7540           {
7541             if (fmd->isLinkableInProject()) documentedEnumValues++;
7542           }
7543         }
7544         // at least one enum value is documented
7545         if (documentedEnumValues>0) md->setDocumentedEnumValues(TRUE);
7546       }
7547     }
7548   }
7549 }
7550
7551 // search for each enum (member or function) if it has documented enum 
7552 // values.
7553 static void findDocumentedEnumValues()
7554 {
7555   findDEV(*Doxygen::memberNameSDict);
7556   findDEV(*Doxygen::functionNameSDict); 
7557 }
7558
7559 //----------------------------------------------------------------------
7560
7561 static void addMembersToIndex()
7562 {
7563   MemberName *mn;
7564   MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
7565   // for each member name
7566   for (mnli.toFirst();(mn=mnli.current());++mnli)
7567   {
7568     MemberDef *md;
7569     MemberNameIterator mni(*mn);
7570     // for each member definition
7571     for (mni.toFirst();(md=mni.current());++mni)
7572     {
7573       addClassMemberNameToIndex(md);
7574     }
7575   }
7576   MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict);
7577   // for each member name
7578   for (fnli.toFirst();(mn=fnli.current());++fnli)
7579   {
7580     MemberDef *md;
7581     MemberNameIterator mni(*mn);
7582     // for each member definition
7583     for (mni.toFirst();(md=mni.current());++mni)
7584     {
7585       if (md->getNamespaceDef())
7586       {
7587         addNamespaceMemberNameToIndex(md);
7588       }
7589       else
7590       {
7591         addFileMemberNameToIndex(md);
7592       }
7593     }
7594   }
7595 }
7596
7597 //----------------------------------------------------------------------
7598 // computes the relation between all members. For each member `m'
7599 // the members that override the implementation of `m' are searched and
7600 // the member that `m' overrides is searched.
7601
7602 static void computeMemberRelations()
7603 {
7604   MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
7605   MemberName *mn;
7606   for ( ; (mn=mnli.current()) ; ++mnli ) // for each member name
7607   {
7608     MemberNameIterator mdi(*mn);
7609     MemberNameIterator bmdi(*mn);
7610     MemberDef *md;
7611     MemberDef *bmd;
7612     for ( ; (md=mdi.current()) ; ++mdi ) // for each member with a specific name
7613     {
7614       for ( bmdi.toFirst() ; (bmd=bmdi.current()); ++bmdi ) // for each other member with the same name
7615       {
7616         ClassDef *mcd  = md->getClassDef();
7617         if (mcd && mcd->baseClasses())
7618         {
7619           ClassDef *bmcd = bmd->getClassDef();
7620           //printf("Check relation between `%s'::`%s' (%p) and `%s'::`%s' (%p)\n",
7621           //      mcd->name().data(),md->name().data(),md,
7622           //       bmcd->name().data(),bmd->name().data(),bmd
7623           //      );
7624           if (md!=bmd && bmcd && mcd && bmcd!=mcd &&
7625               (bmd->virtualness()!=Normal || 
7626                bmcd->compoundType()==ClassDef::Interface || 
7627                bmcd->compoundType()==ClassDef::Protocol
7628               ) &&
7629               md->isFunction() && 
7630               mcd->isLinkable() && 
7631               bmcd->isLinkable() &&
7632               mcd->isBaseClass(bmcd,TRUE))
7633           {
7634             //printf("  derived scope\n");
7635             ArgumentList *bmdAl = bmd->argumentList();
7636             ArgumentList *mdAl =  md->argumentList();
7637             //printf(" Base argList=`%s'\n Super argList=`%s'\n",
7638             //        argListToString(bmdAl.pointer()).data(),
7639             //        argListToString(mdAl.pointer()).data()
7640             //      );
7641             if ( 
7642                 matchArguments2(bmd->getOuterScope(),bmd->getFileDef(),bmdAl,
7643                   md->getOuterScope(), md->getFileDef(), mdAl,
7644                   TRUE
7645                   ) 
7646                )
7647             {
7648               MemberDef *rmd;
7649               if ((rmd=md->reimplements())==0 ||
7650                   minClassDistance(mcd,bmcd)<minClassDistance(mcd,rmd->getClassDef())
7651                  )
7652               {
7653                 //printf("setting (new) reimplements member\n");
7654                 md->setReimplements(bmd);
7655               }
7656               //printf("%s: add reimplementedBy member %s\n",bmcd->name().data(),mcd->name().data());
7657               bmd->insertReimplementedBy(md);
7658             }
7659           }
7660         }
7661       }
7662     }
7663   }
7664 }
7665
7666
7667 //----------------------------------------------------------------------------
7668 //static void computeClassImplUsageRelations()
7669 //{
7670 //  ClassDef *cd;
7671 //  ClassSDict::Iterator cli(*Doxygen::classSDict);
7672 //  for (;(cd=cli.current());++cli)
7673 //  {
7674 //    cd->determineImplUsageRelation();
7675 //  }
7676 //}
7677
7678 //----------------------------------------------------------------------------
7679
7680 static void createTemplateInstanceMembers()
7681 {
7682   ClassSDict::Iterator cli(*Doxygen::classSDict);
7683   ClassDef *cd;
7684   // for each class
7685   for (cli.toFirst();(cd=cli.current());++cli)
7686   {
7687     // that is a template
7688     QDict<ClassDef> *templInstances = cd->getTemplateInstances();
7689     if (templInstances)
7690     {
7691       QDictIterator<ClassDef> qdi(*templInstances);
7692       ClassDef *tcd=0;
7693       // for each instance of the template
7694       for (qdi.toFirst();(tcd=qdi.current());++qdi)
7695       {
7696         tcd->addMembersToTemplateInstance(cd,qdi.currentKey());
7697       }
7698     }
7699   }
7700 }
7701
7702 //----------------------------------------------------------------------------
7703
7704 static void mergeCategories()
7705 {
7706   ClassDef *cd;
7707   ClassSDict::Iterator cli(*Doxygen::classSDict);
7708   // merge members of categories into the class they extend
7709   for (cli.toFirst();(cd=cli.current());++cli)
7710   {
7711     int i=cd->name().find('(');
7712     if (i!=-1) // it is an Objective-C category
7713     {
7714       QCString baseName=cd->name().left(i);
7715       ClassDef *baseClass=Doxygen::classSDict->find(baseName);
7716       if (baseClass)
7717       {
7718         //printf("*** merging members of category %s into %s\n",
7719         //    cd->name().data(),baseClass->name().data());
7720         baseClass->mergeCategory(cd);
7721       }
7722     }
7723   }
7724 }
7725
7726 // builds the list of all members for each class
7727
7728 static void buildCompleteMemberLists()
7729 {
7730   ClassDef *cd;
7731   ClassSDict::Iterator cli(*Doxygen::classSDict);
7732   // merge the member list of base classes into the inherited classes.
7733   for (cli.toFirst();(cd=cli.current());++cli)
7734   {
7735     if (// !cd->isReference() && // not an external class
7736          cd->subClasses()==0 && // is a root of the hierarchy
7737          cd->baseClasses()) // and has at least one base class
7738     {
7739       //printf("*** merging members for %s\n",cd->name().data());
7740       cd->mergeMembers();
7741     }
7742   }
7743   // now sort the member list of all classes.
7744   for (cli.toFirst();(cd=cli.current());++cli)
7745   {
7746     if (cd->memberNameInfoSDict()) cd->memberNameInfoSDict()->sort();
7747   }
7748 }
7749
7750 //----------------------------------------------------------------------------
7751
7752 static void generateFileSources()
7753 {
7754   if (Doxygen::inputNameList->count()>0)
7755   {
7756 #if USE_LIBCLANG
7757     static bool clangAssistedParsing = Config_getBool("CLANG_ASSISTED_PARSING");
7758     if (clangAssistedParsing)
7759     {
7760       QDict<void> g_processedFiles(10007);
7761
7762       // create a dictionary with files to process
7763       QDict<void> g_filesToProcess(10007);
7764       FileNameListIterator fnli(*Doxygen::inputNameList); 
7765       FileName *fn;
7766       for (fnli.toFirst();(fn=fnli.current());++fnli)
7767       {
7768         FileNameIterator fni(*fn);
7769         FileDef *fd;
7770         for (;(fd=fni.current());++fni)
7771         {
7772           g_filesToProcess.insert(fd->absFilePath(),(void*)0x8);
7773         }
7774       }
7775       // process source files (and their include dependencies)
7776       for (fnli.toFirst();(fn=fnli.current());++fnli)
7777       {
7778         FileNameIterator fni(*fn);
7779         FileDef *fd;
7780         for (;(fd=fni.current());++fni)
7781         {
7782           if (fd->isSource() && !fd->isReference())
7783           {
7784             QStrList filesInSameTu;
7785             fd->getAllIncludeFilesRecursively(filesInSameTu);
7786             fd->startParsing();
7787             if (fd->generateSourceFile()) // sources need to be shown in the output
7788             {
7789               msg("Generating code for file %s...\n",fd->docName().data());
7790               fd->writeSource(*g_outputList,FALSE,filesInSameTu);
7791
7792             }
7793             else if (!fd->isReference() && Doxygen::parseSourcesNeeded)
7794               // we needed to parse the sources even if we do not show them
7795             {
7796               msg("Parsing code for file %s...\n",fd->docName().data());
7797               fd->parseSource(FALSE,filesInSameTu);
7798             }
7799
7800             char *incFile = filesInSameTu.first();
7801             while (incFile && g_filesToProcess.find(incFile))
7802             {
7803               if (fd->absFilePath()!=incFile && !g_processedFiles.find(incFile))
7804               {
7805                 QStrList moreFiles;
7806                 bool ambig;
7807                 FileDef *ifd=findFileDef(Doxygen::inputNameDict,incFile,ambig);
7808                 if (ifd && !ifd->isReference())
7809                 {
7810                   if (ifd->generateSourceFile()) // sources need to be shown in the output
7811                   {
7812                     msg(" Generating code for file %s...\n",ifd->docName().data());
7813                     ifd->writeSource(*g_outputList,TRUE,moreFiles);
7814
7815                   }
7816                   else if (!ifd->isReference() && Doxygen::parseSourcesNeeded)
7817                     // we needed to parse the sources even if we do not show them
7818                   {
7819                     msg(" Parsing code for file %s...\n",ifd->docName().data());
7820                     ifd->parseSource(TRUE,moreFiles);
7821                   }
7822                   g_processedFiles.insert(incFile,(void*)0x8);
7823                 }
7824               }
7825               incFile = filesInSameTu.next();
7826             }
7827             fd->finishParsing();
7828             g_processedFiles.insert(fd->absFilePath(),(void*)0x8);
7829           }
7830         }
7831       }
7832       // process remaining files
7833       for (fnli.toFirst();(fn=fnli.current());++fnli)
7834       {
7835         FileNameIterator fni(*fn);
7836         FileDef *fd;
7837         for (;(fd=fni.current());++fni)
7838         {
7839           if (!g_processedFiles.find(fd->absFilePath())) // not yet processed
7840           {
7841             QStrList filesInSameTu;
7842             fd->startParsing();
7843             if (fd->generateSourceFile()) // sources need to be shown in the output
7844             {
7845               msg("Generating code for file %s...\n",fd->docName().data());
7846               fd->writeSource(*g_outputList,FALSE,filesInSameTu);
7847
7848             }
7849             else if (!fd->isReference() && Doxygen::parseSourcesNeeded)
7850               // we needed to parse the sources even if we do not show them
7851             {
7852               msg("Parsing code for file %s...\n",fd->docName().data());
7853               fd->parseSource(FALSE,filesInSameTu);
7854             }
7855             fd->finishParsing();
7856           }
7857         }
7858       }
7859     }
7860     else
7861 #endif
7862     {
7863       FileNameListIterator fnli(*Doxygen::inputNameList); 
7864       FileName *fn;
7865       for (;(fn=fnli.current());++fnli)
7866       {
7867         FileNameIterator fni(*fn);
7868         FileDef *fd;
7869         for (;(fd=fni.current());++fni)
7870         {
7871           QStrList filesInSameTu;
7872           fd->startParsing();
7873           if (fd->generateSourceFile()) // sources need to be shown in the output
7874           {
7875             msg("Generating code for file %s...\n",fd->docName().data());
7876             fd->writeSource(*g_outputList,FALSE,filesInSameTu);
7877
7878           }
7879           else if (!fd->isReference() && Doxygen::parseSourcesNeeded)
7880             // we needed to parse the sources even if we do not show them
7881           {
7882             msg("Parsing code for file %s...\n",fd->docName().data());
7883             fd->parseSource(FALSE,filesInSameTu);
7884           }
7885           fd->finishParsing();
7886         }
7887       }
7888     }
7889   }
7890 }
7891
7892 //----------------------------------------------------------------------------
7893
7894 static void generateFileDocs()
7895 {
7896   if (documentedHtmlFiles==0) return;
7897   
7898   if (Doxygen::inputNameList->count()>0)
7899   {
7900     FileNameListIterator fnli(*Doxygen::inputNameList);
7901     FileName *fn;
7902     for (fnli.toFirst();(fn=fnli.current());++fnli)
7903     {
7904       FileNameIterator fni(*fn);
7905       FileDef *fd;
7906       for (fni.toFirst();(fd=fni.current());++fni)
7907       {
7908         bool doc = fd->isLinkableInProject();
7909         if (doc)
7910         {
7911           msg("Generating docs for file %s...\n",fd->docName().data());
7912           fd->writeDocumentation(*g_outputList);
7913         }
7914       }
7915     }
7916   }
7917 }
7918
7919 //----------------------------------------------------------------------------
7920
7921 static void addSourceReferences()
7922 {
7923   // add source references for class definitions
7924   ClassSDict::Iterator cli(*Doxygen::classSDict);
7925   ClassDef *cd=0;
7926   for (cli.toFirst();(cd=cli.current());++cli)
7927   {
7928     FileDef *fd=cd->getBodyDef();
7929     if (fd && cd->isLinkableInProject() && cd->getStartBodyLine()!=-1)
7930     {
7931       fd->addSourceRef(cd->getStartBodyLine(),cd,0);
7932     }
7933   }
7934   // add source references for namespace definitions
7935   NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
7936   NamespaceDef *nd=0;
7937   for (nli.toFirst();(nd=nli.current());++nli)
7938   {
7939     FileDef *fd=nd->getBodyDef();
7940     if (fd && nd->isLinkableInProject() && nd->getStartBodyLine()!=-1)
7941     {
7942       fd->addSourceRef(nd->getStartBodyLine(),nd,0);
7943     }
7944   }
7945   
7946   // add source references for member names
7947   MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
7948   MemberName *mn=0;
7949   for (mnli.toFirst();(mn=mnli.current());++mnli)
7950   {
7951     MemberNameIterator mni(*mn);
7952     MemberDef *md=0;
7953     for (mni.toFirst();(md=mni.current());++mni)
7954     {
7955       //printf("class member %s: def=%s body=%d link?=%d\n",
7956       //    md->name().data(),
7957       //    md->getBodyDef()?md->getBodyDef()->name().data():"<none>",
7958       //    md->getStartBodyLine(),md->isLinkableInProject());
7959       FileDef *fd=md->getBodyDef();
7960       if (fd && 
7961           md->getStartBodyLine()!=-1 &&
7962           md->isLinkableInProject() &&
7963           (fd->generateSourceFile() || Doxygen::parseSourcesNeeded)
7964          )
7965       {
7966         //printf("Found member `%s' in file `%s' at line `%d' def=%s\n",
7967         //    md->name().data(),fd->name().data(),md->getStartBodyLine(),md->getOuterScope()->name().data()); 
7968         fd->addSourceRef(md->getStartBodyLine(),md->getOuterScope(),md);
7969       }
7970     }
7971   }
7972   MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict);
7973   for (fnli.toFirst();(mn=fnli.current());++fnli)
7974   {
7975     MemberNameIterator mni(*mn);
7976     MemberDef *md=0;
7977     for (mni.toFirst();(md=mni.current());++mni)
7978     {
7979       FileDef *fd=md->getBodyDef();
7980       //printf("member %s body=[%d,%d] fd=%p link=%d parseSources=%d\n",
7981       //    md->name().data(),
7982       //    md->getStartBodyLine(),md->getEndBodyLine(),fd,
7983       //    md->isLinkableInProject(),
7984       //    Doxygen::parseSourcesNeeded);
7985       if (fd && 
7986           md->getStartBodyLine()!=-1 && 
7987           md->isLinkableInProject() && 
7988           (fd->generateSourceFile() || Doxygen::parseSourcesNeeded)
7989          )
7990       {
7991         //printf("Found member `%s' in file `%s' at line `%d' def=%s\n",
7992         //    md->name().data(),fd->name().data(),md->getStartBodyLine(),md->getOuterScope()->name().data()); 
7993         fd->addSourceRef(md->getStartBodyLine(),md->getOuterScope(),md);
7994       }  
7995     }
7996   }
7997 }
7998
7999 //----------------------------------------------------------------------------
8000
8001 static void sortMemberLists()
8002 {
8003   // sort class member lists
8004   ClassSDict::Iterator cli(*Doxygen::classSDict);
8005   ClassDef *cd=0;
8006   for (cli.toFirst();(cd=cli.current());++cli)
8007   {
8008     cd->sortMemberLists();
8009   }
8010
8011   // sort namespace member lists
8012   NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
8013   NamespaceDef *nd=0;
8014   for (nli.toFirst();(nd=nli.current());++nli)
8015   {
8016     nd->sortMemberLists();
8017   }
8018
8019   // sort file member lists
8020   FileNameListIterator fnli(*Doxygen::inputNameList); 
8021   FileName *fn;
8022   for (;(fn=fnli.current());++fnli)
8023   {
8024     FileNameIterator fni(*fn);
8025     FileDef *fd;
8026     for (;(fd=fni.current());++fni)
8027     {
8028       fd->sortMemberLists();
8029     }
8030   }
8031
8032   // sort group member lists
8033   GroupSDict::Iterator gli(*Doxygen::groupSDict);
8034   GroupDef *gd;
8035   for (gli.toFirst();(gd=gli.current());++gli)
8036   {
8037     gd->sortMemberLists();
8038   }
8039 }
8040
8041 //----------------------------------------------------------------------------
8042 // generate the documentation of all classes
8043   
8044 static void generateClassList(ClassSDict &classSDict)
8045 {
8046   ClassSDict::Iterator cli(classSDict);
8047   for ( ; cli.current() ; ++cli )
8048   {
8049     ClassDef *cd=cli.current();
8050    
8051     //printf("cd=%s getOuterScope=%p global=%p\n",cd->name().data(),cd->getOuterScope(),Doxygen::globalScope);
8052     if ((cd->getOuterScope()==0 || // <-- should not happen, but can if we read an old tag file
8053          cd->getOuterScope()==Doxygen::globalScope // only look at global classes
8054         ) && !cd->isHidden() && !cd->isEmbeddedInOuterScope()
8055        ) 
8056     {
8057       // skip external references, anonymous compounds and 
8058       // template instances 
8059       if ( cd->isLinkableInProject() && cd->templateMaster()==0)
8060       {
8061         msg("Generating docs for compound %s...\n",cd->name().data());
8062
8063         cd->writeDocumentation(*g_outputList);
8064         cd->writeMemberList(*g_outputList);
8065       }
8066       // even for undocumented classes, the inner classes can be documented.
8067       cd->writeDocumentationForInnerClasses(*g_outputList);
8068     }
8069   }
8070 }
8071
8072 static void generateClassDocs()
8073 {
8074   generateClassList(*Doxygen::classSDict);
8075   generateClassList(*Doxygen::hiddenClasses);
8076 }
8077
8078 //----------------------------------------------------------------------------
8079
8080 static void inheritDocumentation()
8081 {
8082   MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
8083   MemberName *mn;
8084   //int count=0;
8085   for (;(mn=mnli.current());++mnli)
8086   {
8087     MemberNameIterator mni(*mn);
8088     MemberDef *md;
8089     for (;(md=mni.current());++mni)
8090     {
8091       //printf("%04d Member `%s'\n",count++,md->name().data());
8092       if (md->documentation().isEmpty() && md->briefDescription().isEmpty())
8093       { // no documentation yet
8094         MemberDef *bmd = md->reimplements();
8095         while (bmd && bmd->documentation().isEmpty() && 
8096                       bmd->briefDescription().isEmpty()
8097               )
8098         { // search up the inheritance tree for a documentation member
8099           //printf("bmd=%s class=%s\n",bmd->name().data(),bmd->getClassDef()->name().data());
8100           bmd = bmd->reimplements();
8101         }
8102         if (bmd) // copy the documentation from the reimplemented member
8103         {
8104           md->setInheritsDocsFrom(bmd);
8105           md->setDocumentation(bmd->documentation(),bmd->docFile(),bmd->docLine());
8106           md->setDocsForDefinition(bmd->isDocsForDefinition());
8107           md->setBriefDescription(bmd->briefDescription(),bmd->briefFile(),bmd->briefLine());
8108           md->copyArgumentNames(bmd);
8109           md->setInbodyDocumentation(bmd->inbodyDocumentation(),bmd->inbodyFile(),bmd->inbodyLine());
8110         }
8111       }
8112     }
8113   }
8114 }
8115
8116 //----------------------------------------------------------------------------
8117
8118 static void combineUsingRelations()
8119 {
8120   // for each file
8121   FileNameListIterator fnli(*Doxygen::inputNameList);
8122   FileName *fn;
8123   for (fnli.toFirst();(fn=fnli.current());++fnli)
8124   {
8125     FileNameIterator fni(*fn);
8126     FileDef *fd;
8127     for (fni.toFirst();(fd=fni.current());++fni)
8128     {
8129       fd->visited=FALSE;
8130     }
8131   }
8132   for (fnli.toFirst();(fn=fnli.current());++fnli)
8133   {
8134     FileNameIterator fni(*fn);
8135     FileDef *fd;
8136     for (fni.toFirst();(fd=fni.current());++fni)
8137     {
8138       fd->combineUsingRelations();
8139     }
8140   }
8141
8142   // for each namespace
8143   NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
8144   NamespaceDef *nd;
8145   for (nli.toFirst() ; (nd=nli.current()) ; ++nli )
8146   {
8147     nd->visited=FALSE;
8148   }
8149   for (nli.toFirst() ; (nd=nli.current()) ; ++nli )
8150   {
8151     nd->combineUsingRelations();
8152   }
8153 }
8154
8155 //----------------------------------------------------------------------------
8156   
8157 static void addMembersToMemberGroup()
8158 {
8159   // for each class
8160   ClassSDict::Iterator cli(*Doxygen::classSDict);
8161   ClassDef *cd;
8162   for ( ; (cd=cli.current()) ; ++cli )
8163   {
8164     cd->addMembersToMemberGroup();
8165   }
8166   // for each file
8167   FileNameListIterator fnli(*Doxygen::inputNameList);
8168   FileName *fn;
8169   for (fnli.toFirst();(fn=fnli.current());++fnli)
8170   {
8171     FileNameIterator fni(*fn);
8172     FileDef *fd;
8173     for (fni.toFirst();(fd=fni.current());++fni)
8174     {
8175       fd->addMembersToMemberGroup();
8176     }
8177   }
8178   // for each namespace
8179   NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
8180   NamespaceDef *nd;
8181   for ( ; (nd=nli.current()) ; ++nli )
8182   {
8183     nd->addMembersToMemberGroup();
8184   }
8185   // for each group
8186   GroupSDict::Iterator gli(*Doxygen::groupSDict);
8187   GroupDef *gd;
8188   for (gli.toFirst();(gd=gli.current());++gli)
8189   {
8190     gd->addMembersToMemberGroup();
8191   }
8192 }
8193
8194 //----------------------------------------------------------------------------
8195
8196 static void distributeMemberGroupDocumentation()
8197 {
8198   // for each class
8199   ClassSDict::Iterator cli(*Doxygen::classSDict);
8200   ClassDef *cd;
8201   for ( ; (cd=cli.current()) ; ++cli )
8202   {
8203     cd->distributeMemberGroupDocumentation();
8204   }
8205   // for each file
8206   FileNameListIterator fnli(*Doxygen::inputNameList);
8207   FileName *fn;
8208   for (fnli.toFirst();(fn=fnli.current());++fnli)
8209   {
8210     FileNameIterator fni(*fn);
8211     FileDef *fd;
8212     for (fni.toFirst();(fd=fni.current());++fni)
8213     {
8214       fd->distributeMemberGroupDocumentation();
8215     }
8216   }
8217   // for each namespace
8218   NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
8219   NamespaceDef *nd;
8220   for ( ; (nd=nli.current()) ; ++nli )
8221   {
8222     nd->distributeMemberGroupDocumentation();
8223   }
8224   // for each group
8225   GroupSDict::Iterator gli(*Doxygen::groupSDict);
8226   GroupDef *gd;
8227   for (gli.toFirst();(gd=gli.current());++gli)
8228   {
8229     gd->distributeMemberGroupDocumentation();
8230   }
8231 }
8232
8233 //----------------------------------------------------------------------------
8234
8235 static void findSectionsInDocumentation()
8236 {
8237   // for each class
8238   ClassSDict::Iterator cli(*Doxygen::classSDict);
8239   ClassDef *cd;
8240   for ( ; (cd=cli.current()) ; ++cli )
8241   {
8242     cd->findSectionsInDocumentation();
8243   }
8244   // for each file
8245   FileNameListIterator fnli(*Doxygen::inputNameList);
8246   FileName *fn;
8247   for (fnli.toFirst();(fn=fnli.current());++fnli)
8248   {
8249     FileNameIterator fni(*fn);
8250     FileDef *fd;
8251     for (fni.toFirst();(fd=fni.current());++fni)
8252     {
8253       fd->findSectionsInDocumentation();
8254     }
8255   }
8256   // for each namespace
8257   NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
8258   NamespaceDef *nd;
8259   for ( ; (nd=nli.current()) ; ++nli )
8260   {
8261     nd->findSectionsInDocumentation();
8262   }
8263   // for each group
8264   GroupSDict::Iterator gli(*Doxygen::groupSDict);
8265   GroupDef *gd;
8266   for (gli.toFirst();(gd=gli.current());++gli)
8267   {
8268     gd->findSectionsInDocumentation();
8269   }
8270   // for each page
8271   PageSDict::Iterator pdi(*Doxygen::pageSDict);
8272   PageDef *pd=0;
8273   for (pdi.toFirst();(pd=pdi.current());++pdi)
8274   {
8275     pd->findSectionsInDocumentation();
8276   }
8277   if (Doxygen::mainPage) Doxygen::mainPage->findSectionsInDocumentation();
8278 }
8279
8280 static void flushCachedTemplateRelations()
8281 {
8282   // remove all references to classes from the cache
8283   // as there can be new template instances in the inheritance path
8284   // to this class. Optimization: only remove those classes that
8285   // have inheritance instances as direct or indirect sub classes.
8286   QCacheIterator<LookupInfo> ci(*Doxygen::lookupCache);
8287   LookupInfo *li=0;
8288   for (ci.toFirst();(li=ci.current());++ci)
8289   {
8290     if (li->classDef)
8291     {
8292       Doxygen::lookupCache->remove(ci.currentKey());
8293     }
8294   }
8295   // remove all cached typedef resolutions whose target is a
8296   // template class as this may now be a template instance
8297   MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict);
8298   MemberName *fn;
8299   for (;(fn=fnli.current());++fnli) // for each global function name
8300   {
8301     MemberNameIterator fni(*fn);
8302     MemberDef *fmd;
8303     for (;(fmd=fni.current());++fni) // for each function with that name
8304     {
8305       if (fmd->isTypedefValCached())
8306       {
8307         ClassDef *cd = fmd->getCachedTypedefVal();
8308         if (cd->isTemplate()) fmd->invalidateTypedefValCache();
8309       }
8310     }
8311   }
8312   MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
8313   for (;(fn=mnli.current());++mnli) // for each class method name
8314   {
8315     MemberNameIterator mni(*fn);
8316     MemberDef *fmd;
8317     for (;(fmd=mni.current());++mni) // for each function with that name
8318     {
8319       if (fmd->isTypedefValCached())
8320       {
8321         ClassDef *cd = fmd->getCachedTypedefVal();
8322         if (cd->isTemplate()) fmd->invalidateTypedefValCache();
8323       }
8324     }
8325   }
8326 }
8327
8328 //----------------------------------------------------------------------------
8329
8330 static void flushUnresolvedRelations()
8331 {
8332   // Remove all unresolved references to classes from the cache.
8333   // This is needed before resolving the inheritance relations, since
8334   // it would otherwise not find the inheritance relation
8335   // for C in the example below, as B::I was already found to be unresolvable 
8336   // (which is correct if you igore the inheritance relation between A and B).
8337   // 
8338   // class A { class I {} };
8339   // class B : public A {};
8340   // class C : public B::I {};
8341   //
8342   QCacheIterator<LookupInfo> ci(*Doxygen::lookupCache);
8343   LookupInfo *li=0;
8344   for (ci.toFirst();(li=ci.current());++ci)
8345   {
8346     if (li->classDef==0 && li->typeDef==0)
8347     {
8348       Doxygen::lookupCache->remove(ci.currentKey());
8349     }
8350   }
8351
8352   MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict);
8353   MemberName *fn;
8354   for (;(fn=fnli.current());++fnli) // for each global function name
8355   {
8356     MemberNameIterator fni(*fn);
8357     MemberDef *fmd;
8358     for (;(fmd=fni.current());++fni) // for each function with that name
8359     {
8360       fmd->invalidateCachedArgumentTypes();
8361     }
8362   }
8363   MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
8364   for (;(fn=mnli.current());++mnli) // for each class method name
8365   {
8366     MemberNameIterator mni(*fn);
8367     MemberDef *fmd;
8368     for (;(fmd=mni.current());++mni) // for each function with that name
8369     {
8370       fmd->invalidateCachedArgumentTypes();
8371     }
8372   }
8373
8374 }
8375
8376 //----------------------------------------------------------------------------
8377
8378 static void findDefineDocumentation(EntryNav *rootNav)
8379 {
8380   if ((rootNav->section()==Entry::DEFINEDOC_SEC ||
8381        rootNav->section()==Entry::DEFINE_SEC) && !rootNav->name().isEmpty()
8382      )
8383   {
8384     rootNav->loadEntry(g_storage);
8385     Entry *root = rootNav->entry();
8386     
8387     //printf("found define `%s' `%s' brief=`%s' doc=`%s'\n",
8388     //       root->name.data(),root->args.data(),root->brief.data(),root->doc.data());
8389
8390     if (rootNav->tagInfo() && !root->name.isEmpty()) // define read from a tag file
8391     {
8392       MemberDef *md=new MemberDef("<tagfile>",1,1,
8393                     "#define",root->name,root->args,0,
8394                     Public,Normal,FALSE,Member,MemberType_Define,0,0);
8395       md->setTagInfo(rootNav->tagInfo());
8396       md->setLanguage(root->lang);
8397       //printf("Searching for `%s' fd=%p\n",filePathName.data(),fd);
8398       md->setFileDef(rootNav->parent()->fileDef());
8399       //printf("Adding member=%s\n",md->name().data());
8400       MemberName *mn;
8401       if ((mn=Doxygen::functionNameSDict->find(root->name)))
8402       {
8403         mn->append(md);
8404       }
8405       else 
8406       {
8407         mn = new MemberName(root->name);
8408         mn->append(md);
8409         Doxygen::functionNameSDict->append(root->name,mn);
8410       }
8411     }
8412     MemberName *mn=Doxygen::functionNameSDict->find(root->name);
8413     if (mn)
8414     {
8415       MemberNameIterator mni(*mn);
8416       MemberDef *md;
8417       int count=0;
8418       for (;(md=mni.current());++mni)
8419       {
8420         if (md->memberType()==MemberType_Define) count++;
8421       }
8422       if (count==1)
8423       {
8424         for (mni.toFirst();(md=mni.current());++mni)
8425         {
8426           if (md->memberType()==MemberType_Define)
8427           {
8428             md->setDocumentation(root->doc,root->docFile,root->docLine);
8429             md->setDocsForDefinition(!root->proto);
8430             md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
8431             if (md->inbodyDocumentation().isEmpty())
8432             {
8433               md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
8434             }
8435             md->setBodySegment(root->bodyLine,root->endBodyLine);
8436             md->setBodyDef(rootNav->fileDef());
8437             md->addSectionsToDefinition(root->anchors);
8438             md->setMaxInitLines(root->initLines);
8439             md->setRefItems(root->sli);
8440             if (root->mGrpId!=-1) md->setMemberGroupId(root->mGrpId);
8441             addMemberToGroups(root,md);
8442           }
8443         }
8444       }
8445       else if (count>1 &&
8446                (!root->doc.isEmpty() ||
8447                 !root->brief.isEmpty() ||
8448                 root->bodyLine!=-1
8449                )
8450               )
8451         // multiple defines don't know where to add docs
8452         // but maybe they are in different files together with their documentation
8453       {
8454         for (mni.toFirst();(md=mni.current());++mni)
8455         {
8456           if (md->memberType()==MemberType_Define)
8457           {
8458             FileDef *fd=md->getFileDef();
8459             if (fd && fd->absFilePath()==root->fileName) 
8460               // doc and define in the same file assume they belong together.
8461             {
8462 #if 0
8463               if (md->documentation().isEmpty())
8464 #endif
8465               {
8466                 md->setDocumentation(root->doc,root->docFile,root->docLine);
8467                 md->setDocsForDefinition(!root->proto);
8468               }
8469 #if 0
8470               if (md->briefDescription().isEmpty())
8471 #endif
8472               {
8473                 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
8474               }
8475               if (md->inbodyDocumentation().isEmpty())
8476               {
8477                 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
8478               }
8479               md->setBodySegment(root->bodyLine,root->endBodyLine);
8480               md->setBodyDef(rootNav->fileDef());
8481               md->addSectionsToDefinition(root->anchors);
8482               md->setRefItems(root->sli);
8483               md->setLanguage(root->lang);
8484               if (root->mGrpId!=-1) md->setMemberGroupId(root->mGrpId);
8485               addMemberToGroups(root,md);
8486             }
8487           }
8488         }
8489         //warn("define %s found in the following files:\n",root->name.data());
8490         //warn("Cannot determine where to add the documentation found "
8491         //     "at line %d of file %s. \n",
8492         //     root->startLine,root->fileName.data());
8493       }
8494     }
8495     else if (!root->doc.isEmpty() || !root->brief.isEmpty()) // define not found
8496     {
8497       static bool preEnabled = Config_getBool("ENABLE_PREPROCESSING");
8498       if (preEnabled)
8499       {
8500         warn(root->fileName,root->startLine,
8501              "documentation for unknown define %s found.\n",
8502              root->name.data()
8503             );
8504       }
8505       else
8506       {
8507         warn(root->fileName,root->startLine,
8508              "found documented #define but ignoring it because "
8509              "ENABLE_PREPROCESSING is NO.\n",
8510              root->name.data()
8511             );
8512       }
8513     }
8514
8515     rootNav->releaseEntry();
8516   }
8517   RECURSE_ENTRYTREE(findDefineDocumentation,rootNav);
8518 }
8519
8520 //----------------------------------------------------------------------------
8521
8522 static void findDirDocumentation(EntryNav *rootNav)
8523 {
8524   if (rootNav->section() == Entry::DIRDOC_SEC)
8525   {
8526     rootNav->loadEntry(g_storage);
8527     Entry *root = rootNav->entry();
8528
8529     QCString normalizedName = root->name;
8530     normalizedName = substitute(normalizedName,"\\","/");
8531     //printf("root->docFile=%s normalizedName=%s\n",
8532     //    root->docFile.data(),normalizedName.data());
8533     if (root->docFile==normalizedName) // current dir?
8534     {
8535       int lastSlashPos=normalizedName.findRev('/'); 
8536       if (lastSlashPos!=-1) // strip file name
8537       {
8538         normalizedName=normalizedName.left(lastSlashPos);
8539       }
8540     }
8541     if (normalizedName.at(normalizedName.length()-1)!='/')
8542     {
8543       normalizedName+='/';
8544     }
8545     DirDef *dir,*matchingDir=0;
8546     SDict<DirDef>::Iterator sdi(*Doxygen::directories);
8547     for (sdi.toFirst();(dir=sdi.current());++sdi)
8548     {
8549       //printf("Dir: %s<->%s\n",dir->name().data(),normalizedName.data());
8550       if (dir->name().right(normalizedName.length())==normalizedName)
8551       {
8552         if (matchingDir)
8553         {
8554            warn(root->fileName,root->startLine,
8555              "\\dir command matches multiple directories.\n"
8556              "  Applying the command for directory %s\n"
8557              "  Ignoring the command for directory %s\n",
8558              matchingDir->name().data(),dir->name().data()
8559            );
8560         }
8561         else
8562         {
8563           matchingDir=dir;
8564         }
8565       }
8566     }
8567     if (matchingDir)
8568     {
8569       //printf("Match for with dir %s\n",matchingDir->name().data());
8570       matchingDir->setBriefDescription(root->brief,root->briefFile,root->briefLine);
8571       matchingDir->setDocumentation(root->doc,root->docFile,root->docLine);
8572       matchingDir->setRefItems(root->sli);
8573       addDirToGroups(root,matchingDir);
8574     }
8575     else
8576     {
8577       warn(root->fileName,root->startLine,"No matching "
8578           "directory found for command \\dir %s\n",normalizedName.data());
8579     }
8580     rootNav->releaseEntry();
8581   }
8582   RECURSE_ENTRYTREE(findDirDocumentation,rootNav);
8583 }
8584
8585
8586 //----------------------------------------------------------------------------
8587 // create a (sorted) list of separate documentation pages
8588
8589 static void buildPageList(EntryNav *rootNav)
8590 {
8591   if (rootNav->section() == Entry::PAGEDOC_SEC)
8592   {
8593     rootNav->loadEntry(g_storage);
8594     Entry *root = rootNav->entry();
8595
8596     if (!root->name.isEmpty())
8597     {
8598       addRelatedPage(rootNav);
8599     }
8600
8601     rootNav->releaseEntry();
8602   }
8603   else if (rootNav->section() == Entry::MAINPAGEDOC_SEC)
8604   {
8605     rootNav->loadEntry(g_storage);
8606     Entry *root = rootNav->entry();
8607
8608     QCString title=root->args.stripWhiteSpace();
8609     if (title.isEmpty()) title=theTranslator->trMainPage();
8610     //QCString name = Config_getBool("GENERATE_TREEVIEW")?"main":"index";
8611     QCString name = "index";
8612     addRefItem(root->sli,
8613                name,
8614                "page",
8615                name,
8616                title,
8617                0
8618                );
8619
8620     rootNav->releaseEntry();
8621   }
8622   RECURSE_ENTRYTREE(buildPageList,rootNav);
8623 }
8624
8625 static void findMainPage(EntryNav *rootNav)
8626 {
8627   if (rootNav->section() == Entry::MAINPAGEDOC_SEC)
8628   {
8629     rootNav->loadEntry(g_storage);
8630     Entry *root = rootNav->entry();
8631
8632     if (Doxygen::mainPage==0)
8633     {
8634       //printf("Found main page! \n======\n%s\n=======\n",root->doc.data());
8635       QCString title=root->args.stripWhiteSpace();
8636       //QCString indexName=Config_getBool("GENERATE_TREEVIEW")?"main":"index";
8637       QCString indexName="index";
8638       Doxygen::mainPage = new PageDef(root->docFile,root->docLine,
8639                               indexName, root->brief+root->doc+root->inbodyDocs,title);
8640       //setFileNameForSections(root->anchors,"index",Doxygen::mainPage);
8641       Doxygen::mainPage->setBriefDescription(root->brief,root->briefFile,root->briefLine);
8642       Doxygen::mainPage->setFileName(indexName,TRUE);
8643       Doxygen::mainPage->setShowToc(root->stat);
8644       addPageToContext(Doxygen::mainPage,rootNav);
8645           
8646       SectionInfo *si = Doxygen::sectionDict->find(Doxygen::mainPage->name());
8647       if (si)
8648       {
8649         if (si->lineNr != -1)
8650         {
8651           warn(root->fileName,root->startLine,"multiple use of section label '%s', (first occurrence: %s, line %d)",Doxygen::mainPage->name().data(),si->fileName.data(),si->lineNr);
8652         }
8653         else
8654         {
8655           warn(root->fileName,root->startLine,"multiple use of section label '%s', (first occurrence: %s)",Doxygen::mainPage->name().data(),si->fileName.data());
8656         }
8657       }
8658       else
8659       {
8660         // a page name is a label as well! but should no be double either
8661         si=new SectionInfo(
8662           indexName, root->startLine,
8663           Doxygen::mainPage->name(),
8664           Doxygen::mainPage->title(),
8665           SectionInfo::Page,
8666           0); // level 0
8667         Doxygen::sectionDict->append(indexName,si);
8668         Doxygen::mainPage->addSectionsToDefinition(root->anchors);
8669       }
8670     }
8671     else
8672     {
8673       warn(root->fileName,root->startLine,
8674            "found more than one \\mainpage comment block! Skipping this "
8675            "block."
8676           );
8677     }
8678
8679     rootNav->releaseEntry();
8680   }
8681   RECURSE_ENTRYTREE(findMainPage,rootNav);
8682 }
8683
8684 static void computePageRelations(EntryNav *rootNav)
8685 {
8686   if ((rootNav->section()==Entry::PAGEDOC_SEC || 
8687        rootNav->section()==Entry::MAINPAGEDOC_SEC
8688       )
8689       && !rootNav->name().isEmpty()
8690      )
8691   {
8692     rootNav->loadEntry(g_storage);
8693     Entry *root = rootNav->entry();
8694
8695     PageDef *pd = root->section==Entry::PAGEDOC_SEC ?
8696                     Doxygen::pageSDict->find(root->name) : 
8697                     Doxygen::mainPage; 
8698     if (pd)
8699     {
8700       QListIterator<BaseInfo> bii(*root->extends);
8701       BaseInfo *bi;
8702       for (bii.toFirst();(bi=bii.current());++bii)
8703       {
8704         PageDef *subPd = Doxygen::pageSDict->find(bi->name);
8705         if (subPd)
8706         {
8707           pd->addInnerCompound(subPd);
8708           //printf("*** Added subpage relation: %s->%s\n",
8709           //    pd->name().data(),subPd->name().data());
8710         }
8711       }
8712     }
8713
8714     rootNav->releaseEntry();
8715   }
8716   RECURSE_ENTRYTREE(computePageRelations,rootNav);
8717 }
8718
8719 static void checkPageRelations()
8720 {
8721   PageSDict::Iterator pdi(*Doxygen::pageSDict);
8722   PageDef *pd=0;
8723   for (pdi.toFirst();(pd=pdi.current());++pdi)
8724   {
8725     Definition *ppd = pd->getOuterScope();
8726     while (ppd)
8727     {
8728       if (ppd==pd)
8729       {
8730         err("page defined at line %d of file %s with label %s is a subpage "
8731             "of itself! Please remove this cyclic dependency.\n",
8732             pd->docLine(),pd->docFile().data(),pd->name().data());
8733         exit(1);
8734       }
8735       ppd=ppd->getOuterScope();
8736     }
8737   }
8738 }
8739
8740 //----------------------------------------------------------------------------
8741
8742 static void resolveUserReferences()
8743 {
8744   SDict<SectionInfo>::Iterator sdi(*Doxygen::sectionDict);
8745   SectionInfo *si;
8746   for (;(si=sdi.current());++sdi)
8747   {
8748     //printf("si->label=`%s' si->definition=%s si->fileName=`%s'\n",
8749     //        si->label.data(),si->definition?si->definition->name().data():"<none>",
8750     //        si->fileName.data());
8751     PageDef *pd=0;
8752
8753     // hack: the items of a todo/test/bug/deprecated list are all fragments from 
8754     // different files, so the resulting section's all have the wrong file 
8755     // name (not from the todo/test/bug/deprecated list, but from the file in 
8756     // which they are defined). We correct this here by looking at the 
8757     // generated section labels!
8758     QDictIterator<RefList> rli(*Doxygen::xrefLists);
8759     RefList *rl;
8760     for (rli.toFirst();(rl=rli.current());++rli)
8761     {
8762       QCString label="_"+rl->listName(); // "_todo", "_test", ...
8763       if (si->label.left(label.length())==label)
8764       {
8765         si->fileName=rl->listName();
8766         si->generated=TRUE;
8767         break;
8768       }
8769     }
8770
8771     //printf("start: si->label=%s si->fileName=%s\n",si->label.data(),si->fileName.data());
8772     if (!si->generated)
8773     {
8774       // if this section is in a page and the page is in a group, then we
8775       // have to adjust the link file name to point to the group.
8776       if (!si->fileName.isEmpty() && 
8777           (pd=Doxygen::pageSDict->find(si->fileName)) &&
8778           pd->getGroupDef())
8779       {
8780         si->fileName=pd->getGroupDef()->getOutputFileBase().copy();
8781       }
8782
8783       if (si->definition)
8784       {
8785         // TODO: there should be one function in Definition that returns
8786         // the file to link to, so we can avoid the following tests.
8787         GroupDef *gd=0;
8788         if (si->definition->definitionType()==Definition::TypeMember)
8789         {
8790           gd = ((MemberDef *)si->definition)->getGroupDef();
8791         }
8792
8793         if (gd)
8794         {
8795           si->fileName=gd->getOutputFileBase().copy();
8796         }
8797         else
8798         {
8799           //si->fileName=si->definition->getOutputFileBase().copy();
8800           //printf("Setting si->fileName to %s\n",si->fileName.data());
8801         }
8802       }
8803     }
8804     //printf("end: si->label=%s si->fileName=%s\n",si->label.data(),si->fileName.data());
8805   }
8806 }
8807
8808
8809
8810 //----------------------------------------------------------------------------
8811 // generate all separate documentation pages
8812
8813
8814 static void generatePageDocs()
8815 {
8816   //printf("documentedPages=%d real=%d\n",documentedPages,Doxygen::pageSDict->count());
8817   if (documentedPages==0) return;
8818   PageSDict::Iterator pdi(*Doxygen::pageSDict);
8819   PageDef *pd=0;
8820   for (pdi.toFirst();(pd=pdi.current());++pdi)
8821   {
8822     if (!pd->getGroupDef() && !pd->isReference())
8823     {
8824       msg("Generating docs for page %s...\n",pd->name().data());
8825       Doxygen::insideMainPage=TRUE;
8826       pd->writeDocumentation(*g_outputList);
8827       Doxygen::insideMainPage=FALSE;
8828     }
8829   }
8830 }
8831
8832 //----------------------------------------------------------------------------
8833 // create a (sorted) list & dictionary of example pages
8834
8835 static void buildExampleList(EntryNav *rootNav)
8836 {
8837   if (rootNav->section()==Entry::EXAMPLE_SEC && !rootNav->name().isEmpty()) 
8838   {
8839     rootNav->loadEntry(g_storage);
8840     Entry *root = rootNav->entry();
8841
8842     if (Doxygen::exampleSDict->find(root->name))
8843     {
8844       warn(root->fileName,root->startLine,
8845           "Example %s was already documented. Ignoring "
8846           "documentation found here.",
8847           root->name.data()
8848           );
8849     }
8850     else
8851     {
8852       PageDef *pd=new PageDef(root->fileName,root->startLine,
8853           root->name,root->brief+root->doc+root->inbodyDocs,root->args);
8854       pd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
8855       pd->setFileName(convertNameToFile(pd->name()+"-example",FALSE,TRUE),FALSE);
8856       pd->addSectionsToDefinition(root->anchors);
8857       pd->setLanguage(root->lang);
8858       //pi->addSections(root->anchors);
8859
8860       Doxygen::exampleSDict->inSort(root->name,pd);
8861       //we don't add example to groups 
8862       //addExampleToGroups(root,pd);
8863     }
8864
8865     rootNav->releaseEntry();
8866   }
8867   RECURSE_ENTRYTREE(buildExampleList,rootNav);
8868 }
8869
8870 //----------------------------------------------------------------------------
8871 // prints the Entry tree (for debugging)
8872
8873 void printNavTree(EntryNav *rootNav,int indent)
8874 {
8875   QCString indentStr;
8876   indentStr.fill(' ',indent);
8877   msg("%s%s (sec=0x%x)\n",
8878       indentStr.isEmpty()?"":indentStr.data(),
8879       rootNav->name().isEmpty()?"<empty>":rootNav->name().data(),
8880       rootNav->section());
8881   if (rootNav->children()) 
8882   {
8883     EntryNavListIterator eli(*rootNav->children());
8884     for (;eli.current();++eli) printNavTree(eli.current(),indent+2);
8885   }
8886 }
8887
8888
8889 //----------------------------------------------------------------------------
8890 // generate the example documentation 
8891
8892 static void generateExampleDocs()
8893 {
8894   g_outputList->disable(OutputGenerator::Man);
8895   PageSDict::Iterator pdi(*Doxygen::exampleSDict);
8896   PageDef *pd=0;
8897   for (pdi.toFirst();(pd=pdi.current());++pdi)
8898   {
8899     msg("Generating docs for example %s...\n",pd->name().data());
8900     resetCCodeParserState();
8901     QCString n=pd->getOutputFileBase();
8902     startFile(*g_outputList,n,n,pd->name());
8903     startTitle(*g_outputList,n);
8904     g_outputList->docify(pd->name());
8905     endTitle(*g_outputList,n,0);
8906     g_outputList->startContents();
8907     g_outputList->generateDoc(pd->docFile(),                            // file
8908                          pd->docLine(),                            // startLine
8909                          pd,                                       // context
8910                          0,                                        // memberDef
8911                          pd->documentation()+"\n\n\\include "+pd->name(),          // docs
8912                          TRUE,                                     // index words
8913                          TRUE,                                     // is example
8914                          pd->name()
8915                         );
8916     endFile(*g_outputList); // contains g_outputList->endContents()
8917   }
8918   g_outputList->enable(OutputGenerator::Man);
8919 }
8920
8921 //----------------------------------------------------------------------------
8922 // generate module pages
8923
8924 static void generateGroupDocs()
8925 {
8926   GroupSDict::Iterator gli(*Doxygen::groupSDict);
8927   GroupDef *gd;
8928   for (gli.toFirst();(gd=gli.current());++gli)
8929   {
8930     if (!gd->isReference())
8931     {
8932       gd->writeDocumentation(*g_outputList);
8933     }
8934   }
8935 }
8936
8937 //----------------------------------------------------------------------------
8938
8939 //static void generatePackageDocs()
8940 //{
8941 //  writePackageIndex(*g_outputList);
8942 //  
8943 //  if (Doxygen::packageDict.count()>0)
8944 //  {
8945 //    PackageSDict::Iterator pdi(Doxygen::packageDict);
8946 //    PackageDef *pd;
8947 //    for (pdi.toFirst();(pd=pdi.current());++pdi)
8948 //    {
8949 //      pd->writeDocumentation(*g_outputList);
8950 //    }
8951 //  }
8952 //}
8953
8954 //----------------------------------------------------------------------------
8955 // generate module pages
8956
8957 static void generateNamespaceDocs()
8958 {
8959   //writeNamespaceIndex(*g_outputList);
8960   
8961   NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
8962   NamespaceDef *nd;
8963   // for each namespace...
8964   for (;(nd=nli.current());++nli)
8965   {
8966
8967     if (nd->isLinkableInProject())
8968     {
8969       msg("Generating docs for namespace %s\n",nd->name().data());
8970       nd->writeDocumentation(*g_outputList);
8971     }
8972
8973     // for each class in the namespace...
8974     ClassSDict::Iterator cli(*nd->getClassSDict());
8975     for ( ; cli.current() ; ++cli )
8976     {
8977       ClassDef *cd=cli.current();
8978       if ( ( cd->isLinkableInProject() && 
8979              cd->templateMaster()==0
8980            ) // skip external references, anonymous compounds and 
8981              // template instances and nested classes
8982            && !cd->isHidden() && !cd->isEmbeddedInOuterScope()
8983          )
8984       {
8985         msg("Generating docs for compound %s...\n",cd->name().data());
8986
8987         cd->writeDocumentation(*g_outputList);
8988         cd->writeMemberList(*g_outputList);
8989       }
8990       cd->writeDocumentationForInnerClasses(*g_outputList);
8991     }
8992   }
8993 }
8994
8995 #if defined(_WIN32)
8996 static QCString fixSlashes(QCString &s)
8997 {
8998   QCString result;
8999   uint i;
9000   for (i=0;i<s.length();i++)
9001   {
9002     switch(s.at(i))
9003     {
9004       case '/': 
9005       case '\\': 
9006         result+="\\\\"; 
9007         break;
9008       default:
9009         result+=s.at(i);
9010     }
9011   }
9012   return result;
9013 }
9014 #endif
9015
9016
9017 //----------------------------------------------------------------------------
9018
9019 static bool openOutputFile(const char *outFile,QFile &f)
9020 {
9021   bool fileOpened=FALSE;
9022   bool writeToStdout=(outFile[0]=='-' && outFile[1]=='\0');
9023   if (writeToStdout) // write to stdout
9024   {
9025     fileOpened = f.open(IO_WriteOnly,stdout);
9026   }
9027   else // write to file
9028   {
9029     QFileInfo fi(outFile);
9030     if (fi.exists()) // create a backup
9031     {
9032       QDir dir=fi.dir();
9033       QFileInfo backup(fi.fileName()+".bak");
9034       if (backup.exists()) // remove existing backup
9035         dir.remove(backup.fileName());
9036       dir.rename(fi.fileName(),fi.fileName()+".bak");
9037     } 
9038     f.setName(outFile);
9039     fileOpened = f.open(IO_WriteOnly|IO_Translate);
9040   }
9041   return fileOpened;
9042 }
9043
9044 /*! Generate a template version of the configuration file.
9045  *  If the \a shortList parameter is TRUE a configuration file without
9046  *  comments will be generated.
9047  */
9048 static void generateConfigFile(const char *configFile,bool shortList,
9049                                bool updateOnly=FALSE)
9050 {
9051   QFile f;
9052   bool fileOpened=openOutputFile(configFile,f);
9053   bool writeToStdout=(configFile[0]=='-' && configFile[1]=='\0');
9054   if (fileOpened)
9055   {
9056     FTextStream t(&f);
9057     Config::instance()->writeTemplate(t,shortList,updateOnly);
9058     if (!writeToStdout)
9059     {
9060       if (!updateOnly)
9061       {
9062         msg("\n\nConfiguration file `%s' created.\n\n",configFile);
9063         msg("Now edit the configuration file and enter\n\n");
9064         if (qstrcmp(configFile,"Doxyfile") || qstrcmp(configFile,"doxyfile"))
9065           msg("  doxygen %s\n\n",configFile);
9066         else
9067           msg("  doxygen\n\n");
9068         msg("to generate the documentation for your project\n\n");
9069       }
9070       else
9071       {
9072         msg("\n\nConfiguration file `%s' updated.\n\n",configFile);
9073       }
9074     }
9075   }
9076   else
9077   {
9078     err("Cannot open file %s for writing\n",configFile);
9079     exit(1);
9080   }
9081 }
9082
9083 //----------------------------------------------------------------------------
9084 // read and parse a tag file
9085
9086 //static bool readLineFromFile(QFile &f,QCString &s)
9087 //{
9088 //  char c=0;
9089 //  s.resize(0);
9090 //  while (!f.atEnd() && (c=f.getch())!='\n') s+=c;
9091 //  return f.atEnd();
9092 //}
9093
9094 //----------------------------------------------------------------------------
9095
9096 static void readTagFile(Entry *root,const char *tl)
9097 {
9098   QCString tagLine = tl;
9099   QCString fileName;
9100   QCString destName;
9101   int eqPos = tagLine.find('=');
9102   if (eqPos!=-1) // tag command contains a destination
9103   {
9104     fileName = tagLine.left(eqPos).stripWhiteSpace();
9105     destName = tagLine.right(tagLine.length()-eqPos-1).stripWhiteSpace();
9106     QFileInfo fi(fileName);
9107     Doxygen::tagDestinationDict.insert(fi.absFilePath().utf8(),new QCString(destName));
9108     //printf("insert tagDestination %s->%s\n",fi.fileName().data(),destName.data());
9109   }
9110   else
9111   {
9112     fileName = tagLine;
9113   }
9114     
9115   QFileInfo fi(fileName);
9116   if (!fi.exists() || !fi.isFile())
9117   {
9118     err("Tag file `%s' does not exist or is not a file. Skipping it...\n",
9119         fileName.data());
9120     return;
9121   }
9122
9123   if (!destName.isEmpty())
9124     msg("Reading tag file `%s', location `%s'...\n",fileName.data(),destName.data());
9125   else
9126     msg("Reading tag file `%s'...\n",fileName.data());
9127
9128   parseTagFile(root,fi.absFilePath().utf8());
9129 }
9130
9131 //----------------------------------------------------------------------------
9132 static void copyStyleSheet()
9133 {
9134   QCString &htmlStyleSheet = Config_getString("HTML_STYLESHEET");
9135   if (!htmlStyleSheet.isEmpty())
9136   {
9137     QFileInfo fi(htmlStyleSheet);
9138     if (!fi.exists())
9139     {
9140       err("Style sheet '%s' specified by HTML_STYLESHEET does not exist!\n",htmlStyleSheet.data());
9141       htmlStyleSheet.resize(0); // revert to the default
9142     }
9143     else
9144     {
9145       QCString destFileName = Config_getString("HTML_OUTPUT")+"/"+fi.fileName().data();
9146       copyFile(htmlStyleSheet,destFileName);
9147     }
9148   }
9149   QCString &htmlExtraStyleSheet = Config_getString("HTML_EXTRA_STYLESHEET");
9150   if (!htmlExtraStyleSheet.isEmpty())
9151   {
9152     QFileInfo fi(htmlExtraStyleSheet);
9153     if (!fi.exists())
9154     {
9155       err("Style sheet '%s' specified by HTML_EXTRA_STYLESHEET does not exist!\n",htmlExtraStyleSheet.data());
9156       htmlExtraStyleSheet.resize(0); // revert to the default
9157     }
9158     else
9159     {
9160       QCString destFileName = Config_getString("HTML_OUTPUT")+"/"+fi.fileName().data();
9161       copyFile(htmlExtraStyleSheet,destFileName);
9162     }
9163   }
9164   
9165 }
9166
9167 static void copyLogo()
9168 {
9169   QCString &projectLogo = Config_getString("PROJECT_LOGO");
9170   if (!projectLogo.isEmpty())
9171   {
9172     QFileInfo fi(projectLogo);
9173     if (!fi.exists())
9174     {
9175       err("Project logo '%s' specified by PROJECT_LOGO does not exist!\n",projectLogo.data());
9176       projectLogo.resize(0); // revert to the default
9177     }
9178     else
9179     {
9180       QCString destFileName = Config_getString("HTML_OUTPUT")+"/"+fi.fileName().data();
9181       copyFile(projectLogo,destFileName);
9182       Doxygen::indexList->addImageFile(fi.fileName().data());
9183     }
9184   }
9185 }
9186
9187 static void copyExtraFiles(const QCString& filesOption,const QCString &outputOption)
9188 {
9189   QStrList files = Config_getList(filesOption);
9190   uint i;
9191   for (i=0; i<files.count(); ++i)
9192   {
9193     QCString fileName(files.at(i));
9194     
9195     if (!fileName.isEmpty())
9196     {
9197       QFileInfo fi(fileName);
9198       if (!fi.exists()) 
9199       {
9200         err("Extra file '%s' specified in " + filesOption + " does not exist!\n", fileName.data());
9201       }
9202       else
9203       {
9204         QCString destFileName = Config_getString(outputOption)+"/"+fi.fileName().data();
9205         Doxygen::indexList->addImageFile(fi.fileName().utf8());
9206         copyFile(fileName, destFileName);
9207       }
9208     }
9209   }
9210 }
9211
9212 //----------------------------------------------------------------------------
9213
9214 static ParserInterface *getParserForFile(const char *fn)
9215 {
9216   QCString fileName=fn;
9217   QCString extension;
9218   int ei = fileName.findRev('.');
9219   if (ei!=-1)
9220   {
9221     extension=fileName.right(fileName.length()-ei);
9222   }
9223   else
9224   {
9225     extension = ".no_extension";
9226   }
9227
9228   return Doxygen::parserManager->getParser(extension);
9229 }
9230
9231 static void parseFile(ParserInterface *parser,
9232                       Entry *root,EntryNav *rootNav,FileDef *fd,const char *fn,
9233                       bool sameTu,QStrList &filesInSameTu)
9234 {
9235 #if USE_LIBCLANG
9236   static bool clangAssistedParsing = Config_getBool("CLANG_ASSISTED_PARSING");
9237 #else
9238   static bool clangAssistedParsing = FALSE;
9239 #endif
9240   QCString fileName=fn;
9241   QCString extension;
9242   int ei = fileName.findRev('.');
9243   if (ei!=-1)
9244   {
9245     extension=fileName.right(fileName.length()-ei);
9246   }
9247   else
9248   {
9249     extension = ".no_extension";
9250   }
9251
9252   QFileInfo fi(fileName);
9253   BufStr preBuf(fi.size()+4096);
9254
9255   if (Config_getBool("ENABLE_PREPROCESSING") && 
9256       parser->needsPreprocessing(extension))
9257   {
9258     BufStr inBuf(fi.size()+4096);
9259     msg("Preprocessing %s...\n",fn);
9260     readInputFile(fileName,inBuf);
9261     preprocessFile(fileName,inBuf,preBuf);
9262   }
9263   else // no preprocessing
9264   {
9265     msg("Reading %s...\n",fn);
9266     readInputFile(fileName,preBuf);
9267   }
9268
9269   BufStr convBuf(preBuf.curPos()+1024);
9270
9271   // convert multi-line C++ comments to C style comments
9272   convertCppComments(&preBuf,&convBuf,fileName);
9273
9274   convBuf.addChar('\0');
9275
9276   if (clangAssistedParsing && !sameTu)
9277   {
9278     fd->getAllIncludeFilesRecursively(filesInSameTu);
9279   }
9280
9281   // use language parse to parse the file
9282   parser->parseInput(fileName,convBuf.data(),root,sameTu,filesInSameTu);
9283
9284   // store the Entry tree in a file and create an index to
9285   // navigate/load entries
9286   //printf("root->createNavigationIndex for %s\n",fd->name().data());
9287   root->createNavigationIndex(rootNav,g_storage,fd);
9288 }
9289
9290 //! parse the list of input files
9291 static void parseFiles(Entry *root,EntryNav *rootNav)
9292 {
9293 #if USE_LIBCLANG
9294   static bool clangAssistedParsing = Config_getBool("CLANG_ASSISTED_PARSING");
9295   if (clangAssistedParsing)
9296   {
9297     QDict<void> g_processedFiles(10007);
9298
9299     // create a dictionary with files to process
9300     QDict<void> g_filesToProcess(10007);
9301     StringListIterator it(g_inputFiles);
9302     QCString *s;
9303     for (;(s=it.current());++it)
9304     {
9305       g_filesToProcess.insert(*s,(void*)0x8);
9306     }
9307
9308     // process source files (and their include dependencies)
9309     for (it.toFirst();(s=it.current());++it)
9310     {
9311       bool ambig;
9312       FileDef *fd=findFileDef(Doxygen::inputNameDict,s->data(),ambig);
9313       ASSERT(fd!=0);
9314       if (fd->isSource() && !fd->isReference()) // this is a source file
9315       {
9316         QStrList filesInSameTu;
9317         ParserInterface * parser = getParserForFile(s->data());
9318         parser->startTranslationUnit(s->data());
9319         parseFile(parser,root,rootNav,fd,s->data(),FALSE,filesInSameTu);
9320         //printf("  got %d extra files in tu\n",filesInSameTu.count());
9321
9322         // Now process any include files in the same translation unit 
9323         // first. When libclang is used this is much more efficient.
9324         char *incFile = filesInSameTu.first();
9325         while (incFile && g_filesToProcess.find(incFile))
9326         {
9327           if (qstrcmp(incFile,s->data()) && !g_processedFiles.find(incFile))
9328           {
9329             FileDef *ifd=findFileDef(Doxygen::inputNameDict,incFile,ambig);
9330             if (ifd && !ifd->isReference())
9331             {
9332               QStrList moreFiles;
9333               //printf("  Processing %s in same translation unit as %s\n",incFile,s->data());
9334               parseFile(parser,root,rootNav,ifd,incFile,TRUE,moreFiles);
9335               g_processedFiles.insert(incFile,(void*)0x8);
9336             }
9337           }
9338           incFile = filesInSameTu.next();
9339         }
9340         parser->finishTranslationUnit();
9341         g_processedFiles.insert(*s,(void*)0x8);
9342       }
9343     }
9344     // process remaining files
9345     for (it.toFirst();(s=it.current());++it)
9346     {
9347       if (!g_processedFiles.find(*s)) // not yet processed
9348       {
9349         bool ambig;
9350         QStrList filesInSameTu;
9351         FileDef *fd=findFileDef(Doxygen::inputNameDict,s->data(),ambig);
9352         ASSERT(fd!=0);
9353         ParserInterface * parser = getParserForFile(s->data());
9354         parser->startTranslationUnit(s->data());
9355         parseFile(parser,root,rootNav,fd,s->data(),FALSE,filesInSameTu);
9356         parser->finishTranslationUnit();
9357         g_processedFiles.insert(*s,(void*)0x8);
9358       }
9359     }
9360   }
9361   else // normal pocessing
9362 #endif
9363   {
9364     StringListIterator it(g_inputFiles);
9365     QCString *s;
9366     for (;(s=it.current());++it)
9367     {
9368       bool ambig;
9369       QStrList filesInSameTu;
9370       FileDef *fd=findFileDef(Doxygen::inputNameDict,s->data(),ambig);
9371       ASSERT(fd!=0);
9372       ParserInterface * parser = getParserForFile(s->data());
9373       parser->startTranslationUnit(s->data());
9374       parseFile(parser,root,rootNav,fd,s->data(),FALSE,filesInSameTu);
9375     }
9376   }
9377 }
9378
9379 // resolves a path that may include symlinks, if a recursive symlink is
9380 // found an empty string is returned.
9381 static QCString resolveSymlink(QCString path)
9382 {
9383   int sepPos=0;
9384   int oldPos=0;
9385   QFileInfo fi;
9386   QDict<void> nonSymlinks;
9387   QDict<void> known;
9388   QCString result = path;
9389   QCString oldPrefix = "/";
9390   do
9391   {
9392 #ifdef WIN32
9393     // UNC path, skip server and share name
9394     if (sepPos==0 && (result.left(2)=="//" || result.left(2)=="\\\\")) 
9395       sepPos = result.find('/',2);
9396     if (sepPos!=-1) 
9397       sepPos = result.find('/',sepPos+1);
9398 #else
9399     sepPos = result.find('/',sepPos+1);
9400 #endif
9401     QCString prefix = sepPos==-1 ? result : result.left(sepPos);
9402     if (nonSymlinks.find(prefix)==0)
9403     {
9404       fi.setFile(prefix);
9405       if (fi.isSymLink())
9406       {
9407         QString target = fi.readLink();
9408         bool isRelative = QFileInfo(target).isRelative();
9409         if (isRelative)
9410         {
9411           target = QDir::cleanDirPath(oldPrefix+"/"+target.data());
9412         }
9413         if (sepPos!=-1)
9414         {
9415           if (fi.isDir() && target.length()>0 && target.at(target.length()-1)!='/')
9416           {
9417             target+='/';
9418           }
9419           target+=result.mid(sepPos);
9420         }
9421         result = QDir::cleanDirPath(target).data();
9422         sepPos = 0;
9423         if (known.find(result)) return QCString(); // recursive symlink!
9424         known.insert(result,(void*)0x8);
9425         if (isRelative)
9426         {
9427           sepPos = oldPos;
9428         }
9429         else // link to absolute path
9430         {
9431           sepPos = 0;
9432           oldPrefix = "/";
9433         }
9434       }
9435       else
9436       {
9437         nonSymlinks.insert(prefix,(void*)0x8);
9438         oldPrefix = prefix;
9439       }
9440       oldPos = sepPos;
9441     }
9442   }
9443   while (sepPos!=-1);
9444   return QDir::cleanDirPath(result).data();
9445 }
9446
9447 static QDict<void> g_pathsVisited(1009);
9448
9449 //----------------------------------------------------------------------------
9450 // Read all files matching at least one pattern in `patList' in the 
9451 // directory represented by `fi'.
9452 // The directory is read iff the recusiveFlag is set.
9453 // The contents of all files is append to the input string
9454
9455 int readDir(QFileInfo *fi,
9456             FileNameList *fnList,
9457             FileNameDict *fnDict,
9458             StringDict  *exclDict,
9459             QStrList *patList,
9460             QStrList *exclPatList,
9461             StringList *resultList,
9462             StringDict *resultDict,
9463             bool errorIfNotExist,
9464             bool recursive,
9465             QDict<void> *killDict,
9466             QDict<void> *paths
9467            )
9468 {
9469   QCString dirName = fi->absFilePath().utf8();
9470   if (paths && paths->find(dirName)==0)
9471   {
9472     paths->insert(dirName,(void*)0x8);
9473   }
9474   if (fi->isSymLink())
9475   {
9476     dirName = resolveSymlink(dirName.data());
9477     if (dirName.isEmpty()) return 0;            // recusive symlink
9478     if (g_pathsVisited.find(dirName)) return 0; // already visited path
9479     g_pathsVisited.insert(dirName,(void*)0x8);
9480   }
9481   QDir dir(dirName);
9482   dir.setFilter( QDir::Files | QDir::Dirs | QDir::Hidden );
9483   int totalSize=0;
9484   msg("Searching for files in directory %s\n", fi->absFilePath().data());
9485   //printf("killDict=%p count=%d\n",killDict,killDict->count());
9486   
9487   const QFileInfoList *list = dir.entryInfoList();
9488   if (list)
9489   {
9490     QFileInfoListIterator it( *list );
9491     QFileInfo *cfi;
9492
9493     while ((cfi=it.current()))
9494     {
9495       if (exclDict==0 || exclDict->find(cfi->absFilePath().utf8())==0) 
9496       { // file should not be excluded
9497         //printf("killDict->find(%s)\n",cfi->absFilePath().data());
9498         if (!cfi->exists() || !cfi->isReadable())
9499         {
9500           if (errorIfNotExist)
9501           {
9502             warn_uncond("source %s is not a readable file or directory... skipping.\n",cfi->absFilePath().data());
9503           }
9504         }
9505         else if (cfi->isFile() && 
9506             (!Config_getBool("EXCLUDE_SYMLINKS") || !cfi->isSymLink()) &&
9507             (patList==0 || patternMatch(*cfi,patList)) && 
9508             !patternMatch(*cfi,exclPatList) &&
9509             (killDict==0 || killDict->find(cfi->absFilePath().utf8())==0)
9510             )
9511         {
9512           totalSize+=cfi->size()+cfi->absFilePath().length()+4;
9513           QCString name=cfi->fileName().utf8();
9514           //printf("New file %s\n",name.data());
9515           if (fnDict)
9516           {
9517             FileDef  *fd=new FileDef(cfi->dirPath().utf8()+"/",name);
9518             FileName *fn=0;
9519             if (!name.isEmpty() && (fn=(*fnDict)[name]))
9520             {
9521               fn->append(fd);
9522             }
9523             else
9524             {
9525               fn = new FileName(cfi->absFilePath().utf8(),name);
9526               fn->append(fd);
9527               if (fnList) fnList->inSort(fn);
9528               fnDict->insert(name,fn);
9529             }
9530           }
9531           QCString *rs=0;
9532           if (resultList || resultDict)
9533           {
9534             rs=new QCString(cfi->absFilePath().utf8());
9535           }
9536           if (resultList) resultList->append(rs);
9537           if (resultDict) resultDict->insert(cfi->absFilePath().utf8(),rs);
9538           if (killDict) killDict->insert(cfi->absFilePath().utf8(),(void *)0x8);
9539         }
9540         else if (recursive &&
9541             (!Config_getBool("EXCLUDE_SYMLINKS") || !cfi->isSymLink()) &&
9542             cfi->isDir() && 
9543             !patternMatch(*cfi,exclPatList) &&
9544             cfi->fileName().at(0)!='.') // skip "." ".." and ".dir"
9545         {
9546           cfi->setFile(cfi->absFilePath());
9547           totalSize+=readDir(cfi,fnList,fnDict,exclDict,
9548               patList,exclPatList,resultList,resultDict,errorIfNotExist,
9549               recursive,killDict,paths);
9550         }
9551       }
9552       ++it;
9553     }
9554   }
9555   return totalSize;
9556 }
9557
9558
9559 //----------------------------------------------------------------------------
9560 // read a file or all files in a directory and append their contents to the
9561 // input string. The names of the files are appended to the `fiList' list.
9562
9563 int readFileOrDirectory(const char *s,
9564                         FileNameList *fnList,
9565                         FileNameDict *fnDict,
9566                         StringDict *exclDict,
9567                         QStrList *patList,
9568                         QStrList *exclPatList,
9569                         StringList *resultList,
9570                         StringDict *resultDict,
9571                         bool recursive,
9572                         bool errorIfNotExist,
9573                         QDict<void> *killDict,
9574                         QDict<void> *paths
9575                        )
9576 {
9577   //printf("killDict=%p count=%d\n",killDict,killDict->count());
9578   // strip trailing slashes
9579   if (s==0) return 0;
9580   QCString fs = s;
9581   char lc = fs.at(fs.length()-1);
9582   if (lc=='/' || lc=='\\') fs = fs.left(fs.length()-1);
9583
9584   QFileInfo fi(fs);
9585   //printf("readFileOrDirectory(%s)\n",s);
9586   int totalSize=0;
9587   {
9588     if (exclDict==0 || exclDict->find(fi.absFilePath().utf8())==0)
9589     {
9590       if (!fi.exists() || !fi.isReadable())
9591       {
9592         if (errorIfNotExist)
9593         {
9594           warn_uncond("source %s is not a readable file or directory... skipping.\n",s);
9595         }
9596       }
9597       else if (!Config_getBool("EXCLUDE_SYMLINKS") || !fi.isSymLink())
9598       {
9599         if (fi.isFile())
9600         {
9601           QCString dirPath = fi.dirPath(TRUE).utf8();
9602           QCString filePath = fi.absFilePath().utf8();
9603           if (paths && paths->find(dirPath))
9604           {
9605             paths->insert(dirPath,(void*)0x8);
9606           }
9607           //printf("killDict->find(%s)\n",fi.absFilePath().data());
9608           if (killDict==0 || killDict->find(filePath)==0)
9609           {
9610             totalSize+=fi.size()+fi.absFilePath().length()+4; //readFile(&fi,fiList,input); 
9611             //fiList->inSort(new FileInfo(fi));
9612             QCString name=fi.fileName().utf8();
9613             //printf("New file %s\n",name.data());
9614             if (fnDict)
9615             {
9616               FileDef  *fd=new FileDef(dirPath+"/",name);
9617               FileName *fn=0;
9618               if (!name.isEmpty() && (fn=(*fnDict)[name]))
9619               {
9620                 fn->append(fd);
9621               }
9622               else
9623               {
9624                 fn = new FileName(filePath,name);
9625                 fn->append(fd);
9626                 if (fnList) fnList->inSort(fn);
9627                 fnDict->insert(name,fn);
9628               }
9629             }
9630             QCString *rs=0;
9631             if (resultList || resultDict)
9632             {
9633               rs=new QCString(filePath);
9634               if (resultList) resultList->append(rs);
9635               if (resultDict) resultDict->insert(filePath,rs);
9636             }
9637
9638             if (killDict) killDict->insert(fi.absFilePath().utf8(),(void *)0x8);
9639           }
9640         }
9641         else if (fi.isDir()) // readable dir
9642         {
9643           totalSize+=readDir(&fi,fnList,fnDict,exclDict,patList,
9644               exclPatList,resultList,resultDict,errorIfNotExist,
9645               recursive,killDict,paths);
9646         }
9647       }
9648     }
9649   }
9650   return totalSize;
9651 }
9652
9653 //----------------------------------------------------------------------------
9654
9655 void readFormulaRepository()
9656 {
9657   QFile f(Config_getString("HTML_OUTPUT")+"/formula.repository");
9658   if (f.open(IO_ReadOnly)) // open repository
9659   {
9660     msg("Reading formula repository...\n");
9661     QTextStream t(&f);
9662     QCString line;
9663     while (!t.eof())
9664     {
9665       line=t.readLine().utf8();
9666       int se=line.find(':'); // find name and text separator.
9667       if (se==-1)
9668       {
9669         warn_uncond("formula.repository is corrupted!\n");
9670         break;
9671       }
9672       else
9673       {
9674         QCString formName = line.left(se);
9675         QCString formText = line.right(line.length()-se-1); 
9676         Formula *f=new Formula(formText);
9677         Doxygen::formulaList->setAutoDelete(TRUE);
9678         Doxygen::formulaList->append(f);
9679         Doxygen::formulaDict->insert(formText,f);
9680         Doxygen::formulaNameDict->insert(formName,f);
9681       }
9682     }
9683   }
9684 }
9685
9686 //----------------------------------------------------------------------------
9687
9688 static void expandAliases()
9689 {
9690   QDictIterator<QCString> adi(Doxygen::aliasDict);
9691   QCString *s;
9692   for (adi.toFirst();(s=adi.current());++adi)
9693   {
9694     *s = expandAlias(adi.currentKey(),*s);
9695   }
9696 }
9697
9698 //----------------------------------------------------------------------------
9699
9700 static void escapeAliases()
9701 {
9702   QDictIterator<QCString> adi(Doxygen::aliasDict);
9703   QCString *s;
9704   for (adi.toFirst();(s=adi.current());++adi)
9705   {
9706     QCString value=*s,newValue;
9707     int in,p=0;
9708     // for each \n in the alias command value
9709     while ((in=value.find("\\n",p))!=-1)
9710     {
9711       newValue+=value.mid(p,in-p);
9712       // expand \n's except if \n is part of a built-in command.
9713       if (value.mid(in,5)!="\\note" && 
9714           value.mid(in,5)!="\\name" && 
9715           value.mid(in,10)!="\\namespace" && 
9716           value.mid(in,14)!="\\nosubgrouping"
9717          ) 
9718       {
9719         newValue+="\\_linebr ";
9720       }
9721       else 
9722       {
9723         newValue+="\\n";
9724       }
9725       p=in+2;
9726     }
9727     newValue+=value.mid(p,value.length()-p);
9728     *s=newValue;
9729     //printf("Alias %s has value %s\n",adi.currentKey().data(),s->data());
9730   }
9731 }
9732
9733 //----------------------------------------------------------------------------
9734
9735 void readAliases()
9736
9737   // add aliases to a dictionary
9738   Doxygen::aliasDict.setAutoDelete(TRUE);
9739   QStrList &aliasList = Config_getList("ALIASES");
9740   const char *s=aliasList.first();
9741   while (s)
9742   {
9743     if (Doxygen::aliasDict[s]==0)
9744     {
9745       QCString alias=s;
9746       int i=alias.find('=');
9747       if (i>0)
9748       {
9749         QCString name=alias.left(i).stripWhiteSpace();
9750         QCString value=alias.right(alias.length()-i-1);
9751         //printf("Alias: found name=`%s' value=`%s'\n",name.data(),value.data()); 
9752         if (!name.isEmpty())
9753         {
9754           QCString *dn=Doxygen::aliasDict[name];
9755           if (dn==0) // insert new alias
9756           {
9757             Doxygen::aliasDict.insert(name,new QCString(value));
9758           }
9759           else // overwrite previous alias
9760           {
9761             *dn=value;
9762           }
9763         }
9764       }
9765     }
9766     s=aliasList.next();
9767   }
9768   expandAliases();
9769   escapeAliases();
9770 }
9771
9772 //----------------------------------------------------------------------------
9773
9774 static void dumpSymbol(FTextStream &t,Definition *d)
9775 {
9776   QCString anchor;
9777   if (d->definitionType()==Definition::TypeMember)
9778   {
9779     MemberDef *md = (MemberDef *)d;
9780     anchor=":"+md->anchor();
9781   }
9782   QCString scope;
9783   if (d->getOuterScope() && d->getOuterScope()!=Doxygen::globalScope) 
9784   {
9785     scope = d->getOuterScope()->getOutputFileBase()+Doxygen::htmlFileExtension;
9786   }
9787   t << "REPLACE INTO symbols (symbol_id,scope_id,name,file,line) VALUES('"
9788     << d->getOutputFileBase()+Doxygen::htmlFileExtension+anchor << "','"
9789     << scope << "','"
9790     << d->name() << "','"
9791     << d->getDefFileName() << "','"
9792     << d->getDefLine()
9793     << "');" << endl;
9794 }
9795
9796 static void dumpSymbolMap()
9797
9798   QFile f("symbols.sql");
9799   if (f.open(IO_WriteOnly))
9800   {
9801     FTextStream t(&f);
9802     QDictIterator<DefinitionIntf> di(*Doxygen::symbolMap);
9803     DefinitionIntf *intf;
9804     for (;(intf=di.current());++di)
9805     {
9806       if (intf->definitionType()==DefinitionIntf::TypeSymbolList) // list of symbols
9807       {
9808         DefinitionListIterator dli(*(DefinitionList*)intf);
9809         Definition *d;
9810         // for each symbol
9811         for (dli.toFirst();(d=dli.current());++dli)
9812         {
9813           dumpSymbol(t,d);
9814         }
9815       }
9816       else // single symbol
9817       {
9818         Definition *d = (Definition *)intf;
9819         if (d!=Doxygen::globalScope) dumpSymbol(t,d);
9820       }
9821     }
9822   }
9823 }
9824
9825 // print developer options of doxygen
9826 static void devUsage()
9827 {
9828   msg("Developer parameters:\n");
9829   msg("  -m          dump symbol map\n");
9830   msg("  -b          output to wizard\n");
9831   msg("  -T          activates output generation via Django like template\n");
9832   msg("  -d <level>  enable a debug level, such as (multiple invocations of -d are possible):\n");
9833   Debug::printFlags();
9834 }
9835
9836
9837 //----------------------------------------------------------------------------
9838 // print the usage of doxygen
9839
9840 static void usage(const char *name)
9841 {
9842   msg("Doxygen version %s\nCopyright Dimitri van Heesch 1997-2014\n\n",versionString);
9843   msg("You can use doxygen in a number of ways:\n\n");
9844   msg("1) Use doxygen to generate a template configuration file:\n");
9845   msg("    %s [-s] -g [configName]\n\n",name);
9846   msg("    If - is used for configName doxygen will write to standard output.\n\n");
9847   msg("2) Use doxygen to update an old configuration file:\n");
9848   msg("    %s [-s] -u [configName]\n\n",name);
9849   msg("3) Use doxygen to generate documentation using an existing ");
9850   msg("configuration file:\n");
9851   msg("    %s [configName]\n\n",name);
9852   msg("    If - is used for configName doxygen will read from standard input.\n\n");
9853   msg("4) Use doxygen to generate a template file controlling the layout of the\n");
9854   msg("   generated documentation:\n");
9855   msg("    %s -l layoutFileName.xml\n\n",name);
9856   msg("5) Use doxygen to generate a template style sheet file for RTF, HTML or Latex.\n");
9857   msg("    RTF:        %s -w rtf styleSheetFile\n",name);
9858   msg("    HTML:       %s -w html headerFile footerFile styleSheetFile [configFile]\n",name);
9859   msg("    LaTeX:      %s -w latex headerFile footerFile styleSheetFile [configFile]\n\n",name);
9860   msg("6) Use doxygen to generate a rtf extensions file\n");
9861   msg("    RTF:   %s -e rtf extensionsFile\n\n",name);
9862   msg("If -s is specified the comments of the configuration items in the config file will be omitted.\n");
9863   msg("If configName is omitted `Doxyfile' will be used as a default.\n\n");
9864   msg("-v print version string\n");
9865 }
9866
9867 //----------------------------------------------------------------------------
9868 // read the argument of option `c' from the comment argument list and
9869 // update the option index `optind'.
9870
9871 static const char *getArg(int argc,char **argv,int &optind)
9872 {
9873   char *s=0;
9874   if (qstrlen(&argv[optind][2])>0)
9875     s=&argv[optind][2];
9876   else if (optind+1<argc && argv[optind+1][0]!='-')
9877     s=argv[++optind];
9878   return s;
9879 }
9880
9881 //----------------------------------------------------------------------------
9882
9883 void initDoxygen()
9884 {
9885   const char *lang = portable_getenv("LC_ALL");
9886   if (lang) portable_setenv("LANG",lang);
9887   setlocale(LC_ALL,"");
9888   setlocale(LC_CTYPE,"C"); // to get isspace(0xA0)==0, needed for UTF-8
9889   setlocale(LC_NUMERIC,"C");
9890
9891   Doxygen::runningTime.start();
9892   initPreprocessor();
9893
9894   Doxygen::parserManager = new ParserManager;
9895   Doxygen::parserManager->registerParser("c",            new CLanguageScanner, TRUE);
9896   Doxygen::parserManager->registerParser("python",       new PythonLanguageScanner);
9897   Doxygen::parserManager->registerParser("fortran",      new FortranLanguageScanner);
9898   Doxygen::parserManager->registerParser("fortranfree",  new FortranLanguageScannerFree);
9899   Doxygen::parserManager->registerParser("fortranfixed", new FortranLanguageScannerFixed);
9900   Doxygen::parserManager->registerParser("vhdl",         new VHDLLanguageScanner);
9901   Doxygen::parserManager->registerParser("dbusxml",      new DBusXMLScanner);
9902   Doxygen::parserManager->registerParser("tcl",          new TclLanguageScanner);
9903   Doxygen::parserManager->registerParser("md",           new MarkdownFileParser);
9904
9905   // register any additional parsers here...
9906
9907   initDefaultExtensionMapping();
9908   initClassMemberIndices();
9909   initNamespaceMemberIndices();
9910   initFileMemberIndices();
9911
9912   Doxygen::symbolMap     = new QDict<DefinitionIntf>(50177);
9913 #ifdef USE_LIBCLANG
9914   Doxygen::clangUsrMap   = new QDict<Definition>(50177);
9915 #endif
9916   Doxygen::inputNameList = new FileNameList;
9917   Doxygen::inputNameList->setAutoDelete(TRUE);
9918   Doxygen::memberNameSDict = new MemberNameSDict(10000);   
9919   Doxygen::memberNameSDict->setAutoDelete(TRUE);
9920   Doxygen::functionNameSDict = new MemberNameSDict(10000);   
9921   Doxygen::functionNameSDict->setAutoDelete(TRUE);
9922   Doxygen::groupSDict = new GroupSDict(17);          
9923   Doxygen::groupSDict->setAutoDelete(TRUE);
9924   Doxygen::globalScope = new NamespaceDef("<globalScope>",1,1,"<globalScope>");
9925   Doxygen::namespaceSDict = new NamespaceSDict(20);      
9926   Doxygen::namespaceSDict->setAutoDelete(TRUE);
9927   Doxygen::classSDict = new ClassSDict(1009);         
9928   Doxygen::classSDict->setAutoDelete(TRUE);
9929   Doxygen::hiddenClasses = new ClassSDict(257);
9930   Doxygen::hiddenClasses->setAutoDelete(TRUE);
9931   Doxygen::directories = new DirSDict(17);
9932   Doxygen::directories->setAutoDelete(TRUE);
9933   Doxygen::pageSDict = new PageSDict(1009);          // all doc pages
9934   Doxygen::pageSDict->setAutoDelete(TRUE);
9935   Doxygen::exampleSDict = new PageSDict(1009);       // all examples
9936   Doxygen::exampleSDict->setAutoDelete(TRUE);
9937   Doxygen::inputNameDict = new FileNameDict(10007);
9938   Doxygen::includeNameDict = new FileNameDict(10007);
9939   Doxygen::exampleNameDict = new FileNameDict(1009);
9940   Doxygen::exampleNameDict->setAutoDelete(TRUE);
9941   Doxygen::imageNameDict = new FileNameDict(257);
9942   Doxygen::imageNameDict->setAutoDelete(TRUE);
9943   Doxygen::dotFileNameDict = new FileNameDict(257);
9944   Doxygen::mscFileNameDict = new FileNameDict(257);
9945   Doxygen::diaFileNameDict = new FileNameDict(257);
9946   Doxygen::memGrpInfoDict.setAutoDelete(TRUE);
9947   Doxygen::tagDestinationDict.setAutoDelete(TRUE);
9948   Doxygen::dirRelations.setAutoDelete(TRUE);
9949   Doxygen::citeDict = new CiteDict(257);
9950   Doxygen::genericsDict = new GenericsSDict;
9951   Doxygen::indexList = new IndexList;
9952   Doxygen::formulaList = new FormulaList;
9953   Doxygen::formulaDict = new FormulaDict(1009);
9954   Doxygen::formulaNameDict = new FormulaDict(1009);
9955   Doxygen::sectionDict = new SectionDict(257);
9956   Doxygen::sectionDict->setAutoDelete(TRUE);
9957
9958   /**************************************************************************
9959    *            Initialize some global constants
9960    **************************************************************************/
9961   
9962   g_compoundKeywordDict.insert("template class",(void *)8);
9963   g_compoundKeywordDict.insert("template struct",(void *)8);
9964   g_compoundKeywordDict.insert("class",(void *)8);
9965   g_compoundKeywordDict.insert("struct",(void *)8);
9966   g_compoundKeywordDict.insert("union",(void *)8);
9967   g_compoundKeywordDict.insert("interface",(void *)8);
9968   g_compoundKeywordDict.insert("exception",(void *)8);
9969
9970 }
9971
9972 void cleanUpDoxygen()
9973 {
9974   delete Doxygen::sectionDict;
9975   delete Doxygen::formulaNameDict;
9976   delete Doxygen::formulaDict;
9977   delete Doxygen::formulaList;
9978   delete Doxygen::indexList;
9979   delete Doxygen::genericsDict;
9980   delete Doxygen::inputNameDict;
9981   delete Doxygen::includeNameDict;
9982   delete Doxygen::exampleNameDict;
9983   delete Doxygen::imageNameDict;
9984   delete Doxygen::dotFileNameDict;
9985   delete Doxygen::mscFileNameDict;
9986   delete Doxygen::diaFileNameDict;
9987   delete Doxygen::mainPage;
9988   delete Doxygen::pageSDict;  
9989   delete Doxygen::exampleSDict;
9990   delete Doxygen::globalScope;
9991   delete Doxygen::xrefLists;
9992   delete Doxygen::parserManager;
9993   cleanUpPreprocessor();
9994   delete theTranslator;
9995   delete g_outputList;
9996   Mappers::freeMappers();
9997   codeFreeScanner();
9998
9999   if (Doxygen::symbolMap)
10000   {
10001     // iterate through Doxygen::symbolMap and delete all
10002     // DefinitionList objects, since they have no owner
10003     QDictIterator<DefinitionIntf> dli(*Doxygen::symbolMap);
10004     DefinitionIntf *di;
10005     for (dli.toFirst();(di=dli.current());)
10006     {
10007       if (di->definitionType()==DefinitionIntf::TypeSymbolList)
10008       {
10009         DefinitionIntf *tmp = Doxygen::symbolMap->take(dli.currentKey());
10010         delete (DefinitionList *)tmp;
10011       }
10012       else
10013       {
10014         ++dli;
10015       }
10016     } 
10017   }
10018
10019   delete Doxygen::inputNameList;
10020   delete Doxygen::memberNameSDict;
10021   delete Doxygen::functionNameSDict;
10022   delete Doxygen::groupSDict;
10023   delete Doxygen::classSDict;
10024   delete Doxygen::hiddenClasses;
10025   delete Doxygen::namespaceSDict;
10026   delete Doxygen::directories;
10027
10028   //delete Doxygen::symbolMap; <- we cannot do this unless all static lists 
10029   //                              (such as Doxygen::namespaceSDict)
10030   //                              with objects based on Definition are made
10031   //                              dynamic first
10032 }
10033
10034 static int computeIdealCacheParam(uint v)
10035 {
10036   //printf("computeIdealCacheParam(v=%u)\n",v);
10037
10038   int r=0;
10039   while (v!=0) v>>=1,r++; 
10040   // r = log2(v)
10041
10042   // convert to a valid cache size value
10043   return QMAX(0,QMIN(r-16,9));
10044 }
10045
10046 void readConfiguration(int argc, char **argv)
10047 {
10048   /**************************************************************************
10049    *             Handle arguments                                           *
10050    **************************************************************************/
10051
10052   int optind=1;
10053   const char *configName=0;
10054   const char *layoutName=0;
10055   const char *debugLabel;
10056   const char *formatName;
10057   bool genConfig=FALSE;
10058   bool shortList=FALSE;
10059   bool updateConfig=FALSE;
10060   bool genLayout=FALSE;
10061   int retVal;
10062   while (optind<argc && argv[optind][0]=='-' && 
10063                (isalpha(argv[optind][1]) || argv[optind][1]=='?' || 
10064                 argv[optind][1]=='-')
10065         )
10066   {
10067     switch(argv[optind][1])
10068     {
10069       case 'g':
10070         genConfig=TRUE;
10071         configName=getArg(argc,argv,optind);
10072         if (optind+1<argc && qstrcmp(argv[optind+1],"-")==0)
10073         { configName="-"; optind++; }
10074         if (!configName) 
10075         { configName="Doxyfile"; }
10076         break;
10077       case 'l':
10078         genLayout=TRUE;
10079         layoutName=getArg(argc,argv,optind);
10080         if (!layoutName)
10081         { layoutName="DoxygenLayout.xml"; }
10082         break;
10083       case 'd':
10084         debugLabel=getArg(argc,argv,optind);
10085         if (!debugLabel)
10086         {
10087           err("option \"-d\" is missing debug specifier.\n");
10088           devUsage();
10089           cleanUpDoxygen();
10090           exit(1);
10091         }
10092         retVal = Debug::setFlag(debugLabel);
10093         if (!retVal)
10094         {
10095           err("option \"-d\" has unknown debug specifier: \"%s\".\n",debugLabel);
10096           cleanUpDoxygen();
10097           exit(1);
10098         }
10099         break;
10100       case 's':
10101         shortList=TRUE;
10102         break;
10103       case 'u':
10104         updateConfig=TRUE;
10105         break;
10106       case 'e':
10107         formatName=getArg(argc,argv,optind);
10108         if (!formatName)
10109         {
10110           err("option \"-e\" is missing format specifier rtf.\n");
10111           cleanUpDoxygen();
10112           exit(1);
10113         }
10114         if (qstricmp(formatName,"rtf")==0)
10115         {
10116           if (optind+1>=argc)
10117           {
10118             err("option \"-e rtf\" is missing an extensions file name\n");
10119             cleanUpDoxygen();
10120             exit(1);
10121           }
10122           QFile f;
10123           if (openOutputFile(argv[optind+1],f))
10124           {
10125             RTFGenerator::writeExtensionsFile(f);
10126           }
10127           cleanUpDoxygen();
10128           exit(0);
10129         }
10130         err("option \"-e\" has invalid format specifier.\n");
10131         cleanUpDoxygen();
10132         exit(1);
10133         break; 
10134       case 'w':
10135         formatName=getArg(argc,argv,optind);
10136         if (!formatName)
10137         {
10138           err("option \"-w\" is missing format specifier rtf, html or latex\n");
10139           cleanUpDoxygen();
10140           exit(1);
10141         } 
10142         if (qstricmp(formatName,"rtf")==0)
10143         {
10144           if (optind+1>=argc)
10145           {
10146             err("option \"-w rtf\" is missing a style sheet file name\n");
10147             cleanUpDoxygen();
10148             exit(1);
10149           }
10150           QFile f;
10151           if (openOutputFile(argv[optind+1],f))
10152           {
10153             RTFGenerator::writeStyleSheetFile(f);
10154           }
10155           cleanUpDoxygen();
10156           exit(1);
10157         }
10158         else if (qstricmp(formatName,"html")==0)
10159         {
10160           if (optind+4<argc || QFileInfo("Doxyfile").exists())
10161           {
10162             QCString df = optind+4<argc ? argv[optind+4] : QCString("Doxyfile");
10163             if (!Config::instance()->parse(df))
10164             {
10165               err("error opening or reading configuration file %s!\n",argv[optind+4]);
10166               cleanUpDoxygen();
10167               exit(1);
10168             }
10169             Config::instance()->substituteEnvironmentVars();
10170             Config::instance()->convertStrToVal();
10171             // avoid bootstrapping issues when the config file already
10172             // refers to the files that we are supposed to parse.
10173             Config_getString("HTML_HEADER")="";
10174             Config_getString("HTML_FOOTER")="";
10175             Config::instance()->check();
10176           }
10177           else
10178           {
10179             Config::instance()->init();
10180           }
10181           if (optind+3>=argc)
10182           {
10183             err("option \"-w html\" does not have enough arguments\n");
10184             cleanUpDoxygen();
10185             exit(1);
10186           }
10187
10188           QCString outputLanguage=Config_getEnum("OUTPUT_LANGUAGE");
10189           if (!setTranslator(outputLanguage))
10190           {
10191             warn_uncond("Output language %s not supported! Using English instead.\n", outputLanguage.data());
10192           }
10193
10194           QFile f;
10195           if (openOutputFile(argv[optind+1],f))
10196           {
10197             HtmlGenerator::writeHeaderFile(f, argv[optind+3]);
10198           }
10199           f.close();
10200           if (openOutputFile(argv[optind+2],f))
10201           {
10202             HtmlGenerator::writeFooterFile(f);
10203           }
10204           f.close();
10205           if (openOutputFile(argv[optind+3],f))
10206           {
10207             HtmlGenerator::writeStyleSheetFile(f);
10208           } 
10209           cleanUpDoxygen();
10210           exit(0);
10211         }
10212         else if (qstricmp(formatName,"latex")==0)
10213         {
10214           if (optind+4<argc) // use config file to get settings
10215           {
10216             if (!Config::instance()->parse(argv[optind+4]))
10217             {
10218               err("error opening or reading configuration file %s!\n",argv[optind+4]);
10219               exit(1);
10220             }
10221             Config::instance()->substituteEnvironmentVars();
10222             Config::instance()->convertStrToVal();
10223             Config_getString("LATEX_HEADER")="";
10224             Config::instance()->check();
10225           }
10226           else // use default config
10227           {
10228             Config::instance()->init();
10229           }
10230           if (optind+3>=argc)
10231           {
10232             err("option \"-w latex\" does not have enough arguments\n");
10233             cleanUpDoxygen();
10234             exit(1);
10235           }
10236
10237           QCString outputLanguage=Config_getEnum("OUTPUT_LANGUAGE");
10238           if (!setTranslator(outputLanguage))
10239           {
10240             warn_uncond("Output language %s not supported! Using English instead.\n", outputLanguage.data());
10241           }
10242
10243           QFile f;
10244           if (openOutputFile(argv[optind+1],f))
10245           {
10246             LatexGenerator::writeHeaderFile(f);
10247           }
10248           f.close();
10249           if (openOutputFile(argv[optind+2],f))
10250           {
10251             LatexGenerator::writeFooterFile(f);
10252           }
10253           f.close();
10254           if (openOutputFile(argv[optind+3],f))
10255           {
10256             LatexGenerator::writeStyleSheetFile(f);
10257           }
10258           cleanUpDoxygen();
10259           exit(0);
10260         }
10261         else
10262         {
10263           err("Illegal format specifier \"%s\": should be one of rtf, html or latex\n",formatName);
10264           cleanUpDoxygen();
10265           exit(1);
10266         }
10267         break;
10268       case 'm':
10269         g_dumpSymbolMap = TRUE;
10270         break;
10271       case 'v':
10272         msg("%s\n",versionString); 
10273         cleanUpDoxygen();
10274         exit(0);
10275         break;
10276       case '-':
10277         if (qstrcmp(&argv[optind][2],"help")==0)
10278         {
10279           usage(argv[0]);
10280           exit(0);
10281         }
10282         else if (qstrcmp(&argv[optind][2],"version")==0)
10283         {
10284           msg("%s\n",versionString); 
10285           cleanUpDoxygen();
10286           exit(0);
10287         }
10288         else
10289         {
10290           err("Unknown option \"-%s\"\n",&argv[optind][1]);
10291           usage(argv[0]);
10292           exit(1);
10293         }
10294         break;
10295       case 'b':
10296         setvbuf(stdout,NULL,_IONBF,0);
10297         Doxygen::outputToWizard=TRUE;
10298         break;
10299       case 'T':
10300         msg("Warning: this option activates output generation via Django like template files. "
10301             "This option is scheduled for doxygen 2.0, is currently incomplete and highly experimental! "
10302             "Only use if you are a doxygen developer\n");
10303         g_useOutputTemplate=TRUE;
10304         break;
10305       case 'h':
10306       case '?':
10307         usage(argv[0]);
10308         exit(0);
10309         break;
10310       default:
10311         err("Unknown option \"-%c\"\n",argv[optind][1]);
10312         usage(argv[0]);
10313         exit(1);
10314     }
10315     optind++;
10316   }
10317   
10318   /**************************************************************************
10319    *            Parse or generate the config file                           *
10320    **************************************************************************/
10321
10322   Config::instance()->init();
10323
10324   if (genConfig)
10325   {
10326     generateConfigFile(configName,shortList);
10327     cleanUpDoxygen();
10328     exit(0);
10329   }
10330   if (genLayout)
10331   {
10332     writeDefaultLayoutFile(layoutName);
10333     cleanUpDoxygen();
10334     exit(0);
10335   }
10336
10337   QFileInfo configFileInfo1("Doxyfile"),configFileInfo2("doxyfile");
10338   if (optind>=argc)
10339   { 
10340     if (configFileInfo1.exists()) 
10341     {
10342       configName="Doxyfile";
10343     }
10344     else if (configFileInfo2.exists())
10345     {
10346       configName="doxyfile";
10347     }
10348     else
10349     {
10350       err("Doxyfile not found and no input file specified!\n");
10351       usage(argv[0]);
10352       exit(1);
10353     }
10354   }
10355   else
10356   {
10357     QFileInfo fi(argv[optind]);
10358     if (fi.exists() || qstrcmp(argv[optind],"-")==0)
10359     {
10360       configName=argv[optind];
10361     }
10362     else
10363     {
10364       err("configuration file %s not found!\n",argv[optind]);
10365       usage(argv[0]);
10366       exit(1);
10367     }
10368   }
10369
10370
10371   if (!Config::instance()->parse(configName,updateConfig))
10372   {
10373     err("could not open or read configuration file %s!\n",configName);
10374     cleanUpDoxygen();
10375     exit(1);
10376   }
10377
10378   if (updateConfig)
10379   {
10380     generateConfigFile(configName,shortList,TRUE);
10381     cleanUpDoxygen();
10382     exit(0);
10383   }
10384
10385   /* Perlmod wants to know the path to the config file.*/
10386   QFileInfo configFileInfo(configName);
10387   setPerlModDoxyfile(configFileInfo.absFilePath().data());
10388
10389 }
10390
10391 /** check and resolve config options */
10392 void checkConfiguration()
10393 {
10394   
10395   Config::instance()->substituteEnvironmentVars();
10396   Config::instance()->convertStrToVal();
10397   Config::instance()->check();
10398   
10399   initWarningFormat();
10400 }
10401
10402 /** adjust globals that depend on configuration settings. */
10403 void adjustConfiguration()
10404 {
10405   QCString outputLanguage=Config_getEnum("OUTPUT_LANGUAGE");
10406   if (!setTranslator(outputLanguage))
10407   {
10408     warn_uncond("Output language %s not supported! Using English instead.\n",
10409        outputLanguage.data());
10410   }
10411   QStrList &includePath = Config_getList("INCLUDE_PATH");
10412   char *s=includePath.first();
10413   while (s)
10414   {
10415     QFileInfo fi(s);
10416     addSearchDir(fi.absFilePath().utf8());
10417     s=includePath.next();
10418   }
10419
10420   /* Set the global html file extension. */ 
10421   Doxygen::htmlFileExtension = Config_getString("HTML_FILE_EXTENSION");
10422
10423
10424   Doxygen::xrefLists->setAutoDelete(TRUE);
10425
10426   Doxygen::parseSourcesNeeded = Config_getBool("CALL_GRAPH") || 
10427                                 Config_getBool("CALLER_GRAPH") ||
10428                                 Config_getBool("REFERENCES_RELATION") ||
10429                                 Config_getBool("REFERENCED_BY_RELATION");
10430
10431   Doxygen::markdownSupport = Config_getBool("MARKDOWN_SUPPORT");
10432   
10433   /**************************************************************************
10434    *            Add custom extension mappings
10435    **************************************************************************/
10436
10437   QStrList &extMaps = Config_getList("EXTENSION_MAPPING");
10438   char *mapping = extMaps.first();
10439   while (mapping)
10440   {
10441     QCString mapStr = mapping;
10442     int i;
10443     if ((i=mapStr.find('='))!=-1)
10444     {
10445       QCString ext=mapStr.left(i).stripWhiteSpace().lower();
10446       QCString language=mapStr.mid(i+1).stripWhiteSpace().lower();
10447       if (!updateLanguageMapping(ext,language))
10448       {
10449         err("Failed to map file extension '%s' to unsupported language '%s'.\n"
10450             "Check the EXTENSION_MAPPING setting in the config file.\n", 
10451             ext.data(),language.data());
10452       }
10453       else
10454       {
10455         msg("Adding custom extension mapping: .%s will be treated as language %s\n",
10456             ext.data(),language.data());
10457       }
10458     }
10459     mapping = extMaps.next();
10460   }
10461
10462
10463   // add predefined macro name to a dictionary
10464   QStrList &expandAsDefinedList =Config_getList("EXPAND_AS_DEFINED");
10465   s=expandAsDefinedList.first();
10466   while (s)
10467   {
10468     if (Doxygen::expandAsDefinedDict[s]==0)
10469     {
10470       Doxygen::expandAsDefinedDict.insert(s,(void *)666);
10471     }
10472     s=expandAsDefinedList.next();
10473   }
10474
10475   // read aliases and store them in a dictionary
10476   readAliases();
10477
10478   // store number of spaces in a tab into Doxygen::spaces
10479   int &tabSize = Config_getInt("TAB_SIZE");
10480   Doxygen::spaces.resize(tabSize+1);
10481   int sp;for (sp=0;sp<tabSize;sp++) Doxygen::spaces.at(sp)=' ';
10482   Doxygen::spaces.at(tabSize)='\0';
10483 }
10484
10485 #ifdef HAS_SIGNALS
10486 static void stopDoxygen(int)
10487 {
10488   QDir thisDir;
10489   msg("Cleaning up...\n");
10490   if (!Doxygen::entryDBFileName.isEmpty())
10491   {
10492     thisDir.remove(Doxygen::entryDBFileName);
10493   }
10494   if (!Doxygen::objDBFileName.isEmpty())
10495   {
10496     thisDir.remove(Doxygen::objDBFileName);
10497   }
10498   killpg(0,SIGINT);
10499   exit(1);
10500 }
10501 #endif
10502
10503 static void exitDoxygen()
10504 {
10505   if (!g_successfulRun)  // premature exit
10506   {
10507     QDir thisDir;
10508     msg("Exiting...\n");
10509     if (!Doxygen::entryDBFileName.isEmpty())
10510     {
10511       thisDir.remove(Doxygen::entryDBFileName);
10512     }
10513     if (!Doxygen::objDBFileName.isEmpty())
10514     {
10515       thisDir.remove(Doxygen::objDBFileName);
10516     }
10517   }
10518 }
10519
10520 static QCString createOutputDirectory(const QCString &baseDirName,
10521                                   const char *formatDirOption,
10522                                   const char *defaultDirName)
10523 {
10524   // Note the & on the next line, we modify the formatDirOption!
10525   QCString &formatDirName = Config_getString(formatDirOption);
10526   if (formatDirName.isEmpty())
10527   {
10528     formatDirName = baseDirName + defaultDirName;
10529   }
10530   else if (formatDirName[0]!='/' && (formatDirName.length()==1 || formatDirName[1]!=':'))
10531   {
10532     formatDirName.prepend(baseDirName+'/');
10533   }
10534   QDir formatDir(formatDirName);
10535   if (!formatDir.exists() && !formatDir.mkdir(formatDirName))
10536   {
10537     err("Could not create output directory %s\n", formatDirName.data());
10538     cleanUpDoxygen();
10539     exit(1);
10540   }
10541   return formatDirName;
10542 }
10543
10544 static QCString getQchFileName()
10545 {
10546   QCString const & qchFile = Config_getString("QCH_FILE");
10547   if (!qchFile.isEmpty())
10548   {
10549     return qchFile;
10550   }
10551
10552   QCString const & projectName = Config_getString("PROJECT_NAME");
10553   QCString const & versionText = Config_getString("PROJECT_NUMBER");
10554
10555   return QCString("../qch/")
10556       + (projectName.isEmpty() ? QCString("index") : projectName)
10557       + (versionText.isEmpty() ? QCString("") : QCString("-") + versionText)
10558       + QCString(".qch");
10559 }
10560
10561 void searchInputFiles()
10562 {
10563   QStrList &exclPatterns = Config_getList("EXCLUDE_PATTERNS");
10564   bool alwaysRecursive = Config_getBool("RECURSIVE");
10565   StringDict excludeNameDict(1009);
10566   excludeNameDict.setAutoDelete(TRUE);
10567
10568   // gather names of all files in the include path
10569   g_s.begin("Searching for include files...\n");
10570   QStrList &includePathList = Config_getList("INCLUDE_PATH");
10571   char *s=includePathList.first();
10572   while (s)
10573   {
10574     QStrList &pl = Config_getList("INCLUDE_FILE_PATTERNS");
10575     if (pl.count()==0) 
10576     {
10577       pl = Config_getList("FILE_PATTERNS");
10578     }
10579     readFileOrDirectory(s,0,Doxygen::includeNameDict,0,&pl,
10580                         &exclPatterns,0,0,
10581                         alwaysRecursive);
10582     s=includePathList.next(); 
10583   }
10584   g_s.end();
10585
10586   g_s.begin("Searching for example files...\n");
10587   QStrList &examplePathList = Config_getList("EXAMPLE_PATH");
10588   s=examplePathList.first();
10589   while (s)
10590   {
10591     readFileOrDirectory(s,0,Doxygen::exampleNameDict,0,
10592                         &Config_getList("EXAMPLE_PATTERNS"),
10593                         0,0,0,
10594                         (alwaysRecursive || Config_getBool("EXAMPLE_RECURSIVE")));
10595     s=examplePathList.next(); 
10596   }
10597   g_s.end();
10598
10599   g_s.begin("Searching for images...\n");
10600   QStrList &imagePathList=Config_getList("IMAGE_PATH");
10601   s=imagePathList.first();
10602   while (s)
10603   {
10604     readFileOrDirectory(s,0,Doxygen::imageNameDict,0,0,
10605                         0,0,0,
10606                         alwaysRecursive);
10607     s=imagePathList.next(); 
10608   }
10609   g_s.end();
10610
10611   g_s.begin("Searching for dot files...\n");
10612   QStrList &dotFileList=Config_getList("DOTFILE_DIRS");
10613   s=dotFileList.first();
10614   while (s)
10615   {
10616     readFileOrDirectory(s,0,Doxygen::dotFileNameDict,0,0,
10617                         0,0,0,
10618                         alwaysRecursive);
10619     s=dotFileList.next(); 
10620   }
10621   g_s.end();
10622
10623   g_s.begin("Searching for msc files...\n");
10624   QStrList &mscFileList=Config_getList("MSCFILE_DIRS");
10625   s=mscFileList.first();
10626   while (s)
10627   {
10628     readFileOrDirectory(s,0,Doxygen::mscFileNameDict,0,0,
10629                         0,0,0,
10630                         alwaysRecursive);
10631     s=mscFileList.next(); 
10632   }
10633   g_s.end();
10634
10635   g_s.begin("Searching for dia files...\n");
10636   QStrList &diaFileList=Config_getList("DIAFILE_DIRS");
10637   s=diaFileList.first();
10638   while (s)
10639   {
10640     readFileOrDirectory(s,0,Doxygen::diaFileNameDict,0,0,
10641                         0,0,0,
10642                         alwaysRecursive);
10643     s=diaFileList.next();
10644   }
10645   g_s.end();
10646
10647   g_s.begin("Searching for files to exclude\n");
10648   QStrList &excludeList = Config_getList("EXCLUDE");
10649   s=excludeList.first();
10650   while (s)
10651   {
10652     readFileOrDirectory(s,0,0,0,&Config_getList("FILE_PATTERNS"),
10653                         0,0,&excludeNameDict,
10654                         alwaysRecursive,
10655                         FALSE);
10656     s=excludeList.next();
10657   }
10658   g_s.end();
10659
10660   /**************************************************************************
10661    *             Determine Input Files                                      *
10662    **************************************************************************/
10663
10664   g_s.begin("Searching for files to process...\n");
10665   QDict<void> *killDict = new QDict<void>(10007);
10666   int inputSize=0;
10667   QStrList &inputList=Config_getList("INPUT");
10668   g_inputFiles.setAutoDelete(TRUE);
10669   s=inputList.first();
10670   while (s)
10671   {
10672     QCString path=s;
10673     uint l = path.length();
10674     if (l>0)
10675     {
10676       // strip trailing slashes
10677       if (path.at(l-1)=='\\' || path.at(l-1)=='/') path=path.left(l-1);
10678   
10679       inputSize+=readFileOrDirectory(
10680           path,
10681           Doxygen::inputNameList,
10682           Doxygen::inputNameDict,
10683           &excludeNameDict,
10684           &Config_getList("FILE_PATTERNS"),
10685           &exclPatterns,
10686           &g_inputFiles,0,
10687           alwaysRecursive,
10688           TRUE,
10689           killDict,
10690           &Doxygen::inputPaths);
10691     }
10692     s=inputList.next();
10693   }
10694   delete killDict;
10695   g_s.end();
10696 }
10697
10698   
10699 void parseInput()
10700 {
10701   atexit(exitDoxygen);
10702
10703
10704   /**************************************************************************
10705    *            Make sure the output directory exists
10706    **************************************************************************/
10707   QCString &outputDirectory = Config_getString("OUTPUT_DIRECTORY");
10708   if (outputDirectory.isEmpty()) 
10709   {
10710     outputDirectory=QDir::currentDirPath().utf8();
10711   }
10712   else
10713   {
10714     QDir dir(outputDirectory);
10715     if (!dir.exists())
10716     {
10717       dir.setPath(QDir::currentDirPath());
10718       if (!dir.mkdir(outputDirectory))
10719       {
10720         err("tag OUTPUT_DIRECTORY: Output directory `%s' does not "
10721             "exist and cannot be created\n",outputDirectory.data());
10722         cleanUpDoxygen();
10723         exit(1);
10724       }
10725       else
10726       {
10727         msg("Notice: Output directory `%s' does not exist. "
10728             "I have created it for you.\n", outputDirectory.data());
10729       }
10730       dir.cd(outputDirectory);
10731     }
10732     outputDirectory=dir.absPath().utf8();
10733   }
10734
10735   /**************************************************************************
10736    *            Initialize global lists and dictionaries
10737    **************************************************************************/
10738
10739   Doxygen::symbolStorage = new Store;
10740
10741   // also scale lookup cache with SYMBOL_CACHE_SIZE
10742   int cacheSize = Config_getInt("LOOKUP_CACHE_SIZE");
10743   if (cacheSize<0) cacheSize=0;
10744   if (cacheSize>9) cacheSize=9;
10745   uint lookupSize = 65536 << cacheSize;
10746   Doxygen::lookupCache = new QCache<LookupInfo>(lookupSize,lookupSize);
10747   Doxygen::lookupCache->setAutoDelete(TRUE);
10748
10749 #ifdef HAS_SIGNALS
10750   signal(SIGINT, stopDoxygen);
10751 #endif
10752
10753   uint pid = portable_pid();
10754   Doxygen::objDBFileName.sprintf("doxygen_objdb_%d.tmp",pid);
10755   Doxygen::objDBFileName.prepend(outputDirectory+"/");
10756   Doxygen::entryDBFileName.sprintf("doxygen_entrydb_%d.tmp",pid);
10757   Doxygen::entryDBFileName.prepend(outputDirectory+"/");
10758   
10759   if (Doxygen::symbolStorage->open(Doxygen::objDBFileName)==-1)
10760   {
10761     err("Failed to open temporary file %s\n",Doxygen::objDBFileName.data());
10762     exit(1);
10763   }
10764
10765
10766
10767   /**************************************************************************
10768    *            Check/create output directorties                            *
10769    **************************************************************************/
10770
10771   QCString htmlOutput;
10772   bool &generateHtml = Config_getBool("GENERATE_HTML");
10773   if (generateHtml)
10774     htmlOutput = createOutputDirectory(outputDirectory,"HTML_OUTPUT","/html");
10775
10776   QCString docbookOutput;
10777   bool &generateDocbook = Config_getBool("GENERATE_DOCBOOK");
10778   if (generateDocbook)
10779     docbookOutput = createOutputDirectory(outputDirectory,"DOCBOOK_OUTPUT","/docbook");
10780
10781   QCString xmlOutput;
10782   bool &generateXml = Config_getBool("GENERATE_XML");
10783   if (generateXml)
10784     xmlOutput = createOutputDirectory(outputDirectory,"XML_OUTPUT","/xml");
10785     
10786   QCString latexOutput;
10787   bool &generateLatex = Config_getBool("GENERATE_LATEX");
10788   if (generateLatex)
10789     latexOutput = createOutputDirectory(outputDirectory,"LATEX_OUTPUT","/latex");
10790
10791   QCString rtfOutput;
10792   bool &generateRtf = Config_getBool("GENERATE_RTF");
10793   if (generateRtf)
10794     rtfOutput = createOutputDirectory(outputDirectory,"RTF_OUTPUT","/rtf");
10795
10796   QCString manOutput;
10797   bool &generateMan = Config_getBool("GENERATE_MAN");
10798   if (generateMan)
10799     manOutput = createOutputDirectory(outputDirectory,"MAN_OUTPUT","/man");
10800
10801   //QCString sqlOutput;
10802   //bool &generateSql = Config_getBool("GENERATE_SQLITE3");
10803   //if (generateSql)
10804   //  sqlOutput = createOutputDirectory(outputDirectory,"SQLITE3_OUTPUT","/sqlite3");
10805
10806   if (Config_getBool("HAVE_DOT"))
10807   {
10808     QCString curFontPath = Config_getString("DOT_FONTPATH");
10809     if (curFontPath.isEmpty())
10810     {
10811       portable_getenv("DOTFONTPATH");
10812       QCString newFontPath = ".";
10813       if (!curFontPath.isEmpty())
10814       {
10815         newFontPath+=portable_pathListSeparator();
10816         newFontPath+=curFontPath;
10817       }
10818       portable_setenv("DOTFONTPATH",newFontPath);
10819     }
10820     else
10821     {
10822       portable_setenv("DOTFONTPATH",curFontPath);
10823     }
10824   }
10825
10826
10827
10828   /**************************************************************************
10829    *             Handle layout file                                         *
10830    **************************************************************************/
10831
10832   LayoutDocManager::instance().init();
10833   QCString &layoutFileName = Config_getString("LAYOUT_FILE");
10834   bool defaultLayoutUsed = FALSE;
10835   if (layoutFileName.isEmpty())
10836   {
10837     layoutFileName = "DoxygenLayout.xml";
10838     defaultLayoutUsed = TRUE;
10839   }
10840
10841   QFile layoutFile(layoutFileName);
10842   if (layoutFile.open(IO_ReadOnly))
10843   {
10844     msg("Parsing layout file %s...\n",layoutFileName.data());
10845     QTextStream t(&layoutFile); 
10846     t.setEncoding(QTextStream::Latin1);
10847     LayoutDocManager::instance().parse(t,layoutFileName);
10848   }
10849   else if (!defaultLayoutUsed)
10850   {
10851     warn_uncond("failed to open layout file '%s' for reading!\n",layoutFileName.data());
10852   }
10853
10854   /**************************************************************************
10855    *             Read and preprocess input                                  *
10856    **************************************************************************/
10857  
10858   // prevent search in the output directories
10859   QStrList &exclPatterns = Config_getList("EXCLUDE_PATTERNS");
10860   if (generateHtml)    exclPatterns.append(htmlOutput);
10861   if (generateDocbook) exclPatterns.append(docbookOutput);
10862   if (generateXml)     exclPatterns.append(xmlOutput);
10863   if (generateLatex)   exclPatterns.append(latexOutput);
10864   if (generateRtf)     exclPatterns.append(rtfOutput);
10865   if (generateMan)     exclPatterns.append(manOutput);
10866
10867   searchInputFiles();
10868
10869   // Notice: the order of the function calls below is very important!
10870   
10871   if (Config_getBool("GENERATE_HTML"))
10872   {
10873     readFormulaRepository();
10874   }
10875   
10876   /**************************************************************************
10877    *             Handle Tag Files                                           *
10878    **************************************************************************/
10879
10880   g_storage = new FileStorage;
10881   g_storage->setName(Doxygen::entryDBFileName);
10882   if (!g_storage->open(IO_WriteOnly))
10883   {
10884     err("Failed to create temporary storage file %s\n",
10885         Doxygen::entryDBFileName.data());
10886     exit(1);
10887   }
10888   Entry *root=new Entry;
10889   EntryNav *rootNav = new EntryNav(0,root);
10890   rootNav->setEntry(root);
10891   msg("Reading and parsing tag files\n");
10892   
10893   QStrList &tagFileList = Config_getList("TAGFILES");
10894   char *s=tagFileList.first();
10895   while (s)
10896   {
10897     readTagFile(root,s);
10898     root->createNavigationIndex(rootNav,g_storage,0);
10899     s=tagFileList.next();
10900   }
10901   
10902   /**************************************************************************
10903    *             Parse source files                                         * 
10904    **************************************************************************/
10905
10906   if (Config_getBool("BUILTIN_STL_SUPPORT"))
10907   {
10908     addSTLClasses(rootNav);
10909   }
10910
10911   g_s.begin("Parsing files\n");
10912   parseFiles(root,rootNav);
10913   g_storage->close();
10914   g_s.end();
10915
10916   // we are done with input scanning now, so free up the buffers used by flex
10917   // (can be around 4MB)
10918   preFreeScanner();
10919   scanFreeScanner();
10920   pyscanFreeScanner();
10921
10922   if (!g_storage->open(IO_ReadOnly))
10923   {
10924     err("Failed to open temporary storage file %s for reading",
10925         Doxygen::entryDBFileName.data());
10926     exit(1);
10927   }
10928
10929   /**************************************************************************
10930    *             Gather information                                         * 
10931    **************************************************************************/
10932
10933   g_s.begin("Building group list...\n");
10934   buildGroupList(rootNav);
10935   organizeSubGroups(rootNav);
10936   g_s.end();
10937
10938   g_s.begin("Building directory list...\n");
10939   buildDirectories();
10940   findDirDocumentation(rootNav);
10941   g_s.end();
10942
10943   g_s.begin("Building namespace list...\n");
10944   buildNamespaceList(rootNav);
10945   findUsingDirectives(rootNav);
10946   g_s.end();
10947
10948   g_s.begin("Building file list...\n");
10949   buildFileList(rootNav);
10950   g_s.end();
10951   //generateFileTree();
10952
10953   g_s.begin("Building class list...\n");
10954   buildClassList(rootNav);
10955   g_s.end();
10956
10957   g_s.begin("Associating documentation with classes...\n");
10958   buildClassDocList(rootNav);
10959
10960   // build list of using declarations here (global list)
10961   buildListOfUsingDecls(rootNav);
10962   g_s.end();
10963
10964   g_s.begin("Computing nesting relations for classes...\n");
10965   resolveClassNestingRelations();
10966   g_s.end();
10967   // 1.8.2-20121111: no longer add nested classes to the group as well
10968   //distributeClassGroupRelations(); 
10969
10970   // calling buildClassList may result in cached relations that
10971   // become invalid after resolveClassNestingRelations(), that's why
10972   // we need to clear the cache here
10973   Doxygen::lookupCache->clear();
10974   // we don't need the list of using declaration anymore
10975   g_usingDeclarations.clear();
10976
10977   g_s.begin("Building example list...\n");
10978   buildExampleList(rootNav);
10979   g_s.end();
10980
10981   g_s.begin("Searching for enumerations...\n");
10982   findEnums(rootNav);
10983   g_s.end();
10984
10985   // Since buildVarList calls isVarWithConstructor
10986   // and this calls getResolvedClass we need to process
10987   // typedefs first so the relations between classes via typedefs
10988   // are properly resolved. See bug 536385 for an example.
10989   g_s.begin("Searching for documented typedefs...\n");
10990   buildTypedefList(rootNav);
10991   g_s.end();
10992
10993   g_s.begin("Searching for members imported via using declarations...\n");
10994   findUsingDeclImports(rootNav);
10995   // this should be after buildTypedefList in order to properly import
10996   // used typedefs
10997   findUsingDeclarations(rootNav);
10998   g_s.end();
10999
11000   g_s.begin("Searching for included using directives...\n");
11001   findIncludedUsingDirectives();
11002   g_s.end();
11003
11004   g_s.begin("Searching for documented variables...\n");
11005   buildVarList(rootNav);
11006   g_s.end();
11007
11008   g_s.begin("Building interface member list...\n");
11009   buildInterfaceAndServiceList(rootNav); // UNO IDL
11010
11011   g_s.begin("Building member list...\n"); // using class info only !
11012   buildFunctionList(rootNav);
11013   g_s.end();
11014
11015   g_s.begin("Searching for friends...\n");
11016   findFriends();
11017   g_s.end();
11018
11019   g_s.begin("Searching for documented defines...\n");
11020   findDefineDocumentation(rootNav);
11021   g_s.end();
11022
11023   g_s.begin("Computing class inheritance relations...\n");
11024   findClassEntries(rootNav);
11025   findInheritedTemplateInstances();
11026   g_s.end();
11027
11028   g_s.begin("Computing class usage relations...\n");
11029   findUsedTemplateInstances();
11030   g_s.end();
11031
11032   if (Config_getBool("INLINE_SIMPLE_STRUCTS"))
11033   {
11034     g_s.begin("Searching for tag less structs...\n");
11035     findTagLessClasses();
11036     g_s.end();
11037   }
11038
11039   g_s.begin("Flushing cached template relations that have become invalid...\n");
11040   flushCachedTemplateRelations();
11041   g_s.end();
11042
11043   g_s.begin("Creating members for template instances...\n");
11044   createTemplateInstanceMembers();
11045   g_s.end();
11046
11047   g_s.begin("Computing class relations...\n");
11048   computeTemplateClassRelations();
11049   flushUnresolvedRelations();
11050   if (Config_getBool("OPTIMIZE_OUTPUT_VHDL"))
11051   {
11052     VhdlDocGen::computeVhdlComponentRelations(); 
11053   }
11054   computeClassRelations();
11055   g_classEntries.clear();
11056   g_s.end();
11057
11058   g_s.begin("Add enum values to enums...\n");
11059   addEnumValuesToEnums(rootNav);
11060   findEnumDocumentation(rootNav);
11061   g_s.end();
11062
11063   g_s.begin("Searching for member function documentation...\n");
11064   findObjCMethodDefinitions(rootNav);
11065   findMemberDocumentation(rootNav); // may introduce new members !
11066
11067   transferRelatedFunctionDocumentation();
11068   transferFunctionDocumentation();
11069   g_s.end();
11070
11071   g_s.begin("Building page list...\n");
11072   buildPageList(rootNav);
11073   g_s.end();
11074
11075   g_s.begin("Search for main page...\n");
11076   findMainPage(rootNav);
11077   g_s.end();
11078
11079   g_s.begin("Computing page relations...\n");
11080   computePageRelations(rootNav);
11081   checkPageRelations();
11082   g_s.end();
11083
11084   g_s.begin("Determining the scope of groups...\n");
11085   findGroupScope(rootNav);
11086   g_s.end();
11087
11088   g_s.begin("Sorting lists...\n");
11089   Doxygen::memberNameSDict->sort();
11090   Doxygen::functionNameSDict->sort();
11091   Doxygen::hiddenClasses->sort();
11092   Doxygen::classSDict->sort();
11093   g_s.end();
11094
11095   msg("Freeing entry tree\n");
11096   delete rootNav;
11097   g_storage->close();
11098   delete g_storage;
11099   g_storage=0;
11100
11101   QDir thisDir;
11102   thisDir.remove(Doxygen::entryDBFileName);
11103
11104   g_s.begin("Determining which enums are documented\n");
11105   findDocumentedEnumValues();
11106   g_s.end();
11107
11108   g_s.begin("Computing member relations...\n");
11109   mergeCategories();
11110   computeMemberRelations();
11111   g_s.end();
11112
11113   g_s.begin("Building full member lists recursively...\n");
11114   buildCompleteMemberLists();
11115   g_s.end();
11116
11117   g_s.begin("Adding members to member groups.\n");
11118   addMembersToMemberGroup();
11119   g_s.end();
11120
11121   if (Config_getBool("DISTRIBUTE_GROUP_DOC"))
11122   {
11123     g_s.begin("Distributing member group documentation.\n");
11124     distributeMemberGroupDocumentation();
11125     g_s.end();
11126   }
11127
11128   g_s.begin("Computing member references...\n");
11129   computeMemberReferences();
11130   g_s.end();
11131
11132   if (Config_getBool("INHERIT_DOCS"))
11133   {
11134     g_s.begin("Inheriting documentation...\n");
11135     inheritDocumentation();
11136     g_s.end();
11137   }
11138
11139   // compute the shortest possible names of all files
11140   // without losing the uniqueness of the file names.
11141   g_s.begin("Generating disk names...\n");
11142   Doxygen::inputNameList->generateDiskNames();
11143   g_s.end();
11144
11145   g_s.begin("Adding source references...\n");
11146   addSourceReferences();
11147   g_s.end();
11148
11149   g_s.begin("Adding xrefitems...\n");
11150   addListReferences();
11151   generateXRefPages();
11152   g_s.end();
11153
11154   g_s.begin("Sorting member lists...\n");
11155   sortMemberLists();
11156   g_s.end();
11157
11158   if (Config_getBool("DIRECTORY_GRAPH"))
11159   {
11160     g_s.begin("Computing dependencies between directories...\n");
11161     computeDirDependencies();
11162     g_s.end();
11163   }
11164
11165   //g_s.begin("Resolving citations...\n");
11166   //Doxygen::citeDict->resolve();
11167
11168   g_s.begin("Generating citations page...\n");
11169   Doxygen::citeDict->generatePage();
11170   g_s.end();
11171
11172   g_s.begin("Counting data structures...\n");
11173   countDataStructures();
11174   g_s.end();
11175
11176   g_s.begin("Resolving user defined references...\n");
11177   resolveUserReferences();
11178   g_s.end();
11179
11180   g_s.begin("Finding anchors and sections in the documentation...\n");
11181   findSectionsInDocumentation();
11182   g_s.end();
11183
11184   g_s.begin("Transferring function references...\n");
11185   transferFunctionReferences();
11186   g_s.end();
11187
11188   g_s.begin("Combining using relations...\n");
11189   combineUsingRelations();
11190   g_s.end();
11191
11192   g_s.begin("Adding members to index pages...\n");
11193   addMembersToIndex();
11194   g_s.end();
11195
11196   if (Config_getBool("OPTIMIZE_OUTPUT_VHDL") && 
11197       Config_getBool("HAVE_DOT") &&
11198       Config_getEnum("DOT_IMAGE_FORMAT")=="svg")
11199   {
11200     VhdlDocGen::writeOverview();
11201   }
11202 }
11203
11204 void generateOutput()
11205 {
11206   /**************************************************************************
11207    *            Initialize output generators                                *
11208    **************************************************************************/
11209
11210   //// dump all symbols
11211   if (g_dumpSymbolMap)
11212   {
11213     dumpSymbolMap();
11214     exit(0);
11215   }
11216
11217   initSearchIndexer();
11218
11219   bool generateHtml  = Config_getBool("GENERATE_HTML");
11220   bool generateLatex = Config_getBool("GENERATE_LATEX");
11221   bool generateMan   = Config_getBool("GENERATE_MAN");
11222   bool generateRtf   = Config_getBool("GENERATE_RTF");
11223
11224
11225   g_outputList = new OutputList(TRUE);
11226   if (generateHtml)  
11227   {
11228     g_outputList->add(new HtmlGenerator);
11229     HtmlGenerator::init();
11230
11231     // add HTML indexers that are enabled
11232     bool generateHtmlHelp    = Config_getBool("GENERATE_HTMLHELP");
11233     bool generateEclipseHelp = Config_getBool("GENERATE_ECLIPSEHELP");
11234     bool generateQhp         = Config_getBool("GENERATE_QHP");
11235     bool generateTreeView    = Config_getBool("GENERATE_TREEVIEW");
11236     bool generateDocSet      = Config_getBool("GENERATE_DOCSET");
11237     if (generateEclipseHelp) Doxygen::indexList->addIndex(new EclipseHelp);
11238     if (generateHtmlHelp)    Doxygen::indexList->addIndex(new HtmlHelp);
11239     if (generateQhp)         Doxygen::indexList->addIndex(new Qhp);
11240     if (generateTreeView)    Doxygen::indexList->addIndex(new FTVHelp(TRUE));
11241     if (generateDocSet)      Doxygen::indexList->addIndex(new DocSets);
11242     Doxygen::indexList->initialize();
11243     HtmlGenerator::writeTabData();
11244
11245     // copy static stuff
11246     copyStyleSheet();
11247     copyLogo();
11248     copyExtraFiles("HTML_EXTRA_FILES","HTML_OUTPUT");
11249     FTVHelp::generateTreeViewImages();
11250   }
11251   if (generateLatex) 
11252   {
11253     g_outputList->add(new LatexGenerator);
11254     LatexGenerator::init();
11255
11256     // copy static stuff
11257     copyExtraFiles("LATEX_EXTRA_FILES","LATEX_OUTPUT");
11258   }
11259   if (generateMan)
11260   {
11261     g_outputList->add(new ManGenerator);
11262     ManGenerator::init();
11263   }
11264   if (generateRtf)
11265   {
11266     g_outputList->add(new RTFGenerator);
11267     RTFGenerator::init();
11268   }
11269   if (Config_getBool("USE_HTAGS"))
11270   {
11271     Htags::useHtags = TRUE;
11272     QCString htmldir = Config_getString("HTML_OUTPUT");
11273     if (!Htags::execute(htmldir))
11274        err("USE_HTAGS is YES but htags(1) failed. \n");
11275     if (!Htags::loadFilemap(htmldir))
11276        err("htags(1) ended normally but failed to load the filemap. \n");
11277   }
11278   
11279   /**************************************************************************
11280    *                        Generate documentation                          *
11281    **************************************************************************/
11282
11283   QFile *tag=0;
11284   QCString &generateTagFile = Config_getString("GENERATE_TAGFILE");
11285   if (!generateTagFile.isEmpty())
11286   {
11287     tag=new QFile(generateTagFile);
11288     if (!tag->open(IO_WriteOnly))
11289     {
11290       err("cannot open tag file %s for writing\n",
11291           generateTagFile.data()
11292          );
11293       cleanUpDoxygen();
11294       exit(1);
11295     }
11296     Doxygen::tagFile.setDevice(tag);
11297     Doxygen::tagFile << "<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>" << endl;
11298     Doxygen::tagFile << "<tagfile>" << endl;
11299   }
11300
11301   if (generateHtml)  writeDoxFont(Config_getString("HTML_OUTPUT"));
11302   if (generateLatex) writeDoxFont(Config_getString("LATEX_OUTPUT"));
11303   if (generateRtf)   writeDoxFont(Config_getString("RTF_OUTPUT"));
11304
11305   g_s.begin("Generating style sheet...\n");
11306   //printf("writing style info\n");
11307   g_outputList->writeStyleInfo(0); // write first part
11308   g_s.end();
11309
11310   static bool searchEngine      = Config_getBool("SEARCHENGINE");
11311   static bool serverBasedSearch = Config_getBool("SERVER_BASED_SEARCH");
11312
11313   // generate search indices (need to do this before writing other HTML
11314   // pages as these contain a drop down menu with options depending on
11315   // what categories we find in this function.
11316   if (generateHtml && searchEngine)
11317   {
11318     g_s.begin("Generating search indices...\n");
11319     QCString searchDirName = Config_getString("HTML_OUTPUT")+"/search";
11320     QDir searchDir(searchDirName);
11321     if (!searchDir.exists() && !searchDir.mkdir(searchDirName))
11322     {
11323       err("Could not create search results directory '%s' $PWD='%s'\n",
11324           searchDirName.data(),QDir::currentDirPath().data());
11325       exit(1);
11326     }
11327     HtmlGenerator::writeSearchData(searchDirName);
11328     if (!serverBasedSearch) // client side search index
11329     {
11330       writeJavascriptSearchIndex();
11331     }
11332     g_s.end();
11333   }
11334
11335   g_s.begin("Generating example documentation...\n");
11336   generateExampleDocs();
11337   g_s.end();
11338
11339   if (!Htags::useHtags)
11340   {
11341     g_s.begin("Generating file sources...\n");
11342     generateFileSources();
11343     g_s.end();
11344   }
11345
11346   g_s.begin("Generating file documentation...\n");
11347   generateFileDocs();
11348   g_s.end();
11349
11350   g_s.begin("Generating page documentation...\n");
11351   generatePageDocs();
11352   g_s.end();
11353
11354   g_s.begin("Generating group documentation...\n");
11355   generateGroupDocs();
11356   g_s.end();
11357
11358   g_s.begin("Generating class documentation...\n");
11359   generateClassDocs();
11360   g_s.end();
11361
11362   g_s.begin("Generating namespace index...\n");
11363   generateNamespaceDocs();
11364   g_s.end();
11365
11366   if (Config_getBool("GENERATE_LEGEND"))
11367   {
11368     g_s.begin("Generating graph info page...\n");
11369     writeGraphInfo(*g_outputList);
11370     g_s.end();
11371   }
11372
11373   g_s.begin("Generating directory documentation...\n");
11374   generateDirDocs(*g_outputList);
11375   g_s.end();
11376
11377   if (Doxygen::formulaList->count()>0 && generateHtml
11378       && !Config_getBool("USE_MATHJAX"))
11379   {
11380     g_s.begin("Generating bitmaps for formulas in HTML...\n");
11381     Doxygen::formulaList->generateBitmaps(Config_getString("HTML_OUTPUT"));
11382     g_s.end();
11383   }
11384
11385   if (Config_getBool("SORT_GROUP_NAMES"))
11386   {
11387     Doxygen::groupSDict->sort();
11388     GroupSDict::Iterator gli(*Doxygen::groupSDict);
11389     GroupDef *gd;
11390     for (gli.toFirst();(gd=gli.current());++gli)
11391     {
11392       gd->sortSubGroups();
11393     }
11394   }
11395   
11396   writeMainPageTagFileData();
11397
11398   if (g_outputList->count()>0)
11399   {
11400     writeIndexHierarchy(*g_outputList);
11401   }
11402
11403   g_s.begin("finalizing index lists...\n");
11404   Doxygen::indexList->finalize();
11405   g_s.end();
11406
11407   if (!generateTagFile.isEmpty())
11408   {
11409     Doxygen::tagFile << "</tagfile>" << endl;
11410     delete tag;
11411   }
11412
11413   if (Config_getBool("DOT_CLEANUP"))
11414   {
11415     if (generateHtml)
11416       removeDoxFont(Config_getString("HTML_OUTPUT"));
11417     if (generateRtf)  
11418       removeDoxFont(Config_getString("RTF_OUTPUT"));
11419     if (generateLatex)  
11420       removeDoxFont(Config_getString("LATEX_OUTPUT"));
11421   }
11422
11423   if (Config_getBool("GENERATE_XML"))
11424   {
11425     g_s.begin("Generating XML output...\n");
11426     Doxygen::generatingXmlOutput=TRUE;
11427     generateXML();
11428     Doxygen::generatingXmlOutput=FALSE;
11429     g_s.end();
11430   }
11431   if (USE_SQLITE3)
11432   {
11433     g_s.begin("Generating SQLITE3 output...\n");
11434     generateSqlite3();
11435     g_s.end();
11436   }
11437
11438   if (Config_getBool("GENERATE_DOCBOOK"))
11439   {
11440     g_s.begin("Generating Docbook output...\n");
11441     generateDocbook();
11442     g_s.end();
11443   }
11444
11445   if (Config_getBool("GENERATE_AUTOGEN_DEF"))
11446   {
11447     g_s.begin("Generating AutoGen DEF output...\n");
11448     generateDEF();
11449     g_s.end();
11450   }
11451   if (Config_getBool("GENERATE_PERLMOD"))
11452   {
11453     g_s.begin("Generating Perl module output...\n");
11454     generatePerlMod();
11455     g_s.end();
11456   }
11457   if (generateHtml && searchEngine && serverBasedSearch)
11458   {
11459     g_s.begin("Generating search index\n");
11460     if (Doxygen::searchIndex->kind()==SearchIndexIntf::Internal) // write own search index
11461     {
11462       HtmlGenerator::writeSearchPage();
11463       Doxygen::searchIndex->write(Config_getString("HTML_OUTPUT")+"/search/search.idx");
11464     }
11465     else // write data for external search index
11466     {
11467       HtmlGenerator::writeExternalSearchPage();
11468       QCString searchDataFile = Config_getString("SEARCHDATA_FILE");
11469       if (searchDataFile.isEmpty())
11470       {
11471         searchDataFile="searchdata.xml";
11472       }
11473       if (!portable_isAbsolutePath(searchDataFile))
11474       {
11475         searchDataFile.prepend(Config_getString("OUTPUT_DIRECTORY")+"/");
11476       }
11477       Doxygen::searchIndex->write(searchDataFile);
11478     }
11479     g_s.end();
11480   }
11481
11482   if (g_useOutputTemplate) generateOutputViaTemplate();
11483
11484   if (generateRtf)
11485   {
11486     g_s.begin("Combining RTF output...\n");
11487     if (!RTFGenerator::preProcessFileInplace(Config_getString("RTF_OUTPUT"),"refman.rtf"))
11488     {
11489       err("An error occurred during post-processing the RTF files!\n");
11490     }
11491     g_s.end();
11492   }
11493
11494   if (Config_getBool("HAVE_DOT"))
11495   {
11496     g_s.begin("Running dot...\n");
11497     DotManager::instance()->run();
11498     g_s.end();
11499   }
11500
11501   if (generateHtml &&
11502       Config_getBool("GENERATE_HTMLHELP") && 
11503       !Config_getString("HHC_LOCATION").isEmpty())
11504   {
11505     g_s.begin("Running html help compiler...\n");
11506     QString oldDir = QDir::currentDirPath();
11507     QDir::setCurrent(Config_getString("HTML_OUTPUT"));
11508     portable_sysTimerStart();
11509     if (portable_system(Config_getString("HHC_LOCATION"), "index.hhp", FALSE))
11510     {
11511       err("failed to run html help compiler on index.hhp\n");
11512     }
11513     portable_sysTimerStop();
11514     QDir::setCurrent(oldDir);
11515     g_s.end();
11516   }
11517   if ( generateHtml &&
11518        Config_getBool("GENERATE_QHP") && 
11519       !Config_getString("QHG_LOCATION").isEmpty())
11520   {
11521     g_s.begin("Running qhelpgenerator...\n");
11522     QCString const qhpFileName = Qhp::getQhpFileName();
11523     QCString const qchFileName = getQchFileName();
11524
11525     QCString const args = QCString().sprintf("%s -o \"%s\"", qhpFileName.data(), qchFileName.data());
11526     QString const oldDir = QDir::currentDirPath();
11527     QDir::setCurrent(Config_getString("HTML_OUTPUT"));
11528     portable_sysTimerStart();
11529     if (portable_system(Config_getString("QHG_LOCATION"), args.data(), FALSE))
11530     {
11531       err("failed to run qhelpgenerator on index.qhp\n");
11532     }
11533     portable_sysTimerStop();
11534     QDir::setCurrent(oldDir);
11535     g_s.end();
11536   }
11537
11538   int cacheParam;
11539   msg("lookup cache used %d/%d hits=%d misses=%d\n",
11540       Doxygen::lookupCache->count(),
11541       Doxygen::lookupCache->size(),
11542       Doxygen::lookupCache->hits(),
11543       Doxygen::lookupCache->misses());
11544   cacheParam = computeIdealCacheParam(Doxygen::lookupCache->misses()*2/3); // part of the cache is flushed, hence the 2/3 correction factor
11545   if (cacheParam>Config_getInt("LOOKUP_CACHE_SIZE"))
11546   {
11547     msg("Note: based on cache misses the ideal setting for LOOKUP_CACHE_SIZE is %d at the cost of higher memory usage.\n",cacheParam);
11548   }
11549
11550   if (Debug::isFlagSet(Debug::Time))
11551   {
11552     msg("Total elapsed time: %.3f seconds\n(of which %.3f seconds waiting for external tools to finish)\n",
11553          ((double)Doxygen::runningTime.elapsed())/1000.0,
11554          portable_getSysElapsedTime()
11555         );
11556     g_s.print();
11557   }
11558   else
11559   {
11560     msg("finished...\n");
11561   }
11562
11563
11564   /**************************************************************************
11565    *                        Start cleaning up                               *
11566    **************************************************************************/
11567
11568   cleanUpDoxygen();
11569
11570   finializeSearchIndexer();
11571   Doxygen::symbolStorage->close();
11572   QDir thisDir;
11573   thisDir.remove(Doxygen::objDBFileName);
11574   Config::deleteInstance();
11575   QTextCodec::deleteAllCodecs();
11576   delete Doxygen::symbolMap;
11577   delete Doxygen::clangUsrMap;
11578   delete Doxygen::symbolStorage;
11579   g_successfulRun=TRUE;
11580 }
11581