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