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