Fix for UBSan build
[platform/upstream/doxygen.git] / src / definition.cpp
1 /******************************************************************************
2  *
3  * $Id: index.cpp,v 1.30 1999/03/06 22:15:39 root Exp $
4  *
5  * Copyright (C) 1997-2012 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 "qtbc.h"
19 #include <ctype.h>
20 #include <qregexp.h>
21 #include "md5.h"
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <assert.h>
25 #include "config.h"
26 #include "definition.h"
27 #include "doxygen.h"
28 #include "language.h"
29 #include "message.h"
30 #include "outputlist.h"
31 #include "code.h"
32 #include "util.h"
33 #include "groupdef.h"
34 #include "pagedef.h"
35 #include "section.h"
36 #include "htags.h"
37 #include "parserintf.h"
38 #include "marshal.h"
39 #include "debug.h"
40 #include "vhdldocgen.h"
41
42 #define START_MARKER 0x4445465B // DEF[
43 #define END_MARKER   0x4445465D // DEF]
44
45 //-----------------------------------------------------------------------------------------
46
47
48 /** Private data associated with a Symbol Definition object. */
49 class DefinitionImpl
50 {
51   public:
52     DefinitionImpl();
53    ~DefinitionImpl();
54     void init(const char *df, const char *n);
55
56     SectionDict *sectionDict;  // dictionary of all sections, not accessible
57
58     MemberSDict *sourceRefByDict;       
59     MemberSDict *sourceRefsDict;        
60     QList<ListItemInfo> *xrefListItems; 
61     GroupList *partOfGroups;            
62
63     DocInfo   *details;    // not exported
64     DocInfo   *inbodyDocs; // not exported
65     BriefInfo *brief;      // not exported
66     BodyInfo  *body;       // not exported
67     QCString   docSignatures;
68
69     QCString localName;      // local (unqualified) name of the definition
70                              // in the future m_name should become m_localName
71     QCString qualifiedName;
72     QCString ref;   // reference to external documentation
73
74     bool hidden;
75     bool isArtificial;
76
77     Definition *outerScope;  // not owner
78
79     // where the item was found
80     QCString defFileName;
81     QCString defFileExt;
82
83     SrcLangExt lang;
84 };
85
86 DefinitionImpl::DefinitionImpl() 
87   : sectionDict(0), sourceRefByDict(0), sourceRefsDict(0), 
88     xrefListItems(0), partOfGroups(0),
89     details(0), inbodyDocs(0), brief(0), body(0), 
90     outerScope(0)
91 {
92 }
93
94 DefinitionImpl::~DefinitionImpl()
95 {
96   delete sectionDict;
97   delete sourceRefByDict;
98   delete sourceRefsDict;
99   delete partOfGroups;
100   delete xrefListItems;
101   delete brief;
102   delete details;
103   delete body;
104   delete inbodyDocs;
105 }
106
107 void DefinitionImpl::init(const char *df, const char *n)
108 {
109   defFileName = df;
110   int lastDot = defFileName.findRev('.');
111   if (lastDot!=-1)
112   {
113     defFileExt = defFileName.mid(lastDot);
114   }
115   QCString name = n;
116   if (name!="<globalScope>") 
117   {
118     //extractNamespaceName(m_name,m_localName,ns);
119     localName=stripScope(n);
120   }
121   else
122   {
123     localName=n;
124   }
125   //printf("m_localName=%s\n",m_localName.data());
126
127   brief           = 0;
128   details         = 0;
129   body            = 0;
130   inbodyDocs      = 0;
131   sourceRefByDict = 0;
132   sourceRefsDict  = 0;
133   sectionDict     = 0, 
134   outerScope      = Doxygen::globalScope;
135   partOfGroups    = 0;
136   xrefListItems   = 0;
137   hidden          = FALSE;
138   isArtificial    = FALSE;
139   lang            = SrcLangExt_Unknown;
140 }
141
142 //-----------------------------------------------------------------------------------------
143
144 static bool matchExcludedSymbols(const char *name)
145 {
146   static QStrList &exclSyms = Config_getList("EXCLUDE_SYMBOLS");
147   if (exclSyms.count()==0) return FALSE; // nothing specified
148   const char *pat = exclSyms.first();
149   QCString symName = name;
150   while (pat)
151   {
152     QCString pattern = pat;
153     bool forceStart=FALSE;
154     bool forceEnd=FALSE;
155     if (pattern.at(0)=='^') 
156       pattern=pattern.mid(1),forceStart=TRUE;
157     if (pattern.at(pattern.length()-1)=='$') 
158       pattern=pattern.left(pattern.length()-1),forceEnd=TRUE;
159     if (pattern.find('*')!=-1) // wildcard mode
160     {
161       QRegExp re(substitute(pattern,"*",".*"),TRUE);
162       int i,pl;
163       i = re.match(symName,0,&pl);
164       //printf("  %d = re.match(%s) pattern=%s\n",i,symName.data(),pattern.data());
165       if (i!=-1) // wildcard match
166       {
167         int sl=symName.length();
168         // check if it is a whole word match
169         if ((i==0     || pattern.at(0)=='*'    || (!isId(symName.at(i-1))  && !forceStart)) &&
170             (i+pl==sl || pattern.at(i+pl)=='*' || (!isId(symName.at(i+pl)) && !forceEnd))
171            )
172         {
173           //printf("--> name=%s pattern=%s match at %d\n",symName.data(),pattern.data(),i);
174           return TRUE;
175         }
176       }
177     }
178     else if (!pattern.isEmpty()) // match words
179     {
180       int i = symName.find(pattern);
181       if (i!=-1) // we have a match!
182       {
183         int pl=pattern.length();
184         int sl=symName.length();
185         // check if it is a whole word match
186         if ((i==0     || (!isId(symName.at(i-1))  && !forceStart)) &&
187             (i+pl==sl || (!isId(symName.at(i+pl)) && !forceEnd))
188            )
189         {
190           //printf("--> name=%s pattern=%s match at %d\n",symName.data(),pattern.data(),i);
191           return TRUE; 
192         }
193       }
194     }
195     pat = exclSyms.next();
196   }
197   //printf("--> name=%s: no match\n",name);
198   return FALSE;
199 }
200
201 void Definition::addToMap(const char *name,Definition *d)
202 {
203   bool vhdlOpt = Config_getBool("OPTIMIZE_OUTPUT_VHDL");
204   QCString symbolName = name;
205   int index=computeQualifiedIndex(symbolName);
206   if (!vhdlOpt && index!=-1) symbolName=symbolName.mid(index+2);
207   if (!symbolName.isEmpty()) 
208   {
209     //printf("******* adding symbol `%s' (%p)\n",symbolName.data(),d);
210     DefinitionIntf *di=Doxygen::symbolMap->find(symbolName);
211     //printf("  addToMap(%p): looking for symbol %s: %p\n",d,symbolName.data(),di);
212     if (di==0) // new Symbol
213     {
214       //printf("  new symbol!\n");
215       Doxygen::symbolMap->insert(symbolName,d);
216     }
217     else // existing symbol
218     {
219       //printf("  existing symbol: ");
220       if (di->definitionType()==DefinitionIntf::TypeSymbolList) // already multiple symbols
221       {
222         //printf("adding to exiting list\n");
223         DefinitionList *dl = (DefinitionList*)di;
224         dl->append(d);
225       }
226       else // going from one to two symbols
227       {
228         Doxygen::symbolMap->take(symbolName);
229         DefinitionList *dl = new DefinitionList;
230         //printf("replacing symbol by list %p with elements %p and %p\n",dl,di,d);
231         dl->append((Definition*)di);
232         dl->append(d);
233         Doxygen::symbolMap->insert(symbolName,dl);
234       }
235     }
236
237     // auto resize if needed
238     static int sizeIndex=9;
239     if (Doxygen::symbolMap->size()>SDict_primes[sizeIndex])
240     {
241       Doxygen::symbolMap->resize(SDict_primes[++sizeIndex]);
242     }
243
244     d->_setSymbolName(symbolName);
245   }
246 }
247
248 void Definition::removeFromMap(Definition *d)
249 {
250   QCString symbolName = d->m_symbolName;
251   if (!symbolName.isEmpty()) 
252   {
253     //printf("******* removing symbol `%s' (%p)\n",symbolName.data(),d);
254     DefinitionIntf *di=Doxygen::symbolMap->find(symbolName);
255     if (di)
256     {
257       if (di!=d) // symbolName not unique
258       {
259         //printf("  removing from list: %p!\n",di);
260         DefinitionList *dl = (DefinitionList*)di;
261         bool b = dl->removeRef(d);
262         ASSERT(b==TRUE);
263         if (dl->isEmpty())
264         {
265           Doxygen::symbolMap->take(symbolName);
266         }
267       }
268       else // symbolName unique
269       {
270         //printf("  removing symbol %p\n",di);
271         Doxygen::symbolMap->take(symbolName);
272       }
273     }
274   }
275 }
276
277 Definition::Definition(const char *df,int dl,
278                        const char *name,const char *b,
279                        const char *d,bool isSymbol)
280 {
281   m_name = name;
282   m_defLine = dl;
283   m_impl = new DefinitionImpl;
284   m_impl->init(df,name);
285   m_isSymbol = isSymbol;
286   if (isSymbol) addToMap(name,this);
287   _setBriefDescription(b,df,dl);
288   _setDocumentation(d,df,dl,TRUE,FALSE);
289   if (matchExcludedSymbols(name)) 
290   {
291     m_impl->hidden = TRUE;
292   }
293 }
294
295 Definition::Definition(const Definition &d) : DefinitionIntf(), LockableObj()
296 {
297   m_name = d.m_name;
298   m_defLine = d.m_defLine;
299   m_impl = new DefinitionImpl;
300   *m_impl = *d.m_impl;
301   m_impl->sectionDict = 0;
302   m_impl->sourceRefByDict = 0;
303   m_impl->sourceRefsDict = 0;
304   m_impl->partOfGroups = 0;
305   m_impl->xrefListItems = 0;
306   m_impl->brief = 0;
307   m_impl->details = 0;
308   m_impl->body = 0;
309   m_impl->inbodyDocs = 0;
310   if (d.m_impl->sectionDict)
311   {
312     m_impl->sectionDict = new SectionDict(17);
313     SDict<SectionInfo>::Iterator it(*d.m_impl->sectionDict);
314     SectionInfo *si;
315     for (it.toFirst();(si=it.current());++it)
316     {
317       m_impl->sectionDict->append(si->label,si);
318     }
319   }
320   if (d.m_impl->sourceRefByDict)
321   {
322     m_impl->sourceRefByDict = new MemberSDict;
323     MemberSDict::IteratorDict it(*d.m_impl->sourceRefByDict);
324     MemberDef *md;
325     for (it.toFirst();(md=it.current());++it)
326     {
327       m_impl->sourceRefByDict->append(it.currentKey(),md);
328     }
329   }
330   if (d.m_impl->sourceRefsDict)
331   {
332     m_impl->sourceRefsDict = new MemberSDict;
333     MemberSDict::IteratorDict it(*d.m_impl->sourceRefsDict);
334     MemberDef *md;
335     for (it.toFirst();(md=it.current());++it)
336     {
337       m_impl->sourceRefsDict->append(it.currentKey(),md);
338     }
339   }
340   if (d.m_impl->partOfGroups)
341   {
342     GroupListIterator it(*d.m_impl->partOfGroups);
343     GroupDef *gd;
344     for (it.toFirst();(gd=it.current());++it)
345     {
346       makePartOfGroup(gd);
347     }
348   }
349   if (d.m_impl->xrefListItems)
350   {
351     setRefItems(d.m_impl->xrefListItems);
352   }
353   if (d.m_impl->brief)
354   {
355     m_impl->brief = new BriefInfo(*d.m_impl->brief);
356   }
357   if (d.m_impl->details)
358   {
359     m_impl->details = new DocInfo(*d.m_impl->details);
360   }
361   if (d.m_impl->body)
362   {
363     m_impl->body = new BodyInfo(*d.m_impl->body);
364   }
365   if (d.m_impl->inbodyDocs)
366   {
367     m_impl->details = new DocInfo(*d.m_impl->inbodyDocs);
368   }
369
370   m_isSymbol = d.m_isSymbol;
371   if (m_isSymbol) addToMap(m_name,this);
372 }
373
374 Definition::~Definition()
375 {
376   if (m_isSymbol) 
377   {
378     removeFromMap(this);
379   }
380   if (m_impl)
381   {
382     delete m_impl;
383     m_impl=0;
384   }
385 }
386
387 void Definition::setName(const char *name)
388 {
389   if (name==0) return;
390   m_name = name;
391 }
392
393 void Definition::addSectionsToDefinition(QList<SectionInfo> *anchorList)
394 {
395   if (!anchorList) return;
396   makeResident();
397   //printf("%s: addSectionsToDefinition(%d)\n",name().data(),anchorList->count());
398   SectionInfo *si=anchorList->first();
399   while (si)
400   {
401     //printf("Add section `%s' to definition `%s'\n",
402     //    si->label.data(),name().data());
403     SectionInfo *gsi=Doxygen::sectionDict.find(si->label);
404     //printf("===== label=%s gsi=%p\n",si->label.data(),gsi);
405     if (gsi==0)
406     {
407       gsi = new SectionInfo(*si);
408       Doxygen::sectionDict.append(si->label,gsi);
409     }
410     if (m_impl->sectionDict==0) 
411     {
412       m_impl->sectionDict = new SectionDict(17);
413     }
414     if (m_impl->sectionDict->find(gsi->label)==0)
415     {
416       m_impl->sectionDict->append(gsi->label,gsi);
417       gsi->definition = this;
418     }
419     si=anchorList->next();
420   }
421 }
422
423 bool Definition::hasSections() const
424 {
425   makeResident();
426   //printf("Definition::hasSections(%s) #sections=%d\n",name().data(),
427   //    m_impl->sectionDict ? m_impl->sectionDict->count() : 0);
428   if (m_impl->sectionDict==0) return FALSE;
429   SDict<SectionInfo>::Iterator li(*m_impl->sectionDict);
430   SectionInfo *si;
431   for (li.toFirst();(si=li.current());++li)
432   {
433     if (si->type==SectionInfo::Section || 
434         si->type==SectionInfo::Subsection || 
435         si->type==SectionInfo::Subsubsection ||
436         si->type==SectionInfo::Paragraph)
437     {
438       return TRUE;
439     }
440   }
441   return FALSE;
442 }
443
444 void Definition::addSectionsToIndex()
445 {
446   makeResident();
447   if (m_impl->sectionDict==0) return;
448   //printf("Definition::addSectionsToIndex()\n");
449   SDict<SectionInfo>::Iterator li(*m_impl->sectionDict);
450   SectionInfo *si;
451   int level=1;
452   for (li.toFirst();(si=li.current());++li)
453   {
454     if (si->type==SectionInfo::Section       || 
455         si->type==SectionInfo::Subsection    || 
456         si->type==SectionInfo::Subsubsection ||
457         si->type==SectionInfo::Paragraph)
458     {
459       //printf("  level=%d title=%s\n",level,si->title.data());
460       int nextLevel = (int)si->type;
461       int i;
462       if (nextLevel>level)
463       {
464         for (i=level;i<nextLevel;i++)
465         {
466           Doxygen::indexList.incContentsDepth();
467         }
468       }
469       else if (nextLevel<level)
470       {
471         for (i=nextLevel;i<level;i++)
472         {
473           Doxygen::indexList.decContentsDepth();
474         }
475       }
476       QCString title = si->title;
477       if (title.isEmpty()) title = si->label;
478       Doxygen::indexList.addContentsItem(TRUE,title,
479                                          getReference(),
480                                          getOutputFileBase(),
481                                          si->label,
482                                          FALSE,
483                                          TRUE);
484       level = nextLevel;
485     }
486   }
487   while (level>1)
488   {
489     Doxygen::indexList.decContentsDepth();
490     level--;
491   }
492 }
493
494 void Definition::writeDocAnchorsToTagFile()
495 {
496   makeResident();
497   if (!Config_getString("GENERATE_TAGFILE").isEmpty() && m_impl->sectionDict)
498   {
499     //printf("%s: writeDocAnchorsToTagFile(%d)\n",name().data(),m_sectionDict->count());
500     SDict<SectionInfo>::Iterator sdi(*m_impl->sectionDict);
501     SectionInfo *si;
502     for (;(si=sdi.current());++sdi)
503     {
504       if (!si->generated)
505       {
506         //printf("write an entry!\n");
507         if (definitionType()==TypeMember) Doxygen::tagFile << "  ";
508         Doxygen::tagFile << "    <docanchor file=\"" 
509                          << si->fileName << "\">" << si->label 
510                          << "</docanchor>" << endl;
511       }
512     }
513   }
514 }
515
516 bool Definition::_docsAlreadyAdded(const QCString &doc)
517 {
518   uchar md5_sig[16];
519   QCString sigStr(33);
520   // to avoid mismatches due to differences in indenting, we first remove
521   // double whitespaces...
522   QCString docStr = doc.simplifyWhiteSpace();
523   MD5Buffer((const unsigned char *)docStr.data(),docStr.length(),md5_sig);
524   MD5SigToString(md5_sig,sigStr.data(),33);
525   if (m_impl->docSignatures.find(sigStr)==-1) // new docs, add signature to prevent re-adding it
526   {
527     m_impl->docSignatures+=":"+sigStr;
528     return FALSE;
529   }
530   else
531   {
532     return TRUE;
533   }
534 }
535
536 void Definition::_setDocumentation(const char *d,const char *docFile,int docLine,
537                                    bool stripWhiteSpace,bool atTop)
538 {
539   //printf("%s::setDocumentation(%s,%s,%d,%d)\n",name().data(),d,docFile,docLine,stripWhiteSpace);
540   if (d==0) return;
541   QCString doc = d;
542   if (stripWhiteSpace)
543   {
544     doc = stripLeadingAndTrailingEmptyLines(doc,docLine);
545   }
546   else // don't strip whitespace
547   {
548     doc=d;
549   }
550   if (!_docsAlreadyAdded(doc))
551   {
552     //printf("setting docs for %s: `%s'\n",name().data(),m_doc.data());
553     if (m_impl->details==0)
554     {
555       m_impl->details = new DocInfo;
556     }
557     if (m_impl->details->doc.isEmpty()) // fresh detailed description
558     {
559       m_impl->details->doc = doc;
560     }
561     else if (atTop) // another detailed description, append it to the start
562     {
563       m_impl->details->doc = doc+"\n\n"+m_impl->details->doc;
564     }
565     else // another detailed description, append it to the end
566     {
567       m_impl->details->doc += "\n\n"+doc;
568     }
569     if (docLine!=-1) // store location if valid
570     {
571       m_impl->details->file = docFile;
572       m_impl->details->line = docLine;
573     }
574     else
575     {
576       m_impl->details->file = docFile;
577       m_impl->details->line = 1;
578     }
579   }
580 }
581
582 void Definition::setDocumentation(const char *d,const char *docFile,int docLine,bool stripWhiteSpace)
583 {
584   if (d==0) return;
585   makeResident();
586   _setDocumentation(d,docFile,docLine,stripWhiteSpace,FALSE);
587 }
588
589 #define uni_isupper(c) (QChar(c).category()==QChar::Letter_Uppercase)
590
591 // do a UTF-8 aware search for the last real character and return TRUE 
592 // if that is a multibyte one.
593 static bool lastCharIsMultibyte(const QCString &s)
594 {
595   int l = s.length();
596   int p = 0;
597   int pp = -1;
598   while ((p=nextUtf8CharPosition(s,l,p))<l) pp=p;
599   if (pp==-1 || ((uchar)s[pp])<0x80) return FALSE;
600   return TRUE;
601 }
602
603 void Definition::_setBriefDescription(const char *b,const char *briefFile,int briefLine)
604 {
605   static QCString outputLanguage = Config_getEnum("OUTPUT_LANGUAGE");
606   static bool needsDot = outputLanguage!="Japanese" && 
607                          outputLanguage!="Chinese" &&
608                          outputLanguage!="Korean";
609   QCString brief = b;
610   brief = brief.stripWhiteSpace();
611   if (brief.isEmpty()) return;
612   int bl = brief.length();
613   if (bl>0 && needsDot) // add punctuation if needed
614   {
615     int c = brief.at(bl-1);
616     switch(c)
617     {
618       case '.': case '!': case '?': case '>': case ':': case ')': break;
619       default: 
620         if (uni_isupper(brief.at(0)) && !lastCharIsMultibyte(brief)) brief+='.'; 
621         break;
622     }
623   }
624
625   if (m_impl->brief && !m_impl->brief->doc.isEmpty())
626   {
627       //printf("adding to details\n");
628       _setDocumentation(brief,briefFile,briefLine,FALSE,TRUE);
629   }
630   else if (!_docsAlreadyAdded(brief))
631   {
632     //fprintf(stderr,"Definition::setBriefDescription(%s,%s,%d)\n",b,briefFile,briefLine);
633     if (m_impl->brief==0)
634     {
635       m_impl->brief = new BriefInfo;
636     }
637     m_impl->brief->doc=brief;
638     if (briefLine!=-1)
639     {
640       m_impl->brief->file = briefFile;
641       m_impl->brief->line = briefLine;
642     }
643     else
644     {
645       m_impl->brief->file = briefFile;
646       m_impl->brief->line = 1;
647     }
648   }
649 }
650
651 void Definition::setBriefDescription(const char *b,const char *briefFile,int briefLine) 
652
653   if (b==0) return;
654   makeResident();
655   _setBriefDescription(b,briefFile,briefLine);
656 }
657
658 void Definition::_setInbodyDocumentation(const char *doc,const char *inbodyFile,int inbodyLine)
659 {
660   if (m_impl->inbodyDocs==0)
661   {
662     m_impl->inbodyDocs = new DocInfo;
663   }
664   if (m_impl->inbodyDocs->doc.isEmpty()) // fresh inbody docs
665   {
666     m_impl->inbodyDocs->doc  = doc;
667     m_impl->inbodyDocs->file = inbodyFile;
668     m_impl->inbodyDocs->line = inbodyLine;
669   }
670   else // another inbody documentation fragment, append this to the end
671   {
672     m_impl->inbodyDocs->doc += QCString("\n\n")+doc;
673   }
674 }
675
676 void Definition::setInbodyDocumentation(const char *d,const char *inbodyFile,int inbodyLine)
677 {
678   if (d==0) return;
679   makeResident();
680   _setInbodyDocumentation(d,inbodyFile,inbodyLine);
681 }
682
683 /*! Reads a fragment of code from file \a fileName starting at 
684  * line \a startLine and ending at line \a endLine (inclusive). The fragment is
685  * stored in \a result. If FALSE is returned the code fragment could not be
686  * found.
687  *
688  * The file is scanned for a opening bracket ('{') from \a startLine onward
689  * The line actually containing the bracket is returned via startLine.
690  * The file is scanned for a closing bracket ('}') from \a endLine backward.
691  * The line actually containing the bracket is returned via endLine.
692  * Note that for VHDL code the bracket search is not done.
693  */
694 static bool readCodeFragment(const char *fileName,
695                       int &startLine,int &endLine,QCString &result)
696 {
697   static bool filterSourceFiles = Config_getBool("FILTER_SOURCE_FILES");
698   static int tabSize = Config_getInt("TAB_SIZE");
699   //printf("readCodeFragment(%s,%d,%d)\n",fileName,startLine,endLine);
700   if (fileName==0 || fileName[0]==0) return FALSE; // not a valid file name
701   QCString filter = getFileFilter(fileName,TRUE);
702   FILE *f=0;
703   bool usePipe = !filter.isEmpty() && filterSourceFiles;
704   SrcLangExt lang = getLanguageFromFileName(fileName);
705   if (!usePipe) // no filter given or wanted
706   {
707     f = portable_fopen(fileName,"r");
708   }
709   else // use filter
710   {
711     QCString cmd=filter+" \""+fileName+"\"";
712     Debug::print(Debug::ExtCmd,0,"Executing popen(`%s`)\n",cmd.data());
713     f = portable_popen(cmd,"r");
714   }
715   bool found = lang==SrcLangExt_VHDL   || 
716                lang==SrcLangExt_Tcl    || 
717                lang==SrcLangExt_Python || 
718                lang==SrcLangExt_Fortran;  
719                // for VHDL, TCL, Python, and Fortran no bracket search is possible
720   if (f)
721   {
722     int c=0;
723     int col=0;
724     int lineNr=1;
725     // skip until the startLine has reached
726     while (lineNr<startLine && !feof(f))
727     {
728       while ((c=fgetc(f))!='\n' && c!=EOF) /* skip */;
729       lineNr++; 
730     }
731     if (!feof(f))
732     {
733       // skip until the opening bracket or lonely : is found
734       char cn=0;
735       while (lineNr<=endLine && !feof(f) && !found)
736       {
737         int pc=0;
738         while ((c=fgetc(f))!='{' && c!=':' && c!=EOF) 
739         {
740           //printf("parsing char `%c'\n",c);
741           if (c=='\n') 
742           {
743             lineNr++,col=0; 
744           }
745           else if (c=='\t') 
746           {
747             col+=tabSize - (col%tabSize);
748           }
749           else if (pc=='/' && c=='/') // skip single line comment
750           {
751             while ((c=fgetc(f))!='\n' && c!=EOF) pc=c;
752             if (c=='\n') lineNr++,col=0;
753           }
754           else if (pc=='/' && c=='*') // skip C style comment
755           {
756             while (((c=fgetc(f))!='/' || pc!='*') && c!=EOF) 
757             {
758               if (c=='\n') lineNr++,col=0;
759               pc=c;
760             }
761           }
762           else
763           {
764             col++;
765           }
766           pc = c;
767         }
768         if (c==':')
769         {
770           cn=fgetc(f);
771           if (cn!=':') found=TRUE;
772         }
773         else if (c=='{')   // } so vi matching brackets has no problem
774         {
775           found=TRUE;
776         }
777       }
778       //printf(" -> readCodeFragment(%s,%d,%d) lineNr=%d\n",fileName,startLine,endLine,lineNr);
779       if (found) 
780       {
781         // For code with more than one line,
782         // fill the line with spaces until we are at the right column
783         // so that the opening brace lines up with the closing brace
784         if (endLine!=startLine)
785         {
786           QCString spaces;
787           spaces.fill(' ',col);
788           result+=spaces;
789         }
790         // copy until end of line
791         result+=c;
792         if (c==':') 
793         {
794           result+=cn;
795           if (cn=='\n') lineNr++;
796         }
797         startLine=lineNr;
798         const int maxLineLength=4096;
799         char lineStr[maxLineLength];
800         do 
801         {
802           //printf("reading line %d in range %d-%d\n",lineNr,startLine,endLine);
803           int size_read;
804           do 
805           {
806             // read up to maxLineLength-1 bytes, the last byte being zero
807             char *p = fgets(lineStr, maxLineLength,f);
808             //printf("  read %s",p);
809             if (p) 
810             {
811               size_read=qstrlen(p); 
812             }
813             else  // nothing read
814             {
815               size_read=-1;
816               lineStr[0]='\0';
817             }
818             result+=lineStr;
819           } while (size_read == (maxLineLength-1));
820
821           lineNr++; 
822         } while (lineNr<=endLine && !feof(f));
823
824         // strip stuff after closing bracket
825         int newLineIndex = result.findRev('\n');
826         int braceIndex   = result.findRev('}');
827         if (braceIndex > newLineIndex) 
828         {
829           result.truncate(braceIndex+1);
830         }
831         endLine=lineNr-1;
832       }
833     }
834     if (usePipe) 
835     {
836       portable_pclose(f); 
837       Debug::print(Debug::FilterOutput, 0, "Filter output\n");
838       Debug::print(Debug::FilterOutput,0,"-------------\n%s\n-------------\n",result.data());
839     }
840     else 
841     {
842       fclose(f);
843     }
844   }
845   result = transcodeCharacterStringToUTF8(result);
846   return found;
847 }
848
849 /*! Write a reference to the source code defining this definition */
850 void Definition::writeSourceDef(OutputList &ol,const char *)
851 {
852   static bool sourceBrowser = Config_getBool("SOURCE_BROWSER");
853   static bool latexSourceCode = Config_getBool("LATEX_SOURCE_CODE");
854   makeResident();
855   ol.pushGeneratorState();
856   //printf("Definition::writeSourceRef %d %p\n",bodyLine,bodyDef);
857   if (sourceBrowser && 
858       m_impl->body && m_impl->body->startLine!=-1 && m_impl->body->fileDef)
859   {
860     QCString refText = theTranslator->trDefinedAtLineInSourceFile();
861     int lineMarkerPos = refText.find("@0");
862     int fileMarkerPos = refText.find("@1");
863     if (lineMarkerPos!=-1 && fileMarkerPos!=-1) // should always pass this.
864     {
865       QCString lineStr,anchorStr;
866       lineStr.sprintf("%d",m_impl->body->startLine);
867       anchorStr.sprintf(Htags::useHtags ? "L%d" : "l%05d",m_impl->body->startLine);
868       ol.startParagraph();
869       if (lineMarkerPos<fileMarkerPos) // line marker before file marker
870       {
871         // write text left from linePos marker
872         ol.parseText(refText.left(lineMarkerPos)); 
873         ol.pushGeneratorState();
874         ol.disable(OutputGenerator::RTF); 
875         ol.disable(OutputGenerator::Man); 
876         if (!latexSourceCode)
877         {
878           ol.disable(OutputGenerator::Latex);
879         }
880         // write line link (HTML, LaTeX optionally)
881         ol.writeObjectLink(0,m_impl->body->fileDef->getSourceFileBase(),
882             anchorStr,lineStr);
883         ol.enableAll();
884         ol.disable(OutputGenerator::Html);
885         if (latexSourceCode) 
886         {
887           ol.disable(OutputGenerator::Latex);
888         }
889         // write normal text (Man/RTF, Latex optionally)
890         ol.docify(lineStr);
891         ol.popGeneratorState();
892         
893         // write text between markers
894         ol.parseText(refText.mid(lineMarkerPos+2,
895               fileMarkerPos-lineMarkerPos-2));
896
897         ol.pushGeneratorState();
898         ol.disable(OutputGenerator::RTF); 
899         ol.disable(OutputGenerator::Man); 
900         if (!latexSourceCode)
901         {
902           ol.disable(OutputGenerator::Latex);
903         }
904         // write line link (HTML, LaTeX optionally)
905         ol.writeObjectLink(0,m_impl->body->fileDef->getSourceFileBase(),
906             0,m_impl->body->fileDef->name());
907         ol.enableAll();
908         ol.disable(OutputGenerator::Html);
909         if (latexSourceCode) 
910         {
911           ol.disable(OutputGenerator::Latex);
912         }
913         // write normal text (Man/RTF, Latex optionally)
914         ol.docify(m_impl->body->fileDef->name());
915         ol.popGeneratorState();
916         
917         // write text right from file marker
918         ol.parseText(refText.right(
919               refText.length()-fileMarkerPos-2)); 
920       }
921       else // file marker before line marker
922       {
923         // write text left from file marker
924         ol.parseText(refText.left(fileMarkerPos)); 
925         ol.pushGeneratorState();
926         ol.disable(OutputGenerator::RTF); 
927         ol.disable(OutputGenerator::Man); 
928         if (!latexSourceCode)
929         {
930           ol.disable(OutputGenerator::Latex);
931         }
932         // write file link (HTML only)
933         ol.writeObjectLink(0,m_impl->body->fileDef->getSourceFileBase(),
934             0,m_impl->body->fileDef->name());
935         ol.enableAll();
936         ol.disable(OutputGenerator::Html);
937         if (latexSourceCode) 
938         {
939           ol.disable(OutputGenerator::Latex);
940         }
941         // write normal text (Latex/Man only)
942         ol.docify(m_impl->body->fileDef->name());
943         ol.popGeneratorState();
944         
945         // write text between markers
946         ol.parseText(refText.mid(fileMarkerPos+2,
947               lineMarkerPos-fileMarkerPos-2)); 
948
949         ol.pushGeneratorState();
950         ol.disable(OutputGenerator::RTF); 
951         ol.disable(OutputGenerator::Man); 
952         if (!latexSourceCode)
953         {
954           ol.disable(OutputGenerator::Latex);
955         }
956         ol.disableAllBut(OutputGenerator::Html); 
957         // write line link (HTML only)
958         ol.writeObjectLink(0,m_impl->body->fileDef->getSourceFileBase(),
959             anchorStr,lineStr);
960         ol.enableAll();
961         ol.disable(OutputGenerator::Html);
962         if (latexSourceCode) 
963         {
964           ol.disable(OutputGenerator::Latex);
965         }
966         // write normal text (Latex/Man only)
967         ol.docify(lineStr);
968         ol.popGeneratorState();
969
970         // write text right from linePos marker
971         ol.parseText(refText.right(
972               refText.length()-lineMarkerPos-2)); 
973       }
974       ol.endParagraph();
975     }
976     else
977     {
978       err("error: translation error: invalid markers in trDefinedInSourceFile()\n");
979     }
980   }
981   ol.popGeneratorState();
982 }
983
984 void Definition::setBodySegment(int bls,int ble) 
985 {
986   //printf("setBodySegment(%d,%d) for %s\n",bls,ble,name().data());
987   makeResident();
988   if (m_impl->body==0) m_impl->body = new BodyInfo;
989   m_impl->body->startLine=bls; 
990   m_impl->body->endLine=ble; 
991 }
992
993 void Definition::setBodyDef(FileDef *fd)         
994 {
995   makeResident();
996   if (m_impl->body==0) m_impl->body = new BodyInfo;
997   m_impl->body->fileDef=fd; 
998 }
999
1000 /*! Write code of this definition into the documentation */
1001 void Definition::writeInlineCode(OutputList &ol,const char *scopeName)
1002 {
1003   makeResident();
1004   ol.pushGeneratorState();
1005   //printf("Source Fragment %s: %d-%d bodyDef=%p\n",name().data(),
1006   //        m_startBodyLine,m_endBodyLine,m_bodyDef);
1007   if (Config_getBool("INLINE_SOURCES") && 
1008       m_impl->body && m_impl->body->startLine!=-1 && 
1009       m_impl->body->endLine>=m_impl->body->startLine && m_impl->body->fileDef)
1010   {
1011     QCString codeFragment;
1012     int actualStart=m_impl->body->startLine,actualEnd=m_impl->body->endLine;
1013     if (readCodeFragment(m_impl->body->fileDef->absFilePath(),
1014           actualStart,actualEnd,codeFragment)
1015        )
1016     {
1017       //printf("Adding code fragement '%s' ext='%s'\n",
1018       //    codeFragment.data(),m_impl->defFileExt.data());
1019       ParserInterface *pIntf = Doxygen::parserManager->getParser(m_impl->defFileExt);
1020       pIntf->resetCodeParserState();
1021       //printf("Read:\n`%s'\n\n",codeFragment.data());
1022       MemberDef *thisMd = 0;
1023       if (definitionType()==TypeMember) thisMd = (MemberDef *)this;
1024
1025       // vhdl  parser can' t start at an arbitrary point in the source code
1026       if(this->getLanguage()==SrcLangExt_VHDL)
1027       {
1028         if (thisMd) VhdlDocGen::writeCodeFragment(ol,actualStart,codeFragment,thisMd);
1029         return;
1030       }
1031
1032       ol.startCodeFragment();
1033       pIntf->parseCode(ol,               // codeOutIntf
1034                        scopeName,        // scope
1035                        codeFragment,     // input
1036                        FALSE,            // isExample
1037                        0,                // exampleName
1038                        m_impl->body->fileDef,  // fileDef
1039                        actualStart,      // startLine
1040                        actualEnd,        // endLine
1041                        TRUE,             // inlineFragment
1042                        thisMd,           // memberDef
1043                        FALSE             // show line numbers
1044                       );
1045       ol.endCodeFragment();
1046     }
1047   }
1048   ol.popGeneratorState();
1049 }
1050
1051 /*! Write a reference to the source code fragments in which this 
1052  *  definition is used.
1053  */
1054 void Definition::_writeSourceRefList(OutputList &ol,const char *scopeName,
1055     const QCString &text,MemberSDict *members,bool /*funcOnly*/)
1056 {
1057   LockingPtr<Definition> lock(this,this); // since this can be a memberDef 
1058                                           // accessing other memberDefs prevent
1059                                           // it from being flushed to disk
1060   static bool latexSourceCode = Config_getBool("LATEX_SOURCE_CODE"); 
1061   static bool sourceBrowser   = Config_getBool("SOURCE_BROWSER");
1062   static bool refLinkSource   = Config_getBool("REFERENCES_LINK_SOURCE");
1063   ol.pushGeneratorState();
1064   if (members)
1065   {
1066     members->sort();
1067
1068     ol.startParagraph();
1069     ol.parseText(text);
1070     ol.docify(" ");
1071
1072     QCString ldefLine=theTranslator->trWriteList(members->count());
1073
1074     QRegExp marker("@[0-9]+");
1075     int index=0,newIndex,matchLen;
1076     // now replace all markers in inheritLine with links to the classes
1077     while ((newIndex=marker.match(ldefLine,index,&matchLen))!=-1)
1078     {
1079       bool ok;
1080       ol.parseText(ldefLine.mid(index,newIndex-index));
1081       uint entryIndex = ldefLine.mid(newIndex+1,matchLen-1).toUInt(&ok);
1082       MemberDef *md=members->at(entryIndex);
1083       if (ok && md)
1084       {
1085         QCString scope=md->getScopeString();
1086         QCString name=md->name();
1087         //printf("class=%p scope=%s scopeName=%s\n",md->getClassDef(),scope.data(),scopeName);
1088         if (!scope.isEmpty() && scope!=scopeName)
1089         {
1090           name.prepend(scope+getLanguageSpecificSeparator(m_impl->lang));
1091         }
1092         if (!md->isObjCMethod() &&
1093             (md->isFunction() || md->isSlot() || 
1094              md->isPrototype() || md->isSignal()
1095             )
1096            ) 
1097         {
1098           name+="()";
1099         }
1100         //Definition *d = md->getOutputFileBase();
1101         //if (d==Doxygen::globalScope) d=md->getBodyDef();
1102         if (sourceBrowser &&
1103             !(md->isLinkable() && !refLinkSource) && 
1104             md->getStartBodyLine()!=-1 && 
1105             md->getBodyDef()
1106            )
1107         {
1108           //printf("md->getBodyDef()=%p global=%p\n",md->getBodyDef(),Doxygen::globalScope); 
1109           // for HTML write a real link
1110           ol.pushGeneratorState();
1111           //ol.disableAllBut(OutputGenerator::Html);
1112
1113           ol.disable(OutputGenerator::RTF); 
1114           ol.disable(OutputGenerator::Man); 
1115           if (!latexSourceCode)
1116           {
1117             ol.disable(OutputGenerator::Latex);
1118           }
1119           QCString lineStr,anchorStr;
1120           anchorStr.sprintf("l%05d",md->getStartBodyLine());
1121           //printf("Write object link to %s\n",md->getBodyDef()->getSourceFileBase().data());
1122           ol.writeObjectLink(0,md->getBodyDef()->getSourceFileBase(),anchorStr,name);
1123           ol.popGeneratorState();
1124
1125           // for the other output formats just mention the name
1126           ol.pushGeneratorState();
1127           ol.disable(OutputGenerator::Html);
1128           if (latexSourceCode)
1129           {
1130             ol.disable(OutputGenerator::Latex);
1131           }
1132           ol.docify(name);
1133           ol.popGeneratorState();
1134         }
1135         else if (md->isLinkable() /*&& d && d->isLinkable()*/)
1136         {
1137           // for HTML write a real link
1138           ol.pushGeneratorState();
1139           //ol.disableAllBut(OutputGenerator::Html); 
1140           ol.disable(OutputGenerator::RTF); 
1141           ol.disable(OutputGenerator::Man); 
1142           if (!latexSourceCode)
1143           {
1144             ol.disable(OutputGenerator::Latex);
1145           }
1146
1147           ol.writeObjectLink(md->getReference(),
1148               md->getOutputFileBase(),
1149               md->anchor(),name);
1150           ol.popGeneratorState();
1151
1152           // for the other output formats just mention the name
1153           ol.pushGeneratorState();
1154           ol.disable(OutputGenerator::Html);
1155           if (latexSourceCode)
1156           {
1157             ol.disable(OutputGenerator::Latex);
1158           }
1159           ol.docify(name);
1160           ol.popGeneratorState();
1161         }
1162         else
1163         {
1164           ol.docify(name);
1165         }
1166       }
1167       index=newIndex+matchLen;
1168     } 
1169     ol.parseText(ldefLine.right(ldefLine.length()-index));
1170     ol.writeString(".");
1171     ol.endParagraph();
1172   }
1173   ol.popGeneratorState();
1174 }
1175
1176 void Definition::writeSourceReffedBy(OutputList &ol,const char *scopeName)
1177 {
1178   makeResident();
1179   if (Config_getBool("REFERENCED_BY_RELATION"))
1180   {
1181     _writeSourceRefList(ol,scopeName,theTranslator->trReferencedBy(),m_impl->sourceRefByDict,FALSE);
1182   }
1183 }
1184
1185 void Definition::writeSourceRefs(OutputList &ol,const char *scopeName)
1186 {
1187   makeResident();
1188   if (Config_getBool("REFERENCES_RELATION"))
1189   {
1190     _writeSourceRefList(ol,scopeName,theTranslator->trReferences(),m_impl->sourceRefsDict,TRUE);
1191   }
1192 }
1193
1194 bool Definition::hasDocumentation() const
1195
1196   static bool extractAll    = Config_getBool("EXTRACT_ALL"); 
1197   //static bool sourceBrowser = Config_getBool("SOURCE_BROWSER");
1198   makeResident();
1199   bool hasDocs = 
1200          (m_impl->details    && !m_impl->details->doc.isEmpty())    || // has detailed docs
1201          (m_impl->brief      && !m_impl->brief->doc.isEmpty())      || // has brief description
1202          (m_impl->inbodyDocs && !m_impl->inbodyDocs->doc.isEmpty()) || // has inbody docs
1203          extractAll //||                   // extract everything
1204   //       (sourceBrowser && m_impl->body && 
1205   //        m_impl->body->startLine!=-1 && m_impl->body->fileDef)
1206          ; // link to definition
1207   return hasDocs;
1208 }
1209
1210 bool Definition::hasUserDocumentation() const
1211 {
1212   makeResident();
1213   bool hasDocs = 
1214          (m_impl->details    && !m_impl->details->doc.isEmpty()) ||
1215          (m_impl->brief      && !m_impl->brief->doc.isEmpty())   ||
1216          (m_impl->inbodyDocs && !m_impl->inbodyDocs->doc.isEmpty());
1217   return hasDocs;
1218 }
1219
1220 void Definition::addSourceReferencedBy(MemberDef *md)
1221 {
1222   if (md)
1223   {
1224     makeResident();
1225     QCString name  = md->name();
1226     QCString scope = md->getScopeString();
1227
1228     if (!scope.isEmpty())
1229     {
1230       name.prepend(scope+"::");
1231     }
1232
1233     if (m_impl->sourceRefByDict==0)
1234     {
1235       m_impl->sourceRefByDict = new MemberSDict;
1236     }
1237     if (m_impl->sourceRefByDict->find(name)==0)
1238     {
1239       m_impl->sourceRefByDict->append(name,md);
1240     }
1241   }
1242 }
1243
1244 void Definition::addSourceReferences(MemberDef *md)
1245 {
1246   if (md)
1247   {
1248     QCString name  = md->name();
1249     QCString scope = md->getScopeString();
1250     makeResident();
1251
1252     if (!scope.isEmpty())
1253     {
1254       name.prepend(scope+"::");
1255     }
1256
1257     if (m_impl->sourceRefsDict==0)
1258     {
1259       m_impl->sourceRefsDict = new MemberSDict;
1260     }
1261     if (m_impl->sourceRefsDict->find(name)==0)
1262     {
1263       m_impl->sourceRefsDict->append(name,md);
1264     }
1265   }
1266 }
1267
1268 Definition *Definition::findInnerCompound(const char *)
1269 {
1270   return 0;
1271 }
1272
1273 void Definition::addInnerCompound(Definition *)
1274 {
1275   err("error: Definition::addInnerCompound() called\n");
1276 }
1277
1278 QCString Definition::qualifiedName() const
1279 {
1280   //static int count=0;
1281   //count++;
1282   makeResident();
1283   if (!m_impl->qualifiedName.isEmpty()) 
1284   {
1285     //count--;
1286     return m_impl->qualifiedName;
1287   }
1288   
1289   //printf("start %s::qualifiedName() localName=%s\n",name().data(),m_impl->localName.data());
1290   if (m_impl->outerScope==0) 
1291   {
1292     if (m_impl->localName=="<globalScope>") 
1293     {
1294       //count--;
1295       return "";
1296     }
1297     else 
1298     {
1299       //count--;
1300       return m_impl->localName; 
1301     }
1302   }
1303
1304   if (m_impl->outerScope->name()=="<globalScope>")
1305   {
1306     m_impl->qualifiedName = m_impl->localName;
1307   }
1308   else
1309   {
1310     m_impl->qualifiedName = m_impl->outerScope->qualifiedName()+
1311            getLanguageSpecificSeparator(getLanguage())+
1312            m_impl->localName;
1313   }
1314   //printf("end %s::qualifiedName()=%s\n",name().data(),m_impl->qualifiedName.data());
1315   //count--;
1316   return m_impl->qualifiedName;
1317 };
1318
1319 void Definition::setOuterScope(Definition *d) 
1320 {
1321   makeResident();
1322   //printf("%s::setOuterScope(%s)\n",name().data(),d?d->name().data():"<none>");
1323   if (m_impl->outerScope!=d)
1324   { 
1325     m_impl->qualifiedName.resize(0); // flush cached scope name
1326     m_impl->outerScope = d; 
1327   }
1328   m_impl->hidden = m_impl->hidden || d->isHidden();
1329 }
1330
1331 QCString Definition::localName() const
1332 {
1333   makeResident();
1334   return m_impl->localName;
1335 }
1336
1337 void Definition::makePartOfGroup(GroupDef *gd)
1338 {
1339   makeResident();
1340   if (m_impl->partOfGroups==0) m_impl->partOfGroups = new GroupList;
1341   m_impl->partOfGroups->append(gd);
1342 }
1343
1344 void Definition::setRefItems(const QList<ListItemInfo> *sli)
1345 {
1346   //printf("%s::setRefItems()\n",name().data());
1347   if (sli)
1348   {
1349     makeResident();
1350     // deep copy the list
1351     if (m_impl->xrefListItems==0) 
1352     {
1353       m_impl->xrefListItems=new QList<ListItemInfo>;
1354       m_impl->xrefListItems->setAutoDelete(TRUE);
1355     }
1356     QListIterator<ListItemInfo> slii(*sli);
1357     ListItemInfo *lii;
1358     for (slii.toFirst();(lii=slii.current());++slii)
1359     {
1360       m_impl->xrefListItems->append(new ListItemInfo(*lii));
1361     } 
1362   }
1363 }
1364
1365 void Definition::mergeRefItems(Definition *d)
1366 {
1367   //printf("%s::mergeRefItems()\n",name().data());
1368   LockingPtr< QList<ListItemInfo> > xrefList = d->xrefListItems();
1369   if (xrefList!=0)
1370   {
1371     makeResident();
1372     // deep copy the list
1373     if (m_impl->xrefListItems==0) 
1374     {
1375       m_impl->xrefListItems=new QList<ListItemInfo>;
1376       m_impl->xrefListItems->setAutoDelete(TRUE);
1377     }
1378     QListIterator<ListItemInfo> slii(*xrefList);
1379     ListItemInfo *lii;
1380     for (slii.toFirst();(lii=slii.current());++slii)
1381     {
1382       if (_getXRefListId(lii->type)==-1)
1383       {
1384         m_impl->xrefListItems->append(new ListItemInfo(*lii));
1385       }
1386     } 
1387   }
1388 }
1389
1390 int Definition::_getXRefListId(const char *listName) const
1391 {
1392   makeResident();
1393   if (m_impl->xrefListItems)
1394   {
1395     QListIterator<ListItemInfo> slii(*m_impl->xrefListItems);
1396     ListItemInfo *lii;
1397     for (slii.toFirst();(lii=slii.current());++slii)
1398     {
1399       if (strcmp(lii->type,listName)==0)
1400       {
1401         return lii->itemId;
1402       }
1403     }
1404   }
1405   return -1;
1406 }
1407
1408 LockingPtr< QList<ListItemInfo> > Definition::xrefListItems() const
1409 {
1410   makeResident();
1411   return LockingPtr< QList<ListItemInfo> >(this,m_impl->xrefListItems);
1412 }
1413
1414
1415 QCString Definition::convertNameToFile(const char *name,bool allowDots) const
1416 {
1417   makeResident();
1418   if (!m_impl->ref.isEmpty())
1419   {
1420     return name;
1421   }
1422   else
1423   {
1424     return ::convertNameToFile(name,allowDots);
1425   }
1426 }
1427
1428 QCString Definition::pathFragment() const
1429 {
1430   makeResident();
1431   QCString result;
1432   if (m_impl->outerScope && m_impl->outerScope!=Doxygen::globalScope)
1433   {
1434     result = m_impl->outerScope->pathFragment();
1435   }
1436   if (isLinkable())
1437   {
1438     if (!result.isEmpty()) result+="/";
1439     if (definitionType()==Definition::TypeGroup && ((const GroupDef*)this)->groupTitle())
1440     {
1441       result+=((const GroupDef*)this)->groupTitle();
1442     }
1443     else if (definitionType()==Definition::TypePage && !((const PageDef*)this)->title().isEmpty())
1444     {
1445       result+=((const PageDef*)this)->title();
1446     }
1447     else
1448     {
1449       result+=m_impl->localName;
1450     }
1451   }
1452   else
1453   {
1454     result+=m_impl->localName;
1455   }
1456   return result;
1457 }
1458
1459 //----------------------------------------------------------------------------------------
1460
1461 // TODO: move to htmlgen
1462 /*! Returns the string used in the footer for $navpath when 
1463  *  GENERATE_TREEVIEW is enabled
1464  */
1465 QCString Definition::navigationPathAsString() const
1466 {
1467   makeResident();
1468   QCString result;
1469   Definition *outerScope = getOuterScope();
1470   QCString locName = localName();
1471   if (outerScope && outerScope!=Doxygen::globalScope)
1472   {
1473     result+=outerScope->navigationPathAsString();
1474   }
1475   else if (definitionType()==Definition::TypeFile && ((const FileDef*)this)->getDirDef())
1476   {
1477     result+=((const FileDef*)this)->getDirDef()->navigationPathAsString();
1478   }
1479   result+="<li class=\"navelem\">";
1480   if (isLinkable())
1481   {
1482     if (definitionType()==Definition::TypeGroup && ((const GroupDef*)this)->groupTitle())
1483     {
1484       result+="<a class=\"el\" href=\"$relpath$"+getOutputFileBase()+Doxygen::htmlFileExtension+"\">"+
1485               ((const GroupDef*)this)->groupTitle()+"</a>";
1486     }
1487     else if (definitionType()==Definition::TypePage && !((const PageDef*)this)->title().isEmpty())
1488     {
1489       result+="<a class=\"el\" href=\"$relpath$"+getOutputFileBase()+Doxygen::htmlFileExtension+"\">"+
1490               ((const PageDef*)this)->title()+"</a>";
1491     }
1492     else if (definitionType()==Definition::TypeClass)
1493     {
1494       QCString name = locName;
1495       if (name.right(2)=="-p" /*|| name.right(2)=="-g"*/)
1496       {
1497         name = name.left(name.length()-2);
1498       }
1499       result+="<a class=\"el\" href=\"$relpath$"+getOutputFileBase()+Doxygen::htmlFileExtension;
1500       if (!anchor().isEmpty()) result+="#"+anchor();
1501       result+="\">"+name+"</a>";
1502     }
1503     else
1504     {
1505       result+="<a class=\"el\" href=\"$relpath$"+getOutputFileBase()+Doxygen::htmlFileExtension+"\">"+
1506               locName+"</a>";
1507     }
1508   }
1509   else
1510   {
1511     result+="<b>"+locName+"</b>";
1512   }
1513   result+="</li>";
1514   return result;
1515 }
1516
1517 // TODO: move to htmlgen
1518 void Definition::writeNavigationPath(OutputList &ol) const
1519 {
1520   ol.pushGeneratorState();
1521   ol.disableAllBut(OutputGenerator::Html);
1522
1523   QCString navPath;
1524   navPath += "<div id=\"nav-path\" class=\"navpath\">\n"
1525              "  <ul>\n";
1526   navPath += navigationPathAsString();
1527   navPath += "  </ul>\n"
1528              "</div>\n";
1529   ol.writeNavigationPath(navPath);
1530
1531   ol.popGeneratorState();
1532 }
1533
1534 // TODO: move to htmlgen
1535 void Definition::writeToc(OutputList &ol)
1536 {
1537   makeResident();
1538   SectionDict *sectionDict = m_impl->sectionDict;
1539   if (sectionDict==0) return;
1540   ol.pushGeneratorState();
1541   ol.disableAllBut(OutputGenerator::Html);
1542   ol.writeString("<div class=\"toc\">");
1543   ol.writeString("<h3>");
1544   ol.writeString(theTranslator->trRTFTableOfContents());
1545   ol.writeString("</h3>\n");
1546   ol.writeString("<ul>");
1547   SDict<SectionInfo>::Iterator li(*sectionDict);
1548   SectionInfo *si;
1549   int level=1;
1550   char cs[2];
1551   cs[1]='\0';
1552   bool inLi[5]={ FALSE, FALSE, FALSE, FALSE };
1553   for (li.toFirst();(si=li.current());++li)
1554   {
1555     if (si->type==SectionInfo::Section       || 
1556         si->type==SectionInfo::Subsection    || 
1557         si->type==SectionInfo::Subsubsection ||
1558         si->type==SectionInfo::Paragraph)
1559     {
1560       //printf("  level=%d title=%s\n",level,si->title.data());
1561       int nextLevel = (int)si->type;
1562       if (nextLevel>level)
1563       {
1564         ol.writeString("<ul>");
1565       }
1566       else if (nextLevel<level)
1567       {
1568         if (inLi[level]) ol.writeString("</li>\n");
1569         inLi[level]=FALSE;
1570         ol.writeString("</ul>\n");
1571       }
1572       cs[0]='0'+nextLevel;
1573       if (inLi[nextLevel]) ol.writeString("</li>\n");
1574       ol.writeString("<li class=\"level"+QCString(cs)+"\"><a href=\"#"+si->label+"\">"+si->title+"</a>");
1575       inLi[nextLevel]=TRUE;
1576       level = nextLevel;
1577     }
1578   }
1579   while (level>1)
1580   {
1581     if (inLi[level]) ol.writeString("</li>\n");
1582     inLi[level]=FALSE;
1583     ol.writeString("</ul>\n");
1584     level--;
1585   }
1586   if (inLi[level]) ol.writeString("</li>\n");
1587   inLi[level]=FALSE;
1588   ol.writeString("</ul>\n");
1589   ol.writeString("</div>\n");
1590   ol.popGeneratorState();
1591 }
1592
1593 //----------------------------------------------------------------------------------------
1594
1595
1596 QCString Definition::symbolName() const 
1597
1598   return m_symbolName; 
1599 }
1600
1601 //----------------------
1602
1603 QCString Definition::documentation() const 
1604
1605   makeResident();
1606   return m_impl->details ? m_impl->details->doc : QCString(""); 
1607 }
1608
1609 int Definition::docLine() const 
1610
1611   makeResident();
1612   return m_impl->details ? m_impl->details->line : 1; 
1613 }
1614
1615 QCString Definition::docFile() const 
1616
1617   makeResident();
1618   return m_impl->details ? m_impl->details->file : QCString("<"+m_name+">"); 
1619 }
1620
1621 //----------------------------------------------------------------------------
1622 // strips w from s iff s starts with w
1623 static bool stripWord(QCString &s,QCString w)
1624 {
1625   bool success=FALSE;
1626   if (s.left(w.length())==w) 
1627   {
1628     success=TRUE;
1629     s=s.right(s.length()-w.length());
1630   }
1631   return success;
1632 }
1633
1634 //----------------------------------------------------------------------------
1635 // some quasi intelligent brief description abbreviator :^)
1636 QCString abbreviate(const char *s,const char *name)
1637 {
1638   QCString scopelessName=name;
1639   int i=scopelessName.findRev("::");
1640   if (i!=-1) scopelessName=scopelessName.mid(i+2);
1641   QCString result=s;
1642   result=result.stripWhiteSpace();
1643   // strip trailing .
1644   if (!result.isEmpty() && result.at(result.length()-1)=='.') 
1645     result=result.left(result.length()-1);
1646
1647   // strip any predefined prefix
1648   QStrList &briefDescAbbrev = Config_getList("ABBREVIATE_BRIEF");
1649   const char *p = briefDescAbbrev.first();
1650   while (p)
1651   {
1652     QCString s = p;
1653     s.replace(QRegExp("\\$name"), scopelessName);  // replace $name with entity name
1654     s += " ";
1655     stripWord(result,s);
1656     p = briefDescAbbrev.next();
1657   }
1658
1659   // capitalize first word
1660   if (!result.isEmpty())
1661   {
1662     int c=result[0];
1663     if (c>='a' && c<='z') c+='A'-'a';
1664     result[0]=c;
1665   }
1666   return result;
1667 }
1668
1669
1670 //----------------------
1671
1672 QCString Definition::briefDescription(bool abbr) const 
1673
1674   makeResident();
1675   return m_impl->brief ? 
1676          (abbr ? abbreviate(m_impl->brief->doc,displayName()) : m_impl->brief->doc) :
1677          QCString(""); 
1678 }
1679
1680 QCString Definition::briefDescriptionAsTooltip() const
1681 {
1682   makeResident();
1683   LockingPtr<Definition> lock(this,this); // since this can be a memberDef 
1684                                           // accessing other memberDefs prevent
1685                                           // it from being flushed to disk
1686   if (m_impl->brief)
1687   {
1688     if (m_impl->brief->tooltip.isEmpty() && !m_impl->brief->doc.isEmpty())
1689     {
1690       static bool reentering=FALSE; 
1691       if (!reentering)
1692       {
1693         MemberDef *md = definitionType()==TypeMember ? (MemberDef*)this : 0;
1694         const Definition *scope = definitionType()==TypeMember ? getOuterScope() : this;
1695         reentering=TRUE; // prevent requests for tooltips while parsing a tooltip
1696         m_impl->brief->tooltip = parseCommentAsText(
1697             scope,md,
1698             m_impl->brief->doc,
1699             m_impl->brief->file,
1700             m_impl->brief->line);
1701         reentering=FALSE;
1702       }
1703     }
1704     return m_impl->brief->tooltip;
1705   }
1706   return QCString("");
1707 }
1708
1709 int Definition::briefLine() const 
1710
1711   makeResident();
1712   return m_impl->brief ? m_impl->brief->line : 1; 
1713 }
1714
1715 QCString Definition::briefFile() const 
1716
1717   makeResident();
1718   return m_impl->brief ? m_impl->brief->file : QCString("<"+m_name+">"); 
1719 }
1720
1721 //----------------------
1722
1723 QCString Definition::inbodyDocumentation() const
1724 {
1725   makeResident();
1726   return m_impl->inbodyDocs ? m_impl->inbodyDocs->doc : QCString(""); 
1727 }
1728
1729 int Definition::inbodyLine() const 
1730
1731   makeResident();
1732   return m_impl->inbodyDocs ? m_impl->inbodyDocs->line : 1; 
1733 }
1734
1735 QCString Definition::inbodyFile() const 
1736
1737   makeResident();
1738   return m_impl->inbodyDocs ? m_impl->inbodyDocs->file : QCString("<"+m_name+">"); 
1739 }
1740
1741
1742 //----------------------
1743
1744 QCString Definition::getDefFileName() const 
1745
1746   makeResident();
1747   return m_impl->defFileName; 
1748 }
1749
1750 QCString Definition::getDefFileExtension() const 
1751
1752   makeResident();
1753   return m_impl->defFileExt; 
1754 }
1755
1756 bool Definition::isHidden() const
1757 {
1758   makeResident();
1759   return m_impl->hidden;
1760 }
1761
1762 bool Definition::isVisibleInProject() const 
1763
1764   return isLinkableInProject() && !m_impl->hidden; 
1765 }
1766
1767 bool Definition::isVisible() const
1768
1769   return isLinkable() && !m_impl->hidden; 
1770 }
1771
1772 bool Definition::isArtificial() const
1773 {
1774   return m_impl->isArtificial;
1775 }
1776
1777 QCString Definition::getReference() const 
1778
1779   makeResident();
1780   return m_impl->ref; 
1781 }
1782
1783 bool Definition::isReference() const 
1784
1785   makeResident();
1786   return !m_impl->ref.isEmpty(); 
1787 }
1788
1789 int Definition::getStartBodyLine() const         
1790
1791   makeResident();
1792   return m_impl->body ? m_impl->body->startLine : -1; 
1793 }
1794
1795 int Definition::getEndBodyLine() const           
1796
1797   makeResident();
1798   return m_impl->body ? m_impl->body->endLine : -1; 
1799 }
1800
1801 FileDef *Definition::getBodyDef()                
1802
1803   makeResident();
1804   return m_impl->body ? m_impl->body->fileDef : 0; 
1805 }
1806
1807 LockingPtr<GroupList> Definition::partOfGroups() const 
1808
1809   makeResident();
1810   return LockingPtr<GroupList>(this,m_impl->partOfGroups); 
1811 }
1812
1813 Definition *Definition::getOuterScope() const 
1814
1815   makeResident();
1816   return m_impl->outerScope; 
1817 }
1818
1819 LockingPtr<MemberSDict> Definition::getReferencesMembers() const 
1820
1821   makeResident();
1822   return LockingPtr<MemberSDict>(this,m_impl->sourceRefsDict); 
1823 }
1824
1825 LockingPtr<MemberSDict> Definition::getReferencedByMembers() const 
1826
1827   makeResident();
1828   return LockingPtr<MemberSDict>(this,m_impl->sourceRefByDict); 
1829 }
1830
1831 void Definition::setReference(const char *r) 
1832
1833   makeResident();
1834   m_impl->ref=r; 
1835 }
1836
1837 SrcLangExt Definition::getLanguage() const
1838 {
1839   makeResident();
1840   return m_impl->lang;
1841 }
1842
1843 void Definition::setHidden(bool b) 
1844
1845   makeResident();
1846   m_impl->hidden = m_impl->hidden || b; 
1847 }
1848
1849 void Definition::setArtificial(bool b)
1850 {
1851   makeResident();
1852   m_impl->isArtificial = b;
1853 }
1854
1855 void Definition::setLocalName(const QCString name) 
1856
1857   makeResident();
1858   m_impl->localName=name; 
1859 }
1860
1861 void Definition::setLanguage(SrcLangExt lang) 
1862
1863   makeResident();
1864   m_impl->lang=lang; 
1865 }
1866
1867 void Definition::makeResident() const
1868 {
1869 }
1870
1871 //---------------
1872
1873 void Definition::_setSymbolName(const QCString &name) 
1874
1875   m_symbolName=name; 
1876 }
1877
1878 void Definition::flushToDisk() const
1879 {
1880   //printf("%p: Definition::flushToDisk()\n",this);
1881   Definition *that = (Definition *)this;
1882   //printf("Definition::flushToDisk(): pos=%d\n",(int)m_storagePos); 
1883   marshalUInt(Doxygen::symbolStorage,START_MARKER);
1884   marshalSectionDict  (Doxygen::symbolStorage,m_impl->sectionDict);
1885   marshalMemberSDict  (Doxygen::symbolStorage,m_impl->sourceRefByDict);
1886   marshalMemberSDict  (Doxygen::symbolStorage,m_impl->sourceRefsDict);
1887   marshalItemInfoList (Doxygen::symbolStorage,m_impl->xrefListItems);
1888   marshalGroupList    (Doxygen::symbolStorage,m_impl->partOfGroups);
1889   marshalDocInfo      (Doxygen::symbolStorage,m_impl->details);
1890   marshalDocInfo      (Doxygen::symbolStorage,m_impl->inbodyDocs);
1891   marshalBriefInfo    (Doxygen::symbolStorage,m_impl->brief);
1892   marshalBodyInfo     (Doxygen::symbolStorage,m_impl->body);
1893   marshalQCString     (Doxygen::symbolStorage,m_impl->docSignatures);
1894   marshalQCString     (Doxygen::symbolStorage,m_impl->localName);
1895   marshalQCString     (Doxygen::symbolStorage,m_impl->qualifiedName);
1896   marshalQCString     (Doxygen::symbolStorage,m_impl->ref);
1897   marshalBool         (Doxygen::symbolStorage,m_impl->hidden);
1898   marshalBool         (Doxygen::symbolStorage,m_impl->isArtificial);
1899   marshalObjPointer   (Doxygen::symbolStorage,m_impl->outerScope);
1900   marshalQCString     (Doxygen::symbolStorage,m_impl->defFileName);
1901   marshalQCString     (Doxygen::symbolStorage,m_impl->defFileExt);
1902   marshalInt          (Doxygen::symbolStorage,(int)m_impl->lang);
1903   marshalUInt(Doxygen::symbolStorage,END_MARKER);
1904   delete that->m_impl;
1905   that->m_impl = 0;
1906 }
1907
1908 void Definition::loadFromDisk() const
1909 {
1910   //printf("%p: Definition::loadFromDisk()\n",this);
1911   Definition *that = (Definition *)this;
1912   assert(m_impl==0);
1913   that->m_impl = new DefinitionImpl;
1914   uint marker = unmarshalUInt(Doxygen::symbolStorage);
1915   assert(marker==START_MARKER);
1916   m_impl->sectionDict     = unmarshalSectionDict  (Doxygen::symbolStorage);
1917   m_impl->sourceRefByDict = unmarshalMemberSDict  (Doxygen::symbolStorage);
1918   m_impl->sourceRefsDict  = unmarshalMemberSDict  (Doxygen::symbolStorage);
1919   m_impl->xrefListItems   = unmarshalItemInfoList (Doxygen::symbolStorage);
1920   m_impl->partOfGroups    = unmarshalGroupList    (Doxygen::symbolStorage);
1921   m_impl->details         = unmarshalDocInfo      (Doxygen::symbolStorage);
1922   m_impl->inbodyDocs      = unmarshalDocInfo      (Doxygen::symbolStorage);
1923   m_impl->brief           = unmarshalBriefInfo    (Doxygen::symbolStorage);
1924   m_impl->body            = unmarshalBodyInfo     (Doxygen::symbolStorage);
1925   m_impl->docSignatures   = unmarshalQCString     (Doxygen::symbolStorage);
1926   m_impl->localName       = unmarshalQCString     (Doxygen::symbolStorage);
1927   m_impl->qualifiedName   = unmarshalQCString     (Doxygen::symbolStorage);
1928   m_impl->ref             = unmarshalQCString     (Doxygen::symbolStorage);
1929   m_impl->hidden          = unmarshalBool         (Doxygen::symbolStorage);
1930   m_impl->isArtificial    = unmarshalBool         (Doxygen::symbolStorage);
1931   m_impl->outerScope      = (Definition *)unmarshalObjPointer   (Doxygen::symbolStorage);
1932   m_impl->defFileName     = unmarshalQCString     (Doxygen::symbolStorage);
1933   m_impl->defFileExt      = unmarshalQCString     (Doxygen::symbolStorage);
1934   m_impl->lang            = (SrcLangExt)unmarshalInt(Doxygen::symbolStorage);
1935   marker = unmarshalUInt(Doxygen::symbolStorage);
1936   assert(marker==END_MARKER);
1937 }
1938