Imported Upstream version 1.8.8
[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   // temporarily undo the disbling could be done by startMemberDocumentation()
436   // as a result of setting SEPARATE_MEMBER_PAGES to YES; see bug730512
437   bool isEnabled = ol.isEnabled(OutputGenerator::Html);
438   ol.enable(OutputGenerator::Html);
439
440   if (m_classSDict) m_classSDict->writeDocumentation(ol,this);
441
442   // restore the initial state if needed
443   if (!isEnabled) ol.disable(OutputGenerator::Html);
444 }
445
446 void FileDef::startMemberDeclarations(OutputList &ol)
447 {
448   ol.startMemberSections();
449 }
450
451 void FileDef::endMemberDeclarations(OutputList &ol)
452 {
453   ol.endMemberSections();
454 }
455
456 void FileDef::startMemberDocumentation(OutputList &ol)
457 {
458   if (Config_getBool("SEPARATE_MEMBER_PAGES"))
459   {
460     ol.disable(OutputGenerator::Html);
461     Doxygen::suppressDocWarnings = TRUE;
462   }
463 }
464
465 void FileDef::endMemberDocumentation(OutputList &ol)
466 {
467   if (Config_getBool("SEPARATE_MEMBER_PAGES"))
468   {
469     ol.enable(OutputGenerator::Html);
470     Doxygen::suppressDocWarnings = FALSE;
471   }
472 }
473
474 void FileDef::writeMemberGroups(OutputList &ol)
475 {
476   /* write user defined member groups */
477   if (m_memberGroupSDict)
478   {
479     m_memberGroupSDict->sort();
480     MemberGroupSDict::Iterator mgli(*m_memberGroupSDict);
481     MemberGroup *mg;
482     for (;(mg=mgli.current());++mgli)
483     {
484       if ((!mg->allMembersInSameSection() || !m_subGrouping) 
485           && mg->header()!="[NOHEADER]")
486       {
487         mg->writeDeclarations(ol,0,0,this,0);
488       }
489     }
490   }
491 }
492
493 void FileDef::writeAuthorSection(OutputList &ol)
494 {
495   // write Author section (Man only)
496   ol.pushGeneratorState();
497   ol.disableAllBut(OutputGenerator::Man);
498   ol.startGroupHeader();
499   ol.parseText(theTranslator->trAuthor(TRUE,TRUE));
500   ol.endGroupHeader();
501   ol.parseText(theTranslator->trGeneratedAutomatically(Config_getString("PROJECT_NAME")));
502   ol.popGeneratorState();
503 }
504
505 void FileDef::writeSummaryLinks(OutputList &ol)
506 {
507   ol.pushGeneratorState();
508   ol.disableAllBut(OutputGenerator::Html);
509   QListIterator<LayoutDocEntry> eli(
510       LayoutDocManager::instance().docEntries(LayoutDocManager::File));
511   LayoutDocEntry *lde;
512   bool first=TRUE;
513   SrcLangExt lang=getLanguage();
514   for (eli.toFirst();(lde=eli.current());++eli)
515   {
516     if ((lde->kind()==LayoutDocEntry::FileClasses && 
517          m_classSDict && m_classSDict->declVisible()) || 
518         (lde->kind()==LayoutDocEntry::FileNamespaces && 
519          m_namespaceSDict && m_namespaceSDict->declVisible())
520        )
521     {
522       LayoutDocEntrySection *ls = (LayoutDocEntrySection*)lde;
523       QCString label = lde->kind()==LayoutDocEntry::FileClasses ? "nested-classes" : "namespaces";
524       ol.writeSummaryLink(0,label,ls->title(lang),first);
525       first=FALSE;
526     }
527     else if (lde->kind()==LayoutDocEntry::MemberDecl)
528     {
529       LayoutDocEntryMemberDecl *lmd = (LayoutDocEntryMemberDecl*)lde;
530       MemberList * ml = getMemberList(lmd->type);
531       if (ml && ml->declVisible())
532       {
533         ol.writeSummaryLink(0,MemberList::listTypeAsString(ml->listType()),lmd->title(lang),first);
534         first=FALSE;
535       }
536     }
537   }
538   if (!first)
539   {
540     ol.writeString("  </div>\n");
541   }
542   ol.popGeneratorState();
543 }
544
545 /*! Write the documentation page for this file to the file of output
546     generators \a ol. 
547 */
548 void FileDef::writeDocumentation(OutputList &ol)
549 {
550   static bool generateTreeView = Config_getBool("GENERATE_TREEVIEW");
551   //funcList->countDecMembers();
552   
553   //QCString fn = name();
554   //if (Config_getBool("FULL_PATH_NAMES"))
555   //{
556   //  fn.prepend(stripFromPath(getPath().copy()));
557   //}
558
559   //printf("WriteDocumentation diskname=%s\n",diskname.data());
560   
561   QCString versionTitle;
562   if (!m_fileVersion.isEmpty())
563   {
564     versionTitle=("("+m_fileVersion+")");
565   }
566   QCString title = m_docname+versionTitle;
567   QCString pageTitle=theTranslator->trFileReference(m_docname);
568
569   if (getDirDef())
570   {
571     startFile(ol,getOutputFileBase(),name(),pageTitle,HLI_FileVisible,!generateTreeView);
572     if (!generateTreeView)
573     {
574       getDirDef()->writeNavigationPath(ol);
575       ol.endQuickIndices();
576     }
577     QCString pageTitleShort=theTranslator->trFileReference(name());
578     startTitle(ol,getOutputFileBase(),this);
579     ol.pushGeneratorState();
580       ol.disableAllBut(OutputGenerator::Html);
581       ol.parseText(pageTitleShort); // Html only
582       ol.enableAll();
583       ol.disable(OutputGenerator::Html);
584       ol.parseText(pageTitle); // other output formats
585     ol.popGeneratorState();
586     addGroupListToTitle(ol,this);
587     endTitle(ol,getOutputFileBase(),title);
588   }
589   else
590   {
591     startFile(ol,getOutputFileBase(),name(),pageTitle,HLI_FileVisible,!generateTreeView);
592     if (!generateTreeView)
593     {
594       ol.endQuickIndices();
595     }
596     startTitle(ol,getOutputFileBase(),this);
597     ol.parseText(pageTitle);
598     addGroupListToTitle(ol,this);
599     endTitle(ol,getOutputFileBase(),title);
600   }
601
602   ol.startContents();
603
604   if (!m_fileVersion.isEmpty())
605   {
606     ol.disableAllBut(OutputGenerator::Html);
607     ol.startProjectNumber();
608     ol.docify(versionTitle);
609     ol.endProjectNumber();
610     ol.enableAll();
611   }
612   
613   if (Doxygen::searchIndex)
614   {
615     Doxygen::searchIndex->setCurrentDoc(this,anchor(),FALSE);
616     Doxygen::searchIndex->addWord(localName(),TRUE);
617   }
618   
619   if (!Config_getString("GENERATE_TAGFILE").isEmpty()) 
620   {
621     Doxygen::tagFile << "  <compound kind=\"file\">" << endl;
622     Doxygen::tagFile << "    <name>" << convertToXML(name()) << "</name>" << endl;
623     Doxygen::tagFile << "    <path>" << convertToXML(getPath()) << "</path>" << endl;
624     Doxygen::tagFile << "    <filename>" 
625                      << convertToXML(getOutputFileBase()) 
626                      << "</filename>" << endl;
627   }
628
629   //---------------------------------------- start flexible part -------------------------------
630   
631   SrcLangExt lang = getLanguage();
632   QListIterator<LayoutDocEntry> eli(
633       LayoutDocManager::instance().docEntries(LayoutDocManager::File));
634   LayoutDocEntry *lde;
635   for (eli.toFirst();(lde=eli.current());++eli)
636   {
637     switch (lde->kind())
638     {
639       case LayoutDocEntry::BriefDesc: 
640         writeBriefDescription(ol);
641         break; 
642       case LayoutDocEntry::MemberDeclStart: 
643         startMemberDeclarations(ol);
644         break; 
645       case LayoutDocEntry::FileIncludes:
646         writeIncludeFiles(ol);
647         break;
648       case LayoutDocEntry::FileIncludeGraph:
649         writeIncludeGraph(ol);
650         break;
651       case LayoutDocEntry::FileIncludedByGraph:
652         writeIncludedByGraph(ol);
653         break;
654       case LayoutDocEntry::FileSourceLink:
655         writeSourceLink(ol);
656         break;
657       case LayoutDocEntry::FileClasses: 
658         {
659           LayoutDocEntrySection *ls = (LayoutDocEntrySection*)lde;
660           writeClassDeclarations(ol,ls->title(lang));
661         }
662         break; 
663       case LayoutDocEntry::FileNamespaces: 
664         {
665           LayoutDocEntrySection *ls = (LayoutDocEntrySection*)lde;
666           writeNamespaceDeclarations(ol,ls->title(lang),false);
667         }
668         break; 
669       case LayoutDocEntry::FileConstantGroups:
670         {
671           LayoutDocEntrySection *ls = (LayoutDocEntrySection*)lde;
672           writeNamespaceDeclarations(ol,ls->title(lang),true);
673         }
674         break;
675       case LayoutDocEntry::MemberGroups: 
676         writeMemberGroups(ol);
677         break; 
678       case LayoutDocEntry::MemberDecl: 
679         {
680           LayoutDocEntryMemberDecl *lmd = (LayoutDocEntryMemberDecl*)lde;
681           writeMemberDeclarations(ol,lmd->type,lmd->title(lang));
682         }
683         break; 
684       case LayoutDocEntry::MemberDeclEnd: 
685         endMemberDeclarations(ol);
686         break;
687       case LayoutDocEntry::DetailedDesc: 
688         {
689           LayoutDocEntrySection *ls = (LayoutDocEntrySection*)lde;
690           writeDetailedDescription(ol,ls->title(lang));
691         }
692         break;
693       case LayoutDocEntry::MemberDefStart: 
694         startMemberDocumentation(ol);
695         break; 
696       case LayoutDocEntry::FileInlineClasses:
697         writeInlineClasses(ol);
698         break;
699       case LayoutDocEntry::MemberDef: 
700         {
701           LayoutDocEntryMemberDef *lmd = (LayoutDocEntryMemberDef*)lde;
702           writeMemberDocumentation(ol,lmd->type,lmd->title(lang));
703         }
704         break;
705       case LayoutDocEntry::MemberDefEnd: 
706         endMemberDocumentation(ol);
707         break;
708       case LayoutDocEntry::AuthorSection: 
709         writeAuthorSection(ol);
710         break;
711       case LayoutDocEntry::ClassIncludes:
712       case LayoutDocEntry::ClassInheritanceGraph:
713       case LayoutDocEntry::ClassNestedClasses:
714       case LayoutDocEntry::ClassCollaborationGraph:
715       case LayoutDocEntry::ClassAllMembersLink:
716       case LayoutDocEntry::ClassUsedFiles:
717       case LayoutDocEntry::ClassInlineClasses:
718       case LayoutDocEntry::NamespaceNestedNamespaces:
719       case LayoutDocEntry::NamespaceNestedConstantGroups:
720       case LayoutDocEntry::NamespaceClasses:
721       case LayoutDocEntry::NamespaceInlineClasses:
722       case LayoutDocEntry::GroupClasses: 
723       case LayoutDocEntry::GroupInlineClasses: 
724       case LayoutDocEntry::GroupNamespaces:
725       case LayoutDocEntry::GroupDirs: 
726       case LayoutDocEntry::GroupNestedGroups: 
727       case LayoutDocEntry::GroupFiles:
728       case LayoutDocEntry::GroupGraph: 
729       case LayoutDocEntry::GroupPageDocs:
730       case LayoutDocEntry::DirSubDirs:
731       case LayoutDocEntry::DirFiles:
732       case LayoutDocEntry::DirGraph:
733         err("Internal inconsistency: member %d should not be part of "
734             "LayoutDocManager::File entry list\n",lde->kind());
735         break;
736     }
737   }
738
739   //---------------------------------------- end flexible part -------------------------------
740
741   if (!Config_getString("GENERATE_TAGFILE").isEmpty()) 
742   {
743     writeDocAnchorsToTagFile();
744     Doxygen::tagFile << "  </compound>" << endl;
745   }
746
747   ol.endContents();
748
749   endFileWithNavPath(this,ol);
750
751   if (Config_getBool("SEPARATE_MEMBER_PAGES"))
752   {
753     MemberList *ml = getMemberList(MemberListType_allMembersList);
754     if (ml) ml->sort();
755     writeMemberPages(ol);
756   }
757 }
758
759 void FileDef::writeMemberPages(OutputList &ol)
760 {
761   ol.pushGeneratorState();
762   ol.disableAllBut(OutputGenerator::Html);
763   
764   QListIterator<MemberList> mli(m_memberLists);
765   MemberList *ml;
766   for (mli.toFirst();(ml=mli.current());++mli)
767   {
768     if (ml->listType()&MemberListType_documentationLists)
769     {
770       ml->writeDocumentationPage(ol,name(),this);
771     }
772   }
773
774   ol.popGeneratorState();
775 }
776
777 void FileDef::writeQuickMemberLinks(OutputList &ol,MemberDef *currentMd) const
778 {
779   static bool createSubDirs=Config_getBool("CREATE_SUBDIRS");
780
781   ol.writeString("      <div class=\"navtab\">\n");
782   ol.writeString("        <table>\n");
783
784   MemberList *allMemberList = getMemberList(MemberListType_allMembersList);
785   if (allMemberList)
786   {
787     MemberListIterator mli(*allMemberList);
788     MemberDef *md;
789     for (mli.toFirst();(md=mli.current());++mli)
790     {
791       if (md->getFileDef()==this && md->getNamespaceDef()==0 && md->isLinkable() && !md->isEnumValue())
792       {
793         ol.writeString("          <tr><td class=\"navtab\">");
794         if (md->isLinkableInProject())
795         {
796           if (md==currentMd) // selected item => highlight
797           {
798             ol.writeString("<a class=\"qindexHL\" ");
799           }
800           else
801           {
802             ol.writeString("<a class=\"qindex\" ");
803           }
804           ol.writeString("href=\"");
805           if (createSubDirs) ol.writeString("../../");
806           ol.writeString(md->getOutputFileBase()+Doxygen::htmlFileExtension+"#"+md->anchor());
807           ol.writeString("\">");
808           ol.writeString(convertToHtml(md->localName()));
809           ol.writeString("</a>");
810         }
811         ol.writeString("</td></tr>\n");
812       }
813     }
814   }
815
816   ol.writeString("        </table>\n");
817   ol.writeString("      </div>\n");
818 }
819
820 /*! Write a source listing of this file to the output */
821 void FileDef::writeSource(OutputList &ol,bool sameTu,QStrList &filesInSameTu)
822 {
823   static bool generateTreeView  = Config_getBool("GENERATE_TREEVIEW");
824   static bool filterSourceFiles = Config_getBool("FILTER_SOURCE_FILES");
825   static bool latexSourceCode   = Config_getBool("LATEX_SOURCE_CODE");
826   DevNullCodeDocInterface devNullIntf;
827   QCString title = m_docname;
828   if (!m_fileVersion.isEmpty())
829   {
830     title+=(" ("+m_fileVersion+")");
831   }
832   QCString pageTitle = theTranslator->trSourceFile(title);
833   ol.disable(OutputGenerator::Man);
834   ol.disable(OutputGenerator::RTF);
835   if (!latexSourceCode) ol.disable(OutputGenerator::Latex);
836
837   bool isDocFile = isDocumentationFile();
838   bool genSourceFile = !isDocFile && generateSourceFile();
839   if (getDirDef())
840   {
841     startFile(ol,getSourceFileBase(),0,pageTitle,HLI_FileVisible,
842         !generateTreeView,
843         !isDocFile && genSourceFile ? QCString() : getOutputFileBase());
844     if (!generateTreeView)
845     {
846       getDirDef()->writeNavigationPath(ol);
847       ol.endQuickIndices();
848     }
849     startTitle(ol,getSourceFileBase());
850     ol.parseText(name());
851     endTitle(ol,getSourceFileBase(),title);
852   }
853   else
854   {
855     startFile(ol,getSourceFileBase(),0,pageTitle,HLI_FileVisible,FALSE,
856         !isDocFile && genSourceFile ? QCString() : getOutputFileBase());
857     startTitle(ol,getSourceFileBase());
858     ol.parseText(title);
859     endTitle(ol,getSourceFileBase(),0);
860   }
861
862   ol.startContents();
863
864   if (isLinkable())
865   {
866     if (latexSourceCode) ol.disable(OutputGenerator::Latex);
867     ol.startTextLink(getOutputFileBase(),0);
868     ol.parseText(theTranslator->trGotoDocumentation());
869     ol.endTextLink();
870     if (latexSourceCode) ol.enable(OutputGenerator::Latex);
871   }
872
873   (void)sameTu;
874   (void)filesInSameTu;
875 #if USE_LIBCLANG
876   static bool clangAssistedParsing = Config_getBool("CLANG_ASSISTED_PARSING");
877   if (clangAssistedParsing && 
878       (getLanguage()==SrcLangExt_Cpp || getLanguage()==SrcLangExt_ObjC))
879   {
880     ol.startCodeFragment();
881     if (!sameTu)
882     {
883       ClangParser::instance()->start(absFilePath(),filesInSameTu);
884     }
885     else
886     {
887       ClangParser::instance()->switchToFile(absFilePath());
888     }
889     ClangParser::instance()->writeSources(ol,this);
890     ol.endCodeFragment();
891   }
892   else
893 #endif
894   {
895     ParserInterface *pIntf = Doxygen::parserManager->getParser(getDefFileExtension());
896     pIntf->resetCodeParserState();
897     ol.startCodeFragment();
898     bool needs2PassParsing = 
899         Doxygen::parseSourcesNeeded &&                // we need to parse (filtered) sources for cross-references
900         !filterSourceFiles &&                         // but user wants to show sources as-is
901         !getFileFilter(absFilePath(),TRUE).isEmpty(); // and there is a filter used while parsing
902
903     if (needs2PassParsing)
904     {
905       // parse code for cross-references only (see bug707641)
906       pIntf->parseCode(devNullIntf,0,
907                        fileToString(absFilePath(),TRUE,TRUE),
908                        getLanguage(),
909                        FALSE,0,this
910                       );
911     }
912     pIntf->parseCode(ol,0,
913         fileToString(absFilePath(),filterSourceFiles,TRUE),
914         getLanguage(),      // lang
915         FALSE,              // isExampleBlock
916         0,                  // exampleName
917         this,               // fileDef
918         -1,                 // startLine
919         -1,                 // endLine
920         FALSE,              // inlineFragment
921         0,                  // memberDef
922         TRUE,               // showLineNumbers
923         0,                  // searchCtx
924         !needs2PassParsing  // collectXRefs
925         );
926     ol.endCodeFragment();
927   }
928   ol.endContents();
929   endFileWithNavPath(this,ol);
930   ol.enableAll();
931 }
932
933 void FileDef::parseSource(bool sameTu,QStrList &filesInSameTu)
934 {
935   static bool filterSourceFiles = Config_getBool("FILTER_SOURCE_FILES");
936   DevNullCodeDocInterface devNullIntf;
937   (void)sameTu;
938   (void)filesInSameTu;
939 #if USE_LIBCLANG
940   static bool clangAssistedParsing = Config_getBool("CLANG_ASSISTED_PARSING");
941   if (clangAssistedParsing && 
942       (getLanguage()==SrcLangExt_Cpp || getLanguage()==SrcLangExt_ObjC))
943   {
944     if (!sameTu)
945     {
946       ClangParser::instance()->start(absFilePath(),filesInSameTu);
947     }
948     else
949     {
950       ClangParser::instance()->switchToFile(absFilePath());
951     }
952     ClangParser::instance()->writeSources(devNullIntf,this);
953   }
954   else
955 #endif
956   {
957     ParserInterface *pIntf = Doxygen::parserManager->getParser(getDefFileExtension());
958     pIntf->resetCodeParserState();
959     pIntf->parseCode(
960             devNullIntf,0,
961             fileToString(absFilePath(),filterSourceFiles,TRUE),
962             getLanguage(),
963             FALSE,0,this
964            );
965   }
966 }
967
968 void FileDef::startParsing()
969 {
970 }
971
972 void FileDef::finishParsing()
973 {
974   ClangParser::instance()->finish();
975 }
976
977 void FileDef::addMembersToMemberGroup()
978 {
979   QListIterator<MemberList> mli(m_memberLists);
980   MemberList *ml;
981   for (mli.toFirst();(ml=mli.current());++mli)
982   {
983     if (ml->listType()&MemberListType_declarationLists)
984     {
985       ::addMembersToMemberGroup(ml,&m_memberGroupSDict,this);
986     }
987   }
988
989   // add members inside sections to their groups
990   if (m_memberGroupSDict)
991   {
992     MemberGroupSDict::Iterator mgli(*m_memberGroupSDict);
993     MemberGroup *mg;
994     for (;(mg=mgli.current());++mgli)
995     {
996       if (mg->allMembersInSameSection() && m_subGrouping)
997       {
998         //printf("----> addToDeclarationSection(%s)\n",mg->header().data());
999         mg->addToDeclarationSection();
1000       }
1001     }
1002   }
1003 }
1004
1005 /*! Adds member definition \a md to the list of all members of this file */
1006 void FileDef::insertMember(MemberDef *md)
1007 {
1008   if (md->isHidden()) return;
1009   //printf("%s:FileDef::insertMember(%s (=%p) list has %d elements)\n",
1010   //    name().data(),md->name().data(),md,allMemberList.count());
1011   MemberList *allMemberList = getMemberList(MemberListType_allMembersList);
1012   if (allMemberList && allMemberList->findRef(md)!=-1)  // TODO optimize the findRef!
1013   { 
1014     return;
1015   }
1016
1017   if (allMemberList==0)
1018   {
1019     allMemberList = new MemberList(MemberListType_allMembersList);
1020     m_memberLists.append(allMemberList);
1021   }
1022   allMemberList->append(md); 
1023   //::addFileMemberNameToIndex(md);
1024   switch (md->memberType())
1025   {
1026     case MemberType_Variable:     
1027     case MemberType_Property:     
1028       addMemberToList(MemberListType_decVarMembers,md);
1029       addMemberToList(MemberListType_docVarMembers,md);
1030       break;
1031     case MemberType_Function: 
1032       addMemberToList(MemberListType_decFuncMembers,md);
1033       addMemberToList(MemberListType_docFuncMembers,md);
1034       break;
1035     case MemberType_Typedef:      
1036       addMemberToList(MemberListType_decTypedefMembers,md);
1037       addMemberToList(MemberListType_docTypedefMembers,md);
1038       break;
1039     case MemberType_Enumeration:  
1040       addMemberToList(MemberListType_decEnumMembers,md);
1041       addMemberToList(MemberListType_docEnumMembers,md);
1042       break;
1043     case MemberType_EnumValue:    // enum values are shown inside their enums
1044       break;
1045     case MemberType_Define:       
1046       addMemberToList(MemberListType_decDefineMembers,md);
1047       addMemberToList(MemberListType_docDefineMembers,md);
1048       break;
1049     default:
1050        err("FileDef::insertMembers(): "
1051            "member `%s' with class scope `%s' inserted in file scope `%s'!\n",
1052            md->name().data(),
1053            md->getClassDef() ? md->getClassDef()->name().data() : "<global>",
1054            name().data());
1055   }
1056   //addMemberToGroup(md,groupId);
1057 }
1058
1059 /*! Adds compound definition \a cd to the list of all compounds of this file */
1060 void FileDef::insertClass(ClassDef *cd)
1061 {
1062   if (cd->isHidden()) return;
1063   if (m_classSDict==0)
1064   {
1065     m_classSDict = new ClassSDict(17);
1066   }
1067   if (Config_getBool("SORT_BRIEF_DOCS"))
1068   {
1069     m_classSDict->inSort(cd->name(),cd);
1070   }
1071   else
1072   {
1073     m_classSDict->append(cd->name(),cd);
1074   }
1075 }
1076
1077 /*! Adds namespace definition \a nd to the list of all compounds of this file */
1078 void FileDef::insertNamespace(NamespaceDef *nd)
1079 {
1080   if (nd->isHidden()) return;
1081   if (!nd->name().isEmpty() && 
1082       (m_namespaceSDict==0 || m_namespaceSDict->find(nd->name())==0))
1083   {
1084     if (m_namespaceSDict==0)
1085     {
1086       m_namespaceSDict = new NamespaceSDict;
1087     }
1088     if (Config_getBool("SORT_BRIEF_DOCS"))
1089     {
1090       m_namespaceSDict->inSort(nd->name(),nd);
1091     }
1092     else
1093     {
1094       m_namespaceSDict->append(nd->name(),nd);
1095     }
1096   }
1097 }
1098
1099 QCString FileDef::name() const 
1100
1101   if (Config_getBool("FULL_PATH_NAMES")) 
1102     return m_fileName; 
1103   else 
1104     return Definition::name(); 
1105
1106
1107 void FileDef::addSourceRef(int line,Definition *d,MemberDef *md)
1108 {
1109   //printf("FileDef::addSourceDef(%d,%p,%p)\n",line,d,md);
1110   if (d)
1111   {
1112     if (m_srcDefDict==0)    m_srcDefDict    = new QIntDict<Definition>(257);
1113     if (m_srcMemberDict==0) m_srcMemberDict = new QIntDict<MemberDef>(257);
1114     m_srcDefDict->insert(line,d);
1115     if (md) m_srcMemberDict->insert(line,md);
1116     //printf("Adding member %s with anchor %s at line %d to file %s\n",
1117     //    md?md->name().data():"<none>",md?md->anchor().data():"<none>",line,name().data());
1118   }
1119 }
1120
1121 Definition *FileDef::getSourceDefinition(int lineNr) const
1122 {
1123   Definition *result=0;
1124   if (m_srcDefDict)
1125   {
1126     result = m_srcDefDict->find(lineNr);
1127   }
1128   //printf("%s::getSourceDefinition(%d)=%s\n",name().data(),lineNr,result?result->name().data():"none");
1129   return result;
1130 }
1131
1132 MemberDef *FileDef::getSourceMember(int lineNr) const
1133 {
1134   MemberDef *result=0;
1135   if (m_srcMemberDict)
1136   {
1137     result = m_srcMemberDict->find(lineNr);
1138   }
1139   //printf("%s::getSourceMember(%d)=%s\n",name().data(),lineNr,result?result->name().data():"none");
1140   return result;
1141 }
1142
1143
1144 void FileDef::addUsingDirective(NamespaceDef *nd)
1145 {
1146   if (m_usingDirList==0)
1147   {
1148     m_usingDirList = new NamespaceSDict;
1149   }
1150   if (m_usingDirList->find(nd->qualifiedName())==0)
1151   {
1152     m_usingDirList->append(nd->qualifiedName(),nd);
1153   }
1154   //printf("%p: FileDef::addUsingDirective: %s:%d\n",this,name().data(),usingDirList->count());
1155 }
1156
1157 NamespaceSDict *FileDef::getUsedNamespaces() const 
1158
1159   //printf("%p: FileDef::getUsedNamespace: %s:%d\n",this,name().data(),usingDirList?usingDirList->count():0);
1160   return m_usingDirList; 
1161 }
1162
1163 void FileDef::addUsingDeclaration(Definition *d)
1164 {
1165   if (m_usingDeclList==0)
1166   {
1167     m_usingDeclList = new SDict<Definition>(17);
1168   }
1169   if (m_usingDeclList->find(d->qualifiedName())==0)
1170   {
1171     m_usingDeclList->append(d->qualifiedName(),d);
1172   }
1173 }
1174
1175 void FileDef::addIncludeDependency(FileDef *fd,const char *incName,bool local,
1176                                    bool imported,bool indirect)
1177 {
1178   //printf("FileDef::addIncludeDependency(%p,%s,%d)\n",fd,incName,local);
1179   QCString iName = fd ? fd->absFilePath().data() : incName;
1180   if (!iName.isEmpty() && (!m_includeDict || m_includeDict->find(iName)==0))
1181   {
1182     if (m_includeDict==0)
1183     {
1184       m_includeDict   = new QDict<IncludeInfo>(61);
1185       m_includeList   = new QList<IncludeInfo>;
1186       m_includeList->setAutoDelete(TRUE);
1187     }
1188     IncludeInfo *ii = new IncludeInfo;
1189     ii->fileDef     = fd;
1190     ii->includeName = incName;
1191     ii->local       = local;
1192     ii->imported    = imported;
1193     ii->indirect    = indirect;
1194     m_includeList->append(ii);
1195     m_includeDict->insert(iName,ii);
1196   }
1197 }
1198
1199 void FileDef::addIncludedUsingDirectives()
1200 {
1201   if (visited) return;
1202   visited=TRUE;
1203   //printf("( FileDef::addIncludedUsingDirectives for file %s\n",name().data());
1204
1205   NamespaceList nl;
1206   if (m_includeList) // file contains #includes
1207   {
1208     {
1209       QListIterator<IncludeInfo> iii(*m_includeList);
1210       IncludeInfo *ii;
1211       for (iii.toFirst();(ii=iii.current());++iii) // foreach #include...
1212       {
1213         if (ii->fileDef && !ii->fileDef->visited) // ...that is a known file
1214         {
1215           // recurse into this file
1216           ii->fileDef->addIncludedUsingDirectives();
1217         }
1218       }
1219     }
1220     {
1221       QListIterator<IncludeInfo> iii(*m_includeList);
1222       IncludeInfo *ii;
1223       // iterate through list from last to first
1224       for (iii.toLast();(ii=iii.current());--iii)
1225       {
1226         if (ii->fileDef && ii->fileDef!=this)
1227         {
1228           // add using directives
1229           NamespaceSDict *unl = ii->fileDef->m_usingDirList;
1230           if (unl)
1231           {
1232             NamespaceSDict::Iterator nli(*unl);
1233             NamespaceDef *nd;
1234             for (nli.toLast();(nd=nli.current());--nli)
1235             {
1236               // append each using directive found in a #include file
1237               if (m_usingDirList==0) m_usingDirList = new NamespaceSDict;
1238               //printf("Prepending used namespace %s to the list of file %s\n",
1239               //    nd->name().data(),name().data());
1240               if (m_usingDirList->find(nd->qualifiedName())==0) // not yet added
1241               {
1242                 m_usingDirList->prepend(nd->qualifiedName(),nd);
1243               }
1244             }
1245           }
1246           // add using declarations
1247           SDict<Definition> *udl = ii->fileDef->m_usingDeclList;
1248           if (udl)
1249           {
1250             SDict<Definition>::Iterator udi(*udl);
1251             Definition *d;
1252             for (udi.toLast();(d=udi.current());--udi)
1253             {
1254               //printf("Adding using declaration %s\n",d->name().data());
1255               if (m_usingDeclList==0)
1256               {
1257                 m_usingDeclList = new SDict<Definition>(17);
1258               }
1259               if (m_usingDeclList->find(d->qualifiedName())==0)
1260               {
1261                 m_usingDeclList->prepend(d->qualifiedName(),d);
1262               }
1263             }
1264           }
1265         }
1266       }
1267     }
1268   }
1269   //printf(") end FileDef::addIncludedUsingDirectives for file %s\n",name().data());
1270 }
1271
1272
1273 void FileDef::addIncludedByDependency(FileDef *fd,const char *incName,
1274                                       bool local,bool imported)
1275 {
1276   //printf("FileDef::addIncludedByDependency(%p,%s,%d)\n",fd,incName,local);
1277   QCString iName = fd ? fd->absFilePath().data() : incName;
1278   if (!iName.isEmpty() && (m_includedByDict==0 || m_includedByDict->find(iName)==0))
1279   {
1280     if (m_includedByDict==0)
1281     {
1282       m_includedByDict = new QDict<IncludeInfo>(61);
1283       m_includedByList = new QList<IncludeInfo>;
1284       m_includedByList->setAutoDelete(TRUE);
1285     }
1286     IncludeInfo *ii = new IncludeInfo;
1287     ii->fileDef     = fd;
1288     ii->includeName = incName;
1289     ii->local       = local;
1290     ii->imported    = imported;
1291     ii->indirect    = FALSE;
1292     m_includedByList->append(ii);
1293     m_includedByDict->insert(iName,ii);
1294   }
1295 }
1296
1297 bool FileDef::isIncluded(const QCString &name) const
1298 {
1299   if (name.isEmpty()) return FALSE;
1300   return m_includeDict!=0 && m_includeDict->find(name)!=0;
1301 }
1302
1303 bool FileDef::generateSourceFile() const 
1304
1305   static bool sourceBrowser = Config_getBool("SOURCE_BROWSER");
1306   static bool verbatimHeaders = Config_getBool("VERBATIM_HEADERS");
1307   QCString extension = name().right(4);
1308   return !isReference() && 
1309          (sourceBrowser || 
1310            (verbatimHeaders && guessSection(name())==Entry::HEADER_SEC) 
1311          ) &&
1312          extension!=".doc" && extension!=".txt" && extension!=".dox" &&
1313          extension!=".md" && name().right(9)!=".markdown";  
1314 }
1315
1316
1317 void FileDef::addListReferences()
1318 {
1319   {
1320     QList<ListItemInfo> *xrefItems = xrefListItems();
1321     addRefItem(xrefItems,
1322                getOutputFileBase(),
1323                theTranslator->trFile(TRUE,TRUE),
1324                getOutputFileBase(),name(),
1325                0
1326               );
1327   }
1328   if (m_memberGroupSDict)
1329   {
1330     MemberGroupSDict::Iterator mgli(*m_memberGroupSDict);
1331     MemberGroup *mg;
1332     for (;(mg=mgli.current());++mgli)
1333     {
1334       mg->addListReferences(this);
1335     }
1336   }
1337   QListIterator<MemberList> mli(m_memberLists);
1338   MemberList *ml;
1339   for (mli.toFirst();(ml=mli.current());++mli)
1340   {
1341     if (ml->listType()&MemberListType_documentationLists)
1342     {
1343       ml->addListReferences(this);
1344     }
1345   }
1346 }
1347
1348 //-------------------------------------------------------------------
1349
1350 static int findMatchingPart(const QCString &path,const QCString dir)
1351 {
1352   int si1;
1353   int pos1=0,pos2=0;
1354   while ((si1=path.find('/',pos1))!=-1)
1355   {
1356     int si2=dir.find('/',pos2);
1357     //printf("  found slash at pos %d in path %d: %s<->%s\n",si1,si2,
1358     //    path.mid(pos1,si1-pos2).data(),dir.mid(pos2).data());
1359     if (si2==-1 && path.mid(pos1,si1-pos2)==dir.mid(pos2)) // match at end
1360     {
1361       return dir.length();
1362     }
1363     if (si1!=si2 || path.mid(pos1,si1-pos2)!=dir.mid(pos2,si2-pos2)) // no match in middle
1364     {
1365       return QMAX(pos1-1,0);
1366     }
1367     pos1=si1+1;
1368     pos2=si2+1;
1369   }
1370   return 0;
1371 }
1372
1373 static Directory *findDirNode(Directory *root,const QCString &name)
1374 {
1375   QListIterator<DirEntry> dli(root->children());
1376   DirEntry *de;
1377   for (dli.toFirst();(de=dli.current());++dli)
1378   {
1379     if (de->kind()==DirEntry::Dir)
1380     {
1381       Directory *dir = (Directory *)de;
1382       QCString dirName=dir->name();
1383       int sp=findMatchingPart(name,dirName);
1384       //printf("findMatchingPart(%s,%s)=%d\n",name.data(),dirName.data(),sp);
1385       if (sp>0) // match found
1386       {
1387         if ((uint)sp==dirName.length()) // whole directory matches
1388         {
1389           // recurse into the directory
1390           return findDirNode(dir,name.mid(dirName.length()+1));
1391         } 
1392         else // partial match => we need to split the path into three parts
1393         {
1394           QCString baseName     =dirName.left(sp);
1395           QCString oldBranchName=dirName.mid(sp+1);
1396           QCString newBranchName=name.mid(sp+1);
1397           // strip file name from path
1398           int newIndex=newBranchName.findRev('/');
1399           if (newIndex>0) newBranchName=newBranchName.left(newIndex);
1400
1401           //printf("Splitting off part in new branch \n"
1402           //    "base=%s old=%s new=%s\n",
1403           //    baseName.data(),
1404           //    oldBranchName.data(),
1405           //    newBranchName.data()
1406           //      );
1407           Directory *base = new Directory(root,baseName);
1408           Directory *newBranch = new Directory(base,newBranchName);
1409           dir->reParent(base);
1410           dir->rename(oldBranchName);
1411           base->addChild(dir);
1412           base->addChild(newBranch);
1413           dir->setLast(FALSE);
1414           // remove DirEntry container from list (without deleting it)
1415           root->children().setAutoDelete(FALSE);
1416           root->children().removeRef(dir);
1417           root->children().setAutoDelete(TRUE);
1418           // add new branch to the root
1419           if (!root->children().isEmpty())
1420           {
1421             root->children().getLast()->setLast(FALSE); 
1422           }
1423           root->addChild(base);
1424           return newBranch;
1425         }
1426       }
1427     }
1428   }
1429   int si=name.findRev('/');
1430   if (si==-1) // no subdir
1431   {
1432     return root; // put the file under the root node.
1433   }
1434   else // need to create a subdir 
1435   {
1436     QCString baseName = name.left(si);
1437     //printf("new subdir %s\n",baseName.data());
1438     Directory *newBranch = new Directory(root,baseName);
1439     if (!root->children().isEmpty())
1440     {
1441       root->children().getLast()->setLast(FALSE); 
1442     }
1443     root->addChild(newBranch);
1444     return newBranch;
1445   }
1446 }
1447
1448 static void mergeFileDef(Directory *root,FileDef *fd)
1449 {
1450   QCString rootPath = root->name();
1451   QCString filePath = fd->absFilePath();
1452   //printf("merging %s\n",filePath.data());
1453   Directory *dirNode = findDirNode(root,filePath);
1454   if (!dirNode->children().isEmpty())
1455   {
1456     dirNode->children().getLast()->setLast(FALSE); 
1457   }
1458   DirEntry *e=new DirEntry(dirNode,fd);
1459   dirNode->addChild(e);
1460 }
1461
1462 #if 0
1463 static void generateIndent(QTextStream &t,DirEntry *de,int level)
1464 {
1465   if (de->parent())
1466   {
1467     generateIndent(t,de->parent(),level+1);
1468   }
1469   // from the root up to node n do...
1470   if (level==0) // item before a dir or document
1471   {
1472     if (de->isLast())
1473     {
1474       if (de->kind()==DirEntry::Dir)
1475       {
1476         t << "<img " << FTV_IMGATTRIBS(plastnode) << "/>";
1477       }
1478       else
1479       {
1480         t << "<img " << FTV_IMGATTRIBS(lastnode) << "/>";
1481       }
1482     }
1483     else
1484     {
1485       if (de->kind()==DirEntry::Dir)
1486       {
1487         t << "<img " << FTV_IMGATTRIBS(pnode) << "/>";
1488       }
1489       else
1490       {
1491         t << "<img " << FTV_IMGATTRIBS(node) << "/>";
1492       }
1493     }
1494   }
1495   else // item at another level
1496   {
1497     if (de->isLast())
1498     {
1499       t << "<img " << FTV_IMGATTRIBS(blank) << "/>";
1500     }
1501     else
1502     {
1503       t << "<img " << FTV_IMGATTRIBS(vertline) << "/>";
1504     }
1505   }
1506 }
1507
1508 static void writeDirTreeNode(QTextStream &t,Directory *root,int level)
1509 {
1510   QCString indent;
1511   indent.fill(' ',level*2);
1512   QListIterator<DirEntry> dli(root->children());
1513   DirEntry *de;
1514   for (dli.toFirst();(de=dli.current());++dli)
1515   {
1516     t << indent << "<p>";
1517     generateIndent(t,de,0);
1518     if (de->kind()==DirEntry::Dir)
1519     {
1520       Directory *dir=(Directory *)de;
1521       //printf("%s [dir]: %s (last=%d,dir=%d)\n",indent.data(),dir->name().data(),dir->isLast(),dir->kind()==DirEntry::Dir);
1522       t << "<img " << FTV_IMGATTRIBS(folderclosed) << "/>";
1523       t << dir->name();
1524       t << "</p>\n";
1525       t << indent << "<div>\n";
1526       writeDirTreeNode(t,dir,level+1);
1527       t << indent << "</div>\n";
1528     }
1529     else
1530     {
1531       //printf("%s [file]: %s (last=%d,dir=%d)\n",indent.data(),de->file()->name().data(),de->isLast(),de->kind()==DirEntry::Dir);
1532       t << "<img " << FTV_IMGATTRIBS(doc) << "/>";
1533       t << de->file()->name();
1534       t << "</p>\n";
1535     }
1536   }
1537 }
1538 #endif
1539
1540 static void addDirsAsGroups(Directory *root,GroupDef *parent,int level)
1541 {
1542   GroupDef *gd=0;
1543   if (root->kind()==DirEntry::Dir)
1544   {
1545     gd = new GroupDef("[generated]",
1546                       1,
1547                       root->path(), // name
1548                       root->name()  // title
1549                      );
1550     if (parent) 
1551     {
1552       parent->addGroup(gd);
1553       gd->makePartOfGroup(parent);
1554     }
1555     else
1556     {
1557       Doxygen::groupSDict->append(root->path(),gd);
1558     }
1559   }
1560   QListIterator<DirEntry> dli(root->children());
1561   DirEntry *de;
1562   for (dli.toFirst();(de=dli.current());++dli)
1563   {
1564     if (de->kind()==DirEntry::Dir)
1565     {
1566       addDirsAsGroups((Directory *)de,gd,level+1);
1567     }
1568   }
1569 }
1570
1571 void generateFileTree()
1572 {
1573   Directory *root=new Directory(0,"root");
1574   root->setLast(TRUE);
1575   FileNameListIterator fnli(*Doxygen::inputNameList); 
1576   FileName *fn;
1577   for (fnli.toFirst();(fn=fnli.current());++fnli)
1578   {
1579     FileNameIterator fni(*fn);
1580     FileDef *fd;
1581     for (;(fd=fni.current());++fni)
1582     {
1583       mergeFileDef(root,fd);
1584     }
1585   }
1586   //t << "<div class=\"directory\">\n";
1587   //writeDirTreeNode(t,root,0);
1588   //t << "</div>\n";
1589   addDirsAsGroups(root,0,0);
1590   delete root;
1591 }
1592
1593 //-------------------------------------------------------------------
1594
1595 void FileDef::combineUsingRelations()
1596 {
1597   if (visited) return; // already done
1598   visited=TRUE;
1599   if (m_usingDirList)
1600   {
1601     NamespaceSDict::Iterator nli(*m_usingDirList);
1602     NamespaceDef *nd;
1603     for (nli.toFirst();(nd=nli.current());++nli)
1604     {
1605       nd->combineUsingRelations();
1606     }
1607     for (nli.toFirst();(nd=nli.current());++nli)
1608     {
1609       // add used namespaces of namespace nd to this namespace
1610       if (nd->getUsedNamespaces())
1611       {
1612         NamespaceSDict::Iterator unli(*nd->getUsedNamespaces());
1613         NamespaceDef *und;
1614         for (unli.toFirst();(und=unli.current());++unli)
1615         {
1616           //printf("Adding namespace %s to the using list of %s\n",und->qualifiedName().data(),qualifiedName().data());
1617           addUsingDirective(und);
1618         }
1619       }
1620       // add used classes of namespace nd to this namespace
1621       if (nd->getUsedClasses())
1622       {
1623         SDict<Definition>::Iterator cli(*nd->getUsedClasses());
1624         Definition *ucd;
1625         for (cli.toFirst();(ucd=cli.current());++cli)
1626         {
1627           //printf("Adding class %s to the using list of %s\n",cd->qualifiedName().data(),qualifiedName().data());
1628           addUsingDeclaration(ucd);
1629         }
1630       }
1631     }
1632   }
1633 }
1634
1635 bool FileDef::isDocumentationFile() const
1636 {
1637   return name().right(4)==".doc" ||
1638          name().right(4)==".txt" ||
1639          name().right(4)==".dox" ||
1640          name().right(3)==".md"  ||
1641          name().right(9)==".markdown";
1642 }
1643
1644 void FileDef::acquireFileVersion()
1645 {
1646   QCString vercmd = Config_getString("FILE_VERSION_FILTER");
1647   if (!vercmd.isEmpty() && !m_filePath.isEmpty() && m_filePath!="generated") 
1648   {
1649     msg("Version of %s : ",m_filePath.data());
1650     QCString cmd = vercmd+" \""+m_filePath+"\"";
1651     Debug::print(Debug::ExtCmd,0,"Executing popen(`%s`)\n",cmd.data());
1652     FILE *f=portable_popen(cmd,"r");
1653     if (!f)
1654     {
1655       err("could not execute %s\n",vercmd.data());
1656       return;
1657     }
1658     const int bufSize=1024;
1659     char buf[bufSize];
1660     int numRead = (int)fread(buf,1,bufSize,f);
1661     portable_pclose(f);
1662     if (numRead>0 && !(m_fileVersion=QCString(buf,numRead).stripWhiteSpace()).isEmpty())
1663     {
1664       msg("%s\n",m_fileVersion.data());
1665     }
1666     else 
1667     {
1668       msg("no version available\n");
1669     }
1670   }
1671 }
1672
1673
1674 QCString FileDef::getSourceFileBase() const
1675
1676   if (Htags::useHtags)
1677   {
1678     return Htags::path2URL(m_filePath);
1679   }
1680   else
1681   {
1682     return convertNameToFile(m_diskName)+"_source"; 
1683   }
1684 }
1685
1686 /*! Returns the name of the verbatim copy of this file (if any). */
1687 QCString FileDef::includeName() const 
1688
1689   return getSourceFileBase();
1690 }
1691
1692 MemberList *FileDef::createMemberList(MemberListType lt)
1693 {
1694   m_memberLists.setAutoDelete(TRUE);
1695   QListIterator<MemberList> mli(m_memberLists);
1696   MemberList *ml;
1697   for (mli.toFirst();(ml=mli.current());++mli)
1698   {
1699     if (ml->listType()==lt)
1700     {
1701       return ml;
1702     }
1703   }
1704   // not found, create a new member list
1705   ml = new MemberList(lt);
1706   m_memberLists.append(ml);
1707   return ml;
1708 }
1709
1710 void FileDef::addMemberToList(MemberListType lt,MemberDef *md)
1711 {
1712   static bool sortBriefDocs = Config_getBool("SORT_BRIEF_DOCS");
1713   static bool sortMemberDocs = Config_getBool("SORT_MEMBER_DOCS");
1714   MemberList *ml = createMemberList(lt);
1715   ml->setNeedsSorting(
1716        ((ml->listType()&MemberListType_declarationLists) && sortBriefDocs) ||
1717        ((ml->listType()&MemberListType_documentationLists) && sortMemberDocs));
1718   ml->append(md);
1719 #if 0
1720   if (ml->needsSorting())
1721     ml->inSort(md);
1722   else
1723     ml->append(md);
1724 #endif
1725   if (lt&MemberListType_documentationLists)
1726   {
1727     ml->setInFile(TRUE);
1728   }
1729   if (ml->listType()&MemberListType_declarationLists) md->setSectionList(this,ml);
1730 }
1731
1732 void FileDef::sortMemberLists()
1733 {
1734   QListIterator<MemberList> mli(m_memberLists);
1735   MemberList *ml;
1736   for (;(ml=mli.current());++mli)
1737   {
1738     if (ml->needsSorting()) { ml->sort(); ml->setNeedsSorting(FALSE); }
1739   }
1740 }
1741
1742 MemberList *FileDef::getMemberList(MemberListType lt) const
1743 {
1744   QListIterator<MemberList> mli(m_memberLists);
1745   MemberList *ml;
1746   for (;(ml=mli.current());++mli)
1747   {
1748     if (ml->listType()==lt)
1749     {
1750       return ml;
1751     }
1752   }
1753   return 0;
1754 }
1755
1756 void FileDef::writeMemberDeclarations(OutputList &ol,MemberListType lt,const QCString &title)
1757 {
1758   static bool optVhdl = Config_getBool("OPTIMIZE_OUTPUT_VHDL");
1759   MemberList * ml = getMemberList(lt);
1760   if (ml) 
1761   {
1762     if (optVhdl) // use specific declarations function
1763     {
1764
1765       VhdlDocGen::writeVhdlDeclarations(ml,ol,0,0,this,0);
1766     }
1767     else
1768     {
1769       ml->writeDeclarations(ol,0,0,this,0,title,0,definitionType());
1770     }
1771   }
1772 }
1773
1774 void FileDef::writeMemberDocumentation(OutputList &ol,MemberListType lt,const QCString &title)
1775 {
1776   MemberList * ml = getMemberList(lt);
1777   if (ml) ml->writeDocumentation(ol,name(),this,title);
1778 }
1779
1780 bool FileDef::isLinkableInProject() const
1781 {
1782   static bool showFiles = Config_getBool("SHOW_FILES");
1783   return hasDocumentation() && !isReference() && showFiles;
1784 }
1785
1786 static void getAllIncludeFilesRecursively(
1787     QDict<void> *filesVisited,const FileDef *fd,QStrList &incFiles)
1788 {
1789   if (fd->includeFileList())
1790   {
1791     QListIterator<IncludeInfo> iii(*fd->includeFileList());
1792     IncludeInfo *ii;
1793     for (iii.toFirst();(ii=iii.current());++iii)
1794     {
1795       if (ii->fileDef && !ii->fileDef->isReference() &&
1796           !filesVisited->find(ii->fileDef->absFilePath()))
1797       {
1798         //printf("FileDef::addIncludeDependency(%s)\n",ii->fileDef->absFilePath().data());
1799         incFiles.append(ii->fileDef->absFilePath());
1800         filesVisited->insert(ii->fileDef->absFilePath(),(void*)0x8);
1801         getAllIncludeFilesRecursively(filesVisited,ii->fileDef,incFiles);
1802       }
1803     }
1804   }
1805 }
1806
1807 void FileDef::getAllIncludeFilesRecursively(QStrList &incFiles) const
1808 {
1809   QDict<void> includes(257);
1810   ::getAllIncludeFilesRecursively(&includes,this,incFiles);
1811 }
1812
1813 QCString FileDef::title() const
1814 {
1815   return theTranslator->trFileReference(name());
1816 }
1817
1818 QCString FileDef::fileVersion() const
1819 {
1820   return m_fileVersion;
1821 }