CLI11 2.2.0
Loading...
Searching...
No Matches
Option.hpp
Go to the documentation of this file.
1// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner
2// under NSF AWARD 1414736 and by the respective contributors.
3// All rights reserved.
4//
5// SPDX-License-Identifier: BSD-3-Clause
6
7#pragma once
8
9// [CLI11:public_includes:set]
10#include <algorithm>
11#include <functional>
12#include <memory>
13#include <set>
14#include <string>
15#include <tuple>
16#include <utility>
17#include <vector>
18// [CLI11:public_includes:end]
19
20#include "Error.hpp"
21#include "Macros.hpp"
22#include "Split.hpp"
23#include "StringTools.hpp"
24#include "Validators.hpp"
25
26namespace CLI {
27// [CLI11:option_hpp:verbatim]
28
29using results_t = std::vector<std::string>;
31using callback_t = std::function<bool(const results_t &)>;
32
33class Option;
34class App;
35
36using Option_p = std::unique_ptr<Option>;
38enum class MultiOptionPolicy : char {
39 Throw,
40 TakeLast,
41 TakeFirst,
42 Join,
43 TakeAll,
44 Sum
45};
46
49template <typename CRTP> class OptionBase {
50 friend App;
51
52 protected:
54 std::string group_ = std::string("Options");
55
57 bool required_{false};
58
60 bool ignore_case_{false};
61
63 bool ignore_underscore_{false};
64
66 bool configurable_{true};
67
70
72 char delimiter_{'\0'};
73
76
79
81 template <typename T> void copy_to(T *other) const {
82 other->group(group_);
83 other->required(required_);
84 other->ignore_case(ignore_case_);
85 other->ignore_underscore(ignore_underscore_);
86 other->configurable(configurable_);
87 other->disable_flag_override(disable_flag_override_);
88 other->delimiter(delimiter_);
89 other->always_capture_default(always_capture_default_);
90 other->multi_option_policy(multi_option_policy_);
91 }
92
93 public:
94 // setters
95
97 CRTP *group(const std::string &name) {
99 throw IncorrectConstruction("Group names may not contain newlines or null characters");
100 }
101 group_ = name;
102 return static_cast<CRTP *>(this);
103 }
104
106 CRTP *required(bool value = true) {
107 required_ = value;
108 return static_cast<CRTP *>(this);
109 }
110
112 CRTP *mandatory(bool value = true) { return required(value); }
113
114 CRTP *always_capture_default(bool value = true) {
116 return static_cast<CRTP *>(this);
117 }
118
119 // Getters
120
122 const std::string &get_group() const { return group_; }
123
125 bool get_required() const { return required_; }
126
128 bool get_ignore_case() const { return ignore_case_; }
129
132
134 bool get_configurable() const { return configurable_; }
135
138
140 char get_delimiter() const { return delimiter_; }
141
144
147
148 // Shortcuts for multi option policy
149
151 CRTP *take_last() {
152 auto self = static_cast<CRTP *>(this);
153 self->multi_option_policy(MultiOptionPolicy::TakeLast);
154 return self;
155 }
156
158 CRTP *take_first() {
159 auto self = static_cast<CRTP *>(this);
160 self->multi_option_policy(MultiOptionPolicy::TakeFirst);
161 return self;
162 }
163
165 CRTP *take_all() {
166 auto self = static_cast<CRTP *>(this);
167 self->multi_option_policy(MultiOptionPolicy::TakeAll);
168 return self;
169 }
170
172 CRTP *join() {
173 auto self = static_cast<CRTP *>(this);
174 self->multi_option_policy(MultiOptionPolicy::Join);
175 return self;
176 }
177
179 CRTP *join(char delim) {
180 auto self = static_cast<CRTP *>(this);
181 self->delimiter_ = delim;
182 self->multi_option_policy(MultiOptionPolicy::Join);
183 return self;
184 }
185
187 CRTP *configurable(bool value = true) {
188 configurable_ = value;
189 return static_cast<CRTP *>(this);
190 }
191
193 CRTP *delimiter(char value = '\0') {
194 delimiter_ = value;
195 return static_cast<CRTP *>(this);
196 }
197};
198
201class OptionDefaults : public OptionBase<OptionDefaults> {
202 public:
203 OptionDefaults() = default;
204
205 // Methods here need a different implementation if they are Option vs. OptionDefault
206
212
214 OptionDefaults *ignore_case(bool value = true) {
215 ignore_case_ = value;
216 return this;
217 }
218
220 OptionDefaults *ignore_underscore(bool value = true) {
221 ignore_underscore_ = value;
222 return this;
223 }
224
228 return this;
229 }
230
232 OptionDefaults *delimiter(char value = '\0') {
233 delimiter_ = value;
234 return this;
235 }
236};
237
238class Option : public OptionBase<Option> {
239 friend App;
240
241 protected:
244
246 std::vector<std::string> snames_{};
247
249 std::vector<std::string> lnames_{};
250
253 std::vector<std::pair<std::string, std::string>> default_flag_values_{};
254
256 std::vector<std::string> fnames_{};
257
259 std::string pname_{};
260
262 std::string envname_{};
263
267
269 std::string description_{};
270
272 std::string default_str_{};
273
275 std::string option_text_{};
276
280 std::function<std::string()> type_name_{[]() { return std::string(); }};
281
283 std::function<std::string()> default_function_{};
284
288
294
299
301 std::vector<Validator> validators_{};
302
304 std::set<Option *> needs_{};
305
307 std::set<Option *> excludes_{};
308
312
314 App *parent_{nullptr};
315
318
322
328 enum class option_state : char {
329 parsing = 0,
330 validated = 2,
331 reduced = 4,
332 callback_run = 6,
333 };
337 bool allow_extra_args_{false};
339 bool flag_like_{false};
343 bool inject_separator_{false};
347 bool force_callback_{false};
349
351 Option(std::string option_name, std::string option_description, callback_t callback, App *parent)
352 : description_(std::move(option_description)), parent_(parent), callback_(std::move(callback)) {
353 std::tie(snames_, lnames_, pname_) = detail::get_names(detail::split_names(option_name));
354 }
355
356 public:
359
360 Option(const Option &) = delete;
361 Option &operator=(const Option &) = delete;
362
364 std::size_t count() const { return results_.size(); }
365
367 bool empty() const { return results_.empty(); }
368
370 explicit operator bool() const { return !empty() || force_callback_; }
371
373 void clear() {
374 results_.clear();
376 }
377
381
383 Option *expected(int value) {
384 if(value < 0) {
385 expected_min_ = -value;
388 }
389 allow_extra_args_ = true;
390 flag_like_ = false;
391 } else if(value == detail::expected_max_vector_size) {
392 expected_min_ = 1;
394 allow_extra_args_ = true;
395 flag_like_ = false;
396 } else {
397 expected_min_ = value;
398 expected_max_ = value;
399 flag_like_ = (expected_min_ == 0);
400 }
401 return this;
402 }
403
405 Option *expected(int value_min, int value_max) {
406 if(value_min < 0) {
407 value_min = -value_min;
408 }
409
410 if(value_max < 0) {
412 }
413 if(value_max < value_min) {
414 expected_min_ = value_max;
415 expected_max_ = value_min;
416 } else {
417 expected_max_ = value_max;
418 expected_min_ = value_min;
419 }
420
421 return this;
422 }
425 Option *allow_extra_args(bool value = true) {
426 allow_extra_args_ = value;
427 return this;
428 }
432 Option *trigger_on_parse(bool value = true) {
433 trigger_on_result_ = value;
434 return this;
435 }
438
440 Option *force_callback(bool value = true) {
441 force_callback_ = value;
442 return this;
443 }
445 bool get_force_callback() const { return force_callback_; }
446
449 Option *run_callback_for_default(bool value = true) {
451 return this;
452 }
455
457 Option *check(Validator validator, const std::string &validator_name = "") {
458 validator.non_modifying();
459 validators_.push_back(std::move(validator));
460 if(!validator_name.empty())
461 validators_.back().name(validator_name);
462 return this;
463 }
464
466 Option *check(std::function<std::string(const std::string &)> Validator,
467 std::string Validator_description = "",
468 std::string Validator_name = "") {
469 validators_.emplace_back(Validator, std::move(Validator_description), std::move(Validator_name));
470 validators_.back().non_modifying();
471 return this;
472 }
473
475 Option *transform(Validator Validator, const std::string &Validator_name = "") {
476 validators_.insert(validators_.begin(), std::move(Validator));
477 if(!Validator_name.empty())
478 validators_.front().name(Validator_name);
479 return this;
480 }
481
483 Option *transform(const std::function<std::string(std::string)> &func,
484 std::string transform_description = "",
485 std::string transform_name = "") {
486 validators_.insert(validators_.begin(),
487 Validator(
488 [func](std::string &val) {
489 val = func(val);
490 return std::string{};
491 },
492 std::move(transform_description),
493 std::move(transform_name)));
494
495 return this;
496 }
497
499 Option *each(const std::function<void(std::string)> &func) {
500 validators_.emplace_back(
501 [func](std::string &inout) {
502 func(inout);
503 return std::string{};
504 },
505 std::string{});
506 return this;
507 }
509 Validator *get_validator(const std::string &Validator_name = "") {
510 for(auto &Validator : validators_) {
511 if(Validator_name == Validator.get_name()) {
512 return &Validator;
513 }
514 }
515 if((Validator_name.empty()) && (!validators_.empty())) {
516 return &(validators_.front());
517 }
518 throw OptionNotFound(std::string{"Validator "} + Validator_name + " Not Found");
519 }
520
523 // This is an signed int so that it is not equivalent to a pointer.
524 if(index >= 0 && index < static_cast<int>(validators_.size())) {
525 return &(validators_[static_cast<decltype(validators_)::size_type>(index)]);
526 }
527 throw OptionNotFound("Validator index is not valid");
528 }
529
532 if(opt != this) {
533 needs_.insert(opt);
534 }
535 return this;
536 }
537
539 template <typename T = App> Option *needs(std::string opt_name) {
540 auto opt = static_cast<T *>(parent_)->get_option_no_throw(opt_name);
541 if(opt == nullptr) {
542 throw IncorrectConstruction::MissingOption(opt_name);
543 }
544 return needs(opt);
545 }
546
548 template <typename A, typename B, typename... ARG> Option *needs(A opt, B opt1, ARG... args) {
549 needs(opt);
550 return needs(opt1, args...);
551 }
552
554 bool remove_needs(Option *opt) {
555 auto iterator = std::find(std::begin(needs_), std::end(needs_), opt);
556
557 if(iterator == std::end(needs_)) {
558 return false;
559 }
560 needs_.erase(iterator);
561 return true;
562 }
563
566 if(opt == this) {
567 throw(IncorrectConstruction("and option cannot exclude itself"));
568 }
569 excludes_.insert(opt);
570
571 // Help text should be symmetric - excluding a should exclude b
572 opt->excludes_.insert(this);
573
574 // Ignoring the insert return value, excluding twice is now allowed.
575 // (Mostly to allow both directions to be excluded by user, even though the library does it for you.)
576
577 return this;
578 }
579
581 template <typename T = App> Option *excludes(std::string opt_name) {
582 auto opt = static_cast<T *>(parent_)->get_option_no_throw(opt_name);
583 if(opt == nullptr) {
584 throw IncorrectConstruction::MissingOption(opt_name);
585 }
586 return excludes(opt);
587 }
588
590 template <typename A, typename B, typename... ARG> Option *excludes(A opt, B opt1, ARG... args) {
591 excludes(opt);
592 return excludes(opt1, args...);
593 }
594
597 auto iterator = std::find(std::begin(excludes_), std::end(excludes_), opt);
598
599 if(iterator == std::end(excludes_)) {
600 return false;
601 }
602 excludes_.erase(iterator);
603 return true;
604 }
605
607 Option *envname(std::string name) {
608 envname_ = std::move(name);
609 return this;
610 }
611
616 template <typename T = App> Option *ignore_case(bool value = true) {
617 if(!ignore_case_ && value) {
618 ignore_case_ = value;
619 auto *parent = static_cast<T *>(parent_);
620 for(const Option_p &opt : parent->options_) {
621 if(opt.get() == this) {
622 continue;
623 }
624 auto &omatch = opt->matching_name(*this);
625 if(!omatch.empty()) {
626 ignore_case_ = false;
627 throw OptionAlreadyAdded("adding ignore case caused a name conflict with " + omatch);
628 }
629 }
630 } else {
631 ignore_case_ = value;
632 }
633 return this;
634 }
635
640 template <typename T = App> Option *ignore_underscore(bool value = true) {
641
642 if(!ignore_underscore_ && value) {
643 ignore_underscore_ = value;
644 auto *parent = static_cast<T *>(parent_);
645 for(const Option_p &opt : parent->options_) {
646 if(opt.get() == this) {
647 continue;
648 }
649 auto &omatch = opt->matching_name(*this);
650 if(!omatch.empty()) {
651 ignore_underscore_ = false;
652 throw OptionAlreadyAdded("adding ignore underscore caused a name conflict with " + omatch);
653 }
654 }
655 } else {
656 ignore_underscore_ = value;
657 }
658 return this;
659 }
660
663 if(value != multi_option_policy_) {
665 expected_min_ > 1) { // this bizarre condition is to maintain backwards compatibility
666 // with the previous behavior of expected_ with vectors
668 }
669 multi_option_policy_ = value;
671 }
672 return this;
673 }
674
676 Option *disable_flag_override(bool value = true) {
678 return this;
679 }
683
685 int get_type_size() const { return type_size_min_; }
686
688 int get_type_size_min() const { return type_size_min_; }
690 int get_type_size_max() const { return type_size_max_; }
691
694
696 std::string get_envname() const { return envname_; }
697
699 std::set<Option *> get_needs() const { return needs_; }
700
702 std::set<Option *> get_excludes() const { return excludes_; }
703
705 std::string get_default_str() const { return default_str_; }
706
709
711 const std::vector<std::string> &get_lnames() const { return lnames_; }
712
714 const std::vector<std::string> &get_snames() const { return snames_; }
715
717 const std::vector<std::string> &get_fnames() const { return fnames_; }
719 const std::string &get_single_name() const {
720 if(!lnames_.empty()) {
721 return lnames_[0];
722 }
723 if(!pname_.empty()) {
724 return pname_;
725 }
726 if(!snames_.empty()) {
727 return snames_[0];
728 }
729 return envname_;
730 }
732 int get_expected() const { return expected_min_; }
733
735 int get_expected_min() const { return expected_min_; }
737 int get_expected_max() const { return expected_max_; }
738
741
749
751 bool get_positional() const { return pname_.length() > 0; }
752
754 bool nonpositional() const { return (snames_.size() + lnames_.size()) > 0; }
755
757 bool has_description() const { return description_.length() > 0; }
758
760 const std::string &get_description() const { return description_; }
761
763 Option *description(std::string option_description) {
764 description_ = std::move(option_description);
765 return this;
766 }
767
768 Option *option_text(std::string text) {
769 option_text_ = std::move(text);
770 return this;
771 }
772
773 const std::string &get_option_text() const { return option_text_; }
774
778
783 std::string get_name(bool positional = false,
784 bool all_options = false
785 ) const {
786 if(get_group().empty())
787 return {}; // Hidden
788
789 if(all_options) {
790
791 std::vector<std::string> name_list;
792
794 if((positional && (!pname_.empty())) || (snames_.empty() && lnames_.empty())) {
795 name_list.push_back(pname_);
796 }
797 if((get_items_expected() == 0) && (!fnames_.empty())) {
798 for(const std::string &sname : snames_) {
799 name_list.push_back("-" + sname);
800 if(check_fname(sname)) {
801 name_list.back() += "{" + get_flag_value(sname, "") + "}";
802 }
803 }
804
805 for(const std::string &lname : lnames_) {
806 name_list.push_back("--" + lname);
807 if(check_fname(lname)) {
808 name_list.back() += "{" + get_flag_value(lname, "") + "}";
809 }
810 }
811 } else {
812 for(const std::string &sname : snames_)
813 name_list.push_back("-" + sname);
814
815 for(const std::string &lname : lnames_)
816 name_list.push_back("--" + lname);
817 }
818
819 return detail::join(name_list);
820 }
821
822 // This returns the positional name no matter what
823 if(positional)
824 return pname_;
825
826 // Prefer long name
827 if(!lnames_.empty())
828 return std::string(2, '-') + lnames_[0];
829
830 // Or short name if no long name
831 if(!snames_.empty())
832 return std::string(1, '-') + snames_[0];
833
834 // If positional is the only name, it's okay to use that
835 return pname_;
836 }
837
841
844 if(force_callback_ && results_.empty()) {
846 }
848 _validate_results(results_);
850 }
851
853 _reduce_results(proc_results_, results_);
855 }
858 if(!(callback_)) {
859 return;
860 }
861 const results_t &send_results = proc_results_.empty() ? results_ : proc_results_;
862 bool local_result = callback_(send_results);
863
864 if(!local_result)
866 }
867 }
868
870 const std::string &matching_name(const Option &other) const {
871 static const std::string estring;
872 for(const std::string &sname : snames_)
873 if(other.check_sname(sname))
874 return sname;
875 for(const std::string &lname : lnames_)
876 if(other.check_lname(lname))
877 return lname;
878
879 if(ignore_case_ ||
880 ignore_underscore_) { // We need to do the inverse, in case we are ignore_case or ignore underscore
881 for(const std::string &sname : other.snames_)
882 if(check_sname(sname))
883 return sname;
884 for(const std::string &lname : other.lnames_)
885 if(check_lname(lname))
886 return lname;
887 }
888 return estring;
889 }
891 bool operator==(const Option &other) const { return !matching_name(other).empty(); }
892
894 bool check_name(const std::string &name) const {
895
896 if(name.length() > 2 && name[0] == '-' && name[1] == '-')
897 return check_lname(name.substr(2));
898 if(name.length() > 1 && name.front() == '-')
899 return check_sname(name.substr(1));
900 if(!pname_.empty()) {
901 std::string local_pname = pname_;
902 std::string local_name = name;
904 local_pname = detail::remove_underscore(local_pname);
905 local_name = detail::remove_underscore(local_name);
906 }
907 if(ignore_case_) {
908 local_pname = detail::to_lower(local_pname);
909 local_name = detail::to_lower(local_name);
910 }
911 if(local_name == local_pname) {
912 return true;
913 }
914 }
915
916 if(!envname_.empty()) {
917 // this needs to be the original since envname_ shouldn't match on case insensitivity
918 return (name == envname_);
919 }
920 return false;
921 }
922
924 bool check_sname(std::string name) const {
925 return (detail::find_member(std::move(name), snames_, ignore_case_) >= 0);
926 }
927
929 bool check_lname(std::string name) const {
930 return (detail::find_member(std::move(name), lnames_, ignore_case_, ignore_underscore_) >= 0);
931 }
932
934 bool check_fname(std::string name) const {
935 if(fnames_.empty()) {
936 return false;
937 }
938 return (detail::find_member(std::move(name), fnames_, ignore_case_, ignore_underscore_) >= 0);
939 }
940
943 std::string get_flag_value(const std::string &name, std::string input_value) const {
944 static const std::string trueString{"true"};
945 static const std::string falseString{"false"};
946 static const std::string emptyString{"{}"};
947 // check for disable flag override_
949 if(!((input_value.empty()) || (input_value == emptyString))) {
951 if(default_ind >= 0) {
952 // We can static cast this to std::size_t because it is more than 0 in this block
953 if(default_flag_values_[static_cast<std::size_t>(default_ind)].second != input_value) {
954 throw(ArgumentMismatch::FlagOverride(name));
955 }
956 } else {
957 if(input_value != trueString) {
958 throw(ArgumentMismatch::FlagOverride(name));
959 }
960 }
961 }
962 }
964 if((input_value.empty()) || (input_value == emptyString)) {
965 if(flag_like_) {
966 return (ind < 0) ? trueString : default_flag_values_[static_cast<std::size_t>(ind)].second;
967 } else {
968 return (ind < 0) ? default_str_ : default_flag_values_[static_cast<std::size_t>(ind)].second;
969 }
970 }
971 if(ind < 0) {
972 return input_value;
973 }
974 if(default_flag_values_[static_cast<std::size_t>(ind)].second == falseString) {
975 try {
976 auto val = detail::to_flag_value(input_value);
977 return (val == 1) ? falseString : (val == (-1) ? trueString : std::to_string(-val));
978 } catch(const std::invalid_argument &) {
979 return input_value;
980 }
981 } else {
982 return input_value;
983 }
984 }
985
987 Option *add_result(std::string s) {
988 _add_result(std::move(s), results_);
990 return this;
991 }
992
994 Option *add_result(std::string s, int &results_added) {
995 results_added = _add_result(std::move(s), results_);
997 return this;
998 }
999
1001 Option *add_result(std::vector<std::string> s) {
1003 for(auto &str : s) {
1004 _add_result(std::move(str), results_);
1005 }
1006 return this;
1007 }
1008
1010 const results_t &results() const { return results_; }
1011
1017 res = results_;
1018 _validate_results(res);
1019 }
1020 if(!res.empty()) {
1021 results_t extra;
1022 _reduce_results(extra, res);
1023 if(!extra.empty()) {
1024 res = std::move(extra);
1025 }
1026 }
1027 }
1028 return res;
1029 }
1030
1032 template <typename T> void results(T &output) const {
1033 bool retval;
1034 if(current_option_state_ >= option_state::reduced || (results_.size() == 1 && validators_.empty())) {
1035 const results_t &res = (proc_results_.empty()) ? results_ : proc_results_;
1036 retval = detail::lexical_conversion<T, T>(res, output);
1037 } else {
1038 results_t res;
1039 if(results_.empty()) {
1040 if(!default_str_.empty()) {
1041 // _add_results takes an rvalue only
1042 _add_result(std::string(default_str_), res);
1043 _validate_results(res);
1044 results_t extra;
1045 _reduce_results(extra, res);
1046 if(!extra.empty()) {
1047 res = std::move(extra);
1048 }
1049 } else {
1050 res.emplace_back();
1051 }
1052 } else {
1053 res = reduced_results();
1054 }
1055 retval = detail::lexical_conversion<T, T>(res, output);
1056 }
1057 if(!retval) {
1059 }
1060 }
1061
1063 template <typename T> T as() const {
1064 T output;
1065 results(output);
1066 return output;
1067 }
1068
1071
1075
1077 Option *type_name_fn(std::function<std::string()> typefun) {
1078 type_name_ = std::move(typefun);
1079 return this;
1080 }
1081
1083 Option *type_name(std::string typeval) {
1084 type_name_fn([typeval]() { return typeval; });
1085 return this;
1086 }
1087
1089 Option *type_size(int option_type_size) {
1090 if(option_type_size < 0) {
1091 // this section is included for backwards compatibility
1092 type_size_max_ = -option_type_size;
1093 type_size_min_ = -option_type_size;
1095 } else {
1096 type_size_max_ = option_type_size;
1098 type_size_min_ = option_type_size;
1099 } else {
1100 inject_separator_ = true;
1101 }
1102 if(type_size_max_ == 0)
1103 required_ = false;
1104 }
1105 return this;
1106 }
1108 Option *type_size(int option_type_size_min, int option_type_size_max) {
1109 if(option_type_size_min < 0 || option_type_size_max < 0) {
1110 // this section is included for backwards compatibility
1112 option_type_size_min = (std::abs)(option_type_size_min);
1113 option_type_size_max = (std::abs)(option_type_size_max);
1114 }
1115
1116 if(option_type_size_min > option_type_size_max) {
1117 type_size_max_ = option_type_size_min;
1118 type_size_min_ = option_type_size_max;
1119 } else {
1120 type_size_min_ = option_type_size_min;
1121 type_size_max_ = option_type_size_max;
1122 }
1123 if(type_size_max_ == 0) {
1124 required_ = false;
1125 }
1127 inject_separator_ = true;
1128 }
1129 return this;
1130 }
1131
1133 void inject_separator(bool value = true) { inject_separator_ = value; }
1134
1136 Option *default_function(const std::function<std::string()> &func) {
1137 default_function_ = func;
1138 return this;
1139 }
1140
1143 if(default_function_) {
1145 }
1146 return this;
1147 }
1148
1150 Option *default_str(std::string val) {
1151 default_str_ = std::move(val);
1152 return this;
1153 }
1154
1157 template <typename X> Option *default_val(const X &val) {
1158 std::string val_str = detail::to_string(val);
1159 auto old_option_state = current_option_state_;
1160 results_t old_results{std::move(results_)};
1161 results_.clear();
1162 try {
1163 add_result(val_str);
1164 // if trigger_on_result_ is set the callback already ran
1166 run_callback(); // run callback sets the state, we need to reset it again
1168 } else {
1169 _validate_results(results_);
1170 current_option_state_ = old_option_state;
1171 }
1172 } catch(const CLI::Error &) {
1173 // this should be done
1174 results_ = std::move(old_results);
1175 current_option_state_ = old_option_state;
1176 throw;
1177 }
1178 results_ = std::move(old_results);
1179 default_str_ = std::move(val_str);
1180 return this;
1181 }
1182
1184 std::string get_type_name() const {
1185 std::string full_type_name = type_name_();
1186 if(!validators_.empty()) {
1187 for(auto &Validator : validators_) {
1188 std::string vtype = Validator.get_description();
1189 if(!vtype.empty()) {
1190 full_type_name += ":" + vtype;
1191 }
1192 }
1193 }
1194 return full_type_name;
1195 }
1196
1197 private:
1199 void _validate_results(results_t &res) const {
1200 // Run the Validators (can change the string)
1201 if(!validators_.empty()) {
1202 if(type_size_max_ > 1) { // in this context index refers to the index in the type
1203 int index = 0;
1204 if(get_items_expected_max() < static_cast<int>(res.size()) &&
1206 // create a negative index for the earliest ones
1207 index = get_items_expected_max() - static_cast<int>(res.size());
1208 }
1209
1210 for(std::string &result : res) {
1211 if(detail::is_separator(result) && type_size_max_ != type_size_min_ && index >= 0) {
1212 index = 0; // reset index for variable size chunks
1213 continue;
1214 }
1215 auto err_msg = _validate(result, (index >= 0) ? (index % type_size_max_) : index);
1216 if(!err_msg.empty())
1217 throw ValidationError(get_name(), err_msg);
1218 ++index;
1219 }
1220 } else {
1221 int index = 0;
1222 if(expected_max_ < static_cast<int>(res.size()) &&
1224 // create a negative index for the earliest ones
1225 index = expected_max_ - static_cast<int>(res.size());
1226 }
1227 for(std::string &result : res) {
1228 auto err_msg = _validate(result, index);
1229 ++index;
1230 if(!err_msg.empty())
1231 throw ValidationError(get_name(), err_msg);
1232 }
1233 }
1234 }
1235 }
1236
1240 void _reduce_results(results_t &res, const results_t &original) const {
1241
1242 // max num items expected or length of vector, always at least 1
1243 // Only valid for a trimming policy
1244
1245 res.clear();
1246 // Operation depends on the policy setting
1247 switch(multi_option_policy_) {
1249 break;
1251 // Allow multi-option sizes (including 0)
1252 std::size_t trim_size = std::min<std::size_t>(
1253 static_cast<std::size_t>(std::max<int>(get_items_expected_max(), 1)), original.size());
1254 if(original.size() != trim_size) {
1255 res.assign(original.end() - static_cast<results_t::difference_type>(trim_size), original.end());
1256 }
1257 } break;
1259 std::size_t trim_size = std::min<std::size_t>(
1260 static_cast<std::size_t>(std::max<int>(get_items_expected_max(), 1)), original.size());
1261 if(original.size() != trim_size) {
1262 res.assign(original.begin(), original.begin() + static_cast<results_t::difference_type>(trim_size));
1263 }
1264 } break;
1266 if(results_.size() > 1) {
1267 res.push_back(detail::join(original, std::string(1, (delimiter_ == '\0') ? '\n' : delimiter_)));
1268 }
1269 break;
1271 res.push_back(detail::sum_string_vector(original));
1272 break;
1274 default: {
1275 auto num_min = static_cast<std::size_t>(get_items_expected_min());
1276 auto num_max = static_cast<std::size_t>(get_items_expected_max());
1277 if(num_min == 0) {
1278 num_min = 1;
1279 }
1280 if(num_max == 0) {
1281 num_max = 1;
1282 }
1283 if(original.size() < num_min) {
1284 throw ArgumentMismatch::AtLeast(get_name(), static_cast<int>(num_min), original.size());
1285 }
1286 if(original.size() > num_max) {
1287 throw ArgumentMismatch::AtMost(get_name(), static_cast<int>(num_max), original.size());
1288 }
1289 break;
1290 }
1291 }
1292 // this check is to allow an empty vector in certain circumstances but not if expected is not zero.
1293 // {} is the indicator for a an empty container
1294 if(res.empty()) {
1295 if(original.size() == 1 && original[0] == "{}" && get_items_expected_min() > 0) {
1296 res.push_back("{}");
1297 res.push_back("%%");
1298 }
1299 } else if(res.size() == 1 && res[0] == "{}" && get_items_expected_min() > 0) {
1300 res.push_back("%%");
1301 }
1302 }
1303
1304 // Run a result through the Validators
1305 std::string _validate(std::string &result, int index) const {
1306 std::string err_msg;
1307 if(result.empty() && expected_min_ == 0) {
1308 // an empty with nothing expected is allowed
1309 return err_msg;
1310 }
1311 for(const auto &vali : validators_) {
1312 auto v = vali.get_application_index();
1313 if(v == -1 || v == index) {
1314 try {
1315 err_msg = vali(result);
1316 } catch(const ValidationError &err) {
1317 err_msg = err.what();
1318 }
1319 if(!err_msg.empty())
1320 break;
1321 }
1322 }
1323
1324 return err_msg;
1325 }
1326
1328 int _add_result(std::string &&result, std::vector<std::string> &res) const {
1329 int result_count = 0;
1330 if(allow_extra_args_ && !result.empty() && result.front() == '[' &&
1331 result.back() == ']') { // this is now a vector string likely from the default or user entry
1332 result.pop_back();
1333
1334 for(auto &var : CLI::detail::split(result.substr(1), ',')) {
1335 if(!var.empty()) {
1336 result_count += _add_result(std::move(var), res);
1337 }
1338 }
1339 return result_count;
1340 }
1341 if(delimiter_ == '\0') {
1342 res.push_back(std::move(result));
1343 ++result_count;
1344 } else {
1345 if((result.find_first_of(delimiter_) != std::string::npos)) {
1346 for(const auto &var : CLI::detail::split(result, delimiter_)) {
1347 if(!var.empty()) {
1348 res.push_back(var);
1349 ++result_count;
1350 }
1351 }
1352 } else {
1353 res.push_back(std::move(result));
1354 ++result_count;
1355 }
1356 }
1357 return result_count;
1358 }
1359};
1360
1361// [CLI11:option_hpp:end]
1362} // namespace CLI
Creates a command line program, with very few defaults.
Definition App.hpp:85
All errors derive from this one.
Definition Error.hpp:70
Definition Option.hpp:49
bool get_disable_flag_override() const
The status of configurable.
Definition Option.hpp:137
CRTP * mandatory(bool value=true)
Support Plumbum term.
Definition Option.hpp:112
CRTP * take_all()
Set the multi option policy to take all arguments.
Definition Option.hpp:165
bool get_ignore_case() const
The status of ignore case.
Definition Option.hpp:128
bool get_configurable() const
The status of configurable.
Definition Option.hpp:134
CRTP * group(const std::string &name)
Changes the group membership.
Definition Option.hpp:97
CRTP * join()
Set the multi option policy to join.
Definition Option.hpp:172
bool always_capture_default_
Automatically capture default value.
Definition Option.hpp:75
MultiOptionPolicy multi_option_policy_
Policy for handling multiple arguments beyond the expected Max.
Definition Option.hpp:78
CRTP * join(char delim)
Set the multi option policy to join with a specific delimiter.
Definition Option.hpp:179
bool get_ignore_underscore() const
The status of ignore_underscore.
Definition Option.hpp:131
CRTP * take_first()
Set the multi option policy to take last.
Definition Option.hpp:158
bool ignore_case_
Ignore the case when matching (option, not value)
Definition Option.hpp:60
CRTP * configurable(bool value=true)
Allow in a configuration file.
Definition Option.hpp:187
CRTP * delimiter(char value='\0')
Allow in a configuration file.
Definition Option.hpp:193
MultiOptionPolicy get_multi_option_policy() const
The status of the multi option policy.
Definition Option.hpp:146
bool configurable_
Allow this option to be given in a configuration file.
Definition Option.hpp:66
bool get_required() const
True if this is a required option.
Definition Option.hpp:125
bool disable_flag_override_
Disable overriding flag values with '=value'.
Definition Option.hpp:69
bool required_
True if this is a required option.
Definition Option.hpp:57
CRTP * take_last()
Set the multi option policy to take last.
Definition Option.hpp:151
char delimiter_
Specify a delimiter character for vector arguments.
Definition Option.hpp:72
CRTP * always_capture_default(bool value=true)
Definition Option.hpp:114
bool get_always_capture_default() const
Return true if this will automatically capture the default value for help printing.
Definition Option.hpp:143
std::string group_
The group membership.
Definition Option.hpp:54
char get_delimiter() const
Get the current delimiter char.
Definition Option.hpp:140
const std::string & get_group() const
Get the group of this option.
Definition Option.hpp:122
bool ignore_underscore_
Ignore underscores when matching (option, not value)
Definition Option.hpp:63
void copy_to(T *other) const
Copy the contents to another similar class (one based on OptionBase)
Definition Option.hpp:81
CRTP * required(bool value=true)
Set the option as required.
Definition Option.hpp:106
Definition Option.hpp:201
OptionDefaults * multi_option_policy(MultiOptionPolicy value=MultiOptionPolicy::Throw)
Take the last argument if given multiple times.
Definition Option.hpp:208
OptionDefaults * ignore_case(bool value=true)
Ignore the case of the option name.
Definition Option.hpp:214
OptionDefaults * ignore_underscore(bool value=true)
Ignore underscores in the option name.
Definition Option.hpp:220
OptionDefaults()=default
OptionDefaults * delimiter(char value='\0')
set a delimiter character to split up single arguments to treat as multiple inputs
Definition Option.hpp:232
OptionDefaults * disable_flag_override(bool value=true)
Disable overriding flag values with an '=' segment.
Definition Option.hpp:226
Definition Option.hpp:238
const std::string & get_option_text() const
Definition Option.hpp:773
const std::vector< std::string > & get_lnames() const
Get the long names.
Definition Option.hpp:711
int get_type_size_max() const
The maximum number of arguments the option expects.
Definition Option.hpp:690
std::size_t count() const
Count the total number of times an option was passed.
Definition Option.hpp:364
std::string default_str_
A human readable default value, either manually set, captured, or captured by default.
Definition Option.hpp:272
bool run_callback_for_default_
Control option to run the callback to set the default.
Definition Option.hpp:341
int get_expected_min() const
The number of times the option expects to be included.
Definition Option.hpp:735
Option * excludes(Option *opt)
Sets excluded options.
Definition Option.hpp:565
bool get_run_callback_for_default() const
Get the current value of run_callback_for_default.
Definition Option.hpp:454
Option * type_name(std::string typeval)
Set a custom option typestring.
Definition Option.hpp:1083
std::function< std::string()> type_name_
Definition Option.hpp:280
int get_expected_max() const
The max number of times the option expects to be included.
Definition Option.hpp:737
option_state
enumeration for the option state machine
Definition Option.hpp:328
@ reduced
a subset of results has been generated
@ callback_run
the callback has been executed
@ validated
the results have been validated
@ parsing
The option is currently collecting parsed results.
option_state current_option_state_
Whether the callback has run (needed for INI parsing)
Definition Option.hpp:335
std::string option_text_
If given, replace the text that describes the option type and usage in the help text.
Definition Option.hpp:275
int type_size_min_
The minimum number of arguments an option should be expecting.
Definition Option.hpp:293
bool get_trigger_on_parse() const
The status of trigger on parse.
Definition Option.hpp:437
int get_expected() const
The number of times the option expects to be included.
Definition Option.hpp:732
const results_t & results() const
Get the current complete results set.
Definition Option.hpp:1010
std::string pname_
A positional name.
Definition Option.hpp:259
results_t reduced_results() const
Get a copy of the results.
Definition Option.hpp:1013
int expected_min_
The minimum number of expected values.
Definition Option.hpp:296
Option(std::string option_name, std::string option_description, callback_t callback, App *parent)
Making an option by hand is not defined, it must be made by the App class.
Definition Option.hpp:351
Option * expected(int value_min, int value_max)
Set the range of expected arguments.
Definition Option.hpp:405
int get_type_size_min() const
The minimum number of arguments the option expects.
Definition Option.hpp:688
Option * ignore_case(bool value=true)
Definition Option.hpp:616
std::string get_default_str() const
The default value (for help printing)
Definition Option.hpp:705
std::set< Option * > needs_
A list of options that are required with this option.
Definition Option.hpp:304
Option * default_function(const std::function< std::string()> &func)
Set a capture function for the default. Mostly used by App.
Definition Option.hpp:1136
bool remove_excludes(Option *opt)
Remove needs link from an option. Returns true if the option really was in the needs list.
Definition Option.hpp:596
Option * multi_option_policy(MultiOptionPolicy value=MultiOptionPolicy::Throw)
Take the last argument if given multiple times (or another policy)
Definition Option.hpp:662
bool trigger_on_result_
flag indicating that the option should trigger the validation and callback chain on each result when ...
Definition Option.hpp:345
bool flag_like_
Specify that the option should act like a flag vs regular option.
Definition Option.hpp:339
bool check_lname(std::string name) const
Requires "--" to be removed from string.
Definition Option.hpp:929
Option * add_result(std::string s)
Puts a result at the end.
Definition Option.hpp:987
std::set< Option * > excludes_
A list of options that are excluded with this option.
Definition Option.hpp:307
bool force_callback_
flag indicating that the option should force the callback regardless if any results present
Definition Option.hpp:347
Option & operator=(const Option &)=delete
bool check_fname(std::string name) const
Requires "--" to be removed from string.
Definition Option.hpp:934
std::string get_flag_value(const std::string &name, std::string input_value) const
Definition Option.hpp:943
const std::vector< std::string > & get_fnames() const
Get the flag names with specified default values.
Definition Option.hpp:717
std::vector< std::string > fnames_
a list of flag names with specified default values;
Definition Option.hpp:256
Option * each(const std::function< void(std::string)> &func)
Adds a user supplied function to run on each item passed in (communicate though lambda capture)
Definition Option.hpp:499
Validator * get_validator(const std::string &Validator_name="")
Get a named Validator.
Definition Option.hpp:509
Option * option_text(std::string text)
Definition Option.hpp:768
Option * check(std::function< std::string(const std::string &)> Validator, std::string Validator_description="", std::string Validator_name="")
Adds a Validator. Takes a const string& and returns an error message (empty if conversion/check is ok...
Definition Option.hpp:466
const std::string & get_description() const
Get the description.
Definition Option.hpp:760
Option * expected(int value)
Set the number of expected arguments.
Definition Option.hpp:383
bool has_description() const
True if option has description.
Definition Option.hpp:757
bool check_name(const std::string &name) const
Check a name. Requires "-" or "--" for short / long, supports positional name.
Definition Option.hpp:894
Option(const Option &)=delete
bool get_force_callback() const
The status of force_callback.
Definition Option.hpp:445
bool get_allow_extra_args() const
Get the current value of allow extra args.
Definition Option.hpp:430
Option * disable_flag_override(bool value=true)
Disable flag overrides values, e.g. –flag=is not allowed.
Definition Option.hpp:676
std::vector< std::string > snames_
A list of the short names (-a) without the leading dashes.
Definition Option.hpp:246
results_t proc_results_
results after reduction
Definition Option.hpp:326
Option * run_callback_for_default(bool value=true)
Definition Option.hpp:449
Option * type_size(int option_type_size_min, int option_type_size_max)
Set a custom option type size range.
Definition Option.hpp:1108
void inject_separator(bool value=true)
Set the value of the separator injection flag.
Definition Option.hpp:1133
Option * allow_extra_args(bool value=true)
Definition Option.hpp:425
std::set< Option * > get_excludes() const
The set of options excluded.
Definition Option.hpp:702
Option * trigger_on_parse(bool value=true)
Set the value of trigger_on_parse which specifies that the option callback should be triggered on eve...
Definition Option.hpp:432
int get_type_size() const
The number of arguments the option expects.
Definition Option.hpp:685
Option * type_size(int option_type_size)
Set a custom option size.
Definition Option.hpp:1089
callback_t get_callback() const
Get the callback function.
Definition Option.hpp:708
std::string get_type_name() const
Get the full typename for this option.
Definition Option.hpp:1184
App * parent_
link back up to the parent App for fallthrough
Definition Option.hpp:314
bool nonpositional() const
True if option has at least one non-positional name.
Definition Option.hpp:754
int expected_max_
The maximum number of expected values.
Definition Option.hpp:298
std::string get_envname() const
The environment variable associated to this value.
Definition Option.hpp:696
int get_items_expected_max() const
Get the maximum number of items expected to be returned and used for the callback.
Definition Option.hpp:743
Option * transform(const std::function< std::string(std::string)> &func, std::string transform_description="", std::string transform_name="")
Adds a Validator-like function that can change result.
Definition Option.hpp:483
Option * excludes(std::string opt_name)
Can find a string if needed.
Definition Option.hpp:581
int get_inject_separator() const
Return the inject_separator flag.
Definition Option.hpp:693
std::string description_
The description for help strings.
Definition Option.hpp:269
bool inject_separator_
flag indicating a separator needs to be injected after each argument call
Definition Option.hpp:343
bool remove_needs(Option *opt)
Remove needs link from an option. Returns true if the option really was in the needs list.
Definition Option.hpp:554
bool get_callback_run() const
See if the callback has been run already.
Definition Option.hpp:1070
T as() const
Return the results as the specified type.
Definition Option.hpp:1063
void run_callback()
Process the callback.
Definition Option.hpp:843
Option * transform(Validator Validator, const std::string &Validator_name="")
Adds a transforming Validator with a built in type name.
Definition Option.hpp:475
callback_t callback_
Options store a callback to do all the work.
Definition Option.hpp:317
std::string get_name(bool positional=false, bool all_options=false) const
Gets a comma separated list of names. Will include / prefer the positional name if positional is true...
Definition Option.hpp:783
void clear()
Clear the parsed results (mostly for testing)
Definition Option.hpp:373
Option * add_result(std::vector< std::string > s)
Puts a result at the end.
Definition Option.hpp:1001
Option * capture_default_str()
Capture the default value from the original value (if it can be captured)
Definition Option.hpp:1142
void results(T &output) const
Get the results as a specified type.
Definition Option.hpp:1032
Option * default_str(std::string val)
Set the default value string representation (does not change the contained value)
Definition Option.hpp:1150
bool get_positional() const
True if the argument can be given directly.
Definition Option.hpp:751
std::string envname_
If given, check the environment for this option.
Definition Option.hpp:262
std::function< std::string()> default_function_
Run this function to capture a default (ignore if empty)
Definition Option.hpp:283
std::set< Option * > get_needs() const
The set of options needed.
Definition Option.hpp:699
bool check_sname(std::string name) const
Requires "-" to be removed from string.
Definition Option.hpp:924
Option * ignore_underscore(bool value=true)
Definition Option.hpp:640
std::vector< std::pair< std::string, std::string > > default_flag_values_
Definition Option.hpp:253
std::vector< Validator > validators_
A list of Validators to run on each value parsed.
Definition Option.hpp:301
Option * envname(std::string name)
Sets environment variable to read if no option given.
Definition Option.hpp:607
Option * type_name_fn(std::function< std::string()> typefun)
Set the type function to run when displayed on this option.
Definition Option.hpp:1077
Option * default_val(const X &val)
Definition Option.hpp:1157
Option * add_result(std::string s, int &results_added)
Puts a result at the end and get a count of the number of arguments actually added.
Definition Option.hpp:994
const std::string & get_single_name() const
Get a single name for the option, first of lname, pname, sname, envname.
Definition Option.hpp:719
Option * needs(Option *opt)
Sets required options.
Definition Option.hpp:531
const std::string & matching_name(const Option &other) const
If options share any of the same names, find it.
Definition Option.hpp:870
int type_size_max_
Definition Option.hpp:291
Option * needs(A opt, B opt1, ARG... args)
Any number supported, any mix of string and Opt.
Definition Option.hpp:548
bool allow_extra_args_
Specify that extra args beyond type_size_max should be allowed.
Definition Option.hpp:337
Option * description(std::string option_description)
Set the description.
Definition Option.hpp:763
std::vector< std::string > lnames_
A list of the long names (--long) without the leading dashes.
Definition Option.hpp:249
Option * force_callback(bool value=true)
Set the value of force_callback.
Definition Option.hpp:440
Validator * get_validator(int index)
Get a Validator by index NOTE: this may not be the order of definition.
Definition Option.hpp:522
bool operator==(const Option &other) const
If options share any of the same names, they are equal (not counting positional)
Definition Option.hpp:891
Option * check(Validator validator, const std::string &validator_name="")
Adds a Validator with a built in type name.
Definition Option.hpp:457
Option * needs(std::string opt_name)
Can find a string if needed.
Definition Option.hpp:539
results_t results_
complete Results of parsing
Definition Option.hpp:324
bool empty() const
True if the option was not passed.
Definition Option.hpp:367
int get_items_expected_min() const
The total min number of expected string values to be used.
Definition Option.hpp:740
Option * excludes(A opt, B opt1, ARG... args)
Any number supported, any mix of string and Opt.
Definition Option.hpp:590
const std::vector< std::string > & get_snames() const
Get the short names.
Definition Option.hpp:714
int get_items_expected() const
The total min number of expected string values to be used.
Definition Option.hpp:748
Some validators that are provided.
Definition Validators.hpp:80
Validator & non_modifying(bool no_modify=true)
Specify whether the Validator can be modifying or not.
Definition Validators.hpp:176
const std::string & get_name() const
Get the name of the Validator.
Definition Validators.hpp:162
std::string get_description() const
Generate type description information for the Validator.
Definition Validators.hpp:144
Validator & name(std::string validator_name)
Specify the type string.
Definition Validators.hpp:151
std::vector< std::string > split_names(std::string current)
Definition Split.hpp:67
auto to_string(T &&value) -> decltype(std::forward< T >(value))
Convert an object to a string (directly forward if this can become a string)
Definition TypeTools.hpp:270
std::tuple< std::vector< std::string >, std::vector< std::string >, std::string > get_names(const std::vector< std::string > &input)
Get a vector of short names, one of long names, and a single name.
Definition Split.hpp:107
std::ptrdiff_t find_member(std::string name, const std::vector< std::string > names, bool ignore_case=false, bool ignore_underscore=false)
Check if a string is a member of a list of strings and optionally ignore case or ignore underscores.
Definition StringTools.hpp:304
std::string remove_underscore(std::string str)
remove underscores from a string
Definition StringTools.hpp:267
bool is_separator(const std::string &str)
check if a string is a container segment separator (empty or "%%")
Definition StringTools.hpp:248
std::enable_if< std::is_integral< T >::value, bool >::type checked_multiply(T &a, T b)
Performs a *= b; if it doesn't cause integer overflow. Returns false otherwise.
Definition Validators.hpp:678
constexpr int expected_max_vector_size
Definition StringTools.hpp:43
std::string join(const T &v, std::string delim=",")
Simple function to join a string.
Definition StringTools.hpp:63
std::vector< std::string > split(const std::string &s, char delim)
Split a string by a delim.
Definition StringTools.hpp:46
bool valid_alias_name_string(const std::string &str)
Verify an app name.
Definition StringTools.hpp:242
std::string to_lower(std::string str)
Return a lower case version of a string.
Definition StringTools.hpp:259
std::int64_t to_flag_value(std::string val)
Convert a flag into an integer value typically binary flags.
Definition TypeTools.hpp:836
Definition App.hpp:34
MultiOptionPolicy
Enumeration of the multiOption Policy selection.
Definition Option.hpp:38
@ TakeAll
just get all the passed argument regardless
@ TakeFirst
take only the first Expected number of arguments
@ Throw
Throw an error if any extra arguments were given.
@ TakeLast
take only the last Expected number of arguments
@ Sum
sum all the arguments together if numerical or concatenate directly without delimiter
@ Join
merge all the arguments together into a single string via the delimiter character default(' ')
std::function< bool(const results_t &)> callback_t
callback function definition
Definition Option.hpp:31
std::vector< std::string > results_t
Definition Option.hpp:29
std::unique_ptr< Option > Option_p
Definition Option.hpp:36