File indexing completed on 2025-07-05 08:51:43
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, std::string option_description, callback_t callback, App *parent)
0345 : description_(std::move(option_description)), parent_(parent), callback_(std::move(callback)) {
0346 std::tie(snames_, lnames_, pname_) = detail::get_names(detail::split_names(option_name));
0347 }
0348
0349 public:
0350
0351
0352
0353 Option(const Option &) = delete;
0354 Option &operator=(const Option &) = delete;
0355
0356
0357 CLI11_NODISCARD std::size_t count() const { return results_.size(); }
0358
0359
0360 CLI11_NODISCARD bool empty() const { return results_.empty(); }
0361
0362
0363 explicit operator bool() const { return !empty() || force_callback_; }
0364
0365
0366 void clear() {
0367 results_.clear();
0368 current_option_state_ = option_state::parsing;
0369 }
0370
0371
0372
0373
0374
0375
0376 Option *expected(int value);
0377
0378
0379 Option *expected(int value_min, int value_max);
0380
0381
0382
0383 Option *allow_extra_args(bool value = true) {
0384 allow_extra_args_ = value;
0385 return this;
0386 }
0387
0388 CLI11_NODISCARD bool get_allow_extra_args() const { return allow_extra_args_; }
0389
0390 Option *trigger_on_parse(bool value = true) {
0391 trigger_on_result_ = value;
0392 return this;
0393 }
0394
0395 CLI11_NODISCARD bool get_trigger_on_parse() const { return trigger_on_result_; }
0396
0397
0398 Option *force_callback(bool value = true) {
0399 force_callback_ = value;
0400 return this;
0401 }
0402
0403 CLI11_NODISCARD bool get_force_callback() const { return force_callback_; }
0404
0405
0406
0407 Option *run_callback_for_default(bool value = true) {
0408 run_callback_for_default_ = value;
0409 return this;
0410 }
0411
0412 CLI11_NODISCARD bool get_run_callback_for_default() const { return run_callback_for_default_; }
0413
0414
0415 Option *check(Validator validator, const std::string &validator_name = "");
0416
0417
0418 Option *check(std::function<std::string(const std::string &)> Validator,
0419 std::string Validator_description = "",
0420 std::string Validator_name = "");
0421
0422
0423 Option *transform(Validator Validator, const std::string &Validator_name = "");
0424
0425
0426 Option *transform(const std::function<std::string(std::string)> &func,
0427 std::string transform_description = "",
0428 std::string transform_name = "");
0429
0430
0431 Option *each(const std::function<void(std::string)> &func);
0432
0433
0434 Validator *get_validator(const std::string &Validator_name = "");
0435
0436
0437 Validator *get_validator(int index);
0438
0439
0440 Option *needs(Option *opt) {
0441 if(opt != this) {
0442 needs_.insert(opt);
0443 }
0444 return this;
0445 }
0446
0447
0448 template <typename T = App> Option *needs(std::string opt_name) {
0449 auto opt = static_cast<T *>(parent_)->get_option_no_throw(opt_name);
0450 if(opt == nullptr) {
0451 throw IncorrectConstruction::MissingOption(opt_name);
0452 }
0453 return needs(opt);
0454 }
0455
0456
0457 template <typename A, typename B, typename... ARG> Option *needs(A opt, B opt1, ARG... args) {
0458 needs(opt);
0459 return needs(opt1, args...);
0460 }
0461
0462
0463 bool remove_needs(Option *opt);
0464
0465
0466 Option *excludes(Option *opt);
0467
0468
0469 template <typename T = App> Option *excludes(std::string opt_name) {
0470 auto opt = static_cast<T *>(parent_)->get_option_no_throw(opt_name);
0471 if(opt == nullptr) {
0472 throw IncorrectConstruction::MissingOption(opt_name);
0473 }
0474 return excludes(opt);
0475 }
0476
0477
0478 template <typename A, typename B, typename... ARG> Option *excludes(A opt, B opt1, ARG... args) {
0479 excludes(opt);
0480 return excludes(opt1, args...);
0481 }
0482
0483
0484 bool remove_excludes(Option *opt);
0485
0486
0487 Option *envname(std::string name) {
0488 envname_ = std::move(name);
0489 return this;
0490 }
0491
0492
0493
0494
0495
0496 template <typename T = App> Option *ignore_case(bool value = true);
0497
0498
0499
0500
0501
0502 template <typename T = App> Option *ignore_underscore(bool value = true);
0503
0504
0505 Option *multi_option_policy(MultiOptionPolicy value = MultiOptionPolicy::Throw);
0506
0507
0508 Option *disable_flag_override(bool value = true) {
0509 disable_flag_override_ = value;
0510 return this;
0511 }
0512
0513
0514
0515
0516
0517 CLI11_NODISCARD int get_type_size() const { return type_size_min_; }
0518
0519
0520 CLI11_NODISCARD int get_type_size_min() const { return type_size_min_; }
0521
0522 CLI11_NODISCARD int get_type_size_max() const { return type_size_max_; }
0523
0524
0525 CLI11_NODISCARD bool get_inject_separator() const { return inject_separator_; }
0526
0527
0528 CLI11_NODISCARD std::string get_envname() const { return envname_; }
0529
0530
0531 CLI11_NODISCARD std::set<Option *> get_needs() const { return needs_; }
0532
0533
0534 CLI11_NODISCARD std::set<Option *> get_excludes() const { return excludes_; }
0535
0536
0537 CLI11_NODISCARD std::string get_default_str() const { return default_str_; }
0538
0539
0540 CLI11_NODISCARD callback_t get_callback() const { return callback_; }
0541
0542
0543 CLI11_NODISCARD const std::vector<std::string> &get_lnames() const { return lnames_; }
0544
0545
0546 CLI11_NODISCARD const std::vector<std::string> &get_snames() const { return snames_; }
0547
0548
0549 CLI11_NODISCARD const std::vector<std::string> &get_fnames() const { return fnames_; }
0550
0551 CLI11_NODISCARD const std::string &get_single_name() const {
0552 if(!lnames_.empty()) {
0553 return lnames_[0];
0554 }
0555 if(!snames_.empty()) {
0556 return snames_[0];
0557 }
0558 if(!pname_.empty()) {
0559 return pname_;
0560 }
0561 return envname_;
0562 }
0563
0564 CLI11_NODISCARD int get_expected() const { return expected_min_; }
0565
0566
0567 CLI11_NODISCARD int get_expected_min() const { return expected_min_; }
0568
0569 CLI11_NODISCARD int get_expected_max() const { return expected_max_; }
0570
0571
0572 CLI11_NODISCARD int get_items_expected_min() const { return type_size_min_ * expected_min_; }
0573
0574
0575 CLI11_NODISCARD int get_items_expected_max() const {
0576 int t = type_size_max_;
0577 return detail::checked_multiply(t, expected_max_) ? t : detail::expected_max_vector_size;
0578 }
0579
0580 CLI11_NODISCARD int get_items_expected() const { return get_items_expected_min(); }
0581
0582
0583 CLI11_NODISCARD bool get_positional() const { return !pname_.empty(); }
0584
0585
0586 CLI11_NODISCARD bool nonpositional() const { return (!lnames_.empty() || !snames_.empty()); }
0587
0588
0589 CLI11_NODISCARD bool has_description() const { return !description_.empty(); }
0590
0591
0592 CLI11_NODISCARD const std::string &get_description() const { return description_; }
0593
0594
0595 Option *description(std::string option_description) {
0596 description_ = std::move(option_description);
0597 return this;
0598 }
0599
0600 Option *option_text(std::string text) {
0601 option_text_ = std::move(text);
0602 return this;
0603 }
0604
0605 CLI11_NODISCARD const std::string &get_option_text() const { return option_text_; }
0606
0607
0608
0609
0610
0611
0612
0613
0614
0615 CLI11_NODISCARD std::string get_name(bool positional = false,
0616 bool all_options = false
0617 ) const;
0618
0619
0620
0621
0622
0623
0624 void run_callback();
0625
0626
0627 CLI11_NODISCARD const std::string &matching_name(const Option &other) const;
0628
0629
0630 bool operator==(const Option &other) const { return !matching_name(other).empty(); }
0631
0632
0633 CLI11_NODISCARD bool check_name(const std::string &name) const;
0634
0635
0636 CLI11_NODISCARD bool check_sname(std::string name) const {
0637 return (detail::find_member(std::move(name), snames_, ignore_case_) >= 0);
0638 }
0639
0640
0641 CLI11_NODISCARD bool check_lname(std::string name) const {
0642 return (detail::find_member(std::move(name), lnames_, ignore_case_, ignore_underscore_) >= 0);
0643 }
0644
0645
0646 CLI11_NODISCARD bool check_fname(std::string name) const {
0647 if(fnames_.empty()) {
0648 return false;
0649 }
0650 return (detail::find_member(std::move(name), fnames_, ignore_case_, ignore_underscore_) >= 0);
0651 }
0652
0653
0654
0655 CLI11_NODISCARD std::string get_flag_value(const std::string &name, std::string input_value) const;
0656
0657
0658 Option *add_result(std::string s);
0659
0660
0661 Option *add_result(std::string s, int &results_added);
0662
0663
0664 Option *add_result(std::vector<std::string> s);
0665
0666
0667 CLI11_NODISCARD const results_t &results() const { return results_; }
0668
0669
0670 CLI11_NODISCARD results_t reduced_results() const;
0671
0672
0673 template <typename T> void results(T &output) const {
0674 bool retval = false;
0675 if(current_option_state_ >= option_state::reduced || (results_.size() == 1 && validators_.empty())) {
0676 const results_t &res = (proc_results_.empty()) ? results_ : proc_results_;
0677 retval = detail::lexical_conversion<T, T>(res, output);
0678 } else {
0679 results_t res;
0680 if(results_.empty()) {
0681 if(!default_str_.empty()) {
0682
0683 _add_result(std::string(default_str_), res);
0684 _validate_results(res);
0685 results_t extra;
0686 _reduce_results(extra, res);
0687 if(!extra.empty()) {
0688 res = std::move(extra);
0689 }
0690 } else {
0691 res.emplace_back();
0692 }
0693 } else {
0694 res = reduced_results();
0695 }
0696 retval = detail::lexical_conversion<T, T>(res, output);
0697 }
0698 if(!retval) {
0699 throw ConversionError(get_name(), results_);
0700 }
0701 }
0702
0703
0704 template <typename T> CLI11_NODISCARD T as() const {
0705 T output;
0706 results(output);
0707 return output;
0708 }
0709
0710
0711 CLI11_NODISCARD bool get_callback_run() const { return (current_option_state_ == option_state::callback_run); }
0712
0713
0714
0715
0716
0717
0718 Option *type_name_fn(std::function<std::string()> typefun) {
0719 type_name_ = std::move(typefun);
0720 return this;
0721 }
0722
0723
0724 Option *type_name(std::string typeval) {
0725 type_name_fn([typeval]() { return typeval; });
0726 return this;
0727 }
0728
0729
0730 Option *type_size(int option_type_size);
0731
0732
0733 Option *type_size(int option_type_size_min, int option_type_size_max);
0734
0735
0736 void inject_separator(bool value = true) { inject_separator_ = value; }
0737
0738
0739 Option *default_function(const std::function<std::string()> &func) {
0740 default_function_ = func;
0741 return this;
0742 }
0743
0744
0745 Option *capture_default_str() {
0746 if(default_function_) {
0747 default_str_ = default_function_();
0748 }
0749 return this;
0750 }
0751
0752
0753 Option *default_str(std::string val) {
0754 default_str_ = std::move(val);
0755 return this;
0756 }
0757
0758
0759
0760 template <typename X> Option *default_val(const X &val) {
0761 std::string val_str = detail::to_string(val);
0762 auto old_option_state = current_option_state_;
0763 results_t old_results{std::move(results_)};
0764 results_.clear();
0765 try {
0766 add_result(val_str);
0767
0768 if(run_callback_for_default_ && !trigger_on_result_) {
0769 run_callback();
0770 current_option_state_ = option_state::parsing;
0771 } else {
0772 _validate_results(results_);
0773 current_option_state_ = old_option_state;
0774 }
0775 } catch(const CLI::Error &) {
0776
0777 results_ = std::move(old_results);
0778 current_option_state_ = old_option_state;
0779 throw;
0780 }
0781 results_ = std::move(old_results);
0782 default_str_ = std::move(val_str);
0783 return this;
0784 }
0785
0786
0787 CLI11_NODISCARD std::string get_type_name() const;
0788
0789 private:
0790
0791 void _validate_results(results_t &res) const;
0792
0793
0794
0795
0796 void _reduce_results(results_t &out, const results_t &original) const;
0797
0798
0799 std::string _validate(std::string &result, int index) const;
0800
0801
0802 int _add_result(std::string &&result, std::vector<std::string> &res) const;
0803 };
0804
0805
0806 }
0807
0808 #ifndef CLI11_COMPILE
0809 #include "impl/Option_inl.hpp" // IWYU pragma: export
0810 #endif