cmDocumentation.cxx 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041
  1. /*=========================================================================
  2. Program: CMake - Cross-Platform Makefile Generator
  3. Module: $RCSfile$
  4. Language: C++
  5. Date: $Date$
  6. Version: $Revision$
  7. Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
  8. See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
  9. This software is distributed WITHOUT ANY WARRANTY; without even
  10. the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  11. PURPOSE. See the above copyright notices for more information.
  12. =========================================================================*/
  13. #include "cmDocumentation.h"
  14. #include "cmSystemTools.h"
  15. #include "cmVersion.h"
  16. //----------------------------------------------------------------------------
  17. static const cmDocumentationEntry cmDocumentationStandardOptions[] =
  18. {
  19. {"--copyright [file]", "Print the CMake copyright and exit.",
  20. "If a file is specified, the copyright is written into it."},
  21. {"--help", "Print usage information and exit.",
  22. "Usage describes the basic command line interface and its options."},
  23. {"--help-full [file]", "Print full help and exit.",
  24. "Full help displays most of the documentation provided by the UNIX "
  25. "man page. It is provided for use on non-UNIX platforms, but is "
  26. "also convenient if the man page is not installed. If a file is "
  27. "specified, the help is written into it."},
  28. {"--help-html [file]", "Print full help in HTML format.",
  29. "This option is used by CMake authors to help produce web pages. "
  30. "If a file is specified, the help is written into it."},
  31. {"--help-man [file]", "Print a UNIX man page and exit.",
  32. "This option is used by the cmake build to generate the UNIX man page. "
  33. "If a file is specified, the help is written into it."},
  34. {"--version [file]", "Show program name/version banner and exit.",
  35. "If a file is specified, the version is written into it."},
  36. {0,0,0}
  37. };
  38. //----------------------------------------------------------------------------
  39. static const cmDocumentationEntry cmDocumentationCommandsHeader[] =
  40. {
  41. {0,
  42. "The following commands are available in CMakeLists.txt code:", 0},
  43. {0,0,0}
  44. };
  45. //----------------------------------------------------------------------------
  46. static const cmDocumentationEntry cmDocumentationGeneratorsHeader[] =
  47. {
  48. {0,
  49. "The following generators are available on this platform:", 0},
  50. {0,0,0}
  51. };
  52. //----------------------------------------------------------------------------
  53. const cmDocumentationEntry cmDocumentationMailingList[] =
  54. {
  55. {0,
  56. "For help and discussion about using cmake, a mailing list is provided "
  57. "at [email protected]. Please first read the full documentation at "
  58. "http://www.cmake.org before posting questions to the list.", 0},
  59. {0,0,0}
  60. };
  61. //----------------------------------------------------------------------------
  62. const cmDocumentationEntry cmDocumentationAuthor[] =
  63. {
  64. {0,
  65. "This manual page was generated by the \"--help-man\" option.", 0},
  66. {0,0,0}
  67. };
  68. //----------------------------------------------------------------------------
  69. const cmDocumentationEntry cmDocumentationCopyright[] =
  70. {
  71. {0,
  72. "Copyright (c) 2002 Kitware, Inc., Insight Consortium. "
  73. "All rights reserved.", 0},
  74. {0,
  75. "Redistribution and use in source and binary forms, with or without "
  76. "modification, are permitted provided that the following conditions are "
  77. "met:", 0},
  78. {"",
  79. "Redistributions of source code must retain the above copyright notice, "
  80. "this list of conditions and the following disclaimer.", 0},
  81. {"",
  82. "Redistributions in binary form must reproduce the above copyright "
  83. "notice, this list of conditions and the following disclaimer in the "
  84. "documentation and/or other materials provided with the distribution.",
  85. 0},
  86. {"",
  87. "The names of Kitware, Inc., the Insight Consortium, or the names of "
  88. "any consortium members, or of any contributors, may not be used to "
  89. "endorse or promote products derived from this software without "
  90. "specific prior written permission.", 0},
  91. {"",
  92. "Modified source versions must be plainly marked as such, and must "
  93. "not be misrepresented as being the original software.", 0},
  94. {0,
  95. "THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "
  96. "``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT "
  97. "LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR "
  98. "A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR "
  99. "CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, "
  100. "EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, "
  101. "PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR "
  102. "PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF "
  103. "LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING "
  104. "NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS "
  105. "SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.", 0},
  106. {0, 0, 0}
  107. };
  108. //----------------------------------------------------------------------------
  109. cmDocumentation::cmDocumentation()
  110. {
  111. this->CurrentForm = TextForm;
  112. this->TextIndent = "";
  113. this->TextWidth = 77;
  114. }
  115. //----------------------------------------------------------------------------
  116. bool cmDocumentation::PrintCopyright(std::ostream& os)
  117. {
  118. for(const cmDocumentationEntry* op = cmDocumentationCopyright;
  119. op->brief; ++op)
  120. {
  121. if(op->name)
  122. {
  123. os << " * ";
  124. this->TextIndent = " ";
  125. this->PrintColumn(os, op->brief);
  126. }
  127. else
  128. {
  129. this->TextIndent = "";
  130. this->PrintColumn(os, op->brief);
  131. }
  132. os << "\n";
  133. }
  134. return true;
  135. }
  136. //----------------------------------------------------------------------------
  137. bool cmDocumentation::PrintVersion(std::ostream& os)
  138. {
  139. os << this->GetNameString() << " version " << cmVersion::GetCMakeVersion() << "\n";
  140. return true;
  141. }
  142. //----------------------------------------------------------------------------
  143. void cmDocumentation::AddSection(const char* name,
  144. const cmDocumentationEntry* d)
  145. {
  146. this->Names.push_back(name);
  147. this->Sections.push_back(d);
  148. }
  149. //----------------------------------------------------------------------------
  150. void cmDocumentation::ClearSections()
  151. {
  152. this->Names.erase(this->Names.begin(), this->Names.end());
  153. this->Sections.erase(this->Sections.begin(), this->Sections.end());
  154. }
  155. //----------------------------------------------------------------------------
  156. bool cmDocumentation::PrintDocumentation(Type ht, std::ostream& os)
  157. {
  158. if ( ht != cmDocumentation::HTML &&
  159. ht != cmDocumentation::Man )
  160. {
  161. this->PrintVersion(os);
  162. }
  163. switch (ht)
  164. {
  165. case cmDocumentation::Usage: return this->PrintDocumentationUsage(os);
  166. case cmDocumentation::Single: return this->PrintDocumentationSingle(os);
  167. case cmDocumentation::List: return this->PrintDocumentationList(os);
  168. case cmDocumentation::Full: return this->PrintDocumentationFull(os);
  169. case cmDocumentation::HTML: return this->PrintDocumentationHTML(os);
  170. case cmDocumentation::Man: return this->PrintDocumentationMan(os);
  171. case cmDocumentation::Copyright: return this->PrintCopyright(os);
  172. case cmDocumentation::Version: return true;
  173. default: return false;
  174. }
  175. }
  176. //----------------------------------------------------------------------------
  177. bool cmDocumentation::PrintRequestedDocumentation(std::ostream& os)
  178. {
  179. bool result = true;
  180. // Loop over requested documentation types.
  181. for(RequestedMapType::const_iterator i = this->RequestedMap.begin();
  182. i != this->RequestedMap.end(); ++i)
  183. {
  184. // Special case for printing help for a single command.
  185. if(i->first == cmDocumentation::Usage && i->second.length() > 0 &&
  186. !this->CommandsSection.empty())
  187. {
  188. // Check if the argument to the usage request was a command.
  189. for(cmDocumentationEntry* entry = &this->CommandsSection[0];
  190. entry->brief; ++entry)
  191. {
  192. if(entry->name && (strcmp(entry->name, i->second.c_str()) == 0))
  193. {
  194. this->PrintDocumentationCommand(os, entry);
  195. return true;
  196. }
  197. }
  198. // Argument was not a command. Complain.
  199. os << "Help argument \"" << i->second.c_str()
  200. << "\" is not a CMake command. "
  201. << "Use --help-command-list to see all commands.\n";
  202. return false;
  203. }
  204. // If a file name was given, use it. Otherwise, default to the
  205. // given stream.
  206. std::ofstream* fout = 0;
  207. std::ostream* s = &os;
  208. if(i->second.length() > 0)
  209. {
  210. fout = new std::ofstream(i->second.c_str(), std::ios::out);
  211. if(fout)
  212. {
  213. s = fout;
  214. }
  215. else
  216. {
  217. result = false;
  218. }
  219. }
  220. // Print this documentation type to the stream.
  221. if(!this->PrintDocumentation(i->first, *s) || !*s)
  222. {
  223. result = false;
  224. }
  225. // Close the file if we wrote one.
  226. if(fout)
  227. {
  228. delete fout;
  229. }
  230. }
  231. return result;
  232. }
  233. //----------------------------------------------------------------------------
  234. bool cmDocumentation::CheckOptions(int argc, const char* const* argv)
  235. {
  236. // Providing zero arguments gives usage information.
  237. if(argc == 1)
  238. {
  239. this->RequestedMap[cmDocumentation::Usage] = "";
  240. return true;
  241. }
  242. // Search for supported help options.
  243. bool result = false;
  244. for(int i=1; i < argc; ++i)
  245. {
  246. // Check if this is a supported help option.
  247. Type type = cmDocumentation::None;
  248. if((strcmp(argv[i], "-help") == 0) ||
  249. (strcmp(argv[i], "--help") == 0) ||
  250. (strcmp(argv[i], "/?") == 0) ||
  251. (strcmp(argv[i], "-usage") == 0) ||
  252. (strcmp(argv[i], "-h") == 0) ||
  253. (strcmp(argv[i], "-H") == 0))
  254. {
  255. type = cmDocumentation::Usage;
  256. }
  257. else if(strcmp(argv[i], "--help-full") == 0)
  258. {
  259. type = cmDocumentation::Full;
  260. }
  261. else if(strcmp(argv[i], "--help-html") == 0)
  262. {
  263. type = cmDocumentation::HTML;
  264. }
  265. else if(strcmp(argv[i], "--help-man") == 0)
  266. {
  267. type = cmDocumentation::Man;
  268. }
  269. else if(strcmp(argv[i], "--help-command") == 0)
  270. {
  271. type = cmDocumentation::Single;
  272. if((i+1 < argc) && !this->IsOption(argv[i+1]))
  273. {
  274. this->SingleCommand = argv[i+1];
  275. i = i+1;
  276. }
  277. }
  278. else if(strcmp(argv[i], "--help-command-list") == 0)
  279. {
  280. type = cmDocumentation::List;
  281. }
  282. else if(strcmp(argv[i], "--copyright") == 0)
  283. {
  284. type = cmDocumentation::Copyright;
  285. }
  286. else if((strcmp(argv[i], "--version") == 0) ||
  287. (strcmp(argv[i], "-version") == 0) ||
  288. (strcmp(argv[i], "/V") == 0))
  289. {
  290. type = cmDocumentation::Version;
  291. }
  292. if(type)
  293. {
  294. // This is a help option. See if there is a file name given.
  295. result = true;
  296. if((i+1 < argc) && !this->IsOption(argv[i+1]))
  297. {
  298. this->RequestedMap[type] = argv[i+1];
  299. i = i+1;
  300. }
  301. else
  302. {
  303. this->RequestedMap[type] = "";
  304. }
  305. }
  306. }
  307. return result;
  308. }
  309. //----------------------------------------------------------------------------
  310. void cmDocumentation::Print(Form f, std::ostream& os)
  311. {
  312. this->CurrentForm = f;
  313. for(unsigned int i=0; i < this->Sections.size(); ++i)
  314. {
  315. this->PrintSection(os, this->Sections[i], this->Names[i]);
  316. }
  317. }
  318. //----------------------------------------------------------------------------
  319. void cmDocumentation::SetName(const char* name)
  320. {
  321. this->NameString = name?name:"";
  322. }
  323. //----------------------------------------------------------------------------
  324. void cmDocumentation::SetNameSection(const cmDocumentationEntry* section)
  325. {
  326. this->SetSection(0, section, 0, this->NameSection);
  327. }
  328. //----------------------------------------------------------------------------
  329. void cmDocumentation::SetUsageSection(const cmDocumentationEntry* section)
  330. {
  331. this->SetSection(0, section, 0, this->UsageSection);
  332. }
  333. //----------------------------------------------------------------------------
  334. void cmDocumentation::SetDescriptionSection(const cmDocumentationEntry* section)
  335. {
  336. this->SetSection(0, section, 0, this->DescriptionSection);
  337. }
  338. //----------------------------------------------------------------------------
  339. void cmDocumentation::SetOptionsSection(const cmDocumentationEntry* section)
  340. {
  341. this->SetSection(0, section, cmDocumentationStandardOptions,
  342. this->OptionsSection);
  343. }
  344. //----------------------------------------------------------------------------
  345. void cmDocumentation::SetCommandsSection(const cmDocumentationEntry* section)
  346. {
  347. this->SetSection(cmDocumentationCommandsHeader, section, 0,
  348. this->CommandsSection);
  349. }
  350. //----------------------------------------------------------------------------
  351. void cmDocumentation::SetGeneratorsSection(const cmDocumentationEntry* section)
  352. {
  353. this->SetSection(cmDocumentationGeneratorsHeader, section, 0,
  354. this->GeneratorsSection);
  355. }
  356. //----------------------------------------------------------------------------
  357. void cmDocumentation::SetSeeAlsoList(const cmDocumentationEntry* also)
  358. {
  359. this->SeeAlsoString = ".B ";
  360. for(const cmDocumentationEntry* i = also; i->brief; ++i)
  361. {
  362. this->SeeAlsoString += i->brief;
  363. this->SeeAlsoString += (i+1)->brief? "(1), ":"(1)";
  364. }
  365. cmDocumentationEntry e = {0, 0, 0};
  366. e.brief = this->SeeAlsoString.c_str();
  367. this->SeeAlsoSection.push_back(e);
  368. e.brief = 0;
  369. this->SeeAlsoSection.push_back(e);
  370. }
  371. //----------------------------------------------------------------------------
  372. void cmDocumentation::PrintSection(std::ostream& os,
  373. const cmDocumentationEntry* section,
  374. const char* name)
  375. {
  376. switch (this->CurrentForm)
  377. {
  378. case TextForm: this->PrintSectionText(os, section, name); break;
  379. case HTMLForm: this->PrintSectionHTML(os, section, name); break;
  380. case ManForm: this->PrintSectionMan(os, section, name); break;
  381. case UsageForm: this->PrintSectionUsage(os, section, name); break;
  382. }
  383. }
  384. //----------------------------------------------------------------------------
  385. void cmDocumentation::PrintSectionText(std::ostream& os,
  386. const cmDocumentationEntry* section,
  387. const char* name)
  388. {
  389. if(name)
  390. {
  391. os <<
  392. "---------------------------------------"
  393. "---------------------------------------\n";
  394. os << name << "\n\n";
  395. }
  396. if(!section) { return; }
  397. for(const cmDocumentationEntry* op = section; op->brief; ++op)
  398. {
  399. if(op->name)
  400. {
  401. if(op->name[0])
  402. {
  403. os << " " << op->name << "\n";
  404. }
  405. this->TextIndent = " ";
  406. this->PrintFormatted(os, op->brief);
  407. if(op->full)
  408. {
  409. os << "\n";
  410. this->PrintFormatted(os, op->full);
  411. }
  412. }
  413. else
  414. {
  415. this->TextIndent = "";
  416. this->PrintFormatted(os, op->brief);
  417. }
  418. os << "\n";
  419. }
  420. }
  421. //----------------------------------------------------------------------------
  422. void cmDocumentation::PrintSectionHTML(std::ostream& os,
  423. const cmDocumentationEntry* section,
  424. const char* name)
  425. {
  426. if(name)
  427. {
  428. os << "<h2>" << name << "</h2>\n";
  429. }
  430. if(!section) { return; }
  431. for(const cmDocumentationEntry* op = section; op->brief;)
  432. {
  433. if(op->name)
  434. {
  435. os << "<ul>\n";
  436. for(;op->name;++op)
  437. {
  438. os << " <li>\n";
  439. if(op->name[0])
  440. {
  441. os << " <b><code>";
  442. this->PrintHTMLEscapes(os, op->name);
  443. os << "</code></b>: ";
  444. }
  445. this->PrintHTMLEscapes(os, op->brief);
  446. if(op->full)
  447. {
  448. os << "<br>\n ";
  449. this->PrintFormatted(os, op->full);
  450. }
  451. os << "\n";
  452. os << " </li>\n";
  453. }
  454. os << "</ul>\n";
  455. }
  456. else
  457. {
  458. this->PrintFormatted(os, op->brief);
  459. os << "\n";
  460. ++op;
  461. }
  462. }
  463. }
  464. //----------------------------------------------------------------------------
  465. void cmDocumentation::PrintSectionMan(std::ostream& os,
  466. const cmDocumentationEntry* section,
  467. const char* name)
  468. {
  469. if(name)
  470. {
  471. os << ".SH " << name << "\n";
  472. }
  473. if(!section) { return; }
  474. for(const cmDocumentationEntry* op = section; op->brief; ++op)
  475. {
  476. if(op->name)
  477. {
  478. os << ".TP\n"
  479. << ".B " << (op->name[0]?op->name:"*") << "\n";
  480. this->PrintFormatted(os, op->brief);
  481. this->PrintFormatted(os, op->full);
  482. }
  483. else
  484. {
  485. os << ".PP\n";
  486. this->PrintFormatted(os, op->brief);
  487. }
  488. }
  489. }
  490. //----------------------------------------------------------------------------
  491. void cmDocumentation::PrintSectionUsage(std::ostream& os,
  492. const cmDocumentationEntry* section,
  493. const char* name)
  494. {
  495. if(name)
  496. {
  497. os << name << "\n";
  498. }
  499. if(!section) { return; }
  500. for(const cmDocumentationEntry* op = section; op->brief; ++op)
  501. {
  502. if(op->name)
  503. {
  504. os << " " << op->name;
  505. this->TextIndent = " ";
  506. int align = static_cast<int>(strlen(this->TextIndent))-4;
  507. for(int i = static_cast<int>(strlen(op->name)); i < align; ++i)
  508. {
  509. os << " ";
  510. }
  511. os << "= ";
  512. this->PrintColumn(os, op->brief);
  513. os << "\n";
  514. }
  515. else
  516. {
  517. os << "\n";
  518. this->TextIndent = "";
  519. this->PrintFormatted(os, op->brief);
  520. }
  521. }
  522. os << "\n";
  523. }
  524. //----------------------------------------------------------------------------
  525. void cmDocumentation::PrintFormatted(std::ostream& os, const char* text)
  526. {
  527. if(!text)
  528. {
  529. return;
  530. }
  531. const char* ptr = text;
  532. while(*ptr)
  533. {
  534. // Any ptrs starting in a space are treated as preformatted text.
  535. std::string preformatted;
  536. while(*ptr == ' ')
  537. {
  538. for(char ch = *ptr; ch && ch != '\n'; ++ptr, ch = *ptr)
  539. {
  540. preformatted.append(1, ch);
  541. }
  542. if(*ptr)
  543. {
  544. ++ptr;
  545. preformatted.append(1, '\n');
  546. }
  547. }
  548. if(preformatted.length())
  549. {
  550. this->PrintPreformatted(os, preformatted.c_str());
  551. }
  552. // Other ptrs are treated as paragraphs.
  553. std::string paragraph;
  554. for(char ch = *ptr; ch && ch != '\n'; ++ptr, ch = *ptr)
  555. {
  556. paragraph.append(1, ch);
  557. }
  558. if(*ptr)
  559. {
  560. ++ptr;
  561. paragraph.append(1, '\n');
  562. }
  563. if(paragraph.length())
  564. {
  565. this->PrintParagraph(os, paragraph.c_str());
  566. }
  567. }
  568. }
  569. //----------------------------------------------------------------------------
  570. void cmDocumentation::PrintPreformatted(std::ostream& os, const char* text)
  571. {
  572. switch (this->CurrentForm)
  573. {
  574. case TextForm: this->PrintPreformattedText(os, text); break;
  575. case HTMLForm: this->PrintPreformattedHTML(os, text); break;
  576. case ManForm: this->PrintPreformattedMan(os, text); break;
  577. case UsageForm: this->PrintPreformattedText(os, text); break;
  578. }
  579. }
  580. //----------------------------------------------------------------------------
  581. void cmDocumentation::PrintParagraph(std::ostream& os, const char* text)
  582. {
  583. switch (this->CurrentForm)
  584. {
  585. case TextForm: this->PrintParagraphText(os, text); break;
  586. case HTMLForm: this->PrintParagraphHTML(os, text); break;
  587. case ManForm: this->PrintParagraphMan(os, text); break;
  588. case UsageForm: this->PrintParagraphText(os, text); break;
  589. }
  590. }
  591. //----------------------------------------------------------------------------
  592. void cmDocumentation::PrintPreformattedText(std::ostream& os, const char* text)
  593. {
  594. bool newline = true;
  595. for(const char* ptr = text; *ptr; ++ptr)
  596. {
  597. if(newline)
  598. {
  599. os << this->TextIndent;
  600. newline = false;
  601. }
  602. os << *ptr;
  603. if(*ptr == '\n')
  604. {
  605. newline = true;
  606. }
  607. }
  608. os << "\n";
  609. }
  610. //----------------------------------------------------------------------------
  611. void cmDocumentation::PrintParagraphText(std::ostream& os, const char* text)
  612. {
  613. os << this->TextIndent;
  614. this->PrintColumn(os, text);
  615. os << "\n";
  616. }
  617. //----------------------------------------------------------------------------
  618. void cmDocumentation::PrintPreformattedHTML(std::ostream& os, const char* text)
  619. {
  620. os << "<pre>";
  621. this->PrintHTMLEscapes(os, text);
  622. os << "</pre>\n ";
  623. }
  624. //----------------------------------------------------------------------------
  625. void cmDocumentation::PrintParagraphHTML(std::ostream& os, const char* text)
  626. {
  627. os << "<p>";
  628. this->PrintHTMLEscapes(os, text);
  629. }
  630. //----------------------------------------------------------------------------
  631. void cmDocumentation::PrintPreformattedMan(std::ostream& os, const char* text)
  632. {
  633. os << text << "\n";
  634. }
  635. //----------------------------------------------------------------------------
  636. void cmDocumentation::PrintParagraphMan(std::ostream& os, const char* text)
  637. {
  638. os << text << "\n\n";
  639. }
  640. //----------------------------------------------------------------------------
  641. void cmDocumentation::PrintColumn(std::ostream& os, const char* text)
  642. {
  643. // Print text arranged in an indented column of fixed witdh.
  644. const char* l = text;
  645. int column = 0;
  646. bool newSentence = false;
  647. bool firstLine = true;
  648. int width = this->TextWidth - static_cast<int>(strlen(this->TextIndent));
  649. // Loop until the end of the text.
  650. while(*l)
  651. {
  652. // Parse the next word.
  653. const char* r = l;
  654. while(*r && (*r != '\n') && (*r != ' ')) { ++r; }
  655. // Does it fit on this line?
  656. if(r-l < (width-column-(newSentence?1:0)))
  657. {
  658. // Word fits on this line.
  659. if(r > l)
  660. {
  661. if(column)
  662. {
  663. // Not first word on line. Separate from the previous word
  664. // by a space, or two if this is a new sentence.
  665. if(newSentence)
  666. {
  667. os << " ";
  668. column += 2;
  669. }
  670. else
  671. {
  672. os << " ";
  673. column += 1;
  674. }
  675. }
  676. else
  677. {
  678. // First word on line. Print indentation unless this is the
  679. // first line.
  680. os << (firstLine?"":this->TextIndent);
  681. }
  682. // Print the word.
  683. os.write(l, static_cast<long>(r-l));
  684. newSentence = (*(r-1) == '.');
  685. }
  686. if(*r == '\n')
  687. {
  688. // Text provided a newline. Start a new line.
  689. os << "\n";
  690. ++r;
  691. column = 0;
  692. firstLine = false;
  693. }
  694. else
  695. {
  696. // No provided newline. Continue this line.
  697. column += static_cast<long>(r-l);
  698. }
  699. }
  700. else
  701. {
  702. // Word does not fit on this line. Start a new line.
  703. os << "\n";
  704. firstLine = false;
  705. if(r > l)
  706. {
  707. os << this->TextIndent;
  708. os.write(l, static_cast<long>(r-l));
  709. column = static_cast<long>(r-l);
  710. newSentence = (*(r-1) == '.');
  711. }
  712. }
  713. // Move to beginning of next word. Skip over whitespace.
  714. l = r;
  715. while(*l && (*l == ' ')) { ++l; }
  716. }
  717. }
  718. //----------------------------------------------------------------------------
  719. void cmDocumentation::PrintHTMLEscapes(std::ostream& os, const char* text)
  720. {
  721. static cmDocumentationEntry escapes[] =
  722. {
  723. {"<", "&lt;", 0},
  724. {">", "&gt;", 0},
  725. {"&", "&amp;", 0},
  726. {"\n", "<br>", 0},
  727. {0,0,0}
  728. };
  729. for(const char* p = text; *p; ++p)
  730. {
  731. bool found = false;
  732. for(const cmDocumentationEntry* op = escapes; !found && op->name; ++op)
  733. {
  734. if(op->name[0] == *p)
  735. {
  736. os << op->brief;
  737. found = true;
  738. }
  739. }
  740. if(!found)
  741. {
  742. os << *p;
  743. }
  744. }
  745. }
  746. //----------------------------------------------------------------------------
  747. bool cmDocumentation::PrintDocumentationSingle(std::ostream& os)
  748. {
  749. if(this->CommandsSection.empty())
  750. {
  751. os << "Internal error: commands list is empty." << std::endl;
  752. return false;
  753. }
  754. if(this->SingleCommand.length() == 0)
  755. {
  756. os << "Argument --help-command needs a command name.\n";
  757. return false;
  758. }
  759. for(cmDocumentationEntry* entry = &this->CommandsSection[0];
  760. entry->brief; ++entry)
  761. {
  762. if(entry->name && this->SingleCommand == entry->name)
  763. {
  764. this->PrintDocumentationCommand(os, entry);
  765. return true;
  766. }
  767. }
  768. // Argument was not a command. Complain.
  769. os << "Argument \"" << this->SingleCommand.c_str()
  770. << "\" to --help-command is not a CMake command. "
  771. << "Use --help-command-list to see all commands.\n";
  772. return false;
  773. }
  774. //----------------------------------------------------------------------------
  775. bool cmDocumentation::PrintDocumentationList(std::ostream& os)
  776. {
  777. if(this->CommandsSection.empty())
  778. {
  779. os << "Internal error: commands list is empty." << std::endl;
  780. return false;
  781. }
  782. for(cmDocumentationEntry* entry = &this->CommandsSection[0];
  783. entry->brief; ++entry)
  784. {
  785. if(entry->name)
  786. {
  787. os << entry->name << std::endl;
  788. }
  789. }
  790. return true;
  791. }
  792. //----------------------------------------------------------------------------
  793. bool cmDocumentation::PrintDocumentationUsage(std::ostream& os)
  794. {
  795. this->CreateUsageDocumentation();
  796. this->Print(UsageForm, os);
  797. return true;
  798. }
  799. //----------------------------------------------------------------------------
  800. bool cmDocumentation::PrintDocumentationFull(std::ostream& os)
  801. {
  802. this->CreateFullDocumentation();
  803. this->Print(TextForm, os);
  804. return true;
  805. }
  806. //----------------------------------------------------------------------------
  807. bool cmDocumentation::PrintDocumentationHTML(std::ostream& os)
  808. {
  809. this->CreateFullDocumentation();
  810. os << "<html><body>\n";
  811. this->Print(HTMLForm, os);
  812. os << "</body></html>\n";
  813. return true;
  814. }
  815. //----------------------------------------------------------------------------
  816. bool cmDocumentation::PrintDocumentationMan(std::ostream& os)
  817. {
  818. this->CreateManDocumentation();
  819. os << ".TH " << this->GetNameString() << " 1 \""
  820. << cmSystemTools::GetCurrentDateTime("%B %d, %Y").c_str()
  821. << "\" \"" << this->GetNameString() << " " << cmVersion::GetCMakeVersion()
  822. << "\"\n";
  823. this->Print(ManForm, os);
  824. return true;
  825. }
  826. //----------------------------------------------------------------------------
  827. void cmDocumentation::PrintDocumentationCommand(std::ostream& os,
  828. cmDocumentationEntry* entry)
  829. {
  830. cmDocumentationEntry singleCommandSection[3] =
  831. {
  832. {entry->name, entry->brief, entry->full},
  833. {0,0,0}
  834. };
  835. this->ClearSections();
  836. this->AddSection(0, &singleCommandSection[0]);
  837. this->Print(TextForm, os);
  838. }
  839. //----------------------------------------------------------------------------
  840. void cmDocumentation::CreateUsageDocumentation()
  841. {
  842. this->ClearSections();
  843. if(!this->UsageSection.empty())
  844. {
  845. this->AddSection("Usage", &this->UsageSection[0]);
  846. }
  847. if(!this->OptionsSection.empty())
  848. {
  849. this->AddSection("Command-Line Options", &this->OptionsSection[0]);
  850. }
  851. if(!this->GeneratorsSection.empty())
  852. {
  853. this->AddSection("Generators", &this->GeneratorsSection[0]);
  854. }
  855. }
  856. //----------------------------------------------------------------------------
  857. void cmDocumentation::CreateFullDocumentation()
  858. {
  859. this->ClearSections();
  860. if(!this->NameSection.empty())
  861. {
  862. this->AddSection("Name", &this->NameSection[0]);
  863. }
  864. if(!this->UsageSection.empty())
  865. {
  866. this->AddSection("Usage", &this->UsageSection[0]);
  867. }
  868. if(!this->DescriptionSection.empty())
  869. {
  870. this->AddSection(0, &this->DescriptionSection[0]);
  871. }
  872. if(!this->OptionsSection.empty())
  873. {
  874. this->AddSection("Command-Line Options", &this->OptionsSection[0]);
  875. }
  876. if(!this->GeneratorsSection.empty())
  877. {
  878. this->AddSection("Generators", &this->GeneratorsSection[0]);
  879. }
  880. if(!this->CommandsSection.empty())
  881. {
  882. this->AddSection("Listfile Commands", &this->CommandsSection[0]);
  883. }
  884. this->AddSection("Copyright", cmDocumentationCopyright);
  885. this->AddSection("Mailing List", cmDocumentationMailingList);
  886. }
  887. //----------------------------------------------------------------------------
  888. void cmDocumentation::CreateManDocumentation()
  889. {
  890. this->ClearSections();
  891. if(!this->NameSection.empty())
  892. {
  893. this->AddSection("NAME", &this->NameSection[0]);
  894. }
  895. if(!this->UsageSection.empty())
  896. {
  897. this->AddSection("SYNOPSIS", &this->UsageSection[0]);
  898. }
  899. if(!this->DescriptionSection.empty())
  900. {
  901. this->AddSection("DESCRIPTION", &this->DescriptionSection[0]);
  902. }
  903. if(!this->OptionsSection.empty())
  904. {
  905. this->AddSection("OPTIONS", &this->OptionsSection[0]);
  906. }
  907. if(!this->GeneratorsSection.empty())
  908. {
  909. this->AddSection("GENERATORS", &this->GeneratorsSection[0]);
  910. }
  911. if(!this->CommandsSection.empty())
  912. {
  913. this->AddSection("COMMANDS", &this->CommandsSection[0]);
  914. }
  915. this->AddSection("COPYRIGHT", cmDocumentationCopyright);
  916. this->AddSection("MAILING LIST", cmDocumentationMailingList);
  917. if(!this->SeeAlsoSection.empty())
  918. {
  919. this->AddSection("SEE ALSO", &this->SeeAlsoSection[0]);
  920. }
  921. this->AddSection("AUTHOR", cmDocumentationAuthor);
  922. }
  923. //----------------------------------------------------------------------------
  924. void cmDocumentation::SetSection(const cmDocumentationEntry* header,
  925. const cmDocumentationEntry* section,
  926. const cmDocumentationEntry* footer,
  927. std::vector<cmDocumentationEntry>& vec)
  928. {
  929. vec.erase(vec.begin(), vec.end());
  930. if(header)
  931. {
  932. for(const cmDocumentationEntry* op = header; op->brief; ++op)
  933. {
  934. vec.push_back(*op);
  935. }
  936. }
  937. if(section)
  938. {
  939. for(const cmDocumentationEntry* op = section; op->brief; ++op)
  940. {
  941. vec.push_back(*op);
  942. }
  943. }
  944. if(footer)
  945. {
  946. for(const cmDocumentationEntry* op = footer; op->brief; ++op)
  947. {
  948. vec.push_back(*op);
  949. }
  950. }
  951. cmDocumentationEntry empty = {0,0,0};
  952. vec.push_back(empty);
  953. }
  954. //----------------------------------------------------------------------------
  955. const char* cmDocumentation::GetNameString()
  956. {
  957. if(this->NameString.length() > 0)
  958. {
  959. return this->NameString.c_str();
  960. }
  961. else
  962. {
  963. return "CMake";
  964. }
  965. }
  966. //----------------------------------------------------------------------------
  967. bool cmDocumentation::IsOption(const char* arg)
  968. {
  969. return ((arg[0] == '-') ||
  970. (strcmp(arg, "/V") == 0) ||
  971. (strcmp(arg, "/?") == 0));
  972. }