Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2024-09-28 07:02:18

0001 // Copyright (c) 2017-2020, University of Cincinnati, developed by Henry Schreiner
0002 // under NSF AWARD 1414736 and by the respective contributors.
0003 // All rights reserved.
0004 //
0005 // SPDX-License-Identifier: BSD-3-Clause
0006 
0007 #pragma once
0008 
0009 // [CLI11:public_includes:set]
0010 #include <algorithm>
0011 #include <functional>
0012 #include <memory>
0013 #include <set>
0014 #include <string>
0015 #include <tuple>
0016 #include <utility>
0017 #include <vector>
0018 // [CLI11:public_includes:end]
0019 
0020 #include "Error.hpp"
0021 #include "Macros.hpp"
0022 #include "Split.hpp"
0023 #include "StringTools.hpp"
0024 #include "Validators.hpp"
0025 
0026 namespace CLI {
0027 // [CLI11:option_hpp:verbatim]
0028 
0029 using results_t = std::vector<std::string>;
0030 /// callback function definition
0031 using callback_t = std::function<bool(const results_t &)>;
0032 
0033 class Option;
0034 class App;
0035 
0036 using Option_p = std::unique_ptr<Option>;
0037 /// Enumeration of the multiOption Policy selection
0038 enum class MultiOptionPolicy : char {
0039     Throw,      //!< Throw an error if any extra arguments were given
0040     TakeLast,   //!< take only the last Expected number of arguments
0041     TakeFirst,  //!< take only the first Expected number of arguments
0042     Join,       //!< merge all the arguments together into a single string via the delimiter character default('\n')
0043     TakeAll     //!< just get all the passed argument regardless
0044 };
0045 
0046 /// This is the CRTP base class for Option and OptionDefaults. It was designed this way
0047 /// to share parts of the class; an OptionDefaults can copy to an Option.
0048 template <typename CRTP> class OptionBase {
0049     friend App;
0050 
0051   protected:
0052     /// The group membership
0053     std::string group_ = std::string("Options");
0054 
0055     /// True if this is a required option
0056     bool required_{false};
0057 
0058     /// Ignore the case when matching (option, not value)
0059     bool ignore_case_{false};
0060 
0061     /// Ignore underscores when matching (option, not value)
0062     bool ignore_underscore_{false};
0063 
0064     /// Allow this option to be given in a configuration file
0065     bool configurable_{true};
0066 
0067     /// Disable overriding flag values with '=value'
0068     bool disable_flag_override_{false};
0069 
0070     /// Specify a delimiter character for vector arguments
0071     char delimiter_{'\0'};
0072 
0073     /// Automatically capture default value
0074     bool always_capture_default_{false};
0075 
0076     /// Policy for handling multiple arguments beyond the expected Max
0077     MultiOptionPolicy multi_option_policy_{MultiOptionPolicy::Throw};
0078 
0079     /// Copy the contents to another similar class (one based on OptionBase)
0080     template <typename T> void copy_to(T *other) const {
0081         other->group(group_);
0082         other->required(required_);
0083         other->ignore_case(ignore_case_);
0084         other->ignore_underscore(ignore_underscore_);
0085         other->configurable(configurable_);
0086         other->disable_flag_override(disable_flag_override_);
0087         other->delimiter(delimiter_);
0088         other->always_capture_default(always_capture_default_);
0089         other->multi_option_policy(multi_option_policy_);
0090     }
0091 
0092   public:
0093     // setters
0094 
0095     /// Changes the group membership
0096     CRTP *group(const std::string &name) {
0097         group_ = name;
0098         return static_cast<CRTP *>(this);
0099     }
0100 
0101     /// Set the option as required
0102     CRTP *required(bool value = true) {
0103         required_ = value;
0104         return static_cast<CRTP *>(this);
0105     }
0106 
0107     /// Support Plumbum term
0108     CRTP *mandatory(bool value = true) { return required(value); }
0109 
0110     CRTP *always_capture_default(bool value = true) {
0111         always_capture_default_ = value;
0112         return static_cast<CRTP *>(this);
0113     }
0114 
0115     // Getters
0116 
0117     /// Get the group of this option
0118     const std::string &get_group() const { return group_; }
0119 
0120     /// True if this is a required option
0121     bool get_required() const { return required_; }
0122 
0123     /// The status of ignore case
0124     bool get_ignore_case() const { return ignore_case_; }
0125 
0126     /// The status of ignore_underscore
0127     bool get_ignore_underscore() const { return ignore_underscore_; }
0128 
0129     /// The status of configurable
0130     bool get_configurable() const { return configurable_; }
0131 
0132     /// The status of configurable
0133     bool get_disable_flag_override() const { return disable_flag_override_; }
0134 
0135     /// Get the current delimiter char
0136     char get_delimiter() const { return delimiter_; }
0137 
0138     /// Return true if this will automatically capture the default value for help printing
0139     bool get_always_capture_default() const { return always_capture_default_; }
0140 
0141     /// The status of the multi option policy
0142     MultiOptionPolicy get_multi_option_policy() const { return multi_option_policy_; }
0143 
0144     // Shortcuts for multi option policy
0145 
0146     /// Set the multi option policy to take last
0147     CRTP *take_last() {
0148         auto self = static_cast<CRTP *>(this);
0149         self->multi_option_policy(MultiOptionPolicy::TakeLast);
0150         return self;
0151     }
0152 
0153     /// Set the multi option policy to take last
0154     CRTP *take_first() {
0155         auto self = static_cast<CRTP *>(this);
0156         self->multi_option_policy(MultiOptionPolicy::TakeFirst);
0157         return self;
0158     }
0159 
0160     /// Set the multi option policy to take all arguments
0161     CRTP *take_all() {
0162         auto self = static_cast<CRTP *>(this);
0163         self->multi_option_policy(MultiOptionPolicy::TakeAll);
0164         return self;
0165     }
0166 
0167     /// Set the multi option policy to join
0168     CRTP *join() {
0169         auto self = static_cast<CRTP *>(this);
0170         self->multi_option_policy(MultiOptionPolicy::Join);
0171         return self;
0172     }
0173 
0174     /// Set the multi option policy to join with a specific delimiter
0175     CRTP *join(char delim) {
0176         auto self = static_cast<CRTP *>(this);
0177         self->delimiter_ = delim;
0178         self->multi_option_policy(MultiOptionPolicy::Join);
0179         return self;
0180     }
0181 
0182     /// Allow in a configuration file
0183     CRTP *configurable(bool value = true) {
0184         configurable_ = value;
0185         return static_cast<CRTP *>(this);
0186     }
0187 
0188     /// Allow in a configuration file
0189     CRTP *delimiter(char value = '\0') {
0190         delimiter_ = value;
0191         return static_cast<CRTP *>(this);
0192     }
0193 };
0194 
0195 /// This is a version of OptionBase that only supports setting values,
0196 /// for defaults. It is stored as the default option in an App.
0197 class OptionDefaults : public OptionBase<OptionDefaults> {
0198   public:
0199     OptionDefaults() = default;
0200 
0201     // Methods here need a different implementation if they are Option vs. OptionDefault
0202 
0203     /// Take the last argument if given multiple times
0204     OptionDefaults *multi_option_policy(MultiOptionPolicy value = MultiOptionPolicy::Throw) {
0205         multi_option_policy_ = value;
0206         return this;
0207     }
0208 
0209     /// Ignore the case of the option name
0210     OptionDefaults *ignore_case(bool value = true) {
0211         ignore_case_ = value;
0212         return this;
0213     }
0214 
0215     /// Ignore underscores in the option name
0216     OptionDefaults *ignore_underscore(bool value = true) {
0217         ignore_underscore_ = value;
0218         return this;
0219     }
0220 
0221     /// Disable overriding flag values with an '=<value>' segment
0222     OptionDefaults *disable_flag_override(bool value = true) {
0223         disable_flag_override_ = value;
0224         return this;
0225     }
0226 
0227     /// set a delimiter character to split up single arguments to treat as multiple inputs
0228     OptionDefaults *delimiter(char value = '\0') {
0229         delimiter_ = value;
0230         return this;
0231     }
0232 };
0233 
0234 class Option : public OptionBase<Option> {
0235     friend App;
0236 
0237   protected:
0238     /// @name Names
0239     ///@{
0240 
0241     /// A list of the short names (`-a`) without the leading dashes
0242     std::vector<std::string> snames_{};
0243 
0244     /// A list of the long names (`--long`) without the leading dashes
0245     std::vector<std::string> lnames_{};
0246 
0247     /// A list of the flag names with the appropriate default value, the first part of the pair should be duplicates of
0248     /// what is in snames or lnames but will trigger a particular response on a flag
0249     std::vector<std::pair<std::string, std::string>> default_flag_values_{};
0250 
0251     /// a list of flag names with specified default values;
0252     std::vector<std::string> fnames_{};
0253 
0254     /// A positional name
0255     std::string pname_{};
0256 
0257     /// If given, check the environment for this option
0258     std::string envname_{};
0259 
0260     ///@}
0261     /// @name Help
0262     ///@{
0263 
0264     /// The description for help strings
0265     std::string description_{};
0266 
0267     /// A human readable default value, either manually set, captured, or captured by default
0268     std::string default_str_{};
0269 
0270     /// If given, replace the text that describes the option type and usage in the help text
0271     std::string option_text_{};
0272 
0273     /// A human readable type value, set when App creates this
0274     ///
0275     /// This is a lambda function so "types" can be dynamic, such as when a set prints its contents.
0276     std::function<std::string()> type_name_{[]() { return std::string(); }};
0277 
0278     /// Run this function to capture a default (ignore if empty)
0279     std::function<std::string()> default_function_{};
0280 
0281     ///@}
0282     /// @name Configuration
0283     ///@{
0284 
0285     /// The number of arguments that make up one option. max is the nominal type size, min is the minimum number of
0286     /// strings
0287     int type_size_max_{1};
0288     /// The minimum number of arguments an option should be expecting
0289     int type_size_min_{1};
0290 
0291     /// The minimum number of expected values
0292     int expected_min_{1};
0293     /// The maximum number of expected values
0294     int expected_max_{1};
0295 
0296     /// A list of Validators to run on each value parsed
0297     std::vector<Validator> validators_{};
0298 
0299     /// A list of options that are required with this option
0300     std::set<Option *> needs_{};
0301 
0302     /// A list of options that are excluded with this option
0303     std::set<Option *> excludes_{};
0304 
0305     ///@}
0306     /// @name Other
0307     ///@{
0308 
0309     /// link back up to the parent App for fallthrough
0310     App *parent_{nullptr};
0311 
0312     /// Options store a callback to do all the work
0313     callback_t callback_{};
0314 
0315     ///@}
0316     /// @name Parsing results
0317     ///@{
0318 
0319     /// complete Results of parsing
0320     results_t results_{};
0321     /// results after reduction
0322     results_t proc_results_{};
0323     /// enumeration for the option state machine
0324     enum class option_state : char {
0325         parsing = 0,       //!< The option is currently collecting parsed results
0326         validated = 2,     //!< the results have been validated
0327         reduced = 4,       //!< a subset of results has been generated
0328         callback_run = 6,  //!< the callback has been executed
0329     };
0330     /// Whether the callback has run (needed for INI parsing)
0331     option_state current_option_state_{option_state::parsing};
0332     /// Specify that extra args beyond type_size_max should be allowed
0333     bool allow_extra_args_{false};
0334     /// Specify that the option should act like a flag vs regular option
0335     bool flag_like_{false};
0336     /// Control option to run the callback to set the default
0337     bool run_callback_for_default_{false};
0338     /// flag indicating a separator needs to be injected after each argument call
0339     bool inject_separator_{false};
0340     ///@}
0341 
0342     /// Making an option by hand is not defined, it must be made by the App class
0343     Option(std::string option_name, std::string option_description, callback_t callback, App *parent)
0344         : description_(std::move(option_description)), parent_(parent), callback_(std::move(callback)) {
0345         std::tie(snames_, lnames_, pname_) = detail::get_names(detail::split_names(option_name));
0346     }
0347 
0348   public:
0349     /// @name Basic
0350     ///@{
0351 
0352     Option(const Option &) = delete;
0353     Option &operator=(const Option &) = delete;
0354 
0355     /// Count the total number of times an option was passed
0356     std::size_t count() const { return results_.size(); }
0357 
0358     /// True if the option was not passed
0359     bool empty() const { return results_.empty(); }
0360 
0361     /// This class is true if option is passed.
0362     explicit operator bool() const { return !empty(); }
0363 
0364     /// Clear the parsed results (mostly for testing)
0365     void clear() {
0366         results_.clear();
0367         current_option_state_ = option_state::parsing;
0368     }
0369 
0370     ///@}
0371     /// @name Setting options
0372     ///@{
0373 
0374     /// Set the number of expected arguments
0375     Option *expected(int value) {
0376         if(value < 0) {
0377             expected_min_ = -value;
0378             if(expected_max_ < expected_min_) {
0379                 expected_max_ = expected_min_;
0380             }
0381             allow_extra_args_ = true;
0382             flag_like_ = false;
0383         } else if(value == detail::expected_max_vector_size) {
0384             expected_min_ = 1;
0385             expected_max_ = detail::expected_max_vector_size;
0386             allow_extra_args_ = true;
0387             flag_like_ = false;
0388         } else {
0389             expected_min_ = value;
0390             expected_max_ = value;
0391             flag_like_ = (expected_min_ == 0);
0392         }
0393         return this;
0394     }
0395 
0396     /// Set the range of expected arguments
0397     Option *expected(int value_min, int value_max) {
0398         if(value_min < 0) {
0399             value_min = -value_min;
0400         }
0401 
0402         if(value_max < 0) {
0403             value_max = detail::expected_max_vector_size;
0404         }
0405         if(value_max < value_min) {
0406             expected_min_ = value_max;
0407             expected_max_ = value_min;
0408         } else {
0409             expected_max_ = value_max;
0410             expected_min_ = value_min;
0411         }
0412 
0413         return this;
0414     }
0415     /// Set the value of allow_extra_args which allows extra value arguments on the flag or option to be included
0416     /// with each instance
0417     Option *allow_extra_args(bool value = true) {
0418         allow_extra_args_ = value;
0419         return this;
0420     }
0421     /// Get the current value of allow extra args
0422     bool get_allow_extra_args() const { return allow_extra_args_; }
0423 
0424     /// Set the value of run_callback_for_default which controls whether the callback function should be called to set
0425     /// the default This is controlled automatically but could be manipulated by the user.
0426     Option *run_callback_for_default(bool value = true) {
0427         run_callback_for_default_ = value;
0428         return this;
0429     }
0430     /// Get the current value of run_callback_for_default
0431     bool get_run_callback_for_default() const { return run_callback_for_default_; }
0432 
0433     /// Adds a Validator with a built in type name
0434     Option *check(Validator validator, const std::string &validator_name = "") {
0435         validator.non_modifying();
0436         validators_.push_back(std::move(validator));
0437         if(!validator_name.empty())
0438             validators_.back().name(validator_name);
0439         return this;
0440     }
0441 
0442     /// Adds a Validator. Takes a const string& and returns an error message (empty if conversion/check is okay).
0443     Option *check(std::function<std::string(const std::string &)> Validator,
0444                   std::string Validator_description = "",
0445                   std::string Validator_name = "") {
0446         validators_.emplace_back(Validator, std::move(Validator_description), std::move(Validator_name));
0447         validators_.back().non_modifying();
0448         return this;
0449     }
0450 
0451     /// Adds a transforming Validator with a built in type name
0452     Option *transform(Validator Validator, const std::string &Validator_name = "") {
0453         validators_.insert(validators_.begin(), std::move(Validator));
0454         if(!Validator_name.empty())
0455             validators_.front().name(Validator_name);
0456         return this;
0457     }
0458 
0459     /// Adds a Validator-like function that can change result
0460     Option *transform(const std::function<std::string(std::string)> &func,
0461                       std::string transform_description = "",
0462                       std::string transform_name = "") {
0463         validators_.insert(validators_.begin(),
0464                            Validator(
0465                                [func](std::string &val) {
0466                                    val = func(val);
0467                                    return std::string{};
0468                                },
0469                                std::move(transform_description),
0470                                std::move(transform_name)));
0471 
0472         return this;
0473     }
0474 
0475     /// Adds a user supplied function to run on each item passed in (communicate though lambda capture)
0476     Option *each(const std::function<void(std::string)> &func) {
0477         validators_.emplace_back(
0478             [func](std::string &inout) {
0479                 func(inout);
0480                 return std::string{};
0481             },
0482             std::string{});
0483         return this;
0484     }
0485     /// Get a named Validator
0486     Validator *get_validator(const std::string &Validator_name = "") {
0487         for(auto &Validator : validators_) {
0488             if(Validator_name == Validator.get_name()) {
0489                 return &Validator;
0490             }
0491         }
0492         if((Validator_name.empty()) && (!validators_.empty())) {
0493             return &(validators_.front());
0494         }
0495         throw OptionNotFound(std::string{"Validator "} + Validator_name + " Not Found");
0496     }
0497 
0498     /// Get a Validator by index NOTE: this may not be the order of definition
0499     Validator *get_validator(int index) {
0500         // This is an signed int so that it is not equivalent to a pointer.
0501         if(index >= 0 && index < static_cast<int>(validators_.size())) {
0502             return &(validators_[static_cast<decltype(validators_)::size_type>(index)]);
0503         }
0504         throw OptionNotFound("Validator index is not valid");
0505     }
0506 
0507     /// Sets required options
0508     Option *needs(Option *opt) {
0509         if(opt != this) {
0510             needs_.insert(opt);
0511         }
0512         return this;
0513     }
0514 
0515     /// Can find a string if needed
0516     template <typename T = App> Option *needs(std::string opt_name) {
0517         auto opt = static_cast<T *>(parent_)->get_option_no_throw(opt_name);
0518         if(opt == nullptr) {
0519             throw IncorrectConstruction::MissingOption(opt_name);
0520         }
0521         return needs(opt);
0522     }
0523 
0524     /// Any number supported, any mix of string and Opt
0525     template <typename A, typename B, typename... ARG> Option *needs(A opt, B opt1, ARG... args) {
0526         needs(opt);
0527         return needs(opt1, args...);
0528     }
0529 
0530     /// Remove needs link from an option. Returns true if the option really was in the needs list.
0531     bool remove_needs(Option *opt) {
0532         auto iterator = std::find(std::begin(needs_), std::end(needs_), opt);
0533 
0534         if(iterator == std::end(needs_)) {
0535             return false;
0536         }
0537         needs_.erase(iterator);
0538         return true;
0539     }
0540 
0541     /// Sets excluded options
0542     Option *excludes(Option *opt) {
0543         if(opt == this) {
0544             throw(IncorrectConstruction("and option cannot exclude itself"));
0545         }
0546         excludes_.insert(opt);
0547 
0548         // Help text should be symmetric - excluding a should exclude b
0549         opt->excludes_.insert(this);
0550 
0551         // Ignoring the insert return value, excluding twice is now allowed.
0552         // (Mostly to allow both directions to be excluded by user, even though the library does it for you.)
0553 
0554         return this;
0555     }
0556 
0557     /// Can find a string if needed
0558     template <typename T = App> Option *excludes(std::string opt_name) {
0559         auto opt = static_cast<T *>(parent_)->get_option_no_throw(opt_name);
0560         if(opt == nullptr) {
0561             throw IncorrectConstruction::MissingOption(opt_name);
0562         }
0563         return excludes(opt);
0564     }
0565 
0566     /// Any number supported, any mix of string and Opt
0567     template <typename A, typename B, typename... ARG> Option *excludes(A opt, B opt1, ARG... args) {
0568         excludes(opt);
0569         return excludes(opt1, args...);
0570     }
0571 
0572     /// Remove needs link from an option. Returns true if the option really was in the needs list.
0573     bool remove_excludes(Option *opt) {
0574         auto iterator = std::find(std::begin(excludes_), std::end(excludes_), opt);
0575 
0576         if(iterator == std::end(excludes_)) {
0577             return false;
0578         }
0579         excludes_.erase(iterator);
0580         return true;
0581     }
0582 
0583     /// Sets environment variable to read if no option given
0584     Option *envname(std::string name) {
0585         envname_ = std::move(name);
0586         return this;
0587     }
0588 
0589     /// Ignore case
0590     ///
0591     /// The template hides the fact that we don't have the definition of App yet.
0592     /// You are never expected to add an argument to the template here.
0593     template <typename T = App> Option *ignore_case(bool value = true) {
0594         if(!ignore_case_ && value) {
0595             ignore_case_ = value;
0596             auto *parent = static_cast<T *>(parent_);
0597             for(const Option_p &opt : parent->options_) {
0598                 if(opt.get() == this) {
0599                     continue;
0600                 }
0601                 auto &omatch = opt->matching_name(*this);
0602                 if(!omatch.empty()) {
0603                     ignore_case_ = false;
0604                     throw OptionAlreadyAdded("adding ignore case caused a name conflict with " + omatch);
0605                 }
0606             }
0607         } else {
0608             ignore_case_ = value;
0609         }
0610         return this;
0611     }
0612 
0613     /// Ignore underscores in the option names
0614     ///
0615     /// The template hides the fact that we don't have the definition of App yet.
0616     /// You are never expected to add an argument to the template here.
0617     template <typename T = App> Option *ignore_underscore(bool value = true) {
0618 
0619         if(!ignore_underscore_ && value) {
0620             ignore_underscore_ = value;
0621             auto *parent = static_cast<T *>(parent_);
0622             for(const Option_p &opt : parent->options_) {
0623                 if(opt.get() == this) {
0624                     continue;
0625                 }
0626                 auto &omatch = opt->matching_name(*this);
0627                 if(!omatch.empty()) {
0628                     ignore_underscore_ = false;
0629                     throw OptionAlreadyAdded("adding ignore underscore caused a name conflict with " + omatch);
0630                 }
0631             }
0632         } else {
0633             ignore_underscore_ = value;
0634         }
0635         return this;
0636     }
0637 
0638     /// Take the last argument if given multiple times (or another policy)
0639     Option *multi_option_policy(MultiOptionPolicy value = MultiOptionPolicy::Throw) {
0640         if(value != multi_option_policy_) {
0641             if(multi_option_policy_ == MultiOptionPolicy::Throw && expected_max_ == detail::expected_max_vector_size &&
0642                expected_min_ > 1) {  // this bizarre condition is to maintain backwards compatibility
0643                                      // with the previous behavior of expected_ with vectors
0644                 expected_max_ = expected_min_;
0645             }
0646             multi_option_policy_ = value;
0647             current_option_state_ = option_state::parsing;
0648         }
0649         return this;
0650     }
0651 
0652     /// Disable flag overrides values, e.g. --flag=<value> is not allowed
0653     Option *disable_flag_override(bool value = true) {
0654         disable_flag_override_ = value;
0655         return this;
0656     }
0657     ///@}
0658     /// @name Accessors
0659     ///@{
0660 
0661     /// The number of arguments the option expects
0662     int get_type_size() const { return type_size_min_; }
0663 
0664     /// The minimum number of arguments the option expects
0665     int get_type_size_min() const { return type_size_min_; }
0666     /// The maximum number of arguments the option expects
0667     int get_type_size_max() const { return type_size_max_; }
0668 
0669     /// The number of arguments the option expects
0670     int get_inject_separator() const { return inject_separator_; }
0671 
0672     /// The environment variable associated to this value
0673     std::string get_envname() const { return envname_; }
0674 
0675     /// The set of options needed
0676     std::set<Option *> get_needs() const { return needs_; }
0677 
0678     /// The set of options excluded
0679     std::set<Option *> get_excludes() const { return excludes_; }
0680 
0681     /// The default value (for help printing)
0682     std::string get_default_str() const { return default_str_; }
0683 
0684     /// Get the callback function
0685     callback_t get_callback() const { return callback_; }
0686 
0687     /// Get the long names
0688     const std::vector<std::string> &get_lnames() const { return lnames_; }
0689 
0690     /// Get the short names
0691     const std::vector<std::string> &get_snames() const { return snames_; }
0692 
0693     /// Get the flag names with specified default values
0694     const std::vector<std::string> &get_fnames() const { return fnames_; }
0695     /// Get a single name for the option, first of lname, pname, sname, envname
0696     const std::string &get_single_name() const {
0697         if(!lnames_.empty()) {
0698             return lnames_[0];
0699         }
0700         if(!pname_.empty()) {
0701             return pname_;
0702         }
0703         if(!snames_.empty()) {
0704             return snames_[0];
0705         }
0706         return envname_;
0707     }
0708     /// The number of times the option expects to be included
0709     int get_expected() const { return expected_min_; }
0710 
0711     /// The number of times the option expects to be included
0712     int get_expected_min() const { return expected_min_; }
0713     /// The max number of times the option expects to be included
0714     int get_expected_max() const { return expected_max_; }
0715 
0716     /// The total min number of expected  string values to be used
0717     int get_items_expected_min() const { return type_size_min_ * expected_min_; }
0718 
0719     /// Get the maximum number of items expected to be returned and used for the callback
0720     int get_items_expected_max() const {
0721         int t = type_size_max_;
0722         return detail::checked_multiply(t, expected_max_) ? t : detail::expected_max_vector_size;
0723     }
0724     /// The total min number of expected  string values to be used
0725     int get_items_expected() const { return get_items_expected_min(); }
0726 
0727     /// True if the argument can be given directly
0728     bool get_positional() const { return pname_.length() > 0; }
0729 
0730     /// True if option has at least one non-positional name
0731     bool nonpositional() const { return (snames_.size() + lnames_.size()) > 0; }
0732 
0733     /// True if option has description
0734     bool has_description() const { return description_.length() > 0; }
0735 
0736     /// Get the description
0737     const std::string &get_description() const { return description_; }
0738 
0739     /// Set the description
0740     Option *description(std::string option_description) {
0741         description_ = std::move(option_description);
0742         return this;
0743     }
0744 
0745     Option *option_text(std::string text) {
0746         option_text_ = std::move(text);
0747         return this;
0748     }
0749 
0750     const std::string &get_option_text() const { return option_text_; }
0751 
0752     ///@}
0753     /// @name Help tools
0754     ///@{
0755 
0756     /// \brief Gets a comma separated list of names.
0757     /// Will include / prefer the positional name if positional is true.
0758     /// If all_options is false, pick just the most descriptive name to show.
0759     /// Use `get_name(true)` to get the positional name (replaces `get_pname`)
0760     std::string get_name(bool positional = false,  ///< Show the positional name
0761                          bool all_options = false  ///< Show every option
0762                          ) const {
0763         if(get_group().empty())
0764             return {};  // Hidden
0765 
0766         if(all_options) {
0767 
0768             std::vector<std::string> name_list;
0769 
0770             /// The all list will never include a positional unless asked or that's the only name.
0771             if((positional && (!pname_.empty())) || (snames_.empty() && lnames_.empty())) {
0772                 name_list.push_back(pname_);
0773             }
0774             if((get_items_expected() == 0) && (!fnames_.empty())) {
0775                 for(const std::string &sname : snames_) {
0776                     name_list.push_back("-" + sname);
0777                     if(check_fname(sname)) {
0778                         name_list.back() += "{" + get_flag_value(sname, "") + "}";
0779                     }
0780                 }
0781 
0782                 for(const std::string &lname : lnames_) {
0783                     name_list.push_back("--" + lname);
0784                     if(check_fname(lname)) {
0785                         name_list.back() += "{" + get_flag_value(lname, "") + "}";
0786                     }
0787                 }
0788             } else {
0789                 for(const std::string &sname : snames_)
0790                     name_list.push_back("-" + sname);
0791 
0792                 for(const std::string &lname : lnames_)
0793                     name_list.push_back("--" + lname);
0794             }
0795 
0796             return detail::join(name_list);
0797         }
0798 
0799         // This returns the positional name no matter what
0800         if(positional)
0801             return pname_;
0802 
0803         // Prefer long name
0804         if(!lnames_.empty())
0805             return std::string(2, '-') + lnames_[0];
0806 
0807         // Or short name if no long name
0808         if(!snames_.empty())
0809             return std::string(1, '-') + snames_[0];
0810 
0811         // If positional is the only name, it's okay to use that
0812         return pname_;
0813     }
0814 
0815     ///@}
0816     /// @name Parser tools
0817     ///@{
0818 
0819     /// Process the callback
0820     void run_callback() {
0821 
0822         if(current_option_state_ == option_state::parsing) {
0823             _validate_results(results_);
0824             current_option_state_ = option_state::validated;
0825         }
0826 
0827         if(current_option_state_ < option_state::reduced) {
0828             _reduce_results(proc_results_, results_);
0829             current_option_state_ = option_state::reduced;
0830         }
0831         if(current_option_state_ >= option_state::reduced) {
0832             current_option_state_ = option_state::callback_run;
0833             if(!(callback_)) {
0834                 return;
0835             }
0836             const results_t &send_results = proc_results_.empty() ? results_ : proc_results_;
0837             bool local_result = callback_(send_results);
0838 
0839             if(!local_result)
0840                 throw ConversionError(get_name(), results_);
0841         }
0842     }
0843 
0844     /// If options share any of the same names, find it
0845     const std::string &matching_name(const Option &other) const {
0846         static const std::string estring;
0847         for(const std::string &sname : snames_)
0848             if(other.check_sname(sname))
0849                 return sname;
0850         for(const std::string &lname : lnames_)
0851             if(other.check_lname(lname))
0852                 return lname;
0853 
0854         if(ignore_case_ ||
0855            ignore_underscore_) {  // We need to do the inverse, in case we are ignore_case or ignore underscore
0856             for(const std::string &sname : other.snames_)
0857                 if(check_sname(sname))
0858                     return sname;
0859             for(const std::string &lname : other.lnames_)
0860                 if(check_lname(lname))
0861                     return lname;
0862         }
0863         return estring;
0864     }
0865     /// If options share any of the same names, they are equal (not counting positional)
0866     bool operator==(const Option &other) const { return !matching_name(other).empty(); }
0867 
0868     /// Check a name. Requires "-" or "--" for short / long, supports positional name
0869     bool check_name(const std::string &name) const {
0870 
0871         if(name.length() > 2 && name[0] == '-' && name[1] == '-')
0872             return check_lname(name.substr(2));
0873         if(name.length() > 1 && name.front() == '-')
0874             return check_sname(name.substr(1));
0875         if(!pname_.empty()) {
0876             std::string local_pname = pname_;
0877             std::string local_name = name;
0878             if(ignore_underscore_) {
0879                 local_pname = detail::remove_underscore(local_pname);
0880                 local_name = detail::remove_underscore(local_name);
0881             }
0882             if(ignore_case_) {
0883                 local_pname = detail::to_lower(local_pname);
0884                 local_name = detail::to_lower(local_name);
0885             }
0886             if(local_name == local_pname) {
0887                 return true;
0888             }
0889         }
0890 
0891         if(!envname_.empty()) {
0892             // this needs to be the original since envname_ shouldn't match on case insensitivity
0893             return (name == envname_);
0894         }
0895         return false;
0896     }
0897 
0898     /// Requires "-" to be removed from string
0899     bool check_sname(std::string name) const {
0900         return (detail::find_member(std::move(name), snames_, ignore_case_) >= 0);
0901     }
0902 
0903     /// Requires "--" to be removed from string
0904     bool check_lname(std::string name) const {
0905         return (detail::find_member(std::move(name), lnames_, ignore_case_, ignore_underscore_) >= 0);
0906     }
0907 
0908     /// Requires "--" to be removed from string
0909     bool check_fname(std::string name) const {
0910         if(fnames_.empty()) {
0911             return false;
0912         }
0913         return (detail::find_member(std::move(name), fnames_, ignore_case_, ignore_underscore_) >= 0);
0914     }
0915 
0916     /// Get the value that goes for a flag, nominally gets the default value but allows for overrides if not
0917     /// disabled
0918     std::string get_flag_value(const std::string &name, std::string input_value) const {
0919         static const std::string trueString{"true"};
0920         static const std::string falseString{"false"};
0921         static const std::string emptyString{"{}"};
0922         // check for disable flag override_
0923         if(disable_flag_override_) {
0924             if(!((input_value.empty()) || (input_value == emptyString))) {
0925                 auto default_ind = detail::find_member(name, fnames_, ignore_case_, ignore_underscore_);
0926                 if(default_ind >= 0) {
0927                     // We can static cast this to std::size_t because it is more than 0 in this block
0928                     if(default_flag_values_[static_cast<std::size_t>(default_ind)].second != input_value) {
0929                         throw(ArgumentMismatch::FlagOverride(name));
0930                     }
0931                 } else {
0932                     if(input_value != trueString) {
0933                         throw(ArgumentMismatch::FlagOverride(name));
0934                     }
0935                 }
0936             }
0937         }
0938         auto ind = detail::find_member(name, fnames_, ignore_case_, ignore_underscore_);
0939         if((input_value.empty()) || (input_value == emptyString)) {
0940             if(flag_like_) {
0941                 return (ind < 0) ? trueString : default_flag_values_[static_cast<std::size_t>(ind)].second;
0942             } else {
0943                 return (ind < 0) ? default_str_ : default_flag_values_[static_cast<std::size_t>(ind)].second;
0944             }
0945         }
0946         if(ind < 0) {
0947             return input_value;
0948         }
0949         if(default_flag_values_[static_cast<std::size_t>(ind)].second == falseString) {
0950             try {
0951                 auto val = detail::to_flag_value(input_value);
0952                 return (val == 1) ? falseString : (val == (-1) ? trueString : std::to_string(-val));
0953             } catch(const std::invalid_argument &) {
0954                 return input_value;
0955             }
0956         } else {
0957             return input_value;
0958         }
0959     }
0960 
0961     /// Puts a result at the end
0962     Option *add_result(std::string s) {
0963         _add_result(std::move(s), results_);
0964         current_option_state_ = option_state::parsing;
0965         return this;
0966     }
0967 
0968     /// Puts a result at the end and get a count of the number of arguments actually added
0969     Option *add_result(std::string s, int &results_added) {
0970         results_added = _add_result(std::move(s), results_);
0971         current_option_state_ = option_state::parsing;
0972         return this;
0973     }
0974 
0975     /// Puts a result at the end
0976     Option *add_result(std::vector<std::string> s) {
0977         for(auto &str : s) {
0978             _add_result(std::move(str), results_);
0979         }
0980         current_option_state_ = option_state::parsing;
0981         return this;
0982     }
0983 
0984     /// Get the current complete results set
0985     const results_t &results() const { return results_; }
0986 
0987     /// Get a copy of the results
0988     results_t reduced_results() const {
0989         results_t res = proc_results_.empty() ? results_ : proc_results_;
0990         if(current_option_state_ < option_state::reduced) {
0991             if(current_option_state_ == option_state::parsing) {
0992                 res = results_;
0993                 _validate_results(res);
0994             }
0995             if(!res.empty()) {
0996                 results_t extra;
0997                 _reduce_results(extra, res);
0998                 if(!extra.empty()) {
0999                     res = std::move(extra);
1000                 }
1001             }
1002         }
1003         return res;
1004     }
1005 
1006     /// Get the results as a specified type
1007     template <typename T> void results(T &output) const {
1008         bool retval;
1009         if(current_option_state_ >= option_state::reduced || (results_.size() == 1 && validators_.empty())) {
1010             const results_t &res = (proc_results_.empty()) ? results_ : proc_results_;
1011             retval = detail::lexical_conversion<T, T>(res, output);
1012         } else {
1013             results_t res;
1014             if(results_.empty()) {
1015                 if(!default_str_.empty()) {
1016                     // _add_results takes an rvalue only
1017                     _add_result(std::string(default_str_), res);
1018                     _validate_results(res);
1019                     results_t extra;
1020                     _reduce_results(extra, res);
1021                     if(!extra.empty()) {
1022                         res = std::move(extra);
1023                     }
1024                 } else {
1025                     res.emplace_back();
1026                 }
1027             } else {
1028                 res = reduced_results();
1029             }
1030             retval = detail::lexical_conversion<T, T>(res, output);
1031         }
1032         if(!retval) {
1033             throw ConversionError(get_name(), results_);
1034         }
1035     }
1036 
1037     /// Return the results as the specified type
1038     template <typename T> T as() const {
1039         T output;
1040         results(output);
1041         return output;
1042     }
1043 
1044     /// See if the callback has been run already
1045     bool get_callback_run() const { return (current_option_state_ == option_state::callback_run); }
1046 
1047     ///@}
1048     /// @name Custom options
1049     ///@{
1050 
1051     /// Set the type function to run when displayed on this option
1052     Option *type_name_fn(std::function<std::string()> typefun) {
1053         type_name_ = std::move(typefun);
1054         return this;
1055     }
1056 
1057     /// Set a custom option typestring
1058     Option *type_name(std::string typeval) {
1059         type_name_fn([typeval]() { return typeval; });
1060         return this;
1061     }
1062 
1063     /// Set a custom option size
1064     Option *type_size(int option_type_size) {
1065         if(option_type_size < 0) {
1066             // this section is included for backwards compatibility
1067             type_size_max_ = -option_type_size;
1068             type_size_min_ = -option_type_size;
1069             expected_max_ = detail::expected_max_vector_size;
1070         } else {
1071             type_size_max_ = option_type_size;
1072             if(type_size_max_ < detail::expected_max_vector_size) {
1073                 type_size_min_ = option_type_size;
1074             } else {
1075                 inject_separator_ = true;
1076             }
1077             if(type_size_max_ == 0)
1078                 required_ = false;
1079         }
1080         return this;
1081     }
1082     /// Set a custom option type size range
1083     Option *type_size(int option_type_size_min, int option_type_size_max) {
1084         if(option_type_size_min < 0 || option_type_size_max < 0) {
1085             // this section is included for backwards compatibility
1086             expected_max_ = detail::expected_max_vector_size;
1087             option_type_size_min = (std::abs)(option_type_size_min);
1088             option_type_size_max = (std::abs)(option_type_size_max);
1089         }
1090 
1091         if(option_type_size_min > option_type_size_max) {
1092             type_size_max_ = option_type_size_min;
1093             type_size_min_ = option_type_size_max;
1094         } else {
1095             type_size_min_ = option_type_size_min;
1096             type_size_max_ = option_type_size_max;
1097         }
1098         if(type_size_max_ == 0) {
1099             required_ = false;
1100         }
1101         if(type_size_max_ >= detail::expected_max_vector_size) {
1102             inject_separator_ = true;
1103         }
1104         return this;
1105     }
1106 
1107     /// Set the value of the separator injection flag
1108     void inject_separator(bool value = true) { inject_separator_ = value; }
1109 
1110     /// Set a capture function for the default. Mostly used by App.
1111     Option *default_function(const std::function<std::string()> &func) {
1112         default_function_ = func;
1113         return this;
1114     }
1115 
1116     /// Capture the default value from the original value (if it can be captured)
1117     Option *capture_default_str() {
1118         if(default_function_) {
1119             default_str_ = default_function_();
1120         }
1121         return this;
1122     }
1123 
1124     /// Set the default value string representation (does not change the contained value)
1125     Option *default_str(std::string val) {
1126         default_str_ = std::move(val);
1127         return this;
1128     }
1129 
1130     /// Set the default value and validate the results and run the callback if appropriate to set the value into the
1131     /// bound value only available for types that can be converted to a string
1132     template <typename X> Option *default_val(const X &val) {
1133         std::string val_str = detail::to_string(val);
1134         auto old_option_state = current_option_state_;
1135         results_t old_results{std::move(results_)};
1136         results_.clear();
1137         try {
1138             add_result(val_str);
1139             if(run_callback_for_default_) {
1140                 run_callback();  // run callback sets the state we need to reset it again
1141                 current_option_state_ = option_state::parsing;
1142             } else {
1143                 _validate_results(results_);
1144                 current_option_state_ = old_option_state;
1145             }
1146         } catch(const CLI::Error &) {
1147             // this should be done
1148             results_ = std::move(old_results);
1149             current_option_state_ = old_option_state;
1150             throw;
1151         }
1152         results_ = std::move(old_results);
1153         default_str_ = std::move(val_str);
1154         return this;
1155     }
1156 
1157     /// Get the full typename for this option
1158     std::string get_type_name() const {
1159         std::string full_type_name = type_name_();
1160         if(!validators_.empty()) {
1161             for(auto &Validator : validators_) {
1162                 std::string vtype = Validator.get_description();
1163                 if(!vtype.empty()) {
1164                     full_type_name += ":" + vtype;
1165                 }
1166             }
1167         }
1168         return full_type_name;
1169     }
1170 
1171   private:
1172     /// Run the results through the Validators
1173     void _validate_results(results_t &res) const {
1174         // Run the Validators (can change the string)
1175         if(!validators_.empty()) {
1176             if(type_size_max_ > 1) {  // in this context index refers to the index in the type
1177                 int index = 0;
1178                 if(get_items_expected_max() < static_cast<int>(res.size()) &&
1179                    multi_option_policy_ == CLI::MultiOptionPolicy::TakeLast) {
1180                     // create a negative index for the earliest ones
1181                     index = get_items_expected_max() - static_cast<int>(res.size());
1182                 }
1183 
1184                 for(std::string &result : res) {
1185                     if(detail::is_separator(result) && type_size_max_ != type_size_min_ && index >= 0) {
1186                         index = 0;  // reset index for variable size chunks
1187                         continue;
1188                     }
1189                     auto err_msg = _validate(result, (index >= 0) ? (index % type_size_max_) : index);
1190                     if(!err_msg.empty())
1191                         throw ValidationError(get_name(), err_msg);
1192                     ++index;
1193                 }
1194             } else {
1195                 int index = 0;
1196                 if(expected_max_ < static_cast<int>(res.size()) &&
1197                    multi_option_policy_ == CLI::MultiOptionPolicy::TakeLast) {
1198                     // create a negative index for the earliest ones
1199                     index = expected_max_ - static_cast<int>(res.size());
1200                 }
1201                 for(std::string &result : res) {
1202                     auto err_msg = _validate(result, index);
1203                     ++index;
1204                     if(!err_msg.empty())
1205                         throw ValidationError(get_name(), err_msg);
1206                 }
1207             }
1208         }
1209     }
1210 
1211     /** reduce the results in accordance with the MultiOptionPolicy
1212     @param[out] res results are assigned to res if there if they are different
1213     */
1214     void _reduce_results(results_t &res, const results_t &original) const {
1215 
1216         // max num items expected or length of vector, always at least 1
1217         // Only valid for a trimming policy
1218 
1219         res.clear();
1220         // Operation depends on the policy setting
1221         switch(multi_option_policy_) {
1222         case MultiOptionPolicy::TakeAll:
1223             break;
1224         case MultiOptionPolicy::TakeLast: {
1225             // Allow multi-option sizes (including 0)
1226             std::size_t trim_size = std::min<std::size_t>(
1227                 static_cast<std::size_t>(std::max<int>(get_items_expected_max(), 1)), original.size());
1228             if(original.size() != trim_size) {
1229                 res.assign(original.end() - static_cast<results_t::difference_type>(trim_size), original.end());
1230             }
1231         } break;
1232         case MultiOptionPolicy::TakeFirst: {
1233             std::size_t trim_size = std::min<std::size_t>(
1234                 static_cast<std::size_t>(std::max<int>(get_items_expected_max(), 1)), original.size());
1235             if(original.size() != trim_size) {
1236                 res.assign(original.begin(), original.begin() + static_cast<results_t::difference_type>(trim_size));
1237             }
1238         } break;
1239         case MultiOptionPolicy::Join:
1240             if(results_.size() > 1) {
1241                 res.push_back(detail::join(original, std::string(1, (delimiter_ == '\0') ? '\n' : delimiter_)));
1242             }
1243             break;
1244         case MultiOptionPolicy::Throw:
1245         default: {
1246             auto num_min = static_cast<std::size_t>(get_items_expected_min());
1247             auto num_max = static_cast<std::size_t>(get_items_expected_max());
1248             if(num_min == 0) {
1249                 num_min = 1;
1250             }
1251             if(num_max == 0) {
1252                 num_max = 1;
1253             }
1254             if(original.size() < num_min) {
1255                 throw ArgumentMismatch::AtLeast(get_name(), static_cast<int>(num_min), original.size());
1256             }
1257             if(original.size() > num_max) {
1258                 throw ArgumentMismatch::AtMost(get_name(), static_cast<int>(num_max), original.size());
1259             }
1260             break;
1261         }
1262         }
1263     }
1264 
1265     // Run a result through the Validators
1266     std::string _validate(std::string &result, int index) const {
1267         std::string err_msg;
1268         if(result.empty() && expected_min_ == 0) {
1269             // an empty with nothing expected is allowed
1270             return err_msg;
1271         }
1272         for(const auto &vali : validators_) {
1273             auto v = vali.get_application_index();
1274             if(v == -1 || v == index) {
1275                 try {
1276                     err_msg = vali(result);
1277                 } catch(const ValidationError &err) {
1278                     err_msg = err.what();
1279                 }
1280                 if(!err_msg.empty())
1281                     break;
1282             }
1283         }
1284 
1285         return err_msg;
1286     }
1287 
1288     /// Add a single result to the result set, taking into account delimiters
1289     int _add_result(std::string &&result, std::vector<std::string> &res) const {
1290         int result_count = 0;
1291         if(allow_extra_args_ && !result.empty() && result.front() == '[' &&
1292            result.back() == ']') {  // this is now a vector string likely from the default or user entry
1293             result.pop_back();
1294 
1295             for(auto &var : CLI::detail::split(result.substr(1), ',')) {
1296                 if(!var.empty()) {
1297                     result_count += _add_result(std::move(var), res);
1298                 }
1299             }
1300             return result_count;
1301         }
1302         if(delimiter_ == '\0') {
1303             res.push_back(std::move(result));
1304             ++result_count;
1305         } else {
1306             if((result.find_first_of(delimiter_) != std::string::npos)) {
1307                 for(const auto &var : CLI::detail::split(result, delimiter_)) {
1308                     if(!var.empty()) {
1309                         res.push_back(var);
1310                         ++result_count;
1311                     }
1312                 }
1313             } else {
1314                 res.push_back(std::move(result));
1315                 ++result_count;
1316             }
1317         }
1318         return result_count;
1319     }
1320 };  // namespace CLI
1321 
1322 // [CLI11:option_hpp:end]
1323 }  // namespace CLI