Imported Upstream version 1.8.15
[platform/upstream/doxygen.git] / src / tagreader.cpp
1 /******************************************************************************
2  *
3  * 
4  *
5  *
6  * Copyright (C) 1997-2015 by Dimitri van Heesch.
7  *
8  * Permission to use, copy, modify, and distribute this software and its
9  * documentation under the terms of the GNU General Public License is hereby 
10  * granted. No representations are made about the suitability of this software 
11  * for any purpose. It is provided "as is" without express or implied warranty.
12  * See the GNU General Public License for more details.
13  *
14  * Documents produced by Doxygen are derivative works derived from the
15  * input used in their production; they are not affected by this license.
16  *
17  */
18
19 #include "tagreader.h"
20
21 #include <assert.h>
22 #include <stdio.h>
23 #include <stdarg.h>
24
25 #include <qxml.h>
26 #include <qstack.h>
27 #include <qdict.h>
28 #include <qfileinfo.h>
29 #include <qlist.h>
30 #include <qstring.h>
31 #include <qcstringlist.h>
32
33 #include "entry.h"
34 #include "classdef.h"
35 #include "doxygen.h"
36 #include "util.h"
37 #include "message.h"
38 #include "defargs.h"
39 #include "arguments.h"
40 #include "filedef.h"
41 #include "filename.h"
42 #include "section.h"
43 #include "groupdef.h"
44
45 /** Information about an linkable anchor */
46 class TagAnchorInfo
47 {
48   public:
49     TagAnchorInfo(const QCString &f,
50                   const QCString &l,
51                   const QCString &t=QCString()) 
52       : label(l), fileName(f), title(t) {}
53     QCString label;
54     QCString fileName;
55     QCString title;
56 };
57
58 /** List of TagAnchorInfo objects. */
59 class TagAnchorInfoList : public QList<TagAnchorInfo>
60 {
61   public: 
62     TagAnchorInfoList() : QList<TagAnchorInfo>() { setAutoDelete(TRUE); }
63     virtual ~TagAnchorInfoList() {}
64 };
65
66 /** Container for enum values that are scoped within an enum */
67 class TagEnumValueInfo
68 {
69   public:
70     QCString name;
71     QCString file;
72     QCString anchor;
73     QCString clangid;
74 };
75
76 /** Container for member specific info that can be read from a tagfile */
77 class TagMemberInfo
78 {
79   public:
80     TagMemberInfo() : prot(Public), virt(Normal), isStatic(FALSE) 
81     { enumValues.setAutoDelete(TRUE); }
82     QCString type;
83     QCString name;
84     QCString anchorFile;
85     QCString anchor;
86     QCString arglist;
87     QCString kind;
88     QCString clangId;
89     TagAnchorInfoList docAnchors;
90     Protection prot;
91     Specifier virt;
92     bool isStatic; 
93     QList<TagEnumValueInfo> enumValues;
94 };
95
96 /** Container for class specific info that can be read from a tagfile */
97 class TagClassInfo
98 {
99   public:
100     enum Kind { None=-1, Class, Struct, Union, Interface, Exception, Protocol, Category, Enum, Service, Singleton };
101     TagClassInfo() { bases=0, templateArguments=0; members.setAutoDelete(TRUE); isObjC=FALSE; kind = None; }
102    ~TagClassInfo() { delete bases; delete templateArguments; }
103     QCString name;
104     QCString filename;
105     QCString clangId;
106     QCString anchor;
107     TagAnchorInfoList docAnchors;
108     QList<BaseInfo> *bases;
109     QList<TagMemberInfo> members;
110     QList<QCString> *templateArguments;
111     QCStringList classList;
112     Kind kind;
113     bool isObjC;
114 };
115
116 /** Container for namespace specific info that can be read from a tagfile */
117 class TagNamespaceInfo
118 {
119   public:
120     TagNamespaceInfo() { members.setAutoDelete(TRUE); }
121     QCString name;
122     QCString filename;
123     QCString clangId;
124     QCStringList classList;
125     QCStringList namespaceList;
126     TagAnchorInfoList docAnchors;
127     QList<TagMemberInfo> members;
128 };
129
130 /** Container for package specific info that can be read from a tagfile */
131 class TagPackageInfo
132 {
133   public:
134     TagPackageInfo() { members.setAutoDelete(TRUE); }
135     QCString name;
136     QCString filename;
137     TagAnchorInfoList docAnchors;
138     QList<TagMemberInfo> members;
139     QCStringList classList;
140 };
141
142 /** Container for include info that can be read from a tagfile */
143 class TagIncludeInfo
144 {
145   public:
146     QCString id;
147     QCString name;
148     QCString text;
149     bool isLocal;
150     bool isImported;
151 };
152
153 /** Container for file specific info that can be read from a tagfile */
154 class TagFileInfo
155 {
156   public:
157     TagFileInfo() { members.setAutoDelete(TRUE); includes.setAutoDelete(TRUE); }
158     QCString name;
159     QCString path;
160     QCString filename;
161     TagAnchorInfoList docAnchors;
162     QList<TagMemberInfo> members;
163     QCStringList classList;
164     QCStringList namespaceList;
165     QList<TagIncludeInfo> includes;
166 };
167
168 /** Container for group specific info that can be read from a tagfile */
169 class TagGroupInfo
170 {
171   public:
172     TagGroupInfo() { members.setAutoDelete(TRUE); }
173     QCString name;
174     QCString title;
175     QCString filename;
176     TagAnchorInfoList docAnchors;
177     QList<TagMemberInfo> members;
178     QCStringList subgroupList;
179     QCStringList classList;
180     QCStringList namespaceList;
181     QCStringList fileList;
182     QCStringList pageList;
183     QCStringList dirList;
184 };
185
186 /** Container for page specific info that can be read from a tagfile */
187 class TagPageInfo
188 {
189   public:
190     QCString name;
191     QCString title;
192     QCString filename;
193     TagAnchorInfoList docAnchors;
194 };
195
196 /** Container for directory specific info that can be read from a tagfile */
197 class TagDirInfo
198 {
199   public:
200     QCString name;
201     QCString filename;
202     QCString path;
203     QCStringList subdirList;
204     QCStringList fileList;
205     TagAnchorInfoList docAnchors;
206 };
207
208 /** Tag file parser. 
209  *
210  *  Reads an XML-structured tagfile and builds up the structure in
211  *  memory. The method buildLists() is used to transfer/translate 
212  *  the structures to the doxygen engine.
213  */
214 class TagFileParser : public QXmlDefaultHandler
215 {
216     enum State { Invalid,
217                  InClass,
218                  InFile,
219                  InNamespace,
220                  InGroup,
221                  InPage,
222                  InMember,
223                  InEnumValue,
224                  InPackage,
225                  InDir,
226                  InTempArgList
227                };
228     class StartElementHandler
229     {
230         typedef void (TagFileParser::*Handler)(const QXmlAttributes &attrib); 
231       public:
232         StartElementHandler(TagFileParser *parent, Handler h) : m_parent(parent), m_handler(h) {}
233         void operator()(const QXmlAttributes &attrib) { (m_parent->*m_handler)(attrib); }
234       private:
235         TagFileParser *m_parent;
236         Handler m_handler;
237     };
238
239     class EndElementHandler
240     {
241         typedef void (TagFileParser::*Handler)(); 
242       public:
243         EndElementHandler(TagFileParser *parent, Handler h) : m_parent(parent), m_handler(h) {}
244         void operator()() { (m_parent->*m_handler)(); }
245       private:
246         TagFileParser *m_parent;
247         Handler m_handler;
248     };
249
250   public:
251     TagFileParser(const char *tagName) : m_startElementHandlers(17),
252                                          m_endElementHandlers(17),
253                                          m_tagName(tagName)
254     {
255       m_startElementHandlers.setAutoDelete(TRUE);
256       m_endElementHandlers.setAutoDelete(TRUE);
257       m_curClass=0;
258       m_curFile=0;
259       m_curNamespace=0;
260       m_curPackage=0;
261       m_curGroup=0;
262       m_curPage=0;
263       m_curDir=0;
264       m_curMember=0;
265       m_curEnumValue=0;
266       m_curIncludes=0;
267       m_state = Invalid;
268       m_locator = 0;
269     }
270
271     void setDocumentLocator ( QXmlLocator * locator )
272     {
273       m_locator = locator;
274     }
275
276     void setFileName( const QString &fileName )
277     {
278       m_inputFileName = fileName.utf8();
279     }
280
281     void warn(const char *fmt)
282     {
283       ::warn(m_inputFileName,m_locator->lineNumber(),fmt);
284     }
285     void warn(const char *fmt,const char *s)
286     {
287       ::warn(m_inputFileName,m_locator->lineNumber(),fmt,s);
288     }
289
290     void startCompound( const QXmlAttributes& attrib )
291     {
292       m_curString = "";
293       QString kind = attrib.value("kind");
294       QString isObjC = attrib.value("objc");
295       if (kind=="class")
296       {
297         m_curClass = new TagClassInfo;
298         m_curClass->kind = TagClassInfo::Class;
299         m_state = InClass;
300       }
301       else if (kind=="struct")
302       {
303         m_curClass = new TagClassInfo;
304         m_curClass->kind = TagClassInfo::Struct;
305         m_state = InClass;
306       }
307       else if (kind=="union")
308       {
309         m_curClass = new TagClassInfo;
310         m_curClass->kind = TagClassInfo::Union;
311         m_state = InClass;
312       }
313       else if (kind=="interface")
314       {
315         m_curClass = new TagClassInfo;
316         m_curClass->kind = TagClassInfo::Interface;
317         m_state = InClass;
318       }
319       else if (kind=="enum")
320       {
321         m_curClass = new TagClassInfo;
322         m_curClass->kind = TagClassInfo::Enum;
323         m_state = InClass;
324       }
325       else if (kind=="exception")
326       {
327         m_curClass = new TagClassInfo;
328         m_curClass->kind = TagClassInfo::Exception;
329         m_state = InClass;
330       }
331       else if (kind=="protocol")
332       {
333         m_curClass = new TagClassInfo;
334         m_curClass->kind = TagClassInfo::Protocol;
335         m_state = InClass;
336       }
337       else if (kind=="category")
338       {
339         m_curClass = new TagClassInfo;
340         m_curClass->kind = TagClassInfo::Category;
341         m_state = InClass;
342       }
343       else if (kind=="service")
344       {
345         m_curClass = new TagClassInfo;
346         m_curClass->kind = TagClassInfo::Service;
347         m_state = InClass;
348       }
349       else if (kind=="singleton")
350       {
351         m_curClass = new TagClassInfo;
352         m_curClass->kind = TagClassInfo::Singleton;
353         m_state = InClass;
354       }
355       else if (kind=="file")
356       {
357         m_curFile = new TagFileInfo;
358         m_state = InFile;
359       }
360       else if (kind=="namespace")
361       {
362         m_curNamespace = new TagNamespaceInfo;
363         m_state = InNamespace;
364       }
365       else if (kind=="group")
366       {
367         m_curGroup = new TagGroupInfo;
368         m_state = InGroup;
369       }
370       else if (kind=="page")
371       {
372         m_curPage = new TagPageInfo;
373         m_state = InPage;
374       }
375       else if (kind=="package")
376       {
377         m_curPackage = new TagPackageInfo;
378         m_state = InPackage;
379       }
380       else if (kind=="dir")
381       {
382         m_curDir = new TagDirInfo;
383         m_state = InDir;
384       }
385       else
386       {
387         warn("Unknown compound attribute `%s' found!",kind.data());
388         m_state = Invalid;
389       }
390       if (isObjC=="yes" && m_curClass)
391       {
392         m_curClass->isObjC = TRUE; 
393       }
394     }
395
396     void endCompound()
397     {
398       switch (m_state)
399       {
400         case InClass:     m_tagFileClasses.append(m_curClass); 
401                           m_curClass=0; break; 
402         case InFile:      m_tagFileFiles.append(m_curFile); 
403                           m_curFile=0; break; 
404         case InNamespace: m_tagFileNamespaces.append(m_curNamespace); 
405                           m_curNamespace=0; break; 
406         case InGroup:     m_tagFileGroups.append(m_curGroup); 
407                           m_curGroup=0; break; 
408         case InPage:      m_tagFilePages.append(m_curPage); 
409                           m_curPage=0; break; 
410         case InDir:       m_tagFileDirs.append(m_curDir);
411                           m_curDir=0; break;
412         case InPackage:   m_tagFilePackages.append(m_curPackage); 
413                           m_curPackage=0; break; 
414         default:
415                           warn("tag `compound' was not expected!");
416       }
417     }
418
419     void startMember( const QXmlAttributes& attrib)
420     {
421       m_curMember = new TagMemberInfo;
422       m_curMember->kind = attrib.value("kind").utf8();
423       QCString protStr   = attrib.value("protection").utf8();
424       QCString virtStr   = attrib.value("virtualness").utf8();
425       QCString staticStr = attrib.value("static").utf8();
426       if (protStr=="protected")
427       {
428         m_curMember->prot = Protected;
429       }
430       else if (protStr=="private")
431       {
432         m_curMember->prot = Private;
433       }
434       if (virtStr=="virtual")
435       {
436         m_curMember->virt = Virtual;
437       }
438       else if (virtStr=="pure")
439       {
440         m_curMember->virt = Pure;
441       }
442       if (staticStr=="yes")
443       {
444         m_curMember->isStatic = TRUE;
445       }
446       m_stateStack.push(new State(m_state));
447       m_state = InMember;
448     }
449
450     void endMember()
451     {
452       m_state = *m_stateStack.top();
453       m_stateStack.remove();
454       switch(m_state)
455       {
456         case InClass:     m_curClass->members.append(m_curMember); break;
457         case InFile:      m_curFile->members.append(m_curMember); break;
458         case InNamespace: m_curNamespace->members.append(m_curMember); break;
459         case InGroup:     m_curGroup->members.append(m_curMember); break;
460         case InPackage:   m_curPackage->members.append(m_curMember); break;
461         default:   warn("Unexpected tag `member' found"); break; 
462       }
463     }
464
465     void startEnumValue( const QXmlAttributes& attrib)
466     {
467       if (m_state==InMember)
468       {
469         m_curString = "";
470         m_curEnumValue = new TagEnumValueInfo;
471         m_curEnumValue->file = attrib.value("file").utf8();
472         m_curEnumValue->anchor = attrib.value("anchor").utf8();
473         m_curEnumValue->clangid = attrib.value("clangid").utf8();
474         m_stateStack.push(new State(m_state));
475         m_state = InEnumValue;
476       }
477       else
478       {
479         warn("Found `enumvalue' tag outside of member tag");
480       }
481     }
482
483     void endEnumValue()
484     {
485       m_curEnumValue->name = m_curString.stripWhiteSpace(); 
486       m_state = *m_stateStack.top();
487       m_stateStack.remove();
488       if (m_state==InMember)
489       {
490         m_curMember->enumValues.append(m_curEnumValue);
491         m_curEnumValue=0;
492       }
493     }
494
495     void endDocAnchor()
496     {
497       switch(m_state)
498       {
499         case InClass:     m_curClass->docAnchors.append(new TagAnchorInfo(m_fileName,m_curString,m_title)); break;
500         case InFile:      m_curFile->docAnchors.append(new TagAnchorInfo(m_fileName,m_curString,m_title)); break;
501         case InNamespace: m_curNamespace->docAnchors.append(new TagAnchorInfo(m_fileName,m_curString,m_title)); break;
502         case InGroup:     m_curGroup->docAnchors.append(new TagAnchorInfo(m_fileName,m_curString,m_title)); break;
503         case InPage:      m_curPage->docAnchors.append(new TagAnchorInfo(m_fileName,m_curString,m_title)); break;
504         case InMember:    m_curMember->docAnchors.append(new TagAnchorInfo(m_fileName,m_curString,m_title)); break;
505         case InPackage:   m_curPackage->docAnchors.append(new TagAnchorInfo(m_fileName,m_curString,m_title)); break;
506         case InDir:       m_curDir->docAnchors.append(new TagAnchorInfo(m_fileName,m_curString,m_title)); break;
507         default:   warn("Unexpected tag `docanchor' found"); break; 
508       }
509     }
510
511     void endClass()
512     {
513       switch(m_state)
514       {
515         case InClass:     m_curClass->classList.append(m_curString); break;
516         case InFile:      m_curFile->classList.append(m_curString); break;
517         case InNamespace: m_curNamespace->classList.append(m_curString); break;
518         case InGroup:     m_curGroup->classList.append(m_curString); break;
519         case InPackage:   m_curPackage->classList.append(m_curString); break;
520         default:   warn("Unexpected tag `class' found"); break; 
521       }
522     }
523
524     void endNamespace()
525     {
526       switch(m_state)
527       {
528         case InNamespace: m_curNamespace->classList.append(m_curString); break;
529         case InFile:      m_curFile->namespaceList.append(m_curString); break;
530         case InGroup:     m_curGroup->namespaceList.append(m_curString); break;
531         default:   warn("Unexpected tag `namespace' found"); break; 
532       }
533     }
534
535     void endFile()
536     {
537       switch(m_state)
538       {
539         case InGroup:      m_curGroup->fileList.append(m_curString); break;
540         case InDir:        m_curDir->fileList.append(m_curString); break;
541         default:   warn("Unexpected tag `file' found"); break; 
542       }
543     }
544
545     void endPage()
546     {
547       switch(m_state)
548       {
549         case InGroup:      m_curGroup->fileList.append(m_curString); break;
550         default:   warn("Unexpected tag `page' found"); break; 
551       }
552     }
553
554     void endDir()
555     {
556       switch(m_state)
557       {
558         case InDir:      m_curDir->subdirList.append(m_curString); break;
559         default:   warn("Unexpected tag `dir' found"); break; 
560       }
561     }
562
563     void startStringValue(const QXmlAttributes& )
564     {
565       m_curString = "";
566     }
567
568     void startDocAnchor(const QXmlAttributes& attrib )
569     {
570       m_fileName = attrib.value("file").utf8();
571       m_title = attrib.value("title").utf8();
572       m_curString = "";
573     }
574
575     void endType()
576     {
577       if (m_state==InMember)
578       {
579         m_curMember->type = m_curString; 
580       }
581       else
582       {
583         warn("Unexpected tag `type' found");
584       }
585     }
586
587     void endName()
588     {
589       switch (m_state)
590       {
591         case InClass:     m_curClass->name     = m_curString; break;
592         case InFile:      m_curFile->name      = m_curString; break;
593         case InNamespace: m_curNamespace->name = m_curString; break;
594         case InGroup:     m_curGroup->name     = m_curString; break;
595         case InPage:      m_curPage->name      = m_curString; break;
596         case InDir:       m_curDir->name       = m_curString; break;
597         case InMember:    m_curMember->name    = m_curString; break;
598         case InPackage:   m_curPackage->name   = m_curString; break;
599         default: warn("Unexpected tag `name' found"); break; 
600       }
601     }
602
603     void startBase(const QXmlAttributes& attrib )
604     {
605       m_curString="";
606       if (m_state==InClass && m_curClass)
607       {
608         QString protStr = attrib.value("protection");
609         QString virtStr = attrib.value("virtualness");
610         Protection prot = Public;
611         Specifier  virt = Normal;
612         if (protStr=="protected")
613         {
614           prot = Protected;
615         }
616         else if (protStr=="private")
617         {
618           prot = Private;
619         }
620         if (virtStr=="virtual")
621         {
622           virt = Virtual;
623         }
624         if (m_curClass->bases==0) 
625         {
626           m_curClass->bases = new QList<BaseInfo>;
627           m_curClass->bases->setAutoDelete(TRUE);
628         }
629         m_curClass->bases->append(new BaseInfo(m_curString,prot,virt));
630       }
631       else
632       {
633         warn("Unexpected tag `base' found");
634       }
635     }
636
637     void endBase()
638     {
639       if (m_state==InClass && m_curClass)
640       {
641         m_curClass->bases->getLast()->name = m_curString;
642       }
643       else
644       {
645         warn("Unexpected tag `base' found");
646       }
647     }
648
649     void startIncludes(const QXmlAttributes& attrib )
650     {
651       if (m_state==InFile && m_curFile)
652       {
653         m_curIncludes = new TagIncludeInfo;
654         m_curIncludes->id = attrib.value("id").utf8();
655         m_curIncludes->name = attrib.value("name").utf8();
656         m_curIncludes->isLocal = attrib.value("local").utf8()=="yes" ? TRUE : FALSE;
657         m_curIncludes->isImported = attrib.value("imported").utf8()=="yes" ? TRUE : FALSE;
658         m_curFile->includes.append(m_curIncludes);
659       }
660       else
661       {
662         warn("Unexpected tag `includes' found");
663       }
664       m_curString="";
665     }
666
667     void endIncludes()
668     {
669       m_curIncludes->text = m_curString;
670     }
671
672     void endTemplateArg()
673     {
674       if (m_state==InClass && m_curClass)
675       {
676         if (m_curClass->templateArguments==0) 
677         {
678           m_curClass->templateArguments = new QList<QCString>;
679           m_curClass->templateArguments->setAutoDelete(TRUE);
680         }
681         m_curClass->templateArguments->append(new QCString(m_curString));
682       }
683       else
684       {
685         warn("Unexpected tag `templarg' found");
686       }
687     }
688
689     void endFilename()
690     {
691       switch (m_state)
692       {
693         case InClass:     m_curClass->filename     = m_curString;    break;
694         case InNamespace: m_curNamespace->filename = m_curString;    break;
695         case InFile:      m_curFile->filename      = m_curString;    break;
696         case InGroup:     m_curGroup->filename     = m_curString;    break;
697         case InPage:      m_curPage->filename      = m_curString;    break;
698         case InPackage:   m_curPackage->filename   = m_curString;    break;
699         case InDir:       m_curDir->filename       = m_curString;    break;
700         default: warn("Unexpected tag `filename' found"); break; 
701       }
702     }
703
704     void endPath()
705     {
706       switch (m_state)
707       {
708         case InFile:      m_curFile->path          = m_curString;    break;
709         case InDir:       m_curDir->path           = m_curString;    break;
710         default: warn("Unexpected tag `path' found");     break; 
711       }
712     }
713     
714     void endAnchor()
715     {
716       if (m_state==InMember)
717       {
718         m_curMember->anchor = m_curString; 
719       }
720       else if (m_state==InClass)
721       {
722         m_curClass->anchor = m_curString; 
723       }
724       else
725       {
726         warn("Unexpected tag `anchor' found");
727       }
728     }
729
730     void endClangId()
731     {
732       if (m_state==InMember)
733       {
734         m_curMember->clangId = m_curString; 
735       }
736       else if (m_state==InClass)
737       {
738         m_curClass->clangId =  m_curString;
739       }
740       else if (m_state==InNamespace)
741       {
742         m_curNamespace->clangId = m_curString;
743       }
744       else
745       {
746         warn("Unexpected tag `clangid' found");
747       }
748     }
749
750
751     
752     void endAnchorFile()
753     {
754       if (m_state==InMember)
755       {
756         m_curMember->anchorFile = m_curString; 
757       }
758       else
759       {
760         warn("Unexpected tag `anchorfile' found");
761       }
762     }
763     
764     void endArglist()
765     {
766       if (m_state==InMember)
767       {
768         m_curMember->arglist = m_curString; 
769       }
770       else
771       {
772         warn("Unexpected tag `arglist' found");
773       }
774     }
775     void endTitle()
776     {
777       switch (m_state)
778       {
779         case InGroup:     m_curGroup->title     = m_curString;    break;
780         case InPage:      m_curPage->title      = m_curString;    break;
781         default: warn("Unexpected tag `title' found"); break; 
782       }
783     }
784
785     void endSubgroup()
786     {
787       if (m_state==InGroup)
788       {
789         m_curGroup->subgroupList.append(m_curString);
790       }
791       else
792       {
793         warn("Unexpected tag `subgroup' found");
794       }
795     }
796
797     void startIgnoreElement(const QXmlAttributes& )
798     {
799     }
800
801     void endIgnoreElement()
802     {
803     }
804
805     bool startDocument()
806     {
807       m_state = Invalid;
808
809       m_curClass=0;
810       m_curNamespace=0;
811       m_curFile=0;
812       m_curGroup=0;
813       m_curPage=0;
814       m_curPackage=0;
815       m_curDir=0;
816
817       m_stateStack.setAutoDelete(TRUE);
818       m_tagFileClasses.setAutoDelete(TRUE);
819       m_tagFileFiles.setAutoDelete(TRUE);
820       m_tagFileNamespaces.setAutoDelete(TRUE);
821       m_tagFileGroups.setAutoDelete(TRUE);
822       m_tagFilePages.setAutoDelete(TRUE);
823       m_tagFilePackages.setAutoDelete(TRUE);
824       m_tagFileDirs.setAutoDelete(TRUE);
825
826       m_startElementHandlers.insert("compound",    new StartElementHandler(this,&TagFileParser::startCompound));
827       m_startElementHandlers.insert("member",      new StartElementHandler(this,&TagFileParser::startMember));
828       m_startElementHandlers.insert("enumvalue",   new StartElementHandler(this,&TagFileParser::startEnumValue));
829       m_startElementHandlers.insert("name",        new StartElementHandler(this,&TagFileParser::startStringValue));
830       m_startElementHandlers.insert("base",        new StartElementHandler(this,&TagFileParser::startBase));
831       m_startElementHandlers.insert("filename",    new StartElementHandler(this,&TagFileParser::startStringValue));
832       m_startElementHandlers.insert("includes",    new StartElementHandler(this,&TagFileParser::startIncludes));
833       m_startElementHandlers.insert("path",        new StartElementHandler(this,&TagFileParser::startStringValue));
834       m_startElementHandlers.insert("anchorfile",  new StartElementHandler(this,&TagFileParser::startStringValue));
835       m_startElementHandlers.insert("anchor",      new StartElementHandler(this,&TagFileParser::startStringValue));
836       m_startElementHandlers.insert("clangid",     new StartElementHandler(this,&TagFileParser::startStringValue));
837       m_startElementHandlers.insert("arglist",     new StartElementHandler(this,&TagFileParser::startStringValue));
838       m_startElementHandlers.insert("title",       new StartElementHandler(this,&TagFileParser::startStringValue));
839       m_startElementHandlers.insert("subgroup",    new StartElementHandler(this,&TagFileParser::startStringValue));
840       m_startElementHandlers.insert("class",       new StartElementHandler(this,&TagFileParser::startStringValue));
841       m_startElementHandlers.insert("namespace",   new StartElementHandler(this,&TagFileParser::startStringValue));
842       m_startElementHandlers.insert("file",        new StartElementHandler(this,&TagFileParser::startStringValue));
843       m_startElementHandlers.insert("dir",         new StartElementHandler(this,&TagFileParser::startStringValue));
844       m_startElementHandlers.insert("page",        new StartElementHandler(this,&TagFileParser::startStringValue));
845       m_startElementHandlers.insert("docanchor",   new StartElementHandler(this,&TagFileParser::startDocAnchor));
846       m_startElementHandlers.insert("tagfile",     new StartElementHandler(this,&TagFileParser::startIgnoreElement));
847       m_startElementHandlers.insert("templarg",    new StartElementHandler(this,&TagFileParser::startStringValue));
848       m_startElementHandlers.insert("type",        new StartElementHandler(this,&TagFileParser::startStringValue));
849
850       m_endElementHandlers.insert("compound",    new EndElementHandler(this,&TagFileParser::endCompound));
851       m_endElementHandlers.insert("member",      new EndElementHandler(this,&TagFileParser::endMember));
852       m_endElementHandlers.insert("enumvalue",   new EndElementHandler(this,&TagFileParser::endEnumValue));
853       m_endElementHandlers.insert("name",        new EndElementHandler(this,&TagFileParser::endName));
854       m_endElementHandlers.insert("base",        new EndElementHandler(this,&TagFileParser::endBase));
855       m_endElementHandlers.insert("filename",    new EndElementHandler(this,&TagFileParser::endFilename));
856       m_endElementHandlers.insert("includes",    new EndElementHandler(this,&TagFileParser::endIncludes));
857       m_endElementHandlers.insert("path",        new EndElementHandler(this,&TagFileParser::endPath));
858       m_endElementHandlers.insert("anchorfile",  new EndElementHandler(this,&TagFileParser::endAnchorFile));
859       m_endElementHandlers.insert("anchor",      new EndElementHandler(this,&TagFileParser::endAnchor));
860       m_endElementHandlers.insert("clangid",     new EndElementHandler(this,&TagFileParser::endClangId));
861       m_endElementHandlers.insert("arglist",     new EndElementHandler(this,&TagFileParser::endArglist));
862       m_endElementHandlers.insert("title",       new EndElementHandler(this,&TagFileParser::endTitle));
863       m_endElementHandlers.insert("subgroup",    new EndElementHandler(this,&TagFileParser::endSubgroup));
864       m_endElementHandlers.insert("class"   ,    new EndElementHandler(this,&TagFileParser::endClass));
865       m_endElementHandlers.insert("namespace",   new EndElementHandler(this,&TagFileParser::endNamespace));
866       m_endElementHandlers.insert("file",        new EndElementHandler(this,&TagFileParser::endFile));
867       m_endElementHandlers.insert("dir",         new EndElementHandler(this,&TagFileParser::endDir));
868       m_endElementHandlers.insert("page",        new EndElementHandler(this,&TagFileParser::endPage));
869       m_endElementHandlers.insert("docanchor",   new EndElementHandler(this,&TagFileParser::endDocAnchor));
870       m_endElementHandlers.insert("tagfile",     new EndElementHandler(this,&TagFileParser::endIgnoreElement));
871       m_endElementHandlers.insert("templarg",    new EndElementHandler(this,&TagFileParser::endTemplateArg));
872       m_endElementHandlers.insert("type",        new EndElementHandler(this,&TagFileParser::endType));
873
874       return TRUE;
875     }
876
877     bool startElement( const QString&, const QString&, 
878                        const QString&name, const QXmlAttributes& attrib )
879     {
880       //printf("startElement `%s'\n",name.data());
881       StartElementHandler *handler = m_startElementHandlers[name.utf8()];
882       if (handler)
883       {
884         (*handler)(attrib);
885       }
886       else 
887       {
888         warn("Unknown tag `%s' found!",name.data());
889       }
890       return TRUE;
891     }
892
893     bool endElement( const QString&, const QString&, const QString& name )
894     {
895       //printf("endElement `%s'\n",name.data());
896       EndElementHandler *handler = m_endElementHandlers[name.utf8()];
897       if (handler)
898       {
899         (*handler)();
900       }
901       else 
902       {
903         warn("Unknown tag `%s' found!",name.data());
904       }
905       return TRUE;
906     }
907
908     bool characters ( const QString & ch ) 
909     {
910       m_curString+=ch.utf8();
911       return TRUE;
912     }
913
914     void dump();
915     void buildLists(Entry *root);
916     void addIncludes();
917     
918   private:
919     void buildMemberList(Entry *ce,QList<TagMemberInfo> &members);
920     void addDocAnchors(Entry *e,const TagAnchorInfoList &l);
921     QList<TagClassInfo>        m_tagFileClasses;
922     QList<TagFileInfo>         m_tagFileFiles;
923     QList<TagNamespaceInfo>    m_tagFileNamespaces;
924     QList<TagGroupInfo>        m_tagFileGroups;
925     QList<TagPageInfo>         m_tagFilePages;
926     QList<TagPackageInfo>      m_tagFilePackages;
927     QList<TagDirInfo>          m_tagFileDirs;
928     QDict<StartElementHandler> m_startElementHandlers;
929     QDict<EndElementHandler>   m_endElementHandlers;
930     TagClassInfo              *m_curClass;
931     TagFileInfo               *m_curFile;
932     TagNamespaceInfo          *m_curNamespace;
933     TagPackageInfo            *m_curPackage;
934     TagGroupInfo              *m_curGroup;
935     TagPageInfo               *m_curPage;
936     TagDirInfo                *m_curDir;
937     TagMemberInfo             *m_curMember;
938     TagEnumValueInfo          *m_curEnumValue;
939     TagIncludeInfo            *m_curIncludes;
940     QCString                   m_curString;
941     QCString                   m_tagName;
942     QCString                   m_fileName;
943     QCString                   m_title;
944     State                      m_state;
945     QStack<State>              m_stateStack;
946     QXmlLocator               *m_locator;
947     QCString                   m_inputFileName;
948 };
949
950 /** Error handler for the XML tag file parser. 
951  *
952  *  Basically dumps all fatal error to stderr using err().
953  */
954 class TagFileErrorHandler : public QXmlErrorHandler
955 {
956   public:
957     virtual ~TagFileErrorHandler() {}
958     bool warning( const QXmlParseException & )
959     {
960       return FALSE;
961     }
962     bool error( const QXmlParseException & )
963     {
964       return FALSE;
965     }
966     bool fatalError( const QXmlParseException &exception )
967     {
968       err("Fatal error at line %d column %d: %s\n",
969           exception.lineNumber(),exception.columnNumber(),
970           exception.message().data());
971       return FALSE;
972     }
973     QString errorString() { return ""; }
974
975   private:
976     QString errorMsg;
977 };
978
979 /*! Dumps the internal structures. For debugging only! */
980 void TagFileParser::dump()
981 {
982   msg("Result:\n");
983   QListIterator<TagClassInfo> lci(m_tagFileClasses);
984
985   //============== CLASSES
986   TagClassInfo *cd;
987   for (;(cd=lci.current());++lci)
988   {
989     msg("class `%s'\n",cd->name.data());
990     msg("  filename `%s'\n",cd->filename.data());
991     if (cd->bases)
992     {
993       QListIterator<BaseInfo> bii(*cd->bases);
994       BaseInfo *bi;
995       for ( bii.toFirst() ; (bi=bii.current()) ; ++bii) 
996       {
997         msg( "  base: %s \n", bi->name.data() );
998       }
999     }
1000
1001     QListIterator<TagMemberInfo> mci(cd->members);
1002     TagMemberInfo *md;
1003     for (;(md=mci.current());++mci)
1004     {
1005       msg("  member:\n");
1006       msg("    kind: `%s'\n",md->kind.data());
1007       msg("    name: `%s'\n",md->name.data());
1008       msg("    anchor: `%s'\n",md->anchor.data());
1009       msg("    arglist: `%s'\n",md->arglist.data());
1010     }
1011   }
1012   //============== NAMESPACES
1013   QListIterator<TagNamespaceInfo> lni(m_tagFileNamespaces);
1014   TagNamespaceInfo *nd;
1015   for (;(nd=lni.current());++lni)
1016   {
1017     msg("namespace `%s'\n",nd->name.data());
1018     msg("  filename `%s'\n",nd->filename.data());
1019     QCStringList::Iterator it;
1020     for ( it = nd->classList.begin(); 
1021         it != nd->classList.end(); ++it ) 
1022     {
1023       msg( "  class: %s \n", (*it).data() );
1024     }
1025
1026     QListIterator<TagMemberInfo> mci(nd->members);
1027     TagMemberInfo *md;
1028     for (;(md=mci.current());++mci)
1029     {
1030       msg("  member:\n");
1031       msg("    kind: `%s'\n",md->kind.data());
1032       msg("    name: `%s'\n",md->name.data());
1033       msg("    anchor: `%s'\n",md->anchor.data());
1034       msg("    arglist: `%s'\n",md->arglist.data());
1035     }
1036   }
1037   //============== FILES
1038   QListIterator<TagFileInfo> lfi(m_tagFileFiles);
1039   TagFileInfo *fd;
1040   for (;(fd=lfi.current());++lfi)
1041   {
1042     msg("file `%s'\n",fd->name.data());
1043     msg("  filename `%s'\n",fd->filename.data());
1044     QCStringList::Iterator it;
1045     for ( it = fd->namespaceList.begin(); 
1046         it != fd->namespaceList.end(); ++it ) 
1047     {
1048       msg( "  namespace: %s \n", (*it).data() );
1049     }
1050     for ( it = fd->classList.begin(); 
1051         it != fd->classList.end(); ++it ) 
1052     {
1053       msg( "  class: %s \n", (*it).data() );
1054     }
1055
1056     QListIterator<TagMemberInfo> mci(fd->members);
1057     TagMemberInfo *md;
1058     for (;(md=mci.current());++mci)
1059     {
1060       msg("  member:\n");
1061       msg("    kind: `%s'\n",md->kind.data());
1062       msg("    name: `%s'\n",md->name.data());
1063       msg("    anchor: `%s'\n",md->anchor.data());
1064       msg("    arglist: `%s'\n",md->arglist.data());
1065     }
1066
1067     QListIterator<TagIncludeInfo> mii(fd->includes);
1068     TagIncludeInfo *ii;
1069     for (;(ii=mii.current());++mii)
1070     {
1071       msg("  includes id: %s name: %s\n",ii->id.data(),ii->name.data());
1072     }
1073   }
1074
1075   //============== GROUPS
1076   QListIterator<TagGroupInfo> lgi(m_tagFileGroups);
1077   TagGroupInfo *gd;
1078   for (;(gd=lgi.current());++lgi)
1079   {
1080     msg("group `%s'\n",gd->name.data());
1081     msg("  filename `%s'\n",gd->filename.data());
1082     QCStringList::Iterator it;
1083     for ( it = gd->namespaceList.begin(); 
1084         it != gd->namespaceList.end(); ++it ) 
1085     {
1086       msg( "  namespace: %s \n", (*it).data() );
1087     }
1088     for ( it = gd->classList.begin(); 
1089         it != gd->classList.end(); ++it ) 
1090     {
1091       msg( "  class: %s \n", (*it).data() );
1092     }
1093     for ( it = gd->fileList.begin(); 
1094         it != gd->fileList.end(); ++it ) 
1095     {
1096       msg( "  file: %s \n", (*it).data() );
1097     }
1098     for ( it = gd->subgroupList.begin(); 
1099         it != gd->subgroupList.end(); ++it ) 
1100     {
1101       msg( "  subgroup: %s \n", (*it).data() );
1102     }
1103     for ( it = gd->pageList.begin(); 
1104         it != gd->pageList.end(); ++it ) 
1105     {
1106       msg( "  page: %s \n", (*it).data() );
1107     }
1108
1109     QListIterator<TagMemberInfo> mci(gd->members);
1110     TagMemberInfo *md;
1111     for (;(md=mci.current());++mci)
1112     {
1113       msg("  member:\n");
1114       msg("    kind: `%s'\n",md->kind.data());
1115       msg("    name: `%s'\n",md->name.data());
1116       msg("    anchor: `%s'\n",md->anchor.data());
1117       msg("    arglist: `%s'\n",md->arglist.data());
1118     }
1119   }
1120   //============== PAGES
1121   QListIterator<TagPageInfo> lpi(m_tagFilePages);
1122   TagPageInfo *pd;
1123   for (;(pd=lpi.current());++lpi)
1124   {
1125     msg("page `%s'\n",pd->name.data());
1126     msg("  title `%s'\n",pd->title.data());
1127     msg("  filename `%s'\n",pd->filename.data());
1128   }
1129   //============== DIRS
1130   QListIterator<TagDirInfo> ldi(m_tagFileDirs);
1131   TagDirInfo *dd;
1132   for (;(dd=ldi.current());++ldi)
1133   {
1134     msg("dir `%s'\n",dd->name.data());
1135     msg("  path `%s'\n",dd->path.data());
1136     QCStringList::Iterator it;
1137     for ( it = dd->fileList.begin(); 
1138         it != dd->fileList.end(); ++it ) 
1139     {
1140       msg( "  file: %s \n", (*it).data() );
1141     }
1142     for ( it = dd->subdirList.begin(); 
1143         it != dd->subdirList.end(); ++it ) 
1144     {
1145       msg( "  subdir: %s \n", (*it).data() );
1146     }
1147   }
1148 }
1149
1150 void TagFileParser::addDocAnchors(Entry *e,const TagAnchorInfoList &l)
1151 {
1152   QListIterator<TagAnchorInfo> tli(l);
1153   TagAnchorInfo *ta;
1154   for (tli.toFirst();(ta=tli.current());++tli)
1155   {
1156     if (Doxygen::sectionDict->find(ta->label)==0)
1157     {
1158       //printf("New sectionInfo file=%s anchor=%s\n",
1159       //    ta->fileName.data(),ta->label.data());
1160       SectionInfo *si=new SectionInfo(ta->fileName,-1,ta->label,ta->title,
1161           SectionInfo::Anchor,0,m_tagName);
1162       Doxygen::sectionDict->append(ta->label,si);
1163       e->anchors->append(si);
1164     }
1165     else
1166     {
1167       warn("Duplicate anchor %s found",ta->label.data());
1168     }
1169   }
1170 }
1171
1172 void TagFileParser::buildMemberList(Entry *ce,QList<TagMemberInfo> &members)
1173 {
1174   QListIterator<TagMemberInfo> mii(members);
1175   TagMemberInfo *tmi;
1176   for (;(tmi=mii.current());++mii)
1177   {
1178     Entry *me      = new Entry;
1179     me->type       = tmi->type;
1180     me->name       = tmi->name;
1181     me->args       = tmi->arglist;
1182     if (!me->args.isEmpty())
1183     {
1184       delete me->argList;
1185       me->argList = new ArgumentList;
1186       stringToArgumentList(me->args,me->argList);
1187     }
1188     if (tmi->enumValues.count()>0)
1189     {
1190       me->spec |= Entry::Strong;
1191       QListIterator<TagEnumValueInfo> evii(tmi->enumValues);
1192       TagEnumValueInfo *evi;
1193       for (evii.toFirst();(evi=evii.current());++evii)
1194       {
1195         Entry *ev      = new Entry;
1196         ev->type       = "@";
1197         ev->name       = evi->name;
1198         ev->id         = evi->clangid;
1199         ev->section    = Entry::VARIABLE_SEC;
1200         TagInfo *ti    = new TagInfo;
1201         ti->tagName    = m_tagName;
1202         ti->anchor     = evi->anchor;
1203         ti->fileName   = evi->file;
1204         ev->tagInfo    = ti;
1205         me->addSubEntry(ev);
1206       }
1207     }
1208     me->protection = tmi->prot;
1209     me->virt       = tmi->virt;
1210     me->stat       = tmi->isStatic;
1211     me->fileName   = ce->fileName;
1212     me->id         = tmi->clangId;
1213     if (ce->section == Entry::GROUPDOC_SEC)
1214     {
1215       me->groups->append(new Grouping(ce->name,Grouping::GROUPING_INGROUP));
1216     }
1217     addDocAnchors(me,tmi->docAnchors);
1218     TagInfo *ti    = new TagInfo;
1219     ti->tagName    = m_tagName;
1220     ti->anchor     = tmi->anchor;
1221     ti->fileName   = tmi->anchorFile;
1222     me->tagInfo    = ti;
1223     if (tmi->kind=="define")
1224     {
1225       me->type="#define";
1226       me->section = Entry::DEFINE_SEC;
1227     }
1228     else if (tmi->kind=="enumvalue")
1229     {
1230       me->section = Entry::VARIABLE_SEC;
1231       me->mtype = Method;
1232     }
1233     else if (tmi->kind=="property")
1234     {
1235       me->section = Entry::VARIABLE_SEC;
1236       me->mtype = Property;
1237     }
1238     else if (tmi->kind=="event")
1239     {
1240       me->section = Entry::VARIABLE_SEC;
1241       me->mtype = Event;
1242     }
1243     else if (tmi->kind=="variable")
1244     {
1245       me->section = Entry::VARIABLE_SEC;
1246       me->mtype = Method;
1247     }
1248     else if (tmi->kind=="typedef")
1249     {
1250       me->section = Entry::VARIABLE_SEC; //Entry::TYPEDEF_SEC;
1251       me->type.prepend("typedef ");
1252       me->mtype = Method;
1253     }
1254     else if (tmi->kind=="enumeration")
1255     {
1256       me->section = Entry::ENUM_SEC;
1257       me->mtype = Method;
1258     }
1259     else if (tmi->kind=="function")
1260     {
1261       me->section = Entry::FUNCTION_SEC;
1262       me->mtype = Method;
1263     }
1264     else if (tmi->kind=="signal")
1265     {
1266       me->section = Entry::FUNCTION_SEC;
1267       me->mtype = Signal;
1268     }
1269     else if (tmi->kind=="prototype")
1270     {
1271       me->section = Entry::FUNCTION_SEC;
1272       me->mtype = Method;
1273     }
1274     else if (tmi->kind=="friend")
1275     {
1276       me->section = Entry::FUNCTION_SEC;
1277       me->type.prepend("friend ");
1278       me->mtype = Method;
1279     }
1280     else if (tmi->kind=="dcop")
1281     {
1282       me->section = Entry::FUNCTION_SEC;
1283       me->mtype = DCOP;
1284     }
1285     else if (tmi->kind=="slot")
1286     {
1287       me->section = Entry::FUNCTION_SEC;
1288       me->mtype = Slot;
1289     }
1290     ce->addSubEntry(me);
1291   }
1292 }
1293
1294 static QCString stripPath(const QCString &s)
1295 {
1296   int i=s.findRev('/');
1297   if (i!=-1)
1298   {
1299     return s.right(s.length()-i-1);
1300   }
1301   else
1302   {
1303     return s;
1304   }
1305 }
1306
1307 /*! Injects the info gathered by the XML parser into the Entry tree.
1308  *  This tree contains the information extracted from the input in a 
1309  *  "unrelated" form.
1310  */
1311 void TagFileParser::buildLists(Entry *root)
1312 {
1313   // build class list
1314   QListIterator<TagClassInfo> cit(m_tagFileClasses);
1315   TagClassInfo *tci;
1316   for (cit.toFirst();(tci=cit.current());++cit)
1317   {
1318     Entry *ce = new Entry;
1319     ce->section = Entry::CLASS_SEC;
1320     switch (tci->kind)
1321     {
1322       case TagClassInfo::Class:     break;
1323       case TagClassInfo::Struct:    ce->spec = Entry::Struct;    break;
1324       case TagClassInfo::Union:     ce->spec = Entry::Union;     break;
1325       case TagClassInfo::Interface: ce->spec = Entry::Interface; break;
1326       case TagClassInfo::Enum:      ce->spec = Entry::Enum;      break;
1327       case TagClassInfo::Exception: ce->spec = Entry::Exception; break;
1328       case TagClassInfo::Protocol:  ce->spec = Entry::Protocol;  break;
1329       case TagClassInfo::Category:  ce->spec = Entry::Category;  break;
1330       case TagClassInfo::Service:   ce->spec = Entry::Service;   break;
1331       case TagClassInfo::Singleton: ce->spec = Entry::Singleton; break;
1332       case TagClassInfo::None:      // should never happen, means not properly initialized
1333         assert(tci->kind != TagClassInfo::None);
1334         break;
1335     }
1336     ce->name     = tci->name;
1337     if (tci->kind==TagClassInfo::Protocol)
1338     {
1339       ce->name+="-p";
1340     }
1341     addDocAnchors(ce,tci->docAnchors);
1342     TagInfo *ti  = new TagInfo;
1343     ti->tagName  = m_tagName;
1344     ti->anchor   = tci->anchor;
1345     ti->fileName = tci->filename;
1346     ce->id       = tci->clangId;
1347     ce->tagInfo  = ti;
1348     ce->lang     = tci->isObjC ? SrcLangExt_ObjC : SrcLangExt_Unknown;
1349     // transfer base class list
1350     if (tci->bases)
1351     {
1352       delete ce->extends;
1353       ce->extends = tci->bases; tci->bases = 0;
1354     }
1355     if (tci->templateArguments)
1356     {
1357       if (ce->tArgLists==0)
1358       {
1359         ce->tArgLists = new QList<ArgumentList>;
1360         ce->tArgLists->setAutoDelete(TRUE);
1361       }
1362       ArgumentList *al = new ArgumentList;
1363       ce->tArgLists->append(al);
1364
1365       QListIterator<QCString> sli(*tci->templateArguments);
1366       QCString *argName;
1367       for (;(argName=sli.current());++sli)
1368       {
1369         Argument *a = new Argument;
1370         a->type = "class";
1371         a->name = *argName;
1372         al->append(a);
1373       }
1374     }
1375
1376     buildMemberList(ce,tci->members);
1377     root->addSubEntry(ce);
1378   }
1379
1380   // build file list
1381   QListIterator<TagFileInfo> fit(m_tagFileFiles);
1382   TagFileInfo *tfi;
1383   for (fit.toFirst();(tfi=fit.current());++fit)
1384   {
1385     Entry *fe = new Entry;
1386     fe->section = guessSection(tfi->name);
1387     fe->name     = tfi->name;
1388     addDocAnchors(fe,tfi->docAnchors);
1389     TagInfo *ti  = new TagInfo;
1390     ti->tagName  = m_tagName;
1391     ti->fileName = tfi->filename;
1392     fe->tagInfo  = ti;
1393     
1394     QCString fullName = m_tagName+":"+tfi->path+stripPath(tfi->name);
1395     fe->fileName = fullName;
1396     //printf("new FileDef() filename=%s\n",tfi->filename.data());
1397     FileDef *fd = new FileDef(m_tagName+":"+tfi->path,
1398                               tfi->name,m_tagName,
1399                               tfi->filename
1400                              );
1401     FileName *mn;
1402     if ((mn=Doxygen::inputNameDict->find(tfi->name)))
1403     {
1404       mn->append(fd);
1405     }
1406     else
1407     {
1408       mn = new FileName(fullName,tfi->name);
1409       mn->append(fd);
1410       Doxygen::inputNameList->inSort(mn);
1411       Doxygen::inputNameDict->insert(tfi->name,mn);
1412     }
1413     buildMemberList(fe,tfi->members);
1414     root->addSubEntry(fe);
1415   }
1416
1417   // build namespace list
1418   QListIterator<TagNamespaceInfo> nit(m_tagFileNamespaces);
1419   TagNamespaceInfo *tni;
1420   for (nit.toFirst();(tni=nit.current());++nit)
1421   {
1422     Entry *ne    = new Entry;
1423     ne->section  = Entry::NAMESPACE_SEC;
1424     ne->name     = tni->name;
1425     addDocAnchors(ne,tni->docAnchors);
1426     TagInfo *ti  = new TagInfo;
1427     ti->tagName  = m_tagName;
1428     ti->fileName = tni->filename;
1429     ne->id       = tni->clangId;
1430     ne->tagInfo  = ti;
1431
1432     buildMemberList(ne,tni->members);
1433     root->addSubEntry(ne);
1434   }
1435
1436   // build package list
1437   QListIterator<TagPackageInfo> pit(m_tagFilePackages);
1438   TagPackageInfo *tpgi;
1439   for (pit.toFirst();(tpgi=pit.current());++pit)
1440   {
1441     Entry *pe    = new Entry;
1442     pe->section  = Entry::PACKAGE_SEC;
1443     pe->name     = tpgi->name;
1444     addDocAnchors(pe,tpgi->docAnchors);
1445     TagInfo *ti  = new TagInfo;
1446     ti->tagName  = m_tagName;
1447     ti->fileName = tpgi->filename;
1448     pe->tagInfo  = ti;
1449
1450     buildMemberList(pe,tpgi->members);
1451     root->addSubEntry(pe);
1452   }
1453
1454   // build group list
1455   QListIterator<TagGroupInfo> git(m_tagFileGroups);
1456   TagGroupInfo *tgi;
1457   for (git.toFirst();(tgi=git.current());++git)
1458   {
1459     Entry *ge    = new Entry;
1460     ge->section  = Entry::GROUPDOC_SEC;
1461     ge->name     = tgi->name;
1462     ge->type     = tgi->title;
1463     addDocAnchors(ge,tgi->docAnchors);
1464     TagInfo *ti  = new TagInfo;
1465     ti->tagName  = m_tagName;
1466     ti->fileName = tgi->filename;
1467     ge->tagInfo  = ti;
1468
1469     buildMemberList(ge,tgi->members);
1470     root->addSubEntry(ge);
1471   }
1472
1473   // set subgroup relations bug_774118
1474   for (git.toFirst();(tgi=git.current());++git)
1475   {
1476     QCStringList::Iterator it;
1477     for ( it = tgi->subgroupList.begin(); it != tgi->subgroupList.end(); ++it )
1478     {
1479       QListIterator<Entry> eli(*(root->children()));
1480       Entry *childNode;
1481       for (eli.toFirst();(childNode=eli.current());++eli)
1482       {
1483         if (childNode->name == (*it)) break;
1484       }
1485       childNode->groups->append(new Grouping(tgi->name,Grouping::GROUPING_INGROUP));
1486     }
1487   }
1488
1489   // build page list
1490   QListIterator<TagPageInfo> pgit(m_tagFilePages);
1491   TagPageInfo *tpi;
1492   for (pgit.toFirst();(tpi=pgit.current());++pgit)
1493   {
1494     Entry *pe    = new Entry;
1495     pe->section  = tpi->filename=="index" ? Entry::MAINPAGEDOC_SEC : Entry::PAGEDOC_SEC;
1496     pe->name     = tpi->name;
1497     pe->args     = tpi->title;
1498     addDocAnchors(pe,tpi->docAnchors);
1499     TagInfo *ti  = new TagInfo;
1500     ti->tagName  = m_tagName;
1501     ti->fileName = tpi->filename;
1502     pe->tagInfo  = ti;
1503     root->addSubEntry(pe);
1504   }
1505 }
1506
1507 void TagFileParser::addIncludes()
1508 {
1509   QListIterator<TagFileInfo> fit(m_tagFileFiles);
1510   TagFileInfo *tfi;
1511   for (fit.toFirst();(tfi=fit.current());++fit)
1512   {
1513     //printf("tag file tagName=%s path=%s name=%s\n",m_tagName.data(),tfi->path.data(),tfi->name.data());
1514     FileName *fn = Doxygen::inputNameDict->find(tfi->name);
1515     if (fn)
1516     {
1517       //printf("found\n");
1518       FileNameIterator fni(*fn);
1519       FileDef *fd;
1520       for (;(fd=fni.current());++fni)
1521       {
1522         //printf("input file path=%s name=%s\n",fd->getPath().data(),fd->name().data());
1523         if (fd->getPath()==QCString(m_tagName+":"+tfi->path))
1524         {
1525           //printf("found\n");
1526           QListIterator<TagIncludeInfo> mii(tfi->includes);
1527           TagIncludeInfo *ii;
1528           for (;(ii=mii.current());++mii)
1529           {
1530             //printf("ii->name=`%s'\n",ii->name.data());
1531             FileName *ifn = Doxygen::inputNameDict->find(ii->name);
1532             ASSERT(ifn!=0);
1533             if (ifn)
1534             {
1535               FileNameIterator ifni(*ifn);
1536               FileDef *ifd;
1537               for (;(ifd=ifni.current());++ifni)
1538               {
1539                 //printf("ifd->getOutputFileBase()=%s ii->id=%s\n",
1540                 //        ifd->getOutputFileBase().data(),ii->id.data());
1541                 if (ifd->getOutputFileBase()==QCString(ii->id))
1542                 {
1543                   fd->addIncludeDependency(ifd,ii->text,ii->isLocal,ii->isImported,FALSE);
1544                 }
1545               }
1546             }
1547           }
1548         }
1549       }
1550     }
1551   }
1552 }
1553
1554 void parseTagFile(Entry *root,const char *fullName)
1555 {
1556   QFileInfo fi(fullName);
1557   if (!fi.exists()) return;
1558   TagFileParser handler( fullName ); // tagName
1559   handler.setFileName(fullName);
1560   TagFileErrorHandler errorHandler;
1561   QFile xmlFile( fullName );
1562   QXmlInputSource source( xmlFile );
1563   QXmlSimpleReader reader;
1564   reader.setContentHandler( &handler );
1565   reader.setErrorHandler( &errorHandler );
1566   reader.parse( source );
1567   handler.buildLists(root);
1568   handler.addIncludes();
1569   //handler.dump();
1570 }
1571
1572