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