1 /******************************************************************************
5 * Copyright (C) 1997-2015 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"
47 #define START_MARKER 0x4445465B // DEF[
48 #define END_MARKER 0x4445465D // DEF]
50 //-----------------------------------------------------------------------------------------
53 /** Private data associated with a Symbol Definition object. */
59 void init(const char *df, const char *n);
61 SectionDict *sectionDict; // dictionary of all sections, not accessible
63 MemberSDict *sourceRefByDict;
64 MemberSDict *sourceRefsDict;
65 QList<ListItemInfo> *xrefListItems;
66 GroupList *partOfGroups;
68 DocInfo *details; // not exported
69 DocInfo *inbodyDocs; // not exported
70 BriefInfo *brief; // not exported
71 BodyInfo *body; // not exported
72 QCString briefSignatures;
73 QCString docSignatures;
75 QCString localName; // local (unqualified) name of the definition
76 // in the future m_name should become m_localName
77 QCString qualifiedName;
78 QCString ref; // reference to external documentation
83 Definition *outerScope; // not owner
85 // where the item was found
91 QCString id; // clang unique id
94 DefinitionImpl::DefinitionImpl()
95 : sectionDict(0), sourceRefByDict(0), sourceRefsDict(0),
96 xrefListItems(0), partOfGroups(0),
97 details(0), inbodyDocs(0), brief(0), body(0), hidden(FALSE), isArtificial(FALSE),
98 outerScope(0), lang(SrcLangExt_Unknown)
102 DefinitionImpl::~DefinitionImpl()
105 delete sourceRefByDict;
106 delete sourceRefsDict;
108 delete xrefListItems;
115 void DefinitionImpl::init(const char *df, const char *n)
118 int lastDot = defFileName.findRev('.');
121 defFileExt = defFileName.mid(lastDot);
124 if (name!="<globalScope>")
126 //extractNamespaceName(m_name,m_localName,ns);
127 localName=stripScope(n);
133 //printf("m_localName=%s\n",m_localName.data());
142 outerScope = Doxygen::globalScope;
146 isArtificial = FALSE;
147 lang = SrcLangExt_Unknown;
150 //-----------------------------------------------------------------------------------------
152 static bool matchExcludedSymbols(const char *name)
154 static QStrList &exclSyms = Config_getList(EXCLUDE_SYMBOLS);
155 if (exclSyms.count()==0) return FALSE; // nothing specified
156 const char *pat = exclSyms.first();
157 QCString symName = name;
160 QCString pattern = pat;
161 bool forceStart=FALSE;
163 if (pattern.at(0)=='^')
164 pattern=pattern.mid(1),forceStart=TRUE;
165 if (pattern.at(pattern.length()-1)=='$')
166 pattern=pattern.left(pattern.length()-1),forceEnd=TRUE;
167 if (pattern.find('*')!=-1) // wildcard mode
169 QRegExp re(substitute(pattern,"*",".*"),TRUE);
171 i = re.match(symName,0,&pl);
172 //printf(" %d = re.match(%s) pattern=%s\n",i,symName.data(),pattern.data());
173 if (i!=-1) // wildcard match
175 int sl=symName.length();
176 // check if it is a whole word match
177 if ((i==0 || pattern.at(0)=='*' || (!isId(symName.at(i-1)) && !forceStart)) &&
178 (i+pl==sl || pattern.at(i+pl)=='*' || (!isId(symName.at(i+pl)) && !forceEnd))
181 //printf("--> name=%s pattern=%s match at %d\n",symName.data(),pattern.data(),i);
186 else if (!pattern.isEmpty()) // match words
188 int i = symName.find(pattern);
189 if (i!=-1) // we have a match!
191 int pl=pattern.length();
192 int sl=symName.length();
193 // check if it is a whole word match
194 if ((i==0 || (!isId(symName.at(i-1)) && !forceStart)) &&
195 (i+pl==sl || (!isId(symName.at(i+pl)) && !forceEnd))
198 //printf("--> name=%s pattern=%s match at %d\n",symName.data(),pattern.data(),i);
203 pat = exclSyms.next();
205 //printf("--> name=%s: no match\n",name);
209 void Definition::addToMap(const char *name,Definition *d)
211 bool vhdlOpt = Config_getBool(OPTIMIZE_OUTPUT_VHDL);
212 QCString symbolName = name;
213 int index=computeQualifiedIndex(symbolName);
214 if (!vhdlOpt && index!=-1) symbolName=symbolName.mid(index+2);
215 if (!symbolName.isEmpty())
217 //printf("******* adding symbol `%s' (%p)\n",symbolName.data(),d);
218 DefinitionIntf *di=Doxygen::symbolMap->find(symbolName);
219 //printf(" addToMap(%p): looking for symbol %s: %p\n",d,symbolName.data(),di);
220 if (di==0) // new Symbol
222 //printf(" new symbol!\n");
223 Doxygen::symbolMap->insert(symbolName,d);
225 else // existing symbol
227 //printf(" existing symbol: ");
228 if (di->definitionType()==DefinitionIntf::TypeSymbolList) // already multiple symbols
230 //printf("adding to exiting list\n");
231 DefinitionList *dl = (DefinitionList*)di;
234 else // going from one to two symbols
236 Doxygen::symbolMap->take(symbolName);
237 DefinitionList *dl = new DefinitionList;
238 //printf("replacing symbol by list %p with elements %p and %p\n",dl,di,d);
239 dl->append((Definition*)di);
241 Doxygen::symbolMap->insert(symbolName,dl);
245 // auto resize if needed
246 static int sizeIndex=9;
247 if (Doxygen::symbolMap->size()>SDict_primes[sizeIndex])
249 Doxygen::symbolMap->resize(SDict_primes[++sizeIndex]);
252 d->_setSymbolName(symbolName);
256 void Definition::removeFromMap(Definition *d)
258 QCString symbolName = d->m_symbolName;
259 if (!symbolName.isEmpty())
261 //printf("******* removing symbol `%s' (%p)\n",symbolName.data(),d);
262 DefinitionIntf *di=Doxygen::symbolMap->find(symbolName);
265 if (di!=d) // symbolName not unique
267 //printf(" removing from list: %p!\n",di);
268 DefinitionList *dl = (DefinitionList*)di;
269 bool b = dl->removeRef(d);
273 Doxygen::symbolMap->take(symbolName);
277 else // symbolName unique
279 //printf(" removing symbol %p\n",di);
280 Doxygen::symbolMap->take(symbolName);
286 Definition::Definition(const char *df,int dl,int dc,
287 const char *name,const char *b,
288 const char *d,bool isSymbol) : m_cookie(0)
293 m_impl = new DefinitionImpl;
294 m_impl->init(df,name);
295 m_isSymbol = isSymbol;
296 if (isSymbol) addToMap(name,this);
297 _setBriefDescription(b,df,dl);
298 _setDocumentation(d,df,dl,TRUE,FALSE);
299 if (matchExcludedSymbols(name))
301 m_impl->hidden = TRUE;
305 Definition::Definition(const Definition &d) : DefinitionIntf(), m_cookie(0)
308 m_defLine = d.m_defLine;
309 m_defColumn = d.m_defColumn;
310 m_impl = new DefinitionImpl;
312 m_impl->sectionDict = 0;
313 m_impl->sourceRefByDict = 0;
314 m_impl->sourceRefsDict = 0;
315 m_impl->partOfGroups = 0;
316 m_impl->xrefListItems = 0;
320 m_impl->inbodyDocs = 0;
321 if (d.m_impl->sectionDict)
323 m_impl->sectionDict = new SectionDict(17);
324 SDict<SectionInfo>::Iterator it(*d.m_impl->sectionDict);
326 for (it.toFirst();(si=it.current());++it)
328 m_impl->sectionDict->append(si->label,si);
331 if (d.m_impl->sourceRefByDict)
333 m_impl->sourceRefByDict = new MemberSDict;
334 MemberSDict::IteratorDict it(*d.m_impl->sourceRefByDict);
336 for (it.toFirst();(md=it.current());++it)
338 m_impl->sourceRefByDict->append(it.currentKey(),md);
341 if (d.m_impl->sourceRefsDict)
343 m_impl->sourceRefsDict = new MemberSDict;
344 MemberSDict::IteratorDict it(*d.m_impl->sourceRefsDict);
346 for (it.toFirst();(md=it.current());++it)
348 m_impl->sourceRefsDict->append(it.currentKey(),md);
351 if (d.m_impl->partOfGroups)
353 GroupListIterator it(*d.m_impl->partOfGroups);
355 for (it.toFirst();(gd=it.current());++it)
360 if (d.m_impl->xrefListItems)
362 setRefItems(d.m_impl->xrefListItems);
366 m_impl->brief = new BriefInfo(*d.m_impl->brief);
368 if (d.m_impl->details)
370 m_impl->details = new DocInfo(*d.m_impl->details);
374 m_impl->body = new BodyInfo(*d.m_impl->body);
376 if (d.m_impl->inbodyDocs)
378 m_impl->inbodyDocs = new DocInfo(*d.m_impl->inbodyDocs);
381 m_isSymbol = d.m_isSymbol;
382 if (m_isSymbol) addToMap(m_name,this);
385 Definition::~Definition()
400 void Definition::setName(const char *name)
406 void Definition::setId(const char *id)
410 if (Doxygen::clangUsrMap)
412 //printf("Definition::setId '%s'->'%s'\n",id,m_name.data());
413 Doxygen::clangUsrMap->insert(id,this);
417 QCString Definition::id() const
422 void Definition::addSectionsToDefinition(QList<SectionInfo> *anchorList)
424 if (!anchorList) return;
425 //printf("%s: addSectionsToDefinition(%d)\n",name().data(),anchorList->count());
426 QListIterator<SectionInfo> it(*anchorList);
428 for (;(si=it.current());++it)
430 //printf("Add section `%s' to definition `%s'\n",
431 // si->label.data(),name().data());
432 SectionInfo *gsi=Doxygen::sectionDict->find(si->label);
433 //printf("===== label=%s gsi=%p\n",si->label.data(),gsi);
436 gsi = new SectionInfo(*si);
437 Doxygen::sectionDict->append(si->label,gsi);
439 if (m_impl->sectionDict==0)
441 m_impl->sectionDict = new SectionDict(17);
443 if (m_impl->sectionDict->find(gsi->label)==0)
445 m_impl->sectionDict->append(gsi->label,gsi);
446 gsi->definition = this;
451 bool Definition::hasSections() const
453 //printf("Definition::hasSections(%s) #sections=%d\n",name().data(),
454 // m_impl->sectionDict ? m_impl->sectionDict->count() : 0);
455 if (m_impl->sectionDict==0) return FALSE;
456 SDict<SectionInfo>::Iterator li(*m_impl->sectionDict);
458 for (li.toFirst();(si=li.current());++li)
460 if (si->type==SectionInfo::Section ||
461 si->type==SectionInfo::Subsection ||
462 si->type==SectionInfo::Subsubsection ||
463 si->type==SectionInfo::Paragraph)
471 void Definition::addSectionsToIndex()
473 if (m_impl->sectionDict==0) return;
474 //printf("Definition::addSectionsToIndex()\n");
475 SDict<SectionInfo>::Iterator li(*m_impl->sectionDict);
478 for (li.toFirst();(si=li.current());++li)
480 if (si->type==SectionInfo::Section ||
481 si->type==SectionInfo::Subsection ||
482 si->type==SectionInfo::Subsubsection ||
483 si->type==SectionInfo::Paragraph)
485 //printf(" level=%d title=%s\n",level,si->title.data());
486 int nextLevel = (int)si->type;
490 for (i=level;i<nextLevel;i++)
492 Doxygen::indexList->incContentsDepth();
495 else if (nextLevel<level)
497 for (i=nextLevel;i<level;i++)
499 Doxygen::indexList->decContentsDepth();
502 QCString title = si->title;
503 if (title.isEmpty()) title = si->label;
504 // determine if there is a next level inside this item
506 bool isDir = ((li.current()) ? (int)(li.current()->type > nextLevel):FALSE);
508 Doxygen::indexList->addContentsItem(isDir,title,
519 Doxygen::indexList->decContentsDepth();
524 void Definition::writeDocAnchorsToTagFile(FTextStream &tagFile)
526 if (m_impl->sectionDict)
528 //printf("%s: writeDocAnchorsToTagFile(%d)\n",name().data(),m_impl->sectionDict->count());
529 SDict<SectionInfo>::Iterator sdi(*m_impl->sectionDict);
531 for (;(si=sdi.current());++sdi)
533 if (!si->generated && si->ref.isEmpty())
535 //printf("write an entry!\n");
536 if (definitionType()==TypeMember) tagFile << " ";
537 tagFile << " <docanchor file=\"" << si->fileName << "\"";
538 if (!si->title.isEmpty())
540 tagFile << " title=\"" << convertToXML(si->title) << "\"";
542 tagFile << ">" << si->label << "</docanchor>" << endl;
548 bool Definition::_docsAlreadyAdded(const QCString &doc,QCString &sigList)
552 // to avoid mismatches due to differences in indenting, we first remove
553 // double whitespaces...
554 QCString docStr = doc.simplifyWhiteSpace();
555 MD5Buffer((const unsigned char *)docStr.data(),docStr.length(),md5_sig);
556 MD5SigToString(md5_sig,sigStr.rawData(),33);
557 //printf("%s:_docsAlreadyAdded doc='%s' sig='%s' docSigs='%s'\n",
558 // name().data(),doc.data(),sigStr.data(),sigList.data());
559 if (sigList.find(sigStr)==-1) // new docs, add signature to prevent re-adding it
570 void Definition::_setDocumentation(const char *d,const char *docFile,int docLine,
571 bool stripWhiteSpace,bool atTop)
573 //printf("%s::setDocumentation(%s,%s,%d,%d)\n",name().data(),d,docFile,docLine,stripWhiteSpace);
578 doc = stripLeadingAndTrailingEmptyLines(doc,docLine);
580 else // don't strip whitespace
584 if (!_docsAlreadyAdded(doc,m_impl->docSignatures))
586 //printf("setting docs for %s: `%s'\n",name().data(),m_doc.data());
587 if (m_impl->details==0)
589 m_impl->details = new DocInfo;
591 if (m_impl->details->doc.isEmpty()) // fresh detailed description
593 m_impl->details->doc = doc;
595 else if (atTop) // another detailed description, append it to the start
597 m_impl->details->doc = doc+"\n\n"+m_impl->details->doc;
599 else // another detailed description, append it to the end
601 m_impl->details->doc += "\n\n"+doc;
603 if (docLine!=-1) // store location if valid
605 m_impl->details->file = docFile;
606 m_impl->details->line = docLine;
610 m_impl->details->file = docFile;
611 m_impl->details->line = 1;
616 void Definition::setDocumentation(const char *d,const char *docFile,int docLine,bool stripWhiteSpace)
619 _setDocumentation(d,docFile,docLine,stripWhiteSpace,FALSE);
622 #define uni_isupper(c) (QChar(c).category()==QChar::Letter_Uppercase)
624 // do a UTF-8 aware search for the last real character and return TRUE
625 // if that is a multibyte one.
626 static bool lastCharIsMultibyte(const QCString &s)
631 while ((p=nextUtf8CharPosition(s,l,p))<l) pp=p;
632 if (pp==-1 || ((uchar)s[pp])<0x80) return FALSE;
636 void Definition::_setBriefDescription(const char *b,const char *briefFile,int briefLine)
638 static QCString outputLanguage = Config_getEnum(OUTPUT_LANGUAGE);
639 static bool needsDot = outputLanguage!="Japanese" &&
640 outputLanguage!="Chinese" &&
641 outputLanguage!="Korean";
643 brief = brief.stripWhiteSpace();
644 if (brief.isEmpty()) return;
645 int bl = brief.length();
646 if (bl>0 && needsDot) // add punctuation if needed
648 int c = brief.at(bl-1);
651 case '.': case '!': case '?': case '>': case ':': case ')': break;
653 if (uni_isupper(brief.at(0)) && !lastCharIsMultibyte(brief)) brief+='.';
658 if (!_docsAlreadyAdded(brief,m_impl->briefSignatures))
660 if (m_impl->brief && !m_impl->brief->doc.isEmpty())
662 //printf("adding to details\n");
663 _setDocumentation(brief,briefFile,briefLine,FALSE,TRUE);
667 //fprintf(stderr,"Definition::setBriefDescription(%s,%s,%d)\n",b,briefFile,briefLine);
668 if (m_impl->brief==0)
670 m_impl->brief = new BriefInfo;
672 m_impl->brief->doc=brief;
675 m_impl->brief->file = briefFile;
676 m_impl->brief->line = briefLine;
680 m_impl->brief->file = briefFile;
681 m_impl->brief->line = 1;
687 //printf("do nothing!\n");
691 void Definition::setBriefDescription(const char *b,const char *briefFile,int briefLine)
694 _setBriefDescription(b,briefFile,briefLine);
697 void Definition::_setInbodyDocumentation(const char *doc,const char *inbodyFile,int inbodyLine)
699 if (m_impl->inbodyDocs==0)
701 m_impl->inbodyDocs = new DocInfo;
703 if (m_impl->inbodyDocs->doc.isEmpty()) // fresh inbody docs
705 m_impl->inbodyDocs->doc = doc;
706 m_impl->inbodyDocs->file = inbodyFile;
707 m_impl->inbodyDocs->line = inbodyLine;
709 else // another inbody documentation fragment, append this to the end
711 m_impl->inbodyDocs->doc += QCString("\n\n")+doc;
715 void Definition::setInbodyDocumentation(const char *d,const char *inbodyFile,int inbodyLine)
718 _setInbodyDocumentation(d,inbodyFile,inbodyLine);
721 //---------------------------------------
723 struct FilterCacheItem
725 portable_off_t filePos;
729 /*! Cache for storing the result of filtering a file */
733 FilterCache() : m_endPos(0) { m_cache.setAutoDelete(TRUE); }
734 bool getFileContents(const QCString &fileName,BufStr &str)
736 static bool filterSourceFiles = Config_getBool(FILTER_SOURCE_FILES);
737 QCString filter = getFileFilter(fileName,TRUE);
738 bool usePipe = !filter.isEmpty() && filterSourceFiles;
740 const int blockSize = 4096;
742 FilterCacheItem *item=0;
743 if (usePipe && (item = m_cache.find(fileName))) // cache hit: reuse stored result
745 //printf("getFileContents(%s): cache hit\n",qPrint(fileName));
746 // file already processed, get the results after filtering from the tmp file
747 Debug::print(Debug::FilterOutput,0,"Reusing filter result for %s from %s at offset=%d size=%d\n",
748 qPrint(fileName),qPrint(Doxygen::filterDBFileName),(int)item->filePos,(int)item->fileSize);
749 f = portable_fopen(Doxygen::filterDBFileName,"rb");
753 str.resize(item->fileSize+1);
754 if (portable_fseek(f,item->filePos,SEEK_SET)==-1)
756 err("Failed to seek to position %d in filter database file %s\n",(int)item->filePos,qPrint(Doxygen::filterDBFileName));
761 int numBytes = fread(str.data(),1,item->fileSize,f);
762 if (numBytes!=item->fileSize)
764 err("Failed to read %d bytes from position %d in filter database file %s: got %d bytes\n",
765 (int)item->fileSize,(int)item->filePos,qPrint(Doxygen::filterDBFileName),numBytes);
775 err("Failed to open filter database file %s\n",qPrint(Doxygen::filterDBFileName));
779 else if (usePipe) // cache miss: filter active but file not previously processed
781 //printf("getFileContents(%s): cache miss\n",qPrint(fileName));
783 QCString cmd=filter+" \""+fileName+"\"";
784 Debug::print(Debug::ExtCmd,0,"Executing popen(`%s`)\n",qPrint(cmd));
785 f = portable_popen(cmd,"r");
786 FILE *bf = portable_fopen(Doxygen::filterDBFileName,"a+b");
787 FilterCacheItem *item = new FilterCacheItem;
788 item->filePos = m_endPos;
792 err("Error opening filter database file %s\n",qPrint(Doxygen::filterDBFileName));
798 // append the filtered output to the database file
802 int bytesRead = fread(buf,1,blockSize,f);
803 int bytesWritten = fwrite(buf,1,bytesRead,bf);
804 if (bytesRead!=bytesWritten)
807 err("Failed to write to filter database %s. Wrote %d out of %d bytes\n",
808 qPrint(Doxygen::filterDBFileName),bytesWritten,bytesRead);
816 str.addArray(buf,bytesWritten);
819 item->fileSize = size;
820 // add location entry to the dictionary
821 m_cache.append(fileName,item);
822 Debug::print(Debug::FilterOutput,0,"Storing new filter result for %s in %s at offset=%d size=%d\n",
823 qPrint(fileName),qPrint(Doxygen::filterDBFileName),(int)item->filePos,(int)item->fileSize);
824 // update end of file position
832 //printf("getFileContents(%s): no filter\n",qPrint(fileName));
833 f = portable_fopen(fileName,"r");
836 int bytesRead = fread(buf,1,blockSize,f);
837 str.addArray(buf,bytesRead);
845 SDict<FilterCacheItem> m_cache;
846 portable_off_t m_endPos;
849 static FilterCache g_filterCache;
851 //-----------------------------------------
854 /*! Reads a fragment of code from file \a fileName starting at
855 * line \a startLine and ending at line \a endLine (inclusive). The fragment is
856 * stored in \a result. If FALSE is returned the code fragment could not be
859 * The file is scanned for a opening bracket ('{') from \a startLine onward
860 * The line actually containing the bracket is returned via startLine.
861 * The file is scanned for a closing bracket ('}') from \a endLine backward.
862 * The line actually containing the bracket is returned via endLine.
863 * Note that for VHDL code the bracket search is not done.
865 bool readCodeFragment(const char *fileName,
866 int &startLine,int &endLine,QCString &result)
868 //printf("readCodeFragment(%s,startLine=%d,endLine=%d)\n",fileName,startLine,endLine);
869 static bool filterSourceFiles = Config_getBool(FILTER_SOURCE_FILES);
870 QCString filter = getFileFilter(fileName,TRUE);
871 bool usePipe = !filter.isEmpty() && filterSourceFiles;
872 int tabSize = Config_getInt(TAB_SIZE);
873 SrcLangExt lang = getLanguageFromFileName(fileName);
874 const int blockSize = 4096;
875 BufStr str(blockSize);
876 g_filterCache.getFileContents(fileName,str);
878 bool found = lang==SrcLangExt_VHDL ||
879 lang==SrcLangExt_Tcl ||
880 lang==SrcLangExt_Python ||
881 lang==SrcLangExt_Fortran;
882 // for VHDL, TCL, Python, and Fortran no bracket search is possible
889 // skip until the startLine has reached
890 while (lineNr<startLine && *p)
892 while ((c=*p++)!='\n' && c!=0) /* skip */;
894 if (found && c == '\n') c = '\0';
898 // skip until the opening bracket or lonely : is found
900 while (lineNr<=endLine && *p && !found)
903 while ((c=*p++)!='{' && c!=':' && c!=0)
905 //printf("parsing char `%c'\n",c);
912 col+=tabSize - (col%tabSize);
914 else if (pc=='/' && c=='/') // skip single line comment
916 while ((c=*p++)!='\n' && c!=0) pc=c;
917 if (c=='\n') lineNr++,col=0;
919 else if (pc=='/' && c=='*') // skip C style comment
921 while (((c=*p++)!='/' || pc!='*') && c!=0)
923 if (c=='\n') lineNr++,col=0;
936 if (cn!=':') found=TRUE;
943 //printf(" -> readCodeFragment(%s,%d,%d) lineNr=%d\n",fileName,startLine,endLine,lineNr);
946 // For code with more than one line,
947 // fill the line with spaces until we are at the right column
948 // so that the opening brace lines up with the closing brace
949 if (endLine!=startLine)
952 spaces.fill(' ',col);
955 // copy until end of line
961 if (cn=='\n') lineNr++;
963 char lineStr[blockSize];
966 //printf("reading line %d in range %d-%d\n",lineNr,startLine,endLine);
970 // read up to maxLineLength-1 bytes, the last byte being zero
972 while ((c=*p++) && i<blockSize-1)
975 if (c=='\n') break; // stop at end of the line
979 result+=lineStr; // append line to the output
980 } while (size_read == (blockSize-1)); // append more if line does not fit in buffer
982 } while (lineNr<=endLine && *p);
984 // strip stuff after closing bracket
985 int newLineIndex = result.findRev('\n');
986 int braceIndex = result.findRev('}');
987 if (braceIndex > newLineIndex)
989 result.truncate(braceIndex+1);
996 Debug::print(Debug::FilterOutput, 0, "Filter output\n");
997 Debug::print(Debug::FilterOutput,0,"-------------\n%s\n-------------\n",qPrint(result));
1000 result = transcodeCharacterStringToUTF8(result);
1001 if (!result.isEmpty() && result.at(result.length()-1)!='\n') result += "\n";
1002 //fprintf(stderr,"readCodeFragement(%d-%d)=%s\n",startLine,endLine,result.data());
1006 QCString Definition::getSourceFileBase() const
1008 ASSERT(definitionType()!=Definition::TypeFile); // file overloads this method
1010 static bool sourceBrowser = Config_getBool(SOURCE_BROWSER);
1011 if (sourceBrowser &&
1012 m_impl->body && m_impl->body->startLine!=-1 && m_impl->body->fileDef)
1014 fn = m_impl->body->fileDef->getSourceFileBase();
1019 QCString Definition::getSourceAnchor() const
1021 const int maxAnchorStrLen = 20;
1022 char anchorStr[maxAnchorStrLen];
1024 if (m_impl->body && m_impl->body->startLine!=-1)
1026 if (Htags::useHtags)
1028 qsnprintf(anchorStr,maxAnchorStrLen,"L%d",m_impl->body->startLine);
1032 qsnprintf(anchorStr,maxAnchorStrLen,"l%05d",m_impl->body->startLine);
1038 /*! Write a reference to the source code defining this definition */
1039 void Definition::writeSourceDef(OutputList &ol,const char *)
1041 static bool latexSourceCode = Config_getBool(LATEX_SOURCE_CODE);
1042 static bool rtfSourceCode = Config_getBool(RTF_SOURCE_CODE);
1043 static bool docbookSourceCode = Config_getBool(DOCBOOK_PROGRAMLISTING);
1044 ol.pushGeneratorState();
1045 //printf("Definition::writeSourceRef %d %p\n",bodyLine,bodyDef);
1046 QCString fn = getSourceFileBase();
1049 QCString refText = theTranslator->trDefinedAtLineInSourceFile();
1050 int lineMarkerPos = refText.find("@0");
1051 int fileMarkerPos = refText.find("@1");
1052 if (lineMarkerPos!=-1 && fileMarkerPos!=-1) // should always pass this.
1055 lineStr.sprintf("%d",m_impl->body->startLine);
1056 QCString anchorStr = getSourceAnchor();
1057 ol.startParagraph("definition");
1058 if (lineMarkerPos<fileMarkerPos) // line marker before file marker
1060 // write text left from linePos marker
1061 ol.parseText(refText.left(lineMarkerPos));
1062 ol.pushGeneratorState();
1063 ol.disable(OutputGenerator::Man);
1064 if (!latexSourceCode)
1066 ol.disable(OutputGenerator::Latex);
1068 if (!docbookSourceCode)
1070 ol.disable(OutputGenerator::Docbook);
1074 ol.disable(OutputGenerator::RTF);
1076 // write line link (HTML and optionally LaTeX, Docbook, RTF)
1077 ol.writeObjectLink(0,fn,anchorStr,lineStr);
1079 ol.disable(OutputGenerator::Html);
1080 if (latexSourceCode)
1082 ol.disable(OutputGenerator::Latex);
1084 if (docbookSourceCode)
1086 ol.disable(OutputGenerator::Docbook);
1090 ol.disable(OutputGenerator::RTF);
1092 // write normal text (Man, Latex optionally, RTF optionally)
1094 ol.popGeneratorState();
1096 // write text between markers
1097 ol.parseText(refText.mid(lineMarkerPos+2,
1098 fileMarkerPos-lineMarkerPos-2));
1100 ol.pushGeneratorState();
1101 ol.disable(OutputGenerator::Man);
1102 if (!latexSourceCode)
1104 ol.disable(OutputGenerator::Latex);
1106 if (!docbookSourceCode)
1108 ol.disable(OutputGenerator::Docbook);
1112 ol.disable(OutputGenerator::RTF);
1114 // write file link (HTML, LaTeX optionally, RTF optionally)
1115 ol.writeObjectLink(0,fn,0,m_impl->body->fileDef->name());
1117 ol.disable(OutputGenerator::Html);
1118 if (latexSourceCode)
1120 ol.disable(OutputGenerator::Latex);
1122 if (docbookSourceCode)
1124 ol.disable(OutputGenerator::Docbook);
1128 ol.disable(OutputGenerator::RTF);
1130 // write normal text (Man, Latex optionally, RTF optionally)
1131 ol.docify(m_impl->body->fileDef->name());
1132 ol.popGeneratorState();
1134 // write text right from file marker
1135 ol.parseText(refText.right(
1136 refText.length()-fileMarkerPos-2));
1138 else // file marker before line marker
1140 // write text left from file marker
1141 ol.parseText(refText.left(fileMarkerPos));
1142 ol.pushGeneratorState();
1143 ol.disable(OutputGenerator::Man);
1144 if (!latexSourceCode)
1146 ol.disable(OutputGenerator::Latex);
1148 if (!docbookSourceCode)
1150 ol.disable(OutputGenerator::Docbook);
1154 ol.disable(OutputGenerator::RTF);
1156 // write file link (HTML only)
1157 ol.writeObjectLink(0,fn,0,m_impl->body->fileDef->name());
1159 ol.disable(OutputGenerator::Html);
1160 if (latexSourceCode)
1162 ol.disable(OutputGenerator::Latex);
1164 if (docbookSourceCode)
1166 ol.disable(OutputGenerator::Docbook);
1170 ol.disable(OutputGenerator::RTF);
1172 // write normal text (RTF/Latex/Man only)
1173 ol.docify(m_impl->body->fileDef->name());
1174 ol.popGeneratorState();
1176 // write text between markers
1177 ol.parseText(refText.mid(fileMarkerPos+2,
1178 lineMarkerPos-fileMarkerPos-2));
1180 ol.pushGeneratorState();
1181 ol.disable(OutputGenerator::Man);
1182 ol.disableAllBut(OutputGenerator::Html);
1183 if (latexSourceCode)
1185 ol.enable(OutputGenerator::Latex);
1187 if (docbookSourceCode)
1189 ol.enable(OutputGenerator::Docbook);
1193 ol.enable(OutputGenerator::RTF);
1195 // write line link (HTML only)
1196 ol.writeObjectLink(0,fn,anchorStr,lineStr);
1198 ol.disable(OutputGenerator::Html);
1199 if (latexSourceCode)
1201 ol.disable(OutputGenerator::Latex);
1203 if (docbookSourceCode)
1205 ol.disable(OutputGenerator::Docbook);
1209 ol.disable(OutputGenerator::RTF);
1211 // write normal text (Latex/Man only)
1213 ol.popGeneratorState();
1215 // write text right from linePos marker
1216 ol.parseText(refText.right(
1217 refText.length()-lineMarkerPos-2));
1223 err("translation error: invalid markers in trDefinedAtLineInSourceFile()\n");
1226 ol.popGeneratorState();
1229 void Definition::setBodySegment(int bls,int ble)
1231 //printf("setBodySegment(%d,%d) for %s\n",bls,ble,name().data());
1232 if (m_impl->body==0) m_impl->body = new BodyInfo;
1233 m_impl->body->startLine=bls;
1234 m_impl->body->endLine=ble;
1237 void Definition::setBodyDef(FileDef *fd)
1239 if (m_impl->body==0) m_impl->body = new BodyInfo;
1240 m_impl->body->fileDef=fd;
1243 bool Definition::hasSources() const
1245 return m_impl->body && m_impl->body->startLine!=-1 &&
1246 m_impl->body->endLine>=m_impl->body->startLine &&
1247 m_impl->body->fileDef;
1250 /*! Write code of this definition into the documentation */
1251 void Definition::writeInlineCode(OutputList &ol,const char *scopeName)
1253 static bool inlineSources = Config_getBool(INLINE_SOURCES);
1254 ol.pushGeneratorState();
1255 //printf("Source Fragment %s: %d-%d bodyDef=%p\n",name().data(),
1256 // m_startBodyLine,m_endBodyLine,m_bodyDef);
1257 if (inlineSources && hasSources())
1259 QCString codeFragment;
1260 int actualStart=m_impl->body->startLine,actualEnd=m_impl->body->endLine;
1261 if (readCodeFragment(m_impl->body->fileDef->absFilePath(),
1262 actualStart,actualEnd,codeFragment)
1265 //printf("Adding code fragment '%s' ext='%s'\n",
1266 // codeFragment.data(),m_impl->defFileExt.data());
1267 ParserInterface *pIntf = Doxygen::parserManager->getParser(m_impl->defFileExt);
1268 pIntf->resetCodeParserState();
1269 //printf("Read:\n`%s'\n\n",codeFragment.data());
1270 MemberDef *thisMd = 0;
1271 if (definitionType()==TypeMember) thisMd = (MemberDef *)this;
1273 ol.startCodeFragment();
1274 pIntf->parseCode(ol, // codeOutIntf
1276 codeFragment, // input
1277 m_impl->lang, // lang
1280 m_impl->body->fileDef, // fileDef
1281 actualStart, // startLine
1282 actualEnd, // endLine
1283 TRUE, // inlineFragment
1284 thisMd, // memberDef
1285 TRUE // show line numbers
1287 ol.endCodeFragment();
1290 ol.popGeneratorState();
1293 /*! Write a reference to the source code fragments in which this
1294 * definition is used.
1296 void Definition::_writeSourceRefList(OutputList &ol,const char *scopeName,
1297 const QCString &text,MemberSDict *members,bool /*funcOnly*/)
1299 static bool latexSourceCode = Config_getBool(LATEX_SOURCE_CODE);
1300 static bool docbookSourceCode = Config_getBool(DOCBOOK_PROGRAMLISTING);
1301 static bool rtfSourceCode = Config_getBool(RTF_SOURCE_CODE);
1302 static bool sourceBrowser = Config_getBool(SOURCE_BROWSER);
1303 static bool refLinkSource = Config_getBool(REFERENCES_LINK_SOURCE);
1304 ol.pushGeneratorState();
1309 ol.startParagraph("reference");
1313 QCString ldefLine=theTranslator->trWriteList(members->count());
1315 QRegExp marker("@[0-9]+");
1316 int index=0,newIndex,matchLen;
1317 // now replace all markers in inheritLine with links to the classes
1318 while ((newIndex=marker.match(ldefLine,index,&matchLen))!=-1)
1321 ol.parseText(ldefLine.mid(index,newIndex-index));
1322 uint entryIndex = ldefLine.mid(newIndex+1,matchLen-1).toUInt(&ok);
1323 MemberDef *md=members->at(entryIndex);
1326 QCString scope=md->getScopeString();
1327 QCString name=md->name();
1328 //printf("class=%p scope=%s scopeName=%s\n",md->getClassDef(),scope.data(),scopeName);
1329 if (!scope.isEmpty() && scope!=scopeName)
1331 name.prepend(scope+getLanguageSpecificSeparator(m_impl->lang));
1333 if (!md->isObjCMethod() &&
1334 (md->isFunction() || md->isSlot() ||
1335 md->isPrototype() || md->isSignal()
1341 //Definition *d = md->getOutputFileBase();
1342 //if (d==Doxygen::globalScope) d=md->getBodyDef();
1343 if (sourceBrowser &&
1344 !(md->isLinkable() && !refLinkSource) &&
1345 md->getStartBodyLine()!=-1 &&
1349 //printf("md->getBodyDef()=%p global=%p\n",md->getBodyDef(),Doxygen::globalScope);
1350 // for HTML write a real link
1351 ol.pushGeneratorState();
1352 //ol.disableAllBut(OutputGenerator::Html);
1354 ol.disable(OutputGenerator::Man);
1355 if (!latexSourceCode)
1357 ol.disable(OutputGenerator::Latex);
1359 if (!docbookSourceCode)
1361 ol.disable(OutputGenerator::Docbook);
1365 ol.disable(OutputGenerator::RTF);
1367 const int maxLineNrStr = 10;
1368 char anchorStr[maxLineNrStr];
1369 qsnprintf(anchorStr,maxLineNrStr,"l%05d",md->getStartBodyLine());
1370 //printf("Write object link to %s\n",md->getBodyDef()->getSourceFileBase().data());
1371 ol.writeObjectLink(0,md->getBodyDef()->getSourceFileBase(),anchorStr,name);
1372 ol.popGeneratorState();
1374 // for the other output formats just mention the name
1375 ol.pushGeneratorState();
1376 ol.disable(OutputGenerator::Html);
1377 if (latexSourceCode)
1379 ol.disable(OutputGenerator::Latex);
1381 if (docbookSourceCode)
1383 ol.disable(OutputGenerator::Docbook);
1387 ol.disable(OutputGenerator::RTF);
1390 ol.popGeneratorState();
1392 else if (md->isLinkable() /*&& d && d->isLinkable()*/)
1394 // for HTML write a real link
1395 ol.pushGeneratorState();
1396 //ol.disableAllBut(OutputGenerator::Html);
1397 ol.disable(OutputGenerator::Man);
1398 if (!latexSourceCode)
1400 ol.disable(OutputGenerator::Latex);
1402 if (!docbookSourceCode)
1404 ol.disable(OutputGenerator::Docbook);
1408 ol.disable(OutputGenerator::RTF);
1411 ol.writeObjectLink(md->getReference(),
1412 md->getOutputFileBase(),
1414 ol.popGeneratorState();
1416 // for the other output formats just mention the name
1417 ol.pushGeneratorState();
1418 ol.disable(OutputGenerator::Html);
1419 if (latexSourceCode)
1421 ol.disable(OutputGenerator::Latex);
1423 if (docbookSourceCode)
1425 ol.disable(OutputGenerator::Docbook);
1429 ol.disable(OutputGenerator::RTF);
1432 ol.popGeneratorState();
1439 index=newIndex+matchLen;
1441 ol.parseText(ldefLine.right(ldefLine.length()-index));
1442 ol.writeString(".");
1445 ol.popGeneratorState();
1448 void Definition::writeSourceReffedBy(OutputList &ol,const char *scopeName)
1450 _writeSourceRefList(ol,scopeName,theTranslator->trReferencedBy(),m_impl->sourceRefByDict,FALSE);
1453 void Definition::writeSourceRefs(OutputList &ol,const char *scopeName)
1455 _writeSourceRefList(ol,scopeName,theTranslator->trReferences(),m_impl->sourceRefsDict,TRUE);
1458 bool Definition::hasDocumentation() const
1460 static bool extractAll = Config_getBool(EXTRACT_ALL);
1461 //static bool sourceBrowser = Config_getBool(SOURCE_BROWSER);
1463 (m_impl->details && !m_impl->details->doc.isEmpty()) || // has detailed docs
1464 (m_impl->brief && !m_impl->brief->doc.isEmpty()) || // has brief description
1465 (m_impl->inbodyDocs && !m_impl->inbodyDocs->doc.isEmpty()) || // has inbody docs
1466 extractAll //|| // extract everything
1467 // (sourceBrowser && m_impl->body &&
1468 // m_impl->body->startLine!=-1 && m_impl->body->fileDef)
1469 ; // link to definition
1473 bool Definition::hasUserDocumentation() const
1476 (m_impl->details && !m_impl->details->doc.isEmpty()) ||
1477 (m_impl->brief && !m_impl->brief->doc.isEmpty()) ||
1478 (m_impl->inbodyDocs && !m_impl->inbodyDocs->doc.isEmpty());
1483 void Definition::addSourceReferencedBy(MemberDef *md)
1487 QCString name = md->name();
1488 QCString scope = md->getScopeString();
1490 if (!scope.isEmpty())
1492 name.prepend(scope+"::");
1495 if (m_impl->sourceRefByDict==0)
1497 m_impl->sourceRefByDict = new MemberSDict;
1499 if (m_impl->sourceRefByDict->find(name)==0)
1501 m_impl->sourceRefByDict->append(name,md);
1506 void Definition::addSourceReferences(MemberDef *md)
1510 QCString name = md->name();
1511 QCString scope = md->getScopeString();
1513 if (!scope.isEmpty())
1515 name.prepend(scope+"::");
1518 if (m_impl->sourceRefsDict==0)
1520 m_impl->sourceRefsDict = new MemberSDict;
1522 if (m_impl->sourceRefsDict->find(name)==0)
1524 m_impl->sourceRefsDict->append(name,md);
1529 Definition *Definition::findInnerCompound(const char *) const
1534 void Definition::addInnerCompound(Definition *)
1536 err("Definition::addInnerCompound() called\n");
1539 QCString Definition::qualifiedName() const
1541 //static int count=0;
1543 if (!m_impl->qualifiedName.isEmpty())
1546 return m_impl->qualifiedName;
1549 //printf("start %s::qualifiedName() localName=%s\n",name().data(),m_impl->localName.data());
1550 if (m_impl->outerScope==0)
1552 if (m_impl->localName=="<globalScope>")
1560 return m_impl->localName;
1564 if (m_impl->outerScope->name()=="<globalScope>")
1566 m_impl->qualifiedName = m_impl->localName;
1570 m_impl->qualifiedName = m_impl->outerScope->qualifiedName()+
1571 getLanguageSpecificSeparator(getLanguage())+
1574 //printf("end %s::qualifiedName()=%s\n",name().data(),m_impl->qualifiedName.data());
1576 return m_impl->qualifiedName;
1579 void Definition::setOuterScope(Definition *d)
1581 //printf("%s::setOuterScope(%s)\n",name().data(),d?d->name().data():"<none>");
1582 Definition *p = m_impl->outerScope;
1584 // make sure that we are not creating a recursive scope relation.
1588 p = p->m_impl->outerScope;
1592 m_impl->qualifiedName.resize(0); // flush cached scope name
1593 m_impl->outerScope = d;
1595 m_impl->hidden = m_impl->hidden || d->isHidden();
1598 QCString Definition::localName() const
1600 return m_impl->localName;
1603 void Definition::makePartOfGroup(GroupDef *gd)
1605 if (m_impl->partOfGroups==0) m_impl->partOfGroups = new GroupList;
1606 m_impl->partOfGroups->append(gd);
1609 void Definition::setRefItems(const QList<ListItemInfo> *sli)
1611 //printf("%s::setRefItems()\n",name().data());
1614 // deep copy the list
1615 if (m_impl->xrefListItems==0)
1617 m_impl->xrefListItems=new QList<ListItemInfo>;
1618 m_impl->xrefListItems->setAutoDelete(TRUE);
1620 QListIterator<ListItemInfo> slii(*sli);
1622 for (slii.toFirst();(lii=slii.current());++slii)
1624 m_impl->xrefListItems->append(new ListItemInfo(*lii));
1629 void Definition::mergeRefItems(Definition *d)
1631 //printf("%s::mergeRefItems()\n",name().data());
1632 QList<ListItemInfo> *xrefList = d->xrefListItems();
1635 // deep copy the list
1636 if (m_impl->xrefListItems==0)
1638 m_impl->xrefListItems=new QList<ListItemInfo>;
1639 m_impl->xrefListItems->setAutoDelete(TRUE);
1641 QListIterator<ListItemInfo> slii(*xrefList);
1642 QListIterator<ListItemInfo> mlii(*m_impl->xrefListItems);
1645 for (slii.toFirst();(lii=slii.current());++slii)
1648 for (mlii.toFirst();(mii=mlii.current());++mlii)
1650 if ((qstrcmp(lii->type,mii->type)==0) && (lii->itemId == mii->itemId))
1656 if (!found) m_impl->xrefListItems->append(new ListItemInfo(*lii));
1661 int Definition::_getXRefListId(const char *listName) const
1663 if (m_impl->xrefListItems)
1665 QListIterator<ListItemInfo> slii(*m_impl->xrefListItems);
1667 for (slii.toFirst();(lii=slii.current());++slii)
1669 if (qstrcmp(lii->type,listName)==0)
1678 QList<ListItemInfo> *Definition::xrefListItems() const
1680 return m_impl->xrefListItems;
1683 QCString Definition::pathFragment() const
1686 if (m_impl->outerScope && m_impl->outerScope!=Doxygen::globalScope)
1688 result = m_impl->outerScope->pathFragment();
1692 if (!result.isEmpty()) result+="/";
1693 if (definitionType()==Definition::TypeGroup && ((const GroupDef*)this)->groupTitle())
1695 result+=((const GroupDef*)this)->groupTitle();
1697 else if (definitionType()==Definition::TypePage && !((const PageDef*)this)->title().isEmpty())
1699 result+=((const PageDef*)this)->title();
1703 result+=m_impl->localName;
1708 result+=m_impl->localName;
1713 //----------------------------------------------------------------------------------------
1715 // TODO: move to htmlgen
1716 /*! Returns the string used in the footer for $navpath when
1717 * GENERATE_TREEVIEW is enabled
1719 QCString Definition::navigationPathAsString() const
1722 Definition *outerScope = getOuterScope();
1723 QCString locName = localName();
1724 if (outerScope && outerScope!=Doxygen::globalScope)
1726 result+=outerScope->navigationPathAsString();
1728 else if (definitionType()==Definition::TypeFile && ((const FileDef*)this)->getDirDef())
1730 result+=((const FileDef*)this)->getDirDef()->navigationPathAsString();
1732 result+="<li class=\"navelem\">";
1735 if (definitionType()==Definition::TypeGroup && ((const GroupDef*)this)->groupTitle())
1737 result+="<a class=\"el\" href=\"$relpath^"+getOutputFileBase()+Doxygen::htmlFileExtension+"\">"+
1738 convertToHtml(((const GroupDef*)this)->groupTitle())+"</a>";
1740 else if (definitionType()==Definition::TypePage && !((const PageDef*)this)->title().isEmpty())
1742 result+="<a class=\"el\" href=\"$relpath^"+getOutputFileBase()+Doxygen::htmlFileExtension+"\">"+
1743 convertToHtml(((const PageDef*)this)->title())+"</a>";
1745 else if (definitionType()==Definition::TypeClass)
1747 QCString name = locName;
1748 if (name.right(2)=="-p" /*|| name.right(2)=="-g"*/)
1750 name = name.left(name.length()-2);
1752 result+="<a class=\"el\" href=\"$relpath^"+getOutputFileBase()+Doxygen::htmlFileExtension;
1753 if (!anchor().isEmpty()) result+="#"+anchor();
1754 result+="\">"+convertToHtml(name)+"</a>";
1758 result+="<a class=\"el\" href=\"$relpath^"+getOutputFileBase()+Doxygen::htmlFileExtension+"\">"+
1759 convertToHtml(locName)+"</a>";
1764 result+="<b>"+convertToHtml(locName)+"</b>";
1770 // TODO: move to htmlgen
1771 void Definition::writeNavigationPath(OutputList &ol) const
1773 ol.pushGeneratorState();
1774 ol.disableAllBut(OutputGenerator::Html);
1777 navPath += "<div id=\"nav-path\" class=\"navpath\">\n"
1779 navPath += navigationPathAsString();
1780 navPath += " </ul>\n"
1782 ol.writeNavigationPath(navPath);
1784 ol.popGeneratorState();
1787 // TODO: move to htmlgen
1788 void Definition::writeToc(OutputList &ol, const LocalToc &localToc)
1790 SectionDict *sectionDict = m_impl->sectionDict;
1791 if (sectionDict==0) return;
1792 if (localToc.isHtmlEnabled())
1794 int maxLevel = localToc.htmlLevel();
1795 ol.pushGeneratorState();
1796 ol.disableAllBut(OutputGenerator::Html);
1797 ol.writeString("<div class=\"toc\">");
1798 ol.writeString("<h3>");
1799 ol.writeString(theTranslator->trRTFTableOfContents());
1800 ol.writeString("</h3>\n");
1801 ol.writeString("<ul>");
1802 SDict<SectionInfo>::Iterator li(*sectionDict);
1807 bool inLi[5]={ FALSE, FALSE, FALSE, FALSE, FALSE };
1808 for (li.toFirst();(si=li.current());++li)
1810 if (si->type==SectionInfo::Section ||
1811 si->type==SectionInfo::Subsection ||
1812 si->type==SectionInfo::Subsubsection ||
1813 si->type==SectionInfo::Paragraph)
1815 //printf(" level=%d title=%s\n",level,si->title.data());
1816 int nextLevel = (int)si->type;
1817 if (nextLevel>level)
1819 for (l=level;l<nextLevel;l++)
1821 if (l < maxLevel) ol.writeString("<ul>");
1824 else if (nextLevel<level)
1826 for (l=level;l>nextLevel;l--)
1828 if (l <= maxLevel && inLi[l]) ol.writeString("</li>\n");
1830 if (l <= maxLevel) ol.writeString("</ul>\n");
1833 cs[0]='0'+nextLevel;
1834 if (nextLevel <= maxLevel && inLi[nextLevel]) ol.writeString("</li>\n");
1835 QCString titleDoc = convertToHtml(si->title);
1836 if (nextLevel <= maxLevel) ol.writeString("<li class=\"level"+QCString(cs)+"\"><a href=\"#"+si->label+"\">"+(si->title.isEmpty()?si->label:titleDoc)+"</a>");
1837 inLi[nextLevel]=TRUE;
1841 if (level > maxLevel) level = maxLevel;
1842 while (level>1 && level <= maxLevel)
1844 if (inLi[level]) ol.writeString("</li>\n");
1846 ol.writeString("</ul>\n");
1849 if (level <= maxLevel && inLi[level]) ol.writeString("</li>\n");
1851 ol.writeString("</ul>\n");
1852 ol.writeString("</div>\n");
1853 ol.popGeneratorState();
1856 if (localToc.isDocbookEnabled())
1858 ol.pushGeneratorState();
1859 ol.disableAllBut(OutputGenerator::Docbook);
1860 ol.writeString(" <toc>\n");
1861 ol.writeString(" <title>" + theTranslator->trRTFTableOfContents() + "</title>\n");
1862 SectionDict *sectionDict = getSectionDict();
1863 SDict<SectionInfo>::Iterator li(*sectionDict);
1866 bool inLi[5]={ FALSE, FALSE, FALSE, FALSE, FALSE };
1867 int maxLevel = localToc.docbookLevel();
1868 for (li.toFirst();(si=li.current());++li)
1870 if (si->type==SectionInfo::Section ||
1871 si->type==SectionInfo::Subsection ||
1872 si->type==SectionInfo::Subsubsection ||
1873 si->type==SectionInfo::Paragraph)
1875 //printf(" level=%d title=%s\n",level,si->title.data());
1876 int nextLevel = (int)si->type;
1877 if (nextLevel>level)
1879 for (l=level;l<nextLevel;l++)
1881 if (l < maxLevel) ol.writeString(" <tocdiv>\n");
1884 else if (nextLevel<level)
1886 for (l=level;l>nextLevel;l--)
1889 if (l <= maxLevel) ol.writeString(" </tocdiv>\n");
1892 if (nextLevel <= maxLevel)
1894 QCString titleDoc = convertToDocBook(si->title);
1895 ol.writeString(" <tocentry>" + (si->title.isEmpty()?si->label:titleDoc) + "</tocentry>\n");
1897 inLi[nextLevel]=TRUE;
1901 if (level > maxLevel) level = maxLevel;
1902 while (level>1 && level <= maxLevel)
1905 ol.writeString("</tocdiv>\n");
1909 ol.writeString(" </toc>\n");
1910 ol.popGeneratorState();
1913 if (localToc.isLatexEnabled())
1915 ol.pushGeneratorState();
1916 ol.disableAllBut(OutputGenerator::Latex);
1917 int maxLevel = localToc.latexLevel();
1919 ol.writeString("\\etocsetnexttocdepth{"+QCString().setNum(maxLevel)+"}\n");
1921 ol.writeString("\\localtableofcontents\n");
1922 ol.popGeneratorState();
1926 //----------------------------------------------------------------------------------------
1928 SectionDict * Definition::getSectionDict(void)
1930 return m_impl->sectionDict;
1933 QCString Definition::symbolName() const
1935 return m_symbolName;
1938 //----------------------
1940 QCString Definition::documentation() const
1942 return m_impl->details ? m_impl->details->doc : QCString("");
1945 int Definition::docLine() const
1947 return m_impl->details ? m_impl->details->line : 1;
1950 QCString Definition::docFile() const
1952 return m_impl->details ? m_impl->details->file : QCString("<"+m_name+">");
1955 //----------------------------------------------------------------------------
1956 // strips w from s iff s starts with w
1957 static bool stripWord(QCString &s,QCString w)
1960 if (s.left(w.length())==w)
1963 s=s.right(s.length()-w.length());
1968 //----------------------------------------------------------------------------
1969 // some quasi intelligent brief description abbreviator :^)
1970 QCString abbreviate(const char *s,const char *name)
1972 QCString scopelessName=name;
1973 int i=scopelessName.findRev("::");
1974 if (i!=-1) scopelessName=scopelessName.mid(i+2);
1976 result=result.stripWhiteSpace();
1978 if (!result.isEmpty() && result.at(result.length()-1)=='.')
1979 result=result.left(result.length()-1);
1981 // strip any predefined prefix
1982 QStrList &briefDescAbbrev = Config_getList(ABBREVIATE_BRIEF);
1983 const char *p = briefDescAbbrev.first();
1987 s.replace(QRegExp("\\$name"), scopelessName); // replace $name with entity name
1989 stripWord(result,s);
1990 p = briefDescAbbrev.next();
1993 // capitalize first word
1994 if (!result.isEmpty())
1997 if (c>='a' && c<='z') c+='A'-'a';
2004 //----------------------
2006 QCString Definition::briefDescription(bool abbr) const
2008 //printf("%s::briefDescription(%d)='%s'\n",name().data(),abbr,m_impl->brief?m_impl->brief->doc.data():"<none>");
2009 return m_impl->brief ?
2010 (abbr ? abbreviate(m_impl->brief->doc,displayName()) : m_impl->brief->doc) :
2014 QCString Definition::briefDescriptionAsTooltip() const
2018 if (m_impl->brief->tooltip.isEmpty() && !m_impl->brief->doc.isEmpty())
2020 static bool reentering=FALSE;
2023 MemberDef *md = definitionType()==TypeMember ? (MemberDef*)this : 0;
2024 const Definition *scope = definitionType()==TypeMember ? getOuterScope() : this;
2025 reentering=TRUE; // prevent requests for tooltips while parsing a tooltip
2026 m_impl->brief->tooltip = parseCommentAsText(
2029 m_impl->brief->file,
2030 m_impl->brief->line);
2034 return m_impl->brief->tooltip;
2036 return QCString("");
2039 int Definition::briefLine() const
2041 return m_impl->brief ? m_impl->brief->line : 1;
2044 QCString Definition::briefFile() const
2046 return m_impl->brief ? m_impl->brief->file : QCString("<"+m_name+">");
2049 //----------------------
2051 QCString Definition::inbodyDocumentation() const
2053 return m_impl->inbodyDocs ? m_impl->inbodyDocs->doc : QCString("");
2056 int Definition::inbodyLine() const
2058 return m_impl->inbodyDocs ? m_impl->inbodyDocs->line : 1;
2061 QCString Definition::inbodyFile() const
2063 return m_impl->inbodyDocs ? m_impl->inbodyDocs->file : QCString("<"+m_name+">");
2067 //----------------------
2069 QCString Definition::getDefFileName() const
2071 return m_impl->defFileName;
2074 QCString Definition::getDefFileExtension() const
2076 return m_impl->defFileExt;
2079 bool Definition::isHidden() const
2081 return m_impl->hidden;
2084 bool Definition::isVisibleInProject() const
2086 return isLinkableInProject() && !m_impl->hidden;
2089 bool Definition::isVisible() const
2091 return isLinkable() && !m_impl->hidden;
2094 bool Definition::isArtificial() const
2096 return m_impl->isArtificial;
2099 QCString Definition::getReference() const
2104 bool Definition::isReference() const
2106 return !m_impl->ref.isEmpty();
2109 int Definition::getStartBodyLine() const
2111 return m_impl->body ? m_impl->body->startLine : -1;
2114 int Definition::getEndBodyLine() const
2116 return m_impl->body ? m_impl->body->endLine : -1;
2119 FileDef *Definition::getBodyDef() const
2121 return m_impl->body ? m_impl->body->fileDef : 0;
2124 GroupList *Definition::partOfGroups() const
2126 return m_impl->partOfGroups;
2129 bool Definition::isLinkableViaGroup() const
2131 GroupList *gl = partOfGroups();
2134 GroupListIterator gli(*gl);
2136 for (gli.toFirst();(gd=gli.current());++gli)
2138 if (gd->isLinkable()) return TRUE;
2144 Definition *Definition::getOuterScope() const
2146 return m_impl->outerScope;
2149 MemberSDict *Definition::getReferencesMembers() const
2151 return m_impl->sourceRefsDict;
2154 MemberSDict *Definition::getReferencedByMembers() const
2156 return m_impl->sourceRefByDict;
2159 void Definition::setReference(const char *r)
2164 SrcLangExt Definition::getLanguage() const
2166 return m_impl->lang;
2169 void Definition::setHidden(bool b)
2171 m_impl->hidden = m_impl->hidden || b;
2174 void Definition::setArtificial(bool b)
2176 m_impl->isArtificial = b;
2179 void Definition::setLocalName(const QCString name)
2181 m_impl->localName=name;
2184 void Definition::setLanguage(SrcLangExt lang)
2190 void Definition::_setSymbolName(const QCString &name)
2195 bool Definition::hasBriefDescription() const
2197 static bool briefMemberDesc = Config_getBool(BRIEF_MEMBER_DESC);
2198 return !briefDescription().isEmpty() && briefMemberDesc;
2201 QCString Definition::externalReference(const QCString &relPath) const
2203 QCString ref = getReference();
2206 QCString *dest = Doxygen::tagDestinationDict[ref];
2209 QCString result = *dest;
2210 int l = result.length();
2211 if (!relPath.isEmpty() && l>0 && result.at(0)=='.')
2212 { // relative path -> prepend relPath.
2213 result.prepend(relPath);
2214 l+=relPath.length();
2216 if (l>0 && result.at(l-1)!='/') result+='/';