1 // Copyright (c) 2017-2021, University of Cincinnati, developed by Henry Schreiner
2 // under NSF AWARD 1414736 and by the respective contributors.
3 // All rights reserved.
4 //
5 // SPDX-License-Identifier: BSD-3-Clause
6
7 #pragma once
8
9 // [CLI11:public_includes:set]
10 #include <algorithm>
11 #include <cstdint>
12 #include <functional>
13 #include <iostream>
14 #include <iterator>
15 #include <memory>
16 #include <numeric>
17 #include <set>
18 #include <sstream>
19 #include <string>
20 #include <utility>
21 #include <vector>
22 // [CLI11:public_includes:end]
23
24 // CLI Library includes
25 #include "ConfigFwd.hpp"
26 #include "Error.hpp"
27 #include "FormatterFwd.hpp"
28 #include "Macros.hpp"
29 #include "Option.hpp"
30 #include "Split.hpp"
31 #include "StringTools.hpp"
32 #include "TypeTools.hpp"
33
34 namespace CLI {
35 // [CLI11:app_hpp:verbatim]
36
37 #ifndef CLI11_PARSE
38 #define CLI11_PARSE(app, argc, argv) \
39 try { \
40 (app).parse((argc), (argv)); \
41 } catch(const CLI::ParseError &e) { \
42 return (app).exit(e); \
43 }
44 #endif
45
46 namespace detail {
47 enum class Classifier { NONE, POSITIONAL_MARK, SHORT, LONG, WINDOWS_STYLE, SUBCOMMAND, SUBCOMMAND_TERMINATOR };
48 struct AppFriend;
49 } // namespace detail
50
51 namespace FailureMessage {
52 std::string simple(const App *app, const Error &e);
53 std::string help(const App *app, const Error &e);
54 } // namespace FailureMessage
55
56 /// enumeration of modes of how to deal with extras in config files
57
58 enum class config_extras_mode : char { error = 0, ignore, ignore_all, capture };
59
60 class App;
61
62 using App_p = std::shared_ptr<App>;
63
64 class Option_group;
65 /// Creates a command line program, with very few defaults.
66 /** To use, create a new `Program()` instance with `argc`, `argv`, and a help description. The templated
67 * add_option methods make it easy to prepare options. Remember to call `.start` before starting your
68 * program, so that the options can be evaluated and the help option doesn't accidentally run your program. */
69 class App {
70 friend Option;
71 friend detail::AppFriend;
72
73 protected:
74 // This library follows the Google style guide for member names ending in underscores
75
76 /// @name Basics
77 ///@{
78
79 /// Subcommand name or program name (from parser if name is empty)
80 std::string name_{};
81
82 /// Description of the current program/subcommand
83 std::string description_{};
84
85 /// If true, allow extra arguments (ie, don't throw an error). INHERITABLE
86 bool allow_extras_{false};
87
88 /// If ignore, allow extra arguments in the ini file (ie, don't throw an error). INHERITABLE
89 /// if error error on an extra argument, and if capture feed it to the app
90 config_extras_mode allow_config_extras_{config_extras_mode::ignore};
91
92 /// If true, return immediately on an unrecognized option (implies allow_extras) INHERITABLE
93 bool prefix_command_{false};
94
95 /// If set to true the name was automatically generated from the command line vs a user set name
96 bool has_automatic_name_{false};
97
98 /// If set to true the subcommand is required to be processed and used, ignored for main app
99 bool required_{false};
100
101 /// If set to true the subcommand is disabled and cannot be used, ignored for main app
102 bool disabled_{false};
103
104 /// Flag indicating that the pre_parse_callback has been triggered
105 bool pre_parse_called_{false};
106
107 /// Flag indicating that the callback for the subcommand should be executed immediately on parse completion which is
108 /// before help or ini files are processed. INHERITABLE
109 bool immediate_callback_{false};
110
111 /// This is a function that runs prior to the start of parsing
112 std::function<void(std::size_t)> pre_parse_callback_{};
113
114 /// This is a function that runs when parsing has finished.
115 std::function<void()> parse_complete_callback_{};
116
117 /// This is a function that runs when all processing has completed
118 std::function<void()> final_callback_{};
119
120 ///@}
121 /// @name Options
122 ///@{
123
124 /// The default values for options, customizable and changeable INHERITABLE
125 OptionDefaults option_defaults_{};
126
127 /// The list of options, stored locally
128 std::vector<Option_p> options_{};
129
130 ///@}
131 /// @name Help
132 ///@{
133
134 /// Footer to put after all options in the help output INHERITABLE
135 std::string footer_{};
136
137 /// This is a function that generates a footer to put after all other options in help output
138 std::function<std::string()> footer_callback_{};
139
140 /// A pointer to the help flag if there is one INHERITABLE
141 Option *help_ptr_{nullptr};
142
143 /// A pointer to the help all flag if there is one INHERITABLE
144 Option *help_all_ptr_{nullptr};
145
146 /// A pointer to a version flag if there is one
147 Option *version_ptr_{nullptr};
148
149 /// This is the formatter for help printing. Default provided. INHERITABLE (same pointer)
150 std::shared_ptr<FormatterBase> formatter_{new Formatter()};
151
152 /// The error message printing function INHERITABLE
153 std::function<std::string(const App *, const Error &e)> failure_message_{FailureMessage::simple};
154
155 ///@}
156 /// @name Parsing
157 ///@{
158
159 using missing_t = std::vector<std::pair<detail::Classifier, std::string>>;
160
161 /// Pair of classifier, string for missing options. (extra detail is removed on returning from parse)
162 ///
163 /// This is faster and cleaner than storing just a list of strings and reparsing. This may contain the -- separator.
164 missing_t missing_{};
165
166 /// This is a list of pointers to options with the original parse order
167 std::vector<Option *> parse_order_{};
168
169 /// This is a list of the subcommands collected, in order
170 std::vector<App *> parsed_subcommands_{};
171
172 /// this is a list of subcommands that are exclusionary to this one
173 std::set<App *> exclude_subcommands_{};
174
175 /// This is a list of options which are exclusionary to this App, if the options were used this subcommand should
176 /// not be
177 std::set<Option *> exclude_options_{};
178
179 /// this is a list of subcommands or option groups that are required by this one, the list is not mutual, the
180 /// listed subcommands do not require this one
181 std::set<App *> need_subcommands_{};
182
183 /// This is a list of options which are required by this app, the list is not mutual, listed options do not need the
184 /// subcommand not be
185 std::set<Option *> need_options_{};
186
187 ///@}
188 /// @name Subcommands
189 ///@{
190
191 /// Storage for subcommand list
192 std::vector<App_p> subcommands_{};
193
194 /// If true, the program name is not case sensitive INHERITABLE
195 bool ignore_case_{false};
196
197 /// If true, the program should ignore underscores INHERITABLE
198 bool ignore_underscore_{false};
199
200 /// Allow subcommand fallthrough, so that parent commands can collect commands after subcommand. INHERITABLE
201 bool fallthrough_{false};
202
203 /// Allow '/' for options for Windows like options. Defaults to true on Windows, false otherwise. INHERITABLE
204 bool allow_windows_style_options_{
205 #ifdef _WIN32
206 true
207 #else
208 false
209 #endif
210 };
211 /// specify that positional arguments come at the end of the argument sequence not inheritable
212 bool positionals_at_end_{false};
213
214 enum class startup_mode : char { stable, enabled, disabled };
215 /// specify the startup mode for the app
216 /// stable=no change, enabled= startup enabled, disabled=startup disabled
217 startup_mode default_startup{startup_mode::stable};
218
219 /// if set to true the subcommand can be triggered via configuration files INHERITABLE
220 bool configurable_{false};
221
222 /// If set to true positional options are validated before assigning INHERITABLE
223 bool validate_positionals_{false};
224
225 /// indicator that the subcommand is silent and won't show up in subcommands list
226 /// This is potentially useful as a modifier subcommand
227 bool silent_{false};
228
229 /// Counts the number of times this command/subcommand was parsed
230 std::uint32_t parsed_{0U};
231
232 /// Minimum required subcommands (not inheritable!)
233 std::size_t require_subcommand_min_{0};
234
235 /// Max number of subcommands allowed (parsing stops after this number). 0 is unlimited INHERITABLE
236 std::size_t require_subcommand_max_{0};
237
238 /// Minimum required options (not inheritable!)
239 std::size_t require_option_min_{0};
240
241 /// Max number of options allowed. 0 is unlimited (not inheritable)
242 std::size_t require_option_max_{0};
243
244 /// A pointer to the parent if this is a subcommand
245 App *parent_{nullptr};
246
247 /// The group membership INHERITABLE
248 std::string group_{"Subcommands"};
249
250 /// Alias names for the subcommand
251 std::vector<std::string> aliases_{};
252
253 ///@}
254 /// @name Config
255 ///@{
256
257 /// Pointer to the config option
258 Option *config_ptr_{nullptr};
259
260 /// This is the formatter for help printing. Default provided. INHERITABLE (same pointer)
261 std::shared_ptr<Config> config_formatter_{new ConfigTOML()};
262
263 ///@}
264
265 /// Special private constructor for subcommand
App(std::string app_description,std::string app_name,App * parent)266 App(std::string app_description, std::string app_name, App *parent)
267 : name_(std::move(app_name)), description_(std::move(app_description)), parent_(parent) {
268 // Inherit if not from a nullptr
269 if(parent_ != nullptr) {
270 if(parent_->help_ptr_ != nullptr)
271 set_help_flag(parent_->help_ptr_->get_name(false, true), parent_->help_ptr_->get_description());
272 if(parent_->help_all_ptr_ != nullptr)
273 set_help_all_flag(parent_->help_all_ptr_->get_name(false, true),
274 parent_->help_all_ptr_->get_description());
275
276 /// OptionDefaults
277 option_defaults_ = parent_->option_defaults_;
278
279 // INHERITABLE
280 failure_message_ = parent_->failure_message_;
281 allow_extras_ = parent_->allow_extras_;
282 allow_config_extras_ = parent_->allow_config_extras_;
283 prefix_command_ = parent_->prefix_command_;
284 immediate_callback_ = parent_->immediate_callback_;
285 ignore_case_ = parent_->ignore_case_;
286 ignore_underscore_ = parent_->ignore_underscore_;
287 fallthrough_ = parent_->fallthrough_;
288 validate_positionals_ = parent_->validate_positionals_;
289 configurable_ = parent_->configurable_;
290 allow_windows_style_options_ = parent_->allow_windows_style_options_;
291 group_ = parent_->group_;
292 footer_ = parent_->footer_;
293 formatter_ = parent_->formatter_;
294 config_formatter_ = parent_->config_formatter_;
295 require_subcommand_max_ = parent_->require_subcommand_max_;
296 }
297 }
298
299 public:
300 /// @name Basic
301 ///@{
302
303 /// Create a new program. Pass in the same arguments as main(), along with a help string.
App(std::string app_description="",std::string app_name="")304 explicit App(std::string app_description = "", std::string app_name = "")
305 : App(app_description, app_name, nullptr) {
306 set_help_flag("-h,--help", "Print this help message and exit");
307 }
308
309 App(const App &) = delete;
310 App &operator=(const App &) = delete;
311
312 /// virtual destructor
313 virtual ~App() = default;
314
315 /// Set a callback for execution when all parsing and processing has completed
316 ///
317 /// Due to a bug in c++11,
318 /// it is not possible to overload on std::function (fixed in c++14
319 /// and backported to c++11 on newer compilers). Use capture by reference
320 /// to get a pointer to App if needed.
callback(std::function<void ()> app_callback)321 App *callback(std::function<void()> app_callback) {
322 if(immediate_callback_) {
323 parse_complete_callback_ = std::move(app_callback);
324 } else {
325 final_callback_ = std::move(app_callback);
326 }
327 return this;
328 }
329
330 /// Set a callback for execution when all parsing and processing has completed
331 /// aliased as callback
final_callback(std::function<void ()> app_callback)332 App *final_callback(std::function<void()> app_callback) {
333 final_callback_ = std::move(app_callback);
334 return this;
335 }
336
337 /// Set a callback to execute when parsing has completed for the app
338 ///
parse_complete_callback(std::function<void ()> pc_callback)339 App *parse_complete_callback(std::function<void()> pc_callback) {
340 parse_complete_callback_ = std::move(pc_callback);
341 return this;
342 }
343
344 /// Set a callback to execute prior to parsing.
345 ///
preparse_callback(std::function<void (std::size_t)> pp_callback)346 App *preparse_callback(std::function<void(std::size_t)> pp_callback) {
347 pre_parse_callback_ = std::move(pp_callback);
348 return this;
349 }
350
351 /// Set a name for the app (empty will use parser to set the name)
name(std::string app_name="")352 App *name(std::string app_name = "") {
353
354 if(parent_ != nullptr) {
355 auto oname = name_;
356 name_ = app_name;
357 auto &res = _compare_subcommand_names(*this, *_get_fallthrough_parent());
358 if(!res.empty()) {
359 name_ = oname;
360 throw(OptionAlreadyAdded(app_name + " conflicts with existing subcommand names"));
361 }
362 } else {
363 name_ = app_name;
364 }
365 has_automatic_name_ = false;
366 return this;
367 }
368
369 /// Set an alias for the app
alias(std::string app_name)370 App *alias(std::string app_name) {
371 if(app_name.empty() || !detail::valid_alias_name_string(app_name)) {
372 throw IncorrectConstruction("Aliases may not be empty or contain newlines or null characters");
373 }
374 if(parent_ != nullptr) {
375 aliases_.push_back(app_name);
376 auto &res = _compare_subcommand_names(*this, *_get_fallthrough_parent());
377 if(!res.empty()) {
378 aliases_.pop_back();
379 throw(OptionAlreadyAdded("alias already matches an existing subcommand: " + app_name));
380 }
381 } else {
382 aliases_.push_back(app_name);
383 }
384
385 return this;
386 }
387
388 /// Remove the error when extras are left over on the command line.
allow_extras(bool allow=true)389 App *allow_extras(bool allow = true) {
390 allow_extras_ = allow;
391 return this;
392 }
393
394 /// Remove the error when extras are left over on the command line.
required(bool require=true)395 App *required(bool require = true) {
396 required_ = require;
397 return this;
398 }
399
400 /// Disable the subcommand or option group
disabled(bool disable=true)401 App *disabled(bool disable = true) {
402 disabled_ = disable;
403 return this;
404 }
405
406 /// silence the subcommand from showing up in the processed list
silent(bool silence=true)407 App *silent(bool silence = true) {
408 silent_ = silence;
409 return this;
410 }
411
412 /// Set the subcommand to be disabled by default, so on clear(), at the start of each parse it is disabled
disabled_by_default(bool disable=true)413 App *disabled_by_default(bool disable = true) {
414 if(disable) {
415 default_startup = startup_mode::disabled;
416 } else {
417 default_startup = (default_startup == startup_mode::enabled) ? startup_mode::enabled : startup_mode::stable;
418 }
419 return this;
420 }
421
422 /// Set the subcommand to be enabled by default, so on clear(), at the start of each parse it is enabled (not
423 /// disabled)
enabled_by_default(bool enable=true)424 App *enabled_by_default(bool enable = true) {
425 if(enable) {
426 default_startup = startup_mode::enabled;
427 } else {
428 default_startup =
429 (default_startup == startup_mode::disabled) ? startup_mode::disabled : startup_mode::stable;
430 }
431 return this;
432 }
433
434 /// Set the subcommand callback to be executed immediately on subcommand completion
immediate_callback(bool immediate=true)435 App *immediate_callback(bool immediate = true) {
436 immediate_callback_ = immediate;
437 if(immediate_callback_) {
438 if(final_callback_ && !(parse_complete_callback_)) {
439 std::swap(final_callback_, parse_complete_callback_);
440 }
441 } else if(!(final_callback_) && parse_complete_callback_) {
442 std::swap(final_callback_, parse_complete_callback_);
443 }
444 return this;
445 }
446
447 /// Set the subcommand to validate positional arguments before assigning
validate_positionals(bool validate=true)448 App *validate_positionals(bool validate = true) {
449 validate_positionals_ = validate;
450 return this;
451 }
452
453 /// ignore extras in config files
allow_config_extras(bool allow=true)454 App *allow_config_extras(bool allow = true) {
455 if(allow) {
456 allow_config_extras_ = config_extras_mode::capture;
457 allow_extras_ = true;
458 } else {
459 allow_config_extras_ = config_extras_mode::error;
460 }
461 return this;
462 }
463
464 /// ignore extras in config files
allow_config_extras(config_extras_mode mode)465 App *allow_config_extras(config_extras_mode mode) {
466 allow_config_extras_ = mode;
467 return this;
468 }
469
470 /// Do not parse anything after the first unrecognized option and return
prefix_command(bool allow=true)471 App *prefix_command(bool allow = true) {
472 prefix_command_ = allow;
473 return this;
474 }
475
476 /// Ignore case. Subcommands inherit value.
ignore_case(bool value=true)477 App *ignore_case(bool value = true) {
478 if(value && !ignore_case_) {
479 ignore_case_ = true;
480 auto *p = (parent_ != nullptr) ? _get_fallthrough_parent() : this;
481 auto &match = _compare_subcommand_names(*this, *p);
482 if(!match.empty()) {
483 ignore_case_ = false; // we are throwing so need to be exception invariant
484 throw OptionAlreadyAdded("ignore case would cause subcommand name conflicts: " + match);
485 }
486 }
487 ignore_case_ = value;
488 return this;
489 }
490
491 /// Allow windows style options, such as `/opt`. First matching short or long name used. Subcommands inherit
492 /// value.
allow_windows_style_options(bool value=true)493 App *allow_windows_style_options(bool value = true) {
494 allow_windows_style_options_ = value;
495 return this;
496 }
497
498 /// Specify that the positional arguments are only at the end of the sequence
positionals_at_end(bool value=true)499 App *positionals_at_end(bool value = true) {
500 positionals_at_end_ = value;
501 return this;
502 }
503
504 /// Specify that the subcommand can be triggered by a config file
configurable(bool value=true)505 App *configurable(bool value = true) {
506 configurable_ = value;
507 return this;
508 }
509
510 /// Ignore underscore. Subcommands inherit value.
ignore_underscore(bool value=true)511 App *ignore_underscore(bool value = true) {
512 if(value && !ignore_underscore_) {
513 ignore_underscore_ = true;
514 auto *p = (parent_ != nullptr) ? _get_fallthrough_parent() : this;
515 auto &match = _compare_subcommand_names(*this, *p);
516 if(!match.empty()) {
517 ignore_underscore_ = false;
518 throw OptionAlreadyAdded("ignore underscore would cause subcommand name conflicts: " + match);
519 }
520 }
521 ignore_underscore_ = value;
522 return this;
523 }
524
525 /// Set the help formatter
formatter(std::shared_ptr<FormatterBase> fmt)526 App *formatter(std::shared_ptr<FormatterBase> fmt) {
527 formatter_ = fmt;
528 return this;
529 }
530
531 /// Set the help formatter
formatter_fn(std::function<std::string (const App *,std::string,AppFormatMode)> fmt)532 App *formatter_fn(std::function<std::string(const App *, std::string, AppFormatMode)> fmt) {
533 formatter_ = std::make_shared<FormatterLambda>(fmt);
534 return this;
535 }
536
537 /// Set the config formatter
config_formatter(std::shared_ptr<Config> fmt)538 App *config_formatter(std::shared_ptr<Config> fmt) {
539 config_formatter_ = fmt;
540 return this;
541 }
542
543 /// Check to see if this subcommand was parsed, true only if received on command line.
parsed() const544 bool parsed() const { return parsed_ > 0; }
545
546 /// Get the OptionDefault object, to set option defaults
option_defaults()547 OptionDefaults *option_defaults() { return &option_defaults_; }
548
549 ///@}
550 /// @name Adding options
551 ///@{
552
553 /// Add an option, will automatically understand the type for common types.
554 ///
555 /// To use, create a variable with the expected type, and pass it in after the name.
556 /// After start is called, you can use count to see if the value was passed, and
557 /// the value will be initialized properly. Numbers, vectors, and strings are supported.
558 ///
559 /// ->required(), ->default, and the validators are options,
560 /// The positional options take an optional number of arguments.
561 ///
562 /// For example,
563 ///
564 /// std::string filename;
565 /// program.add_option("filename", filename, "description of filename");
566 ///
add_option(std::string option_name,callback_t option_callback,std::string option_description="",bool defaulted=false,std::function<std::string ()> func={})567 Option *add_option(std::string option_name,
568 callback_t option_callback,
569 std::string option_description = "",
570 bool defaulted = false,
571 std::function<std::string()> func = {}) {
572 Option myopt{option_name, option_description, option_callback, this};
573
__anonf4600cca0102(const Option_p &v) 574 if(std::find_if(std::begin(options_), std::end(options_), [&myopt](const Option_p &v) {
575 return *v == myopt;
576 }) == std::end(options_)) {
577 options_.emplace_back();
578 Option_p &option = options_.back();
579 option.reset(new Option(option_name, option_description, option_callback, this));
580
581 // Set the default string capture function
582 option->default_function(func);
583
584 // For compatibility with CLI11 1.7 and before, capture the default string here
585 if(defaulted)
586 option->capture_default_str();
587
588 // Transfer defaults to the new option
589 option_defaults_.copy_to(option.get());
590
591 // Don't bother to capture if we already did
592 if(!defaulted && option->get_always_capture_default())
593 option->capture_default_str();
594
595 return option.get();
596 }
597 // we know something matches now find what it is so we can produce more error information
598 for(auto &opt : options_) {
599 auto &matchname = opt->matching_name(myopt);
600 if(!matchname.empty()) {
601 throw(OptionAlreadyAdded("added option matched existing option name: " + matchname));
602 }
603 }
604 // this line should not be reached the above loop should trigger the throw
605 throw(OptionAlreadyAdded("added option matched existing option name")); // LCOV_EXCL_LINE
606 }
607
608 /// Add option for assigning to a variable
609 template <typename AssignTo,
610 typename ConvertTo = AssignTo,
611 enable_if_t<!std::is_const<ConvertTo>::value, detail::enabler> = detail::dummy>
add_option(std::string option_name,AssignTo & variable,std::string option_description="")612 Option *add_option(std::string option_name,
613 AssignTo &variable, ///< The variable to set
614 std::string option_description = "") {
615
616 auto fun = [&variable](const CLI::results_t &res) { // comment for spacing
617 return detail::lexical_conversion<AssignTo, ConvertTo>(res, variable);
618 };
619
620 Option *opt = add_option(option_name, fun, option_description, false, [&variable]() {
621 return CLI::detail::checked_to_string<AssignTo, ConvertTo>(variable);
622 });
623 opt->type_name(detail::type_name<ConvertTo>());
624 // these must be actual lvalues since (std::max) sometimes is defined in terms of references and references
625 // to structs used in the evaluation can be temporary so that would cause issues.
626 auto Tcount = detail::type_count<AssignTo>::value;
627 auto XCcount = detail::type_count<ConvertTo>::value;
628 opt->type_size(detail::type_count_min<ConvertTo>::value, (std::max)(Tcount, XCcount));
629 opt->expected(detail::expected_count<ConvertTo>::value);
630 opt->run_callback_for_default();
631 return opt;
632 }
633
634 /// Add option for assigning to a variable
635 template <typename AssignTo, enable_if_t<!std::is_const<AssignTo>::value, detail::enabler> = detail::dummy>
add_option_no_stream(std::string option_name,AssignTo & variable,std::string option_description="")636 Option *add_option_no_stream(std::string option_name,
637 AssignTo &variable, ///< The variable to set
638 std::string option_description = "") {
639
640 auto fun = [&variable](const CLI::results_t &res) { // comment for spacing
641 return detail::lexical_conversion<AssignTo, AssignTo>(res, variable);
642 };
643
644 Option *opt = add_option(option_name, fun, option_description, false, []() { return std::string{}; });
645 opt->type_name(detail::type_name<AssignTo>());
646 opt->type_size(detail::type_count_min<AssignTo>::value, detail::type_count<AssignTo>::value);
647 opt->expected(detail::expected_count<AssignTo>::value);
648 opt->run_callback_for_default();
649 return opt;
650 }
651
652 /// Add option for a callback of a specific type
653 template <typename ArgType>
add_option_function(std::string option_name,const std::function<void (const ArgType &)> & func,std::string option_description="")654 Option *add_option_function(std::string option_name,
655 const std::function<void(const ArgType &)> &func, ///< the callback to execute
656 std::string option_description = "") {
657
658 auto fun = [func](const CLI::results_t &res) {
659 ArgType variable;
660 bool result = detail::lexical_conversion<ArgType, ArgType>(res, variable);
661 if(result) {
662 func(variable);
663 }
664 return result;
665 };
666
667 Option *opt = add_option(option_name, std::move(fun), option_description, false);
668 opt->type_name(detail::type_name<ArgType>());
669 opt->type_size(detail::type_count_min<ArgType>::value, detail::type_count<ArgType>::value);
670 opt->expected(detail::expected_count<ArgType>::value);
671 return opt;
672 }
673
674 /// Add option with no description or variable assignment
add_option(std::string option_name)675 Option *add_option(std::string option_name) {
676 return add_option(option_name, CLI::callback_t{}, std::string{}, false);
677 }
678
679 /// Add option with description but with no variable assignment or callback
680 template <typename T,
681 enable_if_t<std::is_const<T>::value && std::is_constructible<std::string, T>::value, detail::enabler> =
682 detail::dummy>
add_option(std::string option_name,T & option_description)683 Option *add_option(std::string option_name, T &option_description) {
684 return add_option(option_name, CLI::callback_t(), option_description, false);
685 }
686
687 /// Set a help flag, replace the existing one if present
set_help_flag(std::string flag_name="",const std::string & help_description="")688 Option *set_help_flag(std::string flag_name = "", const std::string &help_description = "") {
689 // take flag_description by const reference otherwise add_flag tries to assign to help_description
690 if(help_ptr_ != nullptr) {
691 remove_option(help_ptr_);
692 help_ptr_ = nullptr;
693 }
694
695 // Empty name will simply remove the help flag
696 if(!flag_name.empty()) {
697 help_ptr_ = add_flag(flag_name, help_description);
698 help_ptr_->configurable(false);
699 }
700
701 return help_ptr_;
702 }
703
704 /// Set a help all flag, replaced the existing one if present
set_help_all_flag(std::string help_name="",const std::string & help_description="")705 Option *set_help_all_flag(std::string help_name = "", const std::string &help_description = "") {
706 // take flag_description by const reference otherwise add_flag tries to assign to flag_description
707 if(help_all_ptr_ != nullptr) {
708 remove_option(help_all_ptr_);
709 help_all_ptr_ = nullptr;
710 }
711
712 // Empty name will simply remove the help all flag
713 if(!help_name.empty()) {
714 help_all_ptr_ = add_flag(help_name, help_description);
715 help_all_ptr_->configurable(false);
716 }
717
718 return help_all_ptr_;
719 }
720
721 /// Set a version flag and version display string, replace the existing one if present
set_version_flag(std::string flag_name="",const std::string & versionString="",const std::string & version_help="Display program version information and exit")722 Option *set_version_flag(std::string flag_name = "",
723 const std::string &versionString = "",
724 const std::string &version_help = "Display program version information and exit") {
725 // take flag_description by const reference otherwise add_flag tries to assign to version_description
726 if(version_ptr_ != nullptr) {
727 remove_option(version_ptr_);
728 version_ptr_ = nullptr;
729 }
730
731 // Empty name will simply remove the version flag
732 if(!flag_name.empty()) {
733 version_ptr_ = add_flag_callback(
734 flag_name, [versionString]() { throw(CLI::CallForVersion(versionString, 0)); }, version_help);
735 version_ptr_->configurable(false);
736 }
737
738 return version_ptr_;
739 }
740 /// Generate the version string through a callback function
set_version_flag(std::string flag_name,std::function<std::string ()> vfunc,const std::string & version_help="Display program version information and exit")741 Option *set_version_flag(std::string flag_name,
742 std::function<std::string()> vfunc,
743 const std::string &version_help = "Display program version information and exit") {
744 if(version_ptr_ != nullptr) {
745 remove_option(version_ptr_);
746 version_ptr_ = nullptr;
747 }
748
749 // Empty name will simply remove the version flag
750 if(!flag_name.empty()) {
751 version_ptr_ = add_flag_callback(
752 flag_name, [vfunc]() { throw(CLI::CallForVersion(vfunc(), 0)); }, version_help);
753 version_ptr_->configurable(false);
754 }
755
756 return version_ptr_;
757 }
758
759 private:
760 /// Internal function for adding a flag
_add_flag_internal(std::string flag_name,CLI::callback_t fun,std::string flag_description)761 Option *_add_flag_internal(std::string flag_name, CLI::callback_t fun, std::string flag_description) {
762 Option *opt;
763 if(detail::has_default_flag_values(flag_name)) {
764 // check for default values and if it has them
765 auto flag_defaults = detail::get_default_flag_values(flag_name);
766 detail::remove_default_flag_values(flag_name);
767 opt = add_option(std::move(flag_name), std::move(fun), std::move(flag_description), false);
768 for(const auto &fname : flag_defaults)
769 opt->fnames_.push_back(fname.first);
770 opt->default_flag_values_ = std::move(flag_defaults);
771 } else {
772 opt = add_option(std::move(flag_name), std::move(fun), std::move(flag_description), false);
773 }
774 // flags cannot have positional values
775 if(opt->get_positional()) {
776 auto pos_name = opt->get_name(true);
777 remove_option(opt);
778 throw IncorrectConstruction::PositionalFlag(pos_name);
779 }
780 opt->multi_option_policy(MultiOptionPolicy::TakeLast);
781 opt->expected(0);
782 opt->required(false);
783 return opt;
784 }
785
786 public:
787 /// Add a flag with no description or variable assignment
add_flag(std::string flag_name)788 Option *add_flag(std::string flag_name) { return _add_flag_internal(flag_name, CLI::callback_t(), std::string{}); }
789
790 /// Add flag with description but with no variable assignment or callback
791 /// takes a constant string, if a variable string is passed that variable will be assigned the results from the
792 /// flag
793 template <typename T,
794 enable_if_t<std::is_const<T>::value && std::is_constructible<std::string, T>::value, detail::enabler> =
795 detail::dummy>
add_flag(std::string flag_name,T & flag_description)796 Option *add_flag(std::string flag_name, T &flag_description) {
797 return _add_flag_internal(flag_name, CLI::callback_t(), flag_description);
798 }
799
800 /// Add option for flag with integer result - defaults to allowing multiple passings, but can be forced to one
801 /// if `multi_option_policy(CLI::MultiOptionPolicy::Throw)` is used.
802 template <typename T,
803 enable_if_t<std::is_constructible<T, std::int64_t>::value && !is_bool<T>::value, detail::enabler> =
804 detail::dummy>
add_flag(std::string flag_name,T & flag_count,std::string flag_description="")805 Option *add_flag(std::string flag_name,
806 T &flag_count, ///< A variable holding the count
807 std::string flag_description = "") {
808 flag_count = 0;
809 CLI::callback_t fun = [&flag_count](const CLI::results_t &res) {
810 try {
811 detail::sum_flag_vector(res, flag_count);
812 } catch(const std::invalid_argument &) {
813 return false;
814 }
815 return true;
816 };
817 return _add_flag_internal(flag_name, std::move(fun), std::move(flag_description))
818 ->multi_option_policy(MultiOptionPolicy::TakeAll);
819 }
820
821 /// Other type version accepts all other types that are not vectors such as bool, enum, string or other classes
822 /// that can be converted from a string
823 template <typename T,
824 enable_if_t<!detail::is_mutable_container<T>::value && !std::is_const<T>::value &&
825 (!std::is_constructible<T, std::int64_t>::value || is_bool<T>::value) &&
826 !std::is_constructible<std::function<void(int)>, T>::value,
827 detail::enabler> = detail::dummy>
add_flag(std::string flag_name,T & flag_result,std::string flag_description="")828 Option *add_flag(std::string flag_name,
829 T &flag_result, ///< A variable holding true if passed
830 std::string flag_description = "") {
831
832 CLI::callback_t fun = [&flag_result](const CLI::results_t &res) {
833 return CLI::detail::lexical_cast(res[0], flag_result);
834 };
835 return _add_flag_internal(flag_name, std::move(fun), std::move(flag_description))->run_callback_for_default();
836 }
837
838 /// Vector version to capture multiple flags.
839 template <typename T,
840 enable_if_t<!std::is_assignable<std::function<void(std::int64_t)> &, T>::value, detail::enabler> =
841 detail::dummy>
add_flag(std::string flag_name,std::vector<T> & flag_results,std::string flag_description="")842 Option *add_flag(std::string flag_name,
843 std::vector<T> &flag_results, ///< A vector of values with the flag results
844 std::string flag_description = "") {
845 CLI::callback_t fun = [&flag_results](const CLI::results_t &res) {
846 bool retval = true;
847 for(const auto &elem : res) {
848 flag_results.emplace_back();
849 retval &= detail::lexical_cast(elem, flag_results.back());
850 }
851 return retval;
852 };
853 return _add_flag_internal(flag_name, std::move(fun), std::move(flag_description))
854 ->multi_option_policy(MultiOptionPolicy::TakeAll)
855 ->run_callback_for_default();
856 }
857
858 /// Add option for callback that is triggered with a true flag and takes no arguments
add_flag_callback(std::string flag_name,std::function<void (void)> function,std::string flag_description="")859 Option *add_flag_callback(std::string flag_name,
860 std::function<void(void)> function, ///< A function to call, void(void)
861 std::string flag_description = "") {
862
863 CLI::callback_t fun = [function](const CLI::results_t &res) {
864 bool trigger{false};
865 auto result = CLI::detail::lexical_cast(res[0], trigger);
866 if(result && trigger) {
867 function();
868 }
869 return result;
870 };
871 return _add_flag_internal(flag_name, std::move(fun), std::move(flag_description));
872 }
873
874 /// Add option for callback with an integer value
add_flag_function(std::string flag_name,std::function<void (std::int64_t)> function,std::string flag_description="")875 Option *add_flag_function(std::string flag_name,
876 std::function<void(std::int64_t)> function, ///< A function to call, void(int)
877 std::string flag_description = "") {
878
879 CLI::callback_t fun = [function](const CLI::results_t &res) {
880 std::int64_t flag_count = 0;
881 detail::sum_flag_vector(res, flag_count);
882 function(flag_count);
883 return true;
884 };
885 return _add_flag_internal(flag_name, std::move(fun), std::move(flag_description))
886 ->multi_option_policy(MultiOptionPolicy::TakeAll);
887 }
888
889 #ifdef CLI11_CPP14
890 /// Add option for callback (C++14 or better only)
add_flag(std::string flag_name,std::function<void (std::int64_t)> function,std::string flag_description="")891 Option *add_flag(std::string flag_name,
892 std::function<void(std::int64_t)> function, ///< A function to call, void(std::int64_t)
893 std::string flag_description = "") {
894 return add_flag_function(std::move(flag_name), std::move(function), std::move(flag_description));
895 }
896 #endif
897
898 /// Set a configuration ini file option, or clear it if no name passed
set_config(std::string option_name="",std::string default_filename="",const std::string & help_message="Read an ini file",bool config_required=false)899 Option *set_config(std::string option_name = "",
900 std::string default_filename = "",
901 const std::string &help_message = "Read an ini file",
902 bool config_required = false) {
903
904 // Remove existing config if present
905 if(config_ptr_ != nullptr) {
906 remove_option(config_ptr_);
907 config_ptr_ = nullptr; // need to remove the config_ptr completely
908 }
909
910 // Only add config if option passed
911 if(!option_name.empty()) {
912 config_ptr_ = add_option(option_name, help_message);
913 if(config_required) {
914 config_ptr_->required();
915 }
916 if(!default_filename.empty()) {
917 config_ptr_->default_str(std::move(default_filename));
918 }
919 config_ptr_->configurable(false);
920 }
921
922 return config_ptr_;
923 }
924
925 /// Removes an option from the App. Takes an option pointer. Returns true if found and removed.
remove_option(Option * opt)926 bool remove_option(Option *opt) {
927 // Make sure no links exist
928 for(Option_p &op : options_) {
929 op->remove_needs(opt);
930 op->remove_excludes(opt);
931 }
932
933 if(help_ptr_ == opt)
934 help_ptr_ = nullptr;
935 if(help_all_ptr_ == opt)
936 help_all_ptr_ = nullptr;
937
938 auto iterator =
939 std::find_if(std::begin(options_), std::end(options_), [opt](const Option_p &v) { return v.get() == opt; });
940 if(iterator != std::end(options_)) {
941 options_.erase(iterator);
942 return true;
943 }
944 return false;
945 }
946
947 /// creates an option group as part of the given app
948 template <typename T = Option_group>
add_option_group(std::string group_name,std::string group_description="")949 T *add_option_group(std::string group_name, std::string group_description = "") {
950 if(!detail::valid_alias_name_string(group_name)) {
951 throw IncorrectConstruction("option group names may not contain newlines or null characters");
952 }
953 auto option_group = std::make_shared<T>(std::move(group_description), group_name, this);
954 auto ptr = option_group.get();
955 // move to App_p for overload resolution on older gcc versions
956 App_p app_ptr = std::dynamic_pointer_cast<App>(option_group);
957 add_subcommand(std::move(app_ptr));
958 return ptr;
959 }
960
961 ///@}
962 /// @name Subcommands
963 ///@{
964
965 /// Add a subcommand. Inherits INHERITABLE and OptionDefaults, and help flag
add_subcommand(std::string subcommand_name="",std::string subcommand_description="")966 App *add_subcommand(std::string subcommand_name = "", std::string subcommand_description = "") {
967 if(!subcommand_name.empty() && !detail::valid_name_string(subcommand_name)) {
968 if(!detail::valid_first_char(subcommand_name[0])) {
969 throw IncorrectConstruction(
970 "Subcommand name starts with invalid character, '!' and '-' are not allowed");
971 }
972 for(auto c : subcommand_name) {
973 if(!detail::valid_later_char(c)) {
974 throw IncorrectConstruction(std::string("Subcommand name contains invalid character ('") + c +
975 "'), all characters are allowed except"
976 "'=',':','{','}', and ' '");
977 }
978 }
979 }
980 CLI::App_p subcom = std::shared_ptr<App>(new App(std::move(subcommand_description), subcommand_name, this));
981 return add_subcommand(std::move(subcom));
982 }
983
984 /// Add a previously created app as a subcommand
add_subcommand(CLI::App_p subcom)985 App *add_subcommand(CLI::App_p subcom) {
986 if(!subcom)
987 throw IncorrectConstruction("passed App is not valid");
988 auto ckapp = (name_.empty() && parent_ != nullptr) ? _get_fallthrough_parent() : this;
989 auto &mstrg = _compare_subcommand_names(*subcom, *ckapp);
990 if(!mstrg.empty()) {
991 throw(OptionAlreadyAdded("subcommand name or alias matches existing subcommand: " + mstrg));
992 }
993 subcom->parent_ = this;
994 subcommands_.push_back(std::move(subcom));
995 return subcommands_.back().get();
996 }
997
998 /// Removes a subcommand from the App. Takes a subcommand pointer. Returns true if found and removed.
remove_subcommand(App * subcom)999 bool remove_subcommand(App *subcom) {
1000 // Make sure no links exist
1001 for(App_p &sub : subcommands_) {
1002 sub->remove_excludes(subcom);
1003 sub->remove_needs(subcom);
1004 }
1005
1006 auto iterator = std::find_if(
1007 std::begin(subcommands_), std::end(subcommands_), [subcom](const App_p &v) { return v.get() == subcom; });
1008 if(iterator != std::end(subcommands_)) {
1009 subcommands_.erase(iterator);
1010 return true;
1011 }
1012 return false;
1013 }
1014 /// Check to see if a subcommand is part of this command (doesn't have to be in command line)
1015 /// returns the first subcommand if passed a nullptr
get_subcommand(const App * subcom) const1016 App *get_subcommand(const App *subcom) const {
1017 if(subcom == nullptr)
1018 throw OptionNotFound("nullptr passed");
1019 for(const App_p &subcomptr : subcommands_)
1020 if(subcomptr.get() == subcom)
1021 return subcomptr.get();
1022 throw OptionNotFound(subcom->get_name());
1023 }
1024
1025 /// Check to see if a subcommand is part of this command (text version)
get_subcommand(std::string subcom) const1026 App *get_subcommand(std::string subcom) const {
1027 auto subc = _find_subcommand(subcom, false, false);
1028 if(subc == nullptr)
1029 throw OptionNotFound(subcom);
1030 return subc;
1031 }
1032 /// Get a pointer to subcommand by index
get_subcommand(int index=0) const1033 App *get_subcommand(int index = 0) const {
1034 if(index >= 0) {
1035 auto uindex = static_cast<unsigned>(index);
1036 if(uindex < subcommands_.size())
1037 return subcommands_[uindex].get();
1038 }
1039 throw OptionNotFound(std::to_string(index));
1040 }
1041
1042 /// Check to see if a subcommand is part of this command and get a shared_ptr to it
get_subcommand_ptr(App * subcom) const1043 CLI::App_p get_subcommand_ptr(App *subcom) const {
1044 if(subcom == nullptr)
1045 throw OptionNotFound("nullptr passed");
1046 for(const App_p &subcomptr : subcommands_)
1047 if(subcomptr.get() == subcom)
1048 return subcomptr;
1049 throw OptionNotFound(subcom->get_name());
1050 }
1051
1052 /// Check to see if a subcommand is part of this command (text version)
get_subcommand_ptr(std::string subcom) const1053 CLI::App_p get_subcommand_ptr(std::string subcom) const {
1054 for(const App_p &subcomptr : subcommands_)
1055 if(subcomptr->check_name(subcom))
1056 return subcomptr;
1057 throw OptionNotFound(subcom);
1058 }
1059
1060 /// Get an owning pointer to subcommand by index
get_subcommand_ptr(int index=0) const1061 CLI::App_p get_subcommand_ptr(int index = 0) const {
1062 if(index >= 0) {
1063 auto uindex = static_cast<unsigned>(index);
1064 if(uindex < subcommands_.size())
1065 return subcommands_[uindex];
1066 }
1067 throw OptionNotFound(std::to_string(index));
1068 }
1069
1070 /// Check to see if an option group is part of this App
get_option_group(std::string group_name) const1071 App *get_option_group(std::string group_name) const {
1072 for(const App_p &app : subcommands_) {
1073 if(app->name_.empty() && app->group_ == group_name) {
1074 return app.get();
1075 }
1076 }
1077 throw OptionNotFound(group_name);
1078 }
1079
1080 /// No argument version of count counts the number of times this subcommand was
1081 /// passed in. The main app will return 1. Unnamed subcommands will also return 1 unless
1082 /// otherwise modified in a callback
count() const1083 std::size_t count() const { return parsed_; }
1084
1085 /// Get a count of all the arguments processed in options and subcommands, this excludes arguments which were
1086 /// treated as extras.
count_all() const1087 std::size_t count_all() const {
1088 std::size_t cnt{0};
1089 for(auto &opt : options_) {
1090 cnt += opt->count();
1091 }
1092 for(auto &sub : subcommands_) {
1093 cnt += sub->count_all();
1094 }
1095 if(!get_name().empty()) { // for named subcommands add the number of times the subcommand was called
1096 cnt += parsed_;
1097 }
1098 return cnt;
1099 }
1100
1101 /// Changes the group membership
group(std::string group_name)1102 App *group(std::string group_name) {
1103 group_ = group_name;
1104 return this;
1105 }
1106
1107 /// The argumentless form of require subcommand requires 1 or more subcommands
require_subcommand()1108 App *require_subcommand() {
1109 require_subcommand_min_ = 1;
1110 require_subcommand_max_ = 0;
1111 return this;
1112 }
1113
1114 /// Require a subcommand to be given (does not affect help call)
1115 /// The number required can be given. Negative values indicate maximum
1116 /// number allowed (0 for any number). Max number inheritable.
require_subcommand(int value)1117 App *require_subcommand(int value) {
1118 if(value < 0) {
1119 require_subcommand_min_ = 0;
1120 require_subcommand_max_ = static_cast<std::size_t>(-value);
1121 } else {
1122 require_subcommand_min_ = static_cast<std::size_t>(value);
1123 require_subcommand_max_ = static_cast<std::size_t>(value);
1124 }
1125 return this;
1126 }
1127
1128 /// Explicitly control the number of subcommands required. Setting 0
1129 /// for the max means unlimited number allowed. Max number inheritable.
require_subcommand(std::size_t min,std::size_t max)1130 App *require_subcommand(std::size_t min, std::size_t max) {
1131 require_subcommand_min_ = min;
1132 require_subcommand_max_ = max;
1133 return this;
1134 }
1135
1136 /// The argumentless form of require option requires 1 or more options be used
require_option()1137 App *require_option() {
1138 require_option_min_ = 1;
1139 require_option_max_ = 0;
1140 return this;
1141 }
1142
1143 /// Require an option to be given (does not affect help call)
1144 /// The number required can be given. Negative values indicate maximum
1145 /// number allowed (0 for any number).
require_option(int value)1146 App *require_option(int value) {
1147 if(value < 0) {
1148 require_option_min_ = 0;
1149 require_option_max_ = static_cast<std::size_t>(-value);
1150 } else {
1151 require_option_min_ = static_cast<std::size_t>(value);
1152 require_option_max_ = static_cast<std::size_t>(value);
1153 }
1154 return this;
1155 }
1156
1157 /// Explicitly control the number of options required. Setting 0
1158 /// for the max means unlimited number allowed. Max number inheritable.
require_option(std::size_t min,std::size_t max)1159 App *require_option(std::size_t min, std::size_t max) {
1160 require_option_min_ = min;
1161 require_option_max_ = max;
1162 return this;
1163 }
1164
1165 /// Stop subcommand fallthrough, so that parent commands cannot collect commands after subcommand.
1166 /// Default from parent, usually set on parent.
fallthrough(bool value=true)1167 App *fallthrough(bool value = true) {
1168 fallthrough_ = value;
1169 return this;
1170 }
1171
1172 /// Check to see if this subcommand was parsed, true only if received on command line.
1173 /// This allows the subcommand to be directly checked.
operator bool() const1174 explicit operator bool() const { return parsed_ > 0; }
1175
1176 ///@}
1177 /// @name Extras for subclassing
1178 ///@{
1179
1180 /// This allows subclasses to inject code before callbacks but after parse.
1181 ///
1182 /// This does not run if any errors or help is thrown.
pre_callback()1183 virtual void pre_callback() {}
1184
1185 ///@}
1186 /// @name Parsing
1187 ///@{
1188 //
1189 /// Reset the parsed data
clear()1190 void clear() {
1191
1192 parsed_ = 0;
1193 pre_parse_called_ = false;
1194
1195 missing_.clear();
1196 parsed_subcommands_.clear();
1197 for(const Option_p &opt : options_) {
1198 opt->clear();
1199 }
1200 for(const App_p &subc : subcommands_) {
1201 subc->clear();
1202 }
1203 }
1204
1205 /// Parses the command line - throws errors.
1206 /// This must be called after the options are in but before the rest of the program.
parse(int argc,const char * const * argv)1207 void parse(int argc, const char *const *argv) {
1208 // If the name is not set, read from command line
1209 if(name_.empty() || has_automatic_name_) {
1210 has_automatic_name_ = true;
1211 name_ = argv[0];
1212 }
1213
1214 std::vector<std::string> args;
1215 args.reserve(static_cast<std::size_t>(argc) - 1);
1216 for(int i = argc - 1; i > 0; i--)
1217 args.emplace_back(argv[i]);
1218 parse(std::move(args));
1219 }
1220
1221 /// Parse a single string as if it contained command line arguments.
1222 /// This function splits the string into arguments then calls parse(std::vector<std::string> &)
1223 /// the function takes an optional boolean argument specifying if the programName is included in the string to
1224 /// process
parse(std::string commandline,bool program_name_included=false)1225 void parse(std::string commandline, bool program_name_included = false) {
1226
1227 if(program_name_included) {
1228 auto nstr = detail::split_program_name(commandline);
1229 if((name_.empty()) || (has_automatic_name_)) {
1230 has_automatic_name_ = true;
1231 name_ = nstr.first;
1232 }
1233 commandline = std::move(nstr.second);
1234 } else {
1235 detail::trim(commandline);
1236 }
1237 // the next section of code is to deal with quoted arguments after an '=' or ':' for windows like operations
1238 if(!commandline.empty()) {
1239 commandline = detail::find_and_modify(commandline, "=", detail::escape_detect);
1240 if(allow_windows_style_options_)
1241 commandline = detail::find_and_modify(commandline, ":", detail::escape_detect);
1242 }
1243
1244 auto args = detail::split_up(std::move(commandline));
1245 // remove all empty strings
1246 args.erase(std::remove(args.begin(), args.end(), std::string{}), args.end());
1247 std::reverse(args.begin(), args.end());
1248
1249 parse(std::move(args));
1250 }
1251
1252 /// The real work is done here. Expects a reversed vector.
1253 /// Changes the vector to the remaining options.
parse(std::vector<std::string> & args)1254 void parse(std::vector<std::string> &args) {
1255 // Clear if parsed
1256 if(parsed_ > 0)
1257 clear();
1258
1259 // parsed_ is incremented in commands/subcommands,
1260 // but placed here to make sure this is cleared when
1261 // running parse after an error is thrown, even by _validate or _configure.
1262 parsed_ = 1;
1263 _validate();
1264 _configure();
1265 // set the parent as nullptr as this object should be the top now
1266 parent_ = nullptr;
1267 parsed_ = 0;
1268
1269 _parse(args);
1270 run_callback();
1271 }
1272
1273 /// The real work is done here. Expects a reversed vector.
parse(std::vector<std::string> && args)1274 void parse(std::vector<std::string> &&args) {
1275 // Clear if parsed
1276 if(parsed_ > 0)
1277 clear();
1278
1279 // parsed_ is incremented in commands/subcommands,
1280 // but placed here to make sure this is cleared when
1281 // running parse after an error is thrown, even by _validate or _configure.
1282 parsed_ = 1;
1283 _validate();
1284 _configure();
1285 // set the parent as nullptr as this object should be the top now
1286 parent_ = nullptr;
1287 parsed_ = 0;
1288
1289 _parse(std::move(args));
1290 run_callback();
1291 }
1292
parse_from_stream(std::istream & input)1293 void parse_from_stream(std::istream &input) {
1294 if(parsed_ == 0) {
1295 _validate();
1296 _configure();
1297 // set the parent as nullptr as this object should be the top now
1298 }
1299
1300 _parse_stream(input);
1301 run_callback();
1302 }
1303 /// Provide a function to print a help message. The function gets access to the App pointer and error.
failure_message(std::function<std::string (const App *,const Error & e)> function)1304 void failure_message(std::function<std::string(const App *, const Error &e)> function) {
1305 failure_message_ = function;
1306 }
1307
1308 /// Print a nice error message and return the exit code
exit(const Error & e,std::ostream & out=std::cout,std::ostream & err=std::cerr) const1309 int exit(const Error &e, std::ostream &out = std::cout, std::ostream &err = std::cerr) const {
1310
1311 /// Avoid printing anything if this is a CLI::RuntimeError
1312 if(e.get_name() == "RuntimeError")
1313 return e.get_exit_code();
1314
1315 if(e.get_name() == "CallForHelp") {
1316 out << help();
1317 return e.get_exit_code();
1318 }
1319
1320 if(e.get_name() == "CallForAllHelp") {
1321 out << help("", AppFormatMode::All);
1322 return e.get_exit_code();
1323 }
1324
1325 if(e.get_name() == "CallForVersion") {
1326 out << e.what() << std::endl;
1327 return e.get_exit_code();
1328 }
1329
1330 if(e.get_exit_code() != static_cast<int>(ExitCodes::Success)) {
1331 if(failure_message_)
1332 err << failure_message_(this, e) << std::flush;
1333 }
1334
1335 return e.get_exit_code();
1336 }
1337
1338 ///@}
1339 /// @name Post parsing
1340 ///@{
1341
1342 /// Counts the number of times the given option was passed.
count(std::string option_name) const1343 std::size_t count(std::string option_name) const { return get_option(option_name)->count(); }
1344
1345 /// Get a subcommand pointer list to the currently selected subcommands (after parsing by default, in command
1346 /// line order; use parsed = false to get the original definition list.)
get_subcommands() const1347 std::vector<App *> get_subcommands() const { return parsed_subcommands_; }
1348
1349 /// Get a filtered subcommand pointer list from the original definition list. An empty function will provide all
1350 /// subcommands (const)
get_subcommands(const std::function<bool (const App *)> & filter) const1351 std::vector<const App *> get_subcommands(const std::function<bool(const App *)> &filter) const {
1352 std::vector<const App *> subcomms(subcommands_.size());
1353 std::transform(std::begin(subcommands_), std::end(subcommands_), std::begin(subcomms), [](const App_p &v) {
1354 return v.get();
1355 });
1356
1357 if(filter) {
1358 subcomms.erase(std::remove_if(std::begin(subcomms),
1359 std::end(subcomms),
1360 [&filter](const App *app) { return !filter(app); }),
1361 std::end(subcomms));
1362 }
1363
1364 return subcomms;
1365 }
1366
1367 /// Get a filtered subcommand pointer list from the original definition list. An empty function will provide all
1368 /// subcommands
get_subcommands(const std::function<bool (App *)> & filter)1369 std::vector<App *> get_subcommands(const std::function<bool(App *)> &filter) {
1370 std::vector<App *> subcomms(subcommands_.size());
1371 std::transform(std::begin(subcommands_), std::end(subcommands_), std::begin(subcomms), [](const App_p &v) {
1372 return v.get();
1373 });
1374
1375 if(filter) {
1376 subcomms.erase(
1377 std::remove_if(std::begin(subcomms), std::end(subcomms), [&filter](App *app) { return !filter(app); }),
1378 std::end(subcomms));
1379 }
1380
1381 return subcomms;
1382 }
1383
1384 /// Check to see if given subcommand was selected
got_subcommand(const App * subcom) const1385 bool got_subcommand(const App *subcom) const {
1386 // get subcom needed to verify that this was a real subcommand
1387 return get_subcommand(subcom)->parsed_ > 0;
1388 }
1389
1390 /// Check with name instead of pointer to see if subcommand was selected
got_subcommand(std::string subcommand_name) const1391 bool got_subcommand(std::string subcommand_name) const { return get_subcommand(subcommand_name)->parsed_ > 0; }
1392
1393 /// Sets excluded options for the subcommand
excludes(Option * opt)1394 App *excludes(Option *opt) {
1395 if(opt == nullptr) {
1396 throw OptionNotFound("nullptr passed");
1397 }
1398 exclude_options_.insert(opt);
1399 return this;
1400 }
1401
1402 /// Sets excluded subcommands for the subcommand
excludes(App * app)1403 App *excludes(App *app) {
1404 if(app == nullptr) {
1405 throw OptionNotFound("nullptr passed");
1406 }
1407 if(app == this) {
1408 throw OptionNotFound("cannot self reference in needs");
1409 }
1410 auto res = exclude_subcommands_.insert(app);
1411 // subcommand exclusion should be symmetric
1412 if(res.second) {
1413 app->exclude_subcommands_.insert(this);
1414 }
1415 return this;
1416 }
1417
needs(Option * opt)1418 App *needs(Option *opt) {
1419 if(opt == nullptr) {
1420 throw OptionNotFound("nullptr passed");
1421 }
1422 need_options_.insert(opt);
1423 return this;
1424 }
1425
needs(App * app)1426 App *needs(App *app) {
1427 if(app == nullptr) {
1428 throw OptionNotFound("nullptr passed");
1429 }
1430 if(app == this) {
1431 throw OptionNotFound("cannot self reference in needs");
1432 }
1433 need_subcommands_.insert(app);
1434 return this;
1435 }
1436
1437 /// Removes an option from the excludes list of this subcommand
remove_excludes(Option * opt)1438 bool remove_excludes(Option *opt) {
1439 auto iterator = std::find(std::begin(exclude_options_), std::end(exclude_options_), opt);
1440 if(iterator == std::end(exclude_options_)) {
1441 return false;
1442 }
1443 exclude_options_.erase(iterator);
1444 return true;
1445 }
1446
1447 /// Removes a subcommand from the excludes list of this subcommand
remove_excludes(App * app)1448 bool remove_excludes(App *app) {
1449 auto iterator = std::find(std::begin(exclude_subcommands_), std::end(exclude_subcommands_), app);
1450 if(iterator == std::end(exclude_subcommands_)) {
1451 return false;
1452 }
1453 auto other_app = *iterator;
1454 exclude_subcommands_.erase(iterator);
1455 other_app->remove_excludes(this);
1456 return true;
1457 }
1458
1459 /// Removes an option from the needs list of this subcommand
remove_needs(Option * opt)1460 bool remove_needs(Option *opt) {
1461 auto iterator = std::find(std::begin(need_options_), std::end(need_options_), opt);
1462 if(iterator == std::end(need_options_)) {
1463 return false;
1464 }
1465 need_options_.erase(iterator);
1466 return true;
1467 }
1468
1469 /// Removes a subcommand from the needs list of this subcommand
remove_needs(App * app)1470 bool remove_needs(App *app) {
1471 auto iterator = std::find(std::begin(need_subcommands_), std::end(need_subcommands_), app);
1472 if(iterator == std::end(need_subcommands_)) {
1473 return false;
1474 }
1475 need_subcommands_.erase(iterator);
1476 return true;
1477 }
1478
1479 ///@}
1480 /// @name Help
1481 ///@{
1482
1483 /// Set footer.
footer(std::string footer_string)1484 App *footer(std::string footer_string) {
1485 footer_ = std::move(footer_string);
1486 return this;
1487 }
1488 /// Set footer.
footer(std::function<std::string ()> footer_function)1489 App *footer(std::function<std::string()> footer_function) {
1490 footer_callback_ = std::move(footer_function);
1491 return this;
1492 }
1493 /// Produce a string that could be read in as a config of the current values of the App. Set default_also to
1494 /// include default arguments. write_descriptions will print a description for the App and for each option.
config_to_str(bool default_also=false,bool write_description=false) const1495 std::string config_to_str(bool default_also = false, bool write_description = false) const {
1496 return config_formatter_->to_config(this, default_also, write_description, "");
1497 }
1498
1499 /// Makes a help message, using the currently configured formatter
1500 /// Will only do one subcommand at a time
help(std::string prev="",AppFormatMode mode=AppFormatMode::Normal) const1501 std::string help(std::string prev = "", AppFormatMode mode = AppFormatMode::Normal) const {
1502 if(prev.empty())
1503 prev = get_name();
1504 else
1505 prev += " " + get_name();
1506
1507 // Delegate to subcommand if needed
1508 auto selected_subcommands = get_subcommands();
1509 if(!selected_subcommands.empty()) {
1510 return selected_subcommands.at(0)->help(prev, mode);
1511 }
1512 return formatter_->make_help(this, prev, mode);
1513 }
1514
1515 /// Displays a version string
version() const1516 std::string version() const {
1517 std::string val;
1518 if(version_ptr_ != nullptr) {
1519 auto rv = version_ptr_->results();
1520 version_ptr_->clear();
1521 version_ptr_->add_result("true");
1522 try {
1523 version_ptr_->run_callback();
1524 } catch(const CLI::CallForVersion &cfv) {
1525 val = cfv.what();
1526 }
1527 version_ptr_->clear();
1528 version_ptr_->add_result(rv);
1529 }
1530 return val;
1531 }
1532 ///@}
1533 /// @name Getters
1534 ///@{
1535
1536 /// Access the formatter
get_formatter() const1537 std::shared_ptr<FormatterBase> get_formatter() const { return formatter_; }
1538
1539 /// Access the config formatter
get_config_formatter() const1540 std::shared_ptr<Config> get_config_formatter() const { return config_formatter_; }
1541
1542 /// Access the config formatter as a configBase pointer
get_config_formatter_base() const1543 std::shared_ptr<ConfigBase> get_config_formatter_base() const {
1544 // This is safer as a dynamic_cast if we have RTTI, as Config -> ConfigBase
1545 #if defined(__cpp_rtti) || (defined(__GXX_RTTI) && __GXX_RTTI) || (defined(_HAS_STATIC_RTTI) && (_HAS_STATIC_RTTI == 0))
1546 return std::dynamic_pointer_cast<ConfigBase>(config_formatter_);
1547 #else
1548 return std::static_pointer_cast<ConfigBase>(config_formatter_);
1549 #endif
1550 }
1551
1552 /// Get the app or subcommand description
get_description() const1553 std::string get_description() const { return description_; }
1554
1555 /// Set the description of the app
description(std::string app_description)1556 App *description(std::string app_description) {
1557 description_ = std::move(app_description);
1558 return this;
1559 }
1560
1561 /// Get the list of options (user facing function, so returns raw pointers), has optional filter function
get_options(const std::function<bool (const Option *)> filter={}) const1562 std::vector<const Option *> get_options(const std::function<bool(const Option *)> filter = {}) const {
1563 std::vector<const Option *> options(options_.size());
__anonf4600cca1402(const Option_p &val) 1564 std::transform(std::begin(options_), std::end(options_), std::begin(options), [](const Option_p &val) {
1565 return val.get();
1566 });
1567
1568 if(filter) {
1569 options.erase(std::remove_if(std::begin(options),
1570 std::end(options),
__anonf4600cca1502(const Option *opt) 1571 [&filter](const Option *opt) { return !filter(opt); }),
1572 std::end(options));
1573 }
1574
1575 return options;
1576 }
1577
1578 /// Non-const version of the above
get_options(const std::function<bool (Option *)> filter={})1579 std::vector<Option *> get_options(const std::function<bool(Option *)> filter = {}) {
1580 std::vector<Option *> options(options_.size());
__anonf4600cca1602(const Option_p &val) 1581 std::transform(std::begin(options_), std::end(options_), std::begin(options), [](const Option_p &val) {
1582 return val.get();
1583 });
1584
1585 if(filter) {
1586 options.erase(
__anonf4600cca1702(Option *opt) 1587 std::remove_if(std::begin(options), std::end(options), [&filter](Option *opt) { return !filter(opt); }),
1588 std::end(options));
1589 }
1590
1591 return options;
1592 }
1593
1594 /// Get an option by name (noexcept non-const version)
get_option_no_throw(std::string option_name)1595 Option *get_option_no_throw(std::string option_name) noexcept {
1596 for(Option_p &opt : options_) {
1597 if(opt->check_name(option_name)) {
1598 return opt.get();
1599 }
1600 }
1601 for(auto &subc : subcommands_) {
1602 // also check down into nameless subcommands
1603 if(subc->get_name().empty()) {
1604 auto opt = subc->get_option_no_throw(option_name);
1605 if(opt != nullptr) {
1606 return opt;
1607 }
1608 }
1609 }
1610 return nullptr;
1611 }
1612
1613 /// Get an option by name (noexcept const version)
get_option_no_throw(std::string option_name) const1614 const Option *get_option_no_throw(std::string option_name) const noexcept {
1615 for(const Option_p &opt : options_) {
1616 if(opt->check_name(option_name)) {
1617 return opt.get();
1618 }
1619 }
1620 for(const auto &subc : subcommands_) {
1621 // also check down into nameless subcommands
1622 if(subc->get_name().empty()) {
1623 auto opt = subc->get_option_no_throw(option_name);
1624 if(opt != nullptr) {
1625 return opt;
1626 }
1627 }
1628 }
1629 return nullptr;
1630 }
1631
1632 /// Get an option by name
get_option(std::string option_name) const1633 const Option *get_option(std::string option_name) const {
1634 auto opt = get_option_no_throw(option_name);
1635 if(opt == nullptr) {
1636 throw OptionNotFound(option_name);
1637 }
1638 return opt;
1639 }
1640
1641 /// Get an option by name (non-const version)
get_option(std::string option_name)1642 Option *get_option(std::string option_name) {
1643 auto opt = get_option_no_throw(option_name);
1644 if(opt == nullptr) {
1645 throw OptionNotFound(option_name);
1646 }
1647 return opt;
1648 }
1649
1650 /// Shortcut bracket operator for getting a pointer to an option
operator [](const std::string & option_name) const1651 const Option *operator[](const std::string &option_name) const { return get_option(option_name); }
1652
1653 /// Shortcut bracket operator for getting a pointer to an option
operator [](const char * option_name) const1654 const Option *operator[](const char *option_name) const { return get_option(option_name); }
1655
1656 /// Check the status of ignore_case
get_ignore_case() const1657 bool get_ignore_case() const { return ignore_case_; }
1658
1659 /// Check the status of ignore_underscore
get_ignore_underscore() const1660 bool get_ignore_underscore() const { return ignore_underscore_; }
1661
1662 /// Check the status of fallthrough
get_fallthrough() const1663 bool get_fallthrough() const { return fallthrough_; }
1664
1665 /// Check the status of the allow windows style options
get_allow_windows_style_options() const1666 bool get_allow_windows_style_options() const { return allow_windows_style_options_; }
1667
1668 /// Check the status of the allow windows style options
get_positionals_at_end() const1669 bool get_positionals_at_end() const { return positionals_at_end_; }
1670
1671 /// Check the status of the allow windows style options
get_configurable() const1672 bool get_configurable() const { return configurable_; }
1673
1674 /// Get the group of this subcommand
get_group() const1675 const std::string &get_group() const { return group_; }
1676
1677 /// Generate and return the footer.
get_footer() const1678 std::string get_footer() const { return (footer_callback_) ? footer_callback_() + '\n' + footer_ : footer_; }
1679
1680 /// Get the required min subcommand value
get_require_subcommand_min() const1681 std::size_t get_require_subcommand_min() const { return require_subcommand_min_; }
1682
1683 /// Get the required max subcommand value
get_require_subcommand_max() const1684 std::size_t get_require_subcommand_max() const { return require_subcommand_max_; }
1685
1686 /// Get the required min option value
get_require_option_min() const1687 std::size_t get_require_option_min() const { return require_option_min_; }
1688
1689 /// Get the required max option value
get_require_option_max() const1690 std::size_t get_require_option_max() const { return require_option_max_; }
1691
1692 /// Get the prefix command status
get_prefix_command() const1693 bool get_prefix_command() const { return prefix_command_; }
1694
1695 /// Get the status of allow extras
get_allow_extras() const1696 bool get_allow_extras() const { return allow_extras_; }
1697
1698 /// Get the status of required
get_required() const1699 bool get_required() const { return required_; }
1700
1701 /// Get the status of disabled
get_disabled() const1702 bool get_disabled() const { return disabled_; }
1703
1704 /// Get the status of silence
get_silent() const1705 bool get_silent() const { return silent_; }
1706
1707 /// Get the status of disabled
get_immediate_callback() const1708 bool get_immediate_callback() const { return immediate_callback_; }
1709
1710 /// Get the status of disabled by default
get_disabled_by_default() const1711 bool get_disabled_by_default() const { return (default_startup == startup_mode::disabled); }
1712
1713 /// Get the status of disabled by default
get_enabled_by_default() const1714 bool get_enabled_by_default() const { return (default_startup == startup_mode::enabled); }
1715 /// Get the status of validating positionals
get_validate_positionals() const1716 bool get_validate_positionals() const { return validate_positionals_; }
1717
1718 /// Get the status of allow extras
get_allow_config_extras() const1719 config_extras_mode get_allow_config_extras() const { return allow_config_extras_; }
1720
1721 /// Get a pointer to the help flag.
get_help_ptr()1722 Option *get_help_ptr() { return help_ptr_; }
1723
1724 /// Get a pointer to the help flag. (const)
get_help_ptr() const1725 const Option *get_help_ptr() const { return help_ptr_; }
1726
1727 /// Get a pointer to the help all flag. (const)
get_help_all_ptr() const1728 const Option *get_help_all_ptr() const { return help_all_ptr_; }
1729
1730 /// Get a pointer to the config option.
get_config_ptr()1731 Option *get_config_ptr() { return config_ptr_; }
1732
1733 /// Get a pointer to the config option. (const)
get_config_ptr() const1734 const Option *get_config_ptr() const { return config_ptr_; }
1735
1736 /// Get a pointer to the version option.
get_version_ptr()1737 Option *get_version_ptr() { return version_ptr_; }
1738
1739 /// Get a pointer to the version option. (const)
get_version_ptr() const1740 const Option *get_version_ptr() const { return version_ptr_; }
1741
1742 /// Get the parent of this subcommand (or nullptr if main app)
get_parent()1743 App *get_parent() { return parent_; }
1744
1745 /// Get the parent of this subcommand (or nullptr if main app) (const version)
get_parent() const1746 const App *get_parent() const { return parent_; }
1747
1748 /// Get the name of the current app
get_name() const1749 const std::string &get_name() const { return name_; }
1750
1751 /// Get the aliases of the current app
get_aliases() const1752 const std::vector<std::string> &get_aliases() const { return aliases_; }
1753
1754 /// clear all the aliases of the current App
clear_aliases()1755 App *clear_aliases() {
1756 aliases_.clear();
1757 return this;
1758 }
1759
1760 /// Get a display name for an app
get_display_name(bool with_aliases=false) const1761 std::string get_display_name(bool with_aliases = false) const {
1762 if(name_.empty()) {
1763 return std::string("[Option Group: ") + get_group() + "]";
1764 }
1765 if(aliases_.empty() || !with_aliases) {
1766 return name_;
1767 }
1768 std::string dispname = name_;
1769 for(const auto &lalias : aliases_) {
1770 dispname.push_back(',');
1771 dispname.push_back(' ');
1772 dispname.append(lalias);
1773 }
1774 return dispname;
1775 }
1776
1777 /// Check the name, case insensitive and underscore insensitive if set
check_name(std::string name_to_check) const1778 bool check_name(std::string name_to_check) const {
1779 std::string local_name = name_;
1780 if(ignore_underscore_) {
1781 local_name = detail::remove_underscore(name_);
1782 name_to_check = detail::remove_underscore(name_to_check);
1783 }
1784 if(ignore_case_) {
1785 local_name = detail::to_lower(name_);
1786 name_to_check = detail::to_lower(name_to_check);
1787 }
1788
1789 if(local_name == name_to_check) {
1790 return true;
1791 }
1792 for(auto les : aliases_) {
1793 if(ignore_underscore_) {
1794 les = detail::remove_underscore(les);
1795 }
1796 if(ignore_case_) {
1797 les = detail::to_lower(les);
1798 }
1799 if(les == name_to_check) {
1800 return true;
1801 }
1802 }
1803 return false;
1804 }
1805
1806 /// Get the groups available directly from this option (in order)
get_groups() const1807 std::vector<std::string> get_groups() const {
1808 std::vector<std::string> groups;
1809
1810 for(const Option_p &opt : options_) {
1811 // Add group if it is not already in there
1812 if(std::find(groups.begin(), groups.end(), opt->get_group()) == groups.end()) {
1813 groups.push_back(opt->get_group());
1814 }
1815 }
1816
1817 return groups;
1818 }
1819
1820 /// This gets a vector of pointers with the original parse order
parse_order() const1821 const std::vector<Option *> &parse_order() const { return parse_order_; }
1822
1823 /// This returns the missing options from the current subcommand
remaining(bool recurse=false) const1824 std::vector<std::string> remaining(bool recurse = false) const {
1825 std::vector<std::string> miss_list;
1826 for(const std::pair<detail::Classifier, std::string> &miss : missing_) {
1827 miss_list.push_back(std::get<1>(miss));
1828 }
1829 // Get from a subcommand that may allow extras
1830 if(recurse) {
1831 if(!allow_extras_) {
1832 for(const auto &sub : subcommands_) {
1833 if(sub->name_.empty() && !sub->missing_.empty()) {
1834 for(const std::pair<detail::Classifier, std::string> &miss : sub->missing_) {
1835 miss_list.push_back(std::get<1>(miss));
1836 }
1837 }
1838 }
1839 }
1840 // Recurse into subcommands
1841
1842 for(const App *sub : parsed_subcommands_) {
1843 std::vector<std::string> output = sub->remaining(recurse);
1844 std::copy(std::begin(output), std::end(output), std::back_inserter(miss_list));
1845 }
1846 }
1847 return miss_list;
1848 }
1849
1850 /// This returns the missing options in a form ready for processing by another command line program
remaining_for_passthrough(bool recurse=false) const1851 std::vector<std::string> remaining_for_passthrough(bool recurse = false) const {
1852 std::vector<std::string> miss_list = remaining(recurse);
1853 std::reverse(std::begin(miss_list), std::end(miss_list));
1854 return miss_list;
1855 }
1856
1857 /// This returns the number of remaining options, minus the -- separator
remaining_size(bool recurse=false) const1858 std::size_t remaining_size(bool recurse = false) const {
1859 auto remaining_options = static_cast<std::size_t>(std::count_if(
1860 std::begin(missing_), std::end(missing_), [](const std::pair<detail::Classifier, std::string> &val) {
1861 return val.first != detail::Classifier::POSITIONAL_MARK;
1862 }));
1863
1864 if(recurse) {
1865 for(const App_p &sub : subcommands_) {
1866 remaining_options += sub->remaining_size(recurse);
1867 }
1868 }
1869 return remaining_options;
1870 }
1871
1872 ///@}
1873
1874 protected:
1875 /// Check the options to make sure there are no conflicts.
1876 ///
1877 /// Currently checks to see if multiple positionals exist with unlimited args and checks if the min and max options
1878 /// are feasible
_validate() const1879 void _validate() const {
1880 // count the number of positional only args
1881 auto pcount = std::count_if(std::begin(options_), std::end(options_), [](const Option_p &opt) {
1882 return opt->get_items_expected_max() >= detail::expected_max_vector_size && !opt->nonpositional();
1883 });
1884 if(pcount > 1) {
1885 auto pcount_req = std::count_if(std::begin(options_), std::end(options_), [](const Option_p &opt) {
1886 return opt->get_items_expected_max() >= detail::expected_max_vector_size && !opt->nonpositional() &&
1887 opt->get_required();
1888 });
1889 if(pcount - pcount_req > 1) {
1890 throw InvalidError(name_);
1891 }
1892 }
1893
1894 std::size_t nameless_subs{0};
1895 for(const App_p &app : subcommands_) {
1896 app->_validate();
1897 if(app->get_name().empty())
1898 ++nameless_subs;
1899 }
1900
1901 if(require_option_min_ > 0) {
1902 if(require_option_max_ > 0) {
1903 if(require_option_max_ < require_option_min_) {
1904 throw(InvalidError("Required min options greater than required max options",
1905 ExitCodes::InvalidError));
1906 }
1907 }
1908 if(require_option_min_ > (options_.size() + nameless_subs)) {
1909 throw(InvalidError("Required min options greater than number of available options",
1910 ExitCodes::InvalidError));
1911 }
1912 }
1913 }
1914
1915 /// configure subcommands to enable parsing through the current object
1916 /// set the correct fallthrough and prefix for nameless subcommands and manage the automatic enable or disable
1917 /// makes sure parent is set correctly
_configure()1918 void _configure() {
1919 if(default_startup == startup_mode::enabled) {
1920 disabled_ = false;
1921 } else if(default_startup == startup_mode::disabled) {
1922 disabled_ = true;
1923 }
1924 for(const App_p &app : subcommands_) {
1925 if(app->has_automatic_name_) {
1926 app->name_.clear();
1927 }
1928 if(app->name_.empty()) {
1929 app->fallthrough_ = false; // make sure fallthrough_ is false to prevent infinite loop
1930 app->prefix_command_ = false;
1931 }
1932 // make sure the parent is set to be this object in preparation for parse
1933 app->parent_ = this;
1934 app->_configure();
1935 }
1936 }
1937
1938 /// Internal function to run (App) callback, bottom up
run_callback(bool final_mode=false,bool suppress_final_callback=false)1939 void run_callback(bool final_mode = false, bool suppress_final_callback = false) {
1940 pre_callback();
1941 // in the main app if immediate_callback_ is set it runs the main callback before the used subcommands
1942 if(!final_mode && parse_complete_callback_) {
1943 parse_complete_callback_();
1944 }
1945 // run the callbacks for the received subcommands
1946 for(App *subc : get_subcommands()) {
1947 subc->run_callback(true, suppress_final_callback);
1948 }
1949 // now run callbacks for option_groups
1950 for(auto &subc : subcommands_) {
1951 if(subc->name_.empty() && subc->count_all() > 0) {
1952 subc->run_callback(true, suppress_final_callback);
1953 }
1954 }
1955
1956 // finally run the main callback
1957 if(final_callback_ && (parsed_ > 0) && (!suppress_final_callback)) {
1958 if(!name_.empty() || count_all() > 0 || parent_ == nullptr) {
1959 final_callback_();
1960 }
1961 }
1962 }
1963
1964 /// Check to see if a subcommand is valid. Give up immediately if subcommand max has been reached.
_valid_subcommand(const std::string & current,bool ignore_used=true) const1965 bool _valid_subcommand(const std::string ¤t, bool ignore_used = true) const {
1966 // Don't match if max has been reached - but still check parents
1967 if(require_subcommand_max_ != 0 && parsed_subcommands_.size() >= require_subcommand_max_) {
1968 return parent_ != nullptr && parent_->_valid_subcommand(current, ignore_used);
1969 }
1970 auto com = _find_subcommand(current, true, ignore_used);
1971 if(com != nullptr) {
1972 return true;
1973 }
1974 // Check parent if exists, else return false
1975 return parent_ != nullptr && parent_->_valid_subcommand(current, ignore_used);
1976 }
1977
1978 /// Selects a Classifier enum based on the type of the current argument
_recognize(const std::string & current,bool ignore_used_subcommands=true) const1979 detail::Classifier _recognize(const std::string ¤t, bool ignore_used_subcommands = true) const {
1980 std::string dummy1, dummy2;
1981
1982 if(current == "--")
1983 return detail::Classifier::POSITIONAL_MARK;
1984 if(_valid_subcommand(current, ignore_used_subcommands))
1985 return detail::Classifier::SUBCOMMAND;
1986 if(detail::split_long(current, dummy1, dummy2))
1987 return detail::Classifier::LONG;
1988 if(detail::split_short(current, dummy1, dummy2)) {
1989 if(dummy1[0] >= '0' && dummy1[0] <= '9') {
1990 if(get_option_no_throw(std::string{'-', dummy1[0]}) == nullptr) {
1991 return detail::Classifier::NONE;
1992 }
1993 }
1994 return detail::Classifier::SHORT;
1995 }
1996 if((allow_windows_style_options_) && (detail::split_windows_style(current, dummy1, dummy2)))
1997 return detail::Classifier::WINDOWS_STYLE;
1998 if((current == "++") && !name_.empty() && parent_ != nullptr)
1999 return detail::Classifier::SUBCOMMAND_TERMINATOR;
2000 return detail::Classifier::NONE;
2001 }
2002
2003 // The parse function is now broken into several parts, and part of process
2004
2005 /// Read and process a configuration file (main app only)
_process_config_file()2006 void _process_config_file() {
2007 if(config_ptr_ != nullptr) {
2008 bool config_required = config_ptr_->get_required();
2009 auto file_given = config_ptr_->count() > 0;
2010 auto config_files = config_ptr_->as<std::vector<std::string>>();
2011 if(config_files.empty() || config_files.front().empty()) {
2012 if(config_required) {
2013 throw FileError::Missing("no specified config file");
2014 }
2015 return;
2016 }
2017 for(auto rit = config_files.rbegin(); rit != config_files.rend(); ++rit) {
2018 const auto &config_file = *rit;
2019 auto path_result = detail::check_path(config_file.c_str());
2020 if(path_result == detail::path_type::file) {
2021 try {
2022 std::vector<ConfigItem> values = config_formatter_->from_file(config_file);
2023 _parse_config(values);
2024 if(!file_given) {
2025 config_ptr_->add_result(config_file);
2026 }
2027 } catch(const FileError &) {
2028 if(config_required || file_given)
2029 throw;
2030 }
2031 } else if(config_required || file_given) {
2032 throw FileError::Missing(config_file);
2033 }
2034 }
2035 }
2036 }
2037
2038 /// Get envname options if not yet passed. Runs on *all* subcommands.
_process_env()2039 void _process_env() {
2040 for(const Option_p &opt : options_) {
2041 if(opt->count() == 0 && !opt->envname_.empty()) {
2042 char *buffer = nullptr;
2043 std::string ename_string;
2044
2045 #ifdef _MSC_VER
2046 // Windows version
2047 std::size_t sz = 0;
2048 if(_dupenv_s(&buffer, &sz, opt->envname_.c_str()) == 0 && buffer != nullptr) {
2049 ename_string = std::string(buffer);
2050 free(buffer);
2051 }
2052 #else
2053 // This also works on Windows, but gives a warning
2054 buffer = std::getenv(opt->envname_.c_str());
2055 if(buffer != nullptr)
2056 ename_string = std::string(buffer);
2057 #endif
2058
2059 if(!ename_string.empty()) {
2060 opt->add_result(ename_string);
2061 }
2062 }
2063 }
2064
2065 for(App_p &sub : subcommands_) {
2066 if(sub->get_name().empty() || !sub->parse_complete_callback_)
2067 sub->_process_env();
2068 }
2069 }
2070
2071 /// Process callbacks. Runs on *all* subcommands.
_process_callbacks()2072 void _process_callbacks() {
2073
2074 for(App_p &sub : subcommands_) {
2075 // process the priority option_groups first
2076 if(sub->get_name().empty() && sub->parse_complete_callback_) {
2077 if(sub->count_all() > 0) {
2078 sub->_process_callbacks();
2079 sub->run_callback();
2080 }
2081 }
2082 }
2083
2084 for(const Option_p &opt : options_) {
2085 if((*opt) && !opt->get_callback_run()) {
2086 opt->run_callback();
2087 }
2088 }
2089 for(App_p &sub : subcommands_) {
2090 if(!sub->parse_complete_callback_) {
2091 sub->_process_callbacks();
2092 }
2093 }
2094 }
2095
2096 /// Run help flag processing if any are found.
2097 ///
2098 /// The flags allow recursive calls to remember if there was a help flag on a parent.
_process_help_flags(bool trigger_help=false,bool trigger_all_help=false) const2099 void _process_help_flags(bool trigger_help = false, bool trigger_all_help = false) const {
2100 const Option *help_ptr = get_help_ptr();
2101 const Option *help_all_ptr = get_help_all_ptr();
2102
2103 if(help_ptr != nullptr && help_ptr->count() > 0)
2104 trigger_help = true;
2105 if(help_all_ptr != nullptr && help_all_ptr->count() > 0)
2106 trigger_all_help = true;
2107
2108 // If there were parsed subcommands, call those. First subcommand wins if there are multiple ones.
2109 if(!parsed_subcommands_.empty()) {
2110 for(const App *sub : parsed_subcommands_)
2111 sub->_process_help_flags(trigger_help, trigger_all_help);
2112
2113 // Only the final subcommand should call for help. All help wins over help.
2114 } else if(trigger_all_help) {
2115 throw CallForAllHelp();
2116 } else if(trigger_help) {
2117 throw CallForHelp();
2118 }
2119 }
2120
2121 /// Verify required options and cross requirements. Subcommands too (only if selected).
_process_requirements()2122 void _process_requirements() {
2123 // check excludes
2124 bool excluded{false};
2125 std::string excluder;
2126 for(auto &opt : exclude_options_) {
2127 if(opt->count() > 0) {
2128 excluded = true;
2129 excluder = opt->get_name();
2130 }
2131 }
2132 for(auto &subc : exclude_subcommands_) {
2133 if(subc->count_all() > 0) {
2134 excluded = true;
2135 excluder = subc->get_display_name();
2136 }
2137 }
2138 if(excluded) {
2139 if(count_all() > 0) {
2140 throw ExcludesError(get_display_name(), excluder);
2141 }
2142 // if we are excluded but didn't receive anything, just return
2143 return;
2144 }
2145
2146 // check excludes
2147 bool missing_needed{false};
2148 std::string missing_need;
2149 for(auto &opt : need_options_) {
2150 if(opt->count() == 0) {
2151 missing_needed = true;
2152 missing_need = opt->get_name();
2153 }
2154 }
2155 for(auto &subc : need_subcommands_) {
2156 if(subc->count_all() == 0) {
2157 missing_needed = true;
2158 missing_need = subc->get_display_name();
2159 }
2160 }
2161 if(missing_needed) {
2162 if(count_all() > 0) {
2163 throw RequiresError(get_display_name(), missing_need);
2164 }
2165 // if we missing something but didn't have any options, just return
2166 return;
2167 }
2168
2169 std::size_t used_options = 0;
2170 for(const Option_p &opt : options_) {
2171
2172 if(opt->count() != 0) {
2173 ++used_options;
2174 }
2175 // Required but empty
2176 if(opt->get_required() && opt->count() == 0) {
2177 throw RequiredError(opt->get_name());
2178 }
2179 // Requires
2180 for(const Option *opt_req : opt->needs_)
2181 if(opt->count() > 0 && opt_req->count() == 0)
2182 throw RequiresError(opt->get_name(), opt_req->get_name());
2183 // Excludes
2184 for(const Option *opt_ex : opt->excludes_)
2185 if(opt->count() > 0 && opt_ex->count() != 0)
2186 throw ExcludesError(opt->get_name(), opt_ex->get_name());
2187 }
2188 // check for the required number of subcommands
2189 if(require_subcommand_min_ > 0) {
2190 auto selected_subcommands = get_subcommands();
2191 if(require_subcommand_min_ > selected_subcommands.size())
2192 throw RequiredError::Subcommand(require_subcommand_min_);
2193 }
2194
2195 // Max error cannot occur, the extra subcommand will parse as an ExtrasError or a remaining item.
2196
2197 // run this loop to check how many unnamed subcommands were actually used since they are considered options
2198 // from the perspective of an App
2199 for(App_p &sub : subcommands_) {
2200 if(sub->disabled_)
2201 continue;
2202 if(sub->name_.empty() && sub->count_all() > 0) {
2203 ++used_options;
2204 }
2205 }
2206
2207 if(require_option_min_ > used_options || (require_option_max_ > 0 && require_option_max_ < used_options)) {
2208 auto option_list = detail::join(options_, [this](const Option_p &ptr) {
2209 if(ptr.get() == help_ptr_ || ptr.get() == help_all_ptr_) {
2210 return std::string{};
2211 }
2212 return ptr->get_name(false, true);
2213 });
2214
2215 auto subc_list = get_subcommands([](App *app) { return ((app->get_name().empty()) && (!app->disabled_)); });
2216 if(!subc_list.empty()) {
2217 option_list += "," + detail::join(subc_list, [](const App *app) { return app->get_display_name(); });
2218 }
2219 throw RequiredError::Option(require_option_min_, require_option_max_, used_options, option_list);
2220 }
2221
2222 // now process the requirements for subcommands if needed
2223 for(App_p &sub : subcommands_) {
2224 if(sub->disabled_)
2225 continue;
2226 if(sub->name_.empty() && sub->required_ == false) {
2227 if(sub->count_all() == 0) {
2228 if(require_option_min_ > 0 && require_option_min_ <= used_options) {
2229 continue;
2230 // if we have met the requirement and there is nothing in this option group skip checking
2231 // requirements
2232 }
2233 if(require_option_max_ > 0 && used_options >= require_option_min_) {
2234 continue;
2235 // if we have met the requirement and there is nothing in this option group skip checking
2236 // requirements
2237 }
2238 }
2239 }
2240 if(sub->count() > 0 || sub->name_.empty()) {
2241 sub->_process_requirements();
2242 }
2243
2244 if(sub->required_ && sub->count_all() == 0) {
2245 throw(CLI::RequiredError(sub->get_display_name()));
2246 }
2247 }
2248 }
2249
2250 /// Process callbacks and such.
_process()2251 void _process() {
2252 CLI::FileError fe("ne");
2253 bool caught_error{false};
2254 try {
2255 // the config file might generate a FileError but that should not be processed until later in the process
2256 // to allow for help, version and other errors to generate first.
2257 _process_config_file();
2258 // process env shouldn't throw but no reason to process it if config generated an error
2259 _process_env();
2260 } catch(const CLI::FileError &fe2) {
2261 fe = fe2;
2262 caught_error = true;
2263 }
2264 // callbacks and help_flags can generate exceptions which should take priority over the config file error if one
2265 // exists
2266 _process_callbacks();
2267 _process_help_flags();
2268
2269 if(caught_error) {
2270 throw CLI::FileError(std::move(fe));
2271 }
2272
2273 _process_requirements();
2274 }
2275
2276 /// Throw an error if anything is left over and should not be.
_process_extras()2277 void _process_extras() {
2278 if(!(allow_extras_ || prefix_command_)) {
2279 std::size_t num_left_over = remaining_size();
2280 if(num_left_over > 0) {
2281 throw ExtrasError(name_, remaining(false));
2282 }
2283 }
2284
2285 for(App_p &sub : subcommands_) {
2286 if(sub->count() > 0)
2287 sub->_process_extras();
2288 }
2289 }
2290
2291 /// Throw an error if anything is left over and should not be.
2292 /// Modifies the args to fill in the missing items before throwing.
_process_extras(std::vector<std::string> & args)2293 void _process_extras(std::vector<std::string> &args) {
2294 if(!(allow_extras_ || prefix_command_)) {
2295 std::size_t num_left_over = remaining_size();
2296 if(num_left_over > 0) {
2297 args = remaining(false);
2298 throw ExtrasError(name_, args);
2299 }
2300 }
2301
2302 for(App_p &sub : subcommands_) {
2303 if(sub->count() > 0)
2304 sub->_process_extras(args);
2305 }
2306 }
2307
2308 /// Internal function to recursively increment the parsed counter on the current app as well unnamed subcommands
increment_parsed()2309 void increment_parsed() {
2310 ++parsed_;
2311 for(App_p &sub : subcommands_) {
2312 if(sub->get_name().empty())
2313 sub->increment_parsed();
2314 }
2315 }
2316 /// Internal parse function
_parse(std::vector<std::string> & args)2317 void _parse(std::vector<std::string> &args) {
2318 increment_parsed();
2319 _trigger_pre_parse(args.size());
2320 bool positional_only = false;
2321
2322 while(!args.empty()) {
2323 if(!_parse_single(args, positional_only)) {
2324 break;
2325 }
2326 }
2327
2328 if(parent_ == nullptr) {
2329 _process();
2330
2331 // Throw error if any items are left over (depending on settings)
2332 _process_extras(args);
2333
2334 // Convert missing (pairs) to extras (string only) ready for processing in another app
2335 args = remaining_for_passthrough(false);
2336 } else if(parse_complete_callback_) {
2337 _process_env();
2338 _process_callbacks();
2339 _process_help_flags();
2340 _process_requirements();
2341 run_callback(false, true);
2342 }
2343 }
2344
2345 /// Internal parse function
_parse(std::vector<std::string> && args)2346 void _parse(std::vector<std::string> &&args) {
2347 // this can only be called by the top level in which case parent == nullptr by definition
2348 // operation is simplified
2349 increment_parsed();
2350 _trigger_pre_parse(args.size());
2351 bool positional_only = false;
2352
2353 while(!args.empty()) {
2354 _parse_single(args, positional_only);
2355 }
2356 _process();
2357
2358 // Throw error if any items are left over (depending on settings)
2359 _process_extras();
2360 }
2361
2362 /// Internal function to parse a stream
_parse_stream(std::istream & input)2363 void _parse_stream(std::istream &input) {
2364 auto values = config_formatter_->from_config(input);
2365 _parse_config(values);
2366 increment_parsed();
2367 _trigger_pre_parse(values.size());
2368 _process();
2369
2370 // Throw error if any items are left over (depending on settings)
2371 _process_extras();
2372 }
2373
2374 /// Parse one config param, return false if not found in any subcommand, remove if it is
2375 ///
2376 /// If this has more than one dot.separated.name, go into the subcommand matching it
2377 /// Returns true if it managed to find the option, if false you'll need to remove the arg manually.
_parse_config(const std::vector<ConfigItem> & args)2378 void _parse_config(const std::vector<ConfigItem> &args) {
2379 for(const ConfigItem &item : args) {
2380 if(!_parse_single_config(item) && allow_config_extras_ == config_extras_mode::error)
2381 throw ConfigError::Extras(item.fullname());
2382 }
2383 }
2384
2385 /// Fill in a single config option
_parse_single_config(const ConfigItem & item,std::size_t level=0)2386 bool _parse_single_config(const ConfigItem &item, std::size_t level = 0) {
2387 if(level < item.parents.size()) {
2388 try {
2389 auto subcom = get_subcommand(item.parents.at(level));
2390 auto result = subcom->_parse_single_config(item, level + 1);
2391
2392 return result;
2393 } catch(const OptionNotFound &) {
2394 return false;
2395 }
2396 }
2397 // check for section open
2398 if(item.name == "++") {
2399 if(configurable_) {
2400 increment_parsed();
2401 _trigger_pre_parse(2);
2402 if(parent_ != nullptr) {
2403 parent_->parsed_subcommands_.push_back(this);
2404 }
2405 }
2406 return true;
2407 }
2408 // check for section close
2409 if(item.name == "--") {
2410 if(configurable_) {
2411 _process_callbacks();
2412 _process_requirements();
2413 run_callback();
2414 }
2415 return true;
2416 }
2417 Option *op = get_option_no_throw("--" + item.name);
2418 if(op == nullptr) {
2419 if(item.name.size() == 1) {
2420 op = get_option_no_throw("-" + item.name);
2421 }
2422 }
2423 if(op == nullptr) {
2424 op = get_option_no_throw(item.name);
2425 }
2426 if(op == nullptr) {
2427 // If the option was not present
2428 if(get_allow_config_extras() == config_extras_mode::capture)
2429 // Should we worry about classifying the extras properly?
2430 missing_.emplace_back(detail::Classifier::NONE, item.fullname());
2431 return false;
2432 }
2433
2434 if(!op->get_configurable()) {
2435 if(get_allow_config_extras() == config_extras_mode::ignore_all) {
2436 return false;
2437 }
2438 throw ConfigError::NotConfigurable(item.fullname());
2439 }
2440
2441 if(op->empty()) {
2442 // Flag parsing
2443 if(op->get_expected_min() == 0) {
2444 auto res = config_formatter_->to_flag(item);
2445 res = op->get_flag_value(item.name, res);
2446
2447 op->add_result(res);
2448
2449 } else {
2450 op->add_result(item.inputs);
2451 op->run_callback();
2452 }
2453 }
2454
2455 return true;
2456 }
2457
2458 /// Parse "one" argument (some may eat more than one), delegate to parent if fails, add to missing if missing
2459 /// from main return false if the parse has failed and needs to return to parent
_parse_single(std::vector<std::string> & args,bool & positional_only)2460 bool _parse_single(std::vector<std::string> &args, bool &positional_only) {
2461 bool retval = true;
2462 detail::Classifier classifier = positional_only ? detail::Classifier::NONE : _recognize(args.back());
2463 switch(classifier) {
2464 case detail::Classifier::POSITIONAL_MARK:
2465 args.pop_back();
2466 positional_only = true;
2467 if((!_has_remaining_positionals()) && (parent_ != nullptr)) {
2468 retval = false;
2469 } else {
2470 _move_to_missing(classifier, "--");
2471 }
2472 break;
2473 case detail::Classifier::SUBCOMMAND_TERMINATOR:
2474 // treat this like a positional mark if in the parent app
2475 args.pop_back();
2476 retval = false;
2477 break;
2478 case detail::Classifier::SUBCOMMAND:
2479 retval = _parse_subcommand(args);
2480 break;
2481 case detail::Classifier::LONG:
2482 case detail::Classifier::SHORT:
2483 case detail::Classifier::WINDOWS_STYLE:
2484 // If already parsed a subcommand, don't accept options_
2485 _parse_arg(args, classifier);
2486 break;
2487 case detail::Classifier::NONE:
2488 // Probably a positional or something for a parent (sub)command
2489 retval = _parse_positional(args, false);
2490 if(retval && positionals_at_end_) {
2491 positional_only = true;
2492 }
2493 break;
2494 // LCOV_EXCL_START
2495 default:
2496 throw HorribleError("unrecognized classifier (you should not see this!)");
2497 // LCOV_EXCL_STOP
2498 }
2499 return retval;
2500 }
2501
2502 /// Count the required remaining positional arguments
_count_remaining_positionals(bool required_only=false) const2503 std::size_t _count_remaining_positionals(bool required_only = false) const {
2504 std::size_t retval = 0;
2505 for(const Option_p &opt : options_) {
2506 if(opt->get_positional() && (!required_only || opt->get_required())) {
2507 if(opt->get_items_expected_min() > 0 &&
2508 static_cast<int>(opt->count()) < opt->get_items_expected_min()) {
2509 retval += static_cast<std::size_t>(opt->get_items_expected_min()) - opt->count();
2510 }
2511 }
2512 }
2513 return retval;
2514 }
2515
2516 /// Count the required remaining positional arguments
_has_remaining_positionals() const2517 bool _has_remaining_positionals() const {
2518 for(const Option_p &opt : options_) {
2519 if(opt->get_positional() && ((static_cast<int>(opt->count()) < opt->get_items_expected_min()))) {
2520 return true;
2521 }
2522 }
2523
2524 return false;
2525 }
2526
2527 /// Parse a positional, go up the tree to check
2528 /// @param haltOnSubcommand if set to true the operation will not process subcommands merely return false
2529 /// Return true if the positional was used false otherwise
_parse_positional(std::vector<std::string> & args,bool haltOnSubcommand)2530 bool _parse_positional(std::vector<std::string> &args, bool haltOnSubcommand) {
2531
2532 const std::string &positional = args.back();
2533
2534 if(positionals_at_end_) {
2535 // deal with the case of required arguments at the end which should take precedence over other arguments
2536 auto arg_rem = args.size();
2537 auto remreq = _count_remaining_positionals(true);
2538 if(arg_rem <= remreq) {
2539 for(const Option_p &opt : options_) {
2540 if(opt->get_positional() && opt->required_) {
2541 if(static_cast<int>(opt->count()) < opt->get_items_expected_min()) {
2542 if(validate_positionals_) {
2543 std::string pos = positional;
2544 pos = opt->_validate(pos, 0);
2545 if(!pos.empty()) {
2546 continue;
2547 }
2548 }
2549 opt->add_result(positional);
2550 parse_order_.push_back(opt.get());
2551 args.pop_back();
2552 return true;
2553 }
2554 }
2555 }
2556 }
2557 }
2558 for(const Option_p &opt : options_) {
2559 // Eat options, one by one, until done
2560 if(opt->get_positional() &&
2561 (static_cast<int>(opt->count()) < opt->get_items_expected_min() || opt->get_allow_extra_args())) {
2562 if(validate_positionals_) {
2563 std::string pos = positional;
2564 pos = opt->_validate(pos, 0);
2565 if(!pos.empty()) {
2566 continue;
2567 }
2568 }
2569 opt->add_result(positional);
2570 parse_order_.push_back(opt.get());
2571 args.pop_back();
2572 return true;
2573 }
2574 }
2575
2576 for(auto &subc : subcommands_) {
2577 if((subc->name_.empty()) && (!subc->disabled_)) {
2578 if(subc->_parse_positional(args, false)) {
2579 if(!subc->pre_parse_called_) {
2580 subc->_trigger_pre_parse(args.size());
2581 }
2582 return true;
2583 }
2584 }
2585 }
2586 // let the parent deal with it if possible
2587 if(parent_ != nullptr && fallthrough_)
2588 return _get_fallthrough_parent()->_parse_positional(args, static_cast<bool>(parse_complete_callback_));
2589
2590 /// Try to find a local subcommand that is repeated
2591 auto com = _find_subcommand(args.back(), true, false);
2592 if(com != nullptr && (require_subcommand_max_ == 0 || require_subcommand_max_ > parsed_subcommands_.size())) {
2593 if(haltOnSubcommand) {
2594 return false;
2595 }
2596 args.pop_back();
2597 com->_parse(args);
2598 return true;
2599 }
2600 /// now try one last gasp at subcommands that have been executed before, go to root app and try to find a
2601 /// subcommand in a broader way, if one exists let the parent deal with it
2602 auto parent_app = (parent_ != nullptr) ? _get_fallthrough_parent() : this;
2603 com = parent_app->_find_subcommand(args.back(), true, false);
2604 if(com != nullptr && (com->parent_->require_subcommand_max_ == 0 ||
2605 com->parent_->require_subcommand_max_ > com->parent_->parsed_subcommands_.size())) {
2606 return false;
2607 }
2608
2609 if(positionals_at_end_) {
2610 throw CLI::ExtrasError(name_, args);
2611 }
2612 /// If this is an option group don't deal with it
2613 if(parent_ != nullptr && name_.empty()) {
2614 return false;
2615 }
2616 /// We are out of other options this goes to missing
2617 _move_to_missing(detail::Classifier::NONE, positional);
2618 args.pop_back();
2619 if(prefix_command_) {
2620 while(!args.empty()) {
2621 _move_to_missing(detail::Classifier::NONE, args.back());
2622 args.pop_back();
2623 }
2624 }
2625
2626 return true;
2627 }
2628
2629 /// Locate a subcommand by name with two conditions, should disabled subcommands be ignored, and should used
2630 /// subcommands be ignored
_find_subcommand(const std::string & subc_name,bool ignore_disabled,bool ignore_used) const2631 App *_find_subcommand(const std::string &subc_name, bool ignore_disabled, bool ignore_used) const noexcept {
2632 for(const App_p &com : subcommands_) {
2633 if(com->disabled_ && ignore_disabled)
2634 continue;
2635 if(com->get_name().empty()) {
2636 auto subc = com->_find_subcommand(subc_name, ignore_disabled, ignore_used);
2637 if(subc != nullptr) {
2638 return subc;
2639 }
2640 }
2641 if(com->check_name(subc_name)) {
2642 if((!*com) || !ignore_used)
2643 return com.get();
2644 }
2645 }
2646 return nullptr;
2647 }
2648
2649 /// Parse a subcommand, modify args and continue
2650 ///
2651 /// Unlike the others, this one will always allow fallthrough
2652 /// return true if the subcommand was processed false otherwise
_parse_subcommand(std::vector<std::string> & args)2653 bool _parse_subcommand(std::vector<std::string> &args) {
2654 if(_count_remaining_positionals(/* required */ true) > 0) {
2655 _parse_positional(args, false);
2656 return true;
2657 }
2658 auto com = _find_subcommand(args.back(), true, true);
2659 if(com != nullptr) {
2660 args.pop_back();
2661 if(!com->silent_) {
2662 parsed_subcommands_.push_back(com);
2663 }
2664 com->_parse(args);
2665 auto parent_app = com->parent_;
2666 while(parent_app != this) {
2667 parent_app->_trigger_pre_parse(args.size());
2668 if(!com->silent_) {
2669 parent_app->parsed_subcommands_.push_back(com);
2670 }
2671 parent_app = parent_app->parent_;
2672 }
2673 return true;
2674 }
2675
2676 if(parent_ == nullptr)
2677 throw HorribleError("Subcommand " + args.back() + " missing");
2678 return false;
2679 }
2680
2681 /// Parse a short (false) or long (true) argument, must be at the top of the list
2682 /// return true if the argument was processed or false if nothing was done
_parse_arg(std::vector<std::string> & args,detail::Classifier current_type)2683 bool _parse_arg(std::vector<std::string> &args, detail::Classifier current_type) {
2684
2685 std::string current = args.back();
2686
2687 std::string arg_name;
2688 std::string value;
2689 std::string rest;
2690
2691 switch(current_type) {
2692 case detail::Classifier::LONG:
2693 if(!detail::split_long(current, arg_name, value))
2694 throw HorribleError("Long parsed but missing (you should not see this):" + args.back());
2695 break;
2696 case detail::Classifier::SHORT:
2697 if(!detail::split_short(current, arg_name, rest))
2698 throw HorribleError("Short parsed but missing! You should not see this");
2699 break;
2700 case detail::Classifier::WINDOWS_STYLE:
2701 if(!detail::split_windows_style(current, arg_name, value))
2702 throw HorribleError("windows option parsed but missing! You should not see this");
2703 break;
2704 case detail::Classifier::SUBCOMMAND:
2705 case detail::Classifier::SUBCOMMAND_TERMINATOR:
2706 case detail::Classifier::POSITIONAL_MARK:
2707 case detail::Classifier::NONE:
2708 default:
2709 throw HorribleError("parsing got called with invalid option! You should not see this");
2710 }
2711
2712 auto op_ptr =
2713 std::find_if(std::begin(options_), std::end(options_), [arg_name, current_type](const Option_p &opt) {
2714 if(current_type == detail::Classifier::LONG)
2715 return opt->check_lname(arg_name);
2716 if(current_type == detail::Classifier::SHORT)
2717 return opt->check_sname(arg_name);
2718 // this will only get called for detail::Classifier::WINDOWS_STYLE
2719 return opt->check_lname(arg_name) || opt->check_sname(arg_name);
2720 });
2721
2722 // Option not found
2723 if(op_ptr == std::end(options_)) {
2724 for(auto &subc : subcommands_) {
2725 if(subc->name_.empty() && !subc->disabled_) {
2726 if(subc->_parse_arg(args, current_type)) {
2727 if(!subc->pre_parse_called_) {
2728 subc->_trigger_pre_parse(args.size());
2729 }
2730 return true;
2731 }
2732 }
2733 }
2734 // If a subcommand, try the main command
2735 if(parent_ != nullptr && fallthrough_)
2736 return _get_fallthrough_parent()->_parse_arg(args, current_type);
2737 // don't capture missing if this is a nameless subcommand
2738 if(parent_ != nullptr && name_.empty()) {
2739 return false;
2740 }
2741 // Otherwise, add to missing
2742 args.pop_back();
2743 _move_to_missing(current_type, current);
2744 return true;
2745 }
2746
2747 args.pop_back();
2748
2749 // Get a reference to the pointer to make syntax bearable
2750 Option_p &op = *op_ptr;
2751 /// if we require a separator add it here
2752 if(op->get_inject_separator()) {
2753 if(!op->results().empty() && !op->results().back().empty()) {
2754 op->add_result(std::string{});
2755 }
2756 }
2757 if(op->get_trigger_on_parse() && op->current_option_state_ == Option::option_state::callback_run) {
2758 op->clear();
2759 }
2760 int min_num = (std::min)(op->get_type_size_min(), op->get_items_expected_min());
2761 int max_num = op->get_items_expected_max();
2762 // check container like options to limit the argument size to a single type if the allow_extra_flags argument is
2763 // set. 16 is somewhat arbitrary (needs to be at least 4)
2764 if(max_num >= detail::expected_max_vector_size / 16 && !op->get_allow_extra_args()) {
2765 auto tmax = op->get_type_size_max();
2766 max_num = detail::checked_multiply(tmax, op->get_expected_min()) ? tmax : detail::expected_max_vector_size;
2767 }
2768 // Make sure we always eat the minimum for unlimited vectors
2769 int collected = 0; // total number of arguments collected
2770 int result_count = 0; // local variable for number of results in a single arg string
2771 // deal with purely flag like things
2772 if(max_num == 0) {
2773 auto res = op->get_flag_value(arg_name, value);
2774 op->add_result(res);
2775 parse_order_.push_back(op.get());
2776 } else if(!value.empty()) { // --this=value
2777 op->add_result(value, result_count);
2778 parse_order_.push_back(op.get());
2779 collected += result_count;
2780 // -Trest
2781 } else if(!rest.empty()) {
2782 op->add_result(rest, result_count);
2783 parse_order_.push_back(op.get());
2784 rest = "";
2785 collected += result_count;
2786 }
2787
2788 // gather the minimum number of arguments
2789 while(min_num > collected && !args.empty()) {
2790 std::string current_ = args.back();
2791 args.pop_back();
2792 op->add_result(current_, result_count);
2793 parse_order_.push_back(op.get());
2794 collected += result_count;
2795 }
2796
2797 if(min_num > collected) { // if we have run out of arguments and the minimum was not met
2798 throw ArgumentMismatch::TypedAtLeast(op->get_name(), min_num, op->get_type_name());
2799 }
2800
2801 if(max_num > collected || op->get_allow_extra_args()) { // we allow optional arguments
2802 auto remreqpos = _count_remaining_positionals(true);
2803 // we have met the minimum now optionally check up to the maximum
2804 while((collected < max_num || op->get_allow_extra_args()) && !args.empty() &&
2805 _recognize(args.back(), false) == detail::Classifier::NONE) {
2806 // If any required positionals remain, don't keep eating
2807 if(remreqpos >= args.size()) {
2808 break;
2809 }
2810
2811 op->add_result(args.back(), result_count);
2812 parse_order_.push_back(op.get());
2813 args.pop_back();
2814 collected += result_count;
2815 }
2816
2817 // Allow -- to end an unlimited list and "eat" it
2818 if(!args.empty() && _recognize(args.back()) == detail::Classifier::POSITIONAL_MARK)
2819 args.pop_back();
2820 // optional flag that didn't receive anything now get the default value
2821 if(min_num == 0 && max_num > 0 && collected == 0) {
2822 auto res = op->get_flag_value(arg_name, std::string{});
2823 op->add_result(res);
2824 parse_order_.push_back(op.get());
2825 }
2826 }
2827
2828 // if we only partially completed a type then add an empty string for later processing
2829 if(min_num > 0 && op->get_type_size_max() != min_num && (collected % op->get_type_size_max()) != 0) {
2830 op->add_result(std::string{});
2831 }
2832 if(op->get_trigger_on_parse()) {
2833 op->run_callback();
2834 }
2835 if(!rest.empty()) {
2836 rest = "-" + rest;
2837 args.push_back(rest);
2838 }
2839 return true;
2840 }
2841
2842 /// Trigger the pre_parse callback if needed
_trigger_pre_parse(std::size_t remaining_args)2843 void _trigger_pre_parse(std::size_t remaining_args) {
2844 if(!pre_parse_called_) {
2845 pre_parse_called_ = true;
2846 if(pre_parse_callback_) {
2847 pre_parse_callback_(remaining_args);
2848 }
2849 } else if(immediate_callback_) {
2850 if(!name_.empty()) {
2851 auto pcnt = parsed_;
2852 auto extras = std::move(missing_);
2853 clear();
2854 parsed_ = pcnt;
2855 pre_parse_called_ = true;
2856 missing_ = std::move(extras);
2857 }
2858 }
2859 }
2860
2861 /// Get the appropriate parent to fallthrough to which is the first one that has a name or the main app
_get_fallthrough_parent()2862 App *_get_fallthrough_parent() {
2863 if(parent_ == nullptr) {
2864 throw(HorribleError("No Valid parent"));
2865 }
2866 auto fallthrough_parent = parent_;
2867 while((fallthrough_parent->parent_ != nullptr) && (fallthrough_parent->get_name().empty())) {
2868 fallthrough_parent = fallthrough_parent->parent_;
2869 }
2870 return fallthrough_parent;
2871 }
2872
2873 /// Helper function to run through all possible comparisons of subcommand names to check there is no overlap
_compare_subcommand_names(const App & subcom,const App & base) const2874 const std::string &_compare_subcommand_names(const App &subcom, const App &base) const {
2875 static const std::string estring;
2876 if(subcom.disabled_) {
2877 return estring;
2878 }
2879 for(auto &subc : base.subcommands_) {
2880 if(subc.get() != &subcom) {
2881 if(subc->disabled_) {
2882 continue;
2883 }
2884 if(!subcom.get_name().empty()) {
2885 if(subc->check_name(subcom.get_name())) {
2886 return subcom.get_name();
2887 }
2888 }
2889 if(!subc->get_name().empty()) {
2890 if(subcom.check_name(subc->get_name())) {
2891 return subc->get_name();
2892 }
2893 }
2894 for(const auto &les : subcom.aliases_) {
2895 if(subc->check_name(les)) {
2896 return les;
2897 }
2898 }
2899 // this loop is needed in case of ignore_underscore or ignore_case on one but not the other
2900 for(const auto &les : subc->aliases_) {
2901 if(subcom.check_name(les)) {
2902 return les;
2903 }
2904 }
2905 // if the subcommand is an option group we need to check deeper
2906 if(subc->get_name().empty()) {
2907 auto &cmpres = _compare_subcommand_names(subcom, *subc);
2908 if(!cmpres.empty()) {
2909 return cmpres;
2910 }
2911 }
2912 // if the test subcommand is an option group we need to check deeper
2913 if(subcom.get_name().empty()) {
2914 auto &cmpres = _compare_subcommand_names(*subc, subcom);
2915 if(!cmpres.empty()) {
2916 return cmpres;
2917 }
2918 }
2919 }
2920 }
2921 return estring;
2922 }
2923 /// Helper function to place extra values in the most appropriate position
_move_to_missing(detail::Classifier val_type,const std::string & val)2924 void _move_to_missing(detail::Classifier val_type, const std::string &val) {
2925 if(allow_extras_ || subcommands_.empty()) {
2926 missing_.emplace_back(val_type, val);
2927 return;
2928 }
2929 // allow extra arguments to be places in an option group if it is allowed there
2930 for(auto &subc : subcommands_) {
2931 if(subc->name_.empty() && subc->allow_extras_) {
2932 subc->missing_.emplace_back(val_type, val);
2933 return;
2934 }
2935 }
2936 // if we haven't found any place to put them yet put them in missing
2937 missing_.emplace_back(val_type, val);
2938 }
2939
2940 public:
2941 /// function that could be used by subclasses of App to shift options around into subcommands
_move_option(Option * opt,App * app)2942 void _move_option(Option *opt, App *app) {
2943 if(opt == nullptr) {
2944 throw OptionNotFound("the option is NULL");
2945 }
2946 // verify that the give app is actually a subcommand
2947 bool found = false;
2948 for(auto &subc : subcommands_) {
2949 if(app == subc.get()) {
2950 found = true;
2951 }
2952 }
2953 if(!found) {
2954 throw OptionNotFound("The Given app is not a subcommand");
2955 }
2956
2957 if((help_ptr_ == opt) || (help_all_ptr_ == opt))
2958 throw OptionAlreadyAdded("cannot move help options");
2959
2960 if(config_ptr_ == opt)
2961 throw OptionAlreadyAdded("cannot move config file options");
2962
2963 auto iterator =
2964 std::find_if(std::begin(options_), std::end(options_), [opt](const Option_p &v) { return v.get() == opt; });
2965 if(iterator != std::end(options_)) {
2966 const auto &opt_p = *iterator;
2967 if(std::find_if(std::begin(app->options_), std::end(app->options_), [&opt_p](const Option_p &v) {
2968 return (*v == *opt_p);
2969 }) == std::end(app->options_)) {
2970 // only erase after the insertion was successful
2971 app->options_.push_back(std::move(*iterator));
2972 options_.erase(iterator);
2973 } else {
2974 throw OptionAlreadyAdded("option was not located: " + opt->get_name());
2975 }
2976 } else {
2977 throw OptionNotFound("could not locate the given Option");
2978 }
2979 }
2980 }; // namespace CLI
2981
2982 /// Extension of App to better manage groups of options
2983 class Option_group : public App {
2984 public:
Option_group(std::string group_description,std::string group_name,App * parent)2985 Option_group(std::string group_description, std::string group_name, App *parent)
2986 : App(std::move(group_description), "", parent) {
2987 group(group_name);
2988 // option groups should have automatic fallthrough
2989 }
2990 using App::add_option;
2991 /// Add an existing option to the Option_group
add_option(Option * opt)2992 Option *add_option(Option *opt) {
2993 if(get_parent() == nullptr) {
2994 throw OptionNotFound("Unable to locate the specified option");
2995 }
2996 get_parent()->_move_option(opt, this);
2997 return opt;
2998 }
2999 /// Add an existing option to the Option_group
add_options(Option * opt)3000 void add_options(Option *opt) { add_option(opt); }
3001 /// Add a bunch of options to the group
add_options(Option * opt,Args...args)3002 template <typename... Args> void add_options(Option *opt, Args... args) {
3003 add_option(opt);
3004 add_options(args...);
3005 }
3006 using App::add_subcommand;
3007 /// Add an existing subcommand to be a member of an option_group
add_subcommand(App * subcom)3008 App *add_subcommand(App *subcom) {
3009 App_p subc = subcom->get_parent()->get_subcommand_ptr(subcom);
3010 subc->get_parent()->remove_subcommand(subcom);
3011 add_subcommand(std::move(subc));
3012 return subcom;
3013 }
3014 };
3015 /// Helper function to enable one option group/subcommand when another is used
TriggerOn(App * trigger_app,App * app_to_enable)3016 inline void TriggerOn(App *trigger_app, App *app_to_enable) {
3017 app_to_enable->enabled_by_default(false);
3018 app_to_enable->disabled_by_default();
3019 trigger_app->preparse_callback([app_to_enable](std::size_t) { app_to_enable->disabled(false); });
3020 }
3021
3022 /// Helper function to enable one option group/subcommand when another is used
TriggerOn(App * trigger_app,std::vector<App * > apps_to_enable)3023 inline void TriggerOn(App *trigger_app, std::vector<App *> apps_to_enable) {
3024 for(auto &app : apps_to_enable) {
3025 app->enabled_by_default(false);
3026 app->disabled_by_default();
3027 }
3028
3029 trigger_app->preparse_callback([apps_to_enable](std::size_t) {
3030 for(auto &app : apps_to_enable) {
3031 app->disabled(false);
3032 }
3033 });
3034 }
3035
3036 /// Helper function to disable one option group/subcommand when another is used
TriggerOff(App * trigger_app,App * app_to_enable)3037 inline void TriggerOff(App *trigger_app, App *app_to_enable) {
3038 app_to_enable->disabled_by_default(false);
3039 app_to_enable->enabled_by_default();
3040 trigger_app->preparse_callback([app_to_enable](std::size_t) { app_to_enable->disabled(); });
3041 }
3042
3043 /// Helper function to disable one option group/subcommand when another is used
TriggerOff(App * trigger_app,std::vector<App * > apps_to_enable)3044 inline void TriggerOff(App *trigger_app, std::vector<App *> apps_to_enable) {
3045 for(auto &app : apps_to_enable) {
3046 app->disabled_by_default(false);
3047 app->enabled_by_default();
3048 }
3049
3050 trigger_app->preparse_callback([apps_to_enable](std::size_t) {
3051 for(auto &app : apps_to_enable) {
3052 app->disabled();
3053 }
3054 });
3055 }
3056
3057 /// Helper function to mark an option as deprecated
deprecate_option(Option * opt,const std::string & replacement="")3058 inline void deprecate_option(Option *opt, const std::string &replacement = "") {
3059 Validator deprecate_warning{[opt, replacement](std::string &) {
3060 std::cout << opt->get_name() << " is deprecated please use '" << replacement
3061 << "' instead\n";
3062 return std::string();
3063 },
3064 "DEPRECATED"};
3065 deprecate_warning.application_index(0);
3066 opt->check(deprecate_warning);
3067 if(!replacement.empty()) {
3068 opt->description(opt->get_description() + " DEPRECATED: please use '" + replacement + "' instead");
3069 }
3070 }
3071
3072 /// Helper function to mark an option as deprecated
deprecate_option(App * app,const std::string & option_name,const std::string & replacement="")3073 inline void deprecate_option(App *app, const std::string &option_name, const std::string &replacement = "") {
3074 auto opt = app->get_option(option_name);
3075 deprecate_option(opt, replacement);
3076 }
3077
3078 /// Helper function to mark an option as deprecated
deprecate_option(App & app,const std::string & option_name,const std::string & replacement="")3079 inline void deprecate_option(App &app, const std::string &option_name, const std::string &replacement = "") {
3080 auto opt = app.get_option(option_name);
3081 deprecate_option(opt, replacement);
3082 }
3083
3084 /// Helper function to mark an option as retired
retire_option(App * app,Option * opt)3085 inline void retire_option(App *app, Option *opt) {
3086 App temp;
3087 auto option_copy = temp.add_option(opt->get_name(false, true))
3088 ->type_size(opt->get_type_size_min(), opt->get_type_size_max())
3089 ->expected(opt->get_expected_min(), opt->get_expected_max())
3090 ->allow_extra_args(opt->get_allow_extra_args());
3091
3092 app->remove_option(opt);
3093 auto opt2 = app->add_option(option_copy->get_name(false, true), "option has been retired and has no effect")
3094 ->type_name("RETIRED")
3095 ->default_str("RETIRED")
3096 ->type_size(option_copy->get_type_size_min(), option_copy->get_type_size_max())
3097 ->expected(option_copy->get_expected_min(), option_copy->get_expected_max())
3098 ->allow_extra_args(option_copy->get_allow_extra_args());
3099
3100 Validator retired_warning{[opt2](std::string &) {
3101 std::cout << "WARNING " << opt2->get_name() << " is retired and has no effect\n";
3102 return std::string();
3103 },
3104 ""};
3105 retired_warning.application_index(0);
3106 opt2->check(retired_warning);
3107 }
3108
3109 /// Helper function to mark an option as retired
retire_option(App & app,Option * opt)3110 inline void retire_option(App &app, Option *opt) { retire_option(&app, opt); }
3111
3112 /// Helper function to mark an option as retired
retire_option(App * app,const std::string & option_name)3113 inline void retire_option(App *app, const std::string &option_name) {
3114
3115 auto opt = app->get_option_no_throw(option_name);
3116 if(opt != nullptr) {
3117 retire_option(app, opt);
3118 return;
3119 }
3120 auto opt2 = app->add_option(option_name, "option has been retired and has no effect")
3121 ->type_name("RETIRED")
3122 ->expected(0, 1)
3123 ->default_str("RETIRED");
3124 Validator retired_warning{[opt2](std::string &) {
3125 std::cout << "WARNING " << opt2->get_name() << " is retired and has no effect\n";
3126 return std::string();
3127 },
3128 ""};
3129 retired_warning.application_index(0);
3130 opt2->check(retired_warning);
3131 }
3132
3133 /// Helper function to mark an option as retired
retire_option(App & app,const std::string & option_name)3134 inline void retire_option(App &app, const std::string &option_name) { retire_option(&app, option_name); }
3135
3136 namespace FailureMessage {
3137
3138 /// Printout a clean, simple message on error (the default in CLI11 1.5+)
simple(const App * app,const Error & e)3139 inline std::string simple(const App *app, const Error &e) {
3140 std::string header = std::string(e.what()) + "\n";
3141 std::vector<std::string> names;
3142
3143 // Collect names
3144 if(app->get_help_ptr() != nullptr)
3145 names.push_back(app->get_help_ptr()->get_name());
3146
3147 if(app->get_help_all_ptr() != nullptr)
3148 names.push_back(app->get_help_all_ptr()->get_name());
3149
3150 // If any names found, suggest those
3151 if(!names.empty())
3152 header += "Run with " + detail::join(names, " or ") + " for more information.\n";
3153
3154 return header;
3155 }
3156
3157 /// Printout the full help string on error (if this fn is set, the old default for CLI11)
help(const App * app,const Error & e)3158 inline std::string help(const App *app, const Error &e) {
3159 std::string header = std::string("ERROR: ") + e.get_name() + ": " + e.what() + "\n";
3160 header += app->help();
3161 return header;
3162 }
3163
3164 } // namespace FailureMessage
3165
3166 namespace detail {
3167 /// This class is simply to allow tests access to App's protected functions
3168 struct AppFriend {
3169 #ifdef CLI11_CPP14
3170
3171 /// Wrap _parse_short, perfectly forward arguments and return
parse_argCLI::detail::AppFriend3172 template <typename... Args> static decltype(auto) parse_arg(App *app, Args &&...args) {
3173 return app->_parse_arg(std::forward<Args>(args)...);
3174 }
3175
3176 /// Wrap _parse_subcommand, perfectly forward arguments and return
parse_subcommandCLI::detail::AppFriend3177 template <typename... Args> static decltype(auto) parse_subcommand(App *app, Args &&...args) {
3178 return app->_parse_subcommand(std::forward<Args>(args)...);
3179 }
3180 #else
3181 /// Wrap _parse_short, perfectly forward arguments and return
3182 template <typename... Args>
3183 static auto parse_arg(App *app, Args &&...args) ->
3184 typename std::result_of<decltype (&App::_parse_arg)(App, Args...)>::type {
3185 return app->_parse_arg(std::forward<Args>(args)...);
3186 }
3187
3188 /// Wrap _parse_subcommand, perfectly forward arguments and return
3189 template <typename... Args>
3190 static auto parse_subcommand(App *app, Args &&...args) ->
3191 typename std::result_of<decltype (&App::_parse_subcommand)(App, Args...)>::type {
3192 return app->_parse_subcommand(std::forward<Args>(args)...);
3193 }
3194 #endif
3195 /// Wrap the fallthrough parent function to make sure that is working correctly
get_fallthrough_parentCLI::detail::AppFriend3196 static App *get_fallthrough_parent(App *app) { return app->_get_fallthrough_parent(); }
3197 };
3198 } // namespace detail
3199
3200 // [CLI11:app_hpp:end]
3201 } // namespace CLI
3202