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