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