1 /******************************************************************************
5 * Copyright (C) 1997-2015 by Dimitri van Heesch.
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.
13 * Documents produced by Doxygen are derivative works derived from the
14 * input used in their production; they are not affected by this license.
18 /* http://www.cubic.org/source/archive/fileform/txt/man/ has some
19 nice introductions to groff and man pages. */
30 #include "docparser.h"
31 #include "mandocvisitor.h"
34 static QCString getExtension()
38 * in case of . missing, just ignore it
39 * in case number missing, just place a 3 in front of it
41 QCString ext = Config_getString(MAN_EXTENSION);
59 if (ext.at(0)<'0' || ext.at(0)>'9')
67 static QCString getSubdir()
69 QCString dir = Config_getString(MAN_SUBDIR);
72 dir = "man" + getExtension();
77 ManGenerator::ManGenerator() : OutputGenerator()
79 dir=Config_getString(MAN_OUTPUT) + "/" + getSubdir();
88 ManGenerator::~ManGenerator()
92 //void ManGenerator::append(const OutputGenerator *g)
94 // QCString r=g->getContents();
100 // firstCol = r.at(r.length()-1)=='\n';
102 // firstCol = ((ManGenerator *)g)->firstCol;
103 // col+=((ManGenerator *)g)->col;
104 // inHeader=((ManGenerator *)g)->inHeader;
108 void ManGenerator::init()
110 QCString &manOutput = Config_getString(MAN_OUTPUT);
113 if (!d.exists() && !d.mkdir(manOutput))
115 err("Could not create output directory %s\n",manOutput.data());
118 d.setPath(manOutput + "/" + getSubdir());
119 if (!d.exists() && !d.mkdir(manOutput + "/" + getSubdir()))
121 err("Could not create output directory %s/%s\n",manOutput.data(), getSubdir().data());
127 static QCString buildFileName(const char *name)
130 if (name==0) return "noname";
159 QCString manExtension = "." + getExtension();
160 if (fileName.right(manExtension.length())!=manExtension)
162 fileName+=manExtension;
168 void ManGenerator::startFile(const char *,const char *manName,const char *)
170 startPlainFile( buildFileName( manName ) );
174 void ManGenerator::endFile()
180 void ManGenerator::endTitleHead(const char *,const char *name)
182 t << ".TH \"" << name << "\" " << getExtension() << " \""
183 << dateToString(FALSE) << "\" \"";
184 if (!Config_getString(PROJECT_NUMBER).isEmpty())
185 t << "Version " << Config_getString(PROJECT_NUMBER) << "\" \"";
186 if (Config_getString(PROJECT_NAME).isEmpty())
189 t << Config_getString(PROJECT_NAME);
190 t << "\" \\\" -*- nroff -*-" << endl;
191 t << ".ad l" << endl;
193 t << ".SH NAME" << endl;
200 void ManGenerator::newParagraph()
204 if (!firstCol) t << endl;
211 void ManGenerator::startParagraph(const char *)
215 if (!firstCol) t << endl;
222 void ManGenerator::endParagraph()
226 void ManGenerator::writeString(const char *text)
231 void ManGenerator::startIndexItem(const char *,const char *)
235 void ManGenerator::endIndexItem(const char *,const char *)
239 void ManGenerator::writeStartAnnoItem(const char *,const char *,
240 const char *,const char *)
244 void ManGenerator::writeObjectLink(const char *,const char *,
245 const char *, const char *name)
247 startBold(); docify(name); endBold();
250 void ManGenerator::writeCodeLink(const char *,const char *,
251 const char *, const char *name,
257 void ManGenerator::startHtmlLink(const char *)
261 void ManGenerator::endHtmlLink()
265 //void ManGenerator::writeMailLink(const char *url)
270 void ManGenerator::startGroupHeader(int)
272 if (!firstCol) t << endl;
278 void ManGenerator::endGroupHeader(int)
280 t << "\"\n.PP " << endl;
286 void ManGenerator::startMemberHeader(const char *,int)
288 if (!firstCol) t << endl;
292 void ManGenerator::endMemberHeader()
299 void ManGenerator::docify(const char *str)
309 case '-': t << "\\-"; break; // see bug747780
310 case '.': t << "\\&."; break; // see bug652277
311 case '\\': t << "\\\\"; col++; break;
312 case '\n': t << "\n"; col=0; break;
313 case '\"': c = '\''; // no break!
314 default: t << c; col++; break;
318 //printf("%s",str);fflush(stdout);
323 void ManGenerator::codify(const char *str)
325 //static char spaces[]=" ";
330 int spacesToNextTabStop;
336 case '.': t << "\\&."; break; // see bug652277
337 case '\t': spacesToNextTabStop =
338 Config_getInt(TAB_SIZE) - (col%Config_getInt(TAB_SIZE));
339 t << Doxygen::spaces.left(spacesToNextTabStop);
340 col+=spacesToNextTabStop;
342 case '\n': t << "\n"; firstCol=TRUE; col=0; break;
343 case '\\': t << "\\"; col++; break;
344 case '\"': // no break!
345 default: p=writeUtf8Char(t,p-1); firstCol=FALSE; col++; break;
348 //printf("%s",str);fflush(stdout);
353 void ManGenerator::writeChar(char c)
356 if (firstCol) col=0; else col++;
359 case '\\': t << "\\\\"; break;
360 case '\"': c = '\''; // no break!
361 default: t << c; break;
363 //printf("%c",c);fflush(stdout);
367 void ManGenerator::startDescList(SectionTypes)
370 { t << endl << ".PP" << endl;
371 firstCol=TRUE; paragraph=TRUE;
378 void ManGenerator::startTitle()
380 if (!firstCol) t << endl;
386 void ManGenerator::endTitle()
391 void ManGenerator::startItemListItem()
393 if (!firstCol) t << endl;
400 void ManGenerator::endItemListItem()
404 void ManGenerator::startCodeFragment()
412 void ManGenerator::endCodeFragment()
414 if (!firstCol) t << endl;
421 void ManGenerator::startMemberDoc(const char *,const char *,const char *,const char *,int,int,bool)
423 if (!firstCol) t << endl;
429 void ManGenerator::startDoxyAnchor(const char *,const char *manName,
430 const char *, const char *name,
433 // something to be done?
434 if( !Config_getBool(MAN_LINKS) )
439 // the name of the link file is derived from the name of the anchor:
440 // - truncate after an (optional) ::
441 QCString baseName = name;
442 int i=baseName.findRev("::");
443 if (i!=-1) baseName=baseName.right(baseName.length()-i-2);
445 //printf("Converting man link '%s'->'%s'->'%s'\n",
446 // name,baseName.data(),buildFileName(baseName).data());
448 // - remove dangerous characters and append suffix, then add dir prefix
449 QCString fileName=dir+"/"+buildFileName( baseName );
450 QFile linkfile( fileName );
451 // - only create file if it doesn't exist already
452 if ( !linkfile.open( IO_ReadOnly ) )
454 if ( linkfile.open( IO_WriteOnly ) )
456 FTextStream linkstream;
457 linkstream.setDevice(&linkfile);
458 //linkstream.setEncoding(QTextStream::UnicodeUTF8);
459 linkstream << ".so " << getSubdir() << "/" << buildFileName( manName ) << endl;
465 void ManGenerator::endMemberDoc(bool)
470 void ManGenerator::startSubsection()
472 if (!firstCol) t << endl;
478 void ManGenerator::endSubsection()
484 void ManGenerator::startSubsubsection()
486 if (!firstCol) t << endl;
492 void ManGenerator::endSubsubsection()
497 void ManGenerator::writeSynopsis()
499 if (!firstCol) t << endl;
500 t << ".SH SYNOPSIS\n.br\n.PP\n";
505 void ManGenerator::startDescItem()
507 if (!firstCol) t << endl;
512 //void ManGenerator::endDescTitle()
518 void ManGenerator::startDescForItem()
520 if (!firstCol) t << endl;
521 if (!paragraph) t << ".in -1c" << endl;
522 t << ".in +1c" << endl;
528 void ManGenerator::endDescForItem()
532 void ManGenerator::endDescItem()
534 t << "\" 1c" << endl;
538 void ManGenerator::startAnonTypeScope(int indentLevel)
546 void ManGenerator::endAnonTypeScope(int indentLevel)
555 void ManGenerator::startMemberItem(const char *,int,const char *)
557 if (firstCol && !insideTabbing) t << ".in +1c\n";
558 t << "\n.ti -1c\n.RI \"";
562 void ManGenerator::endMemberItem()
567 void ManGenerator::startMemberList()
571 t << "\n.in +1c"; firstCol=FALSE;
575 void ManGenerator::endMemberList()
579 t << "\n.in -1c"; firstCol=FALSE;
583 void ManGenerator::startMemberGroupHeader(bool)
585 t << "\n.PP\n.RI \"\\fB";
588 void ManGenerator::endMemberGroupHeader()
590 t << "\\fP\"\n.br\n";
594 void ManGenerator::startMemberGroupDocs()
598 void ManGenerator::endMemberGroupDocs()
603 void ManGenerator::startMemberGroup()
608 void ManGenerator::endMemberGroup(bool)
614 void ManGenerator::startSection(const char *,const char *,SectionInfo::SectionType type)
620 case SectionInfo::Page: startGroupHeader(FALSE); break;
621 case SectionInfo::Section: startGroupHeader(FALSE); break;
622 case SectionInfo::Subsection: startMemberHeader(0, -1); break;
623 case SectionInfo::Subsubsection: startMemberHeader(0, -1); break;
624 case SectionInfo::Paragraph: startMemberHeader(0, -1); break;
625 default: ASSERT(0); break;
630 void ManGenerator::endSection(const char *,SectionInfo::SectionType type)
636 case SectionInfo::Page: endGroupHeader(0); break;
637 case SectionInfo::Section: endGroupHeader(0); break;
638 case SectionInfo::Subsection: endMemberHeader(); break;
639 case SectionInfo::Subsubsection: endMemberHeader(); break;
640 case SectionInfo::Paragraph: endMemberHeader(); break;
641 default: ASSERT(0); break;
653 void ManGenerator::startExamples()
656 { t << endl << ".PP" << endl;
657 firstCol=TRUE; paragraph=TRUE;
662 docify(theTranslator->trExamples());
667 void ManGenerator::endExamples()
671 void ManGenerator::startDescTable(const char *title)
674 { t << endl << ".PP" << endl;
675 firstCol=TRUE; paragraph=TRUE;
686 void ManGenerator::endDescTable()
691 void ManGenerator::startParamList(ParamListTypes,const char *title)
694 { t << endl << ".PP" << endl;
695 firstCol=TRUE; paragraph=TRUE;
705 void ManGenerator::endParamList()
709 void ManGenerator::writeDoc(DocNode *n,Definition *ctx,MemberDef *)
711 ManDocVisitor *visitor = new ManDocVisitor(t,*this,ctx?ctx->getDefFileExtension():QCString(""));
718 void ManGenerator::startConstraintList(const char *header)
721 { t << endl << ".PP" << endl;
722 firstCol=TRUE; paragraph=TRUE;
732 void ManGenerator::startConstraintParam()
738 void ManGenerator::endConstraintParam()
745 void ManGenerator::startConstraintType()
750 void ManGenerator::endConstraintType()
755 void ManGenerator::startConstraintDocs()
759 void ManGenerator::endConstraintDocs()
761 t << endl; firstCol=TRUE;
764 void ManGenerator::endConstraintList()
769 void ManGenerator::startInlineHeader()
773 t << endl << ".PP" << endl << ".in -1c" << endl;
778 void ManGenerator::endInlineHeader()
780 t << "\\fP\"" << endl << ".in +1c" << endl;
784 void ManGenerator::startMemberDocSimple(bool isEnum)
788 t << endl << ".PP" << endl;
793 docify(theTranslator->trEnumerationValues());
797 docify(theTranslator->trCompoundMembers());
799 t << ":\\fP" << endl;
800 t << ".RS 4" << endl;
803 void ManGenerator::endMemberDocSimple(bool)
805 if (!firstCol) t << endl;
811 void ManGenerator::startInlineMemberType()
815 void ManGenerator::endInlineMemberType()
820 void ManGenerator::startInlineMemberName()
825 void ManGenerator::endInlineMemberName()
830 void ManGenerator::startInlineMemberDoc()
834 void ManGenerator::endInlineMemberDoc()
836 if (!firstCol) t << endl;
842 void ManGenerator::startLabels()
846 void ManGenerator::writeLabel(const char *l,bool isLast)
848 t << "\\fC [" << l << "]\\fP";
849 if (!isLast) t << ", ";
852 void ManGenerator::endLabels()
856 void ManGenerator::endHeaderSection()