Warning, file /include/CLI/Option.hpp was not indexed
or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001
0002
0003
0004
0005
0006
0007 #pragma once
0008
0009
0010
0011
0012 #include <algorithm>
0013 #include <functional>
0014 #include <memory>
0015 #include <set>
0016 #include <string>
0017 #include <tuple>
0018 #include <utility>
0019 #include <vector>
0020
0021
0022 #include "Error.hpp"
0023 #include "Macros.hpp"
0024 #include "Split.hpp"
0025 #include "StringTools.hpp"
0026 #include "Validators.hpp"
0027
0028 namespace CLI {
0029
0030
0031 using results_t = std::vector<std::string>;
0032
0033 using callback_t = std::function<bool(const results_t &)>;
0034
0035 class Option;
0036 class App;
0037
0038 using Option_p = std::unique_ptr<Option>;
0039
0040 enum class MultiOptionPolicy : char {
0041 Throw,
0042 TakeLast,
0043 TakeFirst,
0044 Join,
0045 TakeAll,
0046 Sum,
0047 Reverse,
0048 };
0049
0050
0051
0052 template <typename CRTP> class OptionBase {
0053 friend App;
0054
0055 protected:
0056
0057 std::string group_ = std::string("OPTIONS");
0058
0059
0060 bool required_{false};
0061
0062
0063 bool ignore_case_{false};
0064
0065
0066 bool ignore_underscore_{false};
0067
0068
0069 bool configurable_{true};
0070
0071
0072 bool disable_flag_override_{false};
0073
0074
0075 char delimiter_{'\0'};
0076
0077
0078 bool always_capture_default_{false};
0079
0080
0081 MultiOptionPolicy multi_option_policy_{MultiOptionPolicy::Throw};
0082
0083
0084 template <typename T> void copy_to(T *other) const;
0085
0086 public:
0087
0088
0089
0090 CRTP *group(const std::string &name) {
0091 if(!detail::valid_alias_name_string(name)) {
0092 throw IncorrectConstruction("Group names may not contain newlines or null characters");
0093 }
0094 group_ = name;
0095 return static_cast<CRTP *>(this);
0096 }
0097
0098
0099 CRTP *required(bool value = true) {
0100 required_ = value;
0101 return static_cast<CRTP *>(this);
0102 }
0103
0104
0105 CRTP *mandatory(bool value = true) { return required(value); }
0106
0107 CRTP *always_capture_default(bool value = true) {
0108 always_capture_default_ = value;
0109 return static_cast<CRTP *>(this);
0110 }
0111
0112
0113
0114
0115 CLI11_NODISCARD const std::string &get_group() const { return group_; }
0116
0117
0118 CLI11_NODISCARD bool get_required() const { return required_; }
0119
0120
0121 CLI11_NODISCARD bool get_ignore_case() const { return ignore_case_; }
0122
0123
0124 CLI11_NODISCARD bool get_ignore_underscore() const { return ignore_underscore_; }
0125
0126
0127 CLI11_NODISCARD bool get_configurable() const { return configurable_; }
0128
0129
0130 CLI11_NODISCARD bool get_disable_flag_override() const { return disable_flag_override_; }
0131
0132
0133 CLI11_NODISCARD char get_delimiter() const { return delimiter_; }
0134
0135
0136 CLI11_NODISCARD bool get_always_capture_default() const { return always_capture_default_; }
0137
0138
0139 CLI11_NODISCARD MultiOptionPolicy get_multi_option_policy() const { return multi_option_policy_; }
0140
0141
0142
0143
0144 CRTP *take_last() {
0145 auto *self = static_cast<CRTP *>(this);
0146 self->multi_option_policy(MultiOptionPolicy::TakeLast);
0147 return self;
0148 }
0149
0150
0151 CRTP *take_first() {
0152 auto *self = static_cast<CRTP *>(this);
0153 self->multi_option_policy(MultiOptionPolicy::TakeFirst);
0154 return self;
0155 }
0156
0157
0158 CRTP *take_all() {
0159 auto self = static_cast<CRTP *>(this);
0160 self->multi_option_policy(MultiOptionPolicy::TakeAll);
0161 return self;
0162 }
0163
0164
0165 CRTP *join() {
0166 auto *self = static_cast<CRTP *>(this);
0167 self->multi_option_policy(MultiOptionPolicy::Join);
0168 return self;
0169 }
0170
0171
0172 CRTP *join(char delim) {
0173 auto self = static_cast<CRTP *>(this);
0174 self->delimiter_ = delim;
0175 self->multi_option_policy(MultiOptionPolicy::Join);
0176 return self;
0177 }
0178
0179
0180 CRTP *configurable(bool value = true) {
0181 configurable_ = value;
0182 return static_cast<CRTP *>(this);
0183 }
0184
0185
0186 CRTP *delimiter(char value = '\0') {
0187 delimiter_ = value;
0188 return static_cast<CRTP *>(this);
0189 }
0190 };
0191
0192
0193
0194 class OptionDefaults : public OptionBase<OptionDefaults> {
0195 public:
0196 OptionDefaults() = default;
0197
0198
0199
0200
0201 OptionDefaults *multi_option_policy(MultiOptionPolicy value = MultiOptionPolicy::Throw) {
0202 multi_option_policy_ = value;
0203 return this;
0204 }
0205
0206
0207 OptionDefaults *ignore_case(bool value = true) {
0208 ignore_case_ = value;
0209 return this;
0210 }
0211
0212
0213 OptionDefaults *ignore_underscore(bool value = true) {
0214 ignore_underscore_ = value;
0215 return this;
0216 }
0217
0218
0219 OptionDefaults *disable_flag_override(bool value = true) {
0220 disable_flag_override_ = value;
0221 return this;
0222 }
0223
0224
0225 OptionDefaults *delimiter(char value = '\0') {
0226 delimiter_ = value;
0227 return this;
0228 }
0229 };
0230
0231 class Option : public OptionBase<Option> {
0232 friend App;
0233
0234 protected:
0235
0236
0237
0238
0239 std::vector<std::string> snames_{};
0240
0241
0242 std::vector<std::string> lnames_{};
0243
0244
0245
0246 std::vector<std::pair<std::string, std::string>> default_flag_values_{};
0247
0248
0249 std::vector<std::string> fnames_{};
0250
0251
0252 std::string pname_{};
0253
0254
0255 std::string envname_{};
0256
0257
0258
0259
0260
0261
0262 std::string description_{};
0263
0264
0265 std::string default_str_{};
0266
0267
0268 std::string option_text_{};
0269
0270
0271
0272
0273 std::function<std::string()> type_name_{[]() { return std::string(); }};
0274
0275
0276 std::function<std::string()> default_function_{};
0277
0278
0279
0280
0281
0282
0283
0284 int type_size_max_{1};
0285
0286 int type_size_min_{1};
0287
0288
0289 int expected_min_{1};
0290
0291 int expected_max_{1};
0292
0293
0294 std::vector<Validator> validators_{};
0295
0296
0297 std::set<Option *> needs_{};
0298
0299
0300 std::set<Option *> excludes_{};
0301
0302
0303
0304
0305
0306
0307 App *parent_{nullptr};
0308
0309
0310 callback_t callback_{};
0311
0312
0313
0314
0315
0316
0317 results_t results_{};
0318
0319 results_t proc_results_{};
0320
0321 enum class option_state : char {
0322 parsing = 0,
0323 validated = 2,
0324 reduced = 4,
0325 callback_run = 6,
0326 };
0327
0328 option_state current_option_state_{option_state::parsing};
0329
0330 bool allow_extra_args_{false};
0331
0332 bool flag_like_{false};
0333
0334 bool run_callback_for_default_{false};
0335
0336 bool inject_separator_{false};
0337
0338 bool trigger_on_result_{false};
0339
0340 bool force_callback_{false};
0341
0342
0343
0344 Option(std::string option_name,
0345 std::string option_description,
0346 callback_t callback,
0347 App *parent,
0348 bool allow_non_standard = false)
0349 : description_(std::move(option_description)), parent_(parent), callback_(std::move(callback)) {
0350 std::tie(snames_, lnames_, pname_) = detail::get_names(detail::split_names(option_name), allow_non_standard);
0351 }
0352
0353 public:
0354
0355
0356
0357 Option(const Option &) = delete;
0358 Option &operator=(const Option &) = delete;
0359
0360
0361 CLI11_NODISCARD std::size_t count() const { return results_.size(); }
0362
0363
0364 CLI11_NODISCARD bool empty() const { return results_.empty(); }
0365
0366
0367 explicit operator bool() const { return !empty() || force_callback_; }
0368
0369
0370 void clear() {
0371 results_.clear();
0372 current_option_state_ = option_state::parsing;
0373 }
0374
0375
0376
0377
0378
0379
0380 Option *expected(int value);
0381
0382
0383 Option *expected(int value_min, int value_max);
0384
0385
0386
0387 Option *allow_extra_args(bool value = true) {
0388 allow_extra_args_ = value;
0389 return this;
0390 }
0391
0392 CLI11_NODISCARD bool get_allow_extra_args() const { return allow_extra_args_; }
0393
0394 Option *trigger_on_parse(bool value = true) {
0395 trigger_on_result_ = value;
0396 return this;
0397 }
0398
0399 CLI11_NODISCARD bool get_trigger_on_parse() const { return trigger_on_result_; }
0400
0401
0402 Option *force_callback(bool value = true) {
0403 force_callback_ = value;
0404 return this;
0405 }
0406
0407 CLI11_NODISCARD bool get_force_callback() const { return force_callback_; }
0408
0409
0410
0411 Option *run_callback_for_default(bool value = true) {
0412 run_callback_for_default_ = value;
0413 return this;
0414 }
0415
0416 CLI11_NODISCARD bool get_run_callback_for_default() const { return run_callback_for_default_; }
0417
0418
0419 Option *check(Validator validator, const std::string &validator_name = "");
0420
0421
0422 Option *check(std::function<std::string(const std::string &)> Validator,
0423 std::string Validator_description = "",
0424 std::string Validator_name = "");
0425
0426
0427 Option *transform(Validator Validator, const std::string &Validator_name = "");
0428
0429
0430 Option *transform(const std::function<std::string(std::string)> &func,
0431 std::string transform_description = "",
0432 std::string transform_name = "");
0433
0434
0435 Option *each(const std::function<void(std::string)> &func);
0436
0437
0438 Validator *get_validator(const std::string &Validator_name = "");
0439
0440
0441 Validator *get_validator(int index);
0442
0443
0444 Option *needs(Option *opt) {
0445 if(opt != this) {
0446 needs_.insert(opt);
0447 }
0448 return this;
0449 }
0450
0451
0452 template <typename T = App> Option *needs(std::string opt_name) {
0453 auto opt = static_cast<T *>(parent_)->get_option_no_throw(opt_name);
0454 if(opt == nullptr) {
0455 throw IncorrectConstruction::MissingOption(opt_name);
0456 }
0457 return needs(opt);
0458 }
0459
0460
0461 template <typename A, typename B, typename... ARG> Option *needs(A opt, B opt1, ARG... args) {
0462 needs(opt);
0463 return needs(opt1, args...);
0464 }
0465
0466
0467 bool remove_needs(Option *opt);
0468
0469
0470 Option *excludes(Option *opt);
0471
0472
0473 template <typename T = App> Option *excludes(std::string opt_name) {
0474 auto opt = static_cast<T *>(parent_)->get_option_no_throw(opt_name);
0475 if(opt == nullptr) {
0476 throw IncorrectConstruction::MissingOption(opt_name);
0477 }
0478 return excludes(opt);
0479 }
0480
0481
0482 template <typename A, typename B, typename... ARG> Option *excludes(A opt, B opt1, ARG... args) {
0483 excludes(opt);
0484 return excludes(opt1, args...);
0485 }
0486
0487
0488 bool remove_excludes(Option *opt);
0489
0490
0491 Option *envname(std::string name) {
0492 envname_ = std::move(name);
0493 return this;
0494 }
0495
0496
0497
0498
0499
0500 template <typename T = App> Option *ignore_case(bool value = true);
0501
0502
0503
0504
0505
0506 template <typename T = App> Option *ignore_underscore(bool value = true);
0507
0508
0509 Option *multi_option_policy(MultiOptionPolicy value = MultiOptionPolicy::Throw);
0510
0511
0512 Option *disable_flag_override(bool value = true) {
0513 disable_flag_override_ = value;
0514 return this;
0515 }
0516
0517
0518
0519
0520
0521 CLI11_NODISCARD int get_type_size() const { return type_size_min_; }
0522
0523
0524 CLI11_NODISCARD int get_type_size_min() const { return type_size_min_; }
0525
0526 CLI11_NODISCARD int get_type_size_max() const { return type_size_max_; }
0527
0528
0529 CLI11_NODISCARD bool get_inject_separator() const { return inject_separator_; }
0530
0531
0532 CLI11_NODISCARD std::string get_envname() const { return envname_; }
0533
0534
0535 CLI11_NODISCARD std::set<Option *> get_needs() const { return needs_; }
0536
0537
0538 CLI11_NODISCARD std::set<Option *> get_excludes() const { return excludes_; }
0539
0540
0541 CLI11_NODISCARD std::string get_default_str() const { return default_str_; }
0542
0543
0544 CLI11_NODISCARD callback_t get_callback() const { return callback_; }
0545
0546
0547 CLI11_NODISCARD const std::vector<std::string> &get_lnames() const { return lnames_; }
0548
0549
0550 CLI11_NODISCARD const std::vector<std::string> &get_snames() const { return snames_; }
0551
0552
0553 CLI11_NODISCARD const std::vector<std::string> &get_fnames() const { return fnames_; }
0554
0555 CLI11_NODISCARD const std::string &get_single_name() const {
0556 if(!lnames_.empty()) {
0557 return lnames_[0];
0558 }
0559 if(!snames_.empty()) {
0560 return snames_[0];
0561 }
0562 if(!pname_.empty()) {
0563 return pname_;
0564 }
0565 return envname_;
0566 }
0567
0568 CLI11_NODISCARD int get_expected() const { return expected_min_; }
0569
0570
0571 CLI11_NODISCARD int get_expected_min() const { return expected_min_; }
0572
0573 CLI11_NODISCARD int get_expected_max() const { return expected_max_; }
0574
0575
0576 CLI11_NODISCARD int get_items_expected_min() const { return type_size_min_ * expected_min_; }
0577
0578
0579 CLI11_NODISCARD int get_items_expected_max() const {
0580 int t = type_size_max_;
0581 return detail::checked_multiply(t, expected_max_) ? t : detail::expected_max_vector_size;
0582 }
0583
0584 CLI11_NODISCARD int get_items_expected() const { return get_items_expected_min(); }
0585
0586
0587 CLI11_NODISCARD bool get_positional() const { return !pname_.empty(); }
0588
0589
0590 CLI11_NODISCARD bool nonpositional() const { return (!lnames_.empty() || !snames_.empty()); }
0591
0592
0593 CLI11_NODISCARD bool has_description() const { return !description_.empty(); }
0594
0595
0596 CLI11_NODISCARD const std::string &get_description() const { return description_; }
0597
0598
0599 Option *description(std::string option_description) {
0600 description_ = std::move(option_description);
0601 return this;
0602 }
0603
0604 Option *option_text(std::string text) {
0605 option_text_ = std::move(text);
0606 return this;
0607 }
0608
0609 CLI11_NODISCARD const std::string &get_option_text() const { return option_text_; }
0610
0611
0612
0613
0614
0615
0616
0617
0618
0619 CLI11_NODISCARD std::string get_name(bool positional = false,
0620 bool all_options = false
0621 ) const;
0622
0623
0624
0625
0626
0627
0628 void run_callback();
0629
0630
0631 CLI11_NODISCARD const std::string &matching_name(const Option &other) const;
0632
0633
0634 bool operator==(const Option &other) const { return !matching_name(other).empty(); }
0635
0636
0637 CLI11_NODISCARD bool check_name(const std::string &name) const;
0638
0639
0640 CLI11_NODISCARD bool check_sname(std::string name) const {
0641 return (detail::find_member(std::move(name), snames_, ignore_case_) >= 0);
0642 }
0643
0644
0645 CLI11_NODISCARD bool check_lname(std::string name) const {
0646 return (detail::find_member(std::move(name), lnames_, ignore_case_, ignore_underscore_) >= 0);
0647 }
0648
0649
0650 CLI11_NODISCARD bool check_fname(std::string name) const {
0651 if(fnames_.empty()) {
0652 return false;
0653 }
0654 return (detail::find_member(std::move(name), fnames_, ignore_case_, ignore_underscore_) >= 0);
0655 }
0656
0657
0658
0659 CLI11_NODISCARD std::string get_flag_value(const std::string &name, std::string input_value) const;
0660
0661
0662 Option *add_result(std::string s);
0663
0664
0665 Option *add_result(std::string s, int &results_added);
0666
0667
0668 Option *add_result(std::vector<std::string> s);
0669
0670
0671 CLI11_NODISCARD const results_t &results() const { return results_; }
0672
0673
0674 CLI11_NODISCARD results_t reduced_results() const;
0675
0676
0677 template <typename T> void results(T &output) const {
0678 bool retval = false;
0679 if(current_option_state_ >= option_state::reduced || (results_.size() == 1 && validators_.empty())) {
0680 const results_t &res = (proc_results_.empty()) ? results_ : proc_results_;
0681 retval = detail::lexical_conversion<T, T>(res, output);
0682 } else {
0683 results_t res;
0684 if(results_.empty()) {
0685 if(!default_str_.empty()) {
0686
0687 _add_result(std::string(default_str_), res);
0688 _validate_results(res);
0689 results_t extra;
0690 _reduce_results(extra, res);
0691 if(!extra.empty()) {
0692 res = std::move(extra);
0693 }
0694 } else {
0695 res.emplace_back();
0696 }
0697 } else {
0698 res = reduced_results();
0699 }
0700 retval = detail::lexical_conversion<T, T>(res, output);
0701 }
0702 if(!retval) {
0703 throw ConversionError(get_name(), results_);
0704 }
0705 }
0706
0707
0708 template <typename T> CLI11_NODISCARD T as() const {
0709 T output;
0710 results(output);
0711 return output;
0712 }
0713
0714
0715 CLI11_NODISCARD bool get_callback_run() const { return (current_option_state_ == option_state::callback_run); }
0716
0717
0718
0719
0720
0721
0722 Option *type_name_fn(std::function<std::string()> typefun) {
0723 type_name_ = std::move(typefun);
0724 return this;
0725 }
0726
0727
0728 Option *type_name(std::string typeval) {
0729 type_name_fn([typeval]() { return typeval; });
0730 return this;
0731 }
0732
0733
0734 Option *type_size(int option_type_size);
0735
0736
0737 Option *type_size(int option_type_size_min, int option_type_size_max);
0738
0739
0740 void inject_separator(bool value = true) { inject_separator_ = value; }
0741
0742
0743 Option *default_function(const std::function<std::string()> &func) {
0744 default_function_ = func;
0745 return this;
0746 }
0747
0748
0749 Option *capture_default_str() {
0750 if(default_function_) {
0751 default_str_ = default_function_();
0752 }
0753 return this;
0754 }
0755
0756
0757 Option *default_str(std::string val) {
0758 default_str_ = std::move(val);
0759 return this;
0760 }
0761
0762
0763
0764 template <typename X> Option *default_val(const X &val) {
0765 std::string val_str = detail::to_string(val);
0766 auto old_option_state = current_option_state_;
0767 results_t old_results{std::move(results_)};
0768 results_.clear();
0769 try {
0770 add_result(val_str);
0771
0772 if(run_callback_for_default_ && !trigger_on_result_) {
0773 run_callback();
0774 current_option_state_ = option_state::parsing;
0775 } else {
0776 _validate_results(results_);
0777 current_option_state_ = old_option_state;
0778 }
0779 } catch(const ValidationError &err) {
0780
0781 results_ = std::move(old_results);
0782 current_option_state_ = old_option_state;
0783
0784 std::string alternate = detail::value_string(val);
0785 if(!alternate.empty() && alternate != val_str) {
0786 return default_val(alternate);
0787 }
0788
0789 throw ValidationError(get_name(),
0790 std::string("given default value does not pass validation :") + err.what());
0791 } catch(const ConversionError &err) {
0792
0793 results_ = std::move(old_results);
0794 current_option_state_ = old_option_state;
0795
0796 throw ConversionError(
0797 get_name(), std::string("given default value(\"") + val_str + "\") produces an error : " + err.what());
0798 } catch(const CLI::Error &) {
0799 results_ = std::move(old_results);
0800 current_option_state_ = old_option_state;
0801 throw;
0802 }
0803 results_ = std::move(old_results);
0804 default_str_ = std::move(val_str);
0805 return this;
0806 }
0807
0808
0809 CLI11_NODISCARD std::string get_type_name() const;
0810
0811 private:
0812
0813 void _validate_results(results_t &res) const;
0814
0815
0816
0817
0818 void _reduce_results(results_t &out, const results_t &original) const;
0819
0820
0821 std::string _validate(std::string &result, int index) const;
0822
0823
0824 int _add_result(std::string &&result, std::vector<std::string> &res) const;
0825 };
0826
0827
0828 }
0829
0830 #ifndef CLI11_COMPILE
0831 #include "impl/Option_inl.hpp" // IWYU pragma: export
0832 #endif