Imported Upstream version 1.9.8
[platform/upstream/doxygen.git] / src / mangen.cpp
1 /******************************************************************************
2  *
3  * Copyright (C) 1997-2022 by Dimitri van Heesch.
4  *
5  * Permission to use, copy, modify, and distribute this software and its
6  * documentation under the terms of the GNU General Public License is hereby
7  * granted. No representations are made about the suitability of this software
8  * for any purpose. It is provided "as is" without express or implied warranty.
9  * See the GNU General Public License for more details.
10  *
11  * Documents produced by Doxygen are derivative works derived from the
12  * input used in their production; they are not affected by this license.
13  *
14  */
15
16 /* http://www.cubic.org/source/archive/fileform/txt/man/ has some
17    nice introductions to groff and man pages. */
18
19 #include <stdlib.h>
20 #include <string.h>
21
22 #include "message.h"
23 #include "mangen.h"
24 #include "config.h"
25 #include "util.h"
26 #include "doxygen.h"
27 #include "docparser.h"
28 #include "mandocvisitor.h"
29 #include "language.h"
30 #include "dir.h"
31 #include "utf8.h"
32 #include "datetime.h"
33 #include "portable.h"
34 #include "outputlist.h"
35
36 static QCString getExtension()
37 {
38   /*
39    * [.][number][rest]
40    * in case of . missing, just ignore it
41    * in case number missing, just place a 3 in front of it
42    */
43   QCString ext = Config_getString(MAN_EXTENSION);
44   if (ext.isEmpty())
45   {
46     ext = "3";
47   }
48   else
49   {
50     if (ext.at(0)=='.')
51     {
52       if (ext.length()==1)
53       {
54         ext = "3";
55       }
56       else // strip .
57       {
58         ext = ext.mid(1);
59       }
60     }
61     if (ext.at(0)<'0' || ext.at(0)>'9')
62     {
63       ext.prepend("3");
64     }
65   }
66   return ext;
67 }
68
69 static QCString getSubdir()
70 {
71   QCString dir = Config_getString(MAN_SUBDIR);
72   if (dir.isEmpty())
73   {
74     dir = "man" + getExtension();
75   }
76   return dir;
77 }
78
79 static QCString docifyToString(const QCString &str)
80 {
81   QCString result;
82   result.reserve(str.length());
83   if (!str.isEmpty())
84   {
85     const char *p=str.data();
86     char c=0;
87     while ((c=*p++))
88     {
89       switch(c)
90       {
91         case '-':  result += "\\-";  break; // see  bug747780
92         case '.':  result += "\\&."; break; // see  bug652277
93         case '\\': result += "\\\\"; break;
94         case '\n': result += "\n";   break;
95         case '\"': c = '\'';   // no break!
96         default:   result += c;      break;
97       }
98     }
99     //printf("%s",str);fflush(stdout);
100   }
101   return result;
102 }
103
104 static QCString objectLinkToString(const QCString &text)
105 {
106   return "\\fB" + docifyToString(text) + "\\fP";
107 }
108
109 //-------------------------------------------------------------------------------
110
111 ManCodeGenerator::ManCodeGenerator(TextStream *t) : m_t(t)
112 {
113 }
114
115 void ManCodeGenerator::startCodeFragment(const QCString &)
116 {
117   *m_t << ".PP\n";
118   *m_t << ".nf\n";
119 }
120
121 void ManCodeGenerator::endCodeFragment(const QCString &)
122 {
123   if (m_col>0) *m_t << "\n";
124   *m_t << ".fi\n";
125   m_col=0;
126 }
127
128 void ManCodeGenerator::writeLineNumber(const QCString &,const QCString &,const QCString &,int l, bool)
129 {
130   *m_t << l << " ";
131   m_col=0;
132 }
133
134 void ManCodeGenerator::writeCodeLink(CodeSymbolType,
135                                  const QCString &,const QCString &,
136                                  const QCString &, const QCString &name,
137                                  const QCString &)
138 {
139   if (!name.isEmpty())
140   {
141     const char *p=name.data();
142     char c=0;
143     while ((c=*p++))
144     {
145       switch(c)
146       {
147         case '-':  *m_t << "\\-"; break; // see  bug747780
148         case '.':  *m_t << "\\&."; break; // see  bug652277
149         case '\\': *m_t << "\\\\"; m_col++; break;
150         case '\n': *m_t << "\n"; m_col=0; break;
151         case '\"':  c = '\''; // no break!
152         default: *m_t << c; m_col++; break;
153       }
154     }
155     //printf("%s",str);fflush(stdout);
156   }
157 }
158
159 void ManCodeGenerator::codify(const QCString &str)
160 {
161   //static char spaces[]="        ";
162   if (!str.isEmpty())
163   {
164     const char *p=str.data();
165     char c;
166     int spacesToNextTabStop;
167     while (*p)
168     {
169       c=*p++;
170       switch(c)
171       {
172         case '-':  *m_t << "\\-"; break; // see  bug747780
173         case '.':   *m_t << "\\&."; break; // see  bug652277
174         case '\t':  spacesToNextTabStop =
175                           Config_getInt(TAB_SIZE) - (m_col%Config_getInt(TAB_SIZE));
176                     *m_t << Doxygen::spaces.left(spacesToNextTabStop);
177                     m_col+=spacesToNextTabStop;
178                     break;
179         case '\n':  *m_t << "\n"; m_col=0; break;
180         case '\\':  *m_t << "\\\\"; m_col++; break;
181         case '\"':  // no break!
182         default:    p=writeUTF8Char(*m_t,p-1); m_col++; break;
183       }
184     }
185     //printf("%s",str);fflush(stdout);
186   }
187 }
188
189
190 //-------------------------------------------------------------------------------
191
192 ManGenerator::ManGenerator()
193   : OutputGenerator(Config_getString(MAN_OUTPUT)+"/"+getSubdir())
194   , m_codeList(std::make_unique<OutputCodeList>())
195 {
196   m_codeGen = m_codeList->add<ManCodeGenerator>(&m_t);
197 }
198
199 ManGenerator::ManGenerator(const ManGenerator &og) : OutputGenerator(og.m_dir)
200 {
201   m_codeList = std::make_unique<OutputCodeList>(*og.m_codeList);
202   m_codeGen      = m_codeList->get<ManCodeGenerator>();
203   m_codeGen->setTextStream(&m_t);
204   m_firstCol      = og.m_firstCol;
205   m_col           = og.m_col;
206   m_paragraph     = og.m_paragraph;
207   m_upperCase     = og.m_upperCase;
208   m_insideTabbing = og.m_insideTabbing;
209   m_inHeader      = og.m_inHeader;
210 }
211
212 ManGenerator &ManGenerator::operator=(const ManGenerator &og)
213 {
214   if (this!=&og)
215   {
216     m_dir           = og.m_dir;
217     m_codeList = std::make_unique<OutputCodeList>(*og.m_codeList);
218     m_codeGen       = m_codeList->get<ManCodeGenerator>();
219     m_codeGen->setTextStream(&m_t);
220     m_firstCol      = og.m_firstCol;
221     m_col           = og.m_col;
222     m_paragraph     = og.m_paragraph;
223     m_upperCase     = og.m_upperCase;
224     m_insideTabbing = og.m_insideTabbing;
225     m_inHeader      = og.m_inHeader;
226   }
227   return *this;
228 }
229
230 ManGenerator::ManGenerator(ManGenerator &&og)
231   : OutputGenerator(std::move(og))
232 {
233   m_codeList      = std::exchange(og.m_codeList,std::unique_ptr<OutputCodeList>());
234   m_codeGen       = m_codeList->get<ManCodeGenerator>();
235   m_codeGen->setTextStream(&m_t);
236   m_firstCol      = std::exchange(og.m_firstCol,true);
237   m_col           = std::exchange(og.m_col,0);
238   m_paragraph     = std::exchange(og.m_paragraph,true);
239   m_upperCase     = std::exchange(og.m_upperCase,false);
240   m_insideTabbing = std::exchange(og.m_insideTabbing,false);
241   m_inHeader      = std::exchange(og.m_inHeader,false);
242 }
243
244 ManGenerator::~ManGenerator()
245 {
246 }
247
248 void ManGenerator::addCodeGen(OutputCodeList &list)
249 {
250   list.add(OutputCodeList::OutputCodeVariant(ManCodeGeneratorDefer(m_codeGen)));
251 }
252
253 void ManGenerator::init()
254 {
255   QCString manOutput = Config_getString(MAN_OUTPUT);
256
257   Dir d(manOutput.str());
258   if (!d.exists() && !d.mkdir(manOutput.str()))
259   {
260     term("Could not create output directory %s\n",qPrint(manOutput));
261   }
262   std::string manDir = manOutput.str()+"/"+getSubdir().str();
263   if (!d.exists(manDir) && !d.mkdir(manDir))
264   {
265     term("Could not create output directory %s/%s\n",qPrint(manOutput), qPrint(getSubdir()));
266   }
267   createSubDirs(d);
268 }
269
270 void ManGenerator::cleanup()
271 {
272   QCString dname = Config_getString(MAN_OUTPUT);
273   Dir d(dname.str());
274   clearSubDirs(d);
275 }
276
277 static QCString buildFileName(const QCString &name)
278 {
279   QCString fileName;
280   if (name.isEmpty()) return "noname";
281
282   const char *p=name.data();
283   char c;
284   while ((c=*p++))
285   {
286     switch (c)
287     {
288       case ':':
289         fileName+="_";
290         if (*p==':') p++;
291         break;
292       case '<':
293       case '>':
294       case '&':
295       case '*':
296       case '!':
297       case '^':
298       case '~':
299       case '%':
300       case '+':
301       case '/':
302         fileName+="_";
303         break;
304       default:
305         fileName+=c;
306     }
307   }
308
309   QCString manExtension = "." + getExtension();
310   if (fileName.right(manExtension.length())!=manExtension)
311   {
312     fileName+=manExtension;
313   }
314
315   return fileName;
316 }
317
318 void ManGenerator::startFile(const QCString &,const QCString &manName,const QCString &,int,int)
319 {
320   startPlainFile( buildFileName( manName ) );
321   m_firstCol=TRUE;
322 }
323
324 void ManGenerator::endFile()
325 {
326   m_t << "\n";
327   endPlainFile();
328 }
329
330 void ManGenerator::endTitleHead(const QCString &,const QCString &name)
331 {
332   m_t << ".TH \"" << name << "\" " << getExtension() << " \"";
333   switch (Config_getEnum(TIMESTAMP))
334   {
335     case TIMESTAMP_t::YES:
336     case TIMESTAMP_t::DATETIME:
337       m_t << dateToString(DateTimeType::DateTime) << "\" \"";
338       break;
339     case TIMESTAMP_t::DATE:
340       m_t << dateToString(DateTimeType::Date) << "\" \"";
341       break;
342     case TIMESTAMP_t::NO:
343       break;
344   }
345   if (!Config_getString(PROJECT_NUMBER).isEmpty())
346     m_t << "Version " << Config_getString(PROJECT_NUMBER) << "\" \"";
347   if (Config_getString(PROJECT_NAME).isEmpty())
348     m_t << "Doxygen";
349   else
350     m_t << Config_getString(PROJECT_NAME);
351   m_t << "\" \\\" -*- nroff -*-\n";
352   m_t << ".ad l\n";
353   m_t << ".nh\n";
354   m_t << ".SH NAME\n";
355   m_t << name;
356   m_firstCol=FALSE;
357   m_paragraph=TRUE;
358   m_inHeader=TRUE;
359 }
360
361 void ManGenerator::newParagraph()
362 {
363   if (!m_paragraph)
364   {
365     if (!m_firstCol) m_t << "\n";
366     m_t << ".PP\n";
367     m_firstCol=TRUE;
368   }
369   m_paragraph=TRUE;
370 }
371
372 void ManGenerator::startParagraph(const QCString &)
373 {
374   if (!m_paragraph)
375   {
376     if (!m_firstCol) m_t << "\n";
377     m_t << ".PP\n";
378     m_firstCol=TRUE;
379   }
380   m_paragraph=TRUE;
381 }
382
383 void ManGenerator::endParagraph()
384 {
385 }
386
387 void ManGenerator::writeString(const QCString &text)
388 {
389   docify(text);
390 }
391
392 void ManGenerator::startIndexItem(const QCString &,const QCString &)
393 {
394 }
395
396 void ManGenerator::endIndexItem(const QCString &,const QCString &)
397 {
398 }
399
400 void ManGenerator::writeStartAnnoItem(const QCString &,const QCString &,
401                                        const QCString &,const QCString &)
402 {
403 }
404
405 void ManGenerator::writeObjectLink(const QCString &,const QCString &,
406                                    const QCString &, const QCString &name)
407 {
408   startBold(); docify(name); endBold();
409 }
410
411 void ManGenerator::startGroupHeader(int)
412 {
413   if (!m_firstCol) m_t << "\n";
414   m_t << ".SH \"";
415   m_upperCase=TRUE;
416   m_firstCol=FALSE;
417 }
418
419 void ManGenerator::endGroupHeader(int)
420 {
421   m_t << "\"\n.PP \n";
422   m_firstCol=TRUE;
423   m_paragraph=TRUE;
424   m_upperCase=FALSE;
425 }
426
427 void ManGenerator::startMemberHeader(const QCString &,int)
428 {
429   if (!m_firstCol) m_t << "\n";
430   m_t << ".SS \"";
431 }
432
433 void ManGenerator::endMemberHeader()
434 {
435   m_t << "\"\n";
436   m_firstCol=TRUE;
437   m_paragraph=FALSE;
438 }
439
440 void ManGenerator::docify(const QCString &str)
441 {
442   if (!str.isEmpty())
443   {
444     const char *p=str.data();
445     char c=0;
446     while ((c=*p++))
447     {
448       switch(c)
449       {
450         case '-':  m_t << "\\-";           break; // see  bug747780
451         case '.':  m_t << "\\&.";          break; // see  bug652277
452         case '\\': m_t << "\\\\"; m_col++; break;
453         case '\n': m_t << "\n";   m_col=0; break;
454         case '\"': c = '\'';         // no break!
455         default:   m_t << c;      m_col++; break;
456       }
457     }
458     m_firstCol=(c=='\n');
459     //printf("%s",str);fflush(stdout);
460   }
461   m_paragraph=FALSE;
462 }
463
464 void ManGenerator::writeChar(char c)
465 {
466   m_firstCol=(c=='\n');
467   if (m_firstCol) m_col=0; else m_col++;
468   switch (c)
469   {
470     case '\\': m_t << "\\\\"; break;
471   case '\"': c = '\''; // no break!
472     default:   m_t << c; break;
473   }
474   //printf("%c",c);fflush(stdout);
475   m_paragraph=FALSE;
476 }
477
478 void ManGenerator::startTitle()
479 {
480   if (!m_firstCol) m_t << "\n";
481   m_t << ".SH \"";
482   m_firstCol=FALSE;
483   m_paragraph=FALSE;
484 }
485
486 void ManGenerator::endTitle()
487 {
488     m_t << "\"";
489 }
490
491 void ManGenerator::startItemListItem()
492 {
493   if (!m_firstCol) m_t << "\n";
494   m_t << ".TP\n";
495   m_firstCol=TRUE;
496   m_paragraph=FALSE;
497   m_col=0;
498 }
499
500 void ManGenerator::endItemListItem()
501 {
502 }
503
504 void ManGenerator::startMemberDoc(const QCString &,const QCString &,const QCString &,const QCString &,int,int,bool)
505 {
506   if (!m_firstCol) m_t << "\n";
507   m_t << ".SS \"";
508   m_firstCol=FALSE;
509   m_paragraph=FALSE;
510 }
511
512 void ManGenerator::startDoxyAnchor(const QCString &,const QCString &manName,
513                                    const QCString &, const QCString &name,
514                                    const QCString &)
515 {
516     // something to be done?
517     if( !Config_getBool(MAN_LINKS) )
518     {
519         return; // no
520     }
521
522     // the name of the link file is derived from the name of the anchor:
523     // - truncate after an (optional) ::
524     QCString baseName = name;
525     int i=baseName.findRev("::");
526     if (i!=-1) baseName=baseName.right(baseName.length()-i-2);
527
528     //printf("Converting man link '%s'->'%s'->'%s'\n",
529     //       name,qPrint(baseName),qPrint(buildFileName(baseName)));
530
531     // - remove dangerous characters and append suffix, then add dir prefix
532     QCString fileName=dir()+"/"+buildFileName( baseName );
533     FileInfo fi(fileName.str());
534     if (!fi.exists())
535     {
536       std::ofstream linkStream = Portable::openOutputStream(fileName);
537       if (linkStream.is_open())
538       {
539         linkStream << ".so " << getSubdir() << "/" << buildFileName( manName ) << "\n";
540       }
541     }
542 }
543
544 void ManGenerator::endMemberDoc(bool)
545 {
546     m_t << "\"\n";
547 }
548
549 void ManGenerator::startCompoundTemplateParams()
550 {
551   if (!m_firstCol) m_t << "\n";
552   m_t << "\n.SS \"";
553   m_firstCol=FALSE;
554   m_paragraph=FALSE;
555 }
556
557 void ManGenerator::endCompoundTemplateParams()
558 {
559   m_t << "\"";
560 }
561 void ManGenerator::writeSynopsis()
562 {
563   if (!m_firstCol) m_t << "\n";
564   m_t << ".SH SYNOPSIS\n.br\n.PP\n";
565   m_firstCol=TRUE;
566   m_paragraph=FALSE;
567 }
568
569 void ManGenerator::startDescForItem()
570 {
571   if (!m_firstCol) m_t << "\n";
572   if (!m_paragraph) m_t << ".in -1c\n";
573   m_t << ".in +1c\n";
574   m_firstCol=TRUE;
575   m_paragraph=FALSE;
576   m_col=0;
577 }
578
579 void ManGenerator::endDescForItem()
580 {
581 }
582
583 void ManGenerator::startAnonTypeScope(int indentLevel)
584 {
585   if (indentLevel==0)
586   {
587     m_insideTabbing=TRUE;
588   }
589 }
590
591 void ManGenerator::endAnonTypeScope(int indentLevel)
592 {
593   if (indentLevel==0)
594   {
595     m_insideTabbing=FALSE;
596   }
597 }
598
599
600 void ManGenerator::startMemberItem(const QCString &,MemberItemType,const QCString &)
601 {
602   if (m_firstCol && !m_insideTabbing) m_t << ".in +1c\n";
603   m_t << "\n.ti -1c\n.RI \"";
604   m_firstCol=FALSE;
605 }
606
607 void ManGenerator::endMemberItem(MemberItemType)
608 {
609   m_t << "\"\n.br";
610 }
611
612 void ManGenerator::startMemberList()
613 {
614   if (!m_insideTabbing)
615   {
616     m_t << "\n.in +1c"; m_firstCol=FALSE;
617   }
618 }
619
620 void ManGenerator::endMemberList()
621 {
622   if (!m_insideTabbing)
623   {
624     m_t << "\n.in -1c"; m_firstCol=FALSE;
625   }
626 }
627
628 void ManGenerator::startMemberGroupHeader(bool)
629 {
630   m_t << "\n.PP\n.RI \"\\fB";
631 }
632
633 void ManGenerator::endMemberGroupHeader()
634 {
635   m_t << "\\fP\"\n.br\n";
636   m_firstCol=TRUE;
637 }
638
639 void ManGenerator::startMemberGroupDocs()
640 {
641 }
642
643 void ManGenerator::endMemberGroupDocs()
644 {
645   m_t << "\n.PP";
646 }
647
648 void ManGenerator::startMemberGroup()
649 {
650   m_t << "\n.in +1c";
651 }
652
653 void ManGenerator::endMemberGroup(bool)
654 {
655   m_t << "\n.in -1c";
656   m_firstCol=FALSE;
657 }
658
659 void ManGenerator::startSection(const QCString &,const QCString &,SectionType type)
660 {
661   if( !m_inHeader )
662   {
663     switch(type)
664     {
665       case SectionType::Page:          startGroupHeader(0); break;
666       case SectionType::Section:       startGroupHeader(0); break;
667       case SectionType::Subsection:    startMemberHeader(QCString(), -1); break;
668       case SectionType::Subsubsection: startMemberHeader(QCString(), -1); break;
669       case SectionType::Paragraph:     startMemberHeader(QCString(), -1); break;
670       default: ASSERT(0); break;
671     }
672   }
673 }
674
675 void ManGenerator::endSection(const QCString &,SectionType type)
676 {
677   if( !m_inHeader )
678   {
679     switch(type)
680     {
681       case SectionType::Page:          endGroupHeader(0); break;
682       case SectionType::Section:       endGroupHeader(0); break;
683       case SectionType::Subsection:    endMemberHeader(); break;
684       case SectionType::Subsubsection: endMemberHeader(); break;
685       case SectionType::Paragraph:     endMemberHeader(); break;
686       default: ASSERT(0); break;
687     }
688   }
689   else
690   {
691     m_t << "\n.PP\n";
692     m_firstCol=TRUE;
693     m_paragraph=FALSE;
694     m_inHeader=FALSE;
695   }
696 }
697
698 void ManGenerator::startExamples()
699 {
700   if (!m_firstCol)
701   { m_t << "\n" << ".PP\n";
702     m_firstCol=TRUE; m_paragraph=TRUE;
703     m_col=0;
704   }
705   m_paragraph=FALSE;
706   startBold();
707   docify(theTranslator->trExamples());
708   endBold();
709   m_paragraph=TRUE;
710 }
711
712 void ManGenerator::endExamples()
713 {
714 }
715
716 void ManGenerator::startDescTable(const QCString &title)
717 {
718   if (!m_firstCol)
719   { m_t << "\n.PP\n";
720     m_firstCol=TRUE; m_paragraph=TRUE;
721     m_col=0;
722   }
723   m_paragraph=FALSE;
724   startBold();
725   docify(title);
726   endBold();
727   m_paragraph=TRUE;
728   startDescForItem();
729 }
730
731 void ManGenerator::endDescTable()
732 {
733   endDescForItem();
734 }
735
736 void ManGenerator::writeDoc(const IDocNodeAST *ast,const Definition *ctx,const MemberDef *,int)
737 {
738   const DocNodeAST *astImpl = dynamic_cast<const DocNodeAST *>(ast);
739   if (astImpl)
740   {
741     ManDocVisitor visitor(m_t,*m_codeList,ctx?ctx->getDefFileExtension():QCString(""));
742     std::visit(visitor,astImpl->root);
743   }
744   m_firstCol=FALSE;
745   m_paragraph = FALSE;
746 }
747
748 void ManGenerator::startConstraintList(const QCString &header)
749 {
750   if (!m_firstCol)
751   { m_t << "\n.PP\n";
752     m_firstCol=TRUE; m_paragraph=TRUE;
753     m_col=0;
754   }
755   m_paragraph=FALSE;
756   startBold();
757   docify(header);
758   endBold();
759   m_paragraph=TRUE;
760 }
761
762 void ManGenerator::startConstraintParam()
763 {
764   startItemListItem();
765   startEmphasis();
766 }
767
768 void ManGenerator::endConstraintParam()
769 {
770   endEmphasis();
771   endItemListItem();
772   m_t << " : ";
773 }
774
775 void ManGenerator::startConstraintType()
776 {
777   startEmphasis();
778 }
779
780 void ManGenerator::endConstraintType()
781 {
782   endEmphasis();
783 }
784
785 void ManGenerator::startConstraintDocs()
786 {
787 }
788
789 void ManGenerator::endConstraintDocs()
790 {
791   m_t << "\n"; m_firstCol=TRUE;
792 }
793
794 void ManGenerator::endConstraintList()
795 {
796 }
797
798
799 void ManGenerator::startInlineHeader()
800 {
801   if (!m_firstCol)
802   {
803     m_t << "\n.PP\n" << ".in -1c\n";
804   }
805   m_t << ".RI \"\\fB";
806 }
807
808 void ManGenerator::endInlineHeader()
809 {
810   m_t << "\\fP\"\n" << ".in +1c\n";
811   m_firstCol = FALSE;
812 }
813
814 void ManGenerator::startMemberDocSimple(bool isEnum)
815 {
816   if (!m_firstCol)
817   {
818     m_t << "\n.PP\n";
819   }
820   m_t << "\\fB";
821   if (isEnum)
822   {
823     docify(theTranslator->trEnumerationValues());
824   }
825   else
826   {
827     docify(theTranslator->trCompoundMembers());
828   }
829   m_t << ":\\fP\n";
830   m_t << ".RS 4\n";
831 }
832
833 void ManGenerator::endMemberDocSimple(bool)
834 {
835   if (!m_firstCol) m_t << "\n";
836   m_t << ".RE\n";
837   m_t << ".PP\n";
838   m_firstCol=TRUE;
839 }
840
841 void ManGenerator::startInlineMemberType()
842 {
843 }
844
845 void ManGenerator::endInlineMemberType()
846 {
847   m_t << " ";
848 }
849
850 void ManGenerator::startInlineMemberName()
851 {
852   m_t << "\\fI";
853 }
854
855 void ManGenerator::endInlineMemberName()
856 {
857   m_t << "\\fP ";
858 }
859
860 void ManGenerator::startInlineMemberDoc()
861 {
862 }
863
864 void ManGenerator::endInlineMemberDoc()
865 {
866   if (!m_firstCol) m_t << "\n";
867   m_t << ".br\n";
868   m_t << ".PP\n";
869   m_firstCol=TRUE;
870 }
871
872 void ManGenerator::startLabels()
873 {
874 }
875
876 void ManGenerator::writeLabel(const QCString &l,bool isLast)
877 {
878   m_t << "\\fC [" << l << "]\\fP";
879   if (!isLast) m_t << ", ";
880 }
881
882 void ManGenerator::endLabels()
883 {
884 }
885
886 void ManGenerator::endHeaderSection()
887 {
888 }
889
890 void ManGenerator::writeInheritedSectionTitle(
891                   const QCString &/*id*/,    const QCString &/*ref*/,
892                   const QCString &/*file*/,  const QCString &/*anchor*/,
893                   const QCString &title,     const QCString &name)
894 {
895   m_t << "\n\n";
896   m_t << theTranslator->trInheritedFrom(docifyToString(title), objectLinkToString(name));
897   m_firstCol = FALSE;
898 }
899