1 /******************************************************************************
5 * Copyright (C) 1997-2014 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.
25 #include "definition.h"
29 #include "outputlist.h"
36 #include "parserintf.h"
39 #include "vhdldocgen.h"
40 #include "memberlist.h"
41 #include "namespacedef.h"
45 #define START_MARKER 0x4445465B // DEF[
46 #define END_MARKER 0x4445465D // DEF]
48 //-----------------------------------------------------------------------------------------
51 /** Private data associated with a Symbol Definition object. */
57 void init(const char *df, const char *n);
59 SectionDict *sectionDict; // dictionary of all sections, not accessible
61 MemberSDict *sourceRefByDict;
62 MemberSDict *sourceRefsDict;
63 QList<ListItemInfo> *xrefListItems;
64 GroupList *partOfGroups;
66 DocInfo *details; // not exported
67 DocInfo *inbodyDocs; // not exported
68 BriefInfo *brief; // not exported
69 BodyInfo *body; // not exported
70 QCString briefSignatures;
71 QCString docSignatures;
73 QCString localName; // local (unqualified) name of the definition
74 // in the future m_name should become m_localName
75 QCString qualifiedName;
76 QCString ref; // reference to external documentation
81 Definition *outerScope; // not owner
83 // where the item was found
89 QCString id; // clang unique id
92 DefinitionImpl::DefinitionImpl()
93 : sectionDict(0), sourceRefByDict(0), sourceRefsDict(0),
94 xrefListItems(0), partOfGroups(0),
95 details(0), inbodyDocs(0), brief(0), body(0),
100 DefinitionImpl::~DefinitionImpl()
103 delete sourceRefByDict;
104 delete sourceRefsDict;
106 delete xrefListItems;
113 void DefinitionImpl::init(const char *df, const char *n)
116 int lastDot = defFileName.findRev('.');
119 defFileExt = defFileName.mid(lastDot);
122 if (name!="<globalScope>")
124 //extractNamespaceName(m_name,m_localName,ns);
125 localName=stripScope(n);
131 //printf("m_localName=%s\n",m_localName.data());
140 outerScope = Doxygen::globalScope;
144 isArtificial = FALSE;
145 lang = SrcLangExt_Unknown;
148 //-----------------------------------------------------------------------------------------
150 static bool matchExcludedSymbols(const char *name)
152 static QStrList &exclSyms = Config_getList("EXCLUDE_SYMBOLS");
153 if (exclSyms.count()==0) return FALSE; // nothing specified
154 const char *pat = exclSyms.first();
155 QCString symName = name;
158 QCString pattern = pat;
159 bool forceStart=FALSE;
161 if (pattern.at(0)=='^')
162 pattern=pattern.mid(1),forceStart=TRUE;
163 if (pattern.at(pattern.length()-1)=='$')
164 pattern=pattern.left(pattern.length()-1),forceEnd=TRUE;
165 if (pattern.find('*')!=-1) // wildcard mode
167 QRegExp re(substitute(pattern,"*",".*"),TRUE);
169 i = re.match(symName,0,&pl);
170 //printf(" %d = re.match(%s) pattern=%s\n",i,symName.data(),pattern.data());
171 if (i!=-1) // wildcard match
173 int sl=symName.length();
174 // check if it is a whole word match
175 if ((i==0 || pattern.at(0)=='*' || (!isId(symName.at(i-1)) && !forceStart)) &&
176 (i+pl==sl || pattern.at(i+pl)=='*' || (!isId(symName.at(i+pl)) && !forceEnd))
179 //printf("--> name=%s pattern=%s match at %d\n",symName.data(),pattern.data(),i);
184 else if (!pattern.isEmpty()) // match words
186 int i = symName.find(pattern);
187 if (i!=-1) // we have a match!
189 int pl=pattern.length();
190 int sl=symName.length();
191 // check if it is a whole word match
192 if ((i==0 || (!isId(symName.at(i-1)) && !forceStart)) &&
193 (i+pl==sl || (!isId(symName.at(i+pl)) && !forceEnd))
196 //printf("--> name=%s pattern=%s match at %d\n",symName.data(),pattern.data(),i);
201 pat = exclSyms.next();
203 //printf("--> name=%s: no match\n",name);
207 void Definition::addToMap(const char *name,Definition *d)
209 bool vhdlOpt = Config_getBool("OPTIMIZE_OUTPUT_VHDL");
210 QCString symbolName = name;
211 int index=computeQualifiedIndex(symbolName);
212 if (!vhdlOpt && index!=-1) symbolName=symbolName.mid(index+2);
213 if (!symbolName.isEmpty())
215 //printf("******* adding symbol `%s' (%p)\n",symbolName.data(),d);
216 DefinitionIntf *di=Doxygen::symbolMap->find(symbolName);
217 //printf(" addToMap(%p): looking for symbol %s: %p\n",d,symbolName.data(),di);
218 if (di==0) // new Symbol
220 //printf(" new symbol!\n");
221 Doxygen::symbolMap->insert(symbolName,d);
223 else // existing symbol
225 //printf(" existing symbol: ");
226 if (di->definitionType()==DefinitionIntf::TypeSymbolList) // already multiple symbols
228 //printf("adding to exiting list\n");
229 DefinitionList *dl = (DefinitionList*)di;
232 else // going from one to two symbols
234 Doxygen::symbolMap->take(symbolName);
235 DefinitionList *dl = new DefinitionList;
236 //printf("replacing symbol by list %p with elements %p and %p\n",dl,di,d);
237 dl->append((Definition*)di);
239 Doxygen::symbolMap->insert(symbolName,dl);
243 // auto resize if needed
244 static int sizeIndex=9;
245 if (Doxygen::symbolMap->size()>SDict_primes[sizeIndex])
247 Doxygen::symbolMap->resize(SDict_primes[++sizeIndex]);
250 d->_setSymbolName(symbolName);
254 void Definition::removeFromMap(Definition *d)
256 QCString symbolName = d->m_symbolName;
257 if (!symbolName.isEmpty())
259 //printf("******* removing symbol `%s' (%p)\n",symbolName.data(),d);
260 DefinitionIntf *di=Doxygen::symbolMap->find(symbolName);
263 if (di!=d) // symbolName not unique
265 //printf(" removing from list: %p!\n",di);
266 DefinitionList *dl = (DefinitionList*)di;
267 bool b = dl->removeRef(d);
271 Doxygen::symbolMap->take(symbolName);
274 else // symbolName unique
276 //printf(" removing symbol %p\n",di);
277 Doxygen::symbolMap->take(symbolName);
283 Definition::Definition(const char *df,int dl,int dc,
284 const char *name,const char *b,
285 const char *d,bool isSymbol)
290 m_impl = new DefinitionImpl;
291 m_impl->init(df,name);
292 m_isSymbol = isSymbol;
293 if (isSymbol) addToMap(name,this);
294 _setBriefDescription(b,df,dl);
295 _setDocumentation(d,df,dl,TRUE,FALSE);
296 if (matchExcludedSymbols(name))
298 m_impl->hidden = TRUE;
302 Definition::Definition(const Definition &d) : DefinitionIntf()
305 m_defLine = d.m_defLine;
306 m_impl = new DefinitionImpl;
308 m_impl->sectionDict = 0;
309 m_impl->sourceRefByDict = 0;
310 m_impl->sourceRefsDict = 0;
311 m_impl->partOfGroups = 0;
312 m_impl->xrefListItems = 0;
316 m_impl->inbodyDocs = 0;
317 if (d.m_impl->sectionDict)
319 m_impl->sectionDict = new SectionDict(17);
320 SDict<SectionInfo>::Iterator it(*d.m_impl->sectionDict);
322 for (it.toFirst();(si=it.current());++it)
324 m_impl->sectionDict->append(si->label,si);
327 if (d.m_impl->sourceRefByDict)
329 m_impl->sourceRefByDict = new MemberSDict;
330 MemberSDict::IteratorDict it(*d.m_impl->sourceRefByDict);
332 for (it.toFirst();(md=it.current());++it)
334 m_impl->sourceRefByDict->append(it.currentKey(),md);
337 if (d.m_impl->sourceRefsDict)
339 m_impl->sourceRefsDict = new MemberSDict;
340 MemberSDict::IteratorDict it(*d.m_impl->sourceRefsDict);
342 for (it.toFirst();(md=it.current());++it)
344 m_impl->sourceRefsDict->append(it.currentKey(),md);
347 if (d.m_impl->partOfGroups)
349 GroupListIterator it(*d.m_impl->partOfGroups);
351 for (it.toFirst();(gd=it.current());++it)
356 if (d.m_impl->xrefListItems)
358 setRefItems(d.m_impl->xrefListItems);
362 m_impl->brief = new BriefInfo(*d.m_impl->brief);
364 if (d.m_impl->details)
366 m_impl->details = new DocInfo(*d.m_impl->details);
370 m_impl->body = new BodyInfo(*d.m_impl->body);
372 if (d.m_impl->inbodyDocs)
374 m_impl->details = new DocInfo(*d.m_impl->inbodyDocs);
377 m_isSymbol = d.m_isSymbol;
378 if (m_isSymbol) addToMap(m_name,this);
381 Definition::~Definition()
394 void Definition::setName(const char *name)
400 void Definition::setId(const char *id)
404 if (Doxygen::clangUsrMap)
406 //printf("Definition::setId '%s'->'%s'\n",id,m_name.data());
407 Doxygen::clangUsrMap->insert(id,this);
411 QCString Definition::id() const
416 void Definition::addSectionsToDefinition(QList<SectionInfo> *anchorList)
418 if (!anchorList) return;
419 //printf("%s: addSectionsToDefinition(%d)\n",name().data(),anchorList->count());
420 QListIterator<SectionInfo> it(*anchorList);
422 for (;(si=it.current());++it)
424 //printf("Add section `%s' to definition `%s'\n",
425 // si->label.data(),name().data());
426 SectionInfo *gsi=Doxygen::sectionDict->find(si->label);
427 //printf("===== label=%s gsi=%p\n",si->label.data(),gsi);
430 gsi = new SectionInfo(*si);
431 Doxygen::sectionDict->append(si->label,gsi);
433 if (m_impl->sectionDict==0)
435 m_impl->sectionDict = new SectionDict(17);
437 if (m_impl->sectionDict->find(gsi->label)==0)
439 m_impl->sectionDict->append(gsi->label,gsi);
440 gsi->definition = this;
445 bool Definition::hasSections() const
447 //printf("Definition::hasSections(%s) #sections=%d\n",name().data(),
448 // m_impl->sectionDict ? m_impl->sectionDict->count() : 0);
449 if (m_impl->sectionDict==0) return FALSE;
450 SDict<SectionInfo>::Iterator li(*m_impl->sectionDict);
452 for (li.toFirst();(si=li.current());++li)
454 if (si->type==SectionInfo::Section ||
455 si->type==SectionInfo::Subsection ||
456 si->type==SectionInfo::Subsubsection ||
457 si->type==SectionInfo::Paragraph)
465 void Definition::addSectionsToIndex()
467 if (m_impl->sectionDict==0) return;
468 //printf("Definition::addSectionsToIndex()\n");
469 SDict<SectionInfo>::Iterator li(*m_impl->sectionDict);
472 for (li.toFirst();(si=li.current());++li)
474 if (si->type==SectionInfo::Section ||
475 si->type==SectionInfo::Subsection ||
476 si->type==SectionInfo::Subsubsection ||
477 si->type==SectionInfo::Paragraph)
479 //printf(" level=%d title=%s\n",level,si->title.data());
480 int nextLevel = (int)si->type;
484 for (i=level;i<nextLevel;i++)
486 Doxygen::indexList->incContentsDepth();
489 else if (nextLevel<level)
491 for (i=nextLevel;i<level;i++)
493 Doxygen::indexList->decContentsDepth();
496 QCString title = si->title;
497 if (title.isEmpty()) title = si->label;
498 Doxygen::indexList->addContentsItem(TRUE,title,
509 Doxygen::indexList->decContentsDepth();
514 void Definition::writeDocAnchorsToTagFile()
516 if (!Config_getString("GENERATE_TAGFILE").isEmpty() && m_impl->sectionDict)
518 //printf("%s: writeDocAnchorsToTagFile(%d)\n",name().data(),m_impl->sectionDict->count());
519 SDict<SectionInfo>::Iterator sdi(*m_impl->sectionDict);
521 for (;(si=sdi.current());++sdi)
525 //printf("write an entry!\n");
526 if (definitionType()==TypeMember) Doxygen::tagFile << " ";
527 Doxygen::tagFile << " <docanchor file=\""
528 << si->fileName << "\"";
529 if (!si->title.isEmpty())
531 Doxygen::tagFile << " title=\"" << convertToXML(si->title) << "\"";
533 Doxygen::tagFile << ">" << si->label
534 << "</docanchor>" << endl;
540 bool Definition::_docsAlreadyAdded(const QCString &doc,QCString &sigList)
544 // to avoid mismatches due to differences in indenting, we first remove
545 // double whitespaces...
546 QCString docStr = doc.simplifyWhiteSpace();
547 MD5Buffer((const unsigned char *)docStr.data(),docStr.length(),md5_sig);
548 MD5SigToString(md5_sig,sigStr.data(),33);
549 //printf("%s:_docsAlreadyAdded doc='%s' sig='%s' docSigs='%s'\n",
550 // name().data(),doc.data(),sigStr.data(),sigList.data());
551 if (sigList.find(sigStr)==-1) // new docs, add signature to prevent re-adding it
562 void Definition::_setDocumentation(const char *d,const char *docFile,int docLine,
563 bool stripWhiteSpace,bool atTop)
565 //printf("%s::setDocumentation(%s,%s,%d,%d)\n",name().data(),d,docFile,docLine,stripWhiteSpace);
570 doc = stripLeadingAndTrailingEmptyLines(doc,docLine);
572 else // don't strip whitespace
576 if (!_docsAlreadyAdded(doc,m_impl->docSignatures))
578 //printf("setting docs for %s: `%s'\n",name().data(),m_doc.data());
579 if (m_impl->details==0)
581 m_impl->details = new DocInfo;
583 if (m_impl->details->doc.isEmpty()) // fresh detailed description
585 m_impl->details->doc = doc;
587 else if (atTop) // another detailed description, append it to the start
589 m_impl->details->doc = doc+"\n\n"+m_impl->details->doc;
591 else // another detailed description, append it to the end
593 m_impl->details->doc += "\n\n"+doc;
595 if (docLine!=-1) // store location if valid
597 m_impl->details->file = docFile;
598 m_impl->details->line = docLine;
602 m_impl->details->file = docFile;
603 m_impl->details->line = 1;
608 void Definition::setDocumentation(const char *d,const char *docFile,int docLine,bool stripWhiteSpace)
611 _setDocumentation(d,docFile,docLine,stripWhiteSpace,FALSE);
614 #define uni_isupper(c) (QChar(c).category()==QChar::Letter_Uppercase)
616 // do a UTF-8 aware search for the last real character and return TRUE
617 // if that is a multibyte one.
618 static bool lastCharIsMultibyte(const QCString &s)
623 while ((p=nextUtf8CharPosition(s,l,p))<l) pp=p;
624 if (pp==-1 || ((uchar)s[pp])<0x80) return FALSE;
628 void Definition::_setBriefDescription(const char *b,const char *briefFile,int briefLine)
630 static QCString outputLanguage = Config_getEnum("OUTPUT_LANGUAGE");
631 static bool needsDot = outputLanguage!="Japanese" &&
632 outputLanguage!="Chinese" &&
633 outputLanguage!="Korean";
635 brief = brief.stripWhiteSpace();
636 if (brief.isEmpty()) return;
637 int bl = brief.length();
638 if (bl>0 && needsDot) // add punctuation if needed
640 int c = brief.at(bl-1);
643 case '.': case '!': case '?': case '>': case ':': case ')': break;
645 if (uni_isupper(brief.at(0)) && !lastCharIsMultibyte(brief)) brief+='.';
650 if (!_docsAlreadyAdded(brief,m_impl->briefSignatures))
652 if (m_impl->brief && !m_impl->brief->doc.isEmpty())
654 //printf("adding to details\n");
655 _setDocumentation(brief,briefFile,briefLine,FALSE,TRUE);
659 //fprintf(stderr,"Definition::setBriefDescription(%s,%s,%d)\n",b,briefFile,briefLine);
660 if (m_impl->brief==0)
662 m_impl->brief = new BriefInfo;
664 m_impl->brief->doc=brief;
667 m_impl->brief->file = briefFile;
668 m_impl->brief->line = briefLine;
672 m_impl->brief->file = briefFile;
673 m_impl->brief->line = 1;
679 //printf("do nothing!\n");
683 void Definition::setBriefDescription(const char *b,const char *briefFile,int briefLine)
686 _setBriefDescription(b,briefFile,briefLine);
689 void Definition::_setInbodyDocumentation(const char *doc,const char *inbodyFile,int inbodyLine)
691 if (m_impl->inbodyDocs==0)
693 m_impl->inbodyDocs = new DocInfo;
695 if (m_impl->inbodyDocs->doc.isEmpty()) // fresh inbody docs
697 m_impl->inbodyDocs->doc = doc;
698 m_impl->inbodyDocs->file = inbodyFile;
699 m_impl->inbodyDocs->line = inbodyLine;
701 else // another inbody documentation fragment, append this to the end
703 m_impl->inbodyDocs->doc += QCString("\n\n")+doc;
707 void Definition::setInbodyDocumentation(const char *d,const char *inbodyFile,int inbodyLine)
710 _setInbodyDocumentation(d,inbodyFile,inbodyLine);
713 /*! Reads a fragment of code from file \a fileName starting at
714 * line \a startLine and ending at line \a endLine (inclusive). The fragment is
715 * stored in \a result. If FALSE is returned the code fragment could not be
718 * The file is scanned for a opening bracket ('{') from \a startLine onward
719 * The line actually containing the bracket is returned via startLine.
720 * The file is scanned for a closing bracket ('}') from \a endLine backward.
721 * The line actually containing the bracket is returned via endLine.
722 * Note that for VHDL code the bracket search is not done.
724 bool readCodeFragment(const char *fileName,
725 int &startLine,int &endLine,QCString &result)
727 static bool filterSourceFiles = Config_getBool("FILTER_SOURCE_FILES");
728 static int tabSize = Config_getInt("TAB_SIZE");
729 //printf("readCodeFragment(%s,%d,%d)\n",fileName,startLine,endLine);
730 if (fileName==0 || fileName[0]==0) return FALSE; // not a valid file name
731 QCString filter = getFileFilter(fileName,TRUE);
733 bool usePipe = !filter.isEmpty() && filterSourceFiles;
734 SrcLangExt lang = getLanguageFromFileName(fileName);
735 if (!usePipe) // no filter given or wanted
737 f = portable_fopen(fileName,"r");
741 QCString cmd=filter+" \""+fileName+"\"";
742 Debug::print(Debug::ExtCmd,0,"Executing popen(`%s`)\n",cmd.data());
743 f = portable_popen(cmd,"r");
745 bool found = lang==SrcLangExt_VHDL ||
746 lang==SrcLangExt_Tcl ||
747 lang==SrcLangExt_Python ||
748 lang==SrcLangExt_Fortran;
749 // for VHDL, TCL, Python, and Fortran no bracket search is possible
755 // skip until the startLine has reached
756 while (lineNr<startLine && !feof(f))
758 while ((c=fgetc(f))!='\n' && c!=EOF) /* skip */;
763 // skip until the opening bracket or lonely : is found
765 while (lineNr<=endLine && !feof(f) && !found)
768 while ((c=fgetc(f))!='{' && c!=':' && c!=EOF)
770 //printf("parsing char `%c'\n",c);
777 col+=tabSize - (col%tabSize);
779 else if (pc=='/' && c=='/') // skip single line comment
781 while ((c=fgetc(f))!='\n' && c!=EOF) pc=c;
782 if (c=='\n') lineNr++,col=0;
784 else if (pc=='/' && c=='*') // skip C style comment
786 while (((c=fgetc(f))!='/' || pc!='*') && c!=EOF)
788 if (c=='\n') lineNr++,col=0;
801 if (cn!=':') found=TRUE;
803 else if (c=='{') // } so vi matching brackets has no problem
808 //printf(" -> readCodeFragment(%s,%d,%d) lineNr=%d\n",fileName,startLine,endLine,lineNr);
811 // For code with more than one line,
812 // fill the line with spaces until we are at the right column
813 // so that the opening brace lines up with the closing brace
814 if (endLine!=startLine)
817 spaces.fill(' ',col);
820 // copy until end of line
826 if (cn=='\n') lineNr++;
828 const int maxLineLength=4096;
829 char lineStr[maxLineLength];
832 //printf("reading line %d in range %d-%d\n",lineNr,startLine,endLine);
836 // read up to maxLineLength-1 bytes, the last byte being zero
837 char *p = fgets(lineStr, maxLineLength,f);
838 //printf(" read %s",p);
841 size_read=qstrlen(p);
849 } while (size_read == (maxLineLength-1));
852 } while (lineNr<=endLine && !feof(f));
854 // strip stuff after closing bracket
855 int newLineIndex = result.findRev('\n');
856 int braceIndex = result.findRev('}');
857 if (braceIndex > newLineIndex)
859 result.truncate(braceIndex+1);
867 Debug::print(Debug::FilterOutput, 0, "Filter output\n");
868 Debug::print(Debug::FilterOutput,0,"-------------\n%s\n-------------\n",result.data());
875 result = transcodeCharacterStringToUTF8(result);
876 //fprintf(stderr,"readCodeFragement(%d-%d)=%s\n",startLine,endLine,result.data());
880 QCString Definition::getSourceFileBase() const
882 ASSERT(definitionType()!=Definition::TypeFile); // file overloads this method
884 static bool sourceBrowser = Config_getBool("SOURCE_BROWSER");
886 m_impl->body && m_impl->body->startLine!=-1 && m_impl->body->fileDef)
888 fn = m_impl->body->fileDef->getSourceFileBase();
893 QCString Definition::getSourceAnchor() const
896 if (m_impl->body && m_impl->body->startLine!=-1)
900 anchorStr.sprintf("L%d",m_impl->body->startLine);
904 anchorStr.sprintf("l%05d",m_impl->body->startLine);
910 /*! Write a reference to the source code defining this definition */
911 void Definition::writeSourceDef(OutputList &ol,const char *)
913 static bool latexSourceCode = Config_getBool("LATEX_SOURCE_CODE");
914 ol.pushGeneratorState();
915 //printf("Definition::writeSourceRef %d %p\n",bodyLine,bodyDef);
916 QCString fn = getSourceFileBase();
919 QCString refText = theTranslator->trDefinedAtLineInSourceFile();
920 int lineMarkerPos = refText.find("@0");
921 int fileMarkerPos = refText.find("@1");
922 if (lineMarkerPos!=-1 && fileMarkerPos!=-1) // should always pass this.
925 lineStr.sprintf("%d",m_impl->body->startLine);
926 QCString anchorStr = getSourceAnchor();
928 if (lineMarkerPos<fileMarkerPos) // line marker before file marker
930 // write text left from linePos marker
931 ol.parseText(refText.left(lineMarkerPos));
932 ol.pushGeneratorState();
933 ol.disable(OutputGenerator::RTF);
934 ol.disable(OutputGenerator::Man);
935 if (!latexSourceCode)
937 ol.disable(OutputGenerator::Latex);
939 // write line link (HTML, LaTeX optionally)
940 ol.writeObjectLink(0,fn,anchorStr,lineStr);
942 ol.disable(OutputGenerator::Html);
945 ol.disable(OutputGenerator::Latex);
947 // write normal text (Man/RTF, Latex optionally)
949 ol.popGeneratorState();
951 // write text between markers
952 ol.parseText(refText.mid(lineMarkerPos+2,
953 fileMarkerPos-lineMarkerPos-2));
955 ol.pushGeneratorState();
956 ol.disable(OutputGenerator::RTF);
957 ol.disable(OutputGenerator::Man);
958 if (!latexSourceCode)
960 ol.disable(OutputGenerator::Latex);
962 // write file link (HTML, LaTeX optionally)
963 ol.writeObjectLink(0,fn,0,m_impl->body->fileDef->name());
965 ol.disable(OutputGenerator::Html);
968 ol.disable(OutputGenerator::Latex);
970 // write normal text (Man/RTF, Latex optionally)
971 ol.docify(m_impl->body->fileDef->name());
972 ol.popGeneratorState();
974 // write text right from file marker
975 ol.parseText(refText.right(
976 refText.length()-fileMarkerPos-2));
978 else // file marker before line marker
980 // write text left from file marker
981 ol.parseText(refText.left(fileMarkerPos));
982 ol.pushGeneratorState();
983 ol.disable(OutputGenerator::RTF);
984 ol.disable(OutputGenerator::Man);
985 if (!latexSourceCode)
987 ol.disable(OutputGenerator::Latex);
989 // write file link (HTML only)
990 ol.writeObjectLink(0,fn,0,m_impl->body->fileDef->name());
992 ol.disable(OutputGenerator::Html);
995 ol.disable(OutputGenerator::Latex);
997 // write normal text (Latex/Man only)
998 ol.docify(m_impl->body->fileDef->name());
999 ol.popGeneratorState();
1001 // write text between markers
1002 ol.parseText(refText.mid(fileMarkerPos+2,
1003 lineMarkerPos-fileMarkerPos-2));
1005 ol.pushGeneratorState();
1006 ol.disable(OutputGenerator::RTF);
1007 ol.disable(OutputGenerator::Man);
1008 if (!latexSourceCode)
1010 ol.disable(OutputGenerator::Latex);
1012 ol.disableAllBut(OutputGenerator::Html);
1013 // write line link (HTML only)
1014 ol.writeObjectLink(0,fn,anchorStr,lineStr);
1016 ol.disable(OutputGenerator::Html);
1017 if (latexSourceCode)
1019 ol.disable(OutputGenerator::Latex);
1021 // write normal text (Latex/Man only)
1023 ol.popGeneratorState();
1025 // write text right from linePos marker
1026 ol.parseText(refText.right(
1027 refText.length()-lineMarkerPos-2));
1033 err("translation error: invalid markers in trDefinedInSourceFile()\n");
1036 ol.popGeneratorState();
1039 void Definition::setBodySegment(int bls,int ble)
1041 //printf("setBodySegment(%d,%d) for %s\n",bls,ble,name().data());
1042 if (m_impl->body==0) m_impl->body = new BodyInfo;
1043 m_impl->body->startLine=bls;
1044 m_impl->body->endLine=ble;
1047 void Definition::setBodyDef(FileDef *fd)
1049 if (m_impl->body==0) m_impl->body = new BodyInfo;
1050 m_impl->body->fileDef=fd;
1053 bool Definition::hasSources() const
1055 return m_impl->body && m_impl->body->startLine!=-1 &&
1056 m_impl->body->endLine>=m_impl->body->startLine &&
1057 m_impl->body->fileDef;
1060 /*! Write code of this definition into the documentation */
1061 void Definition::writeInlineCode(OutputList &ol,const char *scopeName)
1063 static bool inlineSources = Config_getBool("INLINE_SOURCES");
1064 ol.pushGeneratorState();
1065 //printf("Source Fragment %s: %d-%d bodyDef=%p\n",name().data(),
1066 // m_startBodyLine,m_endBodyLine,m_bodyDef);
1067 if (inlineSources && hasSources())
1069 QCString codeFragment;
1070 int actualStart=m_impl->body->startLine,actualEnd=m_impl->body->endLine;
1071 if (readCodeFragment(m_impl->body->fileDef->absFilePath(),
1072 actualStart,actualEnd,codeFragment)
1075 //printf("Adding code fragement '%s' ext='%s'\n",
1076 // codeFragment.data(),m_impl->defFileExt.data());
1077 ParserInterface *pIntf = Doxygen::parserManager->getParser(m_impl->defFileExt);
1078 pIntf->resetCodeParserState();
1079 //printf("Read:\n`%s'\n\n",codeFragment.data());
1080 MemberDef *thisMd = 0;
1081 if (definitionType()==TypeMember) thisMd = (MemberDef *)this;
1083 ol.startCodeFragment();
1084 pIntf->parseCode(ol, // codeOutIntf
1086 codeFragment, // input
1087 m_impl->lang, // lang
1090 m_impl->body->fileDef, // fileDef
1091 actualStart, // startLine
1092 actualEnd, // endLine
1093 TRUE, // inlineFragment
1094 thisMd, // memberDef
1095 TRUE // show line numbers
1097 ol.endCodeFragment();
1100 ol.popGeneratorState();
1103 /*! Write a reference to the source code fragments in which this
1104 * definition is used.
1106 void Definition::_writeSourceRefList(OutputList &ol,const char *scopeName,
1107 const QCString &text,MemberSDict *members,bool /*funcOnly*/)
1109 static bool latexSourceCode = Config_getBool("LATEX_SOURCE_CODE");
1110 static bool sourceBrowser = Config_getBool("SOURCE_BROWSER");
1111 static bool refLinkSource = Config_getBool("REFERENCES_LINK_SOURCE");
1112 ol.pushGeneratorState();
1117 ol.startParagraph();
1121 QCString ldefLine=theTranslator->trWriteList(members->count());
1123 QRegExp marker("@[0-9]+");
1124 int index=0,newIndex,matchLen;
1125 // now replace all markers in inheritLine with links to the classes
1126 while ((newIndex=marker.match(ldefLine,index,&matchLen))!=-1)
1129 ol.parseText(ldefLine.mid(index,newIndex-index));
1130 uint entryIndex = ldefLine.mid(newIndex+1,matchLen-1).toUInt(&ok);
1131 MemberDef *md=members->at(entryIndex);
1134 QCString scope=md->getScopeString();
1135 QCString name=md->name();
1136 //printf("class=%p scope=%s scopeName=%s\n",md->getClassDef(),scope.data(),scopeName);
1137 if (!scope.isEmpty() && scope!=scopeName)
1139 name.prepend(scope+getLanguageSpecificSeparator(m_impl->lang));
1141 if (!md->isObjCMethod() &&
1142 (md->isFunction() || md->isSlot() ||
1143 md->isPrototype() || md->isSignal()
1149 //Definition *d = md->getOutputFileBase();
1150 //if (d==Doxygen::globalScope) d=md->getBodyDef();
1151 if (sourceBrowser &&
1152 !(md->isLinkable() && !refLinkSource) &&
1153 md->getStartBodyLine()!=-1 &&
1157 //printf("md->getBodyDef()=%p global=%p\n",md->getBodyDef(),Doxygen::globalScope);
1158 // for HTML write a real link
1159 ol.pushGeneratorState();
1160 //ol.disableAllBut(OutputGenerator::Html);
1162 ol.disable(OutputGenerator::RTF);
1163 ol.disable(OutputGenerator::Man);
1164 if (!latexSourceCode)
1166 ol.disable(OutputGenerator::Latex);
1168 QCString lineStr,anchorStr;
1169 anchorStr.sprintf("l%05d",md->getStartBodyLine());
1170 //printf("Write object link to %s\n",md->getBodyDef()->getSourceFileBase().data());
1171 ol.writeObjectLink(0,md->getBodyDef()->getSourceFileBase(),anchorStr,name);
1172 ol.popGeneratorState();
1174 // for the other output formats just mention the name
1175 ol.pushGeneratorState();
1176 ol.disable(OutputGenerator::Html);
1177 if (latexSourceCode)
1179 ol.disable(OutputGenerator::Latex);
1182 ol.popGeneratorState();
1184 else if (md->isLinkable() /*&& d && d->isLinkable()*/)
1186 // for HTML write a real link
1187 ol.pushGeneratorState();
1188 //ol.disableAllBut(OutputGenerator::Html);
1189 ol.disable(OutputGenerator::RTF);
1190 ol.disable(OutputGenerator::Man);
1191 if (!latexSourceCode)
1193 ol.disable(OutputGenerator::Latex);
1196 ol.writeObjectLink(md->getReference(),
1197 md->getOutputFileBase(),
1199 ol.popGeneratorState();
1201 // for the other output formats just mention the name
1202 ol.pushGeneratorState();
1203 ol.disable(OutputGenerator::Html);
1204 if (latexSourceCode)
1206 ol.disable(OutputGenerator::Latex);
1209 ol.popGeneratorState();
1216 index=newIndex+matchLen;
1218 ol.parseText(ldefLine.right(ldefLine.length()-index));
1219 ol.writeString(".");
1222 ol.popGeneratorState();
1225 void Definition::writeSourceReffedBy(OutputList &ol,const char *scopeName)
1227 if (Config_getBool("REFERENCED_BY_RELATION"))
1229 _writeSourceRefList(ol,scopeName,theTranslator->trReferencedBy(),m_impl->sourceRefByDict,FALSE);
1233 void Definition::writeSourceRefs(OutputList &ol,const char *scopeName)
1235 if (Config_getBool("REFERENCES_RELATION"))
1237 _writeSourceRefList(ol,scopeName,theTranslator->trReferences(),m_impl->sourceRefsDict,TRUE);
1241 bool Definition::hasDocumentation() const
1243 static bool extractAll = Config_getBool("EXTRACT_ALL");
1244 //static bool sourceBrowser = Config_getBool("SOURCE_BROWSER");
1246 (m_impl->details && !m_impl->details->doc.isEmpty()) || // has detailed docs
1247 (m_impl->brief && !m_impl->brief->doc.isEmpty()) || // has brief description
1248 (m_impl->inbodyDocs && !m_impl->inbodyDocs->doc.isEmpty()) || // has inbody docs
1249 extractAll //|| // extract everything
1250 // (sourceBrowser && m_impl->body &&
1251 // m_impl->body->startLine!=-1 && m_impl->body->fileDef)
1252 ; // link to definition
1256 bool Definition::hasUserDocumentation() const
1259 (m_impl->details && !m_impl->details->doc.isEmpty()) ||
1260 (m_impl->brief && !m_impl->brief->doc.isEmpty()) ||
1261 (m_impl->inbodyDocs && !m_impl->inbodyDocs->doc.isEmpty());
1266 void Definition::addSourceReferencedBy(MemberDef *md)
1270 QCString name = md->name();
1271 QCString scope = md->getScopeString();
1273 if (!scope.isEmpty())
1275 name.prepend(scope+"::");
1278 if (m_impl->sourceRefByDict==0)
1280 m_impl->sourceRefByDict = new MemberSDict;
1282 if (m_impl->sourceRefByDict->find(name)==0)
1284 m_impl->sourceRefByDict->append(name,md);
1289 void Definition::addSourceReferences(MemberDef *md)
1291 QCString name = md->name();
1292 QCString scope = md->getScopeString();
1296 QCString name = md->name();
1297 QCString scope = md->getScopeString();
1299 if (!scope.isEmpty())
1301 name.prepend(scope+"::");
1304 if (m_impl->sourceRefsDict==0)
1306 m_impl->sourceRefsDict = new MemberSDict;
1308 if (m_impl->sourceRefsDict->find(name)==0)
1310 m_impl->sourceRefsDict->append(name,md);
1315 Definition *Definition::findInnerCompound(const char *)
1320 void Definition::addInnerCompound(Definition *)
1322 err("Definition::addInnerCompound() called\n");
1325 QCString Definition::qualifiedName() const
1327 //static int count=0;
1329 if (!m_impl->qualifiedName.isEmpty())
1332 return m_impl->qualifiedName;
1335 //printf("start %s::qualifiedName() localName=%s\n",name().data(),m_impl->localName.data());
1336 if (m_impl->outerScope==0)
1338 if (m_impl->localName=="<globalScope>")
1346 return m_impl->localName;
1350 if (m_impl->outerScope->name()=="<globalScope>")
1352 m_impl->qualifiedName = m_impl->localName;
1356 m_impl->qualifiedName = m_impl->outerScope->qualifiedName()+
1357 getLanguageSpecificSeparator(getLanguage())+
1360 //printf("end %s::qualifiedName()=%s\n",name().data(),m_impl->qualifiedName.data());
1362 return m_impl->qualifiedName;
1365 void Definition::setOuterScope(Definition *d)
1367 //printf("%s::setOuterScope(%s)\n",name().data(),d?d->name().data():"<none>");
1368 Definition *p = m_impl->outerScope;
1370 // make sure that we are not creating a recursive scope relation.
1374 p = p->m_impl->outerScope;
1378 m_impl->qualifiedName.resize(0); // flush cached scope name
1379 m_impl->outerScope = d;
1381 m_impl->hidden = m_impl->hidden || d->isHidden();
1384 QCString Definition::localName() const
1386 return m_impl->localName;
1389 void Definition::makePartOfGroup(GroupDef *gd)
1391 if (m_impl->partOfGroups==0) m_impl->partOfGroups = new GroupList;
1392 m_impl->partOfGroups->append(gd);
1395 void Definition::setRefItems(const QList<ListItemInfo> *sli)
1397 //printf("%s::setRefItems()\n",name().data());
1400 // deep copy the list
1401 if (m_impl->xrefListItems==0)
1403 m_impl->xrefListItems=new QList<ListItemInfo>;
1404 m_impl->xrefListItems->setAutoDelete(TRUE);
1406 QListIterator<ListItemInfo> slii(*sli);
1408 for (slii.toFirst();(lii=slii.current());++slii)
1410 m_impl->xrefListItems->append(new ListItemInfo(*lii));
1415 void Definition::mergeRefItems(Definition *d)
1417 //printf("%s::mergeRefItems()\n",name().data());
1418 QList<ListItemInfo> *xrefList = d->xrefListItems();
1421 // deep copy the list
1422 if (m_impl->xrefListItems==0)
1424 m_impl->xrefListItems=new QList<ListItemInfo>;
1425 m_impl->xrefListItems->setAutoDelete(TRUE);
1427 QListIterator<ListItemInfo> slii(*xrefList);
1429 for (slii.toFirst();(lii=slii.current());++slii)
1431 if (_getXRefListId(lii->type)==-1)
1433 m_impl->xrefListItems->append(new ListItemInfo(*lii));
1439 int Definition::_getXRefListId(const char *listName) const
1441 if (m_impl->xrefListItems)
1443 QListIterator<ListItemInfo> slii(*m_impl->xrefListItems);
1445 for (slii.toFirst();(lii=slii.current());++slii)
1447 if (qstrcmp(lii->type,listName)==0)
1456 QList<ListItemInfo> *Definition::xrefListItems() const
1458 return m_impl->xrefListItems;
1462 QCString Definition::convertNameToFile(const char *name,bool allowDots) const
1464 if (!m_impl->ref.isEmpty())
1470 return ::convertNameToFile(name,allowDots);
1474 QCString Definition::pathFragment() const
1477 if (m_impl->outerScope && m_impl->outerScope!=Doxygen::globalScope)
1479 result = m_impl->outerScope->pathFragment();
1483 if (!result.isEmpty()) result+="/";
1484 if (definitionType()==Definition::TypeGroup && ((const GroupDef*)this)->groupTitle())
1486 result+=((const GroupDef*)this)->groupTitle();
1488 else if (definitionType()==Definition::TypePage && !((const PageDef*)this)->title().isEmpty())
1490 result+=((const PageDef*)this)->title();
1494 result+=m_impl->localName;
1499 result+=m_impl->localName;
1504 //----------------------------------------------------------------------------------------
1506 // TODO: move to htmlgen
1507 /*! Returns the string used in the footer for $navpath when
1508 * GENERATE_TREEVIEW is enabled
1510 QCString Definition::navigationPathAsString() const
1513 Definition *outerScope = getOuterScope();
1514 QCString locName = localName();
1515 if (outerScope && outerScope!=Doxygen::globalScope)
1517 result+=outerScope->navigationPathAsString();
1519 else if (definitionType()==Definition::TypeFile && ((const FileDef*)this)->getDirDef())
1521 result+=((const FileDef*)this)->getDirDef()->navigationPathAsString();
1523 result+="<li class=\"navelem\">";
1526 if (definitionType()==Definition::TypeGroup && ((const GroupDef*)this)->groupTitle())
1528 result+="<a class=\"el\" href=\"$relpath^"+getOutputFileBase()+Doxygen::htmlFileExtension+"\">"+
1529 ((const GroupDef*)this)->groupTitle()+"</a>";
1531 else if (definitionType()==Definition::TypePage && !((const PageDef*)this)->title().isEmpty())
1533 result+="<a class=\"el\" href=\"$relpath^"+getOutputFileBase()+Doxygen::htmlFileExtension+"\">"+
1534 ((const PageDef*)this)->title()+"</a>";
1536 else if (definitionType()==Definition::TypeClass)
1538 QCString name = locName;
1539 if (name.right(2)=="-p" /*|| name.right(2)=="-g"*/)
1541 name = name.left(name.length()-2);
1543 result+="<a class=\"el\" href=\"$relpath^"+getOutputFileBase()+Doxygen::htmlFileExtension;
1544 if (!anchor().isEmpty()) result+="#"+anchor();
1545 result+="\">"+name+"</a>";
1549 result+="<a class=\"el\" href=\"$relpath^"+getOutputFileBase()+Doxygen::htmlFileExtension+"\">"+
1555 result+="<b>"+locName+"</b>";
1561 // TODO: move to htmlgen
1562 void Definition::writeNavigationPath(OutputList &ol) const
1564 ol.pushGeneratorState();
1565 ol.disableAllBut(OutputGenerator::Html);
1568 navPath += "<div id=\"nav-path\" class=\"navpath\">\n"
1570 navPath += navigationPathAsString();
1571 navPath += " </ul>\n"
1573 ol.writeNavigationPath(navPath);
1575 ol.popGeneratorState();
1578 // TODO: move to htmlgen
1579 void Definition::writeToc(OutputList &ol)
1581 SectionDict *sectionDict = m_impl->sectionDict;
1582 if (sectionDict==0) return;
1583 ol.pushGeneratorState();
1584 ol.disableAllBut(OutputGenerator::Html);
1585 ol.writeString("<div class=\"toc\">");
1586 ol.writeString("<h3>");
1587 ol.writeString(theTranslator->trRTFTableOfContents());
1588 ol.writeString("</h3>\n");
1589 ol.writeString("<ul>");
1590 SDict<SectionInfo>::Iterator li(*sectionDict);
1595 bool inLi[5]={ FALSE, FALSE, FALSE, FALSE };
1596 for (li.toFirst();(si=li.current());++li)
1598 if (si->type==SectionInfo::Section ||
1599 si->type==SectionInfo::Subsection ||
1600 si->type==SectionInfo::Subsubsection ||
1601 si->type==SectionInfo::Paragraph)
1603 //printf(" level=%d title=%s\n",level,si->title.data());
1604 int nextLevel = (int)si->type;
1605 if (nextLevel>level)
1607 for (l=level;l<nextLevel;l++)
1609 ol.writeString("<ul>");
1612 else if (nextLevel<level)
1614 for (l=level;l>nextLevel;l--)
1616 if (inLi[l]) ol.writeString("</li>\n");
1618 ol.writeString("</ul>\n");
1621 cs[0]='0'+nextLevel;
1622 if (inLi[nextLevel]) ol.writeString("</li>\n");
1623 ol.writeString("<li class=\"level"+QCString(cs)+"\"><a href=\"#"+si->label+"\">"+si->title+"</a>");
1624 inLi[nextLevel]=TRUE;
1630 if (inLi[level]) ol.writeString("</li>\n");
1632 ol.writeString("</ul>\n");
1635 if (inLi[level]) ol.writeString("</li>\n");
1637 ol.writeString("</ul>\n");
1638 ol.writeString("</div>\n");
1639 ol.popGeneratorState();
1642 //----------------------------------------------------------------------------------------
1645 QCString Definition::symbolName() const
1647 return m_symbolName;
1650 //----------------------
1652 QCString Definition::documentation() const
1654 return m_impl->details ? m_impl->details->doc : QCString("");
1657 int Definition::docLine() const
1659 return m_impl->details ? m_impl->details->line : 1;
1662 QCString Definition::docFile() const
1664 return m_impl->details ? m_impl->details->file : QCString("<"+m_name+">");
1667 //----------------------------------------------------------------------------
1668 // strips w from s iff s starts with w
1669 static bool stripWord(QCString &s,QCString w)
1672 if (s.left(w.length())==w)
1675 s=s.right(s.length()-w.length());
1680 //----------------------------------------------------------------------------
1681 // some quasi intelligent brief description abbreviator :^)
1682 QCString abbreviate(const char *s,const char *name)
1684 QCString scopelessName=name;
1685 int i=scopelessName.findRev("::");
1686 if (i!=-1) scopelessName=scopelessName.mid(i+2);
1688 result=result.stripWhiteSpace();
1690 if (!result.isEmpty() && result.at(result.length()-1)=='.')
1691 result=result.left(result.length()-1);
1693 // strip any predefined prefix
1694 QStrList &briefDescAbbrev = Config_getList("ABBREVIATE_BRIEF");
1695 const char *p = briefDescAbbrev.first();
1699 s.replace(QRegExp("\\$name"), scopelessName); // replace $name with entity name
1701 stripWord(result,s);
1702 p = briefDescAbbrev.next();
1705 // capitalize first word
1706 if (!result.isEmpty())
1709 if (c>='a' && c<='z') c+='A'-'a';
1716 //----------------------
1718 QCString Definition::briefDescription(bool abbr) const
1720 //printf("%s::briefDescription(%d)='%s'\n",name().data(),abbr,m_impl->brief?m_impl->brief->doc.data():"<none>");
1721 return m_impl->brief ?
1722 (abbr ? abbreviate(m_impl->brief->doc,displayName()) : m_impl->brief->doc) :
1726 QCString Definition::briefDescriptionAsTooltip() const
1730 if (m_impl->brief->tooltip.isEmpty() && !m_impl->brief->doc.isEmpty())
1732 static bool reentering=FALSE;
1735 MemberDef *md = definitionType()==TypeMember ? (MemberDef*)this : 0;
1736 const Definition *scope = definitionType()==TypeMember ? getOuterScope() : this;
1737 reentering=TRUE; // prevent requests for tooltips while parsing a tooltip
1738 m_impl->brief->tooltip = parseCommentAsText(
1741 m_impl->brief->file,
1742 m_impl->brief->line);
1746 return m_impl->brief->tooltip;
1748 return QCString("");
1751 int Definition::briefLine() const
1753 return m_impl->brief ? m_impl->brief->line : 1;
1756 QCString Definition::briefFile() const
1758 return m_impl->brief ? m_impl->brief->file : QCString("<"+m_name+">");
1761 //----------------------
1763 QCString Definition::inbodyDocumentation() const
1765 return m_impl->inbodyDocs ? m_impl->inbodyDocs->doc : QCString("");
1768 int Definition::inbodyLine() const
1770 return m_impl->inbodyDocs ? m_impl->inbodyDocs->line : 1;
1773 QCString Definition::inbodyFile() const
1775 return m_impl->inbodyDocs ? m_impl->inbodyDocs->file : QCString("<"+m_name+">");
1779 //----------------------
1781 QCString Definition::getDefFileName() const
1783 return m_impl->defFileName;
1786 QCString Definition::getDefFileExtension() const
1788 return m_impl->defFileExt;
1791 bool Definition::isHidden() const
1793 return m_impl->hidden;
1796 bool Definition::isVisibleInProject() const
1798 return isLinkableInProject() && !m_impl->hidden;
1801 bool Definition::isVisible() const
1803 return isLinkable() && !m_impl->hidden;
1806 bool Definition::isArtificial() const
1808 return m_impl->isArtificial;
1811 QCString Definition::getReference() const
1816 bool Definition::isReference() const
1818 return !m_impl->ref.isEmpty();
1821 int Definition::getStartBodyLine() const
1823 return m_impl->body ? m_impl->body->startLine : -1;
1826 int Definition::getEndBodyLine() const
1828 return m_impl->body ? m_impl->body->endLine : -1;
1831 FileDef *Definition::getBodyDef() const
1833 return m_impl->body ? m_impl->body->fileDef : 0;
1836 GroupList *Definition::partOfGroups() const
1838 return m_impl->partOfGroups;
1841 Definition *Definition::getOuterScope() const
1843 return m_impl->outerScope;
1846 MemberSDict *Definition::getReferencesMembers() const
1848 return m_impl->sourceRefsDict;
1851 MemberSDict *Definition::getReferencedByMembers() const
1853 return m_impl->sourceRefByDict;
1856 void Definition::setReference(const char *r)
1861 SrcLangExt Definition::getLanguage() const
1863 return m_impl->lang;
1866 void Definition::setHidden(bool b)
1868 m_impl->hidden = m_impl->hidden || b;
1871 void Definition::setArtificial(bool b)
1873 m_impl->isArtificial = b;
1876 void Definition::setLocalName(const QCString name)
1878 m_impl->localName=name;
1881 void Definition::setLanguage(SrcLangExt lang)
1887 void Definition::_setSymbolName(const QCString &name)
1892 bool Definition::hasBriefDescription() const
1894 static bool briefMemberDesc = Config_getBool("BRIEF_MEMBER_DESC");
1895 return !briefDescription().isEmpty() && briefMemberDesc;