Coverage Report

Created: 2026-06-15 07:03

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