Imported Upstream version 3.25.0
[platform/upstream/cmake.git] / Source / cmDocumentation.cxx
1 /* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
2    file Copyright.txt or https://cmake.org/licensing for details.  */
3 #include "cmDocumentation.h"
4
5 #include <algorithm>
6 #include <cctype>
7 #include <cstring>
8 #include <utility>
9
10 #include "cmsys/FStream.hxx"
11 #include "cmsys/Glob.hxx"
12
13 #include "cmDocumentationEntry.h"
14 #include "cmDocumentationSection.h"
15 #include "cmRST.h"
16 #include "cmSystemTools.h"
17 #include "cmVersion.h"
18
19 static const char* cmDocumentationStandardOptions[][2] = {
20   { "-h,-H,--help,-help,-usage,/?", "Print usage information and exit." },
21   { "--version,-version,/V [<file>]", "Print version number and exit." },
22   { "--help-full [<file>]", "Print all help manuals and exit." },
23   { "--help-manual <man> [<file>]", "Print one help manual and exit." },
24   { "--help-manual-list [<file>]", "List help manuals available and exit." },
25   { "--help-command <cmd> [<file>]", "Print help for one command and exit." },
26   { "--help-command-list [<file>]",
27     "List commands with help available and exit." },
28   { "--help-commands [<file>]", "Print cmake-commands manual and exit." },
29   { "--help-module <mod> [<file>]", "Print help for one module and exit." },
30   { "--help-module-list [<file>]",
31     "List modules with help available and exit." },
32   { "--help-modules [<file>]", "Print cmake-modules manual and exit." },
33   { "--help-policy <cmp> [<file>]", "Print help for one policy and exit." },
34   { "--help-policy-list [<file>]",
35     "List policies with help available and exit." },
36   { "--help-policies [<file>]", "Print cmake-policies manual and exit." },
37   { "--help-property <prop> [<file>]",
38     "Print help for one property and exit." },
39   { "--help-property-list [<file>]",
40     "List properties with help available and exit." },
41   { "--help-properties [<file>]", "Print cmake-properties manual and exit." },
42   { "--help-variable var [<file>]", "Print help for one variable and exit." },
43   { "--help-variable-list [<file>]",
44     "List variables with help available and exit." },
45   { "--help-variables [<file>]", "Print cmake-variables manual and exit." },
46   { nullptr, nullptr }
47 };
48
49 static const char* cmDocumentationCPackGeneratorsHeader[][2] = {
50   { nullptr, "The following generators are available on this platform:" },
51   { nullptr, nullptr }
52 };
53
54 static const char* cmDocumentationCMakeGeneratorsHeader[][2] = {
55   { nullptr,
56     "The following generators are available on this platform (* marks "
57     "default):" },
58   { nullptr, nullptr }
59 };
60
61 cmDocumentation::cmDocumentation()
62 {
63   this->addCommonStandardDocSections();
64   this->ShowGenerators = true;
65 }
66
67 bool cmDocumentation::PrintVersion(std::ostream& os)
68 {
69   /* clang-format off */
70   os <<
71     this->GetNameString() <<
72     " version " << cmVersion::GetCMakeVersion() << "\n"
73     "\n"
74     "CMake suite maintained and supported by Kitware (kitware.com/cmake).\n"
75     ;
76   /* clang-format on */
77   return true;
78 }
79
80 bool cmDocumentation::PrintDocumentation(Type ht, std::ostream& os)
81 {
82   switch (ht) {
83     case cmDocumentation::Usage:
84       return this->PrintUsage(os);
85     case cmDocumentation::Help:
86       return this->PrintHelp(os);
87     case cmDocumentation::Full:
88       return this->PrintHelpFull(os);
89     case cmDocumentation::OneManual:
90       return this->PrintHelpOneManual(os);
91     case cmDocumentation::OneCommand:
92       return this->PrintHelpOneCommand(os);
93     case cmDocumentation::OneModule:
94       return this->PrintHelpOneModule(os);
95     case cmDocumentation::OnePolicy:
96       return this->PrintHelpOnePolicy(os);
97     case cmDocumentation::OneProperty:
98       return this->PrintHelpOneProperty(os);
99     case cmDocumentation::OneVariable:
100       return this->PrintHelpOneVariable(os);
101     case cmDocumentation::ListManuals:
102       return this->PrintHelpListManuals(os);
103     case cmDocumentation::ListCommands:
104       return this->PrintHelpListCommands(os);
105     case cmDocumentation::ListModules:
106       return this->PrintHelpListModules(os);
107     case cmDocumentation::ListProperties:
108       return this->PrintHelpListProperties(os);
109     case cmDocumentation::ListVariables:
110       return this->PrintHelpListVariables(os);
111     case cmDocumentation::ListPolicies:
112       return this->PrintHelpListPolicies(os);
113     case cmDocumentation::ListGenerators:
114       return this->PrintHelpListGenerators(os);
115     case cmDocumentation::Version:
116       return this->PrintVersion(os);
117     case cmDocumentation::OldCustomModules:
118       return this->PrintOldCustomModules(os);
119     default:
120       return false;
121   }
122 }
123
124 bool cmDocumentation::PrintRequestedDocumentation(std::ostream& os)
125 {
126   int count = 0;
127   bool result = true;
128
129   // Loop over requested documentation types.
130   for (RequestedHelpItem const& rhi : this->RequestedHelpItems) {
131     this->CurrentArgument = rhi.Argument;
132     // If a file name was given, use it.  Otherwise, default to the
133     // given stream.
134     cmsys::ofstream fout;
135     std::ostream* s = &os;
136     if (!rhi.Filename.empty()) {
137       fout.open(rhi.Filename.c_str());
138       s = &fout;
139     } else if (++count > 1) {
140       os << "\n\n";
141     }
142
143     // Print this documentation type to the stream.
144     if (!this->PrintDocumentation(rhi.HelpType, *s) || s->fail()) {
145       result = false;
146     }
147   }
148   return result;
149 }
150
151 #define GET_OPT_ARGUMENT(target)                                              \
152   do {                                                                        \
153     if ((i + 1 < argc) && !this->IsOption(argv[i + 1])) {                     \
154       (target) = argv[i + 1];                                                 \
155       i = i + 1;                                                              \
156     };                                                                        \
157   } while (false)
158
159 void cmDocumentation::WarnFormFromFilename(
160   cmDocumentation::RequestedHelpItem& request, bool& result)
161 {
162   std::string ext = cmSystemTools::GetFilenameLastExtension(request.Filename);
163   ext = cmSystemTools::UpperCase(ext);
164   if ((ext == ".HTM") || (ext == ".HTML")) {
165     request.HelpType = cmDocumentation::None;
166     result = true;
167     cmSystemTools::Message("Warning: HTML help format no longer supported");
168   } else if (ext == ".DOCBOOK") {
169     request.HelpType = cmDocumentation::None;
170     result = true;
171     cmSystemTools::Message("Warning: Docbook help format no longer supported");
172   }
173   // ".1" to ".9" should be manpages
174   else if ((ext.length() == 2) && (ext[1] >= '1') && (ext[1] <= '9')) {
175     request.HelpType = cmDocumentation::None;
176     result = true;
177     cmSystemTools::Message("Warning: Man help format no longer supported");
178   }
179 }
180
181 void cmDocumentation::addCommonStandardDocSections()
182 {
183   cmDocumentationSection sec{ "Options" };
184   sec.Append(cmDocumentationStandardOptions);
185   this->AllSections.emplace("Options", std::move(sec));
186 }
187
188 void cmDocumentation::addCMakeStandardDocSections()
189 {
190   cmDocumentationSection sec{ "Generators" };
191   sec.Append(cmDocumentationCMakeGeneratorsHeader);
192   this->AllSections.emplace("Generators", std::move(sec));
193 }
194
195 void cmDocumentation::addCTestStandardDocSections()
196 {
197   // This is currently done for backward compatibility reason
198   // We may suppress some of these.
199   this->addCMakeStandardDocSections();
200 }
201
202 void cmDocumentation::addCPackStandardDocSections()
203 {
204   cmDocumentationSection sec{ "Generators" };
205   sec.Append(cmDocumentationCPackGeneratorsHeader);
206   this->AllSections.emplace("Generators", std::move(sec));
207 }
208
209 bool cmDocumentation::CheckOptions(int argc, const char* const* argv,
210                                    const char* exitOpt)
211 {
212   // Providing zero arguments gives usage information.
213   if (argc == 1) {
214     RequestedHelpItem help;
215     help.HelpType = cmDocumentation::Usage;
216     this->RequestedHelpItems.push_back(std::move(help));
217     return true;
218   }
219
220   // Search for supported help options.
221
222   bool result = false;
223   for (int i = 1; i < argc; ++i) {
224     if (exitOpt && strcmp(argv[i], exitOpt) == 0) {
225       return result;
226     }
227     RequestedHelpItem help;
228     // Check if this is a supported help option.
229     if ((strcmp(argv[i], "-help") == 0) || (strcmp(argv[i], "--help") == 0) ||
230         (strcmp(argv[i], "/?") == 0) || (strcmp(argv[i], "-usage") == 0) ||
231         (strcmp(argv[i], "-h") == 0) || (strcmp(argv[i], "-H") == 0)) {
232       help.HelpType = cmDocumentation::Help;
233       GET_OPT_ARGUMENT(help.Argument);
234       help.Argument = cmSystemTools::LowerCase(help.Argument);
235       // special case for single command
236       if (!help.Argument.empty()) {
237         help.HelpType = cmDocumentation::OneCommand;
238       }
239     } else if (strcmp(argv[i], "--help-properties") == 0) {
240       help.HelpType = cmDocumentation::OneManual;
241       help.Argument = "cmake-properties.7";
242       GET_OPT_ARGUMENT(help.Filename);
243       this->WarnFormFromFilename(help, result);
244     } else if (strcmp(argv[i], "--help-policies") == 0) {
245       help.HelpType = cmDocumentation::OneManual;
246       help.Argument = "cmake-policies.7";
247       GET_OPT_ARGUMENT(help.Filename);
248       this->WarnFormFromFilename(help, result);
249     } else if (strcmp(argv[i], "--help-variables") == 0) {
250       help.HelpType = cmDocumentation::OneManual;
251       help.Argument = "cmake-variables.7";
252       GET_OPT_ARGUMENT(help.Filename);
253       this->WarnFormFromFilename(help, result);
254     } else if (strcmp(argv[i], "--help-modules") == 0) {
255       help.HelpType = cmDocumentation::OneManual;
256       help.Argument = "cmake-modules.7";
257       GET_OPT_ARGUMENT(help.Filename);
258       this->WarnFormFromFilename(help, result);
259     } else if (strcmp(argv[i], "--help-custom-modules") == 0) {
260       GET_OPT_ARGUMENT(help.Filename);
261       cmSystemTools::Message(
262         "Warning: --help-custom-modules no longer supported");
263       if (help.Filename.empty()) {
264         return true;
265       }
266       // Avoid breaking old project builds completely by at least generating
267       // the output file.  Abuse help.Argument to give the file name to
268       // PrintOldCustomModules without disrupting our internal API.
269       help.HelpType = cmDocumentation::OldCustomModules;
270       help.Argument = cmSystemTools::GetFilenameName(help.Filename);
271     } else if (strcmp(argv[i], "--help-commands") == 0) {
272       help.HelpType = cmDocumentation::OneManual;
273       help.Argument = "cmake-commands.7";
274       GET_OPT_ARGUMENT(help.Filename);
275       this->WarnFormFromFilename(help, result);
276     } else if (strcmp(argv[i], "--help-compatcommands") == 0) {
277       GET_OPT_ARGUMENT(help.Filename);
278       cmSystemTools::Message(
279         "Warning: --help-compatcommands no longer supported");
280       return true;
281     } else if (strcmp(argv[i], "--help-full") == 0) {
282       help.HelpType = cmDocumentation::Full;
283       GET_OPT_ARGUMENT(help.Filename);
284       this->WarnFormFromFilename(help, result);
285     } else if (strcmp(argv[i], "--help-html") == 0) {
286       GET_OPT_ARGUMENT(help.Filename);
287       cmSystemTools::Message("Warning: --help-html no longer supported");
288       return true;
289     } else if (strcmp(argv[i], "--help-man") == 0) {
290       GET_OPT_ARGUMENT(help.Filename);
291       cmSystemTools::Message("Warning: --help-man no longer supported");
292       return true;
293     } else if (strcmp(argv[i], "--help-command") == 0) {
294       help.HelpType = cmDocumentation::OneCommand;
295       GET_OPT_ARGUMENT(help.Argument);
296       GET_OPT_ARGUMENT(help.Filename);
297       help.Argument = cmSystemTools::LowerCase(help.Argument);
298       this->WarnFormFromFilename(help, result);
299     } else if (strcmp(argv[i], "--help-module") == 0) {
300       help.HelpType = cmDocumentation::OneModule;
301       GET_OPT_ARGUMENT(help.Argument);
302       GET_OPT_ARGUMENT(help.Filename);
303       this->WarnFormFromFilename(help, result);
304     } else if (strcmp(argv[i], "--help-property") == 0) {
305       help.HelpType = cmDocumentation::OneProperty;
306       GET_OPT_ARGUMENT(help.Argument);
307       GET_OPT_ARGUMENT(help.Filename);
308       this->WarnFormFromFilename(help, result);
309     } else if (strcmp(argv[i], "--help-policy") == 0) {
310       help.HelpType = cmDocumentation::OnePolicy;
311       GET_OPT_ARGUMENT(help.Argument);
312       GET_OPT_ARGUMENT(help.Filename);
313       this->WarnFormFromFilename(help, result);
314     } else if (strcmp(argv[i], "--help-variable") == 0) {
315       help.HelpType = cmDocumentation::OneVariable;
316       GET_OPT_ARGUMENT(help.Argument);
317       GET_OPT_ARGUMENT(help.Filename);
318       this->WarnFormFromFilename(help, result);
319     } else if (strcmp(argv[i], "--help-manual") == 0) {
320       help.HelpType = cmDocumentation::OneManual;
321       GET_OPT_ARGUMENT(help.Argument);
322       GET_OPT_ARGUMENT(help.Filename);
323       this->WarnFormFromFilename(help, result);
324     } else if (strcmp(argv[i], "--help-command-list") == 0) {
325       help.HelpType = cmDocumentation::ListCommands;
326       GET_OPT_ARGUMENT(help.Filename);
327     } else if (strcmp(argv[i], "--help-module-list") == 0) {
328       help.HelpType = cmDocumentation::ListModules;
329       GET_OPT_ARGUMENT(help.Filename);
330     } else if (strcmp(argv[i], "--help-property-list") == 0) {
331       help.HelpType = cmDocumentation::ListProperties;
332       GET_OPT_ARGUMENT(help.Filename);
333     } else if (strcmp(argv[i], "--help-variable-list") == 0) {
334       help.HelpType = cmDocumentation::ListVariables;
335       GET_OPT_ARGUMENT(help.Filename);
336     } else if (strcmp(argv[i], "--help-policy-list") == 0) {
337       help.HelpType = cmDocumentation::ListPolicies;
338       GET_OPT_ARGUMENT(help.Filename);
339     } else if (strcmp(argv[i], "--help-manual-list") == 0) {
340       help.HelpType = cmDocumentation::ListManuals;
341       GET_OPT_ARGUMENT(help.Filename);
342     } else if (strcmp(argv[i], "--copyright") == 0) {
343       GET_OPT_ARGUMENT(help.Filename);
344       cmSystemTools::Message("Warning: --copyright no longer supported");
345       return true;
346     } else if ((strcmp(argv[i], "--version") == 0) ||
347                (strcmp(argv[i], "-version") == 0) ||
348                (strcmp(argv[i], "/V") == 0)) {
349       help.HelpType = cmDocumentation::Version;
350       GET_OPT_ARGUMENT(help.Filename);
351     }
352     if (help.HelpType != None) {
353       // This is a help option.  See if there is a file name given.
354       result = true;
355       this->RequestedHelpItems.push_back(std::move(help));
356     }
357   }
358   return result;
359 }
360
361 void cmDocumentation::SetName(const std::string& name)
362 {
363   this->NameString = name;
364 }
365
366 void cmDocumentation::SetSection(const char* name,
367                                  cmDocumentationSection section)
368 {
369   this->SectionAtName(name) = std::move(section);
370 }
371
372 void cmDocumentation::SetSection(const char* name,
373                                  std::vector<cmDocumentationEntry>& docs)
374 {
375   cmDocumentationSection sec{ name };
376   sec.Append(docs);
377   this->SetSection(name, std::move(sec));
378 }
379
380 void cmDocumentation::SetSection(const char* name, const char* docs[][2])
381 {
382   cmDocumentationSection sec{ name };
383   sec.Append(docs);
384   this->SetSection(name, std::move(sec));
385 }
386
387 void cmDocumentation::SetSections(
388   std::map<std::string, cmDocumentationSection> sections)
389 {
390   for (auto& s : sections) {
391     this->SetSection(s.first.c_str(), std::move(s.second));
392   }
393 }
394 cmDocumentationSection& cmDocumentation::SectionAtName(const char* name)
395 {
396   return this->AllSections.emplace(name, cmDocumentationSection{ name })
397     .first->second;
398 }
399
400 void cmDocumentation::PrependSection(const char* name, const char* docs[][2])
401 {
402   this->SectionAtName(name).Prepend(docs);
403 }
404
405 void cmDocumentation::PrependSection(const char* name,
406                                      std::vector<cmDocumentationEntry>& docs)
407 {
408   this->SectionAtName(name).Prepend(docs);
409 }
410
411 void cmDocumentation::AppendSection(const char* name, const char* docs[][2])
412 {
413   this->SectionAtName(name).Append(docs);
414 }
415
416 void cmDocumentation::AppendSection(const char* name,
417                                     std::vector<cmDocumentationEntry>& docs)
418 {
419   this->SectionAtName(name).Append(docs);
420 }
421
422 void cmDocumentation::AppendSection(const char* name,
423                                     cmDocumentationEntry& docs)
424 {
425
426   std::vector<cmDocumentationEntry> docsVec;
427   docsVec.push_back(docs);
428   this->AppendSection(name, docsVec);
429 }
430
431 void cmDocumentation::PrependSection(const char* name,
432                                      cmDocumentationEntry& docs)
433 {
434
435   std::vector<cmDocumentationEntry> docsVec;
436   docsVec.push_back(docs);
437   this->PrependSection(name, docsVec);
438 }
439
440 void cmDocumentation::GlobHelp(std::vector<std::string>& files,
441                                std::string const& pattern)
442 {
443   cmsys::Glob gl;
444   std::string findExpr =
445     cmSystemTools::GetCMakeRoot() + "/Help/" + pattern + ".rst";
446   if (gl.FindFiles(findExpr)) {
447     files = gl.GetFiles();
448   }
449 }
450
451 void cmDocumentation::PrintNames(std::ostream& os, std::string const& pattern)
452 {
453   std::vector<std::string> files;
454   this->GlobHelp(files, pattern);
455   std::vector<std::string> names;
456   for (std::string const& f : files) {
457     std::string line;
458     cmsys::ifstream fin(f.c_str());
459     while (fin && cmSystemTools::GetLineFromStream(fin, line)) {
460       if (!line.empty() && (isalnum(line[0]) || line[0] == '<')) {
461         names.push_back(line);
462         break;
463       }
464     }
465   }
466   std::sort(names.begin(), names.end());
467   for (std::string const& n : names) {
468     os << n << "\n";
469   }
470 }
471
472 bool cmDocumentation::PrintFiles(std::ostream& os, std::string const& pattern)
473 {
474   bool found = false;
475   std::vector<std::string> files;
476   this->GlobHelp(files, pattern);
477   std::sort(files.begin(), files.end());
478   cmRST r(os, cmSystemTools::GetCMakeRoot() + "/Help");
479   for (std::string const& f : files) {
480     found = r.ProcessFile(f) || found;
481   }
482   return found;
483 }
484
485 bool cmDocumentation::PrintHelpFull(std::ostream& os)
486 {
487   return this->PrintFiles(os, "index");
488 }
489
490 bool cmDocumentation::PrintHelpOneManual(std::ostream& os)
491 {
492   std::string mname = this->CurrentArgument;
493   std::string::size_type mlen = mname.length();
494   if (mlen > 3 && mname[mlen - 3] == '(' && mname[mlen - 1] == ')') {
495     mname = mname.substr(0, mlen - 3) + "." + mname[mlen - 2];
496   }
497   if (this->PrintFiles(os, "manual/" + mname) ||
498       this->PrintFiles(os, "manual/" + mname + ".[0-9]")) {
499     return true;
500   }
501   // Argument was not a manual.  Complain.
502   os << "Argument \"" << this->CurrentArgument
503      << "\" to --help-manual is not an available manual.  "
504      << "Use --help-manual-list to see all available manuals.\n";
505   return false;
506 }
507
508 bool cmDocumentation::PrintHelpListManuals(std::ostream& os)
509 {
510   this->PrintNames(os, "manual/*");
511   return true;
512 }
513
514 bool cmDocumentation::PrintHelpOneCommand(std::ostream& os)
515 {
516   std::string cname = cmSystemTools::LowerCase(this->CurrentArgument);
517   if (this->PrintFiles(os, "command/" + cname)) {
518     return true;
519   }
520   // Argument was not a command.  Complain.
521   os << "Argument \"" << this->CurrentArgument
522      << "\" to --help-command is not a CMake command.  "
523      << "Use --help-command-list to see all commands.\n";
524   return false;
525 }
526
527 bool cmDocumentation::PrintHelpListCommands(std::ostream& os)
528 {
529   this->PrintNames(os, "command/*");
530   return true;
531 }
532
533 bool cmDocumentation::PrintHelpOneModule(std::ostream& os)
534 {
535   std::string mname = this->CurrentArgument;
536   if (this->PrintFiles(os, "module/" + mname)) {
537     return true;
538   }
539   // Argument was not a module.  Complain.
540   os << "Argument \"" << this->CurrentArgument
541      << "\" to --help-module is not a CMake module.\n";
542   return false;
543 }
544
545 bool cmDocumentation::PrintHelpListModules(std::ostream& os)
546 {
547   std::vector<std::string> files;
548   this->GlobHelp(files, "module/*");
549   std::vector<std::string> modules;
550   for (std::string const& f : files) {
551     std::string module = cmSystemTools::GetFilenameName(f);
552     modules.push_back(module.substr(0, module.size() - 4));
553   }
554   std::sort(modules.begin(), modules.end());
555   for (std::string const& m : modules) {
556     os << m << "\n";
557   }
558   return true;
559 }
560
561 bool cmDocumentation::PrintHelpOneProperty(std::ostream& os)
562 {
563   std::string pname = cmSystemTools::HelpFileName(this->CurrentArgument);
564   if (this->PrintFiles(os, "prop_*/" + pname)) {
565     return true;
566   }
567   // Argument was not a property.  Complain.
568   os << "Argument \"" << this->CurrentArgument
569      << "\" to --help-property is not a CMake property.  "
570      << "Use --help-property-list to see all properties.\n";
571   return false;
572 }
573
574 bool cmDocumentation::PrintHelpListProperties(std::ostream& os)
575 {
576   this->PrintNames(os, "prop_*/*");
577   return true;
578 }
579
580 bool cmDocumentation::PrintHelpOnePolicy(std::ostream& os)
581 {
582   std::string pname = this->CurrentArgument;
583   std::vector<std::string> files;
584   if (this->PrintFiles(os, "policy/" + pname)) {
585     return true;
586   }
587
588   // Argument was not a policy.  Complain.
589   os << "Argument \"" << this->CurrentArgument
590      << "\" to --help-policy is not a CMake policy.\n";
591   return false;
592 }
593
594 bool cmDocumentation::PrintHelpListPolicies(std::ostream& os)
595 {
596   this->PrintNames(os, "policy/*");
597   return true;
598 }
599
600 bool cmDocumentation::PrintHelpListGenerators(std::ostream& os)
601 {
602   const auto si = this->AllSections.find("Generators");
603   if (si != this->AllSections.end()) {
604     this->Formatter.SetIndent("  ");
605     this->Formatter.PrintSection(os, si->second);
606   }
607   return true;
608 }
609
610 bool cmDocumentation::PrintHelpOneVariable(std::ostream& os)
611 {
612   std::string vname = cmSystemTools::HelpFileName(this->CurrentArgument);
613   if (this->PrintFiles(os, "variable/" + vname)) {
614     return true;
615   }
616   // Argument was not a variable.  Complain.
617   os << "Argument \"" << this->CurrentArgument
618      << "\" to --help-variable is not a defined variable.  "
619      << "Use --help-variable-list to see all defined variables.\n";
620   return false;
621 }
622
623 bool cmDocumentation::PrintHelpListVariables(std::ostream& os)
624 {
625   this->PrintNames(os, "variable/*");
626   return true;
627 }
628
629 bool cmDocumentation::PrintUsage(std::ostream& os)
630 {
631   const auto si = this->AllSections.find("Usage");
632   if (si != this->AllSections.end()) {
633     this->Formatter.PrintSection(os, si->second);
634   }
635   return true;
636 }
637
638 bool cmDocumentation::PrintHelp(std::ostream& os)
639 {
640   auto si = this->AllSections.find("Usage");
641   if (si != this->AllSections.end()) {
642     this->Formatter.PrintSection(os, si->second);
643   }
644   si = this->AllSections.find("Options");
645   if (si != this->AllSections.end()) {
646     this->Formatter.PrintSection(os, si->second);
647   }
648   if (this->ShowGenerators) {
649     si = this->AllSections.find("Generators");
650     if (si != this->AllSections.end()) {
651       this->Formatter.PrintSection(os, si->second);
652     }
653   }
654   return true;
655 }
656
657 const char* cmDocumentation::GetNameString() const
658 {
659   if (!this->NameString.empty()) {
660     return this->NameString.c_str();
661   }
662   return "CMake";
663 }
664
665 bool cmDocumentation::IsOption(const char* arg) const
666 {
667   return ((arg[0] == '-') || (strcmp(arg, "/V") == 0) ||
668           (strcmp(arg, "/?") == 0));
669 }
670
671 bool cmDocumentation::PrintOldCustomModules(std::ostream& os)
672 {
673   // CheckOptions abuses the Argument field to give us the file name.
674   std::string filename = this->CurrentArgument;
675   std::string ext = cmSystemTools::UpperCase(
676     cmSystemTools::GetFilenameLastExtension(filename));
677   std::string name = cmSystemTools::GetFilenameWithoutLastExtension(filename);
678
679   const char* summary = "cmake --help-custom-modules no longer supported\n";
680   const char* detail =
681     "CMake versions prior to 3.0 exposed their internal module help page\n"
682     "generation functionality through the --help-custom-modules option.\n"
683     "CMake versions 3.0 and above use other means to generate their module\n"
684     "help pages so this functionality is no longer available to be exposed.\n"
685     "\n"
686     "This file was generated as a placeholder to provide this information.\n";
687   if ((ext == ".HTM") || (ext == ".HTML")) {
688     os << "<html><title>" << name << "</title><body>\n"
689        << summary << "<p/>\n"
690        << detail << "</body></html>\n";
691   } else if ((ext.length() == 2) && (ext[1] >= '1') && (ext[1] <= '9')) {
692     /* clang-format off */
693     os <<
694       ".TH " << name << " " << ext[1] << " \"" <<
695       cmSystemTools::GetCurrentDateTime("%B %d, %Y") <<
696       "\" \"cmake " << cmVersion::GetCMakeVersion() << "\"\n"
697       ".SH NAME\n"
698       ".PP\n" <<
699       name << " \\- " << summary <<
700       "\n"
701       ".SH DESCRIPTION\n"
702       ".PP\n" <<
703       detail
704       ;
705     /* clang-format on */
706   } else {
707     os << name << "\n\n" << summary << "\n" << detail;
708   }
709   return true;
710 }