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