cmDocumentation.cxx 30 KB

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