cmDocumentation.cxx 36 KB

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