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