cmDocumentation.cxx 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542
  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", "Print the CMake copyright and exit.", 0},
  19. {"--usage", "Print usage information and exit.",
  20. "Usage describes the basic command line interface and its options."},
  21. {"--help", "Print full help and exit.",
  22. "Full help displays most of the documentation provided by the UNIX "
  23. "man page. It is provided for use on non-UNIX platforms, but is "
  24. "also convenient if the man page is not installed."},
  25. {"--help-html", "Print full help in HTML format.",
  26. "This option is used by CMake authors to help produce web pages."},
  27. {"--man", "Print a UNIX man page and exit.",
  28. "This option is used by CMake authors to generate the UNIX man page."},
  29. {"--version", "Show program name/version banner and exit.", 0},
  30. {0,0,0}
  31. };
  32. //----------------------------------------------------------------------------
  33. const cmDocumentationEntry cmDocumentationCopyright[] =
  34. {
  35. {0,
  36. "Copyright (c) 2002 Kitware, Inc., Insight Consortium.\n"
  37. "All rights reserved.\n", 0},
  38. {0,
  39. "Redistribution and use in source and binary forms, with or without "
  40. "modification, are permitted provided that the following conditions are "
  41. "met:\n", 0},
  42. {" * ",
  43. "Redistributions of source code must retain the above copyright notice, "
  44. "this list of conditions and the following disclaimer.\n", 0},
  45. {" * ",
  46. "Redistributions in binary form must reproduce the above copyright "
  47. "notice, this list of conditions and the following disclaimer in the "
  48. "documentation and/or other materials provided with the distribution.\n",
  49. 0},
  50. {" * ",
  51. "The names of Kitware, Inc., the Insight Consortium, or the names of "
  52. "any consortium members, or of any contributors, may not be used to "
  53. "endorse or promote products derived from this software without "
  54. "specific prior written permission.\n", 0},
  55. {" * ",
  56. "Modified source versions must be plainly marked as such, and must "
  57. "not be misrepresented as being the original software.\n", 0},
  58. {0,
  59. "THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "
  60. "``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT "
  61. "LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR "
  62. "A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR "
  63. "CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, "
  64. "EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, "
  65. "PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR "
  66. "PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF "
  67. "LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING "
  68. "NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS "
  69. "SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n", 0},
  70. {0, 0, 0}
  71. };
  72. //----------------------------------------------------------------------------
  73. cmDocumentation::cmDocumentation()
  74. {
  75. this->Commands = 0;
  76. this->Description = 0;
  77. this->Name = 0;
  78. this->UsageHelp = 0;
  79. this->SetOptions(0);
  80. }
  81. //----------------------------------------------------------------------------
  82. void cmDocumentation::PrintManSection(std::ostream& os,
  83. const cmDocumentationEntry* section,
  84. const char* name)
  85. {
  86. if(!section) { return; }
  87. os << ".SH " << name << "\n";
  88. for(const cmDocumentationEntry* op = section; op->brief; ++op)
  89. {
  90. if(op->name)
  91. {
  92. os << ".TP\n"
  93. << ".B " << op->name << "\n"
  94. << op->brief << "\n\n";
  95. if(op->full) { os << op->full << "\n"; }
  96. }
  97. else
  98. {
  99. os << ".PP\n"
  100. << op->brief << "\n";
  101. }
  102. }
  103. }
  104. //----------------------------------------------------------------------------
  105. void cmDocumentation::PrintHelpSection(std::ostream& os,
  106. const cmDocumentationEntry* section)
  107. {
  108. if(!section) { return; }
  109. for(const cmDocumentationEntry* op = section; op->brief; ++op)
  110. {
  111. if(op->name)
  112. {
  113. os << " " << op->name << "\n"
  114. << " ";
  115. this->PrintColumn(os, 70, " ", op->brief);
  116. if(op->full)
  117. {
  118. os << "\n"
  119. << "\n"
  120. << " ";
  121. this->PrintColumn(os, 70, " ", op->full);
  122. }
  123. os << "\n";
  124. }
  125. else
  126. {
  127. this->PrintColumn(os, 77, "", op->brief);
  128. os << "\n";
  129. }
  130. os << "\n";
  131. }
  132. }
  133. //----------------------------------------------------------------------------
  134. void cmDocumentation::PrintHTMLEscapes(std::ostream& os, const char* text)
  135. {
  136. static cmDocumentationEntry escapes[] =
  137. {
  138. {"<", "&lt;", 0},
  139. {">", "&gt;", 0},
  140. {"&", "&amp;", 0},
  141. {"\n", "<br>", 0},
  142. {0,0,0}
  143. };
  144. for(const char* p = text; *p; ++p)
  145. {
  146. bool found = false;
  147. for(const cmDocumentationEntry* op = escapes; !found && op->name; ++op)
  148. {
  149. if(op->name[0] == *p)
  150. {
  151. os << op->brief;
  152. found = true;
  153. }
  154. }
  155. if(!found)
  156. {
  157. os << *p;
  158. }
  159. }
  160. }
  161. //----------------------------------------------------------------------------
  162. void cmDocumentation::PrintHTMLFull(std::ostream& os, const char* text)
  163. {
  164. const char* line = text;
  165. while(*line)
  166. {
  167. // Any lines starting in a space are treated as a preformatted
  168. // section.
  169. std::string preformatted;
  170. while(*line == ' ')
  171. {
  172. for(char ch = *line; ch && ch != '\n'; ++line, ch = *line)
  173. {
  174. preformatted.append(1, ch);
  175. }
  176. if(*line)
  177. {
  178. ++line;
  179. preformatted.append(1, '\n');
  180. }
  181. }
  182. if(preformatted.length())
  183. {
  184. os << "<pre>";
  185. this->PrintHTMLEscapes(os, preformatted.c_str());
  186. os << "</pre>";
  187. }
  188. std::string normal;
  189. for(char ch = *line; ch && ch != '\n'; ++line, ch = *line)
  190. {
  191. normal.append(1, ch);
  192. }
  193. if(*line)
  194. {
  195. ++line;
  196. normal.append(1, '\n');
  197. }
  198. if(normal.length())
  199. {
  200. this->PrintHTMLEscapes(os, normal.c_str());
  201. }
  202. }
  203. }
  204. //----------------------------------------------------------------------------
  205. void cmDocumentation::PrintHelpHTMLSection(std::ostream& os,
  206. const cmDocumentationEntry* section,
  207. const char* header)
  208. {
  209. if(!section) { return; }
  210. if(header)
  211. {
  212. os << "<h2>" << header << "</h2>\n";
  213. }
  214. for(const cmDocumentationEntry* op = section; op->brief;)
  215. {
  216. if(op->name)
  217. {
  218. os << "<ul>\n";
  219. for(;op->name;++op)
  220. {
  221. os << " <li>\n";
  222. os << " <b><code>";
  223. this->PrintHTMLEscapes(os, op->name);
  224. os << "</code></b>: ";
  225. this->PrintHTMLEscapes(os, op->brief);
  226. if(op->full)
  227. {
  228. os << "<br>";
  229. this->PrintHTMLFull(os, op->full);
  230. }
  231. os << "\n";
  232. os << " </li>\n";
  233. }
  234. os << "</ul>\n";
  235. }
  236. else
  237. {
  238. this->PrintHTMLEscapes(os, op->brief);
  239. os << "\n";
  240. ++op;
  241. }
  242. }
  243. }
  244. //----------------------------------------------------------------------------
  245. void cmDocumentation::PrintUsageSection(std::ostream& os,
  246. const cmDocumentationEntry* section)
  247. {
  248. if(!section) { return; }
  249. std::ios::fmtflags flags = os.flags();
  250. os.setf(flags | std::ios::left);
  251. for(const cmDocumentationEntry* op = section; op->brief; ++op)
  252. {
  253. if(op->name)
  254. {
  255. os << " ";
  256. os.width(25);
  257. os << op->name << "= " << op->brief << "\n";
  258. }
  259. else
  260. {
  261. os << "\n";
  262. this->PrintColumn(os, 74, "", op->brief);
  263. os << "\n";
  264. }
  265. }
  266. os.setf(flags);
  267. }
  268. //----------------------------------------------------------------------------
  269. void cmDocumentation::PrintUsage(std::ostream& os)
  270. {
  271. os << "Usage:\n";
  272. this->PrintUsageSection(os, this->UsageHelp);
  273. this->PrintUsageSection(os, &this->Options[0]);
  274. }
  275. //----------------------------------------------------------------------------
  276. void cmDocumentation::PrintHelp(std::ostream& os)
  277. {
  278. os << "Usage:\n";
  279. os << "\n";
  280. this->PrintHelpSection(os, this->UsageHelp);
  281. this->PrintHelpSection(os, this->Description);
  282. os << "--------------------------------------------------------------------------\n";
  283. this->PrintHelpSection(os, &this->Options[0]);
  284. os << "--------------------------------------------------------------------------\n";
  285. this->PrintHelpSection(os, this->Commands);
  286. }
  287. //----------------------------------------------------------------------------
  288. void cmDocumentation::PrintHelpHTML(std::ostream& os)
  289. {
  290. os << "<html>\n"
  291. << "<body>\n";
  292. os << "<h2>Using CMake</h2>\n";
  293. if(this->UsageHelp)
  294. {
  295. os << "<blockquote><code>\n";
  296. this->PrintHelpHTMLSection(os, this->UsageHelp, 0);
  297. os << "</code></blockquote>\n";
  298. }
  299. this->PrintHelpHTMLSection(os, this->Description, 0);
  300. this->PrintHelpHTMLSection(os, &this->Options[0], "Command-line Options");
  301. this->PrintHelpHTMLSection(os, this->Commands, "CMakeLists.txt Commands");
  302. os << "</body>\n"
  303. << "</html>\n";
  304. }
  305. //----------------------------------------------------------------------------
  306. void cmDocumentation::PrintManPage(std::ostream& os)
  307. {
  308. os << ".TH CMake 1 \""
  309. << cmSystemTools::GetCurrentDateTime("%B %d, %Y").c_str()
  310. << "\" \"CMake " CMake_VERSION_STRING "\"\n";
  311. this->PrintManSection(os, this->Name, "NAME");
  312. this->PrintManSection(os, this->UsageHelp, "SYNOPSIS");
  313. this->PrintManSection(os, this->Description, "DESCRIPTION");
  314. this->PrintManSection(os, &this->Options[0], "OPTIONS");
  315. this->PrintManSection(os, this->Commands, "COMMANDS");
  316. this->PrintManSection(os, cmDocumentationCopyright, "COPYRIGHT");
  317. os << ".SH MAILING LIST\n";
  318. os << "For help and discussion about using cmake, a mailing list is\n"
  319. << "provided at\n"
  320. << ".B [email protected].\n"
  321. << "Please first read the full documentation at\n"
  322. << ".B http://www.cmake.org\n"
  323. << "before posting questions to the list.\n";
  324. os << ".SH AUTHOR\n"
  325. << "This manual page was generated by \"cmake --man\".\n";
  326. }
  327. //----------------------------------------------------------------------------
  328. void cmDocumentation::PrintCopyright(std::ostream& os)
  329. {
  330. os << "CMake version " CMake_VERSION_STRING "\n";
  331. for(const cmDocumentationEntry* op = cmDocumentationCopyright;
  332. op->brief; ++op)
  333. {
  334. if(op->name)
  335. {
  336. os << " * ";
  337. this->PrintColumn(os, 74, " ", op->brief);
  338. }
  339. else
  340. {
  341. this->PrintColumn(os, 77, "", op->brief);
  342. }
  343. os << "\n";
  344. }
  345. }
  346. //----------------------------------------------------------------------------
  347. void cmDocumentation::PrintVersion(std::ostream& os)
  348. {
  349. os << "CMake version " CMake_VERSION_STRING "\n";
  350. }
  351. //----------------------------------------------------------------------------
  352. void cmDocumentation::PrintColumn(std::ostream& os, int width,
  353. const char* indent, const char* text)
  354. {
  355. // Print text arranged in a column of fixed witdh indented by the
  356. // "indent" text.
  357. const char* l = text;
  358. int column = 0;
  359. bool newSentence = false;
  360. bool firstLine = true;
  361. // Count leading blanks in the text.
  362. int blanks = 0;
  363. for(const char* b = l; *b == ' '; ++b) { ++blanks; }
  364. // Loop until the end of the text.
  365. while(*l)
  366. {
  367. // Parse the next word.
  368. const char* r = l;
  369. while(*r && (*r != '\n') && (*r != ' ')) { ++r; }
  370. // Does it fit on this line?
  371. if(r-l < (width-column-(newSentence?1:0)))
  372. {
  373. // Word fits on this line.
  374. if(r > l)
  375. {
  376. if(column)
  377. {
  378. // Not first word on line. Separate from the previous word
  379. // by a space, or two if this is a new sentence.
  380. if(newSentence)
  381. {
  382. os << " ";
  383. column += 2;
  384. }
  385. else
  386. {
  387. os << " ";
  388. column += 1;
  389. }
  390. }
  391. else
  392. {
  393. // First word on line. Print indentation unless this is the
  394. // first line.
  395. os << (firstLine?"":indent);
  396. // Further indent by leading blanks from the text on this
  397. // line.
  398. for(int i = 0; i < blanks; ++i)
  399. {
  400. os << " ";
  401. ++column;
  402. }
  403. blanks = 0;
  404. }
  405. // Print the word.
  406. os.write(l, static_cast<long>(r-l));
  407. newSentence = (*(r-1) == '.');
  408. }
  409. if(*r == '\n')
  410. {
  411. // Text provided a newline. Start a new line.
  412. os << "\n";
  413. ++r;
  414. column = 0;
  415. firstLine = false;
  416. // Count leading blanks in the text.
  417. for(const char* b = r; *b == ' '; ++b) { ++blanks; }
  418. }
  419. else
  420. {
  421. // No provided newline. Continue this line.
  422. column += static_cast<long>(r-l);
  423. }
  424. }
  425. else
  426. {
  427. // Word does not fit on this line. Start a new line.
  428. os << "\n";
  429. firstLine = false;
  430. if(r > l)
  431. {
  432. os << indent;
  433. os.write(l, static_cast<long>(r-l));
  434. column = static_cast<long>(r-l);
  435. newSentence = (*(r-1) == '.');
  436. }
  437. }
  438. // Move to beginning of next word. Skip over whitespace.
  439. l = r;
  440. while(*l && (*l == ' ')) { ++l; }
  441. }
  442. }
  443. //----------------------------------------------------------------------------
  444. void cmDocumentation::Print(Type ht, std::ostream& os)
  445. {
  446. switch (ht)
  447. {
  448. case cmDocumentation::Usage: this->PrintUsage(os); break;
  449. case cmDocumentation::Help: this->PrintHelp(os); break;
  450. case cmDocumentation::HelpHTML: this->PrintHelpHTML(os); break;
  451. case cmDocumentation::Man: this->PrintManPage(os); break;
  452. case cmDocumentation::Copyright: this->PrintCopyright(os); break;
  453. case cmDocumentation::Version: this->PrintVersion(os); break;
  454. default: break;
  455. }
  456. }
  457. //----------------------------------------------------------------------------
  458. cmDocumentation::Type cmDocumentation::CheckOptions(int argc, char** argv)
  459. {
  460. for(int i=1; i < argc; ++i)
  461. {
  462. if((strcmp(argv[i], "/?") == 0) ||
  463. (strcmp(argv[i], "-usage") == 0) ||
  464. (strcmp(argv[i], "--usage") == 0))
  465. {
  466. return cmDocumentation::Usage;
  467. }
  468. if((strcmp(argv[i], "-help") == 0) ||
  469. (strcmp(argv[i], "--help") == 0))
  470. {
  471. return cmDocumentation::Help;
  472. }
  473. if(strcmp(argv[i], "--help-html") == 0)
  474. {
  475. return cmDocumentation::HelpHTML;
  476. }
  477. if(strcmp(argv[i], "--man") == 0)
  478. {
  479. return cmDocumentation::Man;
  480. }
  481. if(strcmp(argv[i], "--copyright") == 0)
  482. {
  483. return cmDocumentation::Copyright;
  484. }
  485. if(strcmp(argv[i], "--version") == 0)
  486. {
  487. return cmDocumentation::Version;
  488. }
  489. }
  490. return cmDocumentation::None;
  491. }
  492. //----------------------------------------------------------------------------
  493. void cmDocumentation::SetOptions(const cmDocumentationEntry* d)
  494. {
  495. this->Options.erase(this->Options.begin(), this->Options.end());
  496. if(d)
  497. {
  498. for(const cmDocumentationEntry* op = d; op->brief; ++op)
  499. {
  500. this->Options.push_back(*op);
  501. }
  502. }
  503. for(const cmDocumentationEntry* op = cmDocumentationStandardOptions;
  504. op->brief; ++op)
  505. {
  506. this->Options.push_back(*op);
  507. }
  508. cmDocumentationEntry empty = {0,0,0};
  509. this->Options.push_back(empty);
  510. }