Coverage Report

Created: 2026-03-12 06:35

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