/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 | } |