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 <functional>
12 #include <memory>
13 #include <set>
14 #include <string>
15 #include <tuple>
16 #include <utility>
17 #include <vector>
18 // [CLI11:public_includes:end]
19 
20 #include "Error.hpp"
21 #include "Macros.hpp"
22 #include "Split.hpp"
23 #include "StringTools.hpp"
24 #include "Validators.hpp"
25 
26 namespace CLI {
27 // [CLI11:option_hpp:verbatim]
28 
29 using results_t = std::vector<std::string>;
30 /// callback function definition
31 using callback_t = std::function<bool(const results_t &)>;
32 
33 class Option;
34 class App;
35 
36 using Option_p = std::unique_ptr<Option>;
37 /// Enumeration of the multiOption Policy selection
38 enum class MultiOptionPolicy : char {
39     Throw,      //!< Throw an error if any extra arguments were given
40     TakeLast,   //!< take only the last Expected number of arguments
41     TakeFirst,  //!< take only the first Expected number of arguments
42     Join,       //!< merge all the arguments together into a single string via the delimiter character default('\n')
43     TakeAll     //!< just get all the passed argument regardless
44 };
45 
46 /// This is the CRTP base class for Option and OptionDefaults. It was designed this way
47 /// to share parts of the class; an OptionDefaults can copy to an Option.
48 template <typename CRTP> class OptionBase {
49     friend App;
50 
51   protected:
52     /// The group membership
53     std::string group_ = std::string("Options");
54 
55     /// True if this is a required option
56     bool required_{false};
57 
58     /// Ignore the case when matching (option, not value)
59     bool ignore_case_{false};
60 
61     /// Ignore underscores when matching (option, not value)
62     bool ignore_underscore_{false};
63 
64     /// Allow this option to be given in a configuration file
65     bool configurable_{true};
66 
67     /// Disable overriding flag values with '=value'
68     bool disable_flag_override_{false};
69 
70     /// Specify a delimiter character for vector arguments
71     char delimiter_{'\0'};
72 
73     /// Automatically capture default value
74     bool always_capture_default_{false};
75 
76     /// Policy for handling multiple arguments beyond the expected Max
77     MultiOptionPolicy multi_option_policy_{MultiOptionPolicy::Throw};
78 
79     /// Copy the contents to another similar class (one based on OptionBase)
copy_to(T * other) const80     template <typename T> void copy_to(T *other) const {
81         other->group(group_);
82         other->required(required_);
83         other->ignore_case(ignore_case_);
84         other->ignore_underscore(ignore_underscore_);
85         other->configurable(configurable_);
86         other->disable_flag_override(disable_flag_override_);
87         other->delimiter(delimiter_);
88         other->always_capture_default(always_capture_default_);
89         other->multi_option_policy(multi_option_policy_);
90     }
91 
92   public:
93     // setters
94 
95     /// Changes the group membership
group(const std::string & name)96     CRTP *group(const std::string &name) {
97         if(!detail::valid_alias_name_string(name)) {
98             throw IncorrectConstruction("Group names may not contain newlines or null characters");
99         }
100         group_ = name;
101         return static_cast<CRTP *>(this);
102     }
103 
104     /// Set the option as required
required(bool value=true)105     CRTP *required(bool value = true) {
106         required_ = value;
107         return static_cast<CRTP *>(this);
108     }
109 
110     /// Support Plumbum term
mandatory(bool value=true)111     CRTP *mandatory(bool value = true) { return required(value); }
112 
always_capture_default(bool value=true)113     CRTP *always_capture_default(bool value = true) {
114         always_capture_default_ = value;
115         return static_cast<CRTP *>(this);
116     }
117 
118     // Getters
119 
120     /// Get the group of this option
get_group() const121     const std::string &get_group() const { return group_; }
122 
123     /// True if this is a required option
get_required() const124     bool get_required() const { return required_; }
125 
126     /// The status of ignore case
get_ignore_case() const127     bool get_ignore_case() const { return ignore_case_; }
128 
129     /// The status of ignore_underscore
get_ignore_underscore() const130     bool get_ignore_underscore() const { return ignore_underscore_; }
131 
132     /// The status of configurable
get_configurable() const133     bool get_configurable() const { return configurable_; }
134 
135     /// The status of configurable
get_disable_flag_override() const136     bool get_disable_flag_override() const { return disable_flag_override_; }
137 
138     /// Get the current delimiter char
get_delimiter() const139     char get_delimiter() const { return delimiter_; }
140 
141     /// Return true if this will automatically capture the default value for help printing
get_always_capture_default() const142     bool get_always_capture_default() const { return always_capture_default_; }
143 
144     /// The status of the multi option policy
get_multi_option_policy() const145     MultiOptionPolicy get_multi_option_policy() const { return multi_option_policy_; }
146 
147     // Shortcuts for multi option policy
148 
149     /// Set the multi option policy to take last
take_last()150     CRTP *take_last() {
151         auto self = static_cast<CRTP *>(this);
152         self->multi_option_policy(MultiOptionPolicy::TakeLast);
153         return self;
154     }
155 
156     /// Set the multi option policy to take last
take_first()157     CRTP *take_first() {
158         auto self = static_cast<CRTP *>(this);
159         self->multi_option_policy(MultiOptionPolicy::TakeFirst);
160         return self;
161     }
162 
163     /// Set the multi option policy to take all arguments
take_all()164     CRTP *take_all() {
165         auto self = static_cast<CRTP *>(this);
166         self->multi_option_policy(MultiOptionPolicy::TakeAll);
167         return self;
168     }
169 
170     /// Set the multi option policy to join
join()171     CRTP *join() {
172         auto self = static_cast<CRTP *>(this);
173         self->multi_option_policy(MultiOptionPolicy::Join);
174         return self;
175     }
176 
177     /// Set the multi option policy to join with a specific delimiter
join(char delim)178     CRTP *join(char delim) {
179         auto self = static_cast<CRTP *>(this);
180         self->delimiter_ = delim;
181         self->multi_option_policy(MultiOptionPolicy::Join);
182         return self;
183     }
184 
185     /// Allow in a configuration file
configurable(bool value=true)186     CRTP *configurable(bool value = true) {
187         configurable_ = value;
188         return static_cast<CRTP *>(this);
189     }
190 
191     /// Allow in a configuration file
delimiter(char value='\\0')192     CRTP *delimiter(char value = '\0') {
193         delimiter_ = value;
194         return static_cast<CRTP *>(this);
195     }
196 };
197 
198 /// This is a version of OptionBase that only supports setting values,
199 /// for defaults. It is stored as the default option in an App.
200 class OptionDefaults : public OptionBase<OptionDefaults> {
201   public:
202     OptionDefaults() = default;
203 
204     // Methods here need a different implementation if they are Option vs. OptionDefault
205 
206     /// Take the last argument if given multiple times
multi_option_policy(MultiOptionPolicy value=MultiOptionPolicy::Throw)207     OptionDefaults *multi_option_policy(MultiOptionPolicy value = MultiOptionPolicy::Throw) {
208         multi_option_policy_ = value;
209         return this;
210     }
211 
212     /// Ignore the case of the option name
ignore_case(bool value=true)213     OptionDefaults *ignore_case(bool value = true) {
214         ignore_case_ = value;
215         return this;
216     }
217 
218     /// Ignore underscores in the option name
ignore_underscore(bool value=true)219     OptionDefaults *ignore_underscore(bool value = true) {
220         ignore_underscore_ = value;
221         return this;
222     }
223 
224     /// Disable overriding flag values with an '=<value>' segment
disable_flag_override(bool value=true)225     OptionDefaults *disable_flag_override(bool value = true) {
226         disable_flag_override_ = value;
227         return this;
228     }
229 
230     /// set a delimiter character to split up single arguments to treat as multiple inputs
delimiter(char value='\\0')231     OptionDefaults *delimiter(char value = '\0') {
232         delimiter_ = value;
233         return this;
234     }
235 };
236 
237 class Option : public OptionBase<Option> {
238     friend App;
239 
240   protected:
241     /// @name Names
242     ///@{
243 
244     /// A list of the short names (`-a`) without the leading dashes
245     std::vector<std::string> snames_{};
246 
247     /// A list of the long names (`--long`) without the leading dashes
248     std::vector<std::string> lnames_{};
249 
250     /// A list of the flag names with the appropriate default value, the first part of the pair should be duplicates of
251     /// what is in snames or lnames but will trigger a particular response on a flag
252     std::vector<std::pair<std::string, std::string>> default_flag_values_{};
253 
254     /// a list of flag names with specified default values;
255     std::vector<std::string> fnames_{};
256 
257     /// A positional name
258     std::string pname_{};
259 
260     /// If given, check the environment for this option
261     std::string envname_{};
262 
263     ///@}
264     /// @name Help
265     ///@{
266 
267     /// The description for help strings
268     std::string description_{};
269 
270     /// A human readable default value, either manually set, captured, or captured by default
271     std::string default_str_{};
272 
273     /// If given, replace the text that describes the option type and usage in the help text
274     std::string option_text_{};
275 
276     /// A human readable type value, set when App creates this
277     ///
278     /// This is a lambda function so "types" can be dynamic, such as when a set prints its contents.
__anond6b818020102() 279     std::function<std::string()> type_name_{[]() { return std::string(); }};
280 
281     /// Run this function to capture a default (ignore if empty)
282     std::function<std::string()> default_function_{};
283 
284     ///@}
285     /// @name Configuration
286     ///@{
287 
288     /// The number of arguments that make up one option. max is the nominal type size, min is the minimum number of
289     /// strings
290     int type_size_max_{1};
291     /// The minimum number of arguments an option should be expecting
292     int type_size_min_{1};
293 
294     /// The minimum number of expected values
295     int expected_min_{1};
296     /// The maximum number of expected values
297     int expected_max_{1};
298 
299     /// A list of Validators to run on each value parsed
300     std::vector<Validator> validators_{};
301 
302     /// A list of options that are required with this option
303     std::set<Option *> needs_{};
304 
305     /// A list of options that are excluded with this option
306     std::set<Option *> excludes_{};
307 
308     ///@}
309     /// @name Other
310     ///@{
311 
312     /// link back up to the parent App for fallthrough
313     App *parent_{nullptr};
314 
315     /// Options store a callback to do all the work
316     callback_t callback_{};
317 
318     ///@}
319     /// @name Parsing results
320     ///@{
321 
322     /// complete Results of parsing
323     results_t results_{};
324     /// results after reduction
325     results_t proc_results_{};
326     /// enumeration for the option state machine
327     enum class option_state : char {
328         parsing = 0,       //!< The option is currently collecting parsed results
329         validated = 2,     //!< the results have been validated
330         reduced = 4,       //!< a subset of results has been generated
331         callback_run = 6,  //!< the callback has been executed
332     };
333     /// Whether the callback has run (needed for INI parsing)
334     option_state current_option_state_{option_state::parsing};
335     /// Specify that extra args beyond type_size_max should be allowed
336     bool allow_extra_args_{false};
337     /// Specify that the option should act like a flag vs regular option
338     bool flag_like_{false};
339     /// Control option to run the callback to set the default
340     bool run_callback_for_default_{false};
341     /// flag indicating a separator needs to be injected after each argument call
342     bool inject_separator_{false};
343     /// flag indicating that the option should trigger the validation and callback chain on each result when loaded
344     bool trigger_on_result_{false};
345     /// flag indicating that the option should force the callback regardless if any results present
346     bool force_callback_{false};
347     ///@}
348 
349     /// Making an option by hand is not defined, it must be made by the App class
Option(std::string option_name,std::string option_description,callback_t callback,App * parent)350     Option(std::string option_name, std::string option_description, callback_t callback, App *parent)
351         : description_(std::move(option_description)), parent_(parent), callback_(std::move(callback)) {
352         std::tie(snames_, lnames_, pname_) = detail::get_names(detail::split_names(option_name));
353     }
354 
355   public:
356     /// @name Basic
357     ///@{
358 
359     Option(const Option &) = delete;
360     Option &operator=(const Option &) = delete;
361 
362     /// Count the total number of times an option was passed
count() const363     std::size_t count() const { return results_.size(); }
364 
365     /// True if the option was not passed
empty() const366     bool empty() const { return results_.empty(); }
367 
368     /// This bool operator returns true if any arguments were passed or the option callback is forced
operator bool() const369     explicit operator bool() const { return !empty() || force_callback_; }
370 
371     /// Clear the parsed results (mostly for testing)
clear()372     void clear() {
373         results_.clear();
374         current_option_state_ = option_state::parsing;
375     }
376 
377     ///@}
378     /// @name Setting options
379     ///@{
380 
381     /// Set the number of expected arguments
expected(int value)382     Option *expected(int value) {
383         if(value < 0) {
384             expected_min_ = -value;
385             if(expected_max_ < expected_min_) {
386                 expected_max_ = expected_min_;
387             }
388             allow_extra_args_ = true;
389             flag_like_ = false;
390         } else if(value == detail::expected_max_vector_size) {
391             expected_min_ = 1;
392             expected_max_ = detail::expected_max_vector_size;
393             allow_extra_args_ = true;
394             flag_like_ = false;
395         } else {
396             expected_min_ = value;
397             expected_max_ = value;
398             flag_like_ = (expected_min_ == 0);
399         }
400         return this;
401     }
402 
403     /// Set the range of expected arguments
expected(int value_min,int value_max)404     Option *expected(int value_min, int value_max) {
405         if(value_min < 0) {
406             value_min = -value_min;
407         }
408 
409         if(value_max < 0) {
410             value_max = detail::expected_max_vector_size;
411         }
412         if(value_max < value_min) {
413             expected_min_ = value_max;
414             expected_max_ = value_min;
415         } else {
416             expected_max_ = value_max;
417             expected_min_ = value_min;
418         }
419 
420         return this;
421     }
422     /// Set the value of allow_extra_args which allows extra value arguments on the flag or option to be included
423     /// with each instance
allow_extra_args(bool value=true)424     Option *allow_extra_args(bool value = true) {
425         allow_extra_args_ = value;
426         return this;
427     }
428     /// Get the current value of allow extra args
get_allow_extra_args() const429     bool get_allow_extra_args() const { return allow_extra_args_; }
430     /// Set the value of trigger_on_parse which specifies that the option callback should be triggered on every parse
trigger_on_parse(bool value=true)431     Option *trigger_on_parse(bool value = true) {
432         trigger_on_result_ = value;
433         return this;
434     }
435     /// The status of trigger on parse
get_trigger_on_parse() const436     bool get_trigger_on_parse() const { return trigger_on_result_; }
437 
438     /// Set the value of force_callback
force_callback(bool value=true)439     Option *force_callback(bool value = true) {
440         force_callback_ = value;
441         return this;
442     }
443     /// The status of force_callback
get_force_callback() const444     bool get_force_callback() const { return force_callback_; }
445 
446     /// Set the value of run_callback_for_default which controls whether the callback function should be called to set
447     /// the default This is controlled automatically but could be manipulated by the user.
run_callback_for_default(bool value=true)448     Option *run_callback_for_default(bool value = true) {
449         run_callback_for_default_ = value;
450         return this;
451     }
452     /// Get the current value of run_callback_for_default
get_run_callback_for_default() const453     bool get_run_callback_for_default() const { return run_callback_for_default_; }
454 
455     /// Adds a Validator with a built in type name
check(Validator validator,const std::string & validator_name="")456     Option *check(Validator validator, const std::string &validator_name = "") {
457         validator.non_modifying();
458         validators_.push_back(std::move(validator));
459         if(!validator_name.empty())
460             validators_.back().name(validator_name);
461         return this;
462     }
463 
464     /// Adds a Validator. Takes a const string& and returns an error message (empty if conversion/check is okay).
check(std::function<std::string (const std::string &)> Validator,std::string Validator_description="",std::string Validator_name="")465     Option *check(std::function<std::string(const std::string &)> Validator,
466                   std::string Validator_description = "",
467                   std::string Validator_name = "") {
468         validators_.emplace_back(Validator, std::move(Validator_description), std::move(Validator_name));
469         validators_.back().non_modifying();
470         return this;
471     }
472 
473     /// Adds a transforming Validator with a built in type name
transform(Validator Validator,const std::string & Validator_name="")474     Option *transform(Validator Validator, const std::string &Validator_name = "") {
475         validators_.insert(validators_.begin(), std::move(Validator));
476         if(!Validator_name.empty())
477             validators_.front().name(Validator_name);
478         return this;
479     }
480 
481     /// Adds a Validator-like function that can change result
transform(const std::function<std::string (std::string)> & func,std::string transform_description="",std::string transform_name="")482     Option *transform(const std::function<std::string(std::string)> &func,
483                       std::string transform_description = "",
484                       std::string transform_name = "") {
485         validators_.insert(validators_.begin(),
486                            Validator(
487                                [func](std::string &val) {
488                                    val = func(val);
489                                    return std::string{};
490                                },
491                                std::move(transform_description),
492                                std::move(transform_name)));
493 
494         return this;
495     }
496 
497     /// Adds a user supplied function to run on each item passed in (communicate though lambda capture)
each(const std::function<void (std::string)> & func)498     Option *each(const std::function<void(std::string)> &func) {
499         validators_.emplace_back(
500             [func](std::string &inout) {
501                 func(inout);
502                 return std::string{};
503             },
504             std::string{});
505         return this;
506     }
507     /// Get a named Validator
get_validator(const std::string & Validator_name="")508     Validator *get_validator(const std::string &Validator_name = "") {
509         for(auto &Validator : validators_) {
510             if(Validator_name == Validator.get_name()) {
511                 return &Validator;
512             }
513         }
514         if((Validator_name.empty()) && (!validators_.empty())) {
515             return &(validators_.front());
516         }
517         throw OptionNotFound(std::string{"Validator "} + Validator_name + " Not Found");
518     }
519 
520     /// Get a Validator by index NOTE: this may not be the order of definition
get_validator(int index)521     Validator *get_validator(int index) {
522         // This is an signed int so that it is not equivalent to a pointer.
523         if(index >= 0 && index < static_cast<int>(validators_.size())) {
524             return &(validators_[static_cast<decltype(validators_)::size_type>(index)]);
525         }
526         throw OptionNotFound("Validator index is not valid");
527     }
528 
529     /// Sets required options
needs(Option * opt)530     Option *needs(Option *opt) {
531         if(opt != this) {
532             needs_.insert(opt);
533         }
534         return this;
535     }
536 
537     /// Can find a string if needed
needs(std::string opt_name)538     template <typename T = App> Option *needs(std::string opt_name) {
539         auto opt = static_cast<T *>(parent_)->get_option_no_throw(opt_name);
540         if(opt == nullptr) {
541             throw IncorrectConstruction::MissingOption(opt_name);
542         }
543         return needs(opt);
544     }
545 
546     /// Any number supported, any mix of string and Opt
needs(A opt,B opt1,ARG...args)547     template <typename A, typename B, typename... ARG> Option *needs(A opt, B opt1, ARG... args) {
548         needs(opt);
549         return needs(opt1, args...);
550     }
551 
552     /// Remove needs link from an option. Returns true if the option really was in the needs list.
remove_needs(Option * opt)553     bool remove_needs(Option *opt) {
554         auto iterator = std::find(std::begin(needs_), std::end(needs_), opt);
555 
556         if(iterator == std::end(needs_)) {
557             return false;
558         }
559         needs_.erase(iterator);
560         return true;
561     }
562 
563     /// Sets excluded options
excludes(Option * opt)564     Option *excludes(Option *opt) {
565         if(opt == this) {
566             throw(IncorrectConstruction("and option cannot exclude itself"));
567         }
568         excludes_.insert(opt);
569 
570         // Help text should be symmetric - excluding a should exclude b
571         opt->excludes_.insert(this);
572 
573         // Ignoring the insert return value, excluding twice is now allowed.
574         // (Mostly to allow both directions to be excluded by user, even though the library does it for you.)
575 
576         return this;
577     }
578 
579     /// Can find a string if needed
excludes(std::string opt_name)580     template <typename T = App> Option *excludes(std::string opt_name) {
581         auto opt = static_cast<T *>(parent_)->get_option_no_throw(opt_name);
582         if(opt == nullptr) {
583             throw IncorrectConstruction::MissingOption(opt_name);
584         }
585         return excludes(opt);
586     }
587 
588     /// Any number supported, any mix of string and Opt
excludes(A opt,B opt1,ARG...args)589     template <typename A, typename B, typename... ARG> Option *excludes(A opt, B opt1, ARG... args) {
590         excludes(opt);
591         return excludes(opt1, args...);
592     }
593 
594     /// Remove needs link from an option. Returns true if the option really was in the needs list.
remove_excludes(Option * opt)595     bool remove_excludes(Option *opt) {
596         auto iterator = std::find(std::begin(excludes_), std::end(excludes_), opt);
597 
598         if(iterator == std::end(excludes_)) {
599             return false;
600         }
601         excludes_.erase(iterator);
602         return true;
603     }
604 
605     /// Sets environment variable to read if no option given
envname(std::string name)606     Option *envname(std::string name) {
607         envname_ = std::move(name);
608         return this;
609     }
610 
611     /// Ignore case
612     ///
613     /// The template hides the fact that we don't have the definition of App yet.
614     /// You are never expected to add an argument to the template here.
ignore_case(bool value=true)615     template <typename T = App> Option *ignore_case(bool value = true) {
616         if(!ignore_case_ && value) {
617             ignore_case_ = value;
618             auto *parent = static_cast<T *>(parent_);
619             for(const Option_p &opt : parent->options_) {
620                 if(opt.get() == this) {
621                     continue;
622                 }
623                 auto &omatch = opt->matching_name(*this);
624                 if(!omatch.empty()) {
625                     ignore_case_ = false;
626                     throw OptionAlreadyAdded("adding ignore case caused a name conflict with " + omatch);
627                 }
628             }
629         } else {
630             ignore_case_ = value;
631         }
632         return this;
633     }
634 
635     /// Ignore underscores in the option names
636     ///
637     /// The template hides the fact that we don't have the definition of App yet.
638     /// You are never expected to add an argument to the template here.
ignore_underscore(bool value=true)639     template <typename T = App> Option *ignore_underscore(bool value = true) {
640 
641         if(!ignore_underscore_ && value) {
642             ignore_underscore_ = value;
643             auto *parent = static_cast<T *>(parent_);
644             for(const Option_p &opt : parent->options_) {
645                 if(opt.get() == this) {
646                     continue;
647                 }
648                 auto &omatch = opt->matching_name(*this);
649                 if(!omatch.empty()) {
650                     ignore_underscore_ = false;
651                     throw OptionAlreadyAdded("adding ignore underscore caused a name conflict with " + omatch);
652                 }
653             }
654         } else {
655             ignore_underscore_ = value;
656         }
657         return this;
658     }
659 
660     /// Take the last argument if given multiple times (or another policy)
multi_option_policy(MultiOptionPolicy value=MultiOptionPolicy::Throw)661     Option *multi_option_policy(MultiOptionPolicy value = MultiOptionPolicy::Throw) {
662         if(value != multi_option_policy_) {
663             if(multi_option_policy_ == MultiOptionPolicy::Throw && expected_max_ == detail::expected_max_vector_size &&
664                expected_min_ > 1) {  // this bizarre condition is to maintain backwards compatibility
665                                      // with the previous behavior of expected_ with vectors
666                 expected_max_ = expected_min_;
667             }
668             multi_option_policy_ = value;
669             current_option_state_ = option_state::parsing;
670         }
671         return this;
672     }
673 
674     /// Disable flag overrides values, e.g. --flag=<value> is not allowed
disable_flag_override(bool value=true)675     Option *disable_flag_override(bool value = true) {
676         disable_flag_override_ = value;
677         return this;
678     }
679     ///@}
680     /// @name Accessors
681     ///@{
682 
683     /// The number of arguments the option expects
get_type_size() const684     int get_type_size() const { return type_size_min_; }
685 
686     /// The minimum number of arguments the option expects
get_type_size_min() const687     int get_type_size_min() const { return type_size_min_; }
688     /// The maximum number of arguments the option expects
get_type_size_max() const689     int get_type_size_max() const { return type_size_max_; }
690 
691     /// Return the inject_separator flag
get_inject_separator() const692     int get_inject_separator() const { return inject_separator_; }
693 
694     /// The environment variable associated to this value
get_envname() const695     std::string get_envname() const { return envname_; }
696 
697     /// The set of options needed
get_needs() const698     std::set<Option *> get_needs() const { return needs_; }
699 
700     /// The set of options excluded
get_excludes() const701     std::set<Option *> get_excludes() const { return excludes_; }
702 
703     /// The default value (for help printing)
get_default_str() const704     std::string get_default_str() const { return default_str_; }
705 
706     /// Get the callback function
get_callback() const707     callback_t get_callback() const { return callback_; }
708 
709     /// Get the long names
get_lnames() const710     const std::vector<std::string> &get_lnames() const { return lnames_; }
711 
712     /// Get the short names
get_snames() const713     const std::vector<std::string> &get_snames() const { return snames_; }
714 
715     /// Get the flag names with specified default values
get_fnames() const716     const std::vector<std::string> &get_fnames() const { return fnames_; }
717     /// Get a single name for the option, first of lname, pname, sname, envname
get_single_name() const718     const std::string &get_single_name() const {
719         if(!lnames_.empty()) {
720             return lnames_[0];
721         }
722         if(!pname_.empty()) {
723             return pname_;
724         }
725         if(!snames_.empty()) {
726             return snames_[0];
727         }
728         return envname_;
729     }
730     /// The number of times the option expects to be included
get_expected() const731     int get_expected() const { return expected_min_; }
732 
733     /// The number of times the option expects to be included
get_expected_min() const734     int get_expected_min() const { return expected_min_; }
735     /// The max number of times the option expects to be included
get_expected_max() const736     int get_expected_max() const { return expected_max_; }
737 
738     /// The total min number of expected  string values to be used
get_items_expected_min() const739     int get_items_expected_min() const { return type_size_min_ * expected_min_; }
740 
741     /// Get the maximum number of items expected to be returned and used for the callback
get_items_expected_max() const742     int get_items_expected_max() const {
743         int t = type_size_max_;
744         return detail::checked_multiply(t, expected_max_) ? t : detail::expected_max_vector_size;
745     }
746     /// The total min number of expected  string values to be used
get_items_expected() const747     int get_items_expected() const { return get_items_expected_min(); }
748 
749     /// True if the argument can be given directly
get_positional() const750     bool get_positional() const { return pname_.length() > 0; }
751 
752     /// True if option has at least one non-positional name
nonpositional() const753     bool nonpositional() const { return (snames_.size() + lnames_.size()) > 0; }
754 
755     /// True if option has description
has_description() const756     bool has_description() const { return description_.length() > 0; }
757 
758     /// Get the description
get_description() const759     const std::string &get_description() const { return description_; }
760 
761     /// Set the description
description(std::string option_description)762     Option *description(std::string option_description) {
763         description_ = std::move(option_description);
764         return this;
765     }
766 
option_text(std::string text)767     Option *option_text(std::string text) {
768         option_text_ = std::move(text);
769         return this;
770     }
771 
get_option_text() const772     const std::string &get_option_text() const { return option_text_; }
773 
774     ///@}
775     /// @name Help tools
776     ///@{
777 
778     /// \brief Gets a comma separated list of names.
779     /// Will include / prefer the positional name if positional is true.
780     /// If all_options is false, pick just the most descriptive name to show.
781     /// Use `get_name(true)` to get the positional name (replaces `get_pname`)
get_name(bool positional=false,bool all_options=false) const782     std::string get_name(bool positional = false,  ///< Show the positional name
783                          bool all_options = false  ///< Show every option
784     ) const {
785         if(get_group().empty())
786             return {};  // Hidden
787 
788         if(all_options) {
789 
790             std::vector<std::string> name_list;
791 
792             /// The all list will never include a positional unless asked or that's the only name.
793             if((positional && (!pname_.empty())) || (snames_.empty() && lnames_.empty())) {
794                 name_list.push_back(pname_);
795             }
796             if((get_items_expected() == 0) && (!fnames_.empty())) {
797                 for(const std::string &sname : snames_) {
798                     name_list.push_back("-" + sname);
799                     if(check_fname(sname)) {
800                         name_list.back() += "{" + get_flag_value(sname, "") + "}";
801                     }
802                 }
803 
804                 for(const std::string &lname : lnames_) {
805                     name_list.push_back("--" + lname);
806                     if(check_fname(lname)) {
807                         name_list.back() += "{" + get_flag_value(lname, "") + "}";
808                     }
809                 }
810             } else {
811                 for(const std::string &sname : snames_)
812                     name_list.push_back("-" + sname);
813 
814                 for(const std::string &lname : lnames_)
815                     name_list.push_back("--" + lname);
816             }
817 
818             return detail::join(name_list);
819         }
820 
821         // This returns the positional name no matter what
822         if(positional)
823             return pname_;
824 
825         // Prefer long name
826         if(!lnames_.empty())
827             return std::string(2, '-') + lnames_[0];
828 
829         // Or short name if no long name
830         if(!snames_.empty())
831             return std::string(1, '-') + snames_[0];
832 
833         // If positional is the only name, it's okay to use that
834         return pname_;
835     }
836 
837     ///@}
838     /// @name Parser tools
839     ///@{
840 
841     /// Process the callback
run_callback()842     void run_callback() {
843         if(force_callback_ && results_.empty()) {
844             add_result(default_str_);
845         }
846         if(current_option_state_ == option_state::parsing) {
847             _validate_results(results_);
848             current_option_state_ = option_state::validated;
849         }
850 
851         if(current_option_state_ < option_state::reduced) {
852             _reduce_results(proc_results_, results_);
853             current_option_state_ = option_state::reduced;
854         }
855         if(current_option_state_ >= option_state::reduced) {
856             current_option_state_ = option_state::callback_run;
857             if(!(callback_)) {
858                 return;
859             }
860             const results_t &send_results = proc_results_.empty() ? results_ : proc_results_;
861             bool local_result = callback_(send_results);
862 
863             if(!local_result)
864                 throw ConversionError(get_name(), results_);
865         }
866     }
867 
868     /// If options share any of the same names, find it
matching_name(const Option & other) const869     const std::string &matching_name(const Option &other) const {
870         static const std::string estring;
871         for(const std::string &sname : snames_)
872             if(other.check_sname(sname))
873                 return sname;
874         for(const std::string &lname : lnames_)
875             if(other.check_lname(lname))
876                 return lname;
877 
878         if(ignore_case_ ||
879            ignore_underscore_) {  // We need to do the inverse, in case we are ignore_case or ignore underscore
880             for(const std::string &sname : other.snames_)
881                 if(check_sname(sname))
882                     return sname;
883             for(const std::string &lname : other.lnames_)
884                 if(check_lname(lname))
885                     return lname;
886         }
887         return estring;
888     }
889     /// If options share any of the same names, they are equal (not counting positional)
operator ==(const Option & other) const890     bool operator==(const Option &other) const { return !matching_name(other).empty(); }
891 
892     /// Check a name. Requires "-" or "--" for short / long, supports positional name
check_name(const std::string & name) const893     bool check_name(const std::string &name) const {
894 
895         if(name.length() > 2 && name[0] == '-' && name[1] == '-')
896             return check_lname(name.substr(2));
897         if(name.length() > 1 && name.front() == '-')
898             return check_sname(name.substr(1));
899         if(!pname_.empty()) {
900             std::string local_pname = pname_;
901             std::string local_name = name;
902             if(ignore_underscore_) {
903                 local_pname = detail::remove_underscore(local_pname);
904                 local_name = detail::remove_underscore(local_name);
905             }
906             if(ignore_case_) {
907                 local_pname = detail::to_lower(local_pname);
908                 local_name = detail::to_lower(local_name);
909             }
910             if(local_name == local_pname) {
911                 return true;
912             }
913         }
914 
915         if(!envname_.empty()) {
916             // this needs to be the original since envname_ shouldn't match on case insensitivity
917             return (name == envname_);
918         }
919         return false;
920     }
921 
922     /// Requires "-" to be removed from string
check_sname(std::string name) const923     bool check_sname(std::string name) const {
924         return (detail::find_member(std::move(name), snames_, ignore_case_) >= 0);
925     }
926 
927     /// Requires "--" to be removed from string
check_lname(std::string name) const928     bool check_lname(std::string name) const {
929         return (detail::find_member(std::move(name), lnames_, ignore_case_, ignore_underscore_) >= 0);
930     }
931 
932     /// Requires "--" to be removed from string
check_fname(std::string name) const933     bool check_fname(std::string name) const {
934         if(fnames_.empty()) {
935             return false;
936         }
937         return (detail::find_member(std::move(name), fnames_, ignore_case_, ignore_underscore_) >= 0);
938     }
939 
940     /// Get the value that goes for a flag, nominally gets the default value but allows for overrides if not
941     /// disabled
get_flag_value(const std::string & name,std::string input_value) const942     std::string get_flag_value(const std::string &name, std::string input_value) const {
943         static const std::string trueString{"true"};
944         static const std::string falseString{"false"};
945         static const std::string emptyString{"{}"};
946         // check for disable flag override_
947         if(disable_flag_override_) {
948             if(!((input_value.empty()) || (input_value == emptyString))) {
949                 auto default_ind = detail::find_member(name, fnames_, ignore_case_, ignore_underscore_);
950                 if(default_ind >= 0) {
951                     // We can static cast this to std::size_t because it is more than 0 in this block
952                     if(default_flag_values_[static_cast<std::size_t>(default_ind)].second != input_value) {
953                         throw(ArgumentMismatch::FlagOverride(name));
954                     }
955                 } else {
956                     if(input_value != trueString) {
957                         throw(ArgumentMismatch::FlagOverride(name));
958                     }
959                 }
960             }
961         }
962         auto ind = detail::find_member(name, fnames_, ignore_case_, ignore_underscore_);
963         if((input_value.empty()) || (input_value == emptyString)) {
964             if(flag_like_) {
965                 return (ind < 0) ? trueString : default_flag_values_[static_cast<std::size_t>(ind)].second;
966             } else {
967                 return (ind < 0) ? default_str_ : default_flag_values_[static_cast<std::size_t>(ind)].second;
968             }
969         }
970         if(ind < 0) {
971             return input_value;
972         }
973         if(default_flag_values_[static_cast<std::size_t>(ind)].second == falseString) {
974             try {
975                 auto val = detail::to_flag_value(input_value);
976                 return (val == 1) ? falseString : (val == (-1) ? trueString : std::to_string(-val));
977             } catch(const std::invalid_argument &) {
978                 return input_value;
979             }
980         } else {
981             return input_value;
982         }
983     }
984 
985     /// Puts a result at the end
add_result(std::string s)986     Option *add_result(std::string s) {
987         _add_result(std::move(s), results_);
988         current_option_state_ = option_state::parsing;
989         return this;
990     }
991 
992     /// Puts a result at the end and get a count of the number of arguments actually added
add_result(std::string s,int & results_added)993     Option *add_result(std::string s, int &results_added) {
994         results_added = _add_result(std::move(s), results_);
995         current_option_state_ = option_state::parsing;
996         return this;
997     }
998 
999     /// Puts a result at the end
add_result(std::vector<std::string> s)1000     Option *add_result(std::vector<std::string> s) {
1001         current_option_state_ = option_state::parsing;
1002         for(auto &str : s) {
1003             _add_result(std::move(str), results_);
1004         }
1005         return this;
1006     }
1007 
1008     /// Get the current complete results set
results() const1009     const results_t &results() const { return results_; }
1010 
1011     /// Get a copy of the results
reduced_results() const1012     results_t reduced_results() const {
1013         results_t res = proc_results_.empty() ? results_ : proc_results_;
1014         if(current_option_state_ < option_state::reduced) {
1015             if(current_option_state_ == option_state::parsing) {
1016                 res = results_;
1017                 _validate_results(res);
1018             }
1019             if(!res.empty()) {
1020                 results_t extra;
1021                 _reduce_results(extra, res);
1022                 if(!extra.empty()) {
1023                     res = std::move(extra);
1024                 }
1025             }
1026         }
1027         return res;
1028     }
1029 
1030     /// Get the results as a specified type
results(T & output) const1031     template <typename T> void results(T &output) const {
1032         bool retval;
1033         if(current_option_state_ >= option_state::reduced || (results_.size() == 1 && validators_.empty())) {
1034             const results_t &res = (proc_results_.empty()) ? results_ : proc_results_;
1035             retval = detail::lexical_conversion<T, T>(res, output);
1036         } else {
1037             results_t res;
1038             if(results_.empty()) {
1039                 if(!default_str_.empty()) {
1040                     // _add_results takes an rvalue only
1041                     _add_result(std::string(default_str_), res);
1042                     _validate_results(res);
1043                     results_t extra;
1044                     _reduce_results(extra, res);
1045                     if(!extra.empty()) {
1046                         res = std::move(extra);
1047                     }
1048                 } else {
1049                     res.emplace_back();
1050                 }
1051             } else {
1052                 res = reduced_results();
1053             }
1054             retval = detail::lexical_conversion<T, T>(res, output);
1055         }
1056         if(!retval) {
1057             throw ConversionError(get_name(), results_);
1058         }
1059     }
1060 
1061     /// Return the results as the specified type
as() const1062     template <typename T> T as() const {
1063         T output;
1064         results(output);
1065         return output;
1066     }
1067 
1068     /// See if the callback has been run already
get_callback_run() const1069     bool get_callback_run() const { return (current_option_state_ == option_state::callback_run); }
1070 
1071     ///@}
1072     /// @name Custom options
1073     ///@{
1074 
1075     /// Set the type function to run when displayed on this option
type_name_fn(std::function<std::string ()> typefun)1076     Option *type_name_fn(std::function<std::string()> typefun) {
1077         type_name_ = std::move(typefun);
1078         return this;
1079     }
1080 
1081     /// Set a custom option typestring
type_name(std::string typeval)1082     Option *type_name(std::string typeval) {
1083         type_name_fn([typeval]() { return typeval; });
1084         return this;
1085     }
1086 
1087     /// Set a custom option size
type_size(int option_type_size)1088     Option *type_size(int option_type_size) {
1089         if(option_type_size < 0) {
1090             // this section is included for backwards compatibility
1091             type_size_max_ = -option_type_size;
1092             type_size_min_ = -option_type_size;
1093             expected_max_ = detail::expected_max_vector_size;
1094         } else {
1095             type_size_max_ = option_type_size;
1096             if(type_size_max_ < detail::expected_max_vector_size) {
1097                 type_size_min_ = option_type_size;
1098             } else {
1099                 inject_separator_ = true;
1100             }
1101             if(type_size_max_ == 0)
1102                 required_ = false;
1103         }
1104         return this;
1105     }
1106     /// Set a custom option type size range
type_size(int option_type_size_min,int option_type_size_max)1107     Option *type_size(int option_type_size_min, int option_type_size_max) {
1108         if(option_type_size_min < 0 || option_type_size_max < 0) {
1109             // this section is included for backwards compatibility
1110             expected_max_ = detail::expected_max_vector_size;
1111             option_type_size_min = (std::abs)(option_type_size_min);
1112             option_type_size_max = (std::abs)(option_type_size_max);
1113         }
1114 
1115         if(option_type_size_min > option_type_size_max) {
1116             type_size_max_ = option_type_size_min;
1117             type_size_min_ = option_type_size_max;
1118         } else {
1119             type_size_min_ = option_type_size_min;
1120             type_size_max_ = option_type_size_max;
1121         }
1122         if(type_size_max_ == 0) {
1123             required_ = false;
1124         }
1125         if(type_size_max_ >= detail::expected_max_vector_size) {
1126             inject_separator_ = true;
1127         }
1128         return this;
1129     }
1130 
1131     /// Set the value of the separator injection flag
inject_separator(bool value=true)1132     void inject_separator(bool value = true) { inject_separator_ = value; }
1133 
1134     /// Set a capture function for the default. Mostly used by App.
default_function(const std::function<std::string ()> & func)1135     Option *default_function(const std::function<std::string()> &func) {
1136         default_function_ = func;
1137         return this;
1138     }
1139 
1140     /// Capture the default value from the original value (if it can be captured)
capture_default_str()1141     Option *capture_default_str() {
1142         if(default_function_) {
1143             default_str_ = default_function_();
1144         }
1145         return this;
1146     }
1147 
1148     /// Set the default value string representation (does not change the contained value)
default_str(std::string val)1149     Option *default_str(std::string val) {
1150         default_str_ = std::move(val);
1151         return this;
1152     }
1153 
1154     /// Set the default value and validate the results and run the callback if appropriate to set the value into the
1155     /// bound value only available for types that can be converted to a string
default_val(const X & val)1156     template <typename X> Option *default_val(const X &val) {
1157         std::string val_str = detail::to_string(val);
1158         auto old_option_state = current_option_state_;
1159         results_t old_results{std::move(results_)};
1160         results_.clear();
1161         try {
1162             add_result(val_str);
1163             // if trigger_on_result_ is set the callback already ran
1164             if(run_callback_for_default_ && !trigger_on_result_) {
1165                 run_callback();  // run callback sets the state we need to reset it again
1166                 current_option_state_ = option_state::parsing;
1167             } else {
1168                 _validate_results(results_);
1169                 current_option_state_ = old_option_state;
1170             }
1171         } catch(const CLI::Error &) {
1172             // this should be done
1173             results_ = std::move(old_results);
1174             current_option_state_ = old_option_state;
1175             throw;
1176         }
1177         results_ = std::move(old_results);
1178         default_str_ = std::move(val_str);
1179         return this;
1180     }
1181 
1182     /// Get the full typename for this option
get_type_name() const1183     std::string get_type_name() const {
1184         std::string full_type_name = type_name_();
1185         if(!validators_.empty()) {
1186             for(auto &Validator : validators_) {
1187                 std::string vtype = Validator.get_description();
1188                 if(!vtype.empty()) {
1189                     full_type_name += ":" + vtype;
1190                 }
1191             }
1192         }
1193         return full_type_name;
1194     }
1195 
1196   private:
1197     /// Run the results through the Validators
_validate_results(results_t & res) const1198     void _validate_results(results_t &res) const {
1199         // Run the Validators (can change the string)
1200         if(!validators_.empty()) {
1201             if(type_size_max_ > 1) {  // in this context index refers to the index in the type
1202                 int index = 0;
1203                 if(get_items_expected_max() < static_cast<int>(res.size()) &&
1204                    multi_option_policy_ == CLI::MultiOptionPolicy::TakeLast) {
1205                     // create a negative index for the earliest ones
1206                     index = get_items_expected_max() - static_cast<int>(res.size());
1207                 }
1208 
1209                 for(std::string &result : res) {
1210                     if(detail::is_separator(result) && type_size_max_ != type_size_min_ && index >= 0) {
1211                         index = 0;  // reset index for variable size chunks
1212                         continue;
1213                     }
1214                     auto err_msg = _validate(result, (index >= 0) ? (index % type_size_max_) : index);
1215                     if(!err_msg.empty())
1216                         throw ValidationError(get_name(), err_msg);
1217                     ++index;
1218                 }
1219             } else {
1220                 int index = 0;
1221                 if(expected_max_ < static_cast<int>(res.size()) &&
1222                    multi_option_policy_ == CLI::MultiOptionPolicy::TakeLast) {
1223                     // create a negative index for the earliest ones
1224                     index = expected_max_ - static_cast<int>(res.size());
1225                 }
1226                 for(std::string &result : res) {
1227                     auto err_msg = _validate(result, index);
1228                     ++index;
1229                     if(!err_msg.empty())
1230                         throw ValidationError(get_name(), err_msg);
1231                 }
1232             }
1233         }
1234     }
1235 
1236     /** reduce the results in accordance with the MultiOptionPolicy
1237     @param[out] res results are assigned to res if there if they are different
1238     */
_reduce_results(results_t & res,const results_t & original) const1239     void _reduce_results(results_t &res, const results_t &original) const {
1240 
1241         // max num items expected or length of vector, always at least 1
1242         // Only valid for a trimming policy
1243 
1244         res.clear();
1245         // Operation depends on the policy setting
1246         switch(multi_option_policy_) {
1247         case MultiOptionPolicy::TakeAll:
1248             break;
1249         case MultiOptionPolicy::TakeLast: {
1250             // Allow multi-option sizes (including 0)
1251             std::size_t trim_size = std::min<std::size_t>(
1252                 static_cast<std::size_t>(std::max<int>(get_items_expected_max(), 1)), original.size());
1253             if(original.size() != trim_size) {
1254                 res.assign(original.end() - static_cast<results_t::difference_type>(trim_size), original.end());
1255             }
1256         } break;
1257         case MultiOptionPolicy::TakeFirst: {
1258             std::size_t trim_size = std::min<std::size_t>(
1259                 static_cast<std::size_t>(std::max<int>(get_items_expected_max(), 1)), original.size());
1260             if(original.size() != trim_size) {
1261                 res.assign(original.begin(), original.begin() + static_cast<results_t::difference_type>(trim_size));
1262             }
1263         } break;
1264         case MultiOptionPolicy::Join:
1265             if(results_.size() > 1) {
1266                 res.push_back(detail::join(original, std::string(1, (delimiter_ == '\0') ? '\n' : delimiter_)));
1267             }
1268             break;
1269         case MultiOptionPolicy::Throw:
1270         default: {
1271             auto num_min = static_cast<std::size_t>(get_items_expected_min());
1272             auto num_max = static_cast<std::size_t>(get_items_expected_max());
1273             if(num_min == 0) {
1274                 num_min = 1;
1275             }
1276             if(num_max == 0) {
1277                 num_max = 1;
1278             }
1279             if(original.size() < num_min) {
1280                 throw ArgumentMismatch::AtLeast(get_name(), static_cast<int>(num_min), original.size());
1281             }
1282             if(original.size() > num_max) {
1283                 throw ArgumentMismatch::AtMost(get_name(), static_cast<int>(num_max), original.size());
1284             }
1285             break;
1286         }
1287         }
1288     }
1289 
1290     // Run a result through the Validators
_validate(std::string & result,int index) const1291     std::string _validate(std::string &result, int index) const {
1292         std::string err_msg;
1293         if(result.empty() && expected_min_ == 0) {
1294             // an empty with nothing expected is allowed
1295             return err_msg;
1296         }
1297         for(const auto &vali : validators_) {
1298             auto v = vali.get_application_index();
1299             if(v == -1 || v == index) {
1300                 try {
1301                     err_msg = vali(result);
1302                 } catch(const ValidationError &err) {
1303                     err_msg = err.what();
1304                 }
1305                 if(!err_msg.empty())
1306                     break;
1307             }
1308         }
1309 
1310         return err_msg;
1311     }
1312 
1313     /// Add a single result to the result set, taking into account delimiters
_add_result(std::string && result,std::vector<std::string> & res) const1314     int _add_result(std::string &&result, std::vector<std::string> &res) const {
1315         int result_count = 0;
1316         if(allow_extra_args_ && !result.empty() && result.front() == '[' &&
1317            result.back() == ']') {  // this is now a vector string likely from the default or user entry
1318             result.pop_back();
1319 
1320             for(auto &var : CLI::detail::split(result.substr(1), ',')) {
1321                 if(!var.empty()) {
1322                     result_count += _add_result(std::move(var), res);
1323                 }
1324             }
1325             return result_count;
1326         }
1327         if(delimiter_ == '\0') {
1328             res.push_back(std::move(result));
1329             ++result_count;
1330         } else {
1331             if((result.find_first_of(delimiter_) != std::string::npos)) {
1332                 for(const auto &var : CLI::detail::split(result, delimiter_)) {
1333                     if(!var.empty()) {
1334                         res.push_back(var);
1335                         ++result_count;
1336                     }
1337                 }
1338             } else {
1339                 res.push_back(std::move(result));
1340                 ++result_count;
1341             }
1342         }
1343         return result_count;
1344     }
1345 };  // namespace CLI
1346 
1347 // [CLI11:option_hpp:end]
1348 }  // namespace CLI
1349