345629e24a297b23f9996f41f2e4de444eef3aa7
[platform/upstream/doxygen.git] / src / docbookgen.cpp
1 /******************************************************************************
2 *
3
4 *
5 * Copyright (C) 1997-2015 by Dimitri van Heesch.
6 *
7 * Permission to use, copy, modify, and distribute this software and its
8 * documentation under the terms of the GNU General Public License is hereby
9 * granted. No representations are made about the suitability of this software
10 * for any purpose. It is provided "as is" without express or implied warranty.
11 * See the GNU General Public License for more details.
12 *
13 * Documents produced by Doxygen are derivative works derived from the
14 * input used in their production; they are not affected by this license.
15 *
16 */
17
18 #include <stdlib.h>
19
20 #include <qdir.h>
21 #include <qfile.h>
22 #include <qtextstream.h>
23 #include <qintdict.h>
24 #include "docbookgen.h"
25 #include "doxygen.h"
26 #include "message.h"
27 #include "config.h"
28 #include "classlist.h"
29 #include "util.h"
30 #include "defargs.h"
31 #include "outputgen.h"
32 #include "dot.h"
33 #include "pagedef.h"
34 #include "filename.h"
35 #include "version.h"
36 #include "docbookvisitor.h"
37 #include "docparser.h"
38 #include "language.h"
39 #include "parserintf.h"
40 #include "arguments.h"
41 #include "memberlist.h"
42 #include "groupdef.h"
43 #include "memberdef.h"
44 #include "namespacedef.h"
45 #include "membername.h"
46 #include "membergroup.h"
47 #include "dirdef.h"
48 #include "section.h"
49
50 // no debug info
51 #define Docbook_DB(x) do {} while(0)
52 // debug to stdout
53 //#define Docbook_DB(x) printf x
54 // debug inside output
55 //#define Docbook_DB(x) QCString __t;__t.sprintf x;m_t << __t
56
57 //------------------
58
59 class DocbookSectionMapper : public QIntDict<char>
60 {
61   public:
62     DocbookSectionMapper() : QIntDict<char>(47)
63   {
64     insert(MemberListType_pubTypes,"public-type");
65     insert(MemberListType_pubMethods,"public-func");
66     insert(MemberListType_pubAttribs,"public-attrib");
67     insert(MemberListType_pubSlots,"public-slot");
68     insert(MemberListType_signals,"signal");
69     insert(MemberListType_dcopMethods,"dcop-func");
70     insert(MemberListType_properties,"property");
71     insert(MemberListType_events,"event");
72     insert(MemberListType_pubStaticMethods,"public-static-func");
73     insert(MemberListType_pubStaticAttribs,"public-static-attrib");
74     insert(MemberListType_proTypes,"protected-type");
75     insert(MemberListType_proMethods,"protected-func");
76     insert(MemberListType_proAttribs,"protected-attrib");
77     insert(MemberListType_proSlots,"protected-slot");
78     insert(MemberListType_proStaticMethods,"protected-static-func");
79     insert(MemberListType_proStaticAttribs,"protected-static-attrib");
80     insert(MemberListType_pacTypes,"package-type");
81     insert(MemberListType_pacMethods,"package-func");
82     insert(MemberListType_pacAttribs,"package-attrib");
83     insert(MemberListType_pacStaticMethods,"package-static-func");
84     insert(MemberListType_pacStaticAttribs,"package-static-attrib");
85     insert(MemberListType_priTypes,"private-type");
86     insert(MemberListType_priMethods,"private-func");
87     insert(MemberListType_priAttribs,"private-attrib");
88     insert(MemberListType_priSlots,"private-slot");
89     insert(MemberListType_priStaticMethods,"private-static-func");
90     insert(MemberListType_priStaticAttribs,"private-static-attrib");
91     insert(MemberListType_friends,"friend");
92     insert(MemberListType_related,"related");
93     insert(MemberListType_decDefineMembers,"define");
94     insert(MemberListType_decProtoMembers,"prototype");
95     insert(MemberListType_decTypedefMembers,"typedef");
96     insert(MemberListType_decEnumMembers,"enum");
97     insert(MemberListType_decFuncMembers,"func");
98     insert(MemberListType_decVarMembers,"var");
99   }
100 };
101
102 static DocbookSectionMapper g_docbookSectionMapper;
103
104
105 inline void writeDocbookString(FTextStream &t,const char *s)
106 {
107   t << convertToXML(s);
108 }
109
110 inline void writeDocbookCodeString(FTextStream &t,const char *s, int &col)
111 {
112   char c;
113   while ((c=*s++))
114   {
115     switch(c)
116     {
117       case '\t':
118         {
119           static int tabSize = Config_getInt(TAB_SIZE);
120           int spacesToNextTabStop = tabSize - (col%tabSize);
121           col+=spacesToNextTabStop;
122           while (spacesToNextTabStop--) t << "&#32;";
123           break;
124         }
125       case ' ':  t << "&#32;"; col++;  break;
126       case '<':  t << "&lt;"; col++;   break;
127       case '>':  t << "&gt;"; col++;   break;
128       case '&':  t << "&amp;"; col++;  break;
129       case '\'': t << "&apos;"; col++; break;
130       case '"':  t << "&quot;"; col++; break;
131       default:   t << c; col++;        break;
132     }
133   }
134 }
135
136 static void writeDocbookHeaderMainpage(FTextStream &t)
137 {
138   t << "<?xml version='1.0' encoding='UTF-8' standalone='no'?>" << endl;;
139   t << "<chapter xmlns=\"http://docbook.org/ns/docbook\" version=\"5.0\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">" << endl;
140 }
141
142 static void writeDocbookHeader_ID(FTextStream &t, QCString id)
143 {
144   t << "<?xml version='1.0' encoding='UTF-8' standalone='no'?>" << endl;;
145   t << "<section xmlns=\"http://docbook.org/ns/docbook\" version=\"5.0\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xml:id=\"" << id << "\">" << endl;
146 }
147
148 void writeDocbookLink(FTextStream &t,const char * /*extRef*/,const char *compoundId,
149     const char *anchorId,const char * text,const char * /*tooltip*/)
150 {
151   t << "<link linkend=\"" << compoundId;
152   if (anchorId) t << "_1" << anchorId;
153   t << "\"";
154   t << ">";
155   writeDocbookString(t,text);
156   t << "</link>";
157 }
158
159 class TextGeneratorDocbookImpl : public TextGeneratorIntf
160 {
161   public:
162     TextGeneratorDocbookImpl(FTextStream &t): m_t(t) {}
163     void writeString(const char *s,bool /*keepSpaces*/) const
164     {
165       writeDocbookString(m_t,s);
166     }
167     void writeBreak(int) const {}
168     void writeLink(const char *extRef,const char *file,
169         const char *anchor,const char *text
170         ) const
171     {
172       writeDocbookLink(m_t,extRef,file,anchor,text,0);
173     }
174   private:
175     FTextStream &m_t;
176 };
177
178 class DocbookCodeGenerator : public CodeOutputInterface
179 {
180   public:
181     DocbookCodeGenerator(FTextStream &t) : m_t(t), m_lineNumber(-1), m_col(0),
182     m_insideCodeLine(FALSE), m_insideSpecialHL(FALSE) {}
183     virtual ~DocbookCodeGenerator() {}
184
185     void codify(const char *text)
186     {
187       Docbook_DB(("(codify \"%s\")\n",text));
188       writeDocbookCodeString(m_t,text,m_col);
189     }
190     void writeCodeLink(const char *ref,const char *file,
191         const char *anchor,const char *name,
192         const char *tooltip)
193     {
194       Docbook_DB(("(writeCodeLink)\n"));
195       writeDocbookLink(m_t,ref,file,anchor,name,tooltip);
196       m_col+=strlen(name);
197     }
198     void writeTooltip(const char *, const DocLinkInfo &, const char *,
199                       const char *, const SourceLinkInfo &, const SourceLinkInfo &
200                      )
201     {
202       Docbook_DB(("(writeToolTip)\n"));
203     }
204     void startCodeLine(bool)
205     {
206       Docbook_DB(("(startCodeLine)\n"));
207       if (m_lineNumber!=-1)
208       {
209         if (!m_refId.isEmpty())
210         {
211           m_t << "<link linkend=\"" << m_refId << "\">";
212         }
213         m_t << m_lineNumber << " ";
214         if (!m_refId.isEmpty())
215         {
216           m_t << "</link>";
217         }
218       }
219       m_insideCodeLine=TRUE;
220       m_col=0;
221     }
222     void endCodeLine()
223     {
224       m_t << endl;
225       Docbook_DB(("(endCodeLine)\n"));
226       m_lineNumber = -1;
227       m_refId.resize(0);
228       m_external.resize(0);
229       m_insideCodeLine=FALSE;
230     }
231     void startFontClass(const char *colorClass)
232     {
233       Docbook_DB(("(startFontClass)\n"));
234       m_t << "<emphasis class=\"" << colorClass << "\">";
235       m_insideSpecialHL=TRUE;
236     }
237     void endFontClass()
238     {
239       Docbook_DB(("(endFontClass)\n"));
240       m_t << "</emphasis>"; // non DocBook
241       m_insideSpecialHL=FALSE;
242     }
243     void writeCodeAnchor(const char *)
244     {
245       Docbook_DB(("(writeCodeAnchor)\n"));
246     }
247     void writeLineNumber(const char *extRef,const char *compId,
248         const char *anchorId,int l)
249     {
250       Docbook_DB(("(writeLineNumber)\n"));
251       // we remember the information provided here to use it
252       // at the <codeline> start tag.
253       m_lineNumber = l;
254       if (compId)
255       {
256         m_refId=compId;
257         if (anchorId) m_refId+=(QCString)"_1"+anchorId;
258         if (extRef) m_external=extRef;
259       }
260     }
261     void setCurrentDoc(Definition *,const char *,bool)
262     {
263     }
264     void addWord(const char *,bool)
265     {
266     }
267     void finish()
268     {
269       if (m_insideCodeLine) endCodeLine();
270     }
271
272   private:
273     FTextStream &m_t;
274     QCString m_refId;
275     QCString m_external;
276     int m_lineNumber;
277     int m_col;
278     bool m_insideCodeLine;
279     bool m_insideSpecialHL;
280 };
281
282
283 static void writeTemplateArgumentList(ArgumentList *al,
284     FTextStream &t,
285     Definition *scope,
286     FileDef *fileScope,
287     int indent)
288 {
289   QCString indentStr;
290   indentStr.fill(' ',indent);
291   if (al)
292   {
293     t << indentStr << "<templateparamlist>" << endl;
294     ArgumentListIterator ali(*al);
295     Argument *a;
296     for (ali.toFirst();(a=ali.current());++ali)
297     {
298       t << indentStr << "  <param>" << endl;
299       if (!a->type.isEmpty())
300       {
301         t << indentStr <<  "    <type>";
302         linkifyText(TextGeneratorDocbookImpl(t),scope,fileScope,0,a->type);
303         t << "</type>" << endl;
304       }
305       if (!a->name.isEmpty())
306       {
307         t << indentStr <<  "    <declname>" << a->name << "</declname>" << endl;
308         t << indentStr <<  "    <defname>" << a->name << "</defname>" << endl;
309       }
310       if (!a->defval.isEmpty())
311       {
312         t << indentStr << "    <defval>";
313         linkifyText(TextGeneratorDocbookImpl(t),scope,fileScope,0,a->defval);
314         t << "</defval>" << endl;
315       }
316       t << indentStr << "  </param>" << endl;
317     }
318     t << indentStr << "</templateparamlist>" << endl;
319   }
320 }
321
322 static void writeTemplateList(ClassDef *cd,FTextStream &t)
323 {
324   writeTemplateArgumentList(cd->templateArguments(),t,cd,0,4);
325 }
326
327 static void writeDocbookDocBlock(FTextStream &t,
328     const QCString &fileName,
329     int lineNr,
330     Definition *scope,
331     MemberDef * md,
332     const QCString &text)
333 {
334   QCString stext = text.stripWhiteSpace();
335   if (stext.isEmpty()) return;
336   // convert the documentation string into an abstract syntax tree
337   DocNode *root = validatingParseDoc(fileName,lineNr,scope,md,text,FALSE,FALSE);
338   // create a code generator
339   DocbookCodeGenerator *docbookCodeGen = new DocbookCodeGenerator(t);
340   // create a parse tree visitor for Docbook
341   DocbookDocVisitor *visitor = new DocbookDocVisitor(t,*docbookCodeGen);
342   // visit all nodes
343   root->accept(visitor);
344   // clean up
345   delete visitor;
346   delete docbookCodeGen;
347   delete root;
348 }
349
350 void writeDocbookCodeBlock(FTextStream &t,FileDef *fd)
351 {
352   ParserInterface *pIntf=Doxygen::parserManager->getParser(fd->getDefFileExtension());
353   SrcLangExt langExt = getLanguageFromFileName(fd->getDefFileExtension());
354   pIntf->resetCodeParserState();
355   DocbookCodeGenerator *docbookGen = new DocbookCodeGenerator(t);
356   pIntf->parseCode(*docbookGen,  // codeOutIntf
357       0,           // scopeName
358       fileToString(fd->absFilePath(),Config_getBool(FILTER_SOURCE_FILES)),
359       langExt,     // lang
360       FALSE,       // isExampleBlock
361       0,           // exampleName
362       fd,          // fileDef
363       -1,          // startLine
364       -1,          // endLine
365       FALSE,       // inlineFragement
366       0,           // memberDef
367       TRUE         // showLineNumbers
368       );
369   docbookGen->finish();
370   delete docbookGen;
371 }
372
373 static QCString classOutputFileBase(ClassDef *cd)
374 {
375   //static bool inlineGroupedClasses = Config_getBool(INLINE_GROUPED_CLASSES);
376   //if (inlineGroupedClasses && cd->partOfGroups()!=0)
377   return cd->getOutputFileBase();
378   //else
379   //  return cd->getOutputFileBase();
380 }
381
382 static QCString memberOutputFileBase(MemberDef *md)
383 {
384   //static bool inlineGroupedClasses = Config_getBool(INLINE_GROUPED_CLASSES);
385   //if (inlineGroupedClasses && md->getClassDef() && md->getClassDef()->partOfGroups()!=0)
386   //  return md->getClassDef()->getDocbookOutputFileBase();
387   //else
388   //  return md->getOutputFileBase();
389   return md->getOutputFileBase();
390 }
391
392
393 static void generateDocbookForMember(MemberDef *md,FTextStream &t,Definition *def, bool detailed=0)
394 {
395
396   // + declaration/definition arg lists
397   // + reimplements
398   // + reimplementedBy
399   // + exceptions
400   // + const/volatile specifiers
401   // - examples
402   // + source definition
403   // + source references
404   // + source referenced by
405   // - body code
406   // + template arguments
407   //     (templateArguments(), definitionTemplateParameterLists())
408   // - call graph
409
410   // enum values are written as part of the enum
411   if (md->memberType()==MemberType_EnumValue) return;
412   if (md->isHidden()) return;
413   //if (md->name().at(0)=='@') return; // anonymous member
414
415   // group members are only visible in their group
416   //if (def->definitionType()!=Definition::TypeGroup && md->getGroupDef()) return;
417   QCString memType;
418   switch (md->memberType())
419   {
420     case MemberType_Define:      memType="define";    break;
421     case MemberType_Function:    memType="function";  break;
422     case MemberType_Variable:    memType="variable";  break;
423     case MemberType_Typedef:     memType="typedef";   break;
424     case MemberType_Enumeration: memType="enum";      break;
425     case MemberType_EnumValue:   ASSERT(0);           break;
426     case MemberType_Signal:      memType="signal";    break;
427     case MemberType_Slot:        memType="slot";      break;
428     case MemberType_Friend:      memType="friend";    break;
429     case MemberType_DCOP:        memType="dcop";      break;
430     case MemberType_Property:    memType="property";  break;
431     case MemberType_Event:       memType="event";     break;
432     case MemberType_Interface:   memType="interface"; break;
433     case MemberType_Service:     memType="service";   break;
434   }
435   QCString scopeName;
436   if (md->getClassDef())
437   {
438     scopeName=md->getClassDef()->name();
439   }
440   else if (md->getNamespaceDef())
441   {
442     scopeName=md->getNamespaceDef()->name();
443   }
444   if (detailed==0) 
445   {
446     t << "            <para>" << endl;
447     t << "                <itemizedlist>" << endl;
448     t << "                    <listitem>" << endl;
449     //enum
450     bool closePara=TRUE;
451     if (md->memberType()==MemberType_Enumeration) 
452     {
453       MemberList *enumFields = md->enumFieldList();
454       t << "                            <para><literallayout>" << memType << " <link linkend=\"";
455       if (md->getGroupDef() && def->definitionType()==Definition::TypeGroup)
456       {
457         t << md->getGroupDef()->getOutputFileBase();
458       }
459       else
460       {
461         t << memberOutputFileBase(md);
462       }
463       t << "_1" << md->anchor() << "\">" << convertToXML(md->name()) << "</link>";
464       if (enumFields!=0) 
465       {
466         MemberListIterator emli(*enumFields);
467         MemberDef *emd;
468         t << " {" << endl;
469         int cnt=0;
470         for (emli.toFirst();(emd=emli.current());++emli) 
471         {
472           if (cnt!=0) 
473           {
474             t << "," << endl;
475           }
476           t << "<link linkend=\"" << memberOutputFileBase(emd) << "_1" << emd->anchor() << "\">";
477           writeDocbookString(t,emd->name());
478           t << "</link>";
479           if (!emd->initializer().isEmpty()) 
480           {
481             writeDocbookString(t,emd->initializer());
482           }
483           cnt++;
484         }
485         t << endl << "}";
486       }
487       t << "</literallayout>" << endl;
488       if (md->briefDescription())
489       {
490           t << "<para><emphasis>";
491           writeDocbookString(t,md->briefDescription());
492           t << "</emphasis></para>" << endl;
493       }
494     }
495     else if (md->memberType()==MemberType_Define) 
496     {
497       t << "                            <para>" << "#" << memType << " <link linkend=\"";
498       if (md->getGroupDef() && def->definitionType()==Definition::TypeGroup)
499       {
500         t << md->getGroupDef()->getOutputFileBase();
501       }
502       else
503       {
504         t << memberOutputFileBase(md);
505       }
506       t << "_1" << md->anchor() << "\">" << convertToXML(md->name()) << "</link>";
507       if (!md->initializer().isEmpty() && md->initializer().length()<2000) 
508       {
509         t << " ";
510         linkifyText(TextGeneratorDocbookImpl(t),def,md->getBodyDef(),md,md->initializer());
511       }
512       if (md->briefDescription()) 
513       {
514         t << "<para><emphasis>";
515         writeDocbookString(t,md->briefDescription());
516         t << "</emphasis></para>" << endl;
517       }
518     }
519     else if (md->memberType()==MemberType_Variable) 
520     {
521       if (md->getClassDef()) 
522       {
523         t << "                        <para>" << convertToXML(md->declaration());
524         if (md->briefDescription()) 
525         {
526           t << "<para><emphasis>";
527           writeDocbookString(t,md->briefDescription());
528           t << "</emphasis></para>";
529         }
530       } 
531       else 
532       {
533         t << "                        <para>";
534         linkifyText(TextGeneratorDocbookImpl(t),def,md->getBodyDef(),md,md->typeString());
535         t << " <link linkend=\"";
536         if (md->getGroupDef() && def->definitionType()==Definition::TypeGroup)
537         {
538           t << md->getGroupDef()->getOutputFileBase();
539         }
540         else
541         {
542           t << memberOutputFileBase(md);
543         }
544         t << "_1" << md->anchor() << "\">" << convertToXML(md->name()) << "</link>";
545         if (md->briefDescription())
546         {
547             t << "<para><emphasis>";
548             writeDocbookString(t,md->briefDescription());
549             t << "</emphasis></para>" << endl;
550         }
551       }
552     }
553     else if (md->memberType()==MemberType_Typedef) 
554     {
555       t << "                            <para>" << memType;
556       t << " ";
557       linkifyText(TextGeneratorDocbookImpl(t),def,md->getBodyDef(),md,md->typeString());
558       t << " ";
559       t << " <link linkend=\"";
560       if (md->getGroupDef() && def->definitionType()==Definition::TypeGroup)
561       {
562         t << md->getGroupDef()->getOutputFileBase();
563       }
564       else
565       {
566         t << memberOutputFileBase(md);
567       }
568       t << "_1" << md->anchor() << "\">" << convertToXML(md->name()) << "</link>";
569       if (md->briefDescription())
570       {
571           t << "<para><emphasis>";
572           writeDocbookString(t,md->briefDescription());
573           t << "</emphasis></para>" << endl;
574       }
575     }
576     else if (md->memberType()==MemberType_Function) 
577     {
578       t << "                        <para>";
579       linkifyText(TextGeneratorDocbookImpl(t),def,md->getBodyDef(),md,md->typeString());
580       t << " <link linkend=\"";
581       if (md->getGroupDef() && def->definitionType()==Definition::TypeGroup)
582       {
583         t << md->getGroupDef()->getOutputFileBase();
584       }
585       else
586       {
587         t << memberOutputFileBase(md);
588       }
589       t << "_1" << md->anchor() << "\">" << convertToXML(md->name()) << "</link>";
590       t << " (" << endl;
591       ArgumentList *declAl = md->declArgumentList();
592       if (declAl && declAl->count()>0)
593       {
594         ArgumentListIterator declAli(*declAl);
595         Argument *a;
596         int cnt=0;
597         for (declAli.toFirst();(a=declAli.current());++declAli)
598         {
599           if (cnt!=0) 
600           {
601             t << ", ";
602           }
603           if (!a->type.isEmpty())
604           {
605             linkifyText(TextGeneratorDocbookImpl(t),def,md->getBodyDef(),md,a->type);
606           }
607           t << " ";
608           if (!a->name.isEmpty())
609           {
610             writeDocbookString(t,a->name);
611           }
612           cnt++;
613         }
614       }
615       t << ")";
616       if (md->briefDescription())
617       {
618           t << "<para><emphasis>";
619           writeDocbookString(t,md->briefDescription());
620           t << "</emphasis></para>" << endl;
621       }
622     }
623     else
624     {
625       closePara = FALSE;
626     }
627     if (closePara) t << "</para>" << endl;
628     t << "                    </listitem>" << endl;
629     t << "                </itemizedlist>" << endl;
630     t << "            </para>" << endl;
631   }
632   else
633   {
634     if (md->memberType()==MemberType_Enumeration)
635     {
636       MemberList *enumFields = md->enumFieldList();
637       t << "            <section xml:id=\"";
638       if (md->getGroupDef() && def->definitionType()==Definition::TypeGroup)
639       {
640         t << md->getGroupDef()->getOutputFileBase();
641       }
642       else
643       {
644         t << memberOutputFileBase(md);
645       }
646       t << "_1" << md->anchor() << "\">" << endl;
647       t << "               <title>" << memType << " " << convertToXML(md->name()) << " " << "</title>" << endl;
648       t << "               ";
649       writeDocbookDocBlock(t,md->docFile(),md->docLine(),md->getOuterScope(),md,md->documentation());
650       t << endl;
651       if (enumFields!=0) 
652       {
653         MemberListIterator emli(*enumFields);
654         MemberDef *emd;
655         t << "               <formalpara>" << endl;
656         t << "                    <title>" << theTranslator->trEnumerationValues() << ":</title>" << endl;
657         t << "                    <variablelist>" << endl;
658         for (emli.toFirst();(emd=emli.current());++emli) 
659         {
660           t << "                        <varlistentry xml:id=\"";
661           t << memberOutputFileBase(emd) << "_1" << emd->anchor() << "\">" << endl;
662           t << "                            <term>";
663           writeDocbookString(t,emd->name());
664           t << "</term>" << endl;
665           t << "                            <listitem>" << endl;
666           if(Config_getBool(REPEAT_BRIEF))
667           {
668               t << "                                <para>";
669               writeDocbookString(t,emd->briefDescription());
670               t << "</para>" << endl;
671           }
672           t << "                            </listitem>" << endl;
673           t << "                        </varlistentry>" << endl;
674         }
675         t << "                     </variablelist>" << endl;
676         t << "                </formalpara>" << endl;
677         t << "                <para>";
678         t << "Definition at line " << md->getDefLine() << " of file " << stripPath(md->getDefFileName()) << endl;
679         t << "                    <computeroutput><literallayout>" << endl;
680         t << "{" << endl;
681         for (emli.toFirst();(emd=emli.current());++emli) 
682         {
683           writeDocbookString(t,emd->name());
684           if (!emd->initializer().isEmpty()) 
685           {
686             writeDocbookString(t,emd->initializer());
687           }
688           t << ", " << endl;
689         }
690         t << "}" << convertToXML(md->name()) << ";" << endl;
691         t << "                    </literallayout></computeroutput>" << endl;
692         t << "                </para>" << endl;
693         t << "            </section>" << endl;
694       }
695     }
696     else if (md->memberType()==MemberType_Typedef) 
697     {
698       t << "            <section xml:id=\"";
699       if (md->getGroupDef() && def->definitionType()==Definition::TypeGroup)
700       {
701         t << md->getGroupDef()->getOutputFileBase();
702       }
703       else
704       {
705         t << memberOutputFileBase(md);
706       }
707       t << "_1" << md->anchor() << "\">" << endl;
708       t << "                <title>" << convertToXML(md->definition()) << "</title>";
709       if(Config_getBool(REPEAT_BRIEF))
710       {
711           t << " <emphasis>";
712           writeDocbookString(t,md->briefDescription());
713           t << "</emphasis>" << endl;
714       }
715       t << "                ";
716       writeDocbookDocBlock(t,md->docFile(),md->docLine(),md->getOuterScope(),md,md->documentation());
717       t << endl;
718       t << "            </section>" << endl;
719     }
720     else if (md->memberType()==MemberType_Function) 
721     {
722       t << "            <section xml:id=\"";
723       if (md->getGroupDef() && def->definitionType()==Definition::TypeGroup)
724       {
725         t << md->getGroupDef()->getOutputFileBase();
726       }
727       else
728       {
729         t << memberOutputFileBase(md);
730       }
731       t << "_1" << md->anchor() << "\">" << endl;
732       t << "                <title>" << convertToXML(md->definition()) << " " << convertToXML(md->argsString()) << "</title>";
733       if(Config_getBool(REPEAT_BRIEF))
734       {
735           t << " <emphasis>";
736           writeDocbookString(t,md->briefDescription());
737           t << "</emphasis>" << endl;
738       }
739       t << "                ";
740       writeDocbookDocBlock(t,md->docFile(),md->docLine(),md->getOuterScope(),md,md->documentation());
741       t << endl;
742       t << "            </section>" << endl;
743     }
744     else if (md->memberType()==MemberType_Define) 
745     {
746       if (md->documentation()) 
747       {
748         t << "            <section xml:id=\"";
749         if (md->getGroupDef() && def->definitionType()==Definition::TypeGroup)
750         {
751           t << md->getGroupDef()->getOutputFileBase();
752         }
753         else
754         {
755           t << memberOutputFileBase(md);
756         }
757         t << "_1" << md->anchor() << "\">" << endl;
758         t << "                <title>" << convertToXML(md->definition()) << "</title>";
759         t << "                ";
760         writeDocbookDocBlock(t,md->docFile(),md->docLine(),md->getOuterScope(),md,md->documentation());
761         t << endl;
762         t << "                <para>Definition at line " << md->getDefLine() << " of file " << stripPath(md->getDefFileName()) << "</para>" << endl;
763         t << "                <para>The Documentation for this define was generated from the following file: </para>" << endl;
764         t << "                <para><itemizedlist><listitem><para>" << stripPath(md->getDefFileName()) << "</para></listitem></itemizedlist></para>" << endl;
765         t << "            </section>" << endl;
766       }
767     }
768     else if (md->memberType()==MemberType_Variable) 
769     {
770       if (md->getClassDef()) 
771       {
772         if (md->documentation()) 
773         {
774           t << "            <simplesect>" << endl;
775           t << "                <title>" << convertToXML(md->definition()) << "</title>";
776           t << "                ";
777           writeDocbookDocBlock(t,md->docFile(),md->docLine(),md->getOuterScope(),md,md->documentation());
778           t << endl;
779           t << "                <para>Definition at line " << md->getDefLine() << " of file " << stripPath(md->getDefFileName()) << "</para>" << endl;
780           t << "                <para>The Documentation for this struct was generated from the following file: </para>" << endl;
781           t << "                <para><itemizedlist><listitem><para>" << stripPath(md->getDefFileName()) << "</para></listitem></itemizedlist></para>" << endl;
782           t << "            </simplesect>" << endl;
783         }
784       }
785       else 
786       {
787         t << "            <section xml:id=\"";
788         if (md->getGroupDef() && def->definitionType()==Definition::TypeGroup)
789         {
790           t << md->getGroupDef()->getOutputFileBase();
791         }
792         else
793         {
794           t << memberOutputFileBase(md);
795         }
796         t << "_1" << md->anchor() << "\">" << endl;
797         t << "                <title>" << convertToXML(md->definition()) << "</title>";
798         if(Config_getBool(REPEAT_BRIEF))
799         {
800             t << " <emphasis>";
801             writeDocbookString(t,md->briefDescription());
802             t << "</emphasis>" << endl;
803         }
804         t << "                ";
805         writeDocbookDocBlock(t,md->docFile(),md->docLine(),md->getOuterScope(),md,md->documentation());
806         t << endl;
807         t << "            </section>" << endl;
808       }
809     }
810   }
811 }
812
813 static void generateDocbookSection(Definition *d,FTextStream &t,MemberList *ml,const char *,
814     bool detailed=0, const char *header=0,const char *documentation=0)
815 {
816   if (ml==0) return;
817   MemberListIterator mli(*ml);
818   MemberDef *md;
819   int count=0;
820   int doc_count=0;
821   QCString title, desctitle;
822
823   for (mli.toFirst();(md=mli.current());++mli) 
824   {
825     // namespace members are also inserted in the file scope, but
826     // to prevent this duplication in the Docbook output, we filter those here.
827     if (d->definitionType()!=Definition::TypeFile || md->getNamespaceDef()==0) 
828     {
829       count++;
830     }
831   }
832   
833   if (count==0) return; // empty list
834
835   switch (ml->listType())
836   {
837     case MemberListType_decDefineMembers:  title=theTranslator->trDefines();             desctitle=theTranslator->trDefineDocumentation();            break;
838     case MemberListType_decTypedefMembers: title=theTranslator->trTypedefs();            desctitle=theTranslator->trTypedefDocumentation();           break;
839     case MemberListType_decEnumMembers:    title=theTranslator->trEnumerations();        desctitle=theTranslator->trEnumerationTypeDocumentation();   break;
840     case MemberListType_decFuncMembers:    title=theTranslator->trFunctions();           desctitle=theTranslator->trFunctionDocumentation();          break;
841     case MemberListType_decVarMembers:     title=theTranslator->trVariables();           desctitle=theTranslator->trVariableDocumentation();          break;
842     case MemberListType_pubAttribs:        title=theTranslator->trPublicAttribs();       desctitle=theTranslator->trMemberDataDocumentation();        break;
843     case MemberListType_priAttribs:        title=theTranslator->trPrivateAttribs();      desctitle=theTranslator->trMemberDataDocumentation();        break;
844     case MemberListType_proAttribs:        title=theTranslator->trProtectedAttribs();    desctitle=theTranslator->trMemberDataDocumentation();        break;
845     default:                               title="";                    desctitle="";                                  break;
846   }
847
848   if (detailed) 
849   {
850     for (mli.toFirst();(md=mli.current());++mli)
851     {
852         if (md->documentation().isEmpty() && !Config_getBool(REPEAT_BRIEF))
853         {
854             continue;
855         }
856         doc_count = 1;
857         break;
858     }
859
860     if(doc_count == 0)
861     {
862         return;
863     }
864
865     if (desctitle)
866     {
867         t << "        <section>" << endl;
868         t << "            <title>" << desctitle << "</title>" << endl;
869     }
870   } else 
871   {
872     t << "        <section>" << endl;
873     if (header) 
874     {
875       t << "            <title>" << convertToXML(header) << "</title>" << endl;
876     } 
877     else 
878     {
879       t << "            <title>" << title << "</title>" << endl;
880     }
881   }
882
883   if (documentation) 
884   {
885     t << "      <description>";
886     writeDocbookDocBlock(t,d->docFile(),d->docLine(),d,0,documentation);
887     t << "</description>" << endl;
888   }
889   for (mli.toFirst();(md=mli.current());++mli) 
890   {
891     // namespace members are also inserted in the file scope, but
892     // to prevent this duplication in the Docbook output, we filter those here.
893     if (d->definitionType()!=Definition::TypeFile || md->getNamespaceDef()==0) 
894     {
895         if (detailed && md->documentation().isEmpty() && !Config_getBool(REPEAT_BRIEF))
896         {
897             continue;
898         }
899
900         generateDocbookForMember(md,t,d,detailed);
901     }
902   }
903   if (detailed) 
904   {
905     if (desctitle) 
906     {
907         t << "        </section>" << endl;
908     }
909   } 
910   else 
911   {
912     t << "        </section>" << endl;
913   }
914 }
915
916 static void writeInnerClasses(const ClassSDict *cl,FTextStream &t)
917 {
918   if (cl)
919   {
920     ClassSDict::Iterator cli(*cl);
921     ClassDef *cd;
922     QCString title = theTranslator->trClasses();
923
924     if (cli.toFirst()) 
925     {
926       t << "        <section>" << endl;
927       t << "            <title> " << title << " </title>" << endl;
928     }
929     for (cli.toFirst();(cd=cli.current());++cli)
930     {
931       if (!cd->isHidden() && cd->name().find('@')==-1) 
932       {
933         t << "            <para>" << endl;
934         t << "                <itemizedlist>" << endl;
935         t << "                    <listitem>" << endl;
936         t << "                        <para>" << "struct <link linkend=\"" << classOutputFileBase(cd) << "\">" << convertToXML(cd->name()) << "</link>";
937         t << "</para>" << endl;
938         if (cd->briefDescription())
939         {
940             t << "<para><emphasis>";
941             writeDocbookString(t,cd->briefDescription());
942             t << "</emphasis></para>" << endl;
943         }
944         t << "                    </listitem>" << endl;
945         t << "                </itemizedlist>" << endl;
946         t << "            </para>" << endl;
947       }
948     }
949     if (cli.toFirst()) 
950     {
951       t << "        </section>" << endl;
952     }
953   }
954 }
955
956 static void writeInnerNamespaces(const NamespaceSDict *nl,FTextStream &t)
957 {
958   if (nl)
959   {
960     NamespaceSDict::Iterator nli(*nl);
961     NamespaceDef *nd;
962     QCString title = theTranslator->trNamespaces();
963
964     if (nli.toFirst()) 
965     {
966       t << "        <simplesect>" << endl;
967       t << "            <title> " << title << " </title>" << endl;
968     }
969     for (nli.toFirst();(nd=nli.current());++nli)
970     {
971       if (!nd->isHidden() && nd->name().find('@')==-1) // skip anonymouse scopes
972       {
973         t << "            <para>" << endl;
974         t << "                <itemizedlist>" << endl;
975         t << "                    <listitem>" << endl;
976         t << "                        <para>" << "struct <link linkend=\"" << nd->getOutputFileBase() << "\">" << convertToXML(nd->name()) << "</link>";
977         t << "</para>" << endl;
978         t << "                    </listitem>" << endl;
979         t << "                </itemizedlist>" << endl;
980         t << "            </para>" << endl;
981       }
982     }
983     if (nli.toFirst()) 
984     {
985       t << "        </simplesect>" << endl;
986     }
987   }
988 }
989
990 static void writeInnerFiles(const FileList *fl,FTextStream &t)
991 {
992   if (fl)
993   {
994     QListIterator<FileDef> fli(*fl);
995     FileDef *fd;
996     QCString title =  theTranslator->trFile(TRUE,TRUE);
997
998     if (fli.toFirst()) 
999     {
1000       t << "        <simplesect>" << endl;
1001       t << "            <title> " << title << " </title>" << endl;
1002     }
1003     for (fli.toFirst();(fd=fli.current());++fli) 
1004     {
1005       t << "            <para>" << endl;
1006       t << "                <itemizedlist>" << endl;
1007       t << "                    <listitem>" << endl;
1008       t << "                        <para>" << "file <link linkend=\"" << fd->getOutputFileBase() << "\">" << convertToXML(fd->name()) << "</link>";
1009       t << "</para>" << endl;
1010       t << "                    </listitem>" << endl;
1011       t << "                </itemizedlist>" << endl;
1012       t << "            </para>" << endl;
1013     }
1014     if (fli.toFirst()) 
1015     {
1016       t << "        </simplesect>" << endl;
1017     }
1018   }
1019 }
1020
1021 static void writeInnerPages(const PageSDict *pl,FTextStream &t)
1022 {
1023   if (pl)
1024   {
1025     PageSDict::Iterator pli(*pl);
1026     PageDef *pd;
1027
1028     for (pli.toFirst();(pd=pli.current());++pli)
1029     {
1030       t << "<xi:include href=\"" << pd->getOutputFileBase() << ".xml\" xmlns:xi=\"http://www.w3.org/2001/XInclude\"/>"  << endl;
1031     }
1032   }
1033 }
1034
1035 static void writeInnerGroups(const GroupList *gl,FTextStream &t)
1036 {
1037   if (gl)
1038   {
1039     GroupListIterator gli(*gl);
1040     GroupDef *sgd;
1041
1042     //Docbook header tags for inner groups
1043     if (gli.toFirst()) 
1044     {
1045       t << "    <simplesect>" << endl;
1046       t << "        <title>" << theTranslator->trModules() << "</title>" << endl;
1047       t << "    </simplesect>" << endl;
1048       t << "    <para>" << endl;
1049       t << "        <itemizedlist>" << endl;
1050     }
1051
1052     for (gli.toFirst();(sgd=gli.current());++gli)
1053     {
1054       t << "            <listitem><para><link linkend=\"" << sgd->getOutputFileBase() << "\">" << convertToXML(sgd->groupTitle()) << "</link></para></listitem>" << endl;
1055     }
1056
1057     //Docbook footer tags for inner groups
1058     if (gli.toFirst()) 
1059     {
1060       t << "        </itemizedlist>" << endl;
1061       t << "    </para>" << endl;
1062     }
1063
1064   }
1065 }
1066
1067 static void writeInnerDirs(const DirList *dl,FTextStream &t)
1068 {
1069   if (dl)
1070   {
1071     QListIterator<DirDef> subdirs(*dl);
1072     DirDef *subdir;
1073     QCString title = theTranslator->trDirectories();
1074     if (subdirs.toFirst()) 
1075     {
1076       t << "        <simplesect>" << endl;
1077       t << "            <title> " << title << " </title>" << endl;
1078     }
1079     for (subdirs.toFirst();(subdir=subdirs.current());++subdirs)
1080     {
1081       t << "            <para>" << endl;
1082       t << "                <itemizedlist>" << endl;
1083       t << "                    <listitem>" << endl;
1084       t << "                        <para>" << "dir <link linkend=\"" << subdir->getOutputFileBase() << "\">" << convertToXML(subdir->displayName()) << "</link>";
1085       t << "</para>" << endl;
1086       t << "                    </listitem>" << endl;
1087       t << "                </itemizedlist>" << endl;
1088       t << "            </para>" << endl;
1089     }
1090     if (subdirs.toFirst()) 
1091     {
1092       t << "        </simplesect>" << endl;
1093     }
1094   }
1095 }
1096
1097 static void writeInnerGroupFiles(const GroupList *gl,FTextStream &t)
1098 {
1099   if (gl)
1100   {
1101     GroupListIterator gli(*gl);
1102     GroupDef *sgd;
1103
1104     for (gli.toFirst();(sgd=gli.current());++gli)
1105     {
1106       t << "<xi:include href=\"" << sgd->getOutputFileBase() << ".xml\" xmlns:xi=\"http://www.w3.org/2001/XInclude\"/>"  << endl;
1107     }
1108   }
1109 }
1110
1111 static void generateDocbookForClass(ClassDef *cd,FTextStream &ti)
1112 {
1113   // + brief description
1114   // + detailed description
1115   // + template argument list(s)
1116   // - include file
1117   // + member groups
1118   // + inheritance diagram
1119   // + list of direct super classes
1120   // + list of direct sub classes
1121   // + list of inner classes
1122   // + collaboration diagram
1123   // + list of all members
1124   // + user defined member sections
1125   // + standard member sections
1126   // + detailed member documentation
1127   // - examples using the class
1128
1129   if (cd->isReference())        return; // skip external references.
1130   if (cd->isHidden())           return; // skip hidden classes.
1131   if (cd->name().find('@')!=-1) return; // skip anonymous compounds.
1132   if (cd->templateMaster()!=0)  return; // skip generated template instances.
1133
1134   msg("Generating Docbook output for class %s\n",cd->name().data());
1135
1136   QCString fileDocbook=cd->getOutputFileBase()+".xml";
1137   //Add the file Documentation info to index file
1138   ti << "        <xi:include href=\"" << fileDocbook << "\" xmlns:xi=\"http://www.w3.org/2001/XInclude\"/>" << endl;
1139
1140   QCString outputDirectory = Config_getString(DOCBOOK_OUTPUT);
1141   QCString fileName=outputDirectory+"/"+ classOutputFileBase(cd)+".xml";
1142   QCString relPath = relativePathToRoot(fileName);
1143   QFile f(fileName);
1144   if (!f.open(IO_WriteOnly))
1145   {
1146     err("Cannot open file %s for writing!\n",fileName.data());
1147     return;
1148   }
1149   FTextStream t(&f);
1150   //t.setEncoding(FTextStream::UnicodeUTF8);
1151
1152   writeDocbookHeader_ID(t, classOutputFileBase(cd));
1153   t << "<title>";
1154   writeDocbookString(t,cd->name());
1155   t << " " << cd->compoundTypeString() << " Reference";
1156   t << "</title>" << endl;
1157
1158   IncludeInfo *ii=cd->includeInfo();
1159   if (ii)
1160   {
1161     QCString nm = ii->includeName;
1162     if (nm.isEmpty() && ii->fileDef) nm = ii->fileDef->docName();
1163     if (!nm.isEmpty())
1164     {
1165       t << "<para>" << endl;
1166       t << "    <programlisting>#include ";
1167       if (ii->fileDef && !ii->fileDef->isReference()) // TODO: support external references
1168       {
1169         t << "<link linkend=\"" << ii->fileDef->getOutputFileBase() << "\">";
1170       }
1171       if (ii->local)
1172       {
1173         t << "&quot;";
1174       }
1175       else
1176       {
1177         t << "&lt;";
1178       }
1179       t << convertToXML(nm);
1180       if (ii->local)
1181       {
1182         t << "&quot;";
1183       }
1184       else
1185       {
1186         t << "&gt;";
1187       }
1188       if (ii->fileDef && !ii->fileDef->isReference())
1189       {
1190         t << "</link>";
1191       }
1192       t << "</programlisting>" << endl;
1193       t << "</para>" << endl;
1194     }
1195   }
1196
1197   if (Config_getBool(HAVE_DOT) && (Config_getBool(CLASS_DIAGRAMS) || Config_getBool(CLASS_GRAPH)))
1198   {
1199     t << "<para>Inheritance diagram for " << convertToXML(cd->name()) << "</para>" << endl;
1200     DotClassGraph inheritanceGraph(cd,DotNode::Inheritance);
1201     inheritanceGraph.writeGraph(t,GOF_BITMAP,EOF_DocBook,Config_getString(DOCBOOK_OUTPUT),fileName,relPath,TRUE,FALSE);
1202   }
1203
1204   if (Config_getBool(HAVE_DOT) && Config_getBool(COLLABORATION_GRAPH))
1205   {
1206     t << "<para>Collaboration diagram for " << convertToXML(cd->name()) << "</para>" << endl;
1207     DotClassGraph collaborationGraph(cd,DotNode::Collaboration);
1208     collaborationGraph.writeGraph(t,GOF_BITMAP,EOF_DocBook,Config_getString(DOCBOOK_OUTPUT),fileName,relPath,TRUE,FALSE);
1209   }
1210
1211   writeInnerClasses(cd->getClassSDict(),t);
1212
1213   writeTemplateList(cd,t);
1214   if (cd->getMemberGroupSDict())
1215   {
1216     MemberGroupSDict::Iterator mgli(*cd->getMemberGroupSDict());
1217     MemberGroup *mg;
1218     for (;(mg=mgli.current());++mgli)
1219     {
1220       generateDocbookSection(cd,t,mg->members(),"user-defined",0,mg->header(),
1221           mg->documentation());
1222     }
1223   }
1224
1225
1226   QListIterator<MemberList> mli(cd->getMemberLists());
1227   MemberList *ml;
1228   for (mli.toFirst();(ml=mli.current());++mli)
1229   {
1230     if ((ml->listType()&MemberListType_detailedLists)==0)
1231     {
1232       generateDocbookSection(cd,t,ml,g_docbookSectionMapper.find(ml->listType()));
1233     }
1234   }
1235
1236   if(Config_getBool(REPEAT_BRIEF))
1237   {
1238       if (cd->briefDescription()) 
1239       {
1240           t << "    <simplesect>" << endl;
1241           // A title as 'Brief Description' may not be necessary.
1242           //t << "        <title>" << theTranslator->trBriefDescription() << "</title>" << endl;
1243           writeDocbookDocBlock(t,cd->briefFile(),cd->briefLine(),cd,0,cd->briefDescription());
1244           t << "    </simplesect>" << endl;
1245       }
1246   }
1247
1248   if (cd->documentation()) 
1249   {
1250     t << "        <simplesect>" << endl;
1251     t << "            <title>" << theTranslator->trDetailedDescription() << "</title>" << endl;
1252     writeDocbookDocBlock(t,cd->docFile(),cd->docLine(),cd,0,cd->documentation());
1253     t << "                <para>Definition at line " << cd->getDefLine() << " of file " << stripPath(cd->getDefFileName()) << "</para>" << endl;
1254     t << "                <para>The Documentation for this struct was generated from the following file: </para>" << endl;
1255     t << "                <para><itemizedlist><listitem><para>" << stripPath(cd->getDefFileName()) << "</para></listitem></itemizedlist></para>" << endl;
1256     t << "        </simplesect>" << endl;
1257   }
1258   for (mli.toFirst();(ml=mli.current());++mli)
1259   {
1260     if ((ml->listType()&MemberListType_detailedLists)==0)
1261     {
1262       generateDocbookSection(cd,t,ml,g_docbookSectionMapper.find(ml->listType()),1);
1263     }
1264   }
1265
1266   /*// TODO: Handling of Inheritance and Colloboration graph for Docbook to be implemented
1267     DotClassGraph inheritanceGraph(cd,DotNode::Inheritance);
1268     if (!inheritanceGraph.isTrivial())
1269     {
1270     t << "    <inheritancegraph>" << endl;
1271     inheritanceGraph.writeDocbook(t);
1272     t << "    </inheritancegraph>" << endl;
1273     }
1274     DotClassGraph collaborationGraph(cd,DotNode::Collaboration);
1275     if (!collaborationGraph.isTrivial())
1276     {
1277     t << "    <collaborationgraph>" << endl;
1278     collaborationGraph.writeDocbook(t);
1279     t << "    </collaborationgraph>" << endl;
1280     }
1281     t << "    <location file=\""
1282     << cd->getDefFileName() << "\" line=\""
1283     << cd->getDefLine() << "\"";
1284     if (cd->getStartBodyLine()!=-1)
1285     {
1286     FileDef *bodyDef = cd->getBodyDef();
1287     if (bodyDef)
1288     {
1289     t << " bodyfile=\"" << bodyDef->absFilePath() << "\"";
1290     }
1291     t << " bodystart=\"" << cd->getStartBodyLine() << "\" bodyend=\""
1292     << cd->getEndBodyLine() << "\"";
1293     }
1294     t << "/>" << endl;
1295     writeListOfAllMembers(cd,t);
1296    */
1297
1298   t << "</section>" << endl;
1299
1300 }
1301
1302 static void generateDocbookForNamespace(NamespaceDef *nd,FTextStream &ti)
1303 {
1304   // + contained class definitions
1305   // + contained namespace definitions
1306   // + member groups
1307   // + normal members
1308   // + brief desc
1309   // + detailed desc
1310   // + location
1311   // - files containing (parts of) the namespace definition
1312
1313   if (nd->isReference() || nd->isHidden()) return; // skip external references
1314
1315   QCString fileDocbook=nd->getOutputFileBase()+".xml";
1316   //Add the file Documentation info to index file
1317   ti << "        <xi:include href=\"" << fileDocbook << "\" xmlns:xi=\"http://www.w3.org/2001/XInclude\"/>" << endl;
1318
1319   QCString outputDirectory = Config_getString(DOCBOOK_OUTPUT);
1320   QCString fileName=outputDirectory+"/"+nd->getOutputFileBase()+".xml";
1321   QFile f(fileName);
1322   if (!f.open(IO_WriteOnly))
1323   {
1324     err("Cannot open file %s for writing!\n",fileName.data());
1325     return;
1326   }
1327   FTextStream t(&f);
1328   //t.setEncoding(FTextStream::UnicodeUTF8);
1329
1330   writeDocbookHeader_ID(t, nd->getOutputFileBase());
1331   t << "<title>";
1332   writeDocbookString(t,nd->name());
1333   t << "</title>" << endl;
1334
1335   writeInnerClasses(nd->getClassSDict(),t);
1336   writeInnerNamespaces(nd->getNamespaceSDict(),t);
1337
1338   if (nd->getMemberGroupSDict())
1339   {
1340     MemberGroupSDict::Iterator mgli(*nd->getMemberGroupSDict());
1341     MemberGroup *mg;
1342     for (;(mg=mgli.current());++mgli)
1343     {
1344       generateDocbookSection(nd,t,mg->members(),"user-defined",0,mg->header(),
1345           mg->documentation());
1346     }
1347   }
1348
1349   QListIterator<MemberList> mli(nd->getMemberLists());
1350   MemberList *ml;
1351   for (mli.toFirst();(ml=mli.current());++mli)
1352   {
1353     if ((ml->listType()&MemberListType_declarationLists)!=0)
1354     {
1355       generateDocbookSection(nd,t,ml,g_docbookSectionMapper.find(ml->listType()));
1356     }
1357   }
1358
1359   if(Config_getBool(REPEAT_BRIEF))
1360   {
1361       if (nd->briefDescription()) 
1362       {
1363           t << "    <simplesect>" << endl;
1364           //t << "        <title>" << theTranslator->trBriefDescription() << "</title>" << endl;
1365           writeDocbookDocBlock(t,nd->briefFile(),nd->briefLine(),nd,0,nd->briefDescription());
1366           t << "    </simplesect>" << endl;
1367       }
1368   }
1369
1370   if (nd->documentation()) 
1371   {
1372     t << "        <simplesect>" << endl;
1373     t << "            <title>" << theTranslator->trDetailedDescription() << "</title>" << endl;
1374     writeDocbookDocBlock(t,nd->docFile(),nd->docLine(),nd,0,nd->documentation());
1375     t << "                <para>Definition at line " << nd->getDefLine() << " of file " << stripPath(nd->getDefFileName()) << "</para>" << endl;
1376     t << "                <para>The Documentation for this struct was generated from the following file: </para>" << endl;
1377     t << "                <para><itemizedlist><listitem><para>" << stripPath(nd->getDefFileName()) << "</para></listitem></itemizedlist></para>" << endl;
1378     t << "        </simplesect>" << endl;
1379   }
1380   t << "</section>" << endl;
1381 }
1382
1383 static void generateDocbookForFile(FileDef *fd,FTextStream &ti)
1384 {
1385   // + includes files
1386   // + includedby files
1387   // + include graph
1388   // + included by graph
1389   // + contained class definitions
1390   // + contained namespace definitions
1391   // + member groups
1392   // + normal members
1393   // + brief desc
1394   // + detailed desc
1395   // + source code
1396   // + location
1397   // - number of lines
1398
1399   if (fd->isReference()) return; // skip external references
1400
1401   QCString fileDocbook=fd->getOutputFileBase()+".xml";
1402   //Add the file Documentation info to index file
1403   ti << "        <xi:include href=\"" << fileDocbook << "\" xmlns:xi=\"http://www.w3.org/2001/XInclude\"/>" << endl;
1404
1405   QCString outputDirectory = Config_getString(DOCBOOK_OUTPUT);
1406   QCString fileName=outputDirectory+"/"+fd->getOutputFileBase()+".xml";
1407   QCString relPath = relativePathToRoot(fileName);
1408
1409   QFile f(fileName);
1410   if (!f.open(IO_WriteOnly))
1411   {
1412     err("Cannot open file %s for writing!\n",fileName.data());
1413     return;
1414   }
1415   FTextStream t(&f);
1416   //t.setEncoding(FTextStream::UnicodeUTF8);
1417   writeDocbookHeader_ID(t, fd->getOutputFileBase());
1418
1419   t << "    <title>";
1420   writeDocbookString(t,fd->name());
1421   t << " File Reference";
1422   t << "</title>" << endl;
1423
1424   IncludeInfo *inc;
1425
1426   if (fd->includeFileList())
1427   {
1428     QListIterator<IncludeInfo> ili1(*fd->includeFileList());
1429     for (ili1.toFirst();(inc=ili1.current());++ili1)
1430     {
1431       t << "    <programlisting>#include ";
1432       if (inc->local)
1433       {
1434         t << "&quot;";
1435       }
1436       else
1437       {
1438         t << "&lt;";
1439       }
1440       t << convertToXML(inc->includeName);
1441       if (inc->local)
1442       {
1443         t << "&quot;";
1444       }
1445       else
1446       {
1447         t << "&gt;";
1448       }
1449       t << "</programlisting>" << endl;
1450     }
1451   }
1452   if (Config_getBool(HAVE_DOT))
1453   {
1454     if (Config_getBool(INCLUDE_GRAPH))
1455     {
1456       t << "<para>Include dependency diagram for " << convertToXML(fd->name()) << "</para>" << endl;
1457       DotInclDepGraph idepGraph(fd, FALSE);
1458       idepGraph.writeGraph(t,GOF_BITMAP,EOF_DocBook,Config_getString(DOCBOOK_OUTPUT),fileName,relPath,FALSE);
1459     }
1460     if (Config_getBool(INCLUDED_BY_GRAPH))
1461     {
1462       t << "<para>Included by dependency diagram for " << convertToXML(fd->name()) << "</para>" << endl;
1463       DotInclDepGraph ibdepGraph(fd, TRUE);
1464       ibdepGraph.writeGraph(t,GOF_BITMAP,EOF_DocBook,Config_getString(DOCBOOK_OUTPUT),fileName,relPath,FALSE);
1465     }
1466   }
1467
1468   if (fd->getClassSDict())
1469   {
1470     writeInnerClasses(fd->getClassSDict(),t);
1471   }
1472   if (fd->getNamespaceSDict())
1473   {
1474     writeInnerNamespaces(fd->getNamespaceSDict(),t);
1475   }
1476
1477   if (fd->getMemberGroupSDict())
1478   {
1479     MemberGroupSDict::Iterator mgli(*fd->getMemberGroupSDict());
1480     MemberGroup *mg;
1481     for (;(mg=mgli.current());++mgli)
1482     {
1483       generateDocbookSection(fd,t,mg->members(),"user-defined",0,mg->header(),
1484           mg->documentation());
1485     }
1486   }
1487
1488   QListIterator<MemberList> mli(fd->getMemberLists());
1489   MemberList *ml;
1490   for (mli.toFirst();(ml=mli.current());++mli)
1491   {
1492     if ((ml->listType()&MemberListType_declarationLists)!=0)
1493     {
1494       generateDocbookSection(fd,t,ml,g_docbookSectionMapper.find(ml->listType()));
1495     }
1496   }
1497
1498   t << "    <simplesect>" << endl;
1499   t << "        <title>" << theTranslator->trDetailedDescription() << "</title>" << endl;
1500   writeDocbookDocBlock(t,fd->briefFile(),fd->briefLine(),fd,0,fd->briefDescription());
1501   writeDocbookDocBlock(t,fd->docFile(),fd->docLine(),fd,0,fd->documentation());
1502   if (Config_getBool(FULL_PATH_NAMES)) 
1503   {
1504     t << "    <para>Definition in file " << fd->getDefFileName() << "</para>" << endl;
1505   }
1506   else
1507   {
1508     t << "    <para>Definition in file " << stripPath(fd->getDefFileName()) << "</para>" << endl;
1509   }
1510   t << "    </simplesect>" << endl;
1511
1512   if (Config_getBool(DOCBOOK_PROGRAMLISTING))
1513   {
1514     t << "    <literallayout><computeroutput>" << endl;
1515     writeDocbookCodeBlock(t,fd);
1516     t << "    </computeroutput></literallayout>" << endl;
1517   }
1518
1519   t << "</section>" << endl;
1520 }
1521
1522 static void generateDocbookForGroup(GroupDef *gd,FTextStream &ti)
1523 {
1524   // + members
1525   // + member groups
1526   // + files
1527   // + classes
1528   // + namespaces
1529   // - packages
1530   // + pages
1531   // + child groups
1532   // - examples
1533   // + brief description
1534   // + detailed description
1535
1536   if (gd->isReference()) return; // skip external references
1537
1538   if (!gd->isASubGroup()) 
1539   {
1540     QCString fileDocbook=gd->getOutputFileBase()+".xml";
1541     //Add the file Documentation info to index file
1542     ti << "        <xi:include href=\"" << fileDocbook << "\" xmlns:xi=\"http://www.w3.org/2001/XInclude\"/>" << endl;
1543   }
1544
1545   QCString outputDirectory = Config_getString(DOCBOOK_OUTPUT);
1546   QCString fileName=outputDirectory+"/"+gd->getOutputFileBase()+".xml";
1547   QCString relPath = relativePathToRoot(fileName);
1548
1549   QFile f(fileName);
1550   if (!f.open(IO_WriteOnly))
1551   {
1552     err("Cannot open file %s for writing!\n",fileName.data());
1553     return;
1554   }
1555
1556   FTextStream t(&f);
1557   //t.setEncoding(FTextStream::UnicodeUTF8);
1558   writeDocbookHeader_ID(t, gd->getOutputFileBase());
1559
1560   t << "    <title>" << convertToXML(gd->groupTitle()) << "</title>" << endl;
1561
1562   if (Config_getBool(GROUP_GRAPHS) && Config_getBool(HAVE_DOT))
1563   {
1564     t << "<para>Collaboration diagram for " << convertToXML(gd->groupTitle()) << "</para>" << endl;
1565     DotGroupCollaboration collaborationGraph(gd);
1566     collaborationGraph.writeGraph(t,GOF_BITMAP,EOF_DocBook,Config_getString(DOCBOOK_OUTPUT),fileName,relPath,FALSE);
1567   }
1568
1569   if (gd->briefDescription()) 
1570   {
1571     //t << "    <section>" << endl;
1572     //t << "        <title>" << theTranslator->trBriefDescription() << "</title>" << endl;
1573     writeDocbookDocBlock(t,gd->briefFile(),gd->briefLine(),gd,0,gd->briefDescription());
1574     //t << "    </section>" << endl;
1575   }
1576
1577   if (gd->documentation()) 
1578   {
1579     t << "        <section>" << endl;
1580     t << "            <title>" << theTranslator->trDetailedDescription() << "</title>" << endl;
1581     writeDocbookDocBlock(t,gd->docFile(),gd->docLine(),gd,0,gd->documentation());
1582     t << "        </section>" << endl;
1583   }
1584
1585   writeInnerFiles(gd->getFiles(),t);
1586   writeInnerClasses(gd->getClasses(),t);
1587   writeInnerNamespaces(gd->getNamespaces(),t);
1588   writeInnerPages(gd->getPages(),t);
1589   writeInnerGroups(gd->getSubGroups(),t);
1590
1591   if (gd->getMemberGroupSDict())
1592   {
1593     MemberGroupSDict::Iterator mgli(*gd->getMemberGroupSDict());
1594     MemberGroup *mg;
1595     for (;(mg=mgli.current());++mgli)
1596     {
1597       generateDocbookSection(gd,t,mg->members(),"user-defined",0,mg->header(),
1598           mg->documentation());
1599     }
1600   }
1601
1602   QListIterator<MemberList> mli(gd->getMemberLists());
1603   MemberList *ml;
1604   for (mli.toFirst();(ml=mli.current());++mli)
1605   {
1606     if ((ml->listType()&MemberListType_declarationLists)!=0)
1607     {
1608       generateDocbookSection(gd,t,ml,g_docbookSectionMapper.find(ml->listType()));
1609     }
1610   }
1611   for (mli.toFirst();(ml=mli.current());++mli)
1612   {
1613     if ((ml->listType()&MemberListType_declarationLists)!=0)
1614     {
1615       generateDocbookSection(gd,t,ml,g_docbookSectionMapper.find(ml->listType()),1);
1616     }
1617   }
1618
1619   writeInnerGroupFiles(gd->getSubGroups(),t);
1620
1621   t << "</section>" << endl;
1622
1623 }
1624
1625 static void generateDocbookForDir(DirDef *dd,FTextStream &ti)
1626 {
1627   if (dd->isReference()) return; // skip external references
1628
1629   QCString fileDocbook=dd->getOutputFileBase()+".xml";
1630   //Add the file Documentation info to index file
1631   ti << "        <xi:include href=\"" << fileDocbook << "\" xmlns:xi=\"http://www.w3.org/2001/XInclude\"/>" << endl;
1632
1633   QCString outputDirectory = Config_getString(DOCBOOK_OUTPUT);
1634   QCString fileName=outputDirectory+"/"+dd->getOutputFileBase()+".xml";
1635   QFile f(fileName);
1636   QCString relPath = relativePathToRoot(fileName);
1637
1638   if (!f.open(IO_WriteOnly))
1639   {
1640     err("Cannot open file %s for writing!\n",fileName.data());
1641     return;
1642   }
1643
1644   FTextStream t(&f);
1645   //t.setEncoding(FTextStream::UnicodeUTF8);
1646   writeDocbookHeader_ID(t, dd->getOutputFileBase());
1647
1648   t << "    <title>";
1649   t << theTranslator->trDirReference(dd->displayName());
1650   t << "</title>" << endl;
1651   if (Config_getBool(DIRECTORY_GRAPH) && Config_getBool(HAVE_DOT))
1652   {
1653     t << "<para>Directory dependency diagram for " << convertToXML(dd->displayName()) << "</para>" << endl;
1654     DotDirDeps dirdepGraph(dd);
1655     dirdepGraph.writeGraph(t,GOF_BITMAP,EOF_DocBook,Config_getString(DOCBOOK_OUTPUT),fileName,relPath,FALSE);
1656   }
1657
1658   writeInnerDirs(&dd->subDirs(),t);
1659   writeInnerFiles(dd->getFiles(),t);
1660
1661   t << "    <simplesect>" << endl;
1662   t << "        <title>" << theTranslator->trDetailedDescription() << "</title>" << endl;
1663   writeDocbookDocBlock(t,dd->briefFile(),dd->briefLine(),dd,0,dd->briefDescription());
1664   writeDocbookDocBlock(t,dd->docFile(),dd->docLine(),dd,0,dd->documentation());
1665   t << "    <para>Directory location is " << dd->name() << "</para>" << endl;
1666   t << "    </simplesect>" << endl;
1667
1668   t << "</section>" << endl;
1669 }
1670
1671 static void generateDocbookForPage(PageDef *pd,FTextStream &ti,bool isExample)
1672 {
1673   // + name
1674   // + title
1675   // + documentation
1676
1677   if (pd->isReference()) return;
1678
1679   QCString pageName = pd->getOutputFileBase();
1680   if (pd->getGroupDef())
1681   {
1682     pageName+=(QCString)"_"+pd->name();
1683   }
1684   if (pageName=="index") 
1685   {
1686     pageName="mainpage"; // to prevent overwriting the generated index page.
1687   }
1688
1689   QCString outputDirectory = Config_getString(DOCBOOK_OUTPUT);
1690   QCString fileName=outputDirectory+"/"+pageName+".xml";
1691   QFile f(fileName);
1692   if (!f.open(IO_WriteOnly))
1693   {
1694     err("Cannot open file %s for writing!\n",fileName.data());
1695     return;
1696   }
1697
1698   FTextStream t(&f);
1699   //t.setEncoding(FTextStream::UnicodeUTF8);
1700
1701   if(isExample)
1702   {
1703     QCString fileDocbook=pageName+".xml";
1704     ti << "        <xi:include href=\"" << fileDocbook << "\" xmlns:xi=\"http://www.w3.org/2001/XInclude\"/>" << endl;
1705   }
1706
1707   if (!pd->hasParentPage() && !isExample)
1708   {
1709     QCString fileDocbook=pageName+".xml";
1710     //Add the file Documentation info to index file
1711     ti << "        <xi:include href=\"" << fileDocbook << "\" xmlns:xi=\"http://www.w3.org/2001/XInclude\"/>" << endl;
1712     writeDocbookHeaderMainpage(t);
1713   } 
1714   else 
1715   {
1716     QCString pid;
1717     if(isExample)
1718     {
1719       pid = pageName;
1720     }
1721     else
1722     {
1723       pid = pageName+"_1"+pageName;
1724     }
1725     writeDocbookHeader_ID(t, pid);
1726   }
1727
1728   SectionInfo *si = Doxygen::sectionDict->find(pd->name());
1729   if (si)
1730   {
1731     t << "    <title>" << convertToXML(si->title) << "</title>" << endl;
1732   } 
1733   else 
1734   {
1735     t << "    <title>" << convertToXML(pd->name()) << "</title>" << endl;
1736   }
1737
1738   if (isExample)
1739   {
1740     writeDocbookDocBlock(t,pd->docFile(),pd->docLine(),pd,0,
1741         pd->documentation()+"\n\\include "+pd->name());
1742   }
1743   else
1744   {
1745     writeDocbookDocBlock(t,pd->docFile(),pd->docLine(),pd,0,
1746         pd->documentation());
1747   }
1748   writeInnerPages(pd->getSubPages(),t);
1749
1750   if (!pd->hasParentPage() && !isExample)
1751   {
1752     t << endl << "</chapter>" << endl;
1753   } 
1754   else 
1755   {
1756     t << endl << "</section>" << endl;
1757   }
1758 }
1759
1760 void generateDocbook()
1761 {
1762
1763   // + classes
1764   // + namespaces
1765   // + files
1766   // + groups
1767   // + related pages
1768   // - examples
1769
1770   QCString outputDirectory = Config_getString(DOCBOOK_OUTPUT);
1771   if (outputDirectory.isEmpty())
1772   {
1773     outputDirectory=QDir::currentDirPath().utf8();
1774   }
1775   else
1776   {
1777     QDir dir(outputDirectory);
1778     if (!dir.exists())
1779     {
1780       dir.setPath(QDir::currentDirPath());
1781       if (!dir.mkdir(outputDirectory))
1782       {
1783         err("tag DOCBOOK_OUTPUT: Output directory `%s' does not "
1784             "exist and cannot be created\n",outputDirectory.data());
1785         exit(1);
1786       }
1787       else
1788       {
1789         msg("Notice: Output directory `%s' does not exist. "
1790             "I have created it for you.\n", outputDirectory.data());
1791       }
1792       dir.cd(outputDirectory);
1793     }
1794     outputDirectory=dir.absPath().utf8();
1795   }
1796
1797   QDir dir(outputDirectory);
1798   if (!dir.exists())
1799   {
1800     dir.setPath(QDir::currentDirPath());
1801     if (!dir.mkdir(outputDirectory))
1802     {
1803       err("Cannot create directory %s\n",outputDirectory.data());
1804       return;
1805     }
1806   }
1807   QDir docbookDir(outputDirectory);
1808   createSubDirs(docbookDir);
1809
1810   QCString fileName=outputDirectory+"/index.xml";
1811   QCString dbk_projectName = Config_getString(PROJECT_NAME);
1812   QFile f(fileName);
1813
1814   f.setName(fileName);
1815   if (!f.open(IO_WriteOnly))
1816   {
1817     err("Cannot open file %s for writing!\n",fileName.data());
1818     return;
1819   }
1820   FTextStream t(&f);
1821   //t.setEncoding(FTextStream::UnicodeUTF8);
1822
1823   // write index header for Docbook which calls the structure file
1824   t << "<?xml version='1.0' encoding='UTF-8' standalone='no'?>" << endl;;
1825   t << "<book xmlns=\"http://docbook.org/ns/docbook\" version=\"5.0\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">" << endl;
1826   t << "    <info>" << endl;
1827   t << "    <title>" << dbk_projectName << "</title>" << endl;
1828   t << "    </info>" << endl;
1829
1830   // NAMESPACE DOCUMENTATION
1831   NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
1832   NamespaceDef *nd;
1833
1834   //Namespace Documentation index header
1835   if (nli.toFirst()) 
1836   {
1837     t << "    <chapter>" << endl;
1838     t << "        <title>Namespace Documentation</title>" << endl;
1839   }
1840
1841   for (nli.toFirst();(nd=nli.current());++nli)
1842   {
1843     msg("Generating Docbook output for namespace %s\n",nd->name().data());
1844     generateDocbookForNamespace(nd,t);
1845   }
1846
1847   //Namespace Documentation index footer
1848   if (nli.toFirst()) 
1849   {
1850     t << "    </chapter>" << endl;
1851   }
1852
1853   /** MAINPAGE DOCUMENTATION **/
1854
1855   if (Doxygen::mainPage)
1856   {
1857     msg("Generating Docbook output for the main page\n");
1858     generateDocbookForPage(Doxygen::mainPage,t,FALSE);
1859   }
1860
1861   // PAGE DOCUMENTATION
1862   {
1863     PageSDict::Iterator pdi(*Doxygen::pageSDict);
1864     PageDef *pd=0;
1865
1866     for (pdi.toFirst();(pd=pdi.current());++pdi)
1867     {
1868       msg("Generating Docbook output for page %s\n",pd->name().data());
1869       generateDocbookForPage(pd,t,FALSE);
1870     }
1871   }
1872
1873   /** MODULE GROUP DOCUMENTATION **/
1874
1875   GroupSDict::Iterator gli(*Doxygen::groupSDict);
1876   GroupDef *gd;
1877
1878   //Module group Documentation index header
1879   if (gli.toFirst()) 
1880   {
1881     t << "    <chapter>" << endl;
1882     t << "        <title>" << theTranslator->trModuleDocumentation() << "</title>" << endl;
1883   }
1884
1885   for (;(gd=gli.current());++gli)
1886   {
1887     msg("Generating Docbook output for group %s\n",gd->name().data());
1888     generateDocbookForGroup(gd,t);
1889   }
1890
1891   //Module group Documentation index footer
1892   if (gli.toFirst()) 
1893   {
1894     t << "    </chapter>" << endl;
1895   }
1896
1897   //CLASS DOCUMENTATION
1898
1899   {
1900     ClassSDict::Iterator cli(*Doxygen::classSDict);
1901     ClassDef *cd;
1902
1903     //Class Documentation index header
1904     if (cli.toFirst()) 
1905     {
1906       t << "    <chapter>" << endl;
1907       t << "        <title>" << theTranslator->trClassDocumentation() << "</title>" << endl;
1908     }
1909
1910     for (cli.toFirst();(cd=cli.current());++cli)
1911     {
1912       generateDocbookForClass(cd,t);
1913     }
1914
1915     //Class Documentation index footer
1916     if (cli.toFirst()) 
1917     {
1918       t << "    </chapter>" << endl;
1919     }
1920   }
1921
1922   // FILE DOCUMENTATION
1923
1924   static bool showFiles = Config_getBool(SHOW_FILES);
1925   if (showFiles)
1926   {
1927     FileNameListIterator fnli(*Doxygen::inputNameList);
1928     FileName *fn;
1929
1930     //File Documentation index header
1931     if (fnli.toFirst()) 
1932     {
1933       t << "    <chapter>" << endl;
1934       t << "        <title>" << theTranslator->trFileDocumentation() << "</title>" << endl;
1935     }
1936
1937     for (;(fn=fnli.current());++fnli)
1938     {
1939       FileNameIterator fni(*fn);
1940       FileDef *fd;
1941       for (;(fd=fni.current());++fni)
1942       {
1943         msg("Generating Docbook output for file %s\n",fd->name().data());
1944         generateDocbookForFile(fd,t);
1945       }
1946     }
1947
1948     //File Documentation index footer
1949     if (fnli.toFirst()) 
1950     {
1951       t << "    </chapter>" << endl;
1952     }
1953   }
1954
1955   // DIRECTORY DOCUMENTATION
1956   if (Config_getBool(DIRECTORY_GRAPH) && Config_getBool(HAVE_DOT))
1957   {
1958     DirDef *dir;
1959     DirSDict::Iterator sdi(*Doxygen::directories);
1960
1961     //Directory Documentation index header
1962     if (sdi.toFirst()) 
1963     {
1964       t << "    <chapter>" << endl;
1965       t << "        <title>" << theTranslator->trDirDocumentation() << "</title>" << endl;
1966     }
1967
1968     for (sdi.toFirst();(dir=sdi.current());++sdi)
1969     {
1970       msg("Generate Docbook output for dir %s\n",dir->name().data());
1971       generateDocbookForDir(dir,t);
1972     }
1973
1974     //Module group Documentation index footer
1975     if (sdi.toFirst()) 
1976     {
1977       t << "    </chapter>" << endl;
1978     }
1979   }
1980
1981   // EXAMPLE PAGE DOCUMENTATION
1982
1983   {
1984     PageSDict::Iterator pdi(*Doxygen::exampleSDict);
1985     PageDef *pd=0;
1986
1987     //Example Page Documentation index header
1988     if (pdi.toFirst()) 
1989     {
1990       t << "    <chapter>" << endl;
1991       t << "        <title>" << theTranslator->trExampleDocumentation() << "</title>" << endl;
1992     }
1993
1994     for (pdi.toFirst();(pd=pdi.current());++pdi)
1995     {
1996       msg("Generating Docbook output for example %s\n",pd->name().data());
1997       generateDocbookForPage(pd,t,TRUE);
1998     }
1999
2000     //Example Page Documentation index footer
2001     if (pdi.toFirst()) 
2002     {
2003       t << "    </chapter>" << endl;
2004     }
2005   }
2006
2007   t << "</book>" << endl;
2008
2009 }
2010
2011