Fix for UBSan build
[platform/upstream/doxygen.git] / src / filedef.cpp
1 /******************************************************************************
2  *
3  * $Id: filedef.cpp,v 1.55 2001/03/19 19:27:40 root Exp $
4  *
5  * Copyright (C) 1997-2012 by Dimitri van Heesch.
6  *
7  * Permission to use, copy, modify, and distribute this software and its
8  * documentation under the terms of the GNU General Public License is hereby 
9  * granted. No representations are made about the suitability of this software 
10  * for any purpose. It is provided "as is" without express or implied warranty.
11  * See the GNU General Public License for more details.
12  *
13  * Documents produced by Doxygen are derivative works derived from the
14  * input used in their production; they are not affected by this license.
15  *
16  */
17
18 #include "qtbc.h"
19 #include "memberlist.h"
20 #include "classlist.h"
21 #include "filedef.h"
22 #include "doxygen.h"
23 #include "memberdef.h"
24 #include "classdef.h"
25 #include "namespacedef.h"
26 #include "util.h"
27 #include "language.h"
28 #include "outputlist.h"
29 #include "dot.h"
30 #include "message.h"
31 #include "docparser.h"
32 #include "searchindex.h"
33 #include "htags.h"
34 #include "parserintf.h"
35 #include "portable.h"
36 #include "vhdldocgen.h"
37 #include "debug.h"
38 #include "layout.h"
39 #include "entry.h"
40
41 //---------------------------------------------------------------------------
42
43 /** Class implementing CodeOutputInterface by throwing away everything. */
44 class DevNullCodeDocInterface : public CodeOutputInterface
45 {
46   public:
47     virtual void codify(const char *) {}
48     virtual void writeCodeLink(const char *,const char *,
49                                const char *,const char *,
50                                const char *) {}
51     virtual void writeLineNumber(const char *,const char *,
52                                  const char *,int) {}
53     virtual void startCodeLine(bool) {}
54     virtual void endCodeLine() {}
55     virtual void startCodeAnchor(const char *) {}
56     virtual void endCodeAnchor() {}
57     virtual void startFontClass(const char *) {}
58     virtual void endFontClass() {}
59     virtual void writeCodeAnchor(const char *) {}
60     virtual void linkableSymbol(int, const char *,Definition *,Definition *) {}
61 };
62
63 //---------------------------------------------------------------------------
64
65 /*! create a new file definition, where \a p is the file path, 
66     \a nm the file name, and \a lref is an HTML anchor name if the
67     file was read from a tag file or 0 otherwise
68 */
69 FileDef::FileDef(const char *p,const char *nm,
70                  const char *lref,const char *dn)
71    : Definition((QCString)p+nm,1,nm)
72 {
73   path=p;
74   filepath=path+nm;
75   filename=nm;
76   diskname=dn;
77   if (diskname.isEmpty()) diskname=nm;
78   setReference(lref);
79   classSDict        = 0;
80   includeList       = 0;
81   includeDict       = 0; 
82   includedByList    = 0;
83   includedByDict    = 0; 
84   namespaceSDict    = 0; 
85   srcDefDict        = 0;
86   srcMemberDict     = 0;
87   usingDirList      = 0;
88   usingDeclList     = 0;
89   package           = 0;
90   isSource          = FALSE; 
91   docname           = nm;
92   dir               = 0;
93   if (Config_getBool("FULL_PATH_NAMES"))
94   {
95     docname.prepend(stripFromPath(path.copy()));
96   }
97   SrcLangExt lang = getLanguageFromFileName(name());
98   setLanguage(lang);
99   //m_isJava          = lang==SrcLangExt_Java;
100   //m_isCSharp        = lang==SrcLangExt_CSharp;
101   memberGroupSDict = 0;
102   acquireFileVersion();
103   m_subGrouping=Config_getBool("SUBGROUPING");
104 }
105
106 /*! destroy the file definition */
107 FileDef::~FileDef()
108 {
109   delete classSDict;
110   delete includeDict;
111   delete includeList;
112   delete includedByDict;
113   delete includedByList;
114   delete namespaceSDict;
115   delete srcDefDict;
116   delete srcMemberDict;
117   delete usingDirList;
118   delete usingDeclList;
119   delete memberGroupSDict;
120 }
121
122 /*! Compute the HTML anchor names for all members in the class */ 
123 void FileDef::computeAnchors()
124 {
125   MemberList *ml = getMemberList(MemberList::allMembersList);
126   if (ml) setAnchors(0,'a',ml);
127 }
128
129 void FileDef::distributeMemberGroupDocumentation()
130 {
131   //printf("FileDef::distributeMemberGroupDocumentation()\n");
132   if (memberGroupSDict)
133   {
134     MemberGroupSDict::Iterator mgli(*memberGroupSDict);
135     MemberGroup *mg;
136     for (;(mg=mgli.current());++mgli)
137     {
138       mg->distributeMemberGroupDocumentation();
139     }
140   }
141 }
142
143 void FileDef::findSectionsInDocumentation()
144 {
145   docFindSections(documentation(),this,0,docFile());
146   if (memberGroupSDict)
147   {
148     MemberGroupSDict::Iterator mgli(*memberGroupSDict);
149     MemberGroup *mg;
150     for (;(mg=mgli.current());++mgli)
151     {
152       mg->findSectionsInDocumentation();
153     }
154   }
155
156   QListIterator<MemberList> mli(m_memberLists);
157   MemberList *ml;
158   for (mli.toFirst();(ml=mli.current());++mli)
159   {
160     if (ml->listType()&MemberList::declarationLists)
161     {
162       ml->findSectionsInDocumentation();
163     }
164   }
165 }
166
167 void FileDef::writeDetailedDescription(OutputList &ol,const QCString &title)
168 {
169   if ((!briefDescription().isEmpty() && Config_getBool("REPEAT_BRIEF")) || 
170       !documentation().stripWhiteSpace().isEmpty() || // avail empty section
171       (Config_getBool("SOURCE_BROWSER") && getStartBodyLine()!=-1 && getBodyDef())
172      )
173   {
174     ol.pushGeneratorState();
175       ol.disable(OutputGenerator::Html);
176       ol.writeRuler();
177     ol.popGeneratorState();
178     ol.pushGeneratorState();
179       ol.disableAllBut(OutputGenerator::Html);
180       ol.writeAnchor(0,"details"); 
181     ol.popGeneratorState();
182     ol.startGroupHeader();
183     ol.parseText(title);
184     ol.endGroupHeader();
185
186     ol.startTextBlock();
187     if (!briefDescription().isEmpty() && Config_getBool("REPEAT_BRIEF"))
188     {
189       ol.parseDoc(briefFile(),briefLine(),this,0,briefDescription(),FALSE,FALSE);
190     }
191     if (!briefDescription().isEmpty() && Config_getBool("REPEAT_BRIEF") && 
192         !documentation().isEmpty())
193     {
194       ol.pushGeneratorState();
195         ol.disable(OutputGenerator::Man);
196         ol.disable(OutputGenerator::RTF);
197         // ol.newParagraph(); // FIXME:PARA
198         ol.enableAll();
199         ol.disableAllBut(OutputGenerator::Man);
200         ol.writeString("\n\n");
201       ol.popGeneratorState();
202     }
203     if (!documentation().isEmpty())
204     {
205       ol.parseDoc(docFile(),docLine(),this,0,documentation()+"\n",TRUE,FALSE);
206     }
207     //printf("Writing source ref for file %s\n",name().data());
208     if (Config_getBool("SOURCE_BROWSER")) 
209     {
210       ol.startParagraph();
211       QCString refText = theTranslator->trDefinedInSourceFile();
212       int fileMarkerPos = refText.find("@0");
213       if (fileMarkerPos!=-1) // should always pass this.
214       {
215         ol.parseText(refText.left(fileMarkerPos)); //text left from marker 1
216         ol.writeObjectLink(0,getSourceFileBase(),
217             0,name());
218         ol.parseText(refText.right(
219               refText.length()-fileMarkerPos-2)); // text right from marker 2
220       }
221       ol.endParagraph();
222     }
223     ol.endTextBlock();
224   }
225 }
226
227 void FileDef::writeBriefDescription(OutputList &ol)
228 {
229   if (!briefDescription().isEmpty() && Config_getBool("BRIEF_MEMBER_DESC"))
230   {
231     ol.startParagraph();
232     ol.parseDoc(briefFile(),briefLine(),this,0,
233                 briefDescription(),TRUE,FALSE,0,TRUE,FALSE);
234     ol.pushGeneratorState();
235     ol.disable(OutputGenerator::RTF);
236     ol.writeString(" \n");
237     ol.enable(OutputGenerator::RTF);
238
239     if (Config_getBool("REPEAT_BRIEF") ||
240         !documentation().isEmpty()
241        )
242     {
243       ol.disableAllBut(OutputGenerator::Html);
244       ol.startTextLink(0,"details");
245       ol.parseText(theTranslator->trMore());
246       ol.endTextLink();
247     }
248     ol.popGeneratorState();
249     ol.endParagraph();
250
251     //ol.pushGeneratorState();
252     //ol.disable(OutputGenerator::RTF);
253     //ol.newParagraph();
254     //ol.popGeneratorState();
255   }
256   ol.writeSynopsis();
257 }
258
259 void FileDef::writeIncludeFiles(OutputList &ol)
260 {
261   if (/*Config_getBool("SHOW_INCLUDE_FILES") &&*/ includeList && 
262       includeList->count()>0)
263   {
264     ol.startTextBlock(TRUE);
265     QListIterator<IncludeInfo> ili(*includeList);
266     IncludeInfo *ii;
267     for (;(ii=ili.current());++ili)
268     {
269       if (!ii->indirect)
270       {
271         FileDef *fd=ii->fileDef;
272         bool isIDLorJava = FALSE;
273         if (fd)
274         {
275           SrcLangExt lang   = fd->getLanguage();
276           isIDLorJava = lang==SrcLangExt_IDL || lang==SrcLangExt_Java;
277         }
278         ol.startTypewriter();
279         if (isIDLorJava) // IDL/Java include
280         {
281           ol.docify("import ");
282         }
283         else if (ii->imported) // Objective-C include
284         {
285           ol.docify("#import ");
286         }
287         else // C/C++ include
288         {
289           ol.docify("#include ");
290         }
291         if (ii->local || isIDLorJava)
292           ol.docify("\"");
293         else
294           ol.docify("<");
295         ol.disable(OutputGenerator::Html);
296         ol.docify(ii->includeName);
297         ol.enableAll();
298         ol.disableAllBut(OutputGenerator::Html);
299         
300         // Here we use the include file name as it appears in the file.
301         // we could also we the name as it is used within doxygen,
302         // then we should have used fd->docName() instead of ii->includeName
303         if (fd && fd->isLinkable())
304         {
305           ol.writeObjectLink(fd->getReference(),
306               fd->generateSourceFile() ? fd->includeName() : fd->getOutputFileBase(),
307               0,ii->includeName);
308           if (!Config_getString("GENERATE_TAGFILE").isEmpty() && !fd->isReference()) 
309           {
310             const char *locStr = (ii->local    || isIDLorJava) ? "yes" : "no";
311             const char *impStr = (ii->imported || isIDLorJava) ? "yes" : "no";
312             Doxygen::tagFile << "    <includes id=\"" 
313                              << convertToXML(fd->getOutputFileBase()) << "\" "
314                              << "name=\"" << convertToXML(fd->name()) << "\" "
315                              << "local=\"" << locStr << "\" "
316                              << "imported=\"" << impStr << "\">"
317                              << convertToXML(ii->includeName)
318                              << "</includes>" 
319                              << endl;
320           }
321         }
322         else
323         {
324           ol.docify(ii->includeName);
325         }
326         
327         ol.enableAll();
328         if (ii->local || isIDLorJava)
329           ol.docify("\"");
330         else
331           ol.docify(">");
332         if (isIDLorJava) 
333           ol.docify(";");
334         ol.endTypewriter();
335         ol.lineBreak();
336       }
337     }
338     ol.endTextBlock();
339   }
340 }
341
342 void FileDef::writeIncludeGraph(OutputList &ol)
343 {
344   if (Config_getBool("HAVE_DOT") /*&& Config_getBool("INCLUDE_GRAPH")*/)
345   {
346     //printf("Graph for file %s\n",name().data());
347     DotInclDepGraph incDepGraph(this,FALSE);
348     if (incDepGraph.isTooBig())
349     {
350        err("warning: Include graph for '%s' not generated, too many nodes. Consider increasing DOT_GRAPH_MAX_NODES.\n",name().data());
351     }
352     else if (!incDepGraph.isTrivial())
353     {
354       ol.startTextBlock(); 
355       ol.disable(OutputGenerator::Man);
356       ol.startInclDepGraph();
357       ol.parseText(theTranslator->trInclDepGraph(name()));
358       ol.endInclDepGraph(incDepGraph);
359       ol.enableAll();
360       ol.endTextBlock(TRUE);
361     }
362     //incDepGraph.writeGraph(Config_getString("HTML_OUTPUT"),fd->getOutputFileBase());
363   }
364 }
365
366 void FileDef::writeIncludedByGraph(OutputList &ol)
367 {
368   if (Config_getBool("HAVE_DOT") /*&& Config_getBool("INCLUDED_BY_GRAPH")*/)
369   {
370     //printf("Graph for file %s\n",name().data());
371     DotInclDepGraph incDepGraph(this,TRUE);
372     if (incDepGraph.isTooBig())
373     {
374        err("warning: Included by graph for '%s' not generated, too many nodes. Consider increasing DOT_GRAPH_MAX_NODES.\n",name().data());
375     }
376     if (!incDepGraph.isTrivial())
377     {
378       ol.startTextBlock(); 
379       ol.disable(OutputGenerator::Man);
380       ol.startInclDepGraph();
381       ol.parseText(theTranslator->trInclByDepGraph());
382       ol.endInclDepGraph(incDepGraph);
383       ol.enableAll();
384       ol.endTextBlock(TRUE);
385     }
386     //incDepGraph.writeGraph(Config_getString("HTML_OUTPUT"),fd->getOutputFileBase());
387   }
388 }
389
390
391 void FileDef::writeSourceLink(OutputList &ol)
392 {
393   //printf("%s: generateSourceFile()=%d\n",name().data(),generateSourceFile());
394   if (generateSourceFile())
395   {
396     ol.disableAllBut(OutputGenerator::Html);
397     ol.startParagraph();
398     ol.startTextLink(includeName(),0);
399     ol.parseText(theTranslator->trGotoSourceCode());
400     ol.endTextLink();
401     ol.endParagraph();
402     ol.enableAll();
403   }
404 }
405
406 void FileDef::writeNamespaceDeclarations(OutputList &ol,const QCString &title)
407 {
408   // write list of namespaces
409   if (namespaceSDict) namespaceSDict->writeDeclaration(ol,title);
410 }
411
412 void FileDef::writeClassDeclarations(OutputList &ol,const QCString &title)
413 {
414   // write list of classes
415   if (classSDict) classSDict->writeDeclaration(ol,0,title,FALSE);
416 }
417
418 void FileDef::writeInlineClasses(OutputList &ol)
419 {
420   if (classSDict) classSDict->writeDocumentation(ol,this);
421 }
422
423 void FileDef::startMemberDeclarations(OutputList &ol)
424 {
425   ol.startMemberSections();
426 }
427
428 void FileDef::endMemberDeclarations(OutputList &ol)
429 {
430   ol.endMemberSections();
431 }
432
433 void FileDef::startMemberDocumentation(OutputList &ol)
434 {
435   if (Config_getBool("SEPARATE_MEMBER_PAGES"))
436   {
437     ol.disable(OutputGenerator::Html);
438     Doxygen::suppressDocWarnings = TRUE;
439   }
440 }
441
442 void FileDef::endMemberDocumentation(OutputList &ol)
443 {
444   if (Config_getBool("SEPARATE_MEMBER_PAGES"))
445   {
446     ol.enable(OutputGenerator::Html);
447     Doxygen::suppressDocWarnings = FALSE;
448   }
449 }
450
451 void FileDef::writeMemberGroups(OutputList &ol)
452 {
453   /* write user defined member groups */
454   if (memberGroupSDict)
455   {
456     memberGroupSDict->sort();
457     MemberGroupSDict::Iterator mgli(*memberGroupSDict);
458     MemberGroup *mg;
459     for (;(mg=mgli.current());++mgli)
460     {
461       if ((!mg->allMembersInSameSection() || !m_subGrouping) 
462           && mg->header()!="[NOHEADER]")
463       {
464         mg->writeDeclarations(ol,0,0,this,0);
465       }
466     }
467   }
468 }
469
470 void FileDef::writeAuthorSection(OutputList &ol)
471 {
472   // write Author section (Man only)
473   ol.pushGeneratorState();
474   ol.disableAllBut(OutputGenerator::Man);
475   ol.startGroupHeader();
476   ol.parseText(theTranslator->trAuthor(TRUE,TRUE));
477   ol.endGroupHeader();
478   ol.parseText(theTranslator->trGeneratedAutomatically(Config_getString("PROJECT_NAME")));
479   ol.popGeneratorState();
480 }
481
482 void FileDef::writeSummaryLinks(OutputList &ol)
483 {
484   ol.pushGeneratorState();
485   ol.disableAllBut(OutputGenerator::Html);
486   QListIterator<LayoutDocEntry> eli(
487       LayoutDocManager::instance().docEntries(LayoutDocManager::File));
488   LayoutDocEntry *lde;
489   bool first=TRUE;
490   SrcLangExt lang=getLanguage();
491   for (eli.toFirst();(lde=eli.current());++eli)
492   {
493     if ((lde->kind()==LayoutDocEntry::FileClasses && classSDict && classSDict->declVisible()) || 
494         (lde->kind()==LayoutDocEntry::FileNamespaces && namespaceSDict && namespaceSDict->declVisible())
495        )
496     {
497       LayoutDocEntrySection *ls = (LayoutDocEntrySection*)lde;
498       QCString label = lde->kind()==LayoutDocEntry::FileClasses ? "nested-classes" : "namespaces";
499       ol.writeSummaryLink(0,label,ls->title(lang),first);
500       first=FALSE;
501     }
502     else if (lde->kind()==LayoutDocEntry::MemberDecl)
503     {
504       LayoutDocEntryMemberDecl *lmd = (LayoutDocEntryMemberDecl*)lde;
505       MemberList * ml = getMemberList(lmd->type);
506       if (ml && ml->declVisible())
507       {
508         ol.writeSummaryLink(0,ml->listTypeAsString(),lmd->title(lang),first);
509         first=FALSE;
510       }
511     }
512   }
513   if (!first)
514   {
515     ol.writeString("  </div>\n");
516   }
517   ol.popGeneratorState();
518 }
519
520 /*! Write the documentation page for this file to the file of output
521     generators \a ol. 
522 */
523 void FileDef::writeDocumentation(OutputList &ol)
524 {
525   static bool generateTreeView = Config_getBool("GENERATE_TREEVIEW");
526   //funcList->countDecMembers();
527   
528   //QCString fn = name();
529   //if (Config_getBool("FULL_PATH_NAMES"))
530   //{
531   //  fn.prepend(stripFromPath(getPath().copy()));
532   //}
533
534   //printf("WriteDocumentation diskname=%s\n",diskname.data());
535   
536   QCString versionTitle;
537   if (!fileVersion.isEmpty())
538   {
539     versionTitle=("("+fileVersion+")");
540   }
541   QCString title = docname+versionTitle;
542   QCString pageTitle=theTranslator->trFileReference(docname);
543
544   if (getDirDef())
545   {
546     startFile(ol,getOutputFileBase(),name(),pageTitle,HLI_FileVisible,!generateTreeView);
547     if (!generateTreeView)
548     {
549       getDirDef()->writeNavigationPath(ol);
550       ol.endQuickIndices();
551     }
552     QCString pageTitleShort=theTranslator->trFileReference(name());
553     startTitle(ol,getOutputFileBase(),this);
554     ol.pushGeneratorState();
555       ol.disableAllBut(OutputGenerator::Html);
556       ol.parseText(pageTitleShort); // Html only
557       ol.enableAll();
558       ol.disable(OutputGenerator::Html);
559       ol.parseText(pageTitle); // other output formats
560     ol.popGeneratorState();
561     addGroupListToTitle(ol,this);
562     endTitle(ol,getOutputFileBase(),title);
563   }
564   else
565   {
566     startFile(ol,getOutputFileBase(),name(),pageTitle,HLI_FileVisible,!generateTreeView);
567     if (!generateTreeView)
568     {
569       ol.endQuickIndices();
570     }
571     startTitle(ol,getOutputFileBase(),this);
572     ol.parseText(pageTitle);
573     addGroupListToTitle(ol,this);
574     endTitle(ol,getOutputFileBase(),title);
575   }
576
577   ol.startContents();
578
579   if (!fileVersion.isEmpty())
580   {
581     ol.disableAllBut(OutputGenerator::Html);
582     ol.startProjectNumber();
583     ol.docify(versionTitle);
584     ol.endProjectNumber();
585     ol.enableAll();
586   }
587   
588   if (Doxygen::searchIndex)
589   {
590     Doxygen::searchIndex->setCurrentDoc(this,anchor(),FALSE);
591     Doxygen::searchIndex->addWord(localName(),TRUE);
592   }
593   
594   if (!Config_getString("GENERATE_TAGFILE").isEmpty()) 
595   {
596     Doxygen::tagFile << "  <compound kind=\"file\">" << endl;
597     Doxygen::tagFile << "    <name>" << convertToXML(name()) << "</name>" << endl;
598     Doxygen::tagFile << "    <path>" << convertToXML(getPath()) << "</path>" << endl;
599     Doxygen::tagFile << "    <filename>" 
600                      << convertToXML(getOutputFileBase()) 
601                      << "</filename>" << endl;
602   }
603
604   //---------------------------------------- start flexible part -------------------------------
605   
606   SrcLangExt lang = getLanguage();
607   QListIterator<LayoutDocEntry> eli(
608       LayoutDocManager::instance().docEntries(LayoutDocManager::File));
609   LayoutDocEntry *lde;
610   for (eli.toFirst();(lde=eli.current());++eli)
611   {
612     switch (lde->kind())
613     {
614       case LayoutDocEntry::BriefDesc: 
615         writeBriefDescription(ol);
616         break; 
617       case LayoutDocEntry::MemberDeclStart: 
618         startMemberDeclarations(ol);
619         break; 
620       case LayoutDocEntry::FileIncludes:
621         writeIncludeFiles(ol);
622         break;
623       case LayoutDocEntry::FileIncludeGraph:
624         writeIncludeGraph(ol);
625         break;
626       case LayoutDocEntry::FileIncludedByGraph:
627         writeIncludedByGraph(ol);
628         break;
629       case LayoutDocEntry::FileSourceLink:
630         writeSourceLink(ol);
631         break;
632       case LayoutDocEntry::FileClasses: 
633         {
634           LayoutDocEntrySection *ls = (LayoutDocEntrySection*)lde;
635           writeClassDeclarations(ol,ls->title(lang));
636         }
637         break; 
638       case LayoutDocEntry::FileNamespaces: 
639         {
640           LayoutDocEntrySection *ls = (LayoutDocEntrySection*)lde;
641           writeNamespaceDeclarations(ol,ls->title(lang));
642         }
643         break; 
644       case LayoutDocEntry::MemberGroups: 
645         writeMemberGroups(ol);
646         break; 
647       case LayoutDocEntry::MemberDecl: 
648         {
649           LayoutDocEntryMemberDecl *lmd = (LayoutDocEntryMemberDecl*)lde;
650           writeMemberDeclarations(ol,lmd->type,lmd->title(lang));
651         }
652         break; 
653       case LayoutDocEntry::MemberDeclEnd: 
654         endMemberDeclarations(ol);
655         break;
656       case LayoutDocEntry::DetailedDesc: 
657         {
658           LayoutDocEntrySection *ls = (LayoutDocEntrySection*)lde;
659           writeDetailedDescription(ol,ls->title(lang));
660         }
661         break;
662       case LayoutDocEntry::MemberDefStart: 
663         startMemberDocumentation(ol);
664         break; 
665       case LayoutDocEntry::FileInlineClasses:
666         writeInlineClasses(ol);
667         break;
668       case LayoutDocEntry::MemberDef: 
669         {
670           LayoutDocEntryMemberDef *lmd = (LayoutDocEntryMemberDef*)lde;
671           writeMemberDocumentation(ol,lmd->type,lmd->title(lang));
672         }
673         break;
674       case LayoutDocEntry::MemberDefEnd: 
675         endMemberDocumentation(ol);
676         break;
677       case LayoutDocEntry::AuthorSection: 
678         writeAuthorSection(ol);
679         break;
680       case LayoutDocEntry::ClassIncludes:
681       case LayoutDocEntry::ClassInheritanceGraph:
682       case LayoutDocEntry::ClassNestedClasses:
683       case LayoutDocEntry::ClassCollaborationGraph:
684       case LayoutDocEntry::ClassAllMembersLink:
685       case LayoutDocEntry::ClassUsedFiles:
686       case LayoutDocEntry::ClassInlineClasses:
687       case LayoutDocEntry::NamespaceNestedNamespaces:
688       case LayoutDocEntry::NamespaceClasses:
689       case LayoutDocEntry::NamespaceInlineClasses:
690       case LayoutDocEntry::GroupClasses: 
691       case LayoutDocEntry::GroupInlineClasses: 
692       case LayoutDocEntry::GroupNamespaces:
693       case LayoutDocEntry::GroupDirs: 
694       case LayoutDocEntry::GroupNestedGroups: 
695       case LayoutDocEntry::GroupFiles:
696       case LayoutDocEntry::GroupGraph: 
697       case LayoutDocEntry::GroupPageDocs:
698       case LayoutDocEntry::DirSubDirs:
699       case LayoutDocEntry::DirFiles:
700       case LayoutDocEntry::DirGraph:
701         err("Internal inconsistency: member %d should not be part of "
702             "LayoutDocManager::File entry list\n",lde->kind());
703         break;
704     }
705   }
706
707   //---------------------------------------- end flexible part -------------------------------
708
709   if (!Config_getString("GENERATE_TAGFILE").isEmpty()) 
710   {
711     writeDocAnchorsToTagFile();
712     Doxygen::tagFile << "  </compound>" << endl;
713   }
714
715   ol.endContents();
716
717   endFileWithNavPath(this,ol);
718
719   if (Config_getBool("SEPARATE_MEMBER_PAGES"))
720   {
721     MemberList *ml = getMemberList(MemberList::allMembersList);
722     if (ml) ml->sort();
723     writeMemberPages(ol);
724   }
725 }
726
727 void FileDef::writeMemberPages(OutputList &ol)
728 {
729   ol.pushGeneratorState();
730   ol.disableAllBut(OutputGenerator::Html);
731   
732   QListIterator<MemberList> mli(m_memberLists);
733   MemberList *ml;
734   for (mli.toFirst();(ml=mli.current());++mli)
735   {
736     if (ml->listType()&MemberList::documentationLists)
737     {
738       ml->writeDocumentationPage(ol,name(),this);
739     }
740   }
741
742   ol.popGeneratorState();
743 }
744
745 void FileDef::writeQuickMemberLinks(OutputList &ol,MemberDef *currentMd) const
746 {
747   static bool createSubDirs=Config_getBool("CREATE_SUBDIRS");
748
749   ol.writeString("      <div class=\"navtab\">\n");
750   ol.writeString("        <table>\n");
751
752   MemberList *allMemberList = getMemberList(MemberList::allMembersList);
753   if (allMemberList)
754   {
755     MemberListIterator mli(*allMemberList);
756     MemberDef *md;
757     for (mli.toFirst();(md=mli.current());++mli)
758     {
759       if (md->getFileDef()==this && md->getNamespaceDef()==0 && md->isLinkable())
760       {
761         ol.writeString("          <tr><td class=\"navtab\">");
762         if (md->isLinkableInProject())
763         {
764           if (md==currentMd) // selected item => highlight
765           {
766             ol.writeString("<a class=\"qindexHL\" ");
767           }
768           else
769           {
770             ol.writeString("<a class=\"qindex\" ");
771           }
772           ol.writeString("href=\"");
773           if (createSubDirs) ol.writeString("../../");
774           ol.writeString(md->getOutputFileBase()+Doxygen::htmlFileExtension+"#"+md->anchor());
775           ol.writeString("\">");
776           ol.writeString(convertToHtml(md->localName()));
777           ol.writeString("</a>");
778         }
779         ol.writeString("</td></tr>\n");
780       }
781     }
782   }
783
784   ol.writeString("        </table>\n");
785   ol.writeString("      </div>\n");
786 }
787
788 /*! Write a source listing of this file to the output */
789 void FileDef::writeSource(OutputList &ol)
790 {
791   static bool generateTreeView = Config_getBool("GENERATE_TREEVIEW");
792   static bool filterSourceFiles = Config_getBool("FILTER_SOURCE_FILES");
793   static bool latexSourceCode   = Config_getBool("LATEX_SOURCE_CODE");
794   QCString title = docname;
795   if (!fileVersion.isEmpty())
796   {
797     title+=(" ("+fileVersion+")");
798   }
799   QCString pageTitle = theTranslator->trSourceFile(title);
800   ol.disable(OutputGenerator::Man);
801   ol.disable(OutputGenerator::RTF);
802   if (!latexSourceCode) ol.disable(OutputGenerator::Latex);
803
804   bool isDocFile = isDocumentationFile();
805   bool genSourceFile = !isDocFile && generateSourceFile();
806   if (getDirDef())
807   {
808     startFile(ol,getSourceFileBase(),0,pageTitle,HLI_FileVisible,
809         !generateTreeView,
810         !isDocFile && genSourceFile ? 0 : getOutputFileBase());
811     if (!generateTreeView)
812     {
813       getDirDef()->writeNavigationPath(ol);
814       ol.endQuickIndices();
815     }
816     startTitle(ol,getOutputFileBase());
817     ol.parseText(name());
818     endTitle(ol,getOutputFileBase(),title);
819   }
820   else
821   {
822     startFile(ol,getSourceFileBase(),0,pageTitle,HLI_FileVisible,FALSE,
823         !isDocFile && genSourceFile ? 0 : getOutputFileBase());
824     startTitle(ol,getSourceFileBase());
825     ol.parseText(title);
826     endTitle(ol,getSourceFileBase(),0);
827   }
828
829   ol.startContents();
830
831   if (isLinkable())
832   {
833     if (latexSourceCode) ol.disable(OutputGenerator::Latex);
834     ol.startTextLink(getOutputFileBase(),0);
835     ol.parseText(theTranslator->trGotoDocumentation());
836     ol.endTextLink();
837     if (latexSourceCode) ol.enable(OutputGenerator::Latex);
838   }
839
840   ParserInterface *pIntf = Doxygen::parserManager->getParser(getDefFileExtension());
841   pIntf->resetCodeParserState();
842   ol.startCodeFragment();
843   pIntf->parseCode(ol,0,
844             fileToString(absFilePath(),filterSourceFiles,TRUE),
845             FALSE,0,this
846            );
847   ol.endCodeFragment();
848   ol.endContents();
849   endFileWithNavPath(this,ol);
850   ol.enableAll();
851 }
852
853 void FileDef::parseSource()
854 {
855   static bool filterSourceFiles = Config_getBool("FILTER_SOURCE_FILES");
856   DevNullCodeDocInterface devNullIntf;
857   ParserInterface *pIntf = Doxygen::parserManager->getParser(getDefFileExtension());
858   pIntf->resetCodeParserState();
859   pIntf->parseCode(
860             devNullIntf,0,
861             fileToString(absFilePath(),filterSourceFiles,TRUE),
862             FALSE,0,this
863            );
864 }
865
866 void FileDef::addMembersToMemberGroup()
867 {
868   QListIterator<MemberList> mli(m_memberLists);
869   MemberList *ml;
870   for (mli.toFirst();(ml=mli.current());++mli)
871   {
872     if (ml->listType()&MemberList::declarationLists)
873     {
874       ::addMembersToMemberGroup(ml,&memberGroupSDict,this);
875     }
876   }
877
878   // add members inside sections to their groups
879   if (memberGroupSDict)
880   {
881     MemberGroupSDict::Iterator mgli(*memberGroupSDict);
882     MemberGroup *mg;
883     for (;(mg=mgli.current());++mgli)
884     {
885       if (mg->allMembersInSameSection() && m_subGrouping)
886       {
887         //printf("----> addToDeclarationSection(%s)\n",mg->header().data());
888         mg->addToDeclarationSection();
889       }
890     }
891   }
892 }
893
894 /*! Adds member definition \a md to the list of all members of this file */
895 void FileDef::insertMember(MemberDef *md)
896 {
897   if (md->isHidden()) return;
898   //printf("%s:FileDef::insertMember(%s (=%p) list has %d elements)\n",
899   //    name().data(),md->name().data(),md,allMemberList.count());
900   MemberList *allMemberList = getMemberList(MemberList::allMembersList);
901   if (allMemberList && allMemberList->findRef(md)!=-1)  // TODO optimize the findRef!
902   { 
903     return;
904   }
905
906   if (allMemberList==0)
907   {
908     allMemberList = new MemberList(MemberList::allMembersList);;
909     m_memberLists.append(allMemberList);
910   }
911   allMemberList->append(md); 
912   //::addFileMemberNameToIndex(md);
913   switch (md->memberType())
914   {
915     case MemberDef::Variable:     
916     case MemberDef::Property:     
917       addMemberToList(MemberList::decVarMembers,md);
918       addMemberToList(MemberList::docVarMembers,md);
919       break;
920     case MemberDef::Function: 
921       addMemberToList(MemberList::decFuncMembers,md);
922       addMemberToList(MemberList::docFuncMembers,md);
923       break;
924     case MemberDef::Typedef:      
925       addMemberToList(MemberList::decTypedefMembers,md);
926       addMemberToList(MemberList::docTypedefMembers,md);
927       break;
928     case MemberDef::Enumeration:  
929       addMemberToList(MemberList::decEnumMembers,md);
930       addMemberToList(MemberList::docEnumMembers,md);
931       break;
932     case MemberDef::EnumValue:    // enum values are shown inside their enums
933       break;
934     case MemberDef::Define:       
935       addMemberToList(MemberList::decDefineMembers,md);
936       addMemberToList(MemberList::docDefineMembers,md);
937       break;
938     default:
939        err("FileDef::insertMembers(): "
940            "member `%s' with class scope `%s' inserted in file scope `%s'!\n",
941            md->name().data(),
942            md->getClassDef() ? md->getClassDef()->name().data() : "<global>",
943            name().data());
944   }
945   //addMemberToGroup(md,groupId);
946 }
947
948 /*! Adds compound definition \a cd to the list of all compounds of this file */
949 void FileDef::insertClass(ClassDef *cd)
950 {
951   if (cd->isHidden()) return;
952   if (classSDict==0)
953   {
954     classSDict = new ClassSDict(17);
955   }
956   if (Config_getBool("SORT_BRIEF_DOCS"))
957     classSDict->inSort(cd->name(),cd);
958   else
959     classSDict->append(cd->name(),cd);
960 }
961
962 /*! Adds namespace definition \a nd to the list of all compounds of this file */
963 void FileDef::insertNamespace(NamespaceDef *nd)
964 {
965   if (nd->isHidden()) return;
966   if (!nd->name().isEmpty() && 
967       (namespaceSDict==0 || namespaceSDict->find(nd->name())==0))
968   {
969     if (namespaceSDict==0)
970     {
971       namespaceSDict = new NamespaceSDict;
972     }
973     if (Config_getBool("SORT_BRIEF_DOCS"))
974       namespaceSDict->inSort(nd->name(),nd);
975     else
976       namespaceSDict->append(nd->name(),nd);
977   }
978 }
979
980 void FileDef::addSourceRef(int line,Definition *d,MemberDef *md)
981 {
982   //printf("FileDef::addSourceDef(%d,%p,%p)\n",line,d,md);
983   if (d)
984   {
985     if (srcDefDict==0)    srcDefDict    = new QIntDict<Definition>(257);
986     if (srcMemberDict==0) srcMemberDict = new QIntDict<MemberDef>(257);
987     srcDefDict->insert(line,d);
988     if (md) srcMemberDict->insert(line,md);
989     //printf("Adding member %s with anchor %s at line %d to file %s\n",
990     //    md?md->name().data():"<none>",md?md->anchor().data():"<none>",line,name().data());
991   }
992 }
993
994 Definition *FileDef::getSourceDefinition(int lineNr)
995 {
996   Definition *result=0;
997   if (srcDefDict)
998   {
999     result = srcDefDict->find(lineNr);
1000   }
1001   return result;
1002 }
1003
1004 MemberDef *FileDef::getSourceMember(int lineNr)
1005 {
1006   MemberDef *result=0;
1007   if (srcMemberDict)
1008   {
1009     result = srcMemberDict->find(lineNr);
1010   }
1011   return result;
1012 }
1013
1014
1015 void FileDef::addUsingDirective(NamespaceDef *nd)
1016 {
1017   if (usingDirList==0)
1018   {
1019     usingDirList = new NamespaceSDict;
1020   }
1021   if (usingDirList->find(nd->qualifiedName())==0)
1022   {
1023     usingDirList->append(nd->qualifiedName(),nd);
1024   }
1025   //printf("%p: FileDef::addUsingDirective: %s:%d\n",this,name().data(),usingDirList->count());
1026 }
1027
1028 NamespaceSDict *FileDef::getUsedNamespaces() const 
1029
1030   //printf("%p: FileDef::getUsedNamespace: %s:%d\n",this,name().data(),usingDirList?usingDirList->count():0);
1031   return usingDirList; 
1032 }
1033
1034 void FileDef::addUsingDeclaration(Definition *d)
1035 {
1036   if (usingDeclList==0)
1037   {
1038     usingDeclList = new SDict<Definition>(17);
1039   }
1040   if (usingDeclList->find(d->qualifiedName())==0)
1041   {
1042     usingDeclList->append(d->qualifiedName(),d);
1043   }
1044 }
1045
1046 void FileDef::addIncludeDependency(FileDef *fd,const char *incName,bool local,
1047                                    bool imported,bool indirect)
1048 {
1049   //printf("FileDef::addIncludeDependency(%p,%s,%d)\n",fd,incName,local);
1050   QCString iName = fd ? fd->absFilePath().data() : incName;
1051   if (!iName.isEmpty() && (!includeDict || includeDict->find(iName)==0))
1052   {
1053     if (includeDict==0)
1054     {
1055       includeDict   = new QDict<IncludeInfo>(61);
1056       includeList   = new QList<IncludeInfo>;
1057       includeList->setAutoDelete(TRUE);
1058     }
1059     IncludeInfo *ii = new IncludeInfo;
1060     ii->fileDef     = fd;
1061     ii->includeName = incName;
1062     ii->local       = local;
1063     ii->imported    = imported;
1064     ii->indirect    = indirect;
1065     includeList->append(ii);
1066     includeDict->insert(iName,ii);
1067   }
1068 }
1069
1070 void FileDef::addIncludedUsingDirectives()
1071 {
1072   if (visited) return;
1073   visited=TRUE;
1074   //printf("( FileDef::addIncludedUsingDirectives for file %s\n",name().data());
1075
1076   NamespaceList nl;
1077   if (includeList) // file contains #includes
1078   {
1079     {
1080       QListIterator<IncludeInfo> iii(*includeList);
1081       IncludeInfo *ii;
1082       for (iii.toFirst();(ii=iii.current());++iii) // foreach #include...
1083       {
1084         if (ii->fileDef && !ii->fileDef->visited) // ...that is a known file
1085         {
1086           // recurse into this file
1087           ii->fileDef->addIncludedUsingDirectives();
1088         }
1089       }
1090     }
1091     {
1092       QListIterator<IncludeInfo> iii(*includeList);
1093       IncludeInfo *ii;
1094       // iterate through list from last to first
1095       for (iii.toLast();(ii=iii.current());--iii)
1096       {
1097         if (ii->fileDef && ii->fileDef!=this)
1098         {
1099           // add using directives
1100           NamespaceSDict *unl = ii->fileDef->usingDirList;
1101           if (unl)
1102           {
1103             NamespaceSDict::Iterator nli(*unl);
1104             NamespaceDef *nd;
1105             for (nli.toLast();(nd=nli.current());--nli)
1106             {
1107               // append each using directive found in a #include file
1108               if (usingDirList==0) usingDirList = new NamespaceSDict;
1109               //printf("Prepending used namespace %s to the list of file %s\n",
1110               //    nd->name().data(),name().data());
1111               if (usingDirList->find(nd->qualifiedName())==0) // not yet added
1112               {
1113                 usingDirList->prepend(nd->qualifiedName(),nd);
1114               }
1115             }
1116           }
1117           // add using declarations
1118           SDict<Definition> *udl = ii->fileDef->usingDeclList;
1119           if (udl)
1120           {
1121             SDict<Definition>::Iterator udi(*udl);
1122             Definition *d;
1123             for (udi.toLast();(d=udi.current());--udi)
1124             {
1125               //printf("Adding using declaration %s\n",d->name().data());
1126               if (usingDeclList==0)
1127               {
1128                 usingDeclList = new SDict<Definition>(17);
1129               }
1130               if (usingDeclList->find(d->qualifiedName())==0)
1131               {
1132                 usingDeclList->prepend(d->qualifiedName(),d);
1133               }
1134             }
1135           }
1136         }
1137       }
1138     }
1139   }
1140   //printf(") end FileDef::addIncludedUsingDirectives for file %s\n",name().data());
1141 }
1142
1143
1144 void FileDef::addIncludedByDependency(FileDef *fd,const char *incName,
1145                                       bool local,bool imported)
1146 {
1147   //printf("FileDef::addIncludedByDependency(%p,%s,%d)\n",fd,incName,local);
1148   QCString iName = fd ? fd->absFilePath().data() : incName;
1149   if (!iName.isEmpty() && (includedByDict==0 || includedByDict->find(iName)==0))
1150   {
1151     if (includedByDict==0)
1152     {
1153       includedByDict = new QDict<IncludeInfo>(61);
1154       includedByList = new QList<IncludeInfo>;
1155       includedByList->setAutoDelete(TRUE);
1156     }
1157     IncludeInfo *ii = new IncludeInfo;
1158     ii->fileDef     = fd;
1159     ii->includeName = incName;
1160     ii->local       = local;
1161     ii->imported    = imported;
1162     ii->indirect    = FALSE;
1163     includedByList->append(ii);
1164     includedByDict->insert(iName,ii);
1165   }
1166 }
1167
1168 bool FileDef::isIncluded(const QCString &name) const
1169 {
1170   if (name.isEmpty()) return FALSE;
1171   return includeDict!=0 && includeDict->find(name)!=0;
1172 }
1173
1174 bool FileDef::generateSourceFile() const 
1175
1176   QCString extension = name().right(4);
1177   return !isReference() && 
1178          (Config_getBool("SOURCE_BROWSER") || 
1179            (Config_getBool("VERBATIM_HEADERS") && guessSection(name())==Entry::HEADER_SEC) 
1180          ) &&
1181          extension!=".doc" && extension!=".txt" && extension!=".dox" &&
1182          extension!=".md" && extension!=".markdown";  
1183 }
1184
1185
1186 void FileDef::addListReferences()
1187 {
1188   {
1189     LockingPtr< QList<ListItemInfo> > xrefItems = xrefListItems();
1190     addRefItem(xrefItems.pointer(),
1191                getOutputFileBase(),
1192                theTranslator->trFile(TRUE,TRUE),
1193                getOutputFileBase(),name(),
1194                0
1195               );
1196   }
1197   if (memberGroupSDict)
1198   {
1199     MemberGroupSDict::Iterator mgli(*memberGroupSDict);
1200     MemberGroup *mg;
1201     for (;(mg=mgli.current());++mgli)
1202     {
1203       mg->addListReferences(this);
1204     }
1205   }
1206   QListIterator<MemberList> mli(m_memberLists);
1207   MemberList *ml;
1208   for (mli.toFirst();(ml=mli.current());++mli)
1209   {
1210     if (ml->listType()&MemberList::documentationLists)
1211     {
1212       ml->addListReferences(this);
1213     }
1214   }
1215 }
1216
1217 //-------------------------------------------------------------------
1218
1219 static int findMatchingPart(const QCString &path,const QCString dir)
1220 {
1221   int si1;
1222   int pos1=0,pos2=0;
1223   while ((si1=path.find('/',pos1))!=-1)
1224   {
1225     int si2=dir.find('/',pos2);
1226     //printf("  found slash at pos %d in path %d: %s<->%s\n",si1,si2,
1227     //    path.mid(pos1,si1-pos2).data(),dir.mid(pos2).data());
1228     if (si2==-1 && path.mid(pos1,si1-pos2)==dir.mid(pos2)) // match at end
1229     {
1230       return dir.length();
1231     }
1232     if (si1!=si2 || path.mid(pos1,si1-pos2)!=dir.mid(pos2,si2-pos2)) // no match in middle
1233     {
1234       return QMAX(pos1-1,0);
1235     }
1236     pos1=si1+1;
1237     pos2=si2+1;
1238   }
1239   return 0;
1240 }
1241
1242 static Directory *findDirNode(Directory *root,const QCString &name)
1243 {
1244   QListIterator<DirEntry> dli(root->children());
1245   DirEntry *de;
1246   for (dli.toFirst();(de=dli.current());++dli)
1247   {
1248     if (de->kind()==DirEntry::Dir)
1249     {
1250       Directory *dir = (Directory *)de;
1251       QCString dirName=dir->name();
1252       int sp=findMatchingPart(name,dirName);
1253       //printf("findMatchingPart(%s,%s)=%d\n",name.data(),dirName.data(),sp);
1254       if (sp>0) // match found
1255       {
1256         if ((uint)sp==dirName.length()) // whole directory matches
1257         {
1258           // recurse into the directory
1259           return findDirNode(dir,name.mid(dirName.length()+1));
1260         } 
1261         else // partial match => we need to split the path into three parts
1262         {
1263           QCString baseName     =dirName.left(sp);
1264           QCString oldBranchName=dirName.mid(sp+1);
1265           QCString newBranchName=name.mid(sp+1);
1266           // strip file name from path
1267           int newIndex=newBranchName.findRev('/');
1268           if (newIndex>0) newBranchName=newBranchName.left(newIndex);
1269
1270           //printf("Splitting off part in new branch \n"
1271           //    "base=%s old=%s new=%s\n",
1272           //    baseName.data(),
1273           //    oldBranchName.data(),
1274           //    newBranchName.data()
1275           //      );
1276           Directory *base = new Directory(root,baseName);
1277           Directory *newBranch = new Directory(base,newBranchName);
1278           dir->reParent(base);
1279           dir->rename(oldBranchName);
1280           base->addChild(dir);
1281           base->addChild(newBranch);
1282           dir->setLast(FALSE);
1283           // remove DirEntry container from list (without deleting it)
1284           root->children().setAutoDelete(FALSE);
1285           root->children().removeRef(dir);
1286           root->children().setAutoDelete(TRUE);
1287           // add new branch to the root
1288           if (!root->children().isEmpty())
1289           {
1290             root->children().last()->setLast(FALSE); 
1291           }
1292           root->addChild(base);
1293           return newBranch;
1294         }
1295       }
1296     }
1297   }
1298   int si=name.findRev('/');
1299   if (si==-1) // no subdir
1300   {
1301     return root; // put the file under the root node.
1302   }
1303   else // need to create a subdir 
1304   {
1305     QCString baseName = name.left(si);
1306     //printf("new subdir %s\n",baseName.data());
1307     Directory *newBranch = new Directory(root,baseName);
1308     if (!root->children().isEmpty())
1309     {
1310       root->children().last()->setLast(FALSE); 
1311     }
1312     root->addChild(newBranch);
1313     return newBranch;
1314   }
1315 }
1316
1317 static void mergeFileDef(Directory *root,FileDef *fd)
1318 {
1319   QCString rootPath = root->name();
1320   QCString filePath = fd->absFilePath();
1321   //printf("merging %s\n",filePath.data());
1322   Directory *dirNode = findDirNode(root,filePath);
1323   if (!dirNode->children().isEmpty())
1324   {
1325     dirNode->children().last()->setLast(FALSE); 
1326   }
1327   DirEntry *e=new DirEntry(dirNode,fd);
1328   dirNode->addChild(e);
1329 }
1330
1331 #if 0
1332 static void generateIndent(QTextStream &t,DirEntry *de,int level)
1333 {
1334   if (de->parent())
1335   {
1336     generateIndent(t,de->parent(),level+1);
1337   }
1338   // from the root up to node n do...
1339   if (level==0) // item before a dir or document
1340   {
1341     if (de->isLast())
1342     {
1343       if (de->kind()==DirEntry::Dir)
1344       {
1345         t << "<img " << FTV_IMGATTRIBS(plastnode) << "/>";
1346       }
1347       else
1348       {
1349         t << "<img " << FTV_IMGATTRIBS(lastnode) << "/>";
1350       }
1351     }
1352     else
1353     {
1354       if (de->kind()==DirEntry::Dir)
1355       {
1356         t << "<img " << FTV_IMGATTRIBS(pnode) << "/>";
1357       }
1358       else
1359       {
1360         t << "<img " << FTV_IMGATTRIBS(node) << "/>";
1361       }
1362     }
1363   }
1364   else // item at another level
1365   {
1366     if (de->isLast())
1367     {
1368       t << "<img " << FTV_IMGATTRIBS(blank) << "/>";
1369     }
1370     else
1371     {
1372       t << "<img " << FTV_IMGATTRIBS(vertline) << "/>";
1373     }
1374   }
1375 }
1376
1377 static void writeDirTreeNode(QTextStream &t,Directory *root,int level)
1378 {
1379   QCString indent;
1380   indent.fill(' ',level*2);
1381   QListIterator<DirEntry> dli(root->children());
1382   DirEntry *de;
1383   for (dli.toFirst();(de=dli.current());++dli)
1384   {
1385     t << indent << "<p>";
1386     generateIndent(t,de,0);
1387     if (de->kind()==DirEntry::Dir)
1388     {
1389       Directory *dir=(Directory *)de;
1390       //printf("%s [dir]: %s (last=%d,dir=%d)\n",indent.data(),dir->name().data(),dir->isLast(),dir->kind()==DirEntry::Dir);
1391       t << "<img " << FTV_IMGATTRIBS(folderclosed) << "/>";
1392       t << dir->name();
1393       t << "</p>\n";
1394       t << indent << "<div>\n";
1395       writeDirTreeNode(t,dir,level+1);
1396       t << indent << "</div>\n";
1397     }
1398     else
1399     {
1400       //printf("%s [file]: %s (last=%d,dir=%d)\n",indent.data(),de->file()->name().data(),de->isLast(),de->kind()==DirEntry::Dir);
1401       t << "<img " << FTV_IMGATTRIBS(doc) << "/>";
1402       t << de->file()->name();
1403       t << "</p>\n";
1404     }
1405   }
1406 }
1407 #endif
1408
1409 static void addDirsAsGroups(Directory *root,GroupDef *parent,int level)
1410 {
1411   GroupDef *gd=0;
1412   if (root->kind()==DirEntry::Dir)
1413   {
1414     gd = new GroupDef("[generated]",
1415                       1,
1416                       root->path(), // name
1417                       root->name()  // title
1418                      );
1419     if (parent) 
1420     {
1421       parent->addGroup(gd);
1422       gd->makePartOfGroup(parent);
1423     }
1424     else
1425     {
1426       Doxygen::groupSDict->append(root->path(),gd);
1427     }
1428   }
1429   QListIterator<DirEntry> dli(root->children());
1430   DirEntry *de;
1431   for (dli.toFirst();(de=dli.current());++dli)
1432   {
1433     if (de->kind()==DirEntry::Dir)
1434     {
1435       addDirsAsGroups((Directory *)de,gd,level+1);
1436     }
1437   }
1438 }
1439
1440 void generateFileTree()
1441 {
1442   Directory *root=new Directory(0,"root");
1443   root->setLast(TRUE);
1444   FileNameListIterator fnli(*Doxygen::inputNameList); 
1445   FileName *fn;
1446   for (fnli.toFirst();(fn=fnli.current());++fnli)
1447   {
1448     FileNameIterator fni(*fn);
1449     FileDef *fd;
1450     for (;(fd=fni.current());++fni)
1451     {
1452       mergeFileDef(root,fd);
1453     }
1454   }
1455   //t << "<div class=\"directory\">\n";
1456   //writeDirTreeNode(t,root,0);
1457   //t << "</div>\n";
1458   addDirsAsGroups(root,0,0);
1459   delete root;
1460 }
1461
1462 //-------------------------------------------------------------------
1463
1464 void FileDef::combineUsingRelations()
1465 {
1466   if (visited) return; // already done
1467   visited=TRUE;
1468   if (usingDirList)
1469   {
1470     NamespaceSDict::Iterator nli(*usingDirList);
1471     NamespaceDef *nd;
1472     for (nli.toFirst();(nd=nli.current());++nli)
1473     {
1474       nd->combineUsingRelations();
1475     }
1476     for (nli.toFirst();(nd=nli.current());++nli)
1477     {
1478       // add used namespaces of namespace nd to this namespace
1479       if (nd->getUsedNamespaces())
1480       {
1481         NamespaceSDict::Iterator unli(*nd->getUsedNamespaces());
1482         NamespaceDef *und;
1483         for (unli.toFirst();(und=unli.current());++unli)
1484         {
1485           //printf("Adding namespace %s to the using list of %s\n",und->qualifiedName().data(),qualifiedName().data());
1486           addUsingDirective(und);
1487         }
1488       }
1489       // add used classes of namespace nd to this namespace
1490       if (nd->getUsedClasses())
1491       {
1492         SDict<Definition>::Iterator cli(*nd->getUsedClasses());
1493         Definition *ucd;
1494         for (cli.toFirst();(ucd=cli.current());++cli)
1495         {
1496           //printf("Adding class %s to the using list of %s\n",cd->qualifiedName().data(),qualifiedName().data());
1497           addUsingDeclaration(ucd);
1498         }
1499       }
1500     }
1501   }
1502 }
1503
1504 bool FileDef::isDocumentationFile() const
1505 {
1506   return name().right(4)==".doc" ||
1507          name().right(4)==".txt" ||
1508          name().right(4)==".dox" ||
1509          name().right(3)==".md"  ||
1510          name().right(9)==".markdown";
1511 }
1512
1513 void FileDef::acquireFileVersion()
1514 {
1515   QCString vercmd = Config_getString("FILE_VERSION_FILTER");
1516   if (!vercmd.isEmpty() && !filepath.isEmpty() && filepath!="generated") 
1517   {
1518     msg("Version of %s : ",filepath.data());
1519     QCString cmd = vercmd+" \""+filepath+"\"";
1520     Debug::print(Debug::ExtCmd,0,"Executing popen(`%s`)\n",cmd.data());
1521     FILE *f=portable_popen(cmd,"r");
1522     if (!f)
1523     {
1524       err("error: could not execute %s\n",vercmd.data());
1525       return;
1526     }
1527     const int bufSize=1024;
1528     char buf[bufSize];
1529     int numRead = fread(buf,1,bufSize,f);
1530     portable_pclose(f);
1531     if (numRead>0 && !(fileVersion=QCString(buf,numRead).stripWhiteSpace()).isEmpty())
1532     {
1533       msg("%s\n",fileVersion.data());
1534     }
1535     else 
1536     {
1537       msg("no version available\n");
1538     }
1539   }
1540 }
1541
1542
1543 QCString FileDef::getSourceFileBase() const
1544
1545   if (Htags::useHtags)
1546   {
1547     return Htags::path2URL(filepath);
1548   }
1549   else
1550   {
1551     return convertNameToFile(diskname)+"_source"; 
1552   }
1553 }
1554
1555 /*! Returns the name of the verbatim copy of this file (if any). */
1556 QCString FileDef::includeName() const 
1557
1558   if (Htags::useHtags)
1559   {
1560     return Htags::path2URL(filepath);
1561   }
1562   else
1563   {
1564     return convertNameToFile(diskname)+"_source"; 
1565   }
1566 }
1567
1568 MemberList *FileDef::createMemberList(MemberList::ListType lt)
1569 {
1570   m_memberLists.setAutoDelete(TRUE);
1571   QListIterator<MemberList> mli(m_memberLists);
1572   MemberList *ml;
1573   for (mli.toFirst();(ml=mli.current());++mli)
1574   {
1575     if (ml->listType()==lt)
1576     {
1577       return ml;
1578     }
1579   }
1580   // not found, create a new member list
1581   ml = new MemberList(lt);
1582   m_memberLists.append(ml);
1583   return ml;
1584 }
1585
1586 void FileDef::addMemberToList(MemberList::ListType lt,MemberDef *md)
1587 {
1588   static bool sortBriefDocs = Config_getBool("SORT_BRIEF_DOCS");
1589   static bool sortMemberDocs = Config_getBool("SORT_MEMBER_DOCS");
1590   MemberList *ml = createMemberList(lt);
1591   ml->setNeedsSorting(
1592        ((ml->listType()&MemberList::declarationLists) && sortBriefDocs) ||
1593        ((ml->listType()&MemberList::documentationLists) && sortMemberDocs));
1594   ml->append(md);
1595 #if 0
1596   if (ml->needsSorting())
1597     ml->inSort(md);
1598   else
1599     ml->append(md);
1600 #endif
1601   if (lt&MemberList::documentationLists)
1602   {
1603     ml->setInFile(TRUE);
1604   }
1605   if (ml->listType()&MemberList::declarationLists) md->setSectionList(this,ml);
1606 }
1607
1608 void FileDef::sortMemberLists()
1609 {
1610   MemberList *ml = m_memberLists.first();
1611   while (ml)
1612   {
1613     if (ml->needsSorting()) { ml->sort(); ml->setNeedsSorting(FALSE); }
1614     ml = m_memberLists.next();
1615   }
1616 }
1617
1618 MemberList *FileDef::getMemberList(MemberList::ListType lt) const
1619 {
1620   FileDef *that = (FileDef*)this;
1621   MemberList *ml = that->m_memberLists.first();
1622   while (ml)
1623   {
1624     if (ml->listType()==lt)
1625     {
1626       return ml;
1627     }
1628     ml = that->m_memberLists.next();
1629   }
1630   return 0;
1631 }
1632
1633 void FileDef::writeMemberDeclarations(OutputList &ol,MemberList::ListType lt,const QCString &title)
1634 {
1635   static bool optVhdl = Config_getBool("OPTIMIZE_OUTPUT_VHDL");
1636   MemberList * ml = getMemberList(lt);
1637   if (ml) 
1638   {
1639     if (optVhdl) // use specific declarations function
1640     {
1641
1642       VhdlDocGen::writeVhdlDeclarations(ml,ol,0,0,this,0);
1643     }
1644     else
1645     {
1646       ml->writeDeclarations(ol,0,0,this,0,title,0);
1647     }
1648   }
1649 }
1650
1651 void FileDef::writeMemberDocumentation(OutputList &ol,MemberList::ListType lt,const QCString &title)
1652 {
1653   MemberList * ml = getMemberList(lt);
1654   if (ml) ml->writeDocumentation(ol,name(),this,title);
1655 }
1656
1657 bool FileDef::isLinkableInProject() const
1658 {
1659   static bool showFiles = Config_getBool("SHOW_FILES");
1660   return hasDocumentation() && !isReference() && showFiles;
1661 }
1662
1663 #if 0
1664 bool FileDef::includes(FileDef *incFile,QDict<FileDef> *includedFiles) const
1665 {
1666   //printf("%s::includes(%s)\n",name().data(),incFile->name().data());
1667   if (incFile==this) return TRUE;
1668   includedFiles->insert(absFilePath(),this);
1669   if (includeList)
1670   {
1671     QListIterator<IncludeInfo> ili(*includeList);
1672     IncludeInfo *ii;
1673     for (;(ii=ili.current());++ili)
1674     {
1675       //printf("ii=%s\n",ii->includeName.data());
1676       if ((ii->fileDef && 
1677            includedFiles->find(ii->fileDef->absFilePath())==0 &&
1678            ii->fileDef->includes(incFile,includedFiles)
1679           ) ||
1680           incFile->absFilePath()==ii->includeName
1681          ) return TRUE;
1682     }
1683   }
1684   return FALSE;
1685 }
1686
1687 bool FileDef::includesByName(const QCString &fileName) const
1688 {
1689   if (includeList)
1690   {
1691     QListIterator<IncludeInfo> ili(*includeList);
1692     IncludeInfo *ii;
1693     for (;(ii=ili.current());++ili)
1694     {
1695       //printf("ii=%s\n",ii->includeName.data());
1696       if (fileName==ii->includeName) return TRUE;
1697     }
1698   }
1699   return FALSE;
1700 }
1701 #endif