1 /******************************************************************************
3 * $Id: filedef.cpp,v 1.55 2001/03/19 19:27:40 root Exp $
5 * Copyright (C) 1997-2012 by Dimitri van Heesch.
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.
13 * Documents produced by Doxygen are derivative works derived from the
14 * input used in their production; they are not affected by this license.
19 #include "memberlist.h"
20 #include "classlist.h"
23 #include "memberdef.h"
25 #include "namespacedef.h"
28 #include "outputlist.h"
31 #include "docparser.h"
32 #include "searchindex.h"
34 #include "parserintf.h"
36 #include "vhdldocgen.h"
41 //---------------------------------------------------------------------------
43 /** Class implementing CodeOutputInterface by throwing away everything. */
44 class DevNullCodeDocInterface : public CodeOutputInterface
47 virtual void codify(const char *) {}
48 virtual void writeCodeLink(const char *,const char *,
49 const char *,const char *,
51 virtual void writeLineNumber(const char *,const char *,
53 virtual void startCodeLine(bool) {}
54 virtual void endCodeLine() {}
55 virtual void startCodeAnchor(const char *) {}
56 virtual void endCodeAnchor() {}
57 virtual void startFontClass(const char *) {}
58 virtual void endFontClass() {}
59 virtual void writeCodeAnchor(const char *) {}
60 virtual void linkableSymbol(int, const char *,Definition *,Definition *) {}
63 //---------------------------------------------------------------------------
65 /*! create a new file definition, where \a p is the file path,
66 \a nm the file name, and \a lref is an HTML anchor name if the
67 file was read from a tag file or 0 otherwise
69 FileDef::FileDef(const char *p,const char *nm,
70 const char *lref,const char *dn)
71 : Definition((QCString)p+nm,1,nm)
77 if (diskname.isEmpty()) diskname=nm;
93 if (Config_getBool("FULL_PATH_NAMES"))
95 docname.prepend(stripFromPath(path.copy()));
97 SrcLangExt lang = getLanguageFromFileName(name());
99 //m_isJava = lang==SrcLangExt_Java;
100 //m_isCSharp = lang==SrcLangExt_CSharp;
101 memberGroupSDict = 0;
102 acquireFileVersion();
103 m_subGrouping=Config_getBool("SUBGROUPING");
106 /*! destroy the file definition */
112 delete includedByDict;
113 delete includedByList;
114 delete namespaceSDict;
116 delete srcMemberDict;
118 delete usingDeclList;
119 delete memberGroupSDict;
122 /*! Compute the HTML anchor names for all members in the class */
123 void FileDef::computeAnchors()
125 MemberList *ml = getMemberList(MemberList::allMembersList);
126 if (ml) setAnchors(0,'a',ml);
129 void FileDef::distributeMemberGroupDocumentation()
131 //printf("FileDef::distributeMemberGroupDocumentation()\n");
132 if (memberGroupSDict)
134 MemberGroupSDict::Iterator mgli(*memberGroupSDict);
136 for (;(mg=mgli.current());++mgli)
138 mg->distributeMemberGroupDocumentation();
143 void FileDef::findSectionsInDocumentation()
145 docFindSections(documentation(),this,0,docFile());
146 if (memberGroupSDict)
148 MemberGroupSDict::Iterator mgli(*memberGroupSDict);
150 for (;(mg=mgli.current());++mgli)
152 mg->findSectionsInDocumentation();
156 QListIterator<MemberList> mli(m_memberLists);
158 for (mli.toFirst();(ml=mli.current());++mli)
160 if (ml->listType()&MemberList::declarationLists)
162 ml->findSectionsInDocumentation();
167 void FileDef::writeDetailedDescription(OutputList &ol,const QCString &title)
169 if ((!briefDescription().isEmpty() && Config_getBool("REPEAT_BRIEF")) ||
170 !documentation().stripWhiteSpace().isEmpty() || // avail empty section
171 (Config_getBool("SOURCE_BROWSER") && getStartBodyLine()!=-1 && getBodyDef())
174 ol.pushGeneratorState();
175 ol.disable(OutputGenerator::Html);
177 ol.popGeneratorState();
178 ol.pushGeneratorState();
179 ol.disableAllBut(OutputGenerator::Html);
180 ol.writeAnchor(0,"details");
181 ol.popGeneratorState();
182 ol.startGroupHeader();
187 if (!briefDescription().isEmpty() && Config_getBool("REPEAT_BRIEF"))
189 ol.parseDoc(briefFile(),briefLine(),this,0,briefDescription(),FALSE,FALSE);
191 if (!briefDescription().isEmpty() && Config_getBool("REPEAT_BRIEF") &&
192 !documentation().isEmpty())
194 ol.pushGeneratorState();
195 ol.disable(OutputGenerator::Man);
196 ol.disable(OutputGenerator::RTF);
197 // ol.newParagraph(); // FIXME:PARA
199 ol.disableAllBut(OutputGenerator::Man);
200 ol.writeString("\n\n");
201 ol.popGeneratorState();
203 if (!documentation().isEmpty())
205 ol.parseDoc(docFile(),docLine(),this,0,documentation()+"\n",TRUE,FALSE);
207 //printf("Writing source ref for file %s\n",name().data());
208 if (Config_getBool("SOURCE_BROWSER"))
211 QCString refText = theTranslator->trDefinedInSourceFile();
212 int fileMarkerPos = refText.find("@0");
213 if (fileMarkerPos!=-1) // should always pass this.
215 ol.parseText(refText.left(fileMarkerPos)); //text left from marker 1
216 ol.writeObjectLink(0,getSourceFileBase(),
218 ol.parseText(refText.right(
219 refText.length()-fileMarkerPos-2)); // text right from marker 2
227 void FileDef::writeBriefDescription(OutputList &ol)
229 if (!briefDescription().isEmpty() && Config_getBool("BRIEF_MEMBER_DESC"))
232 ol.parseDoc(briefFile(),briefLine(),this,0,
233 briefDescription(),TRUE,FALSE,0,TRUE,FALSE);
234 ol.pushGeneratorState();
235 ol.disable(OutputGenerator::RTF);
236 ol.writeString(" \n");
237 ol.enable(OutputGenerator::RTF);
239 if (Config_getBool("REPEAT_BRIEF") ||
240 !documentation().isEmpty()
243 ol.disableAllBut(OutputGenerator::Html);
244 ol.startTextLink(0,"details");
245 ol.parseText(theTranslator->trMore());
248 ol.popGeneratorState();
251 //ol.pushGeneratorState();
252 //ol.disable(OutputGenerator::RTF);
254 //ol.popGeneratorState();
259 void FileDef::writeIncludeFiles(OutputList &ol)
261 if (/*Config_getBool("SHOW_INCLUDE_FILES") &&*/ includeList &&
262 includeList->count()>0)
264 ol.startTextBlock(TRUE);
265 QListIterator<IncludeInfo> ili(*includeList);
267 for (;(ii=ili.current());++ili)
271 FileDef *fd=ii->fileDef;
272 bool isIDLorJava = FALSE;
275 SrcLangExt lang = fd->getLanguage();
276 isIDLorJava = lang==SrcLangExt_IDL || lang==SrcLangExt_Java;
278 ol.startTypewriter();
279 if (isIDLorJava) // IDL/Java include
281 ol.docify("import ");
283 else if (ii->imported) // Objective-C include
285 ol.docify("#import ");
287 else // C/C++ include
289 ol.docify("#include ");
291 if (ii->local || isIDLorJava)
295 ol.disable(OutputGenerator::Html);
296 ol.docify(ii->includeName);
298 ol.disableAllBut(OutputGenerator::Html);
300 // Here we use the include file name as it appears in the file.
301 // we could also we the name as it is used within doxygen,
302 // then we should have used fd->docName() instead of ii->includeName
303 if (fd && fd->isLinkable())
305 ol.writeObjectLink(fd->getReference(),
306 fd->generateSourceFile() ? fd->includeName() : fd->getOutputFileBase(),
308 if (!Config_getString("GENERATE_TAGFILE").isEmpty() && !fd->isReference())
310 const char *locStr = (ii->local || isIDLorJava) ? "yes" : "no";
311 const char *impStr = (ii->imported || isIDLorJava) ? "yes" : "no";
312 Doxygen::tagFile << " <includes id=\""
313 << convertToXML(fd->getOutputFileBase()) << "\" "
314 << "name=\"" << convertToXML(fd->name()) << "\" "
315 << "local=\"" << locStr << "\" "
316 << "imported=\"" << impStr << "\">"
317 << convertToXML(ii->includeName)
324 ol.docify(ii->includeName);
328 if (ii->local || isIDLorJava)
342 void FileDef::writeIncludeGraph(OutputList &ol)
344 if (Config_getBool("HAVE_DOT") /*&& Config_getBool("INCLUDE_GRAPH")*/)
346 //printf("Graph for file %s\n",name().data());
347 DotInclDepGraph incDepGraph(this,FALSE);
348 if (incDepGraph.isTooBig())
350 err("warning: Include graph for '%s' not generated, too many nodes. Consider increasing DOT_GRAPH_MAX_NODES.\n",name().data());
352 else if (!incDepGraph.isTrivial())
355 ol.disable(OutputGenerator::Man);
356 ol.startInclDepGraph();
357 ol.parseText(theTranslator->trInclDepGraph(name()));
358 ol.endInclDepGraph(incDepGraph);
360 ol.endTextBlock(TRUE);
362 //incDepGraph.writeGraph(Config_getString("HTML_OUTPUT"),fd->getOutputFileBase());
366 void FileDef::writeIncludedByGraph(OutputList &ol)
368 if (Config_getBool("HAVE_DOT") /*&& Config_getBool("INCLUDED_BY_GRAPH")*/)
370 //printf("Graph for file %s\n",name().data());
371 DotInclDepGraph incDepGraph(this,TRUE);
372 if (incDepGraph.isTooBig())
374 err("warning: Included by graph for '%s' not generated, too many nodes. Consider increasing DOT_GRAPH_MAX_NODES.\n",name().data());
376 if (!incDepGraph.isTrivial())
379 ol.disable(OutputGenerator::Man);
380 ol.startInclDepGraph();
381 ol.parseText(theTranslator->trInclByDepGraph());
382 ol.endInclDepGraph(incDepGraph);
384 ol.endTextBlock(TRUE);
386 //incDepGraph.writeGraph(Config_getString("HTML_OUTPUT"),fd->getOutputFileBase());
391 void FileDef::writeSourceLink(OutputList &ol)
393 //printf("%s: generateSourceFile()=%d\n",name().data(),generateSourceFile());
394 if (generateSourceFile())
396 ol.disableAllBut(OutputGenerator::Html);
398 ol.startTextLink(includeName(),0);
399 ol.parseText(theTranslator->trGotoSourceCode());
406 void FileDef::writeNamespaceDeclarations(OutputList &ol,const QCString &title)
408 // write list of namespaces
409 if (namespaceSDict) namespaceSDict->writeDeclaration(ol,title);
412 void FileDef::writeClassDeclarations(OutputList &ol,const QCString &title)
414 // write list of classes
415 if (classSDict) classSDict->writeDeclaration(ol,0,title,FALSE);
418 void FileDef::writeInlineClasses(OutputList &ol)
420 if (classSDict) classSDict->writeDocumentation(ol,this);
423 void FileDef::startMemberDeclarations(OutputList &ol)
425 ol.startMemberSections();
428 void FileDef::endMemberDeclarations(OutputList &ol)
430 ol.endMemberSections();
433 void FileDef::startMemberDocumentation(OutputList &ol)
435 if (Config_getBool("SEPARATE_MEMBER_PAGES"))
437 ol.disable(OutputGenerator::Html);
438 Doxygen::suppressDocWarnings = TRUE;
442 void FileDef::endMemberDocumentation(OutputList &ol)
444 if (Config_getBool("SEPARATE_MEMBER_PAGES"))
446 ol.enable(OutputGenerator::Html);
447 Doxygen::suppressDocWarnings = FALSE;
451 void FileDef::writeMemberGroups(OutputList &ol)
453 /* write user defined member groups */
454 if (memberGroupSDict)
456 memberGroupSDict->sort();
457 MemberGroupSDict::Iterator mgli(*memberGroupSDict);
459 for (;(mg=mgli.current());++mgli)
461 if ((!mg->allMembersInSameSection() || !m_subGrouping)
462 && mg->header()!="[NOHEADER]")
464 mg->writeDeclarations(ol,0,0,this,0);
470 void FileDef::writeAuthorSection(OutputList &ol)
472 // write Author section (Man only)
473 ol.pushGeneratorState();
474 ol.disableAllBut(OutputGenerator::Man);
475 ol.startGroupHeader();
476 ol.parseText(theTranslator->trAuthor(TRUE,TRUE));
478 ol.parseText(theTranslator->trGeneratedAutomatically(Config_getString("PROJECT_NAME")));
479 ol.popGeneratorState();
482 void FileDef::writeSummaryLinks(OutputList &ol)
484 ol.pushGeneratorState();
485 ol.disableAllBut(OutputGenerator::Html);
486 QListIterator<LayoutDocEntry> eli(
487 LayoutDocManager::instance().docEntries(LayoutDocManager::File));
490 SrcLangExt lang=getLanguage();
491 for (eli.toFirst();(lde=eli.current());++eli)
493 if ((lde->kind()==LayoutDocEntry::FileClasses && classSDict && classSDict->declVisible()) ||
494 (lde->kind()==LayoutDocEntry::FileNamespaces && namespaceSDict && namespaceSDict->declVisible())
497 LayoutDocEntrySection *ls = (LayoutDocEntrySection*)lde;
498 QCString label = lde->kind()==LayoutDocEntry::FileClasses ? "nested-classes" : "namespaces";
499 ol.writeSummaryLink(0,label,ls->title(lang),first);
502 else if (lde->kind()==LayoutDocEntry::MemberDecl)
504 LayoutDocEntryMemberDecl *lmd = (LayoutDocEntryMemberDecl*)lde;
505 MemberList * ml = getMemberList(lmd->type);
506 if (ml && ml->declVisible())
508 ol.writeSummaryLink(0,ml->listTypeAsString(),lmd->title(lang),first);
515 ol.writeString(" </div>\n");
517 ol.popGeneratorState();
520 /*! Write the documentation page for this file to the file of output
523 void FileDef::writeDocumentation(OutputList &ol)
525 static bool generateTreeView = Config_getBool("GENERATE_TREEVIEW");
526 //funcList->countDecMembers();
528 //QCString fn = name();
529 //if (Config_getBool("FULL_PATH_NAMES"))
531 // fn.prepend(stripFromPath(getPath().copy()));
534 //printf("WriteDocumentation diskname=%s\n",diskname.data());
536 QCString versionTitle;
537 if (!fileVersion.isEmpty())
539 versionTitle=("("+fileVersion+")");
541 QCString title = docname+versionTitle;
542 QCString pageTitle=theTranslator->trFileReference(docname);
546 startFile(ol,getOutputFileBase(),name(),pageTitle,HLI_FileVisible,!generateTreeView);
547 if (!generateTreeView)
549 getDirDef()->writeNavigationPath(ol);
550 ol.endQuickIndices();
552 QCString pageTitleShort=theTranslator->trFileReference(name());
553 startTitle(ol,getOutputFileBase(),this);
554 ol.pushGeneratorState();
555 ol.disableAllBut(OutputGenerator::Html);
556 ol.parseText(pageTitleShort); // Html only
558 ol.disable(OutputGenerator::Html);
559 ol.parseText(pageTitle); // other output formats
560 ol.popGeneratorState();
561 addGroupListToTitle(ol,this);
562 endTitle(ol,getOutputFileBase(),title);
566 startFile(ol,getOutputFileBase(),name(),pageTitle,HLI_FileVisible,!generateTreeView);
567 if (!generateTreeView)
569 ol.endQuickIndices();
571 startTitle(ol,getOutputFileBase(),this);
572 ol.parseText(pageTitle);
573 addGroupListToTitle(ol,this);
574 endTitle(ol,getOutputFileBase(),title);
579 if (!fileVersion.isEmpty())
581 ol.disableAllBut(OutputGenerator::Html);
582 ol.startProjectNumber();
583 ol.docify(versionTitle);
584 ol.endProjectNumber();
588 if (Doxygen::searchIndex)
590 Doxygen::searchIndex->setCurrentDoc(this,anchor(),FALSE);
591 Doxygen::searchIndex->addWord(localName(),TRUE);
594 if (!Config_getString("GENERATE_TAGFILE").isEmpty())
596 Doxygen::tagFile << " <compound kind=\"file\">" << endl;
597 Doxygen::tagFile << " <name>" << convertToXML(name()) << "</name>" << endl;
598 Doxygen::tagFile << " <path>" << convertToXML(getPath()) << "</path>" << endl;
599 Doxygen::tagFile << " <filename>"
600 << convertToXML(getOutputFileBase())
601 << "</filename>" << endl;
604 //---------------------------------------- start flexible part -------------------------------
606 SrcLangExt lang = getLanguage();
607 QListIterator<LayoutDocEntry> eli(
608 LayoutDocManager::instance().docEntries(LayoutDocManager::File));
610 for (eli.toFirst();(lde=eli.current());++eli)
614 case LayoutDocEntry::BriefDesc:
615 writeBriefDescription(ol);
617 case LayoutDocEntry::MemberDeclStart:
618 startMemberDeclarations(ol);
620 case LayoutDocEntry::FileIncludes:
621 writeIncludeFiles(ol);
623 case LayoutDocEntry::FileIncludeGraph:
624 writeIncludeGraph(ol);
626 case LayoutDocEntry::FileIncludedByGraph:
627 writeIncludedByGraph(ol);
629 case LayoutDocEntry::FileSourceLink:
632 case LayoutDocEntry::FileClasses:
634 LayoutDocEntrySection *ls = (LayoutDocEntrySection*)lde;
635 writeClassDeclarations(ol,ls->title(lang));
638 case LayoutDocEntry::FileNamespaces:
640 LayoutDocEntrySection *ls = (LayoutDocEntrySection*)lde;
641 writeNamespaceDeclarations(ol,ls->title(lang));
644 case LayoutDocEntry::MemberGroups:
645 writeMemberGroups(ol);
647 case LayoutDocEntry::MemberDecl:
649 LayoutDocEntryMemberDecl *lmd = (LayoutDocEntryMemberDecl*)lde;
650 writeMemberDeclarations(ol,lmd->type,lmd->title(lang));
653 case LayoutDocEntry::MemberDeclEnd:
654 endMemberDeclarations(ol);
656 case LayoutDocEntry::DetailedDesc:
658 LayoutDocEntrySection *ls = (LayoutDocEntrySection*)lde;
659 writeDetailedDescription(ol,ls->title(lang));
662 case LayoutDocEntry::MemberDefStart:
663 startMemberDocumentation(ol);
665 case LayoutDocEntry::FileInlineClasses:
666 writeInlineClasses(ol);
668 case LayoutDocEntry::MemberDef:
670 LayoutDocEntryMemberDef *lmd = (LayoutDocEntryMemberDef*)lde;
671 writeMemberDocumentation(ol,lmd->type,lmd->title(lang));
674 case LayoutDocEntry::MemberDefEnd:
675 endMemberDocumentation(ol);
677 case LayoutDocEntry::AuthorSection:
678 writeAuthorSection(ol);
680 case LayoutDocEntry::ClassIncludes:
681 case LayoutDocEntry::ClassInheritanceGraph:
682 case LayoutDocEntry::ClassNestedClasses:
683 case LayoutDocEntry::ClassCollaborationGraph:
684 case LayoutDocEntry::ClassAllMembersLink:
685 case LayoutDocEntry::ClassUsedFiles:
686 case LayoutDocEntry::ClassInlineClasses:
687 case LayoutDocEntry::NamespaceNestedNamespaces:
688 case LayoutDocEntry::NamespaceClasses:
689 case LayoutDocEntry::NamespaceInlineClasses:
690 case LayoutDocEntry::GroupClasses:
691 case LayoutDocEntry::GroupInlineClasses:
692 case LayoutDocEntry::GroupNamespaces:
693 case LayoutDocEntry::GroupDirs:
694 case LayoutDocEntry::GroupNestedGroups:
695 case LayoutDocEntry::GroupFiles:
696 case LayoutDocEntry::GroupGraph:
697 case LayoutDocEntry::GroupPageDocs:
698 case LayoutDocEntry::DirSubDirs:
699 case LayoutDocEntry::DirFiles:
700 case LayoutDocEntry::DirGraph:
701 err("Internal inconsistency: member %d should not be part of "
702 "LayoutDocManager::File entry list\n",lde->kind());
707 //---------------------------------------- end flexible part -------------------------------
709 if (!Config_getString("GENERATE_TAGFILE").isEmpty())
711 writeDocAnchorsToTagFile();
712 Doxygen::tagFile << " </compound>" << endl;
717 endFileWithNavPath(this,ol);
719 if (Config_getBool("SEPARATE_MEMBER_PAGES"))
721 MemberList *ml = getMemberList(MemberList::allMembersList);
723 writeMemberPages(ol);
727 void FileDef::writeMemberPages(OutputList &ol)
729 ol.pushGeneratorState();
730 ol.disableAllBut(OutputGenerator::Html);
732 QListIterator<MemberList> mli(m_memberLists);
734 for (mli.toFirst();(ml=mli.current());++mli)
736 if (ml->listType()&MemberList::documentationLists)
738 ml->writeDocumentationPage(ol,name(),this);
742 ol.popGeneratorState();
745 void FileDef::writeQuickMemberLinks(OutputList &ol,MemberDef *currentMd) const
747 static bool createSubDirs=Config_getBool("CREATE_SUBDIRS");
749 ol.writeString(" <div class=\"navtab\">\n");
750 ol.writeString(" <table>\n");
752 MemberList *allMemberList = getMemberList(MemberList::allMembersList);
755 MemberListIterator mli(*allMemberList);
757 for (mli.toFirst();(md=mli.current());++mli)
759 if (md->getFileDef()==this && md->getNamespaceDef()==0 && md->isLinkable())
761 ol.writeString(" <tr><td class=\"navtab\">");
762 if (md->isLinkableInProject())
764 if (md==currentMd) // selected item => highlight
766 ol.writeString("<a class=\"qindexHL\" ");
770 ol.writeString("<a class=\"qindex\" ");
772 ol.writeString("href=\"");
773 if (createSubDirs) ol.writeString("../../");
774 ol.writeString(md->getOutputFileBase()+Doxygen::htmlFileExtension+"#"+md->anchor());
775 ol.writeString("\">");
776 ol.writeString(convertToHtml(md->localName()));
777 ol.writeString("</a>");
779 ol.writeString("</td></tr>\n");
784 ol.writeString(" </table>\n");
785 ol.writeString(" </div>\n");
788 /*! Write a source listing of this file to the output */
789 void FileDef::writeSource(OutputList &ol)
791 static bool generateTreeView = Config_getBool("GENERATE_TREEVIEW");
792 static bool filterSourceFiles = Config_getBool("FILTER_SOURCE_FILES");
793 static bool latexSourceCode = Config_getBool("LATEX_SOURCE_CODE");
794 QCString title = docname;
795 if (!fileVersion.isEmpty())
797 title+=(" ("+fileVersion+")");
799 QCString pageTitle = theTranslator->trSourceFile(title);
800 ol.disable(OutputGenerator::Man);
801 ol.disable(OutputGenerator::RTF);
802 if (!latexSourceCode) ol.disable(OutputGenerator::Latex);
804 bool isDocFile = isDocumentationFile();
805 bool genSourceFile = !isDocFile && generateSourceFile();
808 startFile(ol,getSourceFileBase(),0,pageTitle,HLI_FileVisible,
810 !isDocFile && genSourceFile ? 0 : getOutputFileBase());
811 if (!generateTreeView)
813 getDirDef()->writeNavigationPath(ol);
814 ol.endQuickIndices();
816 startTitle(ol,getOutputFileBase());
817 ol.parseText(name());
818 endTitle(ol,getOutputFileBase(),title);
822 startFile(ol,getSourceFileBase(),0,pageTitle,HLI_FileVisible,FALSE,
823 !isDocFile && genSourceFile ? 0 : getOutputFileBase());
824 startTitle(ol,getSourceFileBase());
826 endTitle(ol,getSourceFileBase(),0);
833 if (latexSourceCode) ol.disable(OutputGenerator::Latex);
834 ol.startTextLink(getOutputFileBase(),0);
835 ol.parseText(theTranslator->trGotoDocumentation());
837 if (latexSourceCode) ol.enable(OutputGenerator::Latex);
840 ParserInterface *pIntf = Doxygen::parserManager->getParser(getDefFileExtension());
841 pIntf->resetCodeParserState();
842 ol.startCodeFragment();
843 pIntf->parseCode(ol,0,
844 fileToString(absFilePath(),filterSourceFiles,TRUE),
847 ol.endCodeFragment();
849 endFileWithNavPath(this,ol);
853 void FileDef::parseSource()
855 static bool filterSourceFiles = Config_getBool("FILTER_SOURCE_FILES");
856 DevNullCodeDocInterface devNullIntf;
857 ParserInterface *pIntf = Doxygen::parserManager->getParser(getDefFileExtension());
858 pIntf->resetCodeParserState();
861 fileToString(absFilePath(),filterSourceFiles,TRUE),
866 void FileDef::addMembersToMemberGroup()
868 QListIterator<MemberList> mli(m_memberLists);
870 for (mli.toFirst();(ml=mli.current());++mli)
872 if (ml->listType()&MemberList::declarationLists)
874 ::addMembersToMemberGroup(ml,&memberGroupSDict,this);
878 // add members inside sections to their groups
879 if (memberGroupSDict)
881 MemberGroupSDict::Iterator mgli(*memberGroupSDict);
883 for (;(mg=mgli.current());++mgli)
885 if (mg->allMembersInSameSection() && m_subGrouping)
887 //printf("----> addToDeclarationSection(%s)\n",mg->header().data());
888 mg->addToDeclarationSection();
894 /*! Adds member definition \a md to the list of all members of this file */
895 void FileDef::insertMember(MemberDef *md)
897 if (md->isHidden()) return;
898 //printf("%s:FileDef::insertMember(%s (=%p) list has %d elements)\n",
899 // name().data(),md->name().data(),md,allMemberList.count());
900 MemberList *allMemberList = getMemberList(MemberList::allMembersList);
901 if (allMemberList && allMemberList->findRef(md)!=-1) // TODO optimize the findRef!
906 if (allMemberList==0)
908 allMemberList = new MemberList(MemberList::allMembersList);;
909 m_memberLists.append(allMemberList);
911 allMemberList->append(md);
912 //::addFileMemberNameToIndex(md);
913 switch (md->memberType())
915 case MemberDef::Variable:
916 case MemberDef::Property:
917 addMemberToList(MemberList::decVarMembers,md);
918 addMemberToList(MemberList::docVarMembers,md);
920 case MemberDef::Function:
921 addMemberToList(MemberList::decFuncMembers,md);
922 addMemberToList(MemberList::docFuncMembers,md);
924 case MemberDef::Typedef:
925 addMemberToList(MemberList::decTypedefMembers,md);
926 addMemberToList(MemberList::docTypedefMembers,md);
928 case MemberDef::Enumeration:
929 addMemberToList(MemberList::decEnumMembers,md);
930 addMemberToList(MemberList::docEnumMembers,md);
932 case MemberDef::EnumValue: // enum values are shown inside their enums
934 case MemberDef::Define:
935 addMemberToList(MemberList::decDefineMembers,md);
936 addMemberToList(MemberList::docDefineMembers,md);
939 err("FileDef::insertMembers(): "
940 "member `%s' with class scope `%s' inserted in file scope `%s'!\n",
942 md->getClassDef() ? md->getClassDef()->name().data() : "<global>",
945 //addMemberToGroup(md,groupId);
948 /*! Adds compound definition \a cd to the list of all compounds of this file */
949 void FileDef::insertClass(ClassDef *cd)
951 if (cd->isHidden()) return;
954 classSDict = new ClassSDict(17);
956 if (Config_getBool("SORT_BRIEF_DOCS"))
957 classSDict->inSort(cd->name(),cd);
959 classSDict->append(cd->name(),cd);
962 /*! Adds namespace definition \a nd to the list of all compounds of this file */
963 void FileDef::insertNamespace(NamespaceDef *nd)
965 if (nd->isHidden()) return;
966 if (!nd->name().isEmpty() &&
967 (namespaceSDict==0 || namespaceSDict->find(nd->name())==0))
969 if (namespaceSDict==0)
971 namespaceSDict = new NamespaceSDict;
973 if (Config_getBool("SORT_BRIEF_DOCS"))
974 namespaceSDict->inSort(nd->name(),nd);
976 namespaceSDict->append(nd->name(),nd);
980 void FileDef::addSourceRef(int line,Definition *d,MemberDef *md)
982 //printf("FileDef::addSourceDef(%d,%p,%p)\n",line,d,md);
985 if (srcDefDict==0) srcDefDict = new QIntDict<Definition>(257);
986 if (srcMemberDict==0) srcMemberDict = new QIntDict<MemberDef>(257);
987 srcDefDict->insert(line,d);
988 if (md) srcMemberDict->insert(line,md);
989 //printf("Adding member %s with anchor %s at line %d to file %s\n",
990 // md?md->name().data():"<none>",md?md->anchor().data():"<none>",line,name().data());
994 Definition *FileDef::getSourceDefinition(int lineNr)
996 Definition *result=0;
999 result = srcDefDict->find(lineNr);
1004 MemberDef *FileDef::getSourceMember(int lineNr)
1006 MemberDef *result=0;
1009 result = srcMemberDict->find(lineNr);
1015 void FileDef::addUsingDirective(NamespaceDef *nd)
1017 if (usingDirList==0)
1019 usingDirList = new NamespaceSDict;
1021 if (usingDirList->find(nd->qualifiedName())==0)
1023 usingDirList->append(nd->qualifiedName(),nd);
1025 //printf("%p: FileDef::addUsingDirective: %s:%d\n",this,name().data(),usingDirList->count());
1028 NamespaceSDict *FileDef::getUsedNamespaces() const
1030 //printf("%p: FileDef::getUsedNamespace: %s:%d\n",this,name().data(),usingDirList?usingDirList->count():0);
1031 return usingDirList;
1034 void FileDef::addUsingDeclaration(Definition *d)
1036 if (usingDeclList==0)
1038 usingDeclList = new SDict<Definition>(17);
1040 if (usingDeclList->find(d->qualifiedName())==0)
1042 usingDeclList->append(d->qualifiedName(),d);
1046 void FileDef::addIncludeDependency(FileDef *fd,const char *incName,bool local,
1047 bool imported,bool indirect)
1049 //printf("FileDef::addIncludeDependency(%p,%s,%d)\n",fd,incName,local);
1050 QCString iName = fd ? fd->absFilePath().data() : incName;
1051 if (!iName.isEmpty() && (!includeDict || includeDict->find(iName)==0))
1055 includeDict = new QDict<IncludeInfo>(61);
1056 includeList = new QList<IncludeInfo>;
1057 includeList->setAutoDelete(TRUE);
1059 IncludeInfo *ii = new IncludeInfo;
1061 ii->includeName = incName;
1063 ii->imported = imported;
1064 ii->indirect = indirect;
1065 includeList->append(ii);
1066 includeDict->insert(iName,ii);
1070 void FileDef::addIncludedUsingDirectives()
1072 if (visited) return;
1074 //printf("( FileDef::addIncludedUsingDirectives for file %s\n",name().data());
1077 if (includeList) // file contains #includes
1080 QListIterator<IncludeInfo> iii(*includeList);
1082 for (iii.toFirst();(ii=iii.current());++iii) // foreach #include...
1084 if (ii->fileDef && !ii->fileDef->visited) // ...that is a known file
1086 // recurse into this file
1087 ii->fileDef->addIncludedUsingDirectives();
1092 QListIterator<IncludeInfo> iii(*includeList);
1094 // iterate through list from last to first
1095 for (iii.toLast();(ii=iii.current());--iii)
1097 if (ii->fileDef && ii->fileDef!=this)
1099 // add using directives
1100 NamespaceSDict *unl = ii->fileDef->usingDirList;
1103 NamespaceSDict::Iterator nli(*unl);
1105 for (nli.toLast();(nd=nli.current());--nli)
1107 // append each using directive found in a #include file
1108 if (usingDirList==0) usingDirList = new NamespaceSDict;
1109 //printf("Prepending used namespace %s to the list of file %s\n",
1110 // nd->name().data(),name().data());
1111 if (usingDirList->find(nd->qualifiedName())==0) // not yet added
1113 usingDirList->prepend(nd->qualifiedName(),nd);
1117 // add using declarations
1118 SDict<Definition> *udl = ii->fileDef->usingDeclList;
1121 SDict<Definition>::Iterator udi(*udl);
1123 for (udi.toLast();(d=udi.current());--udi)
1125 //printf("Adding using declaration %s\n",d->name().data());
1126 if (usingDeclList==0)
1128 usingDeclList = new SDict<Definition>(17);
1130 if (usingDeclList->find(d->qualifiedName())==0)
1132 usingDeclList->prepend(d->qualifiedName(),d);
1140 //printf(") end FileDef::addIncludedUsingDirectives for file %s\n",name().data());
1144 void FileDef::addIncludedByDependency(FileDef *fd,const char *incName,
1145 bool local,bool imported)
1147 //printf("FileDef::addIncludedByDependency(%p,%s,%d)\n",fd,incName,local);
1148 QCString iName = fd ? fd->absFilePath().data() : incName;
1149 if (!iName.isEmpty() && (includedByDict==0 || includedByDict->find(iName)==0))
1151 if (includedByDict==0)
1153 includedByDict = new QDict<IncludeInfo>(61);
1154 includedByList = new QList<IncludeInfo>;
1155 includedByList->setAutoDelete(TRUE);
1157 IncludeInfo *ii = new IncludeInfo;
1159 ii->includeName = incName;
1161 ii->imported = imported;
1162 ii->indirect = FALSE;
1163 includedByList->append(ii);
1164 includedByDict->insert(iName,ii);
1168 bool FileDef::isIncluded(const QCString &name) const
1170 if (name.isEmpty()) return FALSE;
1171 return includeDict!=0 && includeDict->find(name)!=0;
1174 bool FileDef::generateSourceFile() const
1176 QCString extension = name().right(4);
1177 return !isReference() &&
1178 (Config_getBool("SOURCE_BROWSER") ||
1179 (Config_getBool("VERBATIM_HEADERS") && guessSection(name())==Entry::HEADER_SEC)
1181 extension!=".doc" && extension!=".txt" && extension!=".dox" &&
1182 extension!=".md" && extension!=".markdown";
1186 void FileDef::addListReferences()
1189 LockingPtr< QList<ListItemInfo> > xrefItems = xrefListItems();
1190 addRefItem(xrefItems.pointer(),
1191 getOutputFileBase(),
1192 theTranslator->trFile(TRUE,TRUE),
1193 getOutputFileBase(),name(),
1197 if (memberGroupSDict)
1199 MemberGroupSDict::Iterator mgli(*memberGroupSDict);
1201 for (;(mg=mgli.current());++mgli)
1203 mg->addListReferences(this);
1206 QListIterator<MemberList> mli(m_memberLists);
1208 for (mli.toFirst();(ml=mli.current());++mli)
1210 if (ml->listType()&MemberList::documentationLists)
1212 ml->addListReferences(this);
1217 //-------------------------------------------------------------------
1219 static int findMatchingPart(const QCString &path,const QCString dir)
1223 while ((si1=path.find('/',pos1))!=-1)
1225 int si2=dir.find('/',pos2);
1226 //printf(" found slash at pos %d in path %d: %s<->%s\n",si1,si2,
1227 // path.mid(pos1,si1-pos2).data(),dir.mid(pos2).data());
1228 if (si2==-1 && path.mid(pos1,si1-pos2)==dir.mid(pos2)) // match at end
1230 return dir.length();
1232 if (si1!=si2 || path.mid(pos1,si1-pos2)!=dir.mid(pos2,si2-pos2)) // no match in middle
1234 return QMAX(pos1-1,0);
1242 static Directory *findDirNode(Directory *root,const QCString &name)
1244 QListIterator<DirEntry> dli(root->children());
1246 for (dli.toFirst();(de=dli.current());++dli)
1248 if (de->kind()==DirEntry::Dir)
1250 Directory *dir = (Directory *)de;
1251 QCString dirName=dir->name();
1252 int sp=findMatchingPart(name,dirName);
1253 //printf("findMatchingPart(%s,%s)=%d\n",name.data(),dirName.data(),sp);
1254 if (sp>0) // match found
1256 if ((uint)sp==dirName.length()) // whole directory matches
1258 // recurse into the directory
1259 return findDirNode(dir,name.mid(dirName.length()+1));
1261 else // partial match => we need to split the path into three parts
1263 QCString baseName =dirName.left(sp);
1264 QCString oldBranchName=dirName.mid(sp+1);
1265 QCString newBranchName=name.mid(sp+1);
1266 // strip file name from path
1267 int newIndex=newBranchName.findRev('/');
1268 if (newIndex>0) newBranchName=newBranchName.left(newIndex);
1270 //printf("Splitting off part in new branch \n"
1271 // "base=%s old=%s new=%s\n",
1273 // oldBranchName.data(),
1274 // newBranchName.data()
1276 Directory *base = new Directory(root,baseName);
1277 Directory *newBranch = new Directory(base,newBranchName);
1278 dir->reParent(base);
1279 dir->rename(oldBranchName);
1280 base->addChild(dir);
1281 base->addChild(newBranch);
1282 dir->setLast(FALSE);
1283 // remove DirEntry container from list (without deleting it)
1284 root->children().setAutoDelete(FALSE);
1285 root->children().removeRef(dir);
1286 root->children().setAutoDelete(TRUE);
1287 // add new branch to the root
1288 if (!root->children().isEmpty())
1290 root->children().last()->setLast(FALSE);
1292 root->addChild(base);
1298 int si=name.findRev('/');
1299 if (si==-1) // no subdir
1301 return root; // put the file under the root node.
1303 else // need to create a subdir
1305 QCString baseName = name.left(si);
1306 //printf("new subdir %s\n",baseName.data());
1307 Directory *newBranch = new Directory(root,baseName);
1308 if (!root->children().isEmpty())
1310 root->children().last()->setLast(FALSE);
1312 root->addChild(newBranch);
1317 static void mergeFileDef(Directory *root,FileDef *fd)
1319 QCString rootPath = root->name();
1320 QCString filePath = fd->absFilePath();
1321 //printf("merging %s\n",filePath.data());
1322 Directory *dirNode = findDirNode(root,filePath);
1323 if (!dirNode->children().isEmpty())
1325 dirNode->children().last()->setLast(FALSE);
1327 DirEntry *e=new DirEntry(dirNode,fd);
1328 dirNode->addChild(e);
1332 static void generateIndent(QTextStream &t,DirEntry *de,int level)
1336 generateIndent(t,de->parent(),level+1);
1338 // from the root up to node n do...
1339 if (level==0) // item before a dir or document
1343 if (de->kind()==DirEntry::Dir)
1345 t << "<img " << FTV_IMGATTRIBS(plastnode) << "/>";
1349 t << "<img " << FTV_IMGATTRIBS(lastnode) << "/>";
1354 if (de->kind()==DirEntry::Dir)
1356 t << "<img " << FTV_IMGATTRIBS(pnode) << "/>";
1360 t << "<img " << FTV_IMGATTRIBS(node) << "/>";
1364 else // item at another level
1368 t << "<img " << FTV_IMGATTRIBS(blank) << "/>";
1372 t << "<img " << FTV_IMGATTRIBS(vertline) << "/>";
1377 static void writeDirTreeNode(QTextStream &t,Directory *root,int level)
1380 indent.fill(' ',level*2);
1381 QListIterator<DirEntry> dli(root->children());
1383 for (dli.toFirst();(de=dli.current());++dli)
1385 t << indent << "<p>";
1386 generateIndent(t,de,0);
1387 if (de->kind()==DirEntry::Dir)
1389 Directory *dir=(Directory *)de;
1390 //printf("%s [dir]: %s (last=%d,dir=%d)\n",indent.data(),dir->name().data(),dir->isLast(),dir->kind()==DirEntry::Dir);
1391 t << "<img " << FTV_IMGATTRIBS(folderclosed) << "/>";
1394 t << indent << "<div>\n";
1395 writeDirTreeNode(t,dir,level+1);
1396 t << indent << "</div>\n";
1400 //printf("%s [file]: %s (last=%d,dir=%d)\n",indent.data(),de->file()->name().data(),de->isLast(),de->kind()==DirEntry::Dir);
1401 t << "<img " << FTV_IMGATTRIBS(doc) << "/>";
1402 t << de->file()->name();
1409 static void addDirsAsGroups(Directory *root,GroupDef *parent,int level)
1412 if (root->kind()==DirEntry::Dir)
1414 gd = new GroupDef("[generated]",
1416 root->path(), // name
1417 root->name() // title
1421 parent->addGroup(gd);
1422 gd->makePartOfGroup(parent);
1426 Doxygen::groupSDict->append(root->path(),gd);
1429 QListIterator<DirEntry> dli(root->children());
1431 for (dli.toFirst();(de=dli.current());++dli)
1433 if (de->kind()==DirEntry::Dir)
1435 addDirsAsGroups((Directory *)de,gd,level+1);
1440 void generateFileTree()
1442 Directory *root=new Directory(0,"root");
1443 root->setLast(TRUE);
1444 FileNameListIterator fnli(*Doxygen::inputNameList);
1446 for (fnli.toFirst();(fn=fnli.current());++fnli)
1448 FileNameIterator fni(*fn);
1450 for (;(fd=fni.current());++fni)
1452 mergeFileDef(root,fd);
1455 //t << "<div class=\"directory\">\n";
1456 //writeDirTreeNode(t,root,0);
1458 addDirsAsGroups(root,0,0);
1462 //-------------------------------------------------------------------
1464 void FileDef::combineUsingRelations()
1466 if (visited) return; // already done
1470 NamespaceSDict::Iterator nli(*usingDirList);
1472 for (nli.toFirst();(nd=nli.current());++nli)
1474 nd->combineUsingRelations();
1476 for (nli.toFirst();(nd=nli.current());++nli)
1478 // add used namespaces of namespace nd to this namespace
1479 if (nd->getUsedNamespaces())
1481 NamespaceSDict::Iterator unli(*nd->getUsedNamespaces());
1483 for (unli.toFirst();(und=unli.current());++unli)
1485 //printf("Adding namespace %s to the using list of %s\n",und->qualifiedName().data(),qualifiedName().data());
1486 addUsingDirective(und);
1489 // add used classes of namespace nd to this namespace
1490 if (nd->getUsedClasses())
1492 SDict<Definition>::Iterator cli(*nd->getUsedClasses());
1494 for (cli.toFirst();(ucd=cli.current());++cli)
1496 //printf("Adding class %s to the using list of %s\n",cd->qualifiedName().data(),qualifiedName().data());
1497 addUsingDeclaration(ucd);
1504 bool FileDef::isDocumentationFile() const
1506 return name().right(4)==".doc" ||
1507 name().right(4)==".txt" ||
1508 name().right(4)==".dox" ||
1509 name().right(3)==".md" ||
1510 name().right(9)==".markdown";
1513 void FileDef::acquireFileVersion()
1515 QCString vercmd = Config_getString("FILE_VERSION_FILTER");
1516 if (!vercmd.isEmpty() && !filepath.isEmpty() && filepath!="generated")
1518 msg("Version of %s : ",filepath.data());
1519 QCString cmd = vercmd+" \""+filepath+"\"";
1520 Debug::print(Debug::ExtCmd,0,"Executing popen(`%s`)\n",cmd.data());
1521 FILE *f=portable_popen(cmd,"r");
1524 err("error: could not execute %s\n",vercmd.data());
1527 const int bufSize=1024;
1529 int numRead = fread(buf,1,bufSize,f);
1531 if (numRead>0 && !(fileVersion=QCString(buf,numRead).stripWhiteSpace()).isEmpty())
1533 msg("%s\n",fileVersion.data());
1537 msg("no version available\n");
1543 QCString FileDef::getSourceFileBase() const
1545 if (Htags::useHtags)
1547 return Htags::path2URL(filepath);
1551 return convertNameToFile(diskname)+"_source";
1555 /*! Returns the name of the verbatim copy of this file (if any). */
1556 QCString FileDef::includeName() const
1558 if (Htags::useHtags)
1560 return Htags::path2URL(filepath);
1564 return convertNameToFile(diskname)+"_source";
1568 MemberList *FileDef::createMemberList(MemberList::ListType lt)
1570 m_memberLists.setAutoDelete(TRUE);
1571 QListIterator<MemberList> mli(m_memberLists);
1573 for (mli.toFirst();(ml=mli.current());++mli)
1575 if (ml->listType()==lt)
1580 // not found, create a new member list
1581 ml = new MemberList(lt);
1582 m_memberLists.append(ml);
1586 void FileDef::addMemberToList(MemberList::ListType lt,MemberDef *md)
1588 static bool sortBriefDocs = Config_getBool("SORT_BRIEF_DOCS");
1589 static bool sortMemberDocs = Config_getBool("SORT_MEMBER_DOCS");
1590 MemberList *ml = createMemberList(lt);
1591 ml->setNeedsSorting(
1592 ((ml->listType()&MemberList::declarationLists) && sortBriefDocs) ||
1593 ((ml->listType()&MemberList::documentationLists) && sortMemberDocs));
1596 if (ml->needsSorting())
1601 if (lt&MemberList::documentationLists)
1603 ml->setInFile(TRUE);
1605 if (ml->listType()&MemberList::declarationLists) md->setSectionList(this,ml);
1608 void FileDef::sortMemberLists()
1610 MemberList *ml = m_memberLists.first();
1613 if (ml->needsSorting()) { ml->sort(); ml->setNeedsSorting(FALSE); }
1614 ml = m_memberLists.next();
1618 MemberList *FileDef::getMemberList(MemberList::ListType lt) const
1620 FileDef *that = (FileDef*)this;
1621 MemberList *ml = that->m_memberLists.first();
1624 if (ml->listType()==lt)
1628 ml = that->m_memberLists.next();
1633 void FileDef::writeMemberDeclarations(OutputList &ol,MemberList::ListType lt,const QCString &title)
1635 static bool optVhdl = Config_getBool("OPTIMIZE_OUTPUT_VHDL");
1636 MemberList * ml = getMemberList(lt);
1639 if (optVhdl) // use specific declarations function
1642 VhdlDocGen::writeVhdlDeclarations(ml,ol,0,0,this,0);
1646 ml->writeDeclarations(ol,0,0,this,0,title,0);
1651 void FileDef::writeMemberDocumentation(OutputList &ol,MemberList::ListType lt,const QCString &title)
1653 MemberList * ml = getMemberList(lt);
1654 if (ml) ml->writeDocumentation(ol,name(),this,title);
1657 bool FileDef::isLinkableInProject() const
1659 static bool showFiles = Config_getBool("SHOW_FILES");
1660 return hasDocumentation() && !isReference() && showFiles;
1664 bool FileDef::includes(FileDef *incFile,QDict<FileDef> *includedFiles) const
1666 //printf("%s::includes(%s)\n",name().data(),incFile->name().data());
1667 if (incFile==this) return TRUE;
1668 includedFiles->insert(absFilePath(),this);
1671 QListIterator<IncludeInfo> ili(*includeList);
1673 for (;(ii=ili.current());++ili)
1675 //printf("ii=%s\n",ii->includeName.data());
1677 includedFiles->find(ii->fileDef->absFilePath())==0 &&
1678 ii->fileDef->includes(incFile,includedFiles)
1680 incFile->absFilePath()==ii->includeName
1687 bool FileDef::includesByName(const QCString &fileName) const
1691 QListIterator<IncludeInfo> ili(*includeList);
1693 for (;(ii=ili.current());++ili)
1695 //printf("ii=%s\n",ii->includeName.data());
1696 if (fileName==ii->includeName) return TRUE;