Imported Upstream version 1.8.15
[platform/upstream/doxygen.git] / src / definition.cpp
1 /******************************************************************************
2  *
3  * 
4  *
5  * Copyright (C) 1997-2015 by Dimitri van Heesch.
6  *
7  * Permission to use, copy, modify, and distribute this software and its
8  * documentation under the terms of the GNU General Public License is hereby 
9  * granted. No representations are made about the suitability of this software 
10  * for any purpose. It is provided "as is" without express or implied warranty.
11  * See the GNU General Public License for more details.
12  *
13  * Documents produced by Doxygen are derivative works derived from the
14  * input used in their production; they are not affected by this license.
15  *
16  */
17
18 #include <ctype.h>
19 #include <qregexp.h>
20 #include "md5.h"
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <assert.h>
24 #include "config.h"
25 #include "definition.h"
26 #include "doxygen.h"
27 #include "language.h"
28 #include "message.h"
29 #include "outputlist.h"
30 #include "code.h"
31 #include "util.h"
32 #include "groupdef.h"
33 #include "pagedef.h"
34 #include "section.h"
35 #include "htags.h"
36 #include "parserintf.h"
37 #include "marshal.h"
38 #include "debug.h"
39 #include "vhdldocgen.h"
40 #include "memberlist.h"
41 #include "namespacedef.h"
42 #include "filedef.h"
43 #include "dirdef.h"
44 #include "pagedef.h"
45 #include "bufstr.h"
46
47 #define START_MARKER 0x4445465B // DEF[
48 #define END_MARKER   0x4445465D // DEF]
49
50 //-----------------------------------------------------------------------------------------
51
52
53 /** Private data associated with a Symbol Definition object. */
54 class DefinitionImpl
55 {
56   public:
57     DefinitionImpl();
58    ~DefinitionImpl();
59     void init(const char *df, const char *n);
60
61     SectionDict *sectionDict;  // dictionary of all sections, not accessible
62
63     MemberSDict *sourceRefByDict;
64     MemberSDict *sourceRefsDict;
65     QList<ListItemInfo> *xrefListItems;
66     GroupList *partOfGroups;
67
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;
74
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
79
80     bool hidden;
81     bool isArtificial;
82
83     Definition *outerScope;  // not owner
84
85     // where the item was found
86     QCString defFileName;
87     QCString defFileExt;
88
89     SrcLangExt lang;
90
91     QCString id; // clang unique id
92 };
93
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)
99 {
100 }
101
102 DefinitionImpl::~DefinitionImpl()
103 {
104   delete sectionDict;
105   delete sourceRefByDict;
106   delete sourceRefsDict;
107   delete partOfGroups;
108   delete xrefListItems;
109   delete brief;
110   delete details;
111   delete body;
112   delete inbodyDocs;
113 }
114
115 void DefinitionImpl::init(const char *df, const char *n)
116 {
117   defFileName = df;
118   int lastDot = defFileName.findRev('.');
119   if (lastDot!=-1)
120   {
121     defFileExt = defFileName.mid(lastDot);
122   }
123   QCString name = n;
124   if (name!="<globalScope>") 
125   {
126     //extractNamespaceName(m_name,m_localName,ns);
127     localName=stripScope(n);
128   }
129   else
130   {
131     localName=n;
132   }
133   //printf("m_localName=%s\n",m_localName.data());
134
135   brief           = 0;
136   details         = 0;
137   body            = 0;
138   inbodyDocs      = 0;
139   sourceRefByDict = 0;
140   sourceRefsDict  = 0;
141   sectionDict     = 0, 
142   outerScope      = Doxygen::globalScope;
143   partOfGroups    = 0;
144   xrefListItems   = 0;
145   hidden          = FALSE;
146   isArtificial    = FALSE;
147   lang            = SrcLangExt_Unknown;
148 }
149
150 //-----------------------------------------------------------------------------------------
151
152 static bool matchExcludedSymbols(const char *name)
153 {
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;
158   while (pat)
159   {
160     QCString pattern = pat;
161     bool forceStart=FALSE;
162     bool forceEnd=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
168     {
169       QRegExp re(substitute(pattern,"*",".*"),TRUE);
170       int i,pl;
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
174       {
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))
179            )
180         {
181           //printf("--> name=%s pattern=%s match at %d\n",symName.data(),pattern.data(),i);
182           return TRUE;
183         }
184       }
185     }
186     else if (!pattern.isEmpty()) // match words
187     {
188       int i = symName.find(pattern);
189       if (i!=-1) // we have a match!
190       {
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))
196            )
197         {
198           //printf("--> name=%s pattern=%s match at %d\n",symName.data(),pattern.data(),i);
199           return TRUE; 
200         }
201       }
202     }
203     pat = exclSyms.next();
204   }
205   //printf("--> name=%s: no match\n",name);
206   return FALSE;
207 }
208
209 void Definition::addToMap(const char *name,Definition *d)
210 {
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()) 
216   {
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
221     {
222       //printf("  new symbol!\n");
223       Doxygen::symbolMap->insert(symbolName,d);
224     }
225     else // existing symbol
226     {
227       //printf("  existing symbol: ");
228       if (di->definitionType()==DefinitionIntf::TypeSymbolList) // already multiple symbols
229       {
230         //printf("adding to exiting list\n");
231         DefinitionList *dl = (DefinitionList*)di;
232         dl->append(d);
233       }
234       else // going from one to two symbols
235       {
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);
240         dl->append(d);
241         Doxygen::symbolMap->insert(symbolName,dl);
242       }
243     }
244
245     // auto resize if needed
246     static int sizeIndex=9;
247     if (Doxygen::symbolMap->size()>SDict_primes[sizeIndex])
248     {
249       Doxygen::symbolMap->resize(SDict_primes[++sizeIndex]);
250     }
251
252     d->_setSymbolName(symbolName);
253   }
254 }
255
256 void Definition::removeFromMap(Definition *d)
257 {
258   QCString symbolName = d->m_symbolName;
259   if (!symbolName.isEmpty()) 
260   {
261     //printf("******* removing symbol `%s' (%p)\n",symbolName.data(),d);
262     DefinitionIntf *di=Doxygen::symbolMap->find(symbolName);
263     if (di)
264     {
265       if (di!=d) // symbolName not unique
266       {
267         //printf("  removing from list: %p!\n",di);
268         DefinitionList *dl = (DefinitionList*)di;
269         bool b = dl->removeRef(d);
270         ASSERT(b==TRUE);
271         if (dl->isEmpty())
272         {
273           Doxygen::symbolMap->take(symbolName);
274           delete dl;
275         }
276       }
277       else // symbolName unique
278       {
279         //printf("  removing symbol %p\n",di);
280         Doxygen::symbolMap->take(symbolName);
281       }
282     }
283   }
284 }
285
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)
289 {
290   m_name = name;
291   m_defLine = dl;
292   m_defColumn = dc;
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)) 
300   {
301     m_impl->hidden = TRUE;
302   }
303 }
304
305 Definition::Definition(const Definition &d) : DefinitionIntf(), m_cookie(0)
306 {
307   m_name = d.m_name;
308   m_defLine = d.m_defLine;
309   m_defColumn = d.m_defColumn;
310   m_impl = new DefinitionImpl;
311   *m_impl = *d.m_impl;
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;
317   m_impl->brief = 0;
318   m_impl->details = 0;
319   m_impl->body = 0;
320   m_impl->inbodyDocs = 0;
321   if (d.m_impl->sectionDict)
322   {
323     m_impl->sectionDict = new SectionDict(17);
324     SDict<SectionInfo>::Iterator it(*d.m_impl->sectionDict);
325     SectionInfo *si;
326     for (it.toFirst();(si=it.current());++it)
327     {
328       m_impl->sectionDict->append(si->label,si);
329     }
330   }
331   if (d.m_impl->sourceRefByDict)
332   {
333     m_impl->sourceRefByDict = new MemberSDict;
334     MemberSDict::IteratorDict it(*d.m_impl->sourceRefByDict);
335     MemberDef *md;
336     for (it.toFirst();(md=it.current());++it)
337     {
338       m_impl->sourceRefByDict->append(it.currentKey(),md);
339     }
340   }
341   if (d.m_impl->sourceRefsDict)
342   {
343     m_impl->sourceRefsDict = new MemberSDict;
344     MemberSDict::IteratorDict it(*d.m_impl->sourceRefsDict);
345     MemberDef *md;
346     for (it.toFirst();(md=it.current());++it)
347     {
348       m_impl->sourceRefsDict->append(it.currentKey(),md);
349     }
350   }
351   if (d.m_impl->partOfGroups)
352   {
353     GroupListIterator it(*d.m_impl->partOfGroups);
354     GroupDef *gd;
355     for (it.toFirst();(gd=it.current());++it)
356     {
357       makePartOfGroup(gd);
358     }
359   }
360   if (d.m_impl->xrefListItems)
361   {
362     setRefItems(d.m_impl->xrefListItems);
363   }
364   if (d.m_impl->brief)
365   {
366     m_impl->brief = new BriefInfo(*d.m_impl->brief);
367   }
368   if (d.m_impl->details)
369   {
370     m_impl->details = new DocInfo(*d.m_impl->details);
371   }
372   if (d.m_impl->body)
373   {
374     m_impl->body = new BodyInfo(*d.m_impl->body);
375   }
376   if (d.m_impl->inbodyDocs)
377   {
378     m_impl->inbodyDocs = new DocInfo(*d.m_impl->inbodyDocs);
379   }
380
381   m_isSymbol = d.m_isSymbol;
382   if (m_isSymbol) addToMap(m_name,this);
383 }
384
385 Definition::~Definition()
386 {
387   if (m_isSymbol)
388   {
389     removeFromMap(this);
390   }
391   if (m_impl)
392   {
393     delete m_impl;
394     m_impl=0;
395   }
396   delete m_cookie;
397   m_cookie=0;
398 }
399
400 void Definition::setName(const char *name)
401 {
402   if (name==0) return;
403   m_name = name;
404 }
405
406 void Definition::setId(const char *id)
407 {
408   if (id==0) return;
409   m_impl->id = id;
410   if (Doxygen::clangUsrMap) 
411   {
412     //printf("Definition::setId '%s'->'%s'\n",id,m_name.data());
413     Doxygen::clangUsrMap->insert(id,this);
414   }
415 }
416
417 QCString Definition::id() const
418 {
419   return m_impl->id;
420 }
421
422 void Definition::addSectionsToDefinition(QList<SectionInfo> *anchorList)
423 {
424   if (!anchorList) return;
425   //printf("%s: addSectionsToDefinition(%d)\n",name().data(),anchorList->count());
426   QListIterator<SectionInfo> it(*anchorList);
427   SectionInfo *si;
428   for (;(si=it.current());++it)
429   {
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);
434     if (gsi==0)
435     {
436       gsi = new SectionInfo(*si);
437       Doxygen::sectionDict->append(si->label,gsi);
438     }
439     if (m_impl->sectionDict==0)
440     {
441       m_impl->sectionDict = new SectionDict(17);
442     }
443     if (m_impl->sectionDict->find(gsi->label)==0)
444     {
445       m_impl->sectionDict->append(gsi->label,gsi);
446       gsi->definition = this;
447     }
448   }
449 }
450
451 bool Definition::hasSections() const
452 {
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);
457   SectionInfo *si;
458   for (li.toFirst();(si=li.current());++li)
459   {
460     if (si->type==SectionInfo::Section || 
461         si->type==SectionInfo::Subsection || 
462         si->type==SectionInfo::Subsubsection ||
463         si->type==SectionInfo::Paragraph)
464     {
465       return TRUE;
466     }
467   }
468   return FALSE;
469 }
470
471 void Definition::addSectionsToIndex()
472 {
473   if (m_impl->sectionDict==0) return;
474   //printf("Definition::addSectionsToIndex()\n");
475   SDict<SectionInfo>::Iterator li(*m_impl->sectionDict);
476   SectionInfo *si;
477   int level=1;
478   for (li.toFirst();(si=li.current());++li)
479   {
480     if (si->type==SectionInfo::Section       || 
481         si->type==SectionInfo::Subsection    || 
482         si->type==SectionInfo::Subsubsection ||
483         si->type==SectionInfo::Paragraph)
484     {
485       //printf("  level=%d title=%s\n",level,si->title.data());
486       int nextLevel = (int)si->type;
487       int i;
488       if (nextLevel>level)
489       {
490         for (i=level;i<nextLevel;i++)
491         {
492           Doxygen::indexList->incContentsDepth();
493         }
494       }
495       else if (nextLevel<level)
496       {
497         for (i=nextLevel;i<level;i++)
498         {
499           Doxygen::indexList->decContentsDepth();
500         }
501       }
502       QCString title = si->title;
503       if (title.isEmpty()) title = si->label;
504       // determine if there is a next level inside this item
505       ++li;
506       bool isDir = ((li.current()) ? (int)(li.current()->type > nextLevel):FALSE);
507       --li;
508       Doxygen::indexList->addContentsItem(isDir,title,
509                                          getReference(),
510                                          getOutputFileBase(),
511                                          si->label,
512                                          FALSE,
513                                          TRUE);
514       level = nextLevel;
515     }
516   }
517   while (level>1)
518   {
519     Doxygen::indexList->decContentsDepth();
520     level--;
521   }
522 }
523
524 void Definition::writeDocAnchorsToTagFile(FTextStream &tagFile)
525 {
526   if (m_impl->sectionDict)
527   {
528     //printf("%s: writeDocAnchorsToTagFile(%d)\n",name().data(),m_impl->sectionDict->count());
529     SDict<SectionInfo>::Iterator sdi(*m_impl->sectionDict);
530     SectionInfo *si;
531     for (;(si=sdi.current());++sdi)
532     {
533       if (!si->generated && si->ref.isEmpty())
534       {
535         //printf("write an entry!\n");
536         if (definitionType()==TypeMember) tagFile << "  ";
537         tagFile << "    <docanchor file=\"" << si->fileName << "\"";
538         if (!si->title.isEmpty())
539         {
540           tagFile << " title=\"" << convertToXML(si->title) << "\"";
541         }
542         tagFile << ">" << si->label << "</docanchor>" << endl;
543       }
544     }
545   }
546 }
547
548 bool Definition::_docsAlreadyAdded(const QCString &doc,QCString &sigList)
549 {
550   uchar md5_sig[16];
551   QCString sigStr(33);
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
560   {
561     sigList+=":"+sigStr;
562     return FALSE;
563   }
564   else
565   {
566     return TRUE;
567   }
568 }
569
570 void Definition::_setDocumentation(const char *d,const char *docFile,int docLine,
571                                    bool stripWhiteSpace,bool atTop)
572 {
573   //printf("%s::setDocumentation(%s,%s,%d,%d)\n",name().data(),d,docFile,docLine,stripWhiteSpace);
574   if (d==0) return;
575   QCString doc = d;
576   if (stripWhiteSpace)
577   {
578     doc = stripLeadingAndTrailingEmptyLines(doc,docLine);
579   }
580   else // don't strip whitespace
581   {
582     doc=d;
583   }
584   if (!_docsAlreadyAdded(doc,m_impl->docSignatures))
585   {
586     //printf("setting docs for %s: `%s'\n",name().data(),m_doc.data());
587     if (m_impl->details==0)
588     {
589       m_impl->details = new DocInfo;
590     }
591     if (m_impl->details->doc.isEmpty()) // fresh detailed description
592     {
593       m_impl->details->doc = doc;
594     }
595     else if (atTop) // another detailed description, append it to the start
596     {
597       m_impl->details->doc = doc+"\n\n"+m_impl->details->doc;
598     }
599     else // another detailed description, append it to the end
600     {
601       m_impl->details->doc += "\n\n"+doc;
602     }
603     if (docLine!=-1) // store location if valid
604     {
605       m_impl->details->file = docFile;
606       m_impl->details->line = docLine;
607     }
608     else
609     {
610       m_impl->details->file = docFile;
611       m_impl->details->line = 1;
612     }
613   }
614 }
615
616 void Definition::setDocumentation(const char *d,const char *docFile,int docLine,bool stripWhiteSpace)
617 {
618   if (d==0) return;
619   _setDocumentation(d,docFile,docLine,stripWhiteSpace,FALSE);
620 }
621
622 #define uni_isupper(c) (QChar(c).category()==QChar::Letter_Uppercase)
623
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)
627 {
628   int l = s.length();
629   int p = 0;
630   int pp = -1;
631   while ((p=nextUtf8CharPosition(s,l,p))<l) pp=p;
632   if (pp==-1 || ((uchar)s[pp])<0x80) return FALSE;
633   return TRUE;
634 }
635
636 void Definition::_setBriefDescription(const char *b,const char *briefFile,int briefLine)
637 {
638   static QCString outputLanguage = Config_getEnum(OUTPUT_LANGUAGE);
639   static bool needsDot = outputLanguage!="Japanese" && 
640                          outputLanguage!="Chinese" &&
641                          outputLanguage!="Korean";
642   QCString brief = b;
643   brief = brief.stripWhiteSpace();
644   if (brief.isEmpty()) return;
645   int bl = brief.length();
646   if (bl>0 && needsDot) // add punctuation if needed
647   {
648     int c = brief.at(bl-1);
649     switch(c)
650     {
651       case '.': case '!': case '?': case '>': case ':': case ')': break;
652       default: 
653         if (uni_isupper(brief.at(0)) && !lastCharIsMultibyte(brief)) brief+='.'; 
654         break;
655     }
656   }
657
658   if (!_docsAlreadyAdded(brief,m_impl->briefSignatures))
659   {
660     if (m_impl->brief && !m_impl->brief->doc.isEmpty())
661     {
662        //printf("adding to details\n");
663        _setDocumentation(brief,briefFile,briefLine,FALSE,TRUE);
664     }
665     else
666     {
667       //fprintf(stderr,"Definition::setBriefDescription(%s,%s,%d)\n",b,briefFile,briefLine);
668       if (m_impl->brief==0)
669       {
670         m_impl->brief = new BriefInfo;
671       }
672       m_impl->brief->doc=brief;
673       if (briefLine!=-1)
674       {
675         m_impl->brief->file = briefFile;
676         m_impl->brief->line = briefLine;
677       }
678       else
679       {
680         m_impl->brief->file = briefFile;
681         m_impl->brief->line = 1;
682       }
683     }
684   }
685   else
686   {
687     //printf("do nothing!\n");
688   }
689 }
690
691 void Definition::setBriefDescription(const char *b,const char *briefFile,int briefLine) 
692
693   if (b==0) return;
694   _setBriefDescription(b,briefFile,briefLine);
695 }
696
697 void Definition::_setInbodyDocumentation(const char *doc,const char *inbodyFile,int inbodyLine)
698 {
699   if (m_impl->inbodyDocs==0)
700   {
701     m_impl->inbodyDocs = new DocInfo;
702   }
703   if (m_impl->inbodyDocs->doc.isEmpty()) // fresh inbody docs
704   {
705     m_impl->inbodyDocs->doc  = doc;
706     m_impl->inbodyDocs->file = inbodyFile;
707     m_impl->inbodyDocs->line = inbodyLine;
708   }
709   else // another inbody documentation fragment, append this to the end
710   {
711     m_impl->inbodyDocs->doc += QCString("\n\n")+doc;
712   }
713 }
714
715 void Definition::setInbodyDocumentation(const char *d,const char *inbodyFile,int inbodyLine)
716 {
717   if (d==0) return;
718   _setInbodyDocumentation(d,inbodyFile,inbodyLine);
719 }
720
721 //---------------------------------------
722
723 struct FilterCacheItem
724 {
725   portable_off_t filePos;
726   uint fileSize;
727 };
728
729 /*! Cache for storing the result of filtering a file */
730 class FilterCache
731 {
732   public:
733     FilterCache() : m_endPos(0) { m_cache.setAutoDelete(TRUE); }
734     bool getFileContents(const QCString &fileName,BufStr &str)
735     {
736       static bool filterSourceFiles = Config_getBool(FILTER_SOURCE_FILES);
737       QCString filter = getFileFilter(fileName,TRUE);
738       bool usePipe = !filter.isEmpty() && filterSourceFiles;
739       FILE *f=0;
740       const int blockSize = 4096;
741       char buf[blockSize];
742       FilterCacheItem *item=0;
743       if (usePipe && (item = m_cache.find(fileName))) // cache hit: reuse stored result
744       {
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");
750         if (f)
751         {
752           bool success=TRUE;
753           str.resize(item->fileSize+1);
754           if (portable_fseek(f,item->filePos,SEEK_SET)==-1)
755           {
756             err("Failed to seek to position %d in filter database file %s\n",(int)item->filePos,qPrint(Doxygen::filterDBFileName));
757             success=FALSE;
758           }
759           if (success)
760           {
761             int numBytes = fread(str.data(),1,item->fileSize,f);
762             if (numBytes!=item->fileSize)
763             {
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);
766               success=FALSE;
767             }
768           }
769           str.addChar('\0');
770           fclose(f);
771           return success;
772         }
773         else
774         {
775           err("Failed to open filter database file %s\n",qPrint(Doxygen::filterDBFileName));
776           return FALSE;
777         }
778       }
779       else if (usePipe) // cache miss: filter active but file not previously processed
780       {
781         //printf("getFileContents(%s): cache miss\n",qPrint(fileName));
782         // filter file
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;
789         if (bf==0)
790         {
791           // handle error
792           err("Error opening filter database file %s\n",qPrint(Doxygen::filterDBFileName));
793           str.addChar('\0');
794           delete item;
795           portable_pclose(f);
796           return FALSE;
797         }
798         // append the filtered output to the database file
799         int size=0;
800         while (!feof(f))
801         {
802           int bytesRead = fread(buf,1,blockSize,f);
803           int bytesWritten = fwrite(buf,1,bytesRead,bf);
804           if (bytesRead!=bytesWritten)
805           {
806             // handle error
807             err("Failed to write to filter database %s. Wrote %d out of %d bytes\n",
808                 qPrint(Doxygen::filterDBFileName),bytesWritten,bytesRead);
809             str.addChar('\0');
810             delete item;
811             portable_pclose(f);
812             fclose(bf);
813             return FALSE;
814           }
815           size+=bytesWritten;
816           str.addArray(buf,bytesWritten);
817         }
818         str.addChar('\0');
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
825         m_endPos += size;
826         portable_pclose(f);
827         fclose(bf);
828       }
829       else // no filtering
830       {
831         // normal file
832         //printf("getFileContents(%s): no filter\n",qPrint(fileName));
833         f = portable_fopen(fileName,"r");
834         while (!feof(f))
835         {
836           int bytesRead = fread(buf,1,blockSize,f);
837           str.addArray(buf,bytesRead);
838         }
839         str.addChar('\0');
840         fclose(f);
841       }
842       return TRUE;
843     }
844   private:
845     SDict<FilterCacheItem> m_cache;
846     portable_off_t m_endPos;
847 };
848
849 static FilterCache g_filterCache;
850
851 //-----------------------------------------
852
853
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
857  * found.
858  *
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.
864  */
865 bool readCodeFragment(const char *fileName,
866                       int &startLine,int &endLine,QCString &result)
867 {
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);
877
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
883   char *p=str.data();
884   if (p)
885   {
886     int c=0;
887     int col=0;
888     int lineNr=1;
889     // skip until the startLine has reached
890     while (lineNr<startLine && *p)
891     {
892       while ((c=*p++)!='\n' && c!=0) /* skip */;
893       lineNr++;
894       if (found && c == '\n') c = '\0';
895     }
896     if (*p)
897     {
898       // skip until the opening bracket or lonely : is found
899       char cn=0;
900       while (lineNr<=endLine && *p && !found)
901       {
902         int pc=0;
903         while ((c=*p++)!='{' && c!=':' && c!=0)
904         {
905           //printf("parsing char `%c'\n",c);
906           if (c=='\n')
907           {
908             lineNr++,col=0;
909           }
910           else if (c=='\t')
911           {
912             col+=tabSize - (col%tabSize);
913           }
914           else if (pc=='/' && c=='/') // skip single line comment
915           {
916             while ((c=*p++)!='\n' && c!=0) pc=c;
917             if (c=='\n') lineNr++,col=0;
918           }
919           else if (pc=='/' && c=='*') // skip C style comment
920           {
921             while (((c=*p++)!='/' || pc!='*') && c!=0)
922             {
923               if (c=='\n') lineNr++,col=0;
924               pc=c;
925             }
926           }
927           else
928           {
929             col++;
930           }
931           pc = c;
932         }
933         if (c==':')
934         {
935           cn=*p++;
936           if (cn!=':') found=TRUE;
937         }
938         else if (c=='{')
939         {
940           found=TRUE;
941         }
942       }
943       //printf(" -> readCodeFragment(%s,%d,%d) lineNr=%d\n",fileName,startLine,endLine,lineNr);
944       if (found)
945       {
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)
950         {
951           QCString spaces;
952           spaces.fill(' ',col);
953           result+=spaces;
954         }
955         // copy until end of line
956         if (c) result+=c;
957         startLine=lineNr;
958         if (c==':')
959         {
960           result+=cn;
961           if (cn=='\n') lineNr++;
962         }
963         char lineStr[blockSize];
964         do
965         {
966           //printf("reading line %d in range %d-%d\n",lineNr,startLine,endLine);
967           int size_read;
968           do
969           {
970             // read up to maxLineLength-1 bytes, the last byte being zero
971             int i=0;
972             while ((c=*p++) && i<blockSize-1)
973             {
974               lineStr[i++]=c;
975               if (c=='\n') break; // stop at end of the line
976             }
977             lineStr[i]=0;
978             size_read=i;
979             result+=lineStr; // append line to the output
980           } while (size_read == (blockSize-1)); // append more if line does not fit in buffer
981           lineNr++;
982         } while (lineNr<=endLine && *p);
983
984         // strip stuff after closing bracket
985         int newLineIndex = result.findRev('\n');
986         int braceIndex   = result.findRev('}');
987         if (braceIndex > newLineIndex)
988         {
989           result.truncate(braceIndex+1);
990         }
991         endLine=lineNr-1;
992       }
993     }
994     if (usePipe)
995     {
996       Debug::print(Debug::FilterOutput, 0, "Filter output\n");
997       Debug::print(Debug::FilterOutput,0,"-------------\n%s\n-------------\n",qPrint(result));
998     }
999   }
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());
1003   return found;
1004 }
1005
1006 QCString Definition::getSourceFileBase() const
1007
1008   ASSERT(definitionType()!=Definition::TypeFile); // file overloads this method
1009   QCString fn;
1010   static bool sourceBrowser = Config_getBool(SOURCE_BROWSER);
1011   if (sourceBrowser && 
1012       m_impl->body && m_impl->body->startLine!=-1 && m_impl->body->fileDef)
1013   {
1014     fn = m_impl->body->fileDef->getSourceFileBase();
1015   }
1016   return fn;
1017 }
1018
1019 QCString Definition::getSourceAnchor() const
1020 {
1021   const int maxAnchorStrLen = 20;
1022   char anchorStr[maxAnchorStrLen];
1023   anchorStr[0]='\0';
1024   if (m_impl->body && m_impl->body->startLine!=-1)
1025   {
1026     if (Htags::useHtags)
1027     {
1028       qsnprintf(anchorStr,maxAnchorStrLen,"L%d",m_impl->body->startLine);
1029     }
1030     else
1031     {
1032       qsnprintf(anchorStr,maxAnchorStrLen,"l%05d",m_impl->body->startLine);
1033     }
1034   }
1035   return anchorStr;
1036 }
1037
1038 /*! Write a reference to the source code defining this definition */
1039 void Definition::writeSourceDef(OutputList &ol,const char *)
1040 {
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();
1047   if (!fn.isEmpty())
1048   {
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.
1053     {
1054       QCString lineStr;
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
1059       {
1060         // write text left from linePos marker
1061         ol.parseText(refText.left(lineMarkerPos)); 
1062         ol.pushGeneratorState();
1063         ol.disable(OutputGenerator::Man); 
1064         if (!latexSourceCode)
1065         {
1066           ol.disable(OutputGenerator::Latex);
1067         }
1068         if (!docbookSourceCode)
1069         {
1070           ol.disable(OutputGenerator::Docbook);
1071         }
1072         if (!rtfSourceCode)
1073         {
1074           ol.disable(OutputGenerator::RTF);
1075         }
1076         // write line link (HTML and  optionally LaTeX, Docbook, RTF)
1077         ol.writeObjectLink(0,fn,anchorStr,lineStr);
1078         ol.enableAll();
1079         ol.disable(OutputGenerator::Html);
1080         if (latexSourceCode) 
1081         {
1082           ol.disable(OutputGenerator::Latex);
1083         }
1084         if (docbookSourceCode)
1085         {
1086           ol.disable(OutputGenerator::Docbook);
1087         }
1088         if (rtfSourceCode)
1089         {
1090           ol.disable(OutputGenerator::RTF);
1091         }
1092         // write normal text (Man, Latex optionally, RTF optionally)
1093         ol.docify(lineStr);
1094         ol.popGeneratorState();
1095         
1096         // write text between markers
1097         ol.parseText(refText.mid(lineMarkerPos+2,
1098               fileMarkerPos-lineMarkerPos-2));
1099
1100         ol.pushGeneratorState();
1101         ol.disable(OutputGenerator::Man); 
1102         if (!latexSourceCode)
1103         {
1104           ol.disable(OutputGenerator::Latex);
1105         }
1106         if (!docbookSourceCode)
1107         {
1108           ol.disable(OutputGenerator::Docbook);
1109         }
1110         if (!rtfSourceCode)
1111         {
1112           ol.disable(OutputGenerator::RTF);
1113         }
1114         // write file link (HTML, LaTeX optionally, RTF optionally)
1115         ol.writeObjectLink(0,fn,0,m_impl->body->fileDef->name());
1116         ol.enableAll();
1117         ol.disable(OutputGenerator::Html);
1118         if (latexSourceCode) 
1119         {
1120           ol.disable(OutputGenerator::Latex);
1121         }
1122         if (docbookSourceCode)
1123         {
1124           ol.disable(OutputGenerator::Docbook);
1125         }
1126         if (rtfSourceCode)
1127         {
1128           ol.disable(OutputGenerator::RTF);
1129         }
1130         // write normal text (Man, Latex optionally, RTF optionally)
1131         ol.docify(m_impl->body->fileDef->name());
1132         ol.popGeneratorState();
1133         
1134         // write text right from file marker
1135         ol.parseText(refText.right(
1136               refText.length()-fileMarkerPos-2)); 
1137       }
1138       else // file marker before line marker
1139       {
1140         // write text left from file marker
1141         ol.parseText(refText.left(fileMarkerPos)); 
1142         ol.pushGeneratorState();
1143         ol.disable(OutputGenerator::Man); 
1144         if (!latexSourceCode)
1145         {
1146           ol.disable(OutputGenerator::Latex);
1147         }
1148         if (!docbookSourceCode)
1149         {
1150           ol.disable(OutputGenerator::Docbook);
1151         }
1152         if (!rtfSourceCode)
1153         {
1154           ol.disable(OutputGenerator::RTF);
1155         }
1156         // write file link (HTML only)
1157         ol.writeObjectLink(0,fn,0,m_impl->body->fileDef->name());
1158         ol.enableAll();
1159         ol.disable(OutputGenerator::Html);
1160         if (latexSourceCode) 
1161         {
1162           ol.disable(OutputGenerator::Latex);
1163         }
1164         if (docbookSourceCode)
1165         {
1166           ol.disable(OutputGenerator::Docbook);
1167         }
1168         if (rtfSourceCode)
1169         {
1170           ol.disable(OutputGenerator::RTF);
1171         }
1172         // write normal text (RTF/Latex/Man only)
1173         ol.docify(m_impl->body->fileDef->name());
1174         ol.popGeneratorState();
1175         
1176         // write text between markers
1177         ol.parseText(refText.mid(fileMarkerPos+2,
1178               lineMarkerPos-fileMarkerPos-2)); 
1179
1180         ol.pushGeneratorState();
1181         ol.disable(OutputGenerator::Man); 
1182         ol.disableAllBut(OutputGenerator::Html); 
1183         if (latexSourceCode)
1184         {
1185           ol.enable(OutputGenerator::Latex);
1186         }
1187         if (docbookSourceCode)
1188         {
1189           ol.enable(OutputGenerator::Docbook);
1190         }
1191         if (rtfSourceCode)
1192         {
1193           ol.enable(OutputGenerator::RTF);
1194         }
1195         // write line link (HTML only)
1196         ol.writeObjectLink(0,fn,anchorStr,lineStr);
1197         ol.enableAll();
1198         ol.disable(OutputGenerator::Html);
1199         if (latexSourceCode) 
1200         {
1201           ol.disable(OutputGenerator::Latex);
1202         }
1203         if (docbookSourceCode)
1204         {
1205           ol.disable(OutputGenerator::Docbook);
1206         }
1207         if (rtfSourceCode)
1208         {
1209           ol.disable(OutputGenerator::RTF);
1210         }
1211         // write normal text (Latex/Man only)
1212         ol.docify(lineStr);
1213         ol.popGeneratorState();
1214
1215         // write text right from linePos marker
1216         ol.parseText(refText.right(
1217               refText.length()-lineMarkerPos-2)); 
1218       }
1219       ol.endParagraph();
1220     }
1221     else
1222     {
1223       err("translation error: invalid markers in trDefinedAtLineInSourceFile()\n");
1224     }
1225   }
1226   ol.popGeneratorState();
1227 }
1228
1229 void Definition::setBodySegment(int bls,int ble) 
1230 {
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; 
1235 }
1236
1237 void Definition::setBodyDef(FileDef *fd)         
1238 {
1239   if (m_impl->body==0) m_impl->body = new BodyInfo;
1240   m_impl->body->fileDef=fd; 
1241 }
1242
1243 bool Definition::hasSources() const
1244 {
1245   return m_impl->body && m_impl->body->startLine!=-1 &&
1246          m_impl->body->endLine>=m_impl->body->startLine &&
1247          m_impl->body->fileDef;
1248 }
1249
1250 /*! Write code of this definition into the documentation */
1251 void Definition::writeInlineCode(OutputList &ol,const char *scopeName)
1252 {
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())
1258   {
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)
1263        )
1264     {
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;
1272
1273       ol.startCodeFragment();
1274       pIntf->parseCode(ol,               // codeOutIntf
1275                        scopeName,        // scope
1276                        codeFragment,     // input
1277                        m_impl->lang,     // lang
1278                        FALSE,            // isExample
1279                        0,                // exampleName
1280                        m_impl->body->fileDef,  // fileDef
1281                        actualStart,      // startLine
1282                        actualEnd,        // endLine
1283                        TRUE,             // inlineFragment
1284                        thisMd,           // memberDef
1285                        TRUE              // show line numbers
1286                       );
1287       ol.endCodeFragment();
1288     }
1289   }
1290   ol.popGeneratorState();
1291 }
1292
1293 /*! Write a reference to the source code fragments in which this 
1294  *  definition is used.
1295  */
1296 void Definition::_writeSourceRefList(OutputList &ol,const char *scopeName,
1297     const QCString &text,MemberSDict *members,bool /*funcOnly*/)
1298 {
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();
1305   if (members)
1306   {
1307     members->sort();
1308
1309     ol.startParagraph("reference");
1310     ol.parseText(text);
1311     ol.docify(" ");
1312
1313     QCString ldefLine=theTranslator->trWriteList(members->count());
1314
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)
1319     {
1320       bool ok;
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);
1324       if (ok && md)
1325       {
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)
1330         {
1331           name.prepend(scope+getLanguageSpecificSeparator(m_impl->lang));
1332         }
1333         if (!md->isObjCMethod() &&
1334             (md->isFunction() || md->isSlot() || 
1335              md->isPrototype() || md->isSignal()
1336             )
1337            ) 
1338         {
1339           name+="()";
1340         }
1341         //Definition *d = md->getOutputFileBase();
1342         //if (d==Doxygen::globalScope) d=md->getBodyDef();
1343         if (sourceBrowser &&
1344             !(md->isLinkable() && !refLinkSource) && 
1345             md->getStartBodyLine()!=-1 && 
1346             md->getBodyDef()
1347            )
1348         {
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);
1353
1354           ol.disable(OutputGenerator::Man); 
1355           if (!latexSourceCode)
1356           {
1357             ol.disable(OutputGenerator::Latex);
1358           }
1359           if (!docbookSourceCode)
1360           {
1361             ol.disable(OutputGenerator::Docbook);
1362           }
1363           if (!rtfSourceCode)
1364           {
1365             ol.disable(OutputGenerator::RTF);
1366           }
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();
1373
1374           // for the other output formats just mention the name
1375           ol.pushGeneratorState();
1376           ol.disable(OutputGenerator::Html);
1377           if (latexSourceCode)
1378           {
1379             ol.disable(OutputGenerator::Latex);
1380           }
1381           if (docbookSourceCode)
1382           {
1383             ol.disable(OutputGenerator::Docbook);
1384           }
1385           if (rtfSourceCode)
1386           {
1387             ol.disable(OutputGenerator::RTF);
1388           }
1389           ol.docify(name);
1390           ol.popGeneratorState();
1391         }
1392         else if (md->isLinkable() /*&& d && d->isLinkable()*/)
1393         {
1394           // for HTML write a real link
1395           ol.pushGeneratorState();
1396           //ol.disableAllBut(OutputGenerator::Html); 
1397           ol.disable(OutputGenerator::Man); 
1398           if (!latexSourceCode)
1399           {
1400             ol.disable(OutputGenerator::Latex);
1401           }
1402           if (!docbookSourceCode)
1403           {
1404             ol.disable(OutputGenerator::Docbook);
1405           }
1406           if (!rtfSourceCode)
1407           {
1408             ol.disable(OutputGenerator::RTF);
1409           }
1410
1411           ol.writeObjectLink(md->getReference(),
1412               md->getOutputFileBase(),
1413               md->anchor(),name);
1414           ol.popGeneratorState();
1415
1416           // for the other output formats just mention the name
1417           ol.pushGeneratorState();
1418           ol.disable(OutputGenerator::Html);
1419           if (latexSourceCode)
1420           {
1421             ol.disable(OutputGenerator::Latex);
1422           }
1423           if (docbookSourceCode)
1424           {
1425             ol.disable(OutputGenerator::Docbook);
1426           }
1427           if (rtfSourceCode)
1428           {
1429             ol.disable(OutputGenerator::RTF);
1430           }
1431           ol.docify(name);
1432           ol.popGeneratorState();
1433         }
1434         else
1435         {
1436           ol.docify(name);
1437         }
1438       }
1439       index=newIndex+matchLen;
1440     } 
1441     ol.parseText(ldefLine.right(ldefLine.length()-index));
1442     ol.writeString(".");
1443     ol.endParagraph();
1444   }
1445   ol.popGeneratorState();
1446 }
1447
1448 void Definition::writeSourceReffedBy(OutputList &ol,const char *scopeName)
1449 {
1450   _writeSourceRefList(ol,scopeName,theTranslator->trReferencedBy(),m_impl->sourceRefByDict,FALSE);
1451 }
1452
1453 void Definition::writeSourceRefs(OutputList &ol,const char *scopeName)
1454 {
1455   _writeSourceRefList(ol,scopeName,theTranslator->trReferences(),m_impl->sourceRefsDict,TRUE);
1456 }
1457
1458 bool Definition::hasDocumentation() const
1459
1460   static bool extractAll    = Config_getBool(EXTRACT_ALL); 
1461   //static bool sourceBrowser = Config_getBool(SOURCE_BROWSER);
1462   bool hasDocs = 
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
1470   return hasDocs;
1471 }
1472
1473 bool Definition::hasUserDocumentation() const
1474 {
1475   bool hasDocs = 
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());
1479   return hasDocs;
1480 }
1481
1482
1483 void Definition::addSourceReferencedBy(MemberDef *md)
1484 {
1485   if (md)
1486   {
1487     QCString name  = md->name();
1488     QCString scope = md->getScopeString();
1489
1490     if (!scope.isEmpty())
1491     {
1492       name.prepend(scope+"::");
1493     }
1494
1495     if (m_impl->sourceRefByDict==0)
1496     {
1497       m_impl->sourceRefByDict = new MemberSDict;
1498     }
1499     if (m_impl->sourceRefByDict->find(name)==0)
1500     {
1501       m_impl->sourceRefByDict->append(name,md);
1502     }
1503   }
1504 }
1505
1506 void Definition::addSourceReferences(MemberDef *md)
1507 {
1508   if (md)
1509   {
1510     QCString name  = md->name();
1511     QCString scope = md->getScopeString();
1512
1513     if (!scope.isEmpty())
1514     {
1515       name.prepend(scope+"::");
1516     }
1517
1518     if (m_impl->sourceRefsDict==0)
1519     {
1520       m_impl->sourceRefsDict = new MemberSDict;
1521     }
1522     if (m_impl->sourceRefsDict->find(name)==0)
1523     {
1524       m_impl->sourceRefsDict->append(name,md);
1525     }
1526   }
1527 }
1528
1529 Definition *Definition::findInnerCompound(const char *) const
1530 {
1531   return 0;
1532 }
1533
1534 void Definition::addInnerCompound(Definition *)
1535 {
1536   err("Definition::addInnerCompound() called\n");
1537 }
1538
1539 QCString Definition::qualifiedName() const
1540 {
1541   //static int count=0;
1542   //count++;
1543   if (!m_impl->qualifiedName.isEmpty()) 
1544   {
1545     //count--;
1546     return m_impl->qualifiedName;
1547   }
1548   
1549   //printf("start %s::qualifiedName() localName=%s\n",name().data(),m_impl->localName.data());
1550   if (m_impl->outerScope==0) 
1551   {
1552     if (m_impl->localName=="<globalScope>") 
1553     {
1554       //count--;
1555       return "";
1556     }
1557     else 
1558     {
1559       //count--;
1560       return m_impl->localName; 
1561     }
1562   }
1563
1564   if (m_impl->outerScope->name()=="<globalScope>")
1565   {
1566     m_impl->qualifiedName = m_impl->localName;
1567   }
1568   else
1569   {
1570     m_impl->qualifiedName = m_impl->outerScope->qualifiedName()+
1571            getLanguageSpecificSeparator(getLanguage())+
1572            m_impl->localName;
1573   }
1574   //printf("end %s::qualifiedName()=%s\n",name().data(),m_impl->qualifiedName.data());
1575   //count--;
1576   return m_impl->qualifiedName;
1577 }
1578
1579 void Definition::setOuterScope(Definition *d)
1580 {
1581   //printf("%s::setOuterScope(%s)\n",name().data(),d?d->name().data():"<none>");
1582   Definition *p = m_impl->outerScope;
1583   bool found=false;
1584   // make sure that we are not creating a recursive scope relation.
1585   while (p && !found)
1586   {
1587     found = (p==d);
1588     p = p->m_impl->outerScope;
1589   }
1590   if (!found)
1591   {
1592     m_impl->qualifiedName.resize(0); // flush cached scope name
1593     m_impl->outerScope = d;
1594   }
1595   m_impl->hidden = m_impl->hidden || d->isHidden();
1596 }
1597
1598 QCString Definition::localName() const
1599 {
1600   return m_impl->localName;
1601 }
1602
1603 void Definition::makePartOfGroup(GroupDef *gd)
1604 {
1605   if (m_impl->partOfGroups==0) m_impl->partOfGroups = new GroupList;
1606   m_impl->partOfGroups->append(gd);
1607 }
1608
1609 void Definition::setRefItems(const QList<ListItemInfo> *sli)
1610 {
1611   //printf("%s::setRefItems()\n",name().data());
1612   if (sli)
1613   {
1614     // deep copy the list
1615     if (m_impl->xrefListItems==0) 
1616     {
1617       m_impl->xrefListItems=new QList<ListItemInfo>;
1618       m_impl->xrefListItems->setAutoDelete(TRUE);
1619     }
1620     QListIterator<ListItemInfo> slii(*sli);
1621     ListItemInfo *lii;
1622     for (slii.toFirst();(lii=slii.current());++slii)
1623     {
1624       m_impl->xrefListItems->append(new ListItemInfo(*lii));
1625     } 
1626   }
1627 }
1628
1629 void Definition::mergeRefItems(Definition *d)
1630 {
1631   //printf("%s::mergeRefItems()\n",name().data());
1632   QList<ListItemInfo> *xrefList = d->xrefListItems();
1633   if (xrefList!=0)
1634   {
1635     // deep copy the list
1636     if (m_impl->xrefListItems==0) 
1637     {
1638       m_impl->xrefListItems=new QList<ListItemInfo>;
1639       m_impl->xrefListItems->setAutoDelete(TRUE);
1640     }
1641     QListIterator<ListItemInfo> slii(*xrefList);
1642     QListIterator<ListItemInfo> mlii(*m_impl->xrefListItems);
1643     ListItemInfo *lii;
1644     ListItemInfo *mii;
1645     for (slii.toFirst();(lii=slii.current());++slii)
1646     {
1647       bool found = false;
1648       for (mlii.toFirst();(mii=mlii.current());++mlii)
1649       {
1650         if ((qstrcmp(lii->type,mii->type)==0) && (lii->itemId == mii->itemId))
1651         {
1652           found = true;
1653           break;
1654         }
1655       }
1656       if (!found) m_impl->xrefListItems->append(new ListItemInfo(*lii));
1657     } 
1658   }
1659 }
1660
1661 int Definition::_getXRefListId(const char *listName) const
1662 {
1663   if (m_impl->xrefListItems)
1664   {
1665     QListIterator<ListItemInfo> slii(*m_impl->xrefListItems);
1666     ListItemInfo *lii;
1667     for (slii.toFirst();(lii=slii.current());++slii)
1668     {
1669       if (qstrcmp(lii->type,listName)==0)
1670       {
1671         return lii->itemId;
1672       }
1673     }
1674   }
1675   return -1;
1676 }
1677
1678 QList<ListItemInfo> *Definition::xrefListItems() const
1679 {
1680   return m_impl->xrefListItems;
1681 }
1682
1683 QCString Definition::pathFragment() const
1684 {
1685   QCString result;
1686   if (m_impl->outerScope && m_impl->outerScope!=Doxygen::globalScope)
1687   {
1688     result = m_impl->outerScope->pathFragment();
1689   }
1690   if (isLinkable())
1691   {
1692     if (!result.isEmpty()) result+="/";
1693     if (definitionType()==Definition::TypeGroup && ((const GroupDef*)this)->groupTitle())
1694     {
1695       result+=((const GroupDef*)this)->groupTitle();
1696     }
1697     else if (definitionType()==Definition::TypePage && !((const PageDef*)this)->title().isEmpty())
1698     {
1699       result+=((const PageDef*)this)->title();
1700     }
1701     else
1702     {
1703       result+=m_impl->localName;
1704     }
1705   }
1706   else
1707   {
1708     result+=m_impl->localName;
1709   }
1710   return result;
1711 }
1712
1713 //----------------------------------------------------------------------------------------
1714
1715 // TODO: move to htmlgen
1716 /*! Returns the string used in the footer for $navpath when 
1717  *  GENERATE_TREEVIEW is enabled
1718  */
1719 QCString Definition::navigationPathAsString() const
1720 {
1721   QCString result;
1722   Definition *outerScope = getOuterScope();
1723   QCString locName = localName();
1724   if (outerScope && outerScope!=Doxygen::globalScope)
1725   {
1726     result+=outerScope->navigationPathAsString();
1727   }
1728   else if (definitionType()==Definition::TypeFile && ((const FileDef*)this)->getDirDef())
1729   {
1730     result+=((const FileDef*)this)->getDirDef()->navigationPathAsString();
1731   }
1732   result+="<li class=\"navelem\">";
1733   if (isLinkable())
1734   {
1735     if (definitionType()==Definition::TypeGroup && ((const GroupDef*)this)->groupTitle())
1736     {
1737       result+="<a class=\"el\" href=\"$relpath^"+getOutputFileBase()+Doxygen::htmlFileExtension+"\">"+
1738               convertToHtml(((const GroupDef*)this)->groupTitle())+"</a>";
1739     }
1740     else if (definitionType()==Definition::TypePage && !((const PageDef*)this)->title().isEmpty())
1741     {
1742       result+="<a class=\"el\" href=\"$relpath^"+getOutputFileBase()+Doxygen::htmlFileExtension+"\">"+
1743               convertToHtml(((const PageDef*)this)->title())+"</a>";
1744     }
1745     else if (definitionType()==Definition::TypeClass)
1746     {
1747       QCString name = locName;
1748       if (name.right(2)=="-p" /*|| name.right(2)=="-g"*/)
1749       {
1750         name = name.left(name.length()-2);
1751       }
1752       result+="<a class=\"el\" href=\"$relpath^"+getOutputFileBase()+Doxygen::htmlFileExtension;
1753       if (!anchor().isEmpty()) result+="#"+anchor();
1754       result+="\">"+convertToHtml(name)+"</a>";
1755     }
1756     else
1757     {
1758       result+="<a class=\"el\" href=\"$relpath^"+getOutputFileBase()+Doxygen::htmlFileExtension+"\">"+
1759               convertToHtml(locName)+"</a>";
1760     }
1761   }
1762   else
1763   {
1764     result+="<b>"+convertToHtml(locName)+"</b>";
1765   }
1766   result+="</li>";
1767   return result;
1768 }
1769
1770 // TODO: move to htmlgen
1771 void Definition::writeNavigationPath(OutputList &ol) const
1772 {
1773   ol.pushGeneratorState();
1774   ol.disableAllBut(OutputGenerator::Html);
1775
1776   QCString navPath;
1777   navPath += "<div id=\"nav-path\" class=\"navpath\">\n"
1778              "  <ul>\n";
1779   navPath += navigationPathAsString();
1780   navPath += "  </ul>\n"
1781              "</div>\n";
1782   ol.writeNavigationPath(navPath);
1783
1784   ol.popGeneratorState();
1785 }
1786
1787 // TODO: move to htmlgen
1788 void Definition::writeToc(OutputList &ol, const LocalToc &localToc)
1789 {
1790   SectionDict *sectionDict = m_impl->sectionDict;
1791   if (sectionDict==0) return;
1792   if (localToc.isHtmlEnabled())
1793   {
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);
1803     SectionInfo *si;
1804     int level=1,l;
1805     char cs[2];
1806     cs[1]='\0';
1807     bool inLi[5]={ FALSE, FALSE, FALSE, FALSE, FALSE };
1808     for (li.toFirst();(si=li.current());++li)
1809     {
1810       if (si->type==SectionInfo::Section       || 
1811           si->type==SectionInfo::Subsection    || 
1812           si->type==SectionInfo::Subsubsection ||
1813           si->type==SectionInfo::Paragraph)
1814       {
1815         //printf("  level=%d title=%s\n",level,si->title.data());
1816         int nextLevel = (int)si->type;
1817         if (nextLevel>level)
1818         {
1819           for (l=level;l<nextLevel;l++)
1820           {
1821             if (l < maxLevel) ol.writeString("<ul>");
1822           }
1823         }
1824         else if (nextLevel<level)
1825         {
1826           for (l=level;l>nextLevel;l--)
1827           {
1828             if (l <= maxLevel && inLi[l]) ol.writeString("</li>\n");
1829             inLi[l]=FALSE;
1830             if (l <= maxLevel) ol.writeString("</ul>\n");
1831           }
1832         }
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;
1838         level = nextLevel;
1839       }
1840     }
1841     if (level > maxLevel) level = maxLevel;
1842     while (level>1 && level <= maxLevel)
1843     {
1844       if (inLi[level]) ol.writeString("</li>\n");
1845       inLi[level]=FALSE;
1846       ol.writeString("</ul>\n");
1847       level--;
1848     }
1849     if (level <= maxLevel && inLi[level]) ol.writeString("</li>\n");
1850     inLi[level]=FALSE;
1851     ol.writeString("</ul>\n");
1852     ol.writeString("</div>\n");
1853     ol.popGeneratorState();
1854   }
1855
1856   if (localToc.isDocbookEnabled())
1857   {
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);
1864     SectionInfo *si;
1865     int level=1,l;
1866     bool inLi[5]={ FALSE, FALSE, FALSE, FALSE, FALSE };
1867     int maxLevel = localToc.docbookLevel();
1868     for (li.toFirst();(si=li.current());++li)
1869     {
1870       if (si->type==SectionInfo::Section       ||
1871           si->type==SectionInfo::Subsection    ||
1872           si->type==SectionInfo::Subsubsection ||
1873           si->type==SectionInfo::Paragraph)
1874       {
1875         //printf("  level=%d title=%s\n",level,si->title.data());
1876         int nextLevel = (int)si->type;
1877         if (nextLevel>level)
1878         {
1879           for (l=level;l<nextLevel;l++)
1880           {
1881             if (l < maxLevel) ol.writeString("    <tocdiv>\n");
1882           }
1883         }
1884         else if (nextLevel<level)
1885         {
1886           for (l=level;l>nextLevel;l--)
1887           {
1888             inLi[l]=FALSE;
1889             if (l <= maxLevel) ol.writeString("    </tocdiv>\n");
1890           }
1891         }
1892         if (nextLevel <= maxLevel)
1893         {
1894           QCString titleDoc = convertToDocBook(si->title);
1895           ol.writeString("      <tocentry>" + (si->title.isEmpty()?si->label:titleDoc) + "</tocentry>\n");
1896         }
1897         inLi[nextLevel]=TRUE;
1898         level = nextLevel;
1899       }
1900     }
1901     if (level > maxLevel) level = maxLevel;
1902     while (level>1 && level <= maxLevel)
1903     {
1904       inLi[level]=FALSE;
1905       ol.writeString("</tocdiv>\n");
1906       level--;
1907     }
1908     inLi[level]=FALSE;
1909     ol.writeString("    </toc>\n");
1910     ol.popGeneratorState();
1911   }
1912
1913   if (localToc.isLatexEnabled())
1914   {
1915     ol.pushGeneratorState();
1916     ol.disableAllBut(OutputGenerator::Latex);
1917     int maxLevel = localToc.latexLevel();
1918
1919     ol.writeString("\\etocsetnexttocdepth{"+QCString().setNum(maxLevel)+"}\n");
1920
1921     ol.writeString("\\localtableofcontents\n");
1922     ol.popGeneratorState();
1923   }
1924 }
1925
1926 //----------------------------------------------------------------------------------------
1927
1928 SectionDict * Definition::getSectionDict(void)
1929 {
1930   return m_impl->sectionDict;
1931 }
1932
1933 QCString Definition::symbolName() const 
1934
1935   return m_symbolName; 
1936 }
1937
1938 //----------------------
1939
1940 QCString Definition::documentation() const 
1941
1942   return m_impl->details ? m_impl->details->doc : QCString(""); 
1943 }
1944
1945 int Definition::docLine() const 
1946
1947   return m_impl->details ? m_impl->details->line : 1; 
1948 }
1949
1950 QCString Definition::docFile() const 
1951
1952   return m_impl->details ? m_impl->details->file : QCString("<"+m_name+">"); 
1953 }
1954
1955 //----------------------------------------------------------------------------
1956 // strips w from s iff s starts with w
1957 static bool stripWord(QCString &s,QCString w)
1958 {
1959   bool success=FALSE;
1960   if (s.left(w.length())==w) 
1961   {
1962     success=TRUE;
1963     s=s.right(s.length()-w.length());
1964   }
1965   return success;
1966 }
1967
1968 //----------------------------------------------------------------------------
1969 // some quasi intelligent brief description abbreviator :^)
1970 QCString abbreviate(const char *s,const char *name)
1971 {
1972   QCString scopelessName=name;
1973   int i=scopelessName.findRev("::");
1974   if (i!=-1) scopelessName=scopelessName.mid(i+2);
1975   QCString result=s;
1976   result=result.stripWhiteSpace();
1977   // strip trailing .
1978   if (!result.isEmpty() && result.at(result.length()-1)=='.') 
1979     result=result.left(result.length()-1);
1980
1981   // strip any predefined prefix
1982   QStrList &briefDescAbbrev = Config_getList(ABBREVIATE_BRIEF);
1983   const char *p = briefDescAbbrev.first();
1984   while (p)
1985   {
1986     QCString s = p;
1987     s.replace(QRegExp("\\$name"), scopelessName);  // replace $name with entity name
1988     s += " ";
1989     stripWord(result,s);
1990     p = briefDescAbbrev.next();
1991   }
1992
1993   // capitalize first word
1994   if (!result.isEmpty())
1995   {
1996     int c=result[0];
1997     if (c>='a' && c<='z') c+='A'-'a';
1998     result[0]=c;
1999   }
2000   return result;
2001 }
2002
2003
2004 //----------------------
2005
2006 QCString Definition::briefDescription(bool abbr) const 
2007
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) :
2011          QCString(""); 
2012 }
2013
2014 QCString Definition::briefDescriptionAsTooltip() const
2015 {
2016   if (m_impl->brief)
2017   {
2018     if (m_impl->brief->tooltip.isEmpty() && !m_impl->brief->doc.isEmpty())
2019     {
2020       static bool reentering=FALSE; 
2021       if (!reentering)
2022       {
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(
2027             scope,md,
2028             m_impl->brief->doc,
2029             m_impl->brief->file,
2030             m_impl->brief->line);
2031         reentering=FALSE;
2032       }
2033     }
2034     return m_impl->brief->tooltip;
2035   }
2036   return QCString("");
2037 }
2038
2039 int Definition::briefLine() const 
2040
2041   return m_impl->brief ? m_impl->brief->line : 1; 
2042 }
2043
2044 QCString Definition::briefFile() const 
2045
2046   return m_impl->brief ? m_impl->brief->file : QCString("<"+m_name+">"); 
2047 }
2048
2049 //----------------------
2050
2051 QCString Definition::inbodyDocumentation() const
2052 {
2053   return m_impl->inbodyDocs ? m_impl->inbodyDocs->doc : QCString(""); 
2054 }
2055
2056 int Definition::inbodyLine() const 
2057
2058   return m_impl->inbodyDocs ? m_impl->inbodyDocs->line : 1; 
2059 }
2060
2061 QCString Definition::inbodyFile() const 
2062
2063   return m_impl->inbodyDocs ? m_impl->inbodyDocs->file : QCString("<"+m_name+">"); 
2064 }
2065
2066
2067 //----------------------
2068
2069 QCString Definition::getDefFileName() const 
2070
2071   return m_impl->defFileName; 
2072 }
2073
2074 QCString Definition::getDefFileExtension() const 
2075
2076   return m_impl->defFileExt; 
2077 }
2078
2079 bool Definition::isHidden() const
2080 {
2081   return m_impl->hidden;
2082 }
2083
2084 bool Definition::isVisibleInProject() const 
2085
2086   return isLinkableInProject() && !m_impl->hidden; 
2087 }
2088
2089 bool Definition::isVisible() const
2090
2091   return isLinkable() && !m_impl->hidden; 
2092 }
2093
2094 bool Definition::isArtificial() const
2095 {
2096   return m_impl->isArtificial;
2097 }
2098
2099 QCString Definition::getReference() const 
2100
2101   return m_impl->ref; 
2102 }
2103
2104 bool Definition::isReference() const 
2105
2106   return !m_impl->ref.isEmpty(); 
2107 }
2108
2109 int Definition::getStartBodyLine() const         
2110
2111   return m_impl->body ? m_impl->body->startLine : -1; 
2112 }
2113
2114 int Definition::getEndBodyLine() const           
2115
2116   return m_impl->body ? m_impl->body->endLine : -1; 
2117 }
2118
2119 FileDef *Definition::getBodyDef() const
2120
2121   return m_impl->body ? m_impl->body->fileDef : 0; 
2122 }
2123
2124 GroupList *Definition::partOfGroups() const 
2125
2126   return m_impl->partOfGroups; 
2127 }
2128
2129 bool Definition::isLinkableViaGroup() const
2130 {
2131   GroupList *gl = partOfGroups();
2132   if (gl)
2133   {
2134     GroupListIterator gli(*gl);
2135     GroupDef *gd;
2136     for (gli.toFirst();(gd=gli.current());++gli)
2137     {
2138       if (gd->isLinkable()) return TRUE;
2139     }
2140   }
2141   return FALSE;
2142 }
2143
2144 Definition *Definition::getOuterScope() const 
2145
2146   return m_impl->outerScope; 
2147 }
2148
2149 MemberSDict *Definition::getReferencesMembers() const 
2150
2151   return m_impl->sourceRefsDict; 
2152 }
2153
2154 MemberSDict *Definition::getReferencedByMembers() const 
2155
2156   return m_impl->sourceRefByDict; 
2157 }
2158
2159 void Definition::setReference(const char *r) 
2160
2161   m_impl->ref=r; 
2162 }
2163
2164 SrcLangExt Definition::getLanguage() const
2165 {
2166   return m_impl->lang;
2167 }
2168
2169 void Definition::setHidden(bool b) 
2170
2171   m_impl->hidden = m_impl->hidden || b; 
2172 }
2173
2174 void Definition::setArtificial(bool b)
2175 {
2176   m_impl->isArtificial = b;
2177 }
2178
2179 void Definition::setLocalName(const QCString name) 
2180
2181   m_impl->localName=name; 
2182 }
2183
2184 void Definition::setLanguage(SrcLangExt lang) 
2185
2186   m_impl->lang=lang; 
2187 }
2188
2189
2190 void Definition::_setSymbolName(const QCString &name) 
2191
2192   m_symbolName=name; 
2193 }
2194
2195 bool Definition::hasBriefDescription() const
2196 {
2197   static bool briefMemberDesc = Config_getBool(BRIEF_MEMBER_DESC);
2198   return !briefDescription().isEmpty() && briefMemberDesc;
2199 }
2200
2201 QCString Definition::externalReference(const QCString &relPath) const
2202 {
2203   QCString ref = getReference();
2204   if (!ref.isEmpty())
2205   {
2206     QCString *dest = Doxygen::tagDestinationDict[ref];
2207     if (dest)
2208     {
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();
2215       }
2216       if (l>0 && result.at(l-1)!='/') result+='/';
2217       return result;
2218     }
2219   }
2220   return relPath;
2221 }
2222
2223
2224