00001 /****************************************************************************** 00002 * 00003 * $Id: htmlgen.cpp,v 1.17 1998/11/28 11:33:19 root Exp $ 00004 * 00005 * Copyright (C) 1997-2008 by Dimitri van Heesch. 00006 * 00007 * Permission to use, copy, modify, and distribute this software and its 00008 * documentation under the terms of the GNU General Public License is hereby 00009 * granted. No representations are made about the suitability of this software 00010 * for any purpose. It is provided "as is" without express or implied warranty. 00011 * See the GNU General Public License for more details. 00012 * 00013 * Documents produced by Doxygen are derivative works derived from the 00014 * input used in their production; they are not affected by this license. 00015 * 00016 */ 00017 00018 /* http://www.cubic.org/source/archive/fileform/txt/man/ has some 00019 nice introductions to groff and man pages. */ 00020 00021 #include <stdlib.h> 00022 00023 #include "qtbc.h" 00024 #include <qdir.h> 00025 #include "message.h" 00026 #include "mangen.h" 00027 #include "config.h" 00028 #include "util.h" 00029 #include "doxygen.h" 00030 #include <string.h> 00031 #include "docparser.h" 00032 #include "mandocvisitor.h" 00033 00034 static QCString getExtension() 00035 { 00036 QCString ext = Config_getString("MAN_EXTENSION"); 00037 if( ext.length() >= 2 && 00038 ext.data()[0] == '.') 00039 { 00040 ext = ext.mid(1, ext.length()-1); 00041 } 00042 else 00043 { 00044 ext = "3"; 00045 } 00046 return ext; 00047 } 00048 00049 ManGenerator::ManGenerator() : OutputGenerator() 00050 { 00051 dir=Config_getString("MAN_OUTPUT")+"/man" + getExtension(); 00052 firstCol=TRUE; 00053 paragraph=FALSE; 00054 col=0; 00055 upperCase=FALSE; 00056 insideTabbing=FALSE; 00057 inHeader=FALSE; 00058 } 00059 00060 ManGenerator::~ManGenerator() 00061 { 00062 } 00063 00064 //void ManGenerator::append(const OutputGenerator *g) 00065 //{ 00066 // QCString r=g->getContents(); 00067 // if (upperCase) 00068 // t << r.upper(); 00069 // else 00070 // t << r; 00071 // if (!r.isEmpty()) 00072 // firstCol = r.at(r.length()-1)=='\n'; 00073 // else 00074 // firstCol = ((ManGenerator *)g)->firstCol; 00075 // col+=((ManGenerator *)g)->col; 00076 // inHeader=((ManGenerator *)g)->inHeader; 00077 // paragraph=FALSE; 00078 //} 00079 00080 void ManGenerator::init() 00081 { 00082 QCString ext = getExtension(); 00083 QCString &manOutput = Config_getString("MAN_OUTPUT"); 00084 00085 QDir d(manOutput); 00086 if (!d.exists() && !d.mkdir(manOutput)) 00087 { 00088 err("Could not create output directory %s\n",manOutput.data()); 00089 exit(1); 00090 } 00091 d.setPath(manOutput+"/man"+ext); 00092 if (!d.exists() && !d.mkdir(manOutput+"/man"+ext)) 00093 { 00094 err("Could not create output directory %s/man%s\n",manOutput.data(),ext.data()); 00095 exit(1); 00096 } 00097 createSubDirs(d); 00098 } 00099 00100 static QCString buildFileName(const char *name) 00101 { 00102 QCString fileName; 00103 00104 const char *p=name; 00105 char c; 00106 while ((c=*p++)) 00107 { 00108 switch (c) 00109 { 00110 case ':': 00111 fileName+="_"; 00112 if (*p==':') p++; 00113 break; 00114 case '<': 00115 case '>': 00116 case '&': 00117 case '*': 00118 case '!': 00119 case '^': 00120 case '~': 00121 case '%': 00122 case '+': 00123 case '/': 00124 fileName+="_"; 00125 break; 00126 default: 00127 fileName+=c; 00128 } 00129 } 00130 00131 QCString &manExtension = Config_getString("MAN_EXTENSION"); 00132 if (convertToQCString(fileName.right(2))!=manExtension) 00133 { 00134 fileName+=manExtension; 00135 } 00136 00137 return fileName; 00138 } 00139 00140 void ManGenerator::startFile(const char *,const char *manName,const char *) 00141 { 00142 startPlainFile( buildFileName( manName ) ); 00143 firstCol=TRUE; 00144 } 00145 00146 void ManGenerator::endFile() 00147 { 00148 t << endl; 00149 endPlainFile(); 00150 } 00151 00152 void ManGenerator::endTitleHead(const char *,const char *name) 00153 { 00154 t << ".TH \"" << name << "\" " << getExtension() << " \"" 00155 << dateToString(FALSE) << "\" \""; 00156 if (!Config_getString("PROJECT_NUMBER").isEmpty()) 00157 t << "Version " << Config_getString("PROJECT_NUMBER") << "\" \""; 00158 if (Config_getString("PROJECT_NAME").isEmpty()) 00159 t << "Doxygen"; 00160 else 00161 t << Config_getString("PROJECT_NAME"); 00162 t << "\" \\\" -*- nroff -*-" << endl; 00163 t << ".ad l" << endl; 00164 t << ".nh" << endl; 00165 t << ".SH NAME" << endl; 00166 t << name << " \\- "; 00167 firstCol=FALSE; 00168 inHeader=TRUE; 00169 } 00170 00171 void ManGenerator::newParagraph() 00172 { 00173 if (!paragraph) 00174 { 00175 if (!firstCol) t << endl; 00176 t << ".PP" << endl; 00177 firstCol=TRUE; 00178 } 00179 paragraph=TRUE; 00180 } 00181 00182 void ManGenerator::startParagraph() 00183 { 00184 if (!paragraph) 00185 { 00186 if (!firstCol) t << endl; 00187 t << ".PP" << endl; 00188 firstCol=TRUE; 00189 } 00190 paragraph=TRUE; 00191 } 00192 00193 void ManGenerator::endParagraph() 00194 { 00195 } 00196 00197 void ManGenerator::writeString(const char *text) 00198 { 00199 docify(text); 00200 } 00201 00202 void ManGenerator::startIndexItem(const char *,const char *) 00203 { 00204 } 00205 00206 void ManGenerator::endIndexItem(const char *,const char *) 00207 { 00208 } 00209 00210 void ManGenerator::writeStartAnnoItem(const char *,const char *, 00211 const char *,const char *) 00212 { 00213 } 00214 00215 void ManGenerator::writeObjectLink(const char *,const char *, 00216 const char *, const char *name) 00217 { 00218 startBold(); docify(name); endBold(); 00219 } 00220 00221 void ManGenerator::writeCodeLink(const char *,const char *, 00222 const char *, const char *name, 00223 const char *) 00224 { 00225 docify(name); 00226 } 00227 00228 void ManGenerator::startHtmlLink(const char *) 00229 { 00230 } 00231 00232 void ManGenerator::endHtmlLink() 00233 { 00234 } 00235 00236 //void ManGenerator::writeMailLink(const char *url) 00237 //{ 00238 // docify(url); 00239 //} 00240 00241 void ManGenerator::startGroupHeader() 00242 { 00243 if (!firstCol) t << endl; 00244 t << ".SH \""; 00245 upperCase=TRUE; 00246 firstCol=FALSE; 00247 } 00248 00249 void ManGenerator::endGroupHeader() 00250 { 00251 t << "\"\n.PP " << endl; 00252 firstCol=TRUE; 00253 paragraph=TRUE; 00254 upperCase=FALSE; 00255 } 00256 00257 void ManGenerator::startMemberHeader() 00258 { 00259 if (!firstCol) t << endl; 00260 t << ".SS \""; 00261 } 00262 00263 void ManGenerator::endMemberHeader() 00264 { 00265 t << "\"\n"; 00266 firstCol=TRUE; 00267 paragraph=FALSE; 00268 } 00269 00270 void ManGenerator::docify(const char *str) 00271 { 00272 if (str) 00273 { 00274 const char *p=str; 00275 char c=0; 00276 while ((c=*p++)) 00277 { 00278 switch(c) 00279 { 00280 case '\\': t << "\\\\"; col++; break; 00281 case '\n': t << "\n"; col=0; break; 00282 case '\"': c = '\''; // no break! 00283 default: t << c; col++; break; 00284 } 00285 } 00286 firstCol=(c=='\n'); 00287 //printf("%s",str);fflush(stdout); 00288 } 00289 paragraph=FALSE; 00290 } 00291 00292 void ManGenerator::codify(const char *str) 00293 { 00294 //static char spaces[]=" "; 00295 if (str) 00296 { 00297 const char *p=str; 00298 char c; 00299 int spacesToNextTabStop; 00300 while (*p) 00301 { 00302 c=*p++; 00303 switch(c) 00304 { 00305 case '\t': spacesToNextTabStop = 00306 Config_getInt("TAB_SIZE") - (col%Config_getInt("TAB_SIZE")); 00307 t << spaces.left(spacesToNextTabStop); 00308 col+=spacesToNextTabStop; 00309 break; 00310 case '\n': t << "\n"; firstCol=TRUE; col=0; break; 00311 case '\\': t << "\\"; col++; break; 00312 case '\"': c = '\''; // no break! 00313 default: t << c; firstCol=FALSE; col++; break; 00314 } 00315 } 00316 //printf("%s",str);fflush(stdout); 00317 } 00318 paragraph=FALSE; 00319 } 00320 00321 void ManGenerator::writeChar(char c) 00322 { 00323 firstCol=(c=='\n'); 00324 if (firstCol) col=0; else col++; 00325 switch (c) 00326 { 00327 case '\\': t << "\\\\"; break; 00328 case '\"': c = '\''; // no break! 00329 default: t << c; break; 00330 } 00331 //printf("%c",c);fflush(stdout); 00332 paragraph=FALSE; 00333 } 00334 00335 void ManGenerator::startDescList(SectionTypes) 00336 { 00337 if (!firstCol) 00338 { t << endl << ".PP" << endl; 00339 firstCol=TRUE; paragraph=TRUE; 00340 col=0; 00341 } 00342 paragraph=FALSE; 00343 startBold(); 00344 } 00345 00346 void ManGenerator::startTitle() 00347 { 00348 if (!firstCol) t << endl; 00349 t << ".SH \""; 00350 firstCol=FALSE; 00351 paragraph=FALSE; 00352 } 00353 00354 void ManGenerator::endTitle() 00355 { 00356 t << "\""; 00357 } 00358 00359 void ManGenerator::writeListItem() 00360 { 00361 if (!firstCol) t << endl; 00362 t << ".TP" << endl; 00363 firstCol=TRUE; 00364 paragraph=FALSE; 00365 col=0; 00366 } 00367 00368 void ManGenerator::startCodeFragment() 00369 { 00370 newParagraph(); 00371 t << ".nf" << endl; 00372 firstCol=TRUE; 00373 paragraph=FALSE; 00374 } 00375 00376 void ManGenerator::endCodeFragment() 00377 { 00378 if (!firstCol) t << endl; 00379 t << ".fi" << endl; 00380 firstCol=TRUE; 00381 paragraph=FALSE; 00382 col=0; 00383 } 00384 00385 void ManGenerator::startMemberDoc(const char *,const char *,const char *,const char *) 00386 { 00387 if (!firstCol) t << endl; 00388 t << ".SS \""; 00389 firstCol=FALSE; 00390 paragraph=FALSE; 00391 } 00392 00393 void ManGenerator::startDoxyAnchor(const char *,const char *manName, 00394 const char *, const char *name, 00395 const char *) 00396 { 00397 // something to be done? 00398 if( !Config_getBool("MAN_LINKS") ) 00399 { 00400 return; // no 00401 } 00402 00403 // the name of the link file is derived from the name of the anchor: 00404 // - truncate after an (optional) :: 00405 QCString baseName = name; 00406 int i=baseName.findRev(':'); 00407 if (i!=-1) baseName=baseName.right(baseName.length()-i-1); 00408 00409 // - remove dangerous characters and append suffix, then add dir prefix 00410 QCString fileName=dir+"/"+buildFileName( baseName ); 00411 QFile linkfile( fileName ); 00412 // - only create file if it doesn't exist already 00413 if ( !linkfile.open( IO_ReadOnly ) ) 00414 { 00415 if ( linkfile.open( IO_WriteOnly ) ) 00416 { 00417 QTextStream linkstream; 00418 linkstream.setDevice(&linkfile); 00419 linkstream.setEncoding(QTextStream::UnicodeUTF8); 00420 linkstream << ".so man" << getExtension() << "/" << buildFileName( manName ) << endl; 00421 } 00422 } 00423 linkfile.close(); 00424 } 00425 00426 void ManGenerator::endMemberDoc(bool) 00427 { 00428 t << "\""; 00429 } 00430 00431 void ManGenerator::startSubsection() 00432 { 00433 if (!firstCol) t << endl; 00434 t << ".SS \""; 00435 firstCol=FALSE; 00436 paragraph=FALSE; 00437 } 00438 00439 void ManGenerator::endSubsection() 00440 { 00441 t << "\""; 00442 } 00443 00444 00445 void ManGenerator::startSubsubsection() 00446 { 00447 if (!firstCol) t << endl; 00448 t << "\n.SS \""; 00449 firstCol=FALSE; 00450 paragraph=FALSE; 00451 } 00452 00453 void ManGenerator::endSubsubsection() 00454 { 00455 t << "\""; 00456 } 00457 00458 void ManGenerator::writeSynopsis() 00459 { 00460 if (!firstCol) t << endl; 00461 t << ".SH SYNOPSIS\n.br\n.PP\n"; 00462 firstCol=TRUE; 00463 paragraph=FALSE; 00464 } 00465 00466 void ManGenerator::startDescItem() 00467 { 00468 if (!firstCol) t << endl; 00469 t << ".IP \""; 00470 firstCol=FALSE; 00471 } 00472 00473 //void ManGenerator::endDescTitle() 00474 //{ 00475 // endBold(); 00476 // paragraph=TRUE; 00477 //} 00478 00479 void ManGenerator::writeDescItem() 00480 { 00481 if (!firstCol) t << endl; 00482 if (!paragraph) t << ".in -1c" << endl; 00483 t << ".in +1c" << endl; 00484 firstCol=TRUE; 00485 paragraph=FALSE; 00486 col=0; 00487 } 00488 00489 void ManGenerator::endDescItem() 00490 { 00491 t << "\" 1c" << endl; 00492 firstCol=TRUE; 00493 } 00494 00495 void ManGenerator::startAnonTypeScope(int indentLevel) 00496 { 00497 if (indentLevel==0) 00498 { 00499 insideTabbing=TRUE; 00500 } 00501 } 00502 00503 void ManGenerator::endAnonTypeScope(int indentLevel) 00504 { 00505 if (indentLevel==0) 00506 { 00507 insideTabbing=FALSE; 00508 } 00509 } 00510 00511 00512 void ManGenerator::startMemberItem(int) 00513 { 00514 if (firstCol && !insideTabbing) t << ".in +1c\n"; 00515 t << "\n.ti -1c\n.RI \""; 00516 firstCol=FALSE; 00517 } 00518 00519 void ManGenerator::endMemberItem() 00520 { 00521 t << "\"\n.br"; 00522 } 00523 00524 void ManGenerator::startMemberList() 00525 { 00526 if (!insideTabbing) 00527 { 00528 t << "\n.in +1c"; firstCol=FALSE; 00529 } 00530 } 00531 00532 void ManGenerator::endMemberList() 00533 { 00534 if (!insideTabbing) 00535 { 00536 t << "\n.in -1c"; firstCol=FALSE; 00537 } 00538 } 00539 00540 void ManGenerator::startMemberGroupHeader(bool) 00541 { 00542 t << "\n.PP\n.RI \"\\fB"; 00543 } 00544 00545 void ManGenerator::endMemberGroupHeader() 00546 { 00547 t << "\\fP\"\n.br\n"; 00548 firstCol=TRUE; 00549 } 00550 00551 void ManGenerator::startMemberGroupDocs() 00552 { 00553 } 00554 00555 void ManGenerator::endMemberGroupDocs() 00556 { 00557 t << "\n.PP"; 00558 } 00559 00560 void ManGenerator::startMemberGroup() 00561 { 00562 t << "\n.in +1c"; 00563 } 00564 00565 void ManGenerator::endMemberGroup(bool) 00566 { 00567 t << "\n.in -1c"; 00568 firstCol=FALSE; 00569 } 00570 00571 void ManGenerator::startSection(const char *,const char *,SectionInfo::SectionType type) 00572 { 00573 if( !inHeader ) 00574 { 00575 switch(type) 00576 { 00577 case SectionInfo::Page: startGroupHeader(); break; 00578 case SectionInfo::Section: startGroupHeader(); break; 00579 case SectionInfo::Subsection: startMemberHeader(); break; 00580 case SectionInfo::Subsubsection: startMemberHeader(); break; 00581 case SectionInfo::Paragraph: startMemberHeader(); break; 00582 default: ASSERT(0); break; 00583 } 00584 } 00585 } 00586 00587 void ManGenerator::endSection(const char *,SectionInfo::SectionType type) 00588 { 00589 if( !inHeader ) 00590 { 00591 switch(type) 00592 { 00593 case SectionInfo::Page: endGroupHeader(); break; 00594 case SectionInfo::Section: endGroupHeader(); break; 00595 case SectionInfo::Subsection: endMemberHeader(); break; 00596 case SectionInfo::Subsubsection: endMemberHeader(); break; 00597 case SectionInfo::Paragraph: endMemberHeader(); break; 00598 default: ASSERT(0); break; 00599 } 00600 } 00601 else 00602 { 00603 t << "\n"; 00604 firstCol=TRUE; 00605 paragraph=FALSE; 00606 inHeader=FALSE; 00607 } 00608 } 00609 00610 void ManGenerator::startSimpleSect(SectionTypes,const char *, 00611 const char *,const char *title) 00612 { 00613 if (!firstCol) 00614 { t << endl << ".PP" << endl; 00615 firstCol=TRUE; paragraph=TRUE; 00616 col=0; 00617 } 00618 paragraph=FALSE; 00619 startBold(); 00620 docify(title); 00621 endBold(); 00622 paragraph=TRUE; 00623 } 00624 00625 void ManGenerator::endSimpleSect() 00626 { 00627 } 00628 00629 void ManGenerator::startParamList(ParamListTypes,const char *title) 00630 { 00631 if (!firstCol) 00632 { t << endl << ".PP" << endl; 00633 firstCol=TRUE; paragraph=TRUE; 00634 col=0; 00635 } 00636 paragraph=FALSE; 00637 startBold(); 00638 docify(title); 00639 endBold(); 00640 paragraph=TRUE; 00641 } 00642 00643 void ManGenerator::endParamList() 00644 { 00645 } 00646 00647 void ManGenerator::printDoc(DocNode *n,const char *langExt) 00648 { 00649 ManDocVisitor *visitor = new ManDocVisitor(t,*this,langExt); 00650 n->accept(visitor); 00651 delete visitor; 00652 firstCol=FALSE; 00653 paragraph = FALSE; 00654 } 00655 00656 void ManGenerator::startConstraintList(const char *header) 00657 { 00658 if (!firstCol) 00659 { t << endl << ".PP" << endl; 00660 firstCol=TRUE; paragraph=TRUE; 00661 col=0; 00662 } 00663 paragraph=FALSE; 00664 startBold(); 00665 docify(header); 00666 endBold(); 00667 paragraph=TRUE; 00668 } 00669 00670 void ManGenerator::startConstraintParam() 00671 { 00672 writeListItem(); 00673 startEmphasis(); 00674 } 00675 00676 void ManGenerator::endConstraintParam() 00677 { 00678 endEmphasis(); 00679 t << " : "; 00680 } 00681 00682 void ManGenerator::startConstraintType() 00683 { 00684 startEmphasis(); 00685 } 00686 00687 void ManGenerator::endConstraintType() 00688 { 00689 endEmphasis(); 00690 } 00691 00692 void ManGenerator::startConstraintDocs() 00693 { 00694 } 00695 00696 void ManGenerator::endConstraintDocs() 00697 { 00698 t << endl; firstCol=TRUE; 00699 } 00700 00701 void ManGenerator::endConstraintList() 00702 { 00703 } 00704 00705 00706