Fix for UBSan build
[platform/upstream/doxygen.git] / src / memberlist.cpp
1 /******************************************************************************
2  *
3  * $Id: memberlist.cpp,v 1.35 2001/03/19 19:27:41 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 <qregexp.h>
19
20 #include "memberlist.h"
21 #include "classdef.h"
22 #include "message.h"
23 #include "util.h"
24 #include "language.h"
25 #include "doxygen.h"
26 #include "outputlist.h"
27 #include "groupdef.h"
28 #include "marshal.h"
29 #include "vhdldocgen.h"
30
31 MemberList::MemberList()
32 {
33   memberGroupList=0;
34   m_numDecMembers=-1; // special value indicating that value needs to be computed
35   m_numDocMembers=-1; // special value indicating that value needs to be computed
36 }
37
38 MemberList::MemberList(ListType lt) : m_listType(lt)
39 {
40   memberGroupList=0;
41   m_numDecMembers=-1; // special value indicating that value needs to be computed
42   m_numDocMembers=-1; // special value indicating that value needs to be computed
43   m_inGroup=FALSE;
44   m_inFile=FALSE;
45   m_needsSorting=FALSE;
46 }
47
48 MemberList::~MemberList()
49 {
50   delete memberGroupList;
51 }
52
53 int MemberList::compareItems(GCI item1, GCI item2)
54 {
55   static bool sortConstructorsFirst = Config_getBool("SORT_MEMBERS_CTORS_1ST");
56   MemberDef *c1=(MemberDef *)item1;
57   MemberDef *c2=(MemberDef *)item2;
58   if (sortConstructorsFirst) {
59     int ord1 = c1->isConstructor() ? 2 : (c1->isDestructor() ? 1 : 0);
60     int ord2 = c2->isConstructor() ? 2 : (c2->isDestructor() ? 1 : 0);
61     if (ord1 > ord2)
62       return -1;
63     else if (ord2 > ord1)
64       return 1;
65   }
66   int cmp = stricmp(c1->name(),c2->name());
67   return cmp!=0 ? cmp : c1->getDefLine()-c2->getDefLine();
68 }
69
70 int MemberList::countInheritableMembers(ClassDef *inheritedFrom) const
71 {
72   int count=0;
73   QListIterator<MemberDef> mli(*this);
74   MemberDef *md;
75   for (mli.toFirst();(md=mli.current());++mli)
76   {
77     if (md->isBriefSectionVisible())
78     {
79       if (md->memberType()!=MemberDef::Friend &&
80           md->memberType()!=MemberDef::EnumValue)
81       {
82         //printf("member %s: isReimplementedBy(%s)=%d\n",md->name().data(),
83         //    inheritedFrom->name().data(),
84         //    md->isReimplementedBy(inheritedFrom));
85         if (md->memberType()==MemberDef::Function)
86         {
87           if (!md->isReimplementedBy(inheritedFrom)) count++;
88         }
89         else
90         {
91           count++;
92         }
93       }
94     }
95   }
96   if (memberGroupList)
97   {
98     MemberGroupListIterator mgli(*memberGroupList);
99     MemberGroup *mg;
100     for (;(mg=mgli.current());++mgli)
101     {
102       count+=mg->countInheritableMembers(inheritedFrom);
103     }
104   }
105   //printf("%s::countInheritableMembers(%s)=%d\n",
106   //    listTypeAsString().data(),
107   //    inheritedFrom->name().data(),count);
108   return count;
109 }
110
111 /*! Count the number of members in this list that are visible in
112  *  the declaration part of a compound's documentation page.
113  */
114 void MemberList::countDecMembers(bool countEnumValues,GroupDef *gd)
115 {
116   if (m_numDecMembers!=-1) return; 
117   
118   //printf("----- countDecMembers count=%d ----\n",count());
119   m_varCnt=m_funcCnt=m_enumCnt=m_enumValCnt=0;
120   m_typeCnt=m_protoCnt=m_defCnt=m_friendCnt=0;
121   m_numDecMembers=0;
122   QListIterator<MemberDef> mli(*this);
123   MemberDef *md;
124   for (mli.toFirst();(md=mli.current());++mli)
125   {
126     //printf("MemberList::countDecMembers(md=%s,%d)\n",md->name().data(),md->isBriefSectionVisible());
127     if (md->isBriefSectionVisible())
128     {
129       switch(md->memberType())
130       {
131         case MemberDef::Variable:    // fall through
132         case MemberDef::Event:       // fall through
133         case MemberDef::Property:    m_varCnt++,m_numDecMembers++;  
134                                      break;
135         case MemberDef::Function:    // fall through
136         case MemberDef::Signal:      // fall through
137         case MemberDef::DCOP:        // fall through
138         case MemberDef::Slot:        if (!md->isRelated() || md->getClassDef())
139                                        m_funcCnt++,m_numDecMembers++; 
140                                      break;
141         case MemberDef::Enumeration: m_enumCnt++,m_numDecMembers++; break;
142         case MemberDef::EnumValue:   if (countEnumValues)
143                                        m_enumValCnt++,m_numDecMembers++; 
144                                      break;
145         case MemberDef::Typedef:     m_typeCnt++,m_numDecMembers++; break;
146         //case MemberDef::Prototype:   m_protoCnt++,m_numDecMembers++; break;
147         case MemberDef::Define:      if (Config_getBool("EXTRACT_ALL") || 
148                                          md->argsString() || 
149                                          !md->initializer().isEmpty() ||
150                                          md->hasDocumentation() 
151                                         ) m_defCnt++,m_numDecMembers++;     
152                                      break;
153         case MemberDef::Friend:      m_friendCnt++,m_numDecMembers++;  
154                                      break;
155         default:
156           err("Error: Unknown member type found for member `%s'\n!",md->name().data());
157       }
158     }
159   }
160   if (memberGroupList)
161   {
162     MemberGroupListIterator mgli(*memberGroupList);
163     MemberGroup *mg;
164     for (;(mg=mgli.current());++mgli)
165     {
166       mg->countDecMembers(gd);
167       m_varCnt+=mg->varCount();
168       m_funcCnt+=mg->funcCount();
169       m_enumCnt+=mg->enumCount();
170       m_enumValCnt+=mg->enumValueCount();
171       m_typeCnt+=mg->typedefCount();
172       m_protoCnt+=mg->protoCount();
173       m_defCnt+=mg->defineCount();
174       m_friendCnt+=mg->friendCount();
175       m_numDecMembers+=mg->numDecMembers();
176     }
177   }
178   //printf("----- end countDecMembers ----\n");
179
180   //printf("MemberList::countDecMembers()=%d\n",m_numDecMembers);
181 }
182
183 void MemberList::countDocMembers(bool countEnumValues)
184 {
185   if (m_numDocMembers!=-1) return; // used cached value
186   m_numDocMembers=0;
187   QListIterator<MemberDef> mli(*this);
188   MemberDef *md;
189   for (mli.toFirst();(md=mli.current());++mli)
190   {
191     if (md->isDetailedSectionVisible(m_inGroup,m_inFile)) 
192     {
193       // do not count enum values, since they do not produce entries of their own
194       if (countEnumValues || md->memberType()!=MemberDef::EnumValue) 
195         m_numDocMembers++;
196     }
197   }
198   if (memberGroupList)
199   {
200     MemberGroupListIterator mgli(*memberGroupList);
201     MemberGroup *mg;
202     for (;(mg=mgli.current());++mgli)
203     {
204       mg->countDocMembers();
205       m_numDocMembers+=mg->numDocMembers();
206     }
207   }
208   //printf("MemberList::countDocMembers()=%d memberGroupList=%p\n",m_numDocMembers,memberGroupList);
209 }
210
211 bool MemberList::insert(uint index,const MemberDef *md)
212 {
213   return QList<MemberDef>::insert(index,md);
214 }
215
216 void MemberList::inSort(const MemberDef *md)
217 {
218   QList<MemberDef>::inSort(md);
219 }
220
221 void MemberList::append(const MemberDef *md)
222 {
223   QList<MemberDef>::append(md);
224 }
225
226 MemberListIterator::MemberListIterator(const QList<MemberDef> &l) :
227   QListIterator<MemberDef>(l) 
228 {
229 }
230
231 bool MemberList::declVisible() const
232 {
233   MemberListIterator mli(*this);
234   MemberDef *md;
235   for ( ; (md=mli.current()); ++mli )
236   {
237     if (md->isBriefSectionVisible())
238     {
239       switch (md->memberType())
240       {
241         case MemberDef::Define:    // fall through
242         case MemberDef::Typedef:   // fall through
243         case MemberDef::Variable:  // fall through
244         case MemberDef::Function:  // fall through
245         case MemberDef::Signal:    // fall through
246         case MemberDef::Slot:      // fall through
247         case MemberDef::DCOP:      // fall through
248         case MemberDef::Property:  // fall through
249         case MemberDef::Event:  
250           return TRUE;
251         case MemberDef::Enumeration: 
252           {
253             int enumVars=0;
254             MemberListIterator vmli(*this);
255             MemberDef *vmd;
256             QCString name(md->name());
257             int i=name.findRev("::");
258             if (i!=-1) name=name.right(name.length()-i-2); // strip scope (TODO: is this needed?)
259             if (name[0]=='@') // anonymous enum => append variables
260             {
261               for ( ; (vmd=vmli.current()) ; ++vmli)
262               {
263                 QCString vtype=vmd->typeString();
264                 if ((vtype.find(name))!=-1) 
265                 {
266                   enumVars++;
267                 }
268               }
269             }
270             // if this is an anonymous enum and there are variables of this
271             // enum type (i.e. enumVars>0), then we do not show the enum here.
272             if (enumVars==0) // show enum here
273             {
274               return TRUE;
275             }
276           }
277           break;
278         case MemberDef::Friend:
279           return TRUE;
280         case MemberDef::EnumValue: 
281           {
282             if (m_inGroup)
283             {
284               return TRUE;
285             }
286           }
287           break;
288       }
289     }
290   }
291   return FALSE;
292 }
293
294 void MemberList::writePlainDeclarations(OutputList &ol,
295                        ClassDef *cd,NamespaceDef *nd,FileDef *fd,GroupDef *gd,
296                        ClassDef *inheritedFrom,const char *inheritId
297                       )
298 {
299   //printf("----- writePlainDeclaration() ----\n");
300   countDecMembers();
301   if (numDecMembers()==0) 
302   {
303     //printf("  --> no members!\n");
304     return; // no members in this list
305   }
306   //printf("  --> writePlainDeclaration() numDecMembers()=%d\n",
307   //     numDecMembers());
308   
309   ol.pushGeneratorState();
310
311   bool first=TRUE;
312   MemberDef *md;
313   MemberListIterator mli(*this);
314   for ( ; (md=mli.current()); ++mli )
315   {
316     //printf(">>> Member `%s' type=%d visible=%d\n",
317     //    md->name().data(),md->memberType(),md->isBriefSectionVisible());
318     if ((inheritedFrom==0 || !md->isReimplementedBy(inheritedFrom)) &&
319         md->isBriefSectionVisible())
320     {
321       switch(md->memberType())
322       {
323         case MemberDef::Define:    // fall through
324         //case MemberDef::Prototype: // fall through
325         case MemberDef::Typedef:   // fall through
326         case MemberDef::Variable:  // fall through
327         case MemberDef::Function:  // fall through
328         case MemberDef::Signal:    // fall through
329         case MemberDef::Slot:      // fall through
330         case MemberDef::DCOP:      // fall through
331         case MemberDef::Property:  // fall through
332         case MemberDef::Event:  
333           {
334             if (first) ol.startMemberList(),first=FALSE;
335             md->writeDeclaration(ol,cd,nd,fd,gd,m_inGroup,inheritedFrom,inheritId);
336             break;
337           }
338         case MemberDef::Enumeration: 
339           {
340             int enumVars=0;
341             MemberListIterator vmli(*this);
342             MemberDef *vmd;
343             QCString name(md->name());
344             int i=name.findRev("::");
345             if (i!=-1) name=name.right(name.length()-i-2); // strip scope (TODO: is this needed?)
346             if (name[0]=='@') // anonymous enum => append variables
347             {
348               for ( ; (vmd=vmli.current()) ; ++vmli)
349               {
350                 QCString vtype=vmd->typeString();
351                 if ((vtype.find(name))!=-1) 
352                 {
353                   enumVars++;
354                   vmd->setAnonymousEnumType(md);
355                 }
356               }
357             }
358             // if this is an anonymous enum and there are variables of this
359             // enum type (i.e. enumVars>0), then we do not show the enum here.
360             if (enumVars==0) // show enum here
361             {
362               //printf("Enum!!\n");
363               if (first)
364               {
365                 ol.startMemberList();
366                 first=FALSE;
367               }
368               ol.startMemberDeclaration();
369               ol.startMemberItem(md->anchor(),0,inheritId);
370               ol.writeString("enum ");
371               ol.insertMemberAlign();
372               md->writeEnumDeclaration(ol,cd,nd,fd,gd);
373               ol.endMemberItem();
374               if (!md->briefDescription().isEmpty() && Config_getBool("BRIEF_MEMBER_DESC"))
375               {
376                 ol.startMemberDescription(md->anchor());
377                 ol.parseDoc(
378                     md->briefFile(),md->briefLine(),
379                     cd,md,
380                     md->briefDescription(),
381                     TRUE,FALSE,0,TRUE,FALSE
382                     );
383                 if (md->isDetailedSectionLinkable())
384                 {
385                   ol.disableAllBut(OutputGenerator::Html);
386                   ol.docify(" ");
387                   ol.startTextLink(md->getOutputFileBase(),
388                                    md->anchor());
389                   ol.parseText(theTranslator->trMore());
390                   ol.endTextLink();
391                   ol.enableAll();
392                 }
393                 ol.endMemberDescription();
394               }
395               ol.endMemberDeclaration(md->anchor(),inheritId);
396             }
397             md->warnIfUndocumented();
398             break;
399           }
400         case MemberDef::Friend:
401           if (inheritedFrom==0)
402           {
403             if (first) 
404             {
405               ol.startMemberList();
406               first=FALSE;
407             }
408             md->writeDeclaration(ol,cd,nd,fd,gd,m_inGroup,inheritedFrom,inheritId);
409             break;
410           }
411         case MemberDef::EnumValue: 
412           {
413             if (m_inGroup)
414             {
415               //printf("EnumValue!\n");
416               if (first) ol.startMemberList(),first=FALSE;
417               md->writeDeclaration(ol,cd,nd,fd,gd,m_inGroup,inheritedFrom,inheritId);
418             }
419           }
420           break;
421       }
422     }
423   }
424
425   // handle members that are inside anonymous compounds and for which
426   // no variables of the anonymous compound type exist.
427   if (cd)
428   {
429     MemberListIterator mli(*this);
430     for  ( ; (md=mli.current()) ; ++mli )
431     {
432       if (md->fromAnonymousScope() && !md->anonymousDeclShown())
433       {
434         md->setFromAnonymousScope(FALSE);
435         //printf("anonymous compound members\n");
436         if (md->isBriefSectionVisible())
437         {
438           if (first) 
439           {
440             ol.startMemberList();
441             first=FALSE;
442           }
443           md->writeDeclaration(ol,cd,nd,fd,gd,m_inGroup);
444         }
445         md->setFromAnonymousScope(TRUE);
446       }
447     }
448   }
449  
450   if (!first) 
451   {
452     ol.endMemberList(); 
453   }
454
455   ol.popGeneratorState();
456   //printf("----- end writePlainDeclaration() ----\n");
457 }
458
459 /** Writes the list of members to the output.
460  *  @param ol Output list to write to
461  *  @param cd non-null if this list is part of class documentation.
462  *  @param nd non-null if this list is part of namespace documentation.
463  *  @param fd non-null if this list is part of file documentation.
464  *  @param gd non-null if this list is part of group documentation.
465  *  @param title Title to use for the member list.
466  *  @param subtitle Sub title to use for the member list.
467  *  @param showEnumValues Obsolete, always set to FALSE.
468  *  @param showInline if set to TRUE if title is rendered differently
469  *  @param inheritedFrom if not 0, the list is shown inside the
470  *         given class as inherited members, parameter cd points to the
471  *         class containing the members.
472  */
473 void MemberList::writeDeclarations(OutputList &ol,
474              ClassDef *cd,NamespaceDef *nd,FileDef *fd,GroupDef *gd,
475              const char *title,const char *subtitle, bool showEnumValues,
476              bool showInline,ClassDef *inheritedFrom)
477 {
478   (void)showEnumValues; // unused
479
480   //printf("----- writeDeclaration() this=%p ---- inheritedFrom=%p\n",this,inheritedFrom);
481   static bool optimizeVhdl = Config_getBool("OPTIMIZE_OUTPUT_VHDL");
482   QCString inheritId;
483
484   countDecMembers(/*showEnumValues*/FALSE,gd); // count members shown in this section
485   Definition *ctx = cd;
486   if (ctx==0 && nd) ctx = nd;
487   if (ctx==0 && gd) ctx = gd;
488   if (ctx==0 && fd) ctx = fd;
489
490   //printf("%p: MemberList::writeDeclaration(title=`%s',subtitle=`%s')=%d\n",
491   //       this,title,subtitle,numDecMembers());
492
493   int num = numDecMembers();
494   if (inheritedFrom)
495   {
496     //if ( cd && !optimizeVhdl && countInheritableMembers(inheritedFrom)>0 )
497     if ( cd && !optimizeVhdl && cd->countMembersIncludingGrouped(
498                                       m_listType,inheritedFrom,TRUE)>0 )
499     {
500       ol.pushGeneratorState();
501       ol.disableAllBut(OutputGenerator::Html);
502       inheritId = substitute(listTypeAsString(),"-","_")+"_"+
503                   stripPath(cd->getOutputFileBase());
504       if (title)
505       {
506         ol.writeInheritedSectionTitle(inheritId,cd->getReference(),
507                                       cd->getOutputFileBase(), 
508                                       cd->anchor(),title,cd->displayName());
509       }
510       ol.popGeneratorState();
511     }
512   }
513   else if (num>0)
514   {
515     if (title) 
516     {
517       if (showInline)
518       {
519         ol.startInlineHeader();
520       }
521       else
522       {
523         ol.startMemberHeader(listTypeAsString());
524       }
525       ol.parseText(title);
526       if (showInline)
527       {
528         ol.endInlineHeader();
529       }
530       else
531       {
532         ol.endMemberHeader();
533       }
534     }
535     if (subtitle) 
536     {
537       QCString st=subtitle;
538       st = st.stripWhiteSpace();
539       if (!st.isEmpty())
540       {
541         ol.startMemberSubtitle();
542         ol.parseDoc("[generated]",-1,ctx,0,subtitle,FALSE,FALSE,0,FALSE,FALSE);
543         ol.endMemberSubtitle();
544       }
545     }
546   }
547   if (num>0)
548   {
549     // TODO: Two things need to be worked out for proper VHDL output:
550     // 1. Signals and types under the group need to be
551     //    formatted to associate them with the group somehow
552     //    indentation, or at the very least, extra space after
553     //    the group is done
554     // 2. This might need to be repeated below for memberGroupLists
555     if (optimizeVhdl) // use specific declarations function
556     {
557       VhdlDocGen::writeVhdlDeclarations(this,ol,0,cd,0,0);
558     }
559     else
560     {
561       writePlainDeclarations(ol,cd,nd,fd,gd,inheritedFrom,inheritId);
562     }
563
564     //printf("memberGroupList=%p\n",memberGroupList);
565     if (memberGroupList)
566     {
567       MemberGroupListIterator mgli(*memberGroupList);
568       MemberGroup *mg;
569       while ((mg=mgli.current()))
570       {
571         bool hasHeader=!mg->header().isEmpty() && mg->header()!="[NOHEADER]";
572         if (inheritId.isEmpty())
573         {
574           //printf("mg->header=%s hasHeader=%d\n",mg->header().data(),hasHeader);
575           ol.startMemberGroupHeader(hasHeader);
576           if (hasHeader)
577           {
578             ol.parseText(mg->header());
579           }
580           ol.endMemberGroupHeader();
581           if (!mg->documentation().isEmpty())
582           {
583             //printf("Member group has docs!\n");
584             ol.startMemberGroupDocs();
585             ol.parseDoc("[generated]",-1,ctx,0,mg->documentation()+"\n",FALSE,FALSE);
586             ol.endMemberGroupDocs();
587           }
588           ol.startMemberGroup();
589         }
590         //printf("--- mg->writePlainDeclarations ---\n");
591         mg->writePlainDeclarations(ol,cd,nd,fd,gd,inheritedFrom,inheritId);
592         if (inheritId.isEmpty())
593         {
594           ol.endMemberGroup(hasHeader);
595         }
596         ++mgli;
597       }
598     }
599   }
600   if (inheritedFrom && cd) 
601   {
602     // also add members that of this list type, that are grouped together
603     // in a separate list in class 'inheritedFrom'
604     cd->addGroupedInheritedMembers(ol,m_listType,inheritedFrom,inheritId);
605   }
606   //printf("----- end writeDeclaration() ----\n");
607 }
608
609 void MemberList::writeDocumentation(OutputList &ol,
610                      const char *scopeName, Definition *container,
611                      const char *title,bool showEnumValues,bool showInline)
612 {
613   //printf("MemberList::writeDocumentation()\n");
614
615   countDocMembers(showEnumValues);
616   if (numDocMembers()==0) return;
617
618   if (title)
619   {
620     ol.pushGeneratorState();
621       ol.disable(OutputGenerator::Html);
622       ol.writeRuler();
623     ol.popGeneratorState();
624     ol.startGroupHeader(showInline ? 2 : 0);
625     ol.parseText(title);
626     ol.endGroupHeader(showInline ? 2 : 0);
627   }
628   ol.startMemberDocList();
629   
630   MemberListIterator mli(*this);
631   MemberDef *md;
632   for ( ; (md=mli.current()) ; ++mli)
633   {
634     md->writeDocumentation(this,ol,scopeName,container,
635                            m_inGroup,showEnumValues,showInline);
636   }
637   if (memberGroupList)
638   {
639     //printf("MemberList::writeDocumentation()  --  member groups\n");
640     MemberGroupListIterator mgli(*memberGroupList);
641     MemberGroup *mg;
642     for (;(mg=mgli.current());++mgli)
643     {
644       mg->writeDocumentation(ol,scopeName,container,showEnumValues,showInline);
645     }
646   }
647   ol.endMemberDocList();
648 }
649
650 // members in a table
651 void MemberList::writeSimpleDocumentation(OutputList &ol,
652                      Definition *container)
653 {
654   countDocMembers(FALSE);
655   //printf("MemberList count=%d\n",numDocMembers());
656   if (numDocMembers()==0) return;
657
658   ol.startMemberDocSimple();
659   MemberListIterator mli(*this);
660   MemberDef *md;
661   for ( ; (md=mli.current()) ; ++mli)
662   {
663     md->writeMemberDocSimple(ol,container);
664   }
665   ol.endMemberDocSimple();
666 }
667
668 // separate member pages
669 void MemberList::writeDocumentationPage(OutputList &ol,
670                      const char *scopeName, Definition *container)
671 {
672   static bool generateTreeView = Config_getBool("GENERATE_TREEVIEW");
673   MemberListIterator mli(*this);
674   MemberDef *md;
675   for ( ; (md=mli.current()) ; ++mli)
676   {
677     QCString diskName=md->getOutputFileBase();
678     QCString title=md->qualifiedName();
679     startFile(ol,diskName,md->name(),title,HLI_None,!generateTreeView,
680               container->getOutputFileBase());
681     if (!generateTreeView)
682     {
683       container->writeNavigationPath(ol);
684       ol.endQuickIndices();
685     }
686     ol.startContents();
687
688
689     if (generateTreeView)
690     {
691       md->writeDocumentation(this,ol,scopeName,container,m_inGroup);
692       ol.endContents();
693       endFileWithNavPath(container,ol);
694     }
695     else
696     {
697       ol.writeString("<table cellspacing=\"0\" cellpadding=\"0\" border=\"0\">\n"
698           "  <tr>\n"
699           "   <td valign=\"top\">\n");
700
701       container->writeQuickMemberLinks(ol,md);
702
703       ol.writeString("   </td>\n");
704       ol.writeString("   <td valign=\"top\" class=\"mempage\">\n");
705
706       md->writeDocumentation(this,ol,scopeName,container,m_inGroup);
707
708       ol.writeString("    </td>\n");
709       ol.writeString("  </tr>\n");
710       ol.writeString("</table>\n");
711
712       endFile(ol);
713     }
714   }
715   if (memberGroupList)
716   {
717     //printf("MemberList::writeDocumentation()  --  member groups\n");
718     MemberGroupListIterator mgli(*memberGroupList);
719     MemberGroup *mg;
720     for (;(mg=mgli.current());++mgli)
721     {
722       mg->writeDocumentationPage(ol,scopeName,container);
723     }
724   }
725 }
726
727 void MemberList::addMemberGroup(MemberGroup *mg)
728 {
729   if (memberGroupList==0)
730   {
731     memberGroupList=new MemberGroupList;
732   }
733   //printf("addMemberGroup: this=%p mg=%p\n",this,mg);
734   memberGroupList->append(mg);
735 }
736
737 void MemberList::addListReferences(Definition *def)
738 {
739   MemberListIterator mli(*this);
740   MemberDef *md;
741   for ( ; (md=mli.current()) ; ++mli)
742   {
743     if (md->getGroupDef()==0 || def->definitionType()==Definition::TypeGroup)
744     {
745       md->addListReference(def);
746       LockingPtr<MemberList> enumFields = md->enumFieldList();
747       if (md->memberType()==MemberDef::Enumeration && enumFields!=0)
748       {
749         //printf("  Adding enum values!\n");
750         MemberListIterator vmli(*enumFields);
751         MemberDef *vmd;
752         for ( ; (vmd=vmli.current()) ; ++vmli)
753         {
754           //printf("   adding %s\n",vmd->name().data());  
755           vmd->addListReference(def);
756         }
757       }
758     }
759   }
760   if (memberGroupList)
761   {
762     MemberGroupListIterator mgli(*memberGroupList);
763     MemberGroup *mg;
764     for (;(mg=mgli.current());++mgli)
765     {
766       mg->addListReferences(def);
767     }
768   }
769 }
770
771 void MemberList::findSectionsInDocumentation()
772 {
773   MemberListIterator mli(*this);
774   MemberDef *md;
775   for ( ; (md=mli.current()) ; ++mli)
776   {
777     md->findSectionsInDocumentation();
778   }
779   if (memberGroupList)
780   {
781     MemberGroupListIterator mgli(*memberGroupList);
782     MemberGroup *mg;
783     for (;(mg=mgli.current());++mgli)
784     {
785       mg->findSectionsInDocumentation();
786     }
787   }
788 }
789
790 void MemberList::marshal(StorageIntf *s)
791 {
792   marshalInt(s,(int)m_listType);
793   marshalInt(s,m_varCnt);
794   marshalInt(s,m_funcCnt);
795   marshalInt(s,m_enumCnt);
796   marshalInt(s,m_enumValCnt);
797   marshalInt(s,m_typeCnt);
798   marshalInt(s,m_protoCnt);
799   marshalInt(s,m_defCnt);
800   marshalInt(s,m_friendCnt); 
801   marshalInt(s,m_numDecMembers);
802   marshalInt(s,m_numDocMembers);
803   marshalBool(s,m_inGroup);
804   marshalBool(s,m_inFile);
805   marshalBool(s,m_needsSorting);
806   if (memberGroupList==0)
807   {
808     marshalUInt(s,NULL_LIST); // null pointer representation
809   }
810   else
811   {
812     marshalUInt(s,memberGroupList->count());
813     QListIterator<MemberGroup> mgi(*memberGroupList);
814     MemberGroup *mg=0;
815     for (mgi.toFirst();(mg=mgi.current());++mgi)
816     {
817       mg->marshal(s);
818     }
819   }
820 }
821
822 void MemberList::unmarshal(StorageIntf *s)
823 {
824   m_listType       = (MemberList::ListType)unmarshalInt(s);
825   m_varCnt         = unmarshalInt(s);
826   m_funcCnt        = unmarshalInt(s);
827   m_enumCnt        = unmarshalInt(s);
828   m_enumValCnt     = unmarshalInt(s);
829   m_typeCnt        = unmarshalInt(s);
830   m_protoCnt       = unmarshalInt(s);
831   m_defCnt         = unmarshalInt(s);
832   m_friendCnt      = unmarshalInt(s); 
833   m_numDecMembers  = unmarshalInt(s);
834   m_numDocMembers  = unmarshalInt(s);
835   m_inGroup        = unmarshalBool(s);
836   m_inFile         = unmarshalBool(s);
837   m_needsSorting   = unmarshalBool(s);
838   uint i,count     = unmarshalUInt(s); 
839   if (count==NULL_LIST) // empty list
840   {
841     memberGroupList = 0;
842   }
843   else // add member groups
844   {
845     memberGroupList = new MemberGroupList;
846     for (i=0;i<count;i++)
847     {
848       MemberGroup *mg = new MemberGroup;
849       mg->unmarshal(s);
850       memberGroupList->append(mg);
851     }
852   }
853 }
854
855 QCString MemberList::listTypeAsString() const
856 {
857   switch(m_listType)
858   {
859     case pubMethods: return "pub-methods";
860     case proMethods: return "pro-methods";
861     case pacMethods: return "pac-methods";
862     case priMethods: return "pri-methods";
863     case pubStaticMethods: return "pub-static-methods";
864     case proStaticMethods: return "pro-static-methods";
865     case pacStaticMethods: return "pac-static-methods";
866     case priStaticMethods: return "pri-static-methods";
867     case pubSlots: return "pub-slots";
868     case proSlots: return "pro-slots";
869     case priSlots: return "pri-slots";
870     case pubAttribs: return "pub-attribs";
871     case proAttribs: return "pro-attribs";
872     case pacAttribs: return "pac-attribs";
873     case priAttribs: return "pri-attribs";
874     case pubStaticAttribs: return "pub-static-attribs";
875     case proStaticAttribs: return "pro-static-attribs";
876     case pacStaticAttribs: return "pac-static-attribs";
877     case priStaticAttribs: return "pri-static-attribs";
878     case pubTypes: return "pub-types";
879     case proTypes: return "pro-types";
880     case pacTypes: return "pac-types";
881     case priTypes: return "pri-types";
882     case related: return "related";
883     case signals: return "signals";
884     case friends: return "friends";
885     case dcopMethods: return "dcop-methods";
886     case properties: return "properties";
887     case events: return "events";
888     case decDefineMembers: return "define-members";
889     case decProtoMembers: return "proto-members";
890     case decTypedefMembers: return "typedef-members";
891     case decEnumMembers: return "enum-members";
892     case decFuncMembers: return "func-members";
893     case decVarMembers: return "var-members";
894     case decEnumValMembers: return "enumval-members";
895     case decPubSlotMembers: return "pub-slot-members";
896     case decProSlotMembers: return "pro-slot-members";
897     case decPriSlotMembers: return "pri-slot-members";
898     case decSignalMembers: return "signal-members";
899     case decEventMembers: return "event-members";
900     case decFriendMembers: return "friend-members";
901     case decPropMembers: return "prop-members";
902     case enumFields: return "enum-fields";
903     case memberGroup: return "member-group";
904     default: break;
905   }
906   return "";
907 }
908
909 void MemberList::setNeedsSorting(bool b)
910 {
911   m_needsSorting = b;
912 }
913
914 //--------------------------------------------------------------------------
915
916 int MemberSDict::compareItems(GCI item1, GCI item2)
917 {
918   // NOTE: this function can be triggered from unmarshalMemberSDict
919   // so it may not result in called to MemberDef::makeResident().
920   // As a result, the data returned by MemberDef::name() and 
921   // MemberDef::getDefLine() will always be kept in memory.
922   MemberDef *c1=(MemberDef *)item1;
923   MemberDef *c2=(MemberDef *)item2;
924   //printf("MemberSDict::compareItems(%s,%s)\n",c1->name().data(),c2->name().data());
925   int cmp = stricmp(c1->name(),c2->name());
926   if (cmp)
927   {
928     return cmp;
929   }
930   else
931   {
932     return c1->getDefLine()-c2->getDefLine();
933   }
934 }
935
936