Imported Upstream version 1.8.15
[platform/upstream/doxygen.git] / src / mandocvisitor.cpp
1 /******************************************************************************
2  *
3  * 
4  *
5  *
6  * Copyright (C) 1997-2015 by Dimitri van Heesch.
7  *
8  * Permission to use, copy, modify, and distribute this software and its
9  * documentation under the terms of the GNU General Public License is hereby 
10  * granted. No representations are made about the suitability of this software 
11  * for any purpose. It is provided "as is" without express or implied warranty.
12  * See the GNU General Public License for more details.
13  *
14  * Documents produced by Doxygen are derivative works derived from the
15  * input used in their production; they are not affected by this license.
16  *
17  */
18
19 #include <qfileinfo.h> 
20
21 #include "mandocvisitor.h"
22 #include "docparser.h"
23 #include "language.h"
24 #include "doxygen.h"
25 #include "outputgen.h"
26 #include "code.h"
27 #include "dot.h"
28 #include "util.h"
29 #include "message.h"
30 #include "parserintf.h"
31 #include "filedef.h"
32 #include "htmlentity.h"
33 #include "emoji.h"
34
35 ManDocVisitor::ManDocVisitor(FTextStream &t,CodeOutputInterface &ci,
36                              const char *langExt) 
37   : DocVisitor(DocVisitor_Man), m_t(t), m_ci(ci), m_insidePre(FALSE), m_hide(FALSE), m_firstCol(FALSE),
38     m_indent(0), m_langExt(langExt)
39 {
40 }
41
42   //--------------------------------------
43   // visitor functions for leaf nodes
44   //--------------------------------------
45
46 void ManDocVisitor::visit(DocWord *w)
47 {
48   if (m_hide) return;
49   filter(w->word());
50   m_firstCol=FALSE;
51 }
52
53 void ManDocVisitor::visit(DocLinkedWord *w)
54 {
55   if (m_hide) return;
56   m_t << "\\fB";
57   filter(w->word());
58   m_t << "\\fP";
59   m_firstCol=FALSE;
60 }
61
62 void ManDocVisitor::visit(DocWhiteSpace *w)
63 {
64   if (m_hide) return;
65   if (m_insidePre)
66   {
67     m_t << w->chars();
68     m_firstCol=w->chars().at(w->chars().length()-1)=='\n';
69   }
70   else
71   {
72     m_t << " ";
73     m_firstCol=FALSE;
74   }
75 }
76
77 void ManDocVisitor::visit(DocSymbol *s)
78 {
79   if (m_hide) return;
80   const char *res = HtmlEntityMapper::instance()->man(s->symbol());
81   if (res)
82   {
83     m_t << res;
84   }
85   else
86   {
87     // no error or warning to be supplied
88     // err("man: non supported HTML-entity found: &%s;\n",get_symbol_item(s->symbol()));
89   }
90   m_firstCol=FALSE;
91 }
92
93 void ManDocVisitor::visit(DocEmoji *s)
94 {
95   if (m_hide) return;
96   const char *res = EmojiEntityMapper::instance()->name(s->index());
97   if (res)
98   {
99     m_t << res;
100   }
101   else
102   {
103     m_t << s->name();
104   }
105   m_firstCol=FALSE;
106 }
107
108 void ManDocVisitor::visit(DocURL *u)
109 {
110   if (m_hide) return;
111   m_t << u->url();
112   m_firstCol=FALSE;
113 }
114
115 void ManDocVisitor::visit(DocLineBreak *)
116 {
117   if (m_hide) return;
118   m_t << endl << ".br" << endl;
119   m_firstCol=TRUE;
120 }
121
122 void ManDocVisitor::visit(DocHorRuler *)
123 {
124   if (m_hide) return;
125   if (!m_firstCol) m_t << endl;
126   m_t << ".PP" << endl;
127   m_firstCol=TRUE;
128 }
129
130 void ManDocVisitor::visit(DocStyleChange *s)
131 {
132   if (m_hide) return;
133   switch (s->style())
134   {
135     case DocStyleChange::Bold:
136       if (s->enable()) m_t << "\\fB";      else m_t << "\\fP";
137       m_firstCol=FALSE;
138       break;
139     case DocStyleChange::Strike:
140       /* not supported */
141       break;
142     case DocStyleChange::Underline: //underline is shown as emphasis
143       if (s->enable()) m_t << "\\fI";     else m_t << "\\fP";
144       m_firstCol=FALSE;
145       break;
146     case DocStyleChange::Italic:
147       if (s->enable()) m_t << "\\fI";     else m_t << "\\fP";
148       m_firstCol=FALSE;
149       break;
150     case DocStyleChange::Code:
151       if (s->enable()) m_t << "\\fC";   else m_t << "\\fP";
152       m_firstCol=FALSE;
153       break;
154     case DocStyleChange::Subscript:
155       if (s->enable()) m_t << "\\*<";    else m_t << "\\*> ";
156       m_firstCol=FALSE;
157       break;
158     case DocStyleChange::Superscript:
159       if (s->enable()) m_t << "\\*{";    else m_t << "\\*} ";
160       m_firstCol=FALSE;
161       break;
162     case DocStyleChange::Center:
163       /* not supported */
164       break;
165     case DocStyleChange::Small:
166       /* not supported */
167       break;
168     case DocStyleChange::Preformatted:
169       if (s->enable())
170       {
171         if (!m_firstCol) m_t << endl;
172         m_t << ".PP" << endl;
173         m_t << ".nf" << endl;
174         m_insidePre=TRUE;
175       }
176       else
177       {
178         m_insidePre=FALSE;
179         if (!m_firstCol) m_t << endl;
180         m_t << ".fi" << endl;
181         m_t << ".PP" << endl;
182         m_firstCol=TRUE;
183       }
184       break;
185     case DocStyleChange::Div:  /* HTML only */ break;
186     case DocStyleChange::Span: /* HTML only */ break;
187   }
188 }
189
190 void ManDocVisitor::visit(DocVerbatim *s)
191 {
192   if (m_hide) return;
193   QCString lang = m_langExt;
194   if (!s->language().isEmpty()) // explicit language setting
195   {
196     lang = s->language();
197   }
198   SrcLangExt langExt = getLanguageFromFileName(lang);
199   switch (s->type())
200   {
201     case DocVerbatim::Code: // fall though
202       if (!m_firstCol) m_t << endl;
203       m_t << ".PP" << endl;
204       m_t << ".nf" << endl;
205       Doxygen::parserManager->getParser(lang)
206                             ->parseCode(m_ci,s->context(),s->text(),
207                                         langExt,
208                                         s->isExample(),s->exampleFile());
209       if (!m_firstCol) m_t << endl;
210       m_t << ".fi" << endl;
211       m_t << ".PP" << endl;
212       m_firstCol=TRUE;
213       break;
214     case DocVerbatim::Verbatim: 
215       if (!m_firstCol) m_t << endl;
216       m_t << ".PP" << endl;
217       m_t << ".nf" << endl;
218       m_t << s->text();
219       if (!m_firstCol) m_t << endl;
220       m_t << ".fi" << endl;
221       m_t << ".PP" << endl;
222       m_firstCol=TRUE;
223       break;
224     case DocVerbatim::ManOnly: 
225       m_t << s->text(); 
226       break;
227     case DocVerbatim::HtmlOnly: 
228     case DocVerbatim::XmlOnly: 
229     case DocVerbatim::LatexOnly: 
230     case DocVerbatim::RtfOnly:
231     case DocVerbatim::DocbookOnly:
232     case DocVerbatim::Dot: 
233     case DocVerbatim::Msc: 
234     case DocVerbatim::PlantUML: 
235       /* nothing */ 
236       break;
237   }
238 }
239
240 void ManDocVisitor::visit(DocAnchor *)
241 {
242   /* no support for anchors in man pages */
243 }
244
245 void ManDocVisitor::visit(DocInclude *inc)
246 {
247   if (m_hide) return;
248   SrcLangExt langExt = getLanguageFromFileName(inc->extension());
249   switch(inc->type())
250   {
251     case DocInclude::IncWithLines:
252       { 
253          if (!m_firstCol) m_t << endl;
254          m_t << ".PP" << endl;
255          m_t << ".nf" << endl;
256          QFileInfo cfi( inc->file() );
257          FileDef fd( cfi.dirPath().utf8(), cfi.fileName().utf8() );
258          Doxygen::parserManager->getParser(inc->extension())
259                                ->parseCode(m_ci,inc->context(),
260                                            inc->text(),
261                                            langExt,
262                                            inc->isExample(),
263                                            inc->exampleFile(),
264                                            &fd,   // fileDef,
265                                            -1,    // start line
266                                            -1,    // end line
267                                            FALSE, // inline fragment
268                                            0,     // memberDef
269                                            TRUE
270                                            );
271          if (!m_firstCol) m_t << endl;
272          m_t << ".fi" << endl;
273          m_t << ".PP" << endl;
274          m_firstCol=TRUE;
275       }
276       break;
277     case DocInclude::Include: 
278       if (!m_firstCol) m_t << endl;
279       m_t << ".PP" << endl;
280       m_t << ".nf" << endl;
281       Doxygen::parserManager->getParser(inc->extension())
282                             ->parseCode(m_ci,inc->context(),
283                                         inc->text(),
284                                         langExt,
285                                         inc->isExample(),
286                                         inc->exampleFile(),
287                                         0,     // fileDef
288                                         -1,    // startLine
289                                         -1,    // endLine
290                                         TRUE,  // inlineFragment
291                                         0,     // memberDef
292                                         FALSE
293                                        );
294       if (!m_firstCol) m_t << endl;
295       m_t << ".fi" << endl;
296       m_t << ".PP" << endl;
297       m_firstCol=TRUE;
298       break;
299     case DocInclude::DontInclude: 
300       break;
301     case DocInclude::HtmlInclude: 
302       break;
303     case DocInclude::LatexInclude:
304       break;
305     case DocInclude::VerbInclude: 
306       if (!m_firstCol) m_t << endl;
307       m_t << ".PP" << endl;
308       m_t << ".nf" << endl;
309       m_t << inc->text();
310       if (!m_firstCol) m_t << endl;
311       m_t << ".fi" << endl;
312       m_t << ".PP" << endl;
313       m_firstCol=TRUE;
314       break;
315     case DocInclude::Snippet:
316       if (!m_firstCol) m_t << endl;
317       m_t << ".PP" << endl;
318       m_t << ".nf" << endl;
319       Doxygen::parserManager->getParser(inc->extension())
320                             ->parseCode(m_ci,
321                                         inc->context(),
322                                         extractBlock(inc->text(),inc->blockId()),
323                                         langExt,
324                                         inc->isExample(),
325                                         inc->exampleFile()
326                                        );
327       if (!m_firstCol) m_t << endl;
328       m_t << ".fi" << endl;
329       m_t << ".PP" << endl;
330       m_firstCol=TRUE;
331       break;
332     case DocInclude::SnipWithLines:
333       {
334          if (!m_firstCol) m_t << endl;
335          m_t << ".PP" << endl;
336          m_t << ".nf" << endl;
337          QFileInfo cfi( inc->file() );
338          FileDef fd( cfi.dirPath().utf8(), cfi.fileName().utf8() );
339          Doxygen::parserManager->getParser(inc->extension())
340                                ->parseCode(m_ci,
341                                            inc->context(),
342                                            extractBlock(inc->text(),inc->blockId()),
343                                            langExt,
344                                            inc->isExample(),
345                                            inc->exampleFile(), 
346                                            &fd,
347                                            lineBlock(inc->text(),inc->blockId()),
348                                            -1,    // endLine
349                                            FALSE, // inlineFragment
350                                            0,     // memberDef
351                                            TRUE   // show line number
352                                           );
353          if (!m_firstCol) m_t << endl;
354          m_t << ".fi" << endl;
355          m_t << ".PP" << endl;
356          m_firstCol=TRUE;
357       }
358       break;
359     case DocInclude::SnippetDoc: 
360     case DocInclude::IncludeDoc: 
361       err("Internal inconsistency: found switch SnippetDoc / IncludeDoc in file: %s"
362           "Please create a bug report\n",__FILE__);
363       break;
364   }
365 }
366
367 void ManDocVisitor::visit(DocIncOperator *op)
368 {
369   SrcLangExt langExt = getLanguageFromFileName(m_langExt);
370   //printf("DocIncOperator: type=%d first=%d, last=%d text=`%s'\n",
371   //    op->type(),op->isFirst(),op->isLast(),op->text().data());
372   if (op->isFirst()) 
373   {
374     if (!m_hide)
375     {
376       if (!m_firstCol) m_t << endl;
377       m_t << ".PP" << endl;
378       m_t << ".nf" << endl;
379     }
380     pushEnabled();
381     m_hide = TRUE;
382   }
383   if (op->type()!=DocIncOperator::Skip) 
384   {
385     popEnabled();
386     if (!m_hide) 
387     {
388       Doxygen::parserManager->getParser(m_langExt)
389                             ->parseCode(m_ci,op->context(),op->text(),langExt,
390                                         op->isExample(),op->exampleFile());
391     }
392     pushEnabled();
393     m_hide=TRUE;
394   }
395   if (op->isLast())  
396   {
397     popEnabled();
398     if (!m_hide)
399     {
400       if (!m_firstCol) m_t << endl;
401       m_t << ".fi" << endl;
402       m_t << ".PP" << endl;
403       m_firstCol=TRUE;
404     }
405   }
406   else
407   {
408     if (!m_hide) m_t << endl;
409   }
410 }
411
412 void ManDocVisitor::visit(DocFormula *f)
413 {
414   if (m_hide) return;
415   m_t << f->text();
416 }
417
418 void ManDocVisitor::visit(DocIndexEntry *)
419 {
420 }
421
422 void ManDocVisitor::visit(DocSimpleSectSep *)
423 {
424 }
425
426 void ManDocVisitor::visit(DocCite *cite)
427 {
428   if (m_hide) return;
429   m_t << "\\fB";
430   if (cite->file().isEmpty()) m_t << "[";
431   filter(cite->text());
432   if (cite->file().isEmpty()) m_t << "]";
433   m_t << "\\fP";
434 }
435
436
437 //--------------------------------------
438 // visitor functions for compound nodes
439 //--------------------------------------
440
441 void ManDocVisitor::visitPre(DocAutoList *)
442 {
443   if (m_hide) return;
444   m_indent+=2;
445 }
446
447 void ManDocVisitor::visitPost(DocAutoList *)
448 {
449   if (m_hide) return;
450   m_indent-=2;
451   m_t << ".PP" << endl;
452 }
453
454 void ManDocVisitor::visitPre(DocAutoListItem *li)
455 {
456   if (m_hide) return;
457   QCString ws;
458   ws.fill(' ',m_indent-2);
459   if (!m_firstCol) m_t << endl;
460   m_t << ".IP \"" << ws; 
461   if (((DocAutoList *)li->parent())->isEnumList())
462   {
463     m_t << li->itemNumber() << ".\" " << m_indent+2;
464   }
465   else // bullet list
466   {
467     m_t << "\\(bu\" " << m_indent;
468   }
469   m_t << endl;
470   m_firstCol=TRUE;
471 }
472
473 void ManDocVisitor::visitPost(DocAutoListItem *) 
474 {
475   if (m_hide) return;
476   m_t << endl;
477   m_firstCol=TRUE;
478 }
479
480 void ManDocVisitor::visitPre(DocPara *) 
481 {
482 }
483
484 void ManDocVisitor::visitPost(DocPara *p)
485 {
486   if (m_hide) return;
487   if (!p->isLast() &&            // omit <p> for last paragraph
488       !(p->parent() &&           // and for parameter sections
489         p->parent()->kind()==DocNode::Kind_ParamSect
490        )
491      ) 
492   {
493     if (!m_firstCol) m_t << endl;
494     m_t << ".PP" << endl;
495     m_firstCol=TRUE;
496   }
497 }
498
499 void ManDocVisitor::visitPre(DocRoot *)
500 {
501 }
502
503 void ManDocVisitor::visitPost(DocRoot *)
504 {
505 }
506
507 void ManDocVisitor::visitPre(DocSimpleSect *s)
508 {
509   if (m_hide) return;
510   if (!m_firstCol)
511   { 
512     m_t << endl;
513     m_t << ".PP" << endl;
514   }
515   m_t << "\\fB";
516   switch(s->type())
517   {
518     case DocSimpleSect::See: 
519       m_t << theTranslator->trSeeAlso(); break;
520     case DocSimpleSect::Return: 
521       m_t << theTranslator->trReturns(); break;
522     case DocSimpleSect::Author: 
523       m_t << theTranslator->trAuthor(TRUE,TRUE); break;
524     case DocSimpleSect::Authors: 
525       m_t << theTranslator->trAuthor(TRUE,FALSE); break;
526     case DocSimpleSect::Version: 
527       m_t << theTranslator->trVersion(); break;
528     case DocSimpleSect::Since: 
529       m_t << theTranslator->trSince(); break;
530     case DocSimpleSect::Date: 
531       m_t << theTranslator->trDate(); break;
532     case DocSimpleSect::Note: 
533       m_t << theTranslator->trNote(); break;
534     case DocSimpleSect::Warning:
535       m_t << theTranslator->trWarning(); break;
536     case DocSimpleSect::Pre:
537       m_t << theTranslator->trPrecondition(); break;
538     case DocSimpleSect::Post:
539       m_t << theTranslator->trPostcondition(); break;
540     case DocSimpleSect::Copyright:
541       m_t << theTranslator->trCopyright(); break;
542     case DocSimpleSect::Invar:
543       m_t << theTranslator->trInvariant(); break;
544     case DocSimpleSect::Remark:
545       m_t << theTranslator->trRemarks(); break;
546     case DocSimpleSect::Attention:
547       m_t << theTranslator->trAttention(); break;
548     case DocSimpleSect::User: break;
549     case DocSimpleSect::Rcs: break;
550     case DocSimpleSect::Unknown:  break;
551   }
552
553   // special case 1: user defined title
554   if (s->type()!=DocSimpleSect::User && s->type()!=DocSimpleSect::Rcs)
555   {
556     m_t << ":\\fP" << endl;
557     m_t << ".RS 4" << endl;
558   }
559 }
560
561 void ManDocVisitor::visitPost(DocSimpleSect *)
562 {
563   if (m_hide) return;
564   if (!m_firstCol) m_t << endl;
565   m_t << ".RE" << endl;
566   m_t << ".PP" << endl;
567   m_firstCol=TRUE;
568 }
569
570 void ManDocVisitor::visitPre(DocTitle *)
571 {
572 }
573
574 void ManDocVisitor::visitPost(DocTitle *)
575 {
576   if (m_hide) return;
577   m_t << "\\fP" << endl;
578   m_t << ".RS 4" << endl;
579 }
580
581 void ManDocVisitor::visitPre(DocSimpleList *)
582 {
583   if (m_hide) return;
584   m_indent+=2;
585   if (!m_firstCol) m_t << endl;
586   m_t << ".PD 0" << endl;
587 }
588
589 void ManDocVisitor::visitPost(DocSimpleList *)
590 {
591   if (m_hide) return;
592   m_indent-=2;
593   m_t << ".PP" << endl;
594 }
595
596 void ManDocVisitor::visitPre(DocSimpleListItem *)
597 {
598   if (m_hide) return;
599   QCString ws;
600   ws.fill(' ',m_indent-2);
601   if (!m_firstCol) m_t << endl;
602   m_t << ".IP \"" << ws << "\\(bu\" " << m_indent << endl;
603   m_firstCol=TRUE;
604 }
605
606 void ManDocVisitor::visitPost(DocSimpleListItem *) 
607 {
608   if (m_hide) return;
609   m_t << endl;
610   m_firstCol=TRUE;
611 }
612
613 void ManDocVisitor::visitPre(DocSection *s)
614 {
615   if (m_hide) return;
616   if (!m_firstCol) m_t << endl;
617   if (s->level()==1) m_t << ".SH"; else m_t << ".SS";
618   m_t << " \"";
619   filter(s->title());
620   m_t << "\"" << endl;
621   if (s->level()==1) m_t << ".PP" << endl;
622   m_firstCol=TRUE;
623 }
624
625 void ManDocVisitor::visitPost(DocSection *) 
626 {
627 }
628
629 void ManDocVisitor::visitPre(DocHtmlList *)
630 {
631   if (m_hide) return;
632   m_indent+=2;
633   if (!m_firstCol) m_t << endl;
634   m_t << ".PD 0" << endl;
635 }
636
637 void ManDocVisitor::visitPost(DocHtmlList *) 
638 {
639   if (m_hide) return;
640   m_indent-=2;
641   if (!m_firstCol) m_t << endl;
642   m_t << ".PP" << endl;
643 }
644
645 void ManDocVisitor::visitPre(DocHtmlListItem *li)
646 {
647   if (m_hide) return;
648   QCString ws;
649   ws.fill(' ',m_indent-2);
650   if (!m_firstCol) m_t << endl;
651   m_t << ".IP \"" << ws; 
652   if (((DocHtmlList *)li->parent())->type()==DocHtmlList::Ordered)
653   {
654     m_t << li->itemNumber() << ".\" " << m_indent+2;
655   }
656   else // bullet list
657   {
658     m_t << "\\(bu\" " << m_indent;
659   }
660   m_t << endl;
661   m_firstCol=TRUE;
662 }
663
664 void ManDocVisitor::visitPost(DocHtmlListItem *) 
665 {
666   if (m_hide) return;
667   m_t << endl;
668   m_firstCol=TRUE;
669 }
670
671 //void ManDocVisitor::visitPre(DocHtmlPre *)
672 //{
673 //  if (!m_firstCol) m_t << endl;
674 //  m_t << ".PP" << endl;
675 //  m_t << ".nf" << endl;
676 //  m_insidePre=TRUE;
677 //}
678 //
679 //void ManDocVisitor::visitPost(DocHtmlPre *) 
680 //{
681 //  m_insidePre=FALSE;
682 //  if (!m_firstCol) m_t << endl;
683 //  m_t << ".fi" << endl;
684 //  m_t << ".PP" << endl;
685 //  m_firstCol=TRUE;
686 //}
687
688 void ManDocVisitor::visitPre(DocHtmlDescList *)
689 {
690 }
691
692 void ManDocVisitor::visitPost(DocHtmlDescList *) 
693 {
694   if (m_hide) return;
695   if (!m_firstCol) m_t << endl;
696   m_t << ".PP" << endl;
697   m_firstCol=TRUE;
698 }
699
700 void ManDocVisitor::visitPre(DocHtmlDescTitle *)
701 {
702   if (m_hide) return;
703   if (!m_firstCol) m_t << endl;
704   m_t << ".IP \"\\fB";
705   m_firstCol=FALSE;
706 }
707
708 void ManDocVisitor::visitPost(DocHtmlDescTitle *) 
709 {
710   if (m_hide) return;
711   m_t << "\\fP\" 1c" << endl;
712   m_firstCol=TRUE;
713 }
714
715 void ManDocVisitor::visitPre(DocHtmlDescData *)
716 {
717 }
718
719 void ManDocVisitor::visitPost(DocHtmlDescData *) 
720 {
721 }
722
723 void ManDocVisitor::visitPre(DocHtmlTable *)
724 {
725 }
726
727 void ManDocVisitor::visitPost(DocHtmlTable *) 
728 {
729 }
730
731 void ManDocVisitor::visitPre(DocHtmlCaption *)
732 {
733 }
734
735 void ManDocVisitor::visitPost(DocHtmlCaption *) 
736 {
737 }
738
739 void ManDocVisitor::visitPre(DocHtmlRow *)
740 {
741 }
742
743 void ManDocVisitor::visitPost(DocHtmlRow *) 
744 {
745 }
746
747 void ManDocVisitor::visitPre(DocHtmlCell *)
748 {
749 }
750
751 void ManDocVisitor::visitPost(DocHtmlCell *) 
752 {
753 }
754
755 void ManDocVisitor::visitPre(DocInternal *)
756 {
757   if (m_hide) return;
758   //if (!m_firstCol) m_t << endl;
759   //m_t << ".PP" << endl;
760   //m_t << "\\fB" << theTranslator->trForInternalUseOnly() << "\\fP" << endl;
761   //m_t << ".RS 4" << endl;
762 }
763
764 void ManDocVisitor::visitPost(DocInternal *) 
765 {
766   if (m_hide) return;
767   //if (!m_firstCol) m_t << endl;
768   //m_t << ".RE" << endl;
769   //m_t << ".PP" << endl;
770   //m_firstCol=TRUE;
771 }
772
773 void ManDocVisitor::visitPre(DocHRef *)
774 {
775   if (m_hide) return;
776   m_t << "\\fC";
777 }
778
779 void ManDocVisitor::visitPost(DocHRef *) 
780 {
781   if (m_hide) return;
782   m_t << "\\fP";
783 }
784
785 void ManDocVisitor::visitPre(DocHtmlHeader *header)
786 {
787   if (m_hide) return;
788   if (!m_firstCol) m_t << endl;
789   if (header->level()==1) m_t << ".SH"; else m_t << ".SS";
790   m_t << " \"";
791 }
792
793 void ManDocVisitor::visitPost(DocHtmlHeader *header) 
794 {
795   if (m_hide) return;
796   m_t << "\"" << endl;
797   if (header->level()==1) m_t << ".PP" << endl;
798   m_firstCol=TRUE;
799 }
800
801 void ManDocVisitor::visitPre(DocImage *)
802 {
803 }
804
805 void ManDocVisitor::visitPost(DocImage *) 
806 {
807 }
808
809 void ManDocVisitor::visitPre(DocDotFile *)
810 {
811 }
812
813 void ManDocVisitor::visitPost(DocDotFile *) 
814 {
815 }
816 void ManDocVisitor::visitPre(DocMscFile *)
817 {
818 }
819
820 void ManDocVisitor::visitPost(DocMscFile *) 
821 {
822 }
823
824 void ManDocVisitor::visitPre(DocDiaFile *)
825 {
826 }
827
828 void ManDocVisitor::visitPost(DocDiaFile *)
829 {
830 }
831
832 void ManDocVisitor::visitPre(DocLink *)
833 {
834   if (m_hide) return;
835   m_t << "\\fB";
836 }
837
838 void ManDocVisitor::visitPost(DocLink *) 
839 {
840   if (m_hide) return;
841   m_t << "\\fP";
842 }
843
844 void ManDocVisitor::visitPre(DocRef *ref)
845 {
846   if (m_hide) return;
847   m_t << "\\fB";
848   if (!ref->hasLinkText()) filter(ref->targetTitle());
849 }
850
851 void ManDocVisitor::visitPost(DocRef *) 
852 {
853   if (m_hide) return;
854   m_t << "\\fP";
855 }
856
857 void ManDocVisitor::visitPre(DocSecRefItem *)
858 {
859   if (m_hide) return;
860   QCString ws;
861   ws.fill(' ',m_indent-2);
862   if (!m_firstCol) m_t << endl;
863   m_t << ".IP \"" << ws << "\\(bu\" " << m_indent << endl;
864   m_firstCol=TRUE;
865 }
866
867 void ManDocVisitor::visitPost(DocSecRefItem *) 
868 {
869   if (m_hide) return;
870   m_t << endl;
871   m_firstCol=TRUE;
872 }
873
874 void ManDocVisitor::visitPre(DocSecRefList *)
875 {
876   if (m_hide) return;
877   m_indent+=2;
878 }
879
880 void ManDocVisitor::visitPost(DocSecRefList *) 
881 {
882   if (m_hide) return;
883   m_indent-=2;
884   if (!m_firstCol) m_t << endl;
885   m_t << ".PP" << endl;
886 }
887
888 //void ManDocVisitor::visitPre(DocLanguage *l)
889 //{
890 //  QString langId = Config_getEnum(OUTPUT_LANGUAGE);
891 //  if (l->id().lower()!=langId.lower())
892 //  {
893 //    pushEnabled();
894 //    m_hide = TRUE;
895 //  }
896 //}
897 //
898 //void ManDocVisitor::visitPost(DocLanguage *l) 
899 //{
900 //  QString langId = Config_getEnum(OUTPUT_LANGUAGE);
901 //  if (l->id().lower()!=langId.lower())
902 //  {
903 //    popEnabled();
904 //  }
905 //}
906
907 void ManDocVisitor::visitPre(DocParamSect *s)
908 {
909   if (m_hide) return;
910   if (!m_firstCol)
911   { 
912     m_t << endl;
913     m_t << ".PP" << endl;
914   }
915   m_t << "\\fB";
916   switch(s->type())
917   {
918     case DocParamSect::Param: 
919       m_t << theTranslator->trParameters(); break;
920     case DocParamSect::RetVal: 
921       m_t << theTranslator->trReturnValues(); break;
922     case DocParamSect::Exception: 
923       m_t << theTranslator->trExceptions(); break;
924     case DocParamSect::TemplateParam: 
925       m_t << theTranslator->trTemplateParameters(); break;
926     default:
927       ASSERT(0);
928   }
929   m_t << ":\\fP" << endl;
930   m_t << ".RS 4" << endl;
931 }
932
933 void ManDocVisitor::visitPost(DocParamSect *)
934 {
935   if (m_hide) return;
936   if (!m_firstCol) m_t << endl;
937   m_t << ".RE" << endl;
938   m_t << ".PP" << endl;
939   m_firstCol=TRUE;
940 }
941
942 void ManDocVisitor::visitPre(DocParamList *pl)
943 {
944   if (m_hide) return;
945   m_t << "\\fI";
946   //QStrListIterator li(pl->parameters());
947   //const char *s;
948   QListIterator<DocNode> li(pl->parameters());
949   DocNode *param;
950   bool first=TRUE;
951   for (li.toFirst();(param=li.current());++li)
952   {
953     if (!first) m_t << ","; else first=FALSE;
954     if (param->kind()==DocNode::Kind_Word)
955     {
956       visit((DocWord*)param); 
957     }
958     else if (param->kind()==DocNode::Kind_LinkedWord)
959     {
960       visit((DocLinkedWord*)param); 
961     }
962   }
963   m_t << "\\fP ";
964 }
965
966 void ManDocVisitor::visitPost(DocParamList *pl)
967 {
968   if (m_hide) return;
969   if (!pl->isLast())
970   {
971     if (!m_firstCol) m_t << endl;
972     m_t << ".br" << endl;
973   }
974 }
975
976 void ManDocVisitor::visitPre(DocXRefItem *x)
977 {
978   if (m_hide) return;
979   if (x->title().isEmpty()) return;
980   if (!m_firstCol)
981   { 
982     m_t << endl;
983     m_t << ".PP" << endl;
984   }
985   m_t << "\\fB";
986   filter(x->title());
987   m_t << "\\fP" << endl;
988   m_t << ".RS 4" << endl;
989 }
990
991 void ManDocVisitor::visitPost(DocXRefItem *x)
992 {
993   if (m_hide) return;
994   if (x->title().isEmpty()) return;
995   if (!m_firstCol) m_t << endl;
996   m_t << ".RE" << endl;
997   m_t << ".PP" << endl;
998   m_firstCol=TRUE;
999 }
1000
1001 void ManDocVisitor::visitPre(DocInternalRef *)
1002 {
1003   if (m_hide) return;
1004   m_t << "\\fB";
1005 }
1006
1007 void ManDocVisitor::visitPost(DocInternalRef *) 
1008 {
1009   if (m_hide) return;
1010   m_t << "\\fP";
1011 }
1012
1013 void ManDocVisitor::visitPre(DocCopy *)
1014 {
1015 }
1016
1017 void ManDocVisitor::visitPost(DocCopy *)
1018 {
1019 }
1020
1021 void ManDocVisitor::visitPre(DocText *)
1022 {
1023 }
1024
1025 void ManDocVisitor::visitPost(DocText *)
1026 {
1027 }
1028
1029 void ManDocVisitor::visitPre(DocHtmlBlockQuote *)
1030 {
1031   if (m_hide) return;
1032   if (!m_firstCol)
1033   { 
1034     m_t << endl;
1035     m_t << ".PP" << endl;
1036   }
1037   m_t << ".RS 4" << endl; // TODO: add support for nested block quotes
1038 }
1039
1040 void ManDocVisitor::visitPost(DocHtmlBlockQuote *)
1041 {
1042   if (m_hide) return;
1043   if (!m_firstCol) m_t << endl;
1044   m_t << ".RE" << endl;
1045   m_t << ".PP" << endl;
1046   m_firstCol=TRUE;
1047 }
1048
1049 void ManDocVisitor::visitPre(DocVhdlFlow *)
1050 {
1051 }
1052
1053 void ManDocVisitor::visitPost(DocVhdlFlow *)
1054 {
1055 }
1056
1057 void ManDocVisitor::visitPre(DocParBlock *)
1058 {
1059 }
1060
1061 void ManDocVisitor::visitPost(DocParBlock *)
1062 {
1063 }
1064
1065
1066 void ManDocVisitor::filter(const char *str)
1067
1068   if (str)
1069   {
1070     const char *p=str;
1071     char c=0;
1072     while ((c=*p++)) 
1073     {
1074       switch(c)
1075       {
1076         case '.':  m_t << "\\&."; break; // see  bug652277
1077         case '\\': m_t << "\\\\"; break;
1078         case '"':  c = '\''; // fall through
1079         default: m_t << c; break;
1080       }
1081     }
1082   }
1083 }
1084
1085 void ManDocVisitor::pushEnabled()
1086 {
1087   m_enabled.push(new bool(m_hide));
1088 }
1089
1090 void ManDocVisitor::popEnabled()
1091 {
1092   bool *v=m_enabled.pop();
1093   ASSERT(v!=0);
1094   m_hide = *v;
1095   delete v;
1096 }
1097