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