38 #error This file should only be included once in any given source (.cpp) file. 58 #include <type_traits> 73 #error This file cannot be included alongside a different CLI11 header. 76 #define CLI11_VERSION_MAJOR 2 77 #define CLI11_VERSION_MINOR 3 78 #define CLI11_VERSION_PATCH 1 79 #define CLI11_VERSION "2.3.1" 85 #if !(defined(_MSC_VER) && __cplusplus == 199711L) && !defined(__INTEL_COMPILER) 86 #if __cplusplus >= 201402L 88 #if __cplusplus >= 201703L 90 #if __cplusplus > 201703L 95 #elif defined(_MSC_VER) && __cplusplus == 199711L 98 #if _MSVC_LANG >= 201402L 100 #if _MSVC_LANG > 201402L && _MSC_VER >= 1910 102 #if _MSVC_LANG > 201703L && _MSC_VER >= 1910 109 #if defined(CLI11_CPP14) 110 #define CLI11_DEPRECATED(reason) [[deprecated(reason)]] 111 #elif defined(_MSC_VER) 112 #define CLI11_DEPRECATED(reason) __declspec(deprecated(reason)) 114 #define CLI11_DEPRECATED(reason) __attribute__((deprecated(reason))) 118 #if !defined(CLI11_CPP17) || \ 119 (defined(__GNUC__) && !defined(__llvm__) && !defined(__INTEL_COMPILER) && __GNUC__ < 10 && __GNUC__ > 4) 120 #define CLI11_NODISCARD 122 #define CLI11_NODISCARD [[nodiscard]] 126 #ifndef CLI11_USE_STATIC_RTTI 127 #if(defined(_HAS_STATIC_RTTI) && _HAS_STATIC_RTTI) 128 #define CLI11_USE_STATIC_RTTI 1 129 #elif defined(__cpp_rtti) 130 #if(defined(_CPPRTTI) && _CPPRTTI == 0) 131 #define CLI11_USE_STATIC_RTTI 1 133 #define CLI11_USE_STATIC_RTTI 0 135 #elif(defined(__GCC_RTTI) && __GXX_RTTI) 136 #define CLI11_USE_STATIC_RTTI 0 138 #define CLI11_USE_STATIC_RTTI 1 146 #define CLI11_INLINE inline 153 #if defined CLI11_CPP17 && defined __has_include && !defined CLI11_HAS_FILESYSTEM 154 #if __has_include(<filesystem>) 156 #if defined __MAC_OS_X_VERSION_MIN_REQUIRED && __MAC_OS_X_VERSION_MIN_REQUIRED < 101500 157 #define CLI11_HAS_FILESYSTEM 0 158 #elif defined(__wasi__) 160 #define CLI11_HAS_FILESYSTEM 0 162 #include <filesystem> 163 #if defined __cpp_lib_filesystem && __cpp_lib_filesystem >= 201703 164 #if defined _GLIBCXX_RELEASE && _GLIBCXX_RELEASE >= 9 165 #define CLI11_HAS_FILESYSTEM 1 166 #elif defined(__GLIBCXX__) 168 #define CLI11_HAS_FILESYSTEM 0 170 #define CLI11_HAS_FILESYSTEM 1 173 #define CLI11_HAS_FILESYSTEM 0 179 #if defined CLI11_HAS_FILESYSTEM && CLI11_HAS_FILESYSTEM > 0 180 #include <filesystem> 182 #include <sys/stat.h> 183 #include <sys/types.h> 190 PXR_NAMESPACE_OPEN_SCOPE
202 template <typename T, typename = typename std::enable_if<std::is_enum<T>::value>::type>
205 return in << static_cast<typename std::underlying_type<T>::type>(item);
211 using enums::operator<<;
216 constexpr
int expected_max_vector_size{1 << 29};
219 CLI11_INLINE std::vector<std::string> split(
const std::string &s,
char delim);
222 template <
typename T> std::string join(
const T &v, std::string delim =
",") {
223 std::ostringstream s;
224 auto beg = std::begin(v);
225 auto end = std::end(v);
229 s << delim << *beg++;
235 template <
typename T,
237 typename =
typename std::enable_if<!std::is_constructible<std::string, Callable>::value>::type>
238 std::string join(
const T &v, Callable func, std::string delim =
",") {
239 std::ostringstream s;
240 auto beg = std::begin(v);
241 auto end = std::end(v);
242 auto loc = s.tellp();
244 auto nloc = s.tellp();
255 template <
typename T> std::string rjoin(
const T &v, std::string delim =
",") {
256 std::ostringstream s;
257 for(std::size_t start = 0; start < v.size(); start++) {
260 s << v[v.size() - start - 1];
268 CLI11_INLINE std::string <rim(std::string &str);
271 CLI11_INLINE std::string <rim(std::string &str,
const std::string &filter);
274 CLI11_INLINE std::string &rtrim(std::string &str);
277 CLI11_INLINE std::string &rtrim(std::string &str,
const std::string &filter);
280 inline std::string &trim(std::string &str) {
return ltrim(rtrim(str)); }
283 inline std::string &trim(std::string &str,
const std::string filter) {
return ltrim(rtrim(str, filter), filter); }
286 inline std::string trim_copy(
const std::string &str) {
292 CLI11_INLINE std::string &remove_quotes(std::string &str);
298 CLI11_INLINE std::string fix_newlines(
const std::string &leader, std::string input);
301 inline std::string trim_copy(
const std::string &str,
const std::string &filter) {
303 return trim(s, filter);
306 CLI11_INLINE std::ostream &
307 format_help(std::ostream &out, std::string name,
const std::string &description, std::size_t wid);
310 CLI11_INLINE std::ostream &format_aliases(std::ostream &out,
const std::vector<std::string> &aliases, std::size_t wid);
314 template <
typename T>
bool valid_first_char(T c) {
return ((c !=
'-') && (c !=
'!') && (c !=
' ') && c !=
'\n'); }
317 template <
typename T>
bool valid_later_char(T c) {
321 return ((c !=
'=') && (c !=
':') && (c !=
'{') && (c !=
' ') && c !=
'\n');
325 CLI11_INLINE
bool valid_name_string(
const std::string &str);
328 inline bool valid_alias_name_string(
const std::string &str) {
329 static const std::string badChars(std::string(
"\n") +
'\0');
330 return (str.find_first_of(badChars) == std::string::npos);
334 inline bool is_separator(
const std::string &str) {
335 static const std::string sep(
"%%");
336 return (str.empty() || str == sep);
340 inline bool isalpha(
const std::string &str) {
341 return std::all_of(str.begin(), str.end(), [](
char c) {
return std::isalpha(c, std::locale()); });
345 inline std::string to_lower(std::string str) {
346 std::transform(std::begin(str), std::end(str), std::begin(str), [](
const std::string::value_type &x) {
347 return std::tolower(x, std::locale());
353 inline std::string remove_underscore(std::string str) {
354 str.erase(std::remove(std::begin(str), std::end(str),
'_'), std::end(str));
359 CLI11_INLINE std::string find_and_replace(std::string str, std::string from, std::string to);
362 inline bool has_default_flag_values(
const std::string &flags) {
363 return (flags.find_first_of(
"{!") != std::string::npos);
366 CLI11_INLINE
void remove_default_flag_values(std::string &flags);
369 CLI11_INLINE std::ptrdiff_t find_member(std::string name,
370 const std::vector<std::string> names,
371 bool ignore_case =
false,
372 bool ignore_underscore =
false);
376 template <
typename Callable>
inline std::string find_and_modify(std::string str, std::string trigger, Callable modify) {
377 std::size_t start_pos = 0;
378 while((start_pos = str.find(trigger, start_pos)) != std::string::npos) {
379 start_pos = modify(str, start_pos);
386 CLI11_INLINE std::vector<std::string> split_up(std::string str,
char delimiter =
'\0');
392 CLI11_INLINE std::size_t escape_detect(std::string &str, std::size_t offset);
395 CLI11_INLINE std::string &add_quotes_if_needed(std::string &str);
403 CLI11_INLINE std::vector<std::string> split(
const std::string &s,
char delim) {
404 std::vector<std::string> elems;
407 elems.emplace_back();
409 std::stringstream ss;
412 while(std::getline(ss, item, delim)) {
413 elems.push_back(item);
419 CLI11_INLINE std::string <rim(std::string &str) {
420 auto it = std::find_if(str.begin(), str.end(), [](
char ch) {
return !std::isspace<char>(ch, std::locale()); });
421 str.erase(str.begin(), it);
425 CLI11_INLINE std::string <rim(std::string &str,
const std::string &filter) {
426 auto it = std::find_if(str.begin(), str.end(), [&filter](
char ch) {
return filter.find(ch) == std::string::npos; });
427 str.erase(str.begin(), it);
431 CLI11_INLINE std::string &rtrim(std::string &str) {
432 auto it = std::find_if(str.rbegin(), str.rend(), [](
char ch) {
return !std::isspace<char>(ch, std::locale()); });
433 str.erase(it.base(), str.end());
437 CLI11_INLINE std::string &rtrim(std::string &str,
const std::string &filter) {
439 std::find_if(str.rbegin(), str.rend(), [&filter](
char ch) {
return filter.find(ch) == std::string::npos; });
440 str.erase(it.base(), str.end());
444 CLI11_INLINE std::string &remove_quotes(std::string &str) {
445 if(str.length() > 1 && (str.front() ==
'"' || str.front() ==
'\'')) {
446 if(str.front() == str.back()) {
448 str.erase(str.begin(), str.begin() + 1);
454 CLI11_INLINE std::string fix_newlines(
const std::string &leader, std::string input) {
455 std::string::size_type n = 0;
456 while(n != std::string::npos && n < input.size()) {
457 n = input.find(
'\n', n);
458 if(n != std::string::npos) {
459 input = input.substr(0, n + 1) + leader + input.substr(n + 1);
466 CLI11_INLINE std::ostream &
467 format_help(std::ostream &out, std::string name,
const std::string &description, std::size_t wid) {
469 out << std::setw(static_cast<int>(wid)) << std::left << name;
470 if(!description.empty()) {
471 if(name.length() >= wid)
472 out <<
"\n" << std::setw(static_cast<int>(wid)) <<
"";
473 for(
const char c : description) {
476 out << std::setw(static_cast<int>(wid)) <<
"";
484 CLI11_INLINE std::ostream &format_aliases(std::ostream &out,
const std::vector<std::string> &aliases, std::size_t wid) {
485 if(!aliases.empty()) {
486 out << std::setw(static_cast<int>(wid)) <<
" aliases: ";
488 for(
const auto &alias : aliases) {
494 out << detail::fix_newlines(
" ", alias);
501 CLI11_INLINE
bool valid_name_string(
const std::string &str) {
502 if(str.empty() || !valid_first_char(str[0])) {
506 for(
auto c = str.begin() + 1; c != e; ++c)
507 if(!valid_later_char(*c))
512 CLI11_INLINE std::string find_and_replace(std::string str, std::string from, std::string to) {
514 std::size_t start_pos = 0;
516 while((start_pos = str.find(from, start_pos)) != std::string::npos) {
517 str.replace(start_pos, from.length(), to);
518 start_pos += to.length();
524 CLI11_INLINE
void remove_default_flag_values(std::string &flags) {
525 auto loc = flags.find_first_of(
'{', 2);
526 while(loc != std::string::npos) {
527 auto finish = flags.find_first_of(
"},", loc + 1);
528 if((finish != std::string::npos) && (flags[finish] ==
'}')) {
529 flags.erase(flags.begin() + static_cast<std::ptrdiff_t>(loc),
530 flags.begin() + static_cast<std::ptrdiff_t>(finish) + 1);
532 loc = flags.find_first_of(
'{', loc + 1);
534 flags.erase(std::remove(flags.begin(), flags.end(),
'!'), flags.end());
537 CLI11_INLINE std::ptrdiff_t
538 find_member(std::string name,
const std::vector<std::string> names,
bool ignore_case,
bool ignore_underscore) {
539 auto it = std::end(names);
541 if(ignore_underscore) {
542 name = detail::to_lower(detail::remove_underscore(name));
543 it = std::find_if(std::begin(names), std::end(names), [&name](std::string local_name) {
544 return detail::to_lower(detail::remove_underscore(local_name)) == name;
547 name = detail::to_lower(name);
548 it = std::find_if(std::begin(names), std::end(names), [&name](std::string local_name) {
549 return detail::to_lower(local_name) == name;
553 }
else if(ignore_underscore) {
554 name = detail::remove_underscore(name);
555 it = std::find_if(std::begin(names), std::end(names), [&name](std::string local_name) {
556 return detail::remove_underscore(local_name) == name;
559 it = std::find(std::begin(names), std::end(names), name);
562 return (it != std::end(names)) ? (it - std::begin(names)) : (-1);
565 CLI11_INLINE std::vector<std::string> split_up(std::string str,
char delimiter) {
567 const std::string delims(
"\'\"`");
568 auto find_ws = [delimiter](
char ch) {
569 return (delimiter ==
'\0') ? std::isspace<char>(ch, std::locale()) : (ch == delimiter);
573 std::vector<std::string> output;
574 bool embeddedQuote =
false;
576 while(!str.empty()) {
577 if(delims.find_first_of(str[0]) != std::string::npos) {
579 auto end = str.find_first_of(keyChar, 1);
580 while((end != std::string::npos) && (str[end - 1] ==
'\\')) {
581 end = str.find_first_of(keyChar, end + 1);
582 embeddedQuote =
true;
584 if(end != std::string::npos) {
585 output.push_back(str.substr(1, end - 1));
586 if(end + 2 < str.size()) {
587 str = str.substr(end + 2);
593 output.push_back(str.substr(1));
597 auto it = std::find_if(std::begin(str), std::end(str), find_ws);
598 if(it != std::end(str)) {
599 std::string value = std::string(str.begin(), it);
600 output.push_back(value);
601 str = std::string(it + 1, str.end());
603 output.push_back(str);
609 output.back() = find_and_replace(output.back(), std::string(
"\\") + keyChar, std::string(1, keyChar));
610 embeddedQuote =
false;
617 CLI11_INLINE std::size_t escape_detect(std::string &str, std::size_t offset) {
618 auto next = str[offset + 1];
619 if((next ==
'\"') || (next ==
'\'') || (next ==
'`')) {
620 auto astart = str.find_last_of(
"-/ \"\'`", offset - 1);
621 if(astart != std::string::npos) {
622 if(str[astart] == ((str[offset] ==
'=') ?
'-' :
'/'))
629 CLI11_INLINE std::string &add_quotes_if_needed(std::string &str) {
630 if((str.front() !=
'"' && str.front() !=
'\'') || str.front() != str.back()) {
631 char quote = str.find(
'"') < str.find(
'\'') ?
'\'' :
'"';
632 if(str.find(
' ') != std::string::npos) {
633 str.insert(0, 1, quote);
634 str.append(1, quote);
646 #define CLI11_ERROR_DEF(parent, name) \ 648 name(std::string ename, std::string msg, int exit_code) : parent(std::move(ename), std::move(msg), exit_code) {} \ 649 name(std::string ename, std::string msg, ExitCodes exit_code) \ 650 : parent(std::move(ename), std::move(msg), exit_code) {} \ 653 name(std::string msg, ExitCodes exit_code) : parent(#name, std::move(msg), exit_code) {} \ 654 name(std::string msg, int exit_code) : parent(#name, std::move(msg), exit_code) {} 657 #define CLI11_ERROR_SIMPLE(name) \ 658 explicit name(std::string msg) : name(#name, msg, ExitCodes::name) {} 662 enum class ExitCodes {
664 IncorrectConstruction = 100,
691 class Error :
public std::runtime_error {
692 int actual_exit_code;
693 std::string error_name{
"Error"};
696 CLI11_NODISCARD
int get_exit_code()
const {
return actual_exit_code; }
698 CLI11_NODISCARD std::string get_name()
const {
return error_name; }
700 Error(std::string name, std::string msg,
int exit_code = static_cast<int>(ExitCodes::BaseClass))
701 : runtime_error(msg), actual_exit_code(exit_code), error_name(std::move(name)) {}
703 Error(std::string name, std::string msg, ExitCodes exit_code) :
Error(name, msg, static_cast<int>(exit_code)) {}
731 name +
": You can't change expected arguments after you've changed the multi option policy!");
737 return IncorrectConstruction(name +
": multi_option_policy only works for flags and exact value options");
748 return BadNameString(
"Must have a name, not just dashes: " + name);
750 static BadNameString MultiPositionalNames(std::string name) {
751 return BadNameString(
"Only one positional name allowed, remove: " + name);
761 return {name +
" requires " + other, ExitCodes::OptionAlreadyAdded};
764 return {name +
" excludes " + other, ExitCodes::OptionAlreadyAdded};
780 Success() :
Success(
"Successfully completed, should be caught and quit", ExitCodes::Success) {}
786 CallForHelp() :
CallForHelp(
"This should be caught in your main function, see examples", ExitCodes::Success) {}
793 :
CallForAllHelp(
"This should be caught in your main function, see examples", ExitCodes::Success) {}
800 :
CallForVersion(
"This should be caught in your main function, see examples", ExitCodes::Success) {}
813 static FileError Missing(std::string name) {
return FileError(name +
" was not readable (missing?)"); }
821 :
ConversionError(
"The value " + member +
" is not an allowed value for " + name) {}
823 :
ConversionError(
"Could not convert: " + name +
" = " + detail::join(results)) {}
844 if(min_subcom == 1) {
847 return {
"Requires at least " + std::to_string(min_subcom) +
" subcommands", ExitCodes::RequiredError};
850 Option(std::size_t min_option, std::size_t max_option, std::size_t used,
const std::string &option_list) {
851 if((min_option == 1) && (max_option == 1) && (used == 0))
852 return RequiredError(
"Exactly 1 option from [" + option_list +
"]");
853 if((min_option == 1) && (max_option == 1) && (used > 1)) {
854 return {
"Exactly 1 option from [" + option_list +
"] is required and " + std::to_string(used) +
856 ExitCodes::RequiredError};
858 if((min_option == 1) && (used == 0))
859 return RequiredError(
"At least 1 option from [" + option_list +
"]");
860 if(used < min_option) {
861 return {
"Requires at least " + std::to_string(min_option) +
" options used and only " +
862 std::to_string(used) +
"were given from [" + option_list +
"]",
863 ExitCodes::RequiredError};
866 return {
"Requires at most 1 options be given from [" + option_list +
"]", ExitCodes::RequiredError};
868 return {
"Requires at most " + std::to_string(max_option) +
" options be used and " + std::to_string(used) +
869 "were given from [" + option_list +
"]",
870 ExitCodes::RequiredError};
879 :
ArgumentMismatch(expected > 0 ? (
"Expected exactly " + std::to_string(expected) +
" arguments to " + name +
880 ", got " + std::to_string(received))
881 : (
"Expected at least " + std::to_string(-expected) +
" arguments to " + name +
882 ", got " + std::to_string(received)),
883 ExitCodes::ArgumentMismatch) {}
885 static ArgumentMismatch AtLeast(std::string name,
int num, std::size_t received) {
886 return ArgumentMismatch(name +
": At least " + std::to_string(num) +
" required but received " +
887 std::to_string(received));
889 static ArgumentMismatch AtMost(std::string name,
int num, std::size_t received) {
890 return ArgumentMismatch(name +
": At Most " + std::to_string(num) +
" required but received " +
891 std::to_string(received));
893 static ArgumentMismatch TypedAtLeast(std::string name,
int num, std::string type) {
894 return ArgumentMismatch(name +
": " + std::to_string(num) +
" required " + type +
" missing");
899 static ArgumentMismatch PartialType(std::string name,
int num, std::string type) {
900 return ArgumentMismatch(name +
": " + type +
" only partially specified: " + std::to_string(num) +
901 " required for each element");
909 :
RequiresError(curname +
" requires " + subname, ExitCodes::RequiresError) {}
916 :
ExcludesError(curname +
" excludes " + subname, ExitCodes::ExcludesError) {}
922 explicit ExtrasError(std::vector<std::string> args)
923 :
ExtrasError((args.size() > 1 ?
"The following arguments were not expected: " 924 :
"The following argument was not expected: ") +
925 detail::rjoin(args,
" "),
926 ExitCodes::ExtrasError) {}
927 ExtrasError(
const std::string &name, std::vector<std::string> args)
929 (args.size() > 1 ?
"The following arguments were not expected: " 930 :
"The following argument was not expected: ") +
931 detail::rjoin(args,
" "),
932 ExitCodes::ExtrasError) {}
940 static ConfigError NotConfigurable(std::string item) {
941 return ConfigError(item +
": This option is not allowed in a configuration file");
949 :
InvalidError(name +
": Too many positional arguments with unlimited expected args", ExitCodes::InvalidError) {
968 #undef CLI11_ERROR_DEF 969 #undef CLI11_ERROR_SIMPLE 982 enum class enabler {};
985 constexpr enabler dummy = {};
993 template <
bool B,
class T =
void>
using enable_if_t =
typename std::enable_if<B, T>::type;
996 template <
typename... Ts>
struct make_void {
using type = void; };
999 template <
typename... Ts>
using void_t =
typename make_void<Ts...>::type;
1002 template <
bool B,
class T,
class F>
using conditional_t =
typename std::conditional<B, T, F>::type;
1005 template <
typename T>
struct is_bool : std::false_type {};
1008 template <>
struct is_bool<bool> : std::true_type {};
1014 template <
typename T>
struct is_shared_ptr<std::shared_ptr<T>> : std::true_type {};
1017 template <
typename T>
struct is_shared_ptr<const std::shared_ptr<T>> : std::true_type {};
1028 template <>
struct IsMemberType<const char *> {
using type = std::string; };
1038 template <
typename T,
typename Enable =
void>
struct element_type {
using type = T; };
1040 template <
typename T>
struct element_type<T, typename std::enable_if<is_copyable_ptr<T>::value>::type> {
1041 using type =
typename std::pointer_traits<T>::element_type;
1049 template <
typename T,
typename _ =
void>
struct pair_adaptor : std::false_type {
1050 using value_type =
typename T::value_type;
1051 using first_type =
typename std::remove_const<value_type>::type;
1052 using second_type =
typename std::remove_const<value_type>::type;
1055 template <
typename Q>
static auto first(Q &&pair_value) -> decltype(std::forward<Q>(pair_value)) {
1056 return std::forward<Q>(pair_value);
1059 template <
typename Q>
static auto second(Q &&pair_value) -> decltype(std::forward<Q>(pair_value)) {
1060 return std::forward<Q>(pair_value);
1066 template <
typename T>
1069 conditional_t<false, void_t<typename T::value_type::first_type, typename T::value_type::second_type>, void>>
1071 using value_type =
typename T::value_type;
1072 using first_type =
typename std::remove_const<typename value_type::first_type>::type;
1073 using second_type =
typename std::remove_const<typename value_type::second_type>::type;
1076 template <
typename Q>
static auto first(Q &&pair_value) -> decltype(std::get<0>(std::forward<Q>(pair_value))) {
1077 return std::get<0>(std::forward<Q>(pair_value));
1080 template <
typename Q>
static auto second(Q &&pair_value) -> decltype(std::get<1>(std::forward<Q>(pair_value))) {
1081 return std::get<1>(std::forward<Q>(pair_value));
1092 #pragma GCC diagnostic push 1093 #pragma GCC diagnostic ignored "-Wnarrowing" 1096 template <
typename T,
typename C>
class is_direct_constructible {
1097 template <
typename TT,
typename CC>
1098 static auto test(
int, std::true_type) -> decltype(
1101 #pragma diag_suppress 2361
1103 TT{std::declval<CC>()}
1105 #pragma diag_default 2361 1108 std::is_move_assignable<TT>());
1110 template <
typename TT,
typename CC>
static auto test(
int, std::false_type) -> std::false_type;
1112 template <
typename,
typename>
static auto test(...) -> std::false_type;
1115 static constexpr
bool value = decltype(test<T, C>(0,
typename std::is_constructible<T, C>::type()))::value;
1118 #pragma GCC diagnostic pop 1124 template <
typename T,
typename S = std::o
stringstream>
class is_ostreamable {
1125 template <
typename TT,
typename SS>
1126 static auto test(
int) -> decltype(std::declval<SS &>() << std::declval<TT>(), std::true_type());
1128 template <
typename,
typename>
static auto test(...) -> std::false_type;
1131 static constexpr
bool value = decltype(test<T, S>(0))::value;
1136 template <
typename TT,
typename SS>
1137 static auto test(
int) -> decltype(std::declval<SS &>() >> std::declval<TT &>(), std::true_type());
1139 template <
typename,
typename>
static auto test(...) -> std::false_type;
1142 static constexpr
bool value = decltype(test<T, S>(0))::value;
1147 template <
typename TT>
1148 static auto test(
int) -> decltype(std::declval<TT>().real(), std::declval<TT>().imag(), std::true_type());
1150 template <
typename>
static auto test(...) -> std::false_type;
1153 static constexpr
bool value = decltype(test<T>(0))::value;
1157 template <typename T, enable_if_t<is_istreamable<T>::value, detail::enabler> = detail::dummy>
1158 bool from_stream(
const std::string &istring, T &obj) {
1159 std::istringstream is;
1162 return !is.fail() && !is.rdbuf()->in_avail();
1165 template <typename T, enable_if_t<!is_istreamable<T>::value, detail::enabler> = detail::dummy>
1166 bool from_stream(
const std::string & , T & ) {
1171 template <
typename T,
typename _ =
void>
struct is_mutable_container : std::false_type {};
1176 template <
typename T>
1177 struct is_mutable_container<
1179 conditional_t<false,
1180 void_t<typename T::value_type,
1181 decltype(std::declval<T>().end()),
1182 decltype(std::declval<T>().clear()),
1183 decltype(std::declval<T>().insert(std::declval<decltype(std::declval<T>().end())>(),
1184 std::declval<const typename T::value_type &>()))>,
1186 :
public conditional_t<std::is_constructible<T, std::string>::value, std::false_type, std::true_type> {};
1189 template <
typename T,
typename _ =
void>
struct is_readable_container : std::false_type {};
1194 template <
typename T>
1195 struct is_readable_container<
1197 conditional_t<false, void_t<decltype(std::declval<T>().end()), decltype(std::declval<T>().begin())>, void>>
1198 :
public std::true_type {};
1201 template <
typename T,
typename _ =
void>
struct is_wrapper : std::false_type {};
1204 template <
typename T>
1205 struct is_wrapper<T, conditional_t<false, void_t<typename T::value_type>, void>> :
public std::true_type {};
1208 template <
typename S>
class is_tuple_like {
1209 template <
typename SS>
1212 static auto test(
int) -> decltype(std::tuple_size<
typename std::decay<SS>::type>::value, std::true_type{});
1213 template <
typename>
static auto test(...) -> std::false_type;
1216 static constexpr
bool value = decltype(test<S>(0))::value;
1220 template <typename T, enable_if_t<std::is_convertible<T, std::string>::value, detail::enabler> = detail::dummy>
1221 auto to_string(T &&value) -> decltype(std::forward<T>(value)) {
1222 return std::forward<T>(value);
1226 template <
typename T,
1227 enable_if_t<std::is_constructible<std::string, T>::value && !std::is_convertible<T, std::string>::value,
1228 detail::enabler> = detail::dummy>
1229 std::string to_string(
const T &value) {
1230 return std::string(value);
1234 template <
typename T,
1235 enable_if_t<!std::is_convertible<std::string, T>::value && !std::is_constructible<std::string, T>::value &&
1236 is_ostreamable<T>::value,
1237 detail::enabler> = detail::dummy>
1238 std::string to_string(T &&value) {
1239 std::stringstream stream;
1241 return stream.str();
1245 template <
typename T,
1246 enable_if_t<!std::is_constructible<std::string, T>::value && !is_ostreamable<T>::value &&
1247 !is_readable_container<typename std::remove_const<T>::type>::value,
1248 detail::enabler> = detail::dummy>
1249 std::string to_string(T &&) {
1254 template <
typename T,
1255 enable_if_t<!std::is_constructible<std::string, T>::value && !is_ostreamable<T>::value &&
1256 is_readable_container<T>::value,
1257 detail::enabler> = detail::dummy>
1258 std::string to_string(T &&variable) {
1259 auto cval = variable.begin();
1260 auto end = variable.end();
1264 std::vector<std::string> defaults;
1265 while(cval != end) {
1266 defaults.emplace_back(CLI::detail::to_string(*cval));
1269 return {
"[" + detail::join(defaults) +
"]"};
1273 template <
typename T1,
1276 enable_if_t<std::is_same<T1, T2>::value, detail::enabler> = detail::dummy>
1277 auto checked_to_string(T &&value) -> decltype(to_string(std::forward<T>(value))) {
1278 return to_string(std::forward<T>(value));
1282 template <
typename T1,
1285 enable_if_t<!std::is_same<T1, T2>::value, detail::enabler> = detail::dummy>
1286 std::string checked_to_string(T &&) {
1287 return std::string{};
1290 template <typename T, enable_if_t<std::is_arithmetic<T>::value, detail::enabler> = detail::dummy>
1291 std::string value_string(
const T &value) {
1292 return std::to_string(value);
1295 template <typename T, enable_if_t<std::is_enum<T>::value, detail::enabler> = detail::dummy>
1296 std::string value_string(
const T &value) {
1297 return std::to_string(
static_cast<typename std::underlying_type<T>::type
>(value));
1300 template <
typename T,
1301 enable_if_t<!std::is_enum<T>::value && !std::is_arithmetic<T>::value, detail::enabler> = detail::dummy>
1302 auto value_string(
const T &value) -> decltype(to_string(value)) {
1303 return to_string(value);
1307 template <
typename T,
typename def,
typename Enable =
void>
struct wrapped_type {
using type = def; };
1310 template <
typename T,
typename def>
struct wrapped_type<T, def, typename std::enable_if<is_wrapper<T>::value>::type> {
1311 using type =
typename T::value_type;
1315 template <
typename T,
typename Enable =
void>
struct type_count_base {
static const int value{0}; };
1318 template <
typename T>
1320 typename std::enable_if<!is_tuple_like<T>::value && !is_mutable_container<T>::value &&
1321 !std::is_void<T>::value>::type> {
1322 static constexpr
int value{1};
1326 template <
typename T>
1327 struct type_count_base<T, typename std::enable_if<is_tuple_like<T>::value && !is_mutable_container<T>::value>::type> {
1328 static constexpr
int value{std::tuple_size<T>::value};
1332 template <
typename T>
struct type_count_base<T, typename std::enable_if<is_mutable_container<T>::value>::type> {
1345 template <
typename T,
typename Enable =
void>
struct type_count {
static const int value{0}; };
1348 template <
typename T>
1350 typename std::enable_if<!is_wrapper<T>::value && !is_tuple_like<T>::value && !is_complex<T>::value &&
1351 !std::is_void<T>::value>::type> {
1352 static constexpr
int value{1};
1356 template <
typename T>
struct type_count<T, typename std::enable_if<is_complex<T>::value>::type> {
1357 static constexpr
int value{2};
1361 template <
typename T>
struct type_count<T, typename std::enable_if<is_mutable_container<T>::value>::type> {
1366 template <
typename T>
1368 typename std::enable_if<is_wrapper<T>::value && !is_complex<T>::value && !is_tuple_like<T>::value &&
1369 !is_mutable_container<T>::value>::type> {
1374 template <
typename T, std::
size_t I>
1375 constexpr
typename std::enable_if<I == type_count_base<T>::value,
int>::type tuple_type_size() {
1380 template <
typename T, std::
size_t I>
1381 constexpr
typename std::enable_if < I<type_count_base<T>::value,
int>::type tuple_type_size() {
1382 return subtype_count<typename std::tuple_element<I, T>::type>::value + tuple_type_size<T, I + 1>();
1386 template <
typename T>
struct type_count<T, typename std::enable_if<is_tuple_like<T>::value>::type> {
1387 static constexpr
int value{tuple_type_size<T, 0>()};
1391 template <
typename T>
struct subtype_count {
1392 static constexpr
int value{is_mutable_container<T>::value ? expected_max_vector_size : type_count<T>::value};
1396 template <
typename T,
typename Enable =
void>
struct type_count_min {
static const int value{0}; };
1399 template <
typename T>
1400 struct type_count_min<
1402 typename std::enable_if<!is_mutable_container<T>::value && !is_tuple_like<T>::value && !is_wrapper<T>::value &&
1403 !is_complex<T>::value && !std::is_void<T>::value>::type> {
1404 static constexpr
int value{type_count<T>::value};
1408 template <
typename T>
struct type_count_min<T, typename std::enable_if<is_complex<T>::value>::type> {
1409 static constexpr
int value{1};
1413 template <
typename T>
1414 struct type_count_min<
1416 typename std::enable_if<is_wrapper<T>::value && !is_complex<T>::value && !is_tuple_like<T>::value>::type> {
1417 static constexpr
int value{subtype_count_min<typename T::value_type>::value};
1421 template <
typename T, std::
size_t I>
1422 constexpr
typename std::enable_if<I == type_count_base<T>::value,
int>::type tuple_type_size_min() {
1427 template <
typename T, std::
size_t I>
1428 constexpr
typename std::enable_if < I<type_count_base<T>::value,
int>::type tuple_type_size_min() {
1429 return subtype_count_min<typename std::tuple_element<I, T>::type>::value + tuple_type_size_min<T, I + 1>();
1433 template <
typename T>
struct type_count_min<T, typename std::enable_if<is_tuple_like<T>::value>::type> {
1434 static constexpr
int value{tuple_type_size_min<T, 0>()};
1438 template <
typename T>
struct subtype_count_min {
1439 static constexpr
int value{is_mutable_container<T>::value
1440 ? ((type_count<T>::value < expected_max_vector_size) ? type_count<T>::value : 0)
1441 : type_count_min<T>::value};
1445 template <
typename T,
typename Enable =
void>
struct expected_count {
static const int value{0}; };
1448 template <
typename T>
1449 struct expected_count<T,
1450 typename std::enable_if<!is_mutable_container<T>::value && !is_wrapper<T>::value &&
1451 !std::is_void<T>::value>::type> {
1452 static constexpr
int value{1};
1455 template <
typename T>
struct expected_count<T, typename std::enable_if<is_mutable_container<T>::value>::type> {
1456 static constexpr
int value{expected_max_vector_size};
1460 template <
typename T>
1461 struct expected_count<T, typename std::enable_if<!is_mutable_container<T>::value && is_wrapper<T>::value>::type> {
1462 static constexpr
int value{expected_count<typename T::value_type>::value};
1466 enum class object_category : int {
1469 unsigned_integral = 4,
1472 floating_point = 10,
1473 number_constructible = 12,
1474 double_constructible = 14,
1475 integer_constructible = 16,
1477 string_assignable = 23,
1478 string_constructible = 24,
1482 complex_number = 60,
1484 container_value = 80,
1491 template <
typename T,
typename Enable =
void>
struct classify_object {
1492 static constexpr object_category value{object_category::other};
1496 template <
typename T>
1497 struct classify_object<
1499 typename std::enable_if<std::is_integral<T>::value && !std::is_same<T, char>::value && std::is_signed<T>::value &&
1500 !is_bool<T>::value && !std::is_enum<T>::value>::type> {
1501 static constexpr object_category value{object_category::integral_value};
1505 template <
typename T>
1506 struct classify_object<T,
1507 typename std::enable_if<std::is_integral<T>::value && std::is_unsigned<T>::value &&
1508 !std::is_same<T, char>::value && !is_bool<T>::value>::type> {
1509 static constexpr object_category value{object_category::unsigned_integral};
1513 template <
typename T>
1514 struct classify_object<T, typename std::enable_if<std::is_same<T, char>::value && !std::is_enum<T>::value>::type> {
1515 static constexpr object_category value{object_category::char_value};
1519 template <
typename T>
struct classify_object<T, typename std::enable_if<is_bool<T>::value>::type> {
1520 static constexpr object_category value{object_category::boolean_value};
1524 template <
typename T>
struct classify_object<T, typename std::enable_if<std::is_floating_point<T>::value>::type> {
1525 static constexpr object_category value{object_category::floating_point};
1529 template <
typename T>
1530 struct classify_object<T,
1531 typename std::enable_if<!std::is_floating_point<T>::value && !std::is_integral<T>::value &&
1532 std::is_assignable<T &, std::string>::value>::type> {
1533 static constexpr object_category value{object_category::string_assignable};
1537 template <
typename T>
1538 struct classify_object<
1540 typename std::enable_if<!std::is_floating_point<T>::value && !std::is_integral<T>::value &&
1541 !std::is_assignable<T &, std::string>::value && (type_count<T>::value == 1) &&
1542 std::is_constructible<T, std::string>::value>::type> {
1543 static constexpr object_category value{object_category::string_constructible};
1547 template <
typename T>
struct classify_object<T, typename std::enable_if<std::is_enum<T>::value>::type> {
1548 static constexpr object_category value{object_category::enumeration};
1551 template <
typename T>
struct classify_object<T, typename std::enable_if<is_complex<T>::value>::type> {
1552 static constexpr object_category value{object_category::complex_number};
1557 template <
typename T>
struct uncommon_type {
1558 using type =
typename std::conditional<!std::is_floating_point<T>::value && !std::is_integral<T>::value &&
1559 !std::is_assignable<T &, std::string>::value &&
1560 !std::is_constructible<T, std::string>::value && !is_complex<T>::value &&
1561 !is_mutable_container<T>::value && !std::is_enum<T>::value,
1563 std::false_type>::type;
1564 static constexpr
bool value = type::value;
1568 template <
typename T>
1569 struct classify_object<T,
1570 typename std::enable_if<(!is_mutable_container<T>::value && is_wrapper<T>::value &&
1571 !is_tuple_like<T>::value && uncommon_type<T>::value)>::type> {
1572 static constexpr object_category value{object_category::wrapper_value};
1576 template <
typename T>
1577 struct classify_object<T,
1578 typename std::enable_if<uncommon_type<T>::value && type_count<T>::value == 1 &&
1579 !is_wrapper<T>::value && is_direct_constructible<T, double>::value &&
1580 is_direct_constructible<T, int>::value>::type> {
1581 static constexpr object_category value{object_category::number_constructible};
1585 template <
typename T>
1586 struct classify_object<T,
1587 typename std::enable_if<uncommon_type<T>::value && type_count<T>::value == 1 &&
1588 !is_wrapper<T>::value && !is_direct_constructible<T, double>::value &&
1589 is_direct_constructible<T, int>::value>::type> {
1590 static constexpr object_category value{object_category::integer_constructible};
1594 template <
typename T>
1595 struct classify_object<T,
1596 typename std::enable_if<uncommon_type<T>::value && type_count<T>::value == 1 &&
1597 !is_wrapper<T>::value && is_direct_constructible<T, double>::value &&
1598 !is_direct_constructible<T, int>::value>::type> {
1599 static constexpr object_category value{object_category::double_constructible};
1603 template <
typename T>
1604 struct classify_object<
1606 typename std::enable_if<is_tuple_like<T>::value &&
1607 ((type_count<T>::value >= 2 && !is_wrapper<T>::value) ||
1608 (uncommon_type<T>::value && !is_direct_constructible<T, double>::value &&
1609 !is_direct_constructible<T, int>::value) ||
1610 (uncommon_type<T>::value && type_count<T>::value >= 2))>::type> {
1611 static constexpr object_category value{object_category::tuple_value};
1620 template <
typename T>
struct classify_object<T, typename std::enable_if<is_mutable_container<T>::value>::type> {
1621 static constexpr object_category value{object_category::container_value};
1630 template <
typename T,
1631 enable_if_t<classify_object<T>::value == object_category::char_value, detail::enabler> = detail::dummy>
1632 constexpr
const char *type_name() {
1636 template <
typename T,
1637 enable_if_t<classify_object<T>::value == object_category::integral_value ||
1638 classify_object<T>::value == object_category::integer_constructible,
1639 detail::enabler> = detail::dummy>
1640 constexpr
const char *type_name() {
1644 template <
typename T,
1645 enable_if_t<classify_object<T>::value == object_category::unsigned_integral, detail::enabler> = detail::dummy>
1646 constexpr
const char *type_name() {
1650 template <
typename T,
1651 enable_if_t<classify_object<T>::value == object_category::floating_point ||
1652 classify_object<T>::value == object_category::number_constructible ||
1653 classify_object<T>::value == object_category::double_constructible,
1654 detail::enabler> = detail::dummy>
1655 constexpr
const char *type_name() {
1660 template <
typename T,
1661 enable_if_t<classify_object<T>::value == object_category::enumeration, detail::enabler> = detail::dummy>
1662 constexpr
const char *type_name() {
1667 template <
typename T,
1668 enable_if_t<classify_object<T>::value == object_category::boolean_value, detail::enabler> = detail::dummy>
1669 constexpr
const char *type_name() {
1674 template <
typename T,
1675 enable_if_t<classify_object<T>::value == object_category::complex_number, detail::enabler> = detail::dummy>
1676 constexpr
const char *type_name() {
1681 template <
typename T,
1682 enable_if_t<classify_object<T>::value >= object_category::string_assignable &&
1683 classify_object<T>::value <= object_category::other,
1684 detail::enabler> = detail::dummy>
1685 constexpr
const char *type_name() {
1689 template <
typename T,
1690 enable_if_t<classify_object<T>::value == object_category::tuple_value && type_count_base<T>::value >= 2,
1691 detail::enabler> = detail::dummy>
1692 std::string type_name();
1695 template <
typename T,
1696 enable_if_t<classify_object<T>::value == object_category::container_value ||
1697 classify_object<T>::value == object_category::wrapper_value,
1698 detail::enabler> = detail::dummy>
1699 std::string type_name();
1702 template <
typename T,
1703 enable_if_t<classify_object<T>::value == object_category::tuple_value && type_count_base<T>::value == 1,
1704 detail::enabler> = detail::dummy>
1705 inline std::string type_name() {
1706 return type_name<typename std::decay<typename std::tuple_element<0, T>::type>::type>();
1710 template <
typename T, std::
size_t I>
1711 inline typename std::enable_if<I == type_count_base<T>::value, std::string>::type tuple_name() {
1712 return std::string{};
1716 template <
typename T, std::
size_t I>
1717 inline typename std::enable_if<(I < type_count_base<T>::value), std::string>::type tuple_name() {
1718 auto str = std::string{type_name<typename std::decay<typename std::tuple_element<I, T>::type>::type>()} +
',' +
1719 tuple_name<T, I + 1>();
1720 if(str.back() ==
',')
1726 template <
typename T,
1727 enable_if_t<classify_object<T>::value == object_category::tuple_value && type_count_base<T>::value >= 2,
1729 inline std::string type_name() {
1730 auto tname = std::string(1,
'[') + tuple_name<T, 0>();
1731 tname.push_back(
']');
1736 template <
typename T,
1737 enable_if_t<classify_object<T>::value == object_category::container_value ||
1738 classify_object<T>::value == object_category::wrapper_value,
1740 inline std::string type_name() {
1741 return type_name<typename T::value_type>();
1747 template <typename T, enable_if_t<std::is_unsigned<T>::value, detail::enabler> = detail::dummy>
1748 bool integral_conversion(
const std::string &input, T &output) noexcept {
1752 char *val =
nullptr;
1753 std::uint64_t output_ll = std::strtoull(input.c_str(), &val, 0);
1754 output = static_cast<T>(output_ll);
1755 if(val == (input.c_str() + input.size()) && static_cast<std::uint64_t>(output) == output_ll) {
1759 std::int64_t output_sll = std::strtoll(input.c_str(), &val, 0);
1760 if(val == (input.c_str() + input.size())) {
1761 output = (output_sll < 0) ? static_cast<T>(0) : static_cast<T>(output_sll);
1762 return (static_cast<std::int64_t>(output) == output_sll);
1768 template <typename T, enable_if_t<std::is_signed<T>::value, detail::enabler> = detail::dummy>
1769 bool integral_conversion(
const std::string &input, T &output) noexcept {
1773 char *val =
nullptr;
1774 std::int64_t output_ll = std::strtoll(input.c_str(), &val, 0);
1775 output = static_cast<T>(output_ll);
1776 if(val == (input.c_str() + input.size()) && static_cast<std::int64_t>(output) == output_ll) {
1779 if(input ==
"true") {
1781 output = static_cast<T>(1);
1788 inline std::int64_t to_flag_value(std::string val) {
1789 static const std::string trueString(
"true");
1790 static const std::string falseString(
"false");
1791 if(val == trueString) {
1794 if(val == falseString) {
1797 val = detail::to_lower(val);
1798 std::int64_t ret = 0;
1799 if(val.size() == 1) {
1800 if(val[0] >=
'1' && val[0] <=
'9') {
1801 return (static_cast<std::int64_t>(val[0]) -
'0');
1816 throw std::invalid_argument(
"unrecognized character");
1820 if(val == trueString || val ==
"on" || val ==
"yes" || val ==
"enable") {
1822 }
else if(val == falseString || val ==
"off" || val ==
"no" || val ==
"disable") {
1825 ret = std::stoll(val);
1831 template <
typename T,
1832 enable_if_t<classify_object<T>::value == object_category::integral_value ||
1833 classify_object<T>::value == object_category::unsigned_integral,
1834 detail::enabler> = detail::dummy>
1835 bool lexical_cast(
const std::string &input, T &output) {
1836 return integral_conversion(input, output);
1840 template <
typename T,
1841 enable_if_t<classify_object<T>::value == object_category::char_value, detail::enabler> = detail::dummy>
1842 bool lexical_cast(
const std::string &input, T &output) {
1843 if(input.size() == 1) {
1844 output = static_cast<T>(input[0]);
1847 return integral_conversion(input, output);
1851 template <
typename T,
1852 enable_if_t<classify_object<T>::value == object_category::boolean_value, detail::enabler> = detail::dummy>
1853 bool lexical_cast(
const std::string &input, T &output) {
1855 auto out = to_flag_value(input);
1858 }
catch(
const std::invalid_argument &) {
1860 }
catch(
const std::out_of_range &) {
1863 output = (input[0] !=
'-');
1869 template <
typename T,
1870 enable_if_t<classify_object<T>::value == object_category::floating_point, detail::enabler> = detail::dummy>
1871 bool lexical_cast(
const std::string &input, T &output) {
1875 char *val =
nullptr;
1876 auto output_ld = std::strtold(input.c_str(), &val);
1877 output = static_cast<T>(output_ld);
1878 return val == (input.c_str() + input.size());
1882 template <
typename T,
1883 enable_if_t<classify_object<T>::value == object_category::complex_number, detail::enabler> = detail::dummy>
1884 bool lexical_cast(
const std::string &input, T &output) {
1885 using XC =
typename wrapped_type<T, double>::type;
1888 bool worked =
false;
1889 auto nloc = str1.find_last_of(
"+-");
1890 if(nloc != std::string::npos && nloc > 0) {
1891 worked = detail::lexical_cast(str1.substr(0, nloc), x);
1892 str1 = str1.substr(nloc);
1893 if(str1.back() ==
'i' || str1.back() ==
'j')
1895 worked = worked && detail::lexical_cast(str1, y);
1897 if(str1.back() ==
'i' || str1.back() ==
'j') {
1899 worked = detail::lexical_cast(str1, y);
1902 worked = detail::lexical_cast(str1, x);
1910 return from_stream(input, output);
1914 template <
typename T,
1915 enable_if_t<classify_object<T>::value == object_category::string_assignable, detail::enabler> = detail::dummy>
1916 bool lexical_cast(
const std::string &input, T &output) {
1924 enable_if_t<classify_object<T>::value == object_category::string_constructible, detail::enabler> = detail::dummy>
1925 bool lexical_cast(
const std::string &input, T &output) {
1931 template <
typename T,
1932 enable_if_t<classify_object<T>::value == object_category::enumeration, detail::enabler> = detail::dummy>
1933 bool lexical_cast(
const std::string &input, T &output) {
1934 typename std::underlying_type<T>::type val;
1935 if(!integral_conversion(input, val)) {
1938 output = static_cast<T>(val);
1943 template <
typename T,
1944 enable_if_t<classify_object<T>::value == object_category::wrapper_value &&
1945 std::is_assignable<T &, typename T::value_type>::value,
1946 detail::enabler> = detail::dummy>
1947 bool lexical_cast(
const std::string &input, T &output) {
1948 typename T::value_type val;
1949 if(lexical_cast(input, val)) {
1953 return from_stream(input, output);
1956 template <
typename T,
1957 enable_if_t<classify_object<T>::value == object_category::wrapper_value &&
1958 !std::is_assignable<T &, typename T::value_type>::value && std::is_assignable<T &, T>::value,
1959 detail::enabler> = detail::dummy>
1960 bool lexical_cast(
const std::string &input, T &output) {
1961 typename T::value_type val;
1962 if(lexical_cast(input, val)) {
1966 return from_stream(input, output);
1972 enable_if_t<classify_object<T>::value == object_category::number_constructible, detail::enabler> = detail::dummy>
1973 bool lexical_cast(
const std::string &input, T &output) {
1975 if(integral_conversion(input, val)) {
1981 if(lexical_cast(input, dval)) {
1986 return from_stream(input, output);
1992 enable_if_t<classify_object<T>::value == object_category::integer_constructible, detail::enabler> = detail::dummy>
1993 bool lexical_cast(
const std::string &input, T &output) {
1995 if(integral_conversion(input, val)) {
1999 return from_stream(input, output);
2005 enable_if_t<classify_object<T>::value == object_category::double_constructible, detail::enabler> = detail::dummy>
2006 bool lexical_cast(
const std::string &input, T &output) {
2008 if(lexical_cast(input, val)) {
2012 return from_stream(input, output);
2016 template <
typename T,
2017 enable_if_t<classify_object<T>::value == object_category::other && std::is_assignable<T &, int>::value,
2018 detail::enabler> = detail::dummy>
2019 bool lexical_cast(
const std::string &input, T &output) {
2021 if(integral_conversion(input, val)) {
2023 #pragma warning(push) 2024 #pragma warning(disable : 4800) 2030 #pragma warning(pop) 2037 return from_stream(input, output);
2042 template <
typename T,
2043 enable_if_t<classify_object<T>::value == object_category::other && !std::is_assignable<T &, int>::value,
2044 detail::enabler> = detail::dummy>
2045 bool lexical_cast(
const std::string &input, T &output) {
2046 static_assert(is_istreamable<T>::value,
2047 "option object type must have a lexical cast overload or streaming input operator(>>) defined, if it " 2048 "is convertible from another type use the add_option<T, XC>(...) with XC being the known type");
2049 return from_stream(input, output);
2054 template <
typename AssignTo,
2056 enable_if_t<std::is_same<AssignTo, ConvertTo>::value &&
2057 (classify_object<AssignTo>::value == object_category::string_assignable ||
2058 classify_object<AssignTo>::value == object_category::string_constructible),
2059 detail::enabler> = detail::dummy>
2060 bool lexical_assign(
const std::string &input, AssignTo &output) {
2061 return lexical_cast(input, output);
2065 template <
typename AssignTo,
2067 enable_if_t<std::is_same<AssignTo, ConvertTo>::value && std::is_assignable<AssignTo &, AssignTo>::value &&
2068 classify_object<AssignTo>::value != object_category::string_assignable &&
2069 classify_object<AssignTo>::value != object_category::string_constructible,
2070 detail::enabler> = detail::dummy>
2071 bool lexical_assign(
const std::string &input, AssignTo &output) {
2073 output = AssignTo{};
2077 return lexical_cast(input, output);
2081 template <
typename AssignTo,
2083 enable_if_t<std::is_same<AssignTo, ConvertTo>::value && !std::is_assignable<AssignTo &, AssignTo>::value &&
2084 classify_object<AssignTo>::value == object_category::wrapper_value,
2085 detail::enabler> = detail::dummy>
2086 bool lexical_assign(
const std::string &input, AssignTo &output) {
2088 typename AssignTo::value_type emptyVal{};
2092 return lexical_cast(input, output);
2097 template <
typename AssignTo,
2099 enable_if_t<std::is_same<AssignTo, ConvertTo>::value && !std::is_assignable<AssignTo &, AssignTo>::value &&
2100 classify_object<AssignTo>::value != object_category::wrapper_value &&
2101 std::is_assignable<AssignTo &, int>::value,
2102 detail::enabler> = detail::dummy>
2103 bool lexical_assign(
const std::string &input, AssignTo &output) {
2109 if(lexical_cast(input, val)) {
2117 template <
typename AssignTo,
2119 enable_if_t<!std::is_same<AssignTo, ConvertTo>::value && std::is_assignable<AssignTo &, ConvertTo &>::value,
2120 detail::enabler> = detail::dummy>
2121 bool lexical_assign(
const std::string &input, AssignTo &output) {
2123 bool parse_result = (!input.empty()) ? lexical_cast<ConvertTo>(input, val) :
true;
2127 return parse_result;
2134 enable_if_t<!std::is_same<AssignTo, ConvertTo>::value && !std::is_assignable<AssignTo &, ConvertTo &>::value &&
2135 std::is_move_assignable<AssignTo>::value,
2136 detail::enabler> = detail::dummy>
2137 bool lexical_assign(
const std::string &input, AssignTo &output) {
2139 bool parse_result = input.empty() ? true : lexical_cast<ConvertTo>(input, val);
2141 output = AssignTo(val);
2143 return parse_result;
2147 template <
typename AssignTo,
2149 enable_if_t<classify_object<ConvertTo>::value <= object_category::other &&
2150 classify_object<AssignTo>::value <= object_category::wrapper_value,
2151 detail::enabler> = detail::dummy>
2152 bool lexical_conversion(
const std::vector<std ::string> &strings, AssignTo &output) {
2153 return lexical_assign<AssignTo, ConvertTo>(strings[0], output);
2158 template <
typename AssignTo,
2160 enable_if_t<(type_count<AssignTo>::value <= 2) && expected_count<AssignTo>::value == 1 &&
2161 is_tuple_like<ConvertTo>::value && type_count_base<ConvertTo>::value == 2,
2162 detail::enabler> = detail::dummy>
2163 bool lexical_conversion(
const std::vector<std ::string> &strings, AssignTo &output) {
2165 typename std::remove_const<typename std::tuple_element<0, ConvertTo>::type>::type v1;
2166 typename std::tuple_element<1, ConvertTo>::type v2;
2167 bool retval = lexical_assign<decltype(v1), decltype(v1)>(strings[0], v1);
2168 if(strings.size() > 1) {
2169 retval = retval && lexical_assign<decltype(v2), decltype(v2)>(strings[1], v2);
2172 output = AssignTo{v1, v2};
2178 template <
class AssignTo,
2180 enable_if_t<is_mutable_container<AssignTo>::value && is_mutable_container<ConvertTo>::value &&
2181 type_count<ConvertTo>::value == 1,
2182 detail::enabler> = detail::dummy>
2183 bool lexical_conversion(
const std::vector<std ::string> &strings, AssignTo &output) {
2184 output.erase(output.begin(), output.end());
2185 if(strings.size() == 1 && strings[0] ==
"{}") {
2188 bool skip_remaining =
false;
2189 if(strings.size() == 2 && strings[0] ==
"{}" && is_separator(strings[1])) {
2190 skip_remaining =
true;
2192 for(
const auto &elem : strings) {
2193 typename AssignTo::value_type out;
2194 bool retval = lexical_assign<typename AssignTo::value_type, typename ConvertTo::value_type>(elem, out);
2198 output.insert(output.end(), std::move(out));
2199 if(skip_remaining) {
2203 return (!output.empty());
2207 template <class AssignTo, class ConvertTo, enable_if_t<is_complex<ConvertTo>::value, detail::enabler> = detail::dummy>
2208 bool lexical_conversion(
const std::vector<std::string> &strings, AssignTo &output) {
2210 if(strings.size() >= 2 && !strings[1].empty()) {
2211 using XC2 =
typename wrapped_type<ConvertTo, double>::type;
2213 auto str1 = strings[1];
2214 if(str1.back() ==
'i' || str1.back() ==
'j') {
2217 auto worked = detail::lexical_cast(strings[0], x) && detail::lexical_cast(str1, y);
2219 output = ConvertTo{x, y};
2223 return lexical_assign<AssignTo, ConvertTo>(strings[0], output);
2227 template <
class AssignTo,
2229 enable_if_t<is_mutable_container<AssignTo>::value && (expected_count<ConvertTo>::value == 1) &&
2230 (type_count<ConvertTo>::value == 1),
2231 detail::enabler> = detail::dummy>
2232 bool lexical_conversion(
const std::vector<std ::string> &strings, AssignTo &output) {
2235 output.reserve(strings.size());
2236 for(
const auto &elem : strings) {
2238 output.emplace_back();
2239 retval = retval && lexical_assign<typename AssignTo::value_type, ConvertTo>(elem, output.back());
2241 return (!output.empty()) && retval;
2247 template <
class AssignTo,
2249 enable_if_t<is_mutable_container<AssignTo>::value && is_mutable_container<ConvertTo>::value &&
2250 type_count_base<ConvertTo>::value == 2,
2251 detail::enabler> = detail::dummy>
2252 bool lexical_conversion(std::vector<std::string> strings, AssignTo &output);
2255 template <
class AssignTo,
2257 enable_if_t<is_mutable_container<AssignTo>::value && is_mutable_container<ConvertTo>::value &&
2258 type_count_base<ConvertTo>::value != 2 &&
2259 ((type_count<ConvertTo>::value > 2) ||
2260 (type_count<ConvertTo>::value > type_count_base<ConvertTo>::value)),
2261 detail::enabler> = detail::dummy>
2262 bool lexical_conversion(
const std::vector<std::string> &strings, AssignTo &output);
2265 template <
class AssignTo,
2267 enable_if_t<is_tuple_like<AssignTo>::value && is_tuple_like<ConvertTo>::value &&
2268 (type_count_base<ConvertTo>::value != type_count<ConvertTo>::value ||
2269 type_count<ConvertTo>::value > 2),
2270 detail::enabler> = detail::dummy>
2271 bool lexical_conversion(
const std::vector<std::string> &strings, AssignTo &output);
2275 template <
typename AssignTo,
2277 enable_if_t<!is_tuple_like<AssignTo>::value && !is_mutable_container<AssignTo>::value &&
2278 classify_object<ConvertTo>::value != object_category::wrapper_value &&
2279 (is_mutable_container<ConvertTo>::value || type_count<ConvertTo>::value > 2),
2280 detail::enabler> = detail::dummy>
2281 bool lexical_conversion(
const std::vector<std ::string> &strings, AssignTo &output) {
2283 if(strings.size() > 1 || (!strings.empty() && !(strings.front().empty()))) {
2285 auto retval = lexical_conversion<ConvertTo, ConvertTo>(strings, val);
2286 output = AssignTo{val};
2289 output = AssignTo{};
2294 template <
class AssignTo,
class ConvertTo, std::
size_t I>
2295 inline typename std::enable_if<(I >= type_count_base<AssignTo>::value),
bool>::type
2296 tuple_conversion(
const std::vector<std::string> &, AssignTo &) {
2301 template <
class AssignTo,
class ConvertTo>
2302 inline typename std::enable_if<!is_mutable_container<ConvertTo>::value && type_count<ConvertTo>::value == 1,
bool>::type
2303 tuple_type_conversion(std::vector<std::string> &strings, AssignTo &output) {
2304 auto retval = lexical_assign<AssignTo, ConvertTo>(strings[0], output);
2305 strings.erase(strings.begin());
2310 template <
class AssignTo,
class ConvertTo>
2311 inline typename std::enable_if<!is_mutable_container<ConvertTo>::value && (type_count<ConvertTo>::value > 1) &&
2312 type_count<ConvertTo>::value == type_count_min<ConvertTo>::value,
2314 tuple_type_conversion(std::vector<std::string> &strings, AssignTo &output) {
2315 auto retval = lexical_conversion<AssignTo, ConvertTo>(strings, output);
2316 strings.erase(strings.begin(), strings.begin() + type_count<ConvertTo>::value);
2321 template <
class AssignTo,
class ConvertTo>
2322 inline typename std::enable_if<is_mutable_container<ConvertTo>::value ||
2323 type_count<ConvertTo>::value != type_count_min<ConvertTo>::value,
2325 tuple_type_conversion(std::vector<std::string> &strings, AssignTo &output) {
2327 std::size_t index{subtype_count_min<ConvertTo>::value};
2328 const std::size_t mx_count{subtype_count<ConvertTo>::value};
2329 const std::size_t mx{(std::max)(mx_count, strings.size())};
2332 if(is_separator(strings[index])) {
2337 bool retval = lexical_conversion<AssignTo, ConvertTo>(
2338 std::vector<std::string>(strings.begin(), strings.begin() + static_cast<std::ptrdiff_t>(index)), output);
2339 strings.erase(strings.begin(), strings.begin() + static_cast<std::ptrdiff_t>(index) + 1);
2344 template <
class AssignTo,
class ConvertTo, std::
size_t I>
2345 inline typename std::enable_if<(I < type_count_base<AssignTo>::value),
bool>::type
2346 tuple_conversion(std::vector<std::string> strings, AssignTo &output) {
2348 using ConvertToElement =
typename std::
2349 conditional<is_tuple_like<ConvertTo>::value,
typename std::tuple_element<I, ConvertTo>::type, ConvertTo>::type;
2350 if(!strings.empty()) {
2351 retval = retval && tuple_type_conversion<typename std::tuple_element<I, AssignTo>::type, ConvertToElement>(
2352 strings, std::get<I>(output));
2354 retval = retval && tuple_conversion<AssignTo, ConvertTo, I + 1>(std::move(strings), output);
2359 template <
class AssignTo,
2361 enable_if_t<is_mutable_container<AssignTo>::value && is_mutable_container<ConvertTo>::value &&
2362 type_count_base<ConvertTo>::value == 2,
2364 bool lexical_conversion(std::vector<std::string> strings, AssignTo &output) {
2366 while(!strings.empty()) {
2368 typename std::remove_const<typename std::tuple_element<0, typename ConvertTo::value_type>::type>::type v1;
2369 typename std::tuple_element<1, typename ConvertTo::value_type>::type v2;
2370 bool retval = tuple_type_conversion<decltype(v1), decltype(v1)>(strings, v1);
2371 if(!strings.empty()) {
2372 retval = retval && tuple_type_conversion<decltype(v2), decltype(v2)>(strings, v2);
2375 output.insert(output.end(),
typename AssignTo::value_type{v1, v2});
2380 return (!output.empty());
2384 template <
class AssignTo,
2386 enable_if_t<is_tuple_like<AssignTo>::value && is_tuple_like<ConvertTo>::value &&
2387 (type_count_base<ConvertTo>::value != type_count<ConvertTo>::value ||
2388 type_count<ConvertTo>::value > 2),
2390 bool lexical_conversion(
const std::vector<std ::string> &strings, AssignTo &output) {
2392 !is_tuple_like<ConvertTo>::value || type_count_base<AssignTo>::value == type_count_base<ConvertTo>::value,
2393 "if the conversion type is defined as a tuple it must be the same size as the type you are converting to");
2394 return tuple_conversion<AssignTo, ConvertTo, 0>(strings, output);
2398 template <
class AssignTo,
2400 enable_if_t<is_mutable_container<AssignTo>::value && is_mutable_container<ConvertTo>::value &&
2401 type_count_base<ConvertTo>::value != 2 &&
2402 ((type_count<ConvertTo>::value > 2) ||
2403 (type_count<ConvertTo>::value > type_count_base<ConvertTo>::value)),
2405 bool lexical_conversion(
const std::vector<std ::string> &strings, AssignTo &output) {
2408 std::vector<std::string> temp;
2410 std::size_t icount{0};
2411 std::size_t xcm{type_count<ConvertTo>::value};
2412 auto ii_max = strings.size();
2413 while(ii < ii_max) {
2414 temp.push_back(strings[ii]);
2417 if(icount == xcm || is_separator(temp.back()) || ii == ii_max) {
2418 if(static_cast<int>(xcm) > type_count_min<ConvertTo>::value && is_separator(temp.back())) {
2421 typename AssignTo::value_type temp_out;
2423 lexical_conversion<typename AssignTo::value_type, typename ConvertTo::value_type>(temp, temp_out);
2428 output.insert(output.end(), std::move(temp_out));
2436 template <
typename AssignTo,
2438 enable_if_t<classify_object<ConvertTo>::value == object_category::wrapper_value &&
2439 std::is_assignable<ConvertTo &, ConvertTo>::value,
2440 detail::enabler> = detail::dummy>
2441 bool lexical_conversion(
const std::vector<std::string> &strings, AssignTo &output) {
2442 if(strings.empty() || strings.front().empty()) {
2443 output = ConvertTo{};
2446 typename ConvertTo::value_type val;
2447 if(lexical_conversion<typename ConvertTo::value_type, typename ConvertTo::value_type>(strings, val)) {
2448 output = ConvertTo{val};
2455 template <
typename AssignTo,
2457 enable_if_t<classify_object<ConvertTo>::value == object_category::wrapper_value &&
2458 !std::is_assignable<AssignTo &, ConvertTo>::value,
2459 detail::enabler> = detail::dummy>
2460 bool lexical_conversion(
const std::vector<std::string> &strings, AssignTo &output) {
2461 using ConvertType =
typename ConvertTo::value_type;
2462 if(strings.empty() || strings.front().empty()) {
2463 output = ConvertType{};
2467 if(lexical_conversion<typename ConvertTo::value_type, typename ConvertTo::value_type>(strings, val)) {
2475 inline std::string sum_string_vector(
const std::vector<std::string> &values) {
2479 for(
const auto &arg : values) {
2481 auto comp = detail::lexical_cast<double>(arg, tv);
2484 tv = static_cast<double>(detail::to_flag_value(arg));
2485 }
catch(
const std::exception &) {
2493 for(
const auto &arg : values) {
2497 if(val <= static_cast<double>((std::numeric_limits<std::int64_t>::min)()) ||
2498 val >= static_cast<double>((std::numeric_limits<std::int64_t>::max)()) ||
2500 val == static_cast<std::int64_t>(val)) {
2501 output = detail::value_string(static_cast<int64_t>(val));
2503 output = detail::value_string(val);
2516 CLI11_INLINE
bool split_short(
const std::string ¤t, std::string &name, std::string &rest);
2519 CLI11_INLINE
bool split_long(
const std::string ¤t, std::string &name, std::string &value);
2522 CLI11_INLINE
bool split_windows_style(
const std::string ¤t, std::string &name, std::string &value);
2525 CLI11_INLINE std::vector<std::string> split_names(std::string current);
2528 CLI11_INLINE std::vector<std::pair<std::string, std::string>> get_default_flag_values(
const std::string &str);
2531 CLI11_INLINE std::tuple<std::vector<std::string>, std::vector<std::string>, std::string>
2532 get_names(
const std::vector<std::string> &input);
2540 CLI11_INLINE
bool split_short(
const std::string ¤t, std::string &name, std::string &rest) {
2541 if(current.size() > 1 && current[0] ==
'-' && valid_first_char(current[1])) {
2542 name = current.substr(1, 1);
2543 rest = current.substr(2);
2549 CLI11_INLINE
bool split_long(
const std::string ¤t, std::string &name, std::string &value) {
2550 if(current.size() > 2 && current.substr(0, 2) ==
"--" && valid_first_char(current[2])) {
2551 auto loc = current.find_first_of(
'=');
2552 if(loc != std::string::npos) {
2553 name = current.substr(2, loc - 2);
2554 value = current.substr(loc + 1);
2556 name = current.substr(2);
2564 CLI11_INLINE
bool split_windows_style(
const std::string ¤t, std::string &name, std::string &value) {
2565 if(current.size() > 1 && current[0] ==
'/' && valid_first_char(current[1])) {
2566 auto loc = current.find_first_of(
':');
2567 if(loc != std::string::npos) {
2568 name = current.substr(1, loc - 1);
2569 value = current.substr(loc + 1);
2571 name = current.substr(1);
2579 CLI11_INLINE std::vector<std::string> split_names(std::string current) {
2580 std::vector<std::string> output;
2581 std::size_t val = 0;
2582 while((val = current.find(
',')) != std::string::npos) {
2583 output.push_back(trim_copy(current.substr(0, val)));
2584 current = current.substr(val + 1);
2586 output.push_back(trim_copy(current));
2590 CLI11_INLINE std::vector<std::pair<std::string, std::string>> get_default_flag_values(
const std::string &str) {
2591 std::vector<std::string> flags = split_names(str);
2592 flags.erase(std::remove_if(flags.begin(),
2594 [](
const std::string &name) {
2595 return ((name.empty()) || (!(((name.find_first_of(
'{') != std::string::npos) &&
2596 (name.back() ==
'}')) ||
2597 (name[0] ==
'!'))));
2600 std::vector<std::pair<std::string, std::string>> output;
2601 output.reserve(flags.size());
2602 for(
auto &flag : flags) {
2603 auto def_start = flag.find_first_of(
'{');
2604 std::string defval =
"false";
2605 if((def_start != std::string::npos) && (flag.back() ==
'}')) {
2606 defval = flag.substr(def_start + 1);
2608 flag.erase(def_start, std::string::npos);
2610 flag.erase(0, flag.find_first_not_of(
"-!"));
2611 output.emplace_back(flag, defval);
2616 CLI11_INLINE std::tuple<std::vector<std::string>, std::vector<std::string>, std::string>
2617 get_names(
const std::vector<std::string> &input) {
2619 std::vector<std::string> short_names;
2620 std::vector<std::string> long_names;
2621 std::string pos_name;
2623 for(std::string name : input) {
2624 if(name.length() == 0) {
2627 if(name.length() > 1 && name[0] ==
'-' && name[1] !=
'-') {
2628 if(name.length() == 2 && valid_first_char(name[1]))
2629 short_names.emplace_back(1, name[1]);
2631 throw BadNameString::OneCharName(name);
2632 }
else if(name.length() > 2 && name.substr(0, 2) ==
"--") {
2633 name = name.substr(2);
2634 if(valid_name_string(name))
2635 long_names.push_back(name);
2637 throw BadNameString::BadLongName(name);
2638 }
else if(name ==
"-" || name ==
"--") {
2639 throw BadNameString::DashesOnly(name);
2641 if(pos_name.length() > 0)
2642 throw BadNameString::MultiPositionalNames(name);
2647 return std::make_tuple(short_names, long_names, pos_name);
2659 std::vector<std::string> parents{};
2665 std::vector<std::string> inputs{};
2669 std::vector<std::string> tmp = parents;
2670 tmp.emplace_back(name);
2671 return detail::join(tmp,
".");
2678 std::vector<ConfigItem> items{};
2682 virtual std::string to_config(
const App *,
bool,
bool, std::string)
const = 0;
2685 virtual std::vector<ConfigItem> from_config(std::istream &)
const = 0;
2689 if(item.
inputs.size() == 1) {
2690 return item.
inputs.at(0);
2692 if(item.
inputs.empty()) {
2695 throw ConversionError::TooManyInputsFlag(item.
fullname());
2699 CLI11_NODISCARD std::vector<ConfigItem>
from_file(
const std::string &name)
const {
2700 std::ifstream input{name};
2702 throw FileError::Missing(name);
2704 return from_config(input);
2708 virtual ~
Config() =
default;
2715 char commentChar =
'#';
2717 char arrayStart =
'[';
2719 char arrayEnd =
']';
2721 char arraySeparator =
',';
2723 char valueDelimiter =
'=';
2725 char stringQuote =
'"';
2727 char characterQuote =
'\'';
2729 uint8_t maximumLayers{255};
2731 char parentSeparatorChar{
'.'};
2733 int16_t configIndex{-1};
2735 std::string configSection{};
2739 to_config(
const App * ,
bool default_also,
bool write_description, std::string prefix)
const override;
2741 std::vector<ConfigItem> from_config(std::istream &input)
const override;
2744 commentChar = cchar;
2749 arrayStart = aStart;
2755 arraySeparator = aSep;
2760 valueDelimiter = vSep;
2765 stringQuote = qString;
2766 characterQuote = qChar;
2771 maximumLayers = layers;
2776 parentSeparatorChar = sep;
2782 CLI11_NODISCARD
const std::string &
section()
const {
return configSection; }
2785 configSection = sectionName;
2792 CLI11_NODISCARD int16_t
index()
const {
return configIndex; }
2795 configIndex = sectionIndex;
2801 using ConfigTOML = ConfigBase;
2811 arraySeparator =
' ';
2812 valueDelimiter =
'=';
2833 std::function<std::string()> desc_function_{[]() {
return std::string{}; }};
2837 std::function<std::string(std::string &)> func_{[](std::string &) {
return std::string{}; }};
2839 std::string name_{};
2841 int application_index_ = -1;
2845 bool non_modifying_{
false};
2847 Validator(std::string validator_desc, std::function<std::string(std::string &)> func)
2848 : desc_function_([validator_desc]() {
return validator_desc; }), func_(std::move(func)) {}
2851 Validator() =
default;
2853 explicit Validator(std::string validator_desc) : desc_function_([validator_desc]() {
return validator_desc; }) {}
2855 Validator(std::function<std::string(std::string &)> op, std::string validator_desc, std::string validator_name =
"")
2856 : desc_function_([validator_desc]() {
return validator_desc; }), func_(std::move(op)),
2857 name_(std::move(validator_name)) {}
2860 func_ = std::move(op);
2865 std::string operator()(std::string &str)
const;
2870 std::string value = str;
2871 return (active_) ? func_(value) : std::string{};
2876 desc_function_ = [validator_desc]() {
return validator_desc; };
2880 CLI11_NODISCARD
Validator description(std::string validator_desc)
const;
2885 return desc_function_();
2887 return std::string{};
2891 name_ = std::move(validator_name);
2897 newval.
name_ = std::move(validator_name);
2901 CLI11_NODISCARD
const std::string &
get_name()
const {
return name_; }
2904 active_ = active_val;
2916 non_modifying_ = no_modify;
2921 application_index_ = app_index;
2950 void _merge_description(
const Validator &val1,
const Validator &val2,
const std::string &merger);
2963 enum class path_type { nonexistent, file, directory };
2966 CLI11_INLINE path_type check_path(
const char *file) noexcept;
3021 :
Validator(validator_name, [](std::string &input_string) {
3022 auto val = DesiredType();
3023 if(!detail::lexical_cast(input_string, val)) {
3024 return std::string(
"Failed parsing ") + input_string +
" as a " + detail::type_name<DesiredType>();
3026 return std::string();
3038 explicit FileOnDefaultPath(std::string default_path,
bool enableErrorReturn =
true);
3048 template <
typename T>
3049 Range(T min_val, T max_val,
const std::string &validator_name = std::string{}) :
Validator(validator_name) {
3050 if(validator_name.empty()) {
3051 std::stringstream out;
3052 out << detail::type_name<T>() <<
" in [" << min_val <<
" - " << max_val <<
"]";
3053 description(out.str());
3056 func_ = [min_val, max_val](std::string &input) {
3058 bool converted = detail::lexical_cast(input, val);
3059 if((!converted) || (val < min_val || val > max_val)) {
3060 std::stringstream out;
3061 out <<
"Value " << input <<
" not in range [";
3062 out << min_val <<
" - " << max_val <<
"]";
3065 return std::string{};
3070 template <
typename T>
3071 explicit Range(T max_val,
const std::string &validator_name = std::string{})
3072 :
Range(static_cast<T>(0), max_val, validator_name) {}
3076 const Range NonNegativeNumber((std::numeric_limits<double>::max)(),
"NONNEGATIVE");
3079 const Range PositiveNumber((std::numeric_limits<double>::min)(), (std::numeric_limits<double>::max)(),
"POSITIVE");
3088 template <
typename T>
Bound(T min_val, T max_val) {
3089 std::stringstream out;
3090 out << detail::type_name<T>() <<
" bounded to [" << min_val <<
" - " << max_val <<
"]";
3091 description(out.str());
3093 func_ = [min_val, max_val](std::string &input) {
3095 bool converted = detail::lexical_cast(input, val);
3097 return std::string(
"Value ") + input +
" could not be converted";
3100 input = detail::to_string(min_val);
3101 else if(val > max_val)
3102 input = detail::to_string(max_val);
3104 return std::string{};
3109 template <
typename T>
explicit Bound(T max_val) :
Bound(static_cast<T>(0), max_val) {}
3113 template <
typename T,
3114 enable_if_t<is_copyable_ptr<typename std::remove_reference<T>::type>::value, detail::enabler> = detail::dummy>
3115 auto smart_deref(T value) -> decltype(*value) {
3121 enable_if_t<!is_copyable_ptr<typename std::remove_reference<T>::type>::value, detail::enabler> = detail::dummy>
3122 typename std::remove_reference<T>::type &smart_deref(T &value) {
3126 template <
typename T> std::string generate_set(
const T &set) {
3127 using element_t =
typename detail::element_type<T>::type;
3128 using iteration_type_t =
typename detail::pair_adaptor<element_t>::value_type;
3129 std::string out(1,
'{');
3130 out.append(detail::join(
3131 detail::smart_deref(set),
3139 template <
typename T> std::string generate_map(
const T &map,
bool key_only =
false) {
3140 using element_t =
typename detail::element_type<T>::type;
3141 using iteration_type_t =
typename detail::pair_adaptor<element_t>::value_type;
3142 std::string out(1,
'{');
3143 out.append(detail::join(
3144 detail::smart_deref(map),
3145 [key_only](
const iteration_type_t &v) {
3159 template <
typename C,
typename V>
struct has_find {
3160 template <
typename CC,
typename VV>
3161 static auto test(
int) -> decltype(std::declval<CC>().find(std::declval<VV>()), std::true_type());
3162 template <
typename,
typename>
static auto test(...) -> decltype(std::false_type());
3164 static const auto value = decltype(test<C, V>(0))::value;
3165 using type = std::integral_constant<bool, value>;
3169 template <typename T, typename V, enable_if_t<!has_find<T, V>::value, detail::enabler> = detail::dummy>
3170 auto search(
const T &set,
const V &val) -> std::pair<bool, decltype(std::begin(detail::smart_deref(set)))> {
3171 using element_t =
typename detail::element_type<T>::type;
3172 auto &setref = detail::smart_deref(set);
3173 auto it = std::find_if(std::begin(setref), std::end(setref), [&val](decltype(*std::begin(setref)) v) {
3176 return {(it != std::end(setref)), it};
3180 template <typename T, typename V, enable_if_t<has_find<T, V>::value, detail::enabler> = detail::dummy>
3181 auto search(
const T &set,
const V &val) -> std::pair<bool, decltype(std::begin(detail::smart_deref(set)))> {
3182 auto &setref = detail::smart_deref(set);
3183 auto it = setref.find(val);
3184 return {(it != std::end(setref)), it};
3188 template <
typename T,
typename V>
3189 auto search(
const T &set,
const V &val,
const std::function<V(V)> &filter_function)
3190 -> std::pair<bool, decltype(std::begin(detail::smart_deref(set)))> {
3191 using element_t =
typename detail::element_type<T>::type;
3193 auto res = search(set, val);
3194 if((res.first) || (!(filter_function))) {
3198 auto &setref = detail::smart_deref(set);
3199 auto it = std::find_if(std::begin(setref), std::end(setref), [&](decltype(*std::begin(setref)) v) {
3201 a = filter_function(a);
3204 return {(it != std::end(setref)), it};
3211 template <
typename T>
3212 inline typename std::enable_if<std::is_signed<T>::value, T>::type overflowCheck(
const T &a,
const T &b) {
3213 if((a > 0) == (b > 0)) {
3214 return ((std::numeric_limits<T>::max)() / (std::abs)(a) < (std::abs)(b));
3216 return ((std::numeric_limits<T>::min)() / (std::abs)(a) > -(std::abs)(b));
3219 template <
typename T>
3220 inline typename std::enable_if<!std::is_signed<T>::value, T>::type overflowCheck(
const T &a,
const T &b) {
3221 return ((std::numeric_limits<T>::max)() / a < b);
3225 template <
typename T>
typename std::enable_if<std::is_integral<T>::value,
bool>::type checked_multiply(T &a, T b) {
3226 if(a == 0 || b == 0 || a == 1 || b == 1) {
3230 if(a == (std::numeric_limits<T>::min)() || b == (std::numeric_limits<T>::min)()) {
3233 if(overflowCheck(a, b)) {
3241 template <
typename T>
3242 typename std::enable_if<std::is_floating_point<T>::value,
bool>::type checked_multiply(T &a, T b) {
3244 if(std::isinf(c) && !std::isinf(a) && !std::isinf(b)) {
3255 using filter_fn_t = std::function<std::string(std::string)>;
3258 template <
typename T,
typename... Args>
3259 IsMember(std::initializer_list<T> values, Args &&...args)
3260 :
IsMember(std::vector<T>(values), std::forward<Args>(args)...) {}
3267 template <
typename T,
typename F>
explicit IsMember(T set, F filter_function) {
3271 using element_t =
typename detail::element_type<T>::type;
3272 using item_t =
typename detail::pair_adaptor<element_t>::first_type;
3274 using local_item_t =
typename IsMemberType<item_t>::type;
3278 std::function<local_item_t(local_item_t)> filter_fn = filter_function;
3281 desc_function_ = [set]() {
return detail::generate_set(detail::smart_deref(set)); };
3285 func_ = [set, filter_fn](std::string &input) {
3287 if(!detail::lexical_cast(input, b)) {
3293 auto res = detail::search(set, b, filter_fn);
3301 return std::string{};
3305 return input +
" not in " + detail::generate_set(detail::smart_deref(set));
3310 template <
typename T,
typename... Args>
3311 IsMember(T &&set, filter_fn_t filter_fn_1, filter_fn_t filter_fn_2, Args &&...other)
3313 std::forward<T>(set),
3314 [filter_fn_1, filter_fn_2](std::string a) {
return filter_fn_2(filter_fn_1(a)); },
3319 template <
typename T>
using TransformPairs = std::vector<std::pair<std::string, T>>;
3324 using filter_fn_t = std::function<std::string(std::string)>;
3327 template <
typename... Args>
3328 Transformer(std::initializer_list<std::pair<std::string, std::string>> values, Args &&...args)
3329 :
Transformer(TransformPairs<std::string>(values), std::forward<Args>(args)...) {}
3336 template <
typename T,
typename F>
explicit Transformer(T mapping, F filter_function) {
3339 "mapping must produce value pairs");
3342 using element_t =
typename detail::element_type<T>::type;
3343 using item_t =
typename detail::pair_adaptor<element_t>::first_type;
3344 using local_item_t =
typename IsMemberType<item_t>::type;
3348 std::function<local_item_t(local_item_t)> filter_fn = filter_function;
3351 desc_function_ = [mapping]() {
return detail::generate_map(detail::smart_deref(mapping)); };
3353 func_ = [mapping, filter_fn](std::string &input) {
3355 if(!detail::lexical_cast(input, b)) {
3356 return std::string();
3362 auto res = detail::search(mapping, b, filter_fn);
3366 return std::string{};
3371 template <
typename T,
typename... Args>
3372 Transformer(T &&mapping, filter_fn_t filter_fn_1, filter_fn_t filter_fn_2, Args &&...other)
3374 std::forward<T>(mapping),
3375 [filter_fn_1, filter_fn_2](std::string a) {
return filter_fn_2(filter_fn_1(a)); },
3382 using filter_fn_t = std::function<std::string(std::string)>;
3385 template <
typename... Args>
3387 :
CheckedTransformer(TransformPairs<std::string>(values), std::forward<Args>(args)...) {}
3397 "mapping must produce value pairs");
3400 using element_t =
typename detail::element_type<T>::type;
3401 using item_t =
typename detail::pair_adaptor<element_t>::first_type;
3402 using local_item_t =
typename IsMemberType<item_t>::type;
3404 using iteration_type_t =
typename detail::pair_adaptor<element_t>::value_type;
3407 std::function<local_item_t(local_item_t)> filter_fn = filter_function;
3409 auto tfunc = [mapping]() {
3410 std::string out(
"value in ");
3411 out += detail::generate_map(detail::smart_deref(mapping)) +
" OR {";
3412 out += detail::join(
3413 detail::smart_deref(mapping),
3420 desc_function_ = tfunc;
3422 func_ = [mapping, tfunc, filter_fn](std::string &input) {
3424 bool converted = detail::lexical_cast(input, b);
3429 auto res = detail::search(mapping, b, filter_fn);
3432 return std::string{};
3435 for(
const auto &v : detail::smart_deref(mapping)) {
3437 if(output_string == input) {
3438 return std::string();
3442 return "Check " + input +
" " + tfunc() +
" FAILED";
3447 template <
typename T,
typename... Args>
3450 std::forward<T>(mapping),
3451 [filter_fn_1, filter_fn_2](std::string a) {
return filter_fn_2(filter_fn_1(a)); },
3456 inline std::string ignore_case(std::string item) {
return detail::to_lower(item); }
3459 inline std::string ignore_underscore(std::string item) {
return detail::remove_underscore(item); }
3462 inline std::string ignore_space(std::string item) {
3463 item.erase(std::remove(std::begin(item), std::end(item),
' '), std::end(item));
3464 item.erase(std::remove(std::begin(item), std::end(item),
'\t'), std::end(item));
3487 CASE_INSENSITIVE = 1,
3490 DEFAULT = CASE_INSENSITIVE | UNIT_OPTIONAL
3493 template <
typename Number>
3495 Options opts = DEFAULT,
3496 const std::string &unit_name =
"UNIT") {
3497 description(generate_description<Number>(unit_name, opts));
3498 validate_mapping(mapping, opts);
3501 func_ = [mapping, opts](std::string &input) -> std::string {
3504 detail::rtrim(input);
3506 throw ValidationError(
"Input is empty");
3510 auto unit_begin = input.end();
3511 while(unit_begin > input.begin() && std::isalpha(*(unit_begin - 1), std::locale())) {
3515 std::string unit{unit_begin, input.end()};
3516 input.resize(static_cast<std::size_t>(std::distance(input.begin(), unit_begin)));
3517 detail::trim(input);
3519 if(opts & UNIT_REQUIRED && unit.empty()) {
3520 throw ValidationError(
"Missing mandatory unit");
3522 if(opts & CASE_INSENSITIVE) {
3523 unit = detail::to_lower(unit);
3526 if(!detail::lexical_cast(input, num)) {
3527 throw ValidationError(std::string(
"Value ") + input +
" could not be converted to " +
3528 detail::type_name<Number>());
3535 auto it = mapping.find(unit);
3536 if(it == mapping.end()) {
3537 throw ValidationError(unit +
3538 " unit not recognized. " 3539 "Allowed values: " +
3540 detail::generate_map(mapping,
true));
3543 if(!input.empty()) {
3544 bool converted = detail::lexical_cast(input, num);
3546 throw ValidationError(std::string(
"Value ") + input +
" could not be converted to " +
3547 detail::type_name<Number>());
3550 bool ok = detail::checked_multiply(num, it->second);
3552 throw ValidationError(detail::to_string(num) +
" multiplied by " + unit +
3553 " factor would cause number overflow. Use smaller value.");
3556 num = static_cast<Number>(it->second);
3559 input = detail::to_string(num);
3568 template <
typename Number>
static void validate_mapping(std::map<std::string, Number> &mapping, Options opts) {
3569 for(
auto &kv : mapping) {
3570 if(kv.first.empty()) {
3571 throw ValidationError(
"Unit must not be empty.");
3573 if(!detail::isalpha(kv.first)) {
3574 throw ValidationError(
"Unit must contain only letters.");
3579 if(opts & CASE_INSENSITIVE) {
3580 std::map<std::string, Number> lower_mapping;
3581 for(
auto &kv : mapping) {
3582 auto s = detail::to_lower(kv.first);
3583 if(lower_mapping.count(s)) {
3584 throw ValidationError(std::string(
"Several matching lowercase unit representations are found: ") +
3587 lower_mapping[detail::to_lower(kv.first)] = kv.second;
3589 mapping = std::move(lower_mapping);
3594 template <
typename Number>
static std::string generate_description(
const std::string &name, Options opts) {
3595 std::stringstream out;
3596 out << detail::type_name<Number>() <<
' ';
3597 if(opts & UNIT_REQUIRED) {
3600 out <<
'[' << name <<
']';
3607 return static_cast<AsNumberWithUnit::Options>(static_cast<int>(a) | static_cast<int>(b));
3623 using result_t = std::uint64_t;
3636 static std::map<std::string, result_t> init_mapping(
bool kb_is_1000);
3639 static std::map<std::string, result_t> get_mapping(
bool kb_is_1000);
3647 CLI11_INLINE std::pair<std::string, std::string> split_program_name(std::string commandline);
3656 std::string retstring;
3658 if(non_modifying_) {
3659 std::string value = str;
3660 retstring = func_(value);
3662 retstring = func_(str);
3670 newval.
desc_function_ = [validator_desc]() {
return validator_desc; };
3677 newval._merge_description(*
this, other,
" AND ");
3680 const std::function<std::string(std::string & filename)> &f1 = func_;
3681 const std::function<std::string(std::string & filename)> &f2 = other.
func_;
3683 newval.
func_ = [f1, f2](std::string &input) {
3684 std::string s1 = f1(input);
3685 std::string s2 = f2(input);
3686 if(!s1.empty() && !s2.empty())
3687 return std::string(
"(") + s1 +
") AND (" + s2 +
")";
3699 newval._merge_description(*
this, other,
" OR ");
3702 const std::function<std::string(std::string &)> &f1 = func_;
3703 const std::function<std::string(std::string &)> &f2 = other.
func_;
3705 newval.
func_ = [f1, f2](std::string &input) {
3706 std::string s1 = f1(input);
3707 std::string s2 = f2(input);
3708 if(s1.empty() || s2.empty())
3709 return std::string();
3711 return std::string(
"(") + s1 +
") OR (" + s2 +
")";
3720 const std::function<std::string()> &dfunc1 = desc_function_;
3722 auto str = dfunc1();
3723 return (!str.empty()) ? std::string(
"NOT ") + str : std::string{};
3726 const std::function<std::string(std::string & res)> &f1 = func_;
3728 newval.
func_ = [f1, dfunc1](std::string &test) -> std::string {
3729 std::string s1 = f1(test);
3731 return std::string(
"check ") + dfunc1() +
" succeeded improperly";
3733 return std::string{};
3741 Validator::_merge_description(
const Validator &val1,
const Validator &val2,
const std::string &merger) {
3743 const std::function<std::string()> &dfunc1 = val1.
desc_function_;
3744 const std::function<std::string()> &dfunc2 = val2.
desc_function_;
3746 desc_function_ = [=]() {
3747 std::string f1 = dfunc1();
3748 std::string f2 = dfunc2();
3749 if((f1.empty()) || (f2.empty())) {
3752 return std::string(1,
'(') + f1 +
')' + merger +
'(' + f2 +
')';
3758 #if defined CLI11_HAS_FILESYSTEM && CLI11_HAS_FILESYSTEM > 0 3759 CLI11_INLINE path_type check_path(
const char *file) noexcept {
3761 auto stat = std::filesystem::status(file, ec);
3763 return path_type::nonexistent;
3765 switch(stat.type()) {
3766 case std::filesystem::file_type::none:
3767 case std::filesystem::file_type::not_found:
3768 return path_type::nonexistent;
3769 case std::filesystem::file_type::directory:
3770 return path_type::directory;
3771 case std::filesystem::file_type::symlink:
3772 case std::filesystem::file_type::block:
3773 case std::filesystem::file_type::character:
3774 case std::filesystem::file_type::fifo:
3775 case std::filesystem::file_type::socket:
3776 case std::filesystem::file_type::regular:
3777 case std::filesystem::file_type::unknown:
3779 return path_type::file;
3783 CLI11_INLINE path_type check_path(
const char *file) noexcept {
3784 #if defined(_MSC_VER) 3785 struct __stat64 buffer;
3786 if(_stat64(file, &buffer) == 0) {
3787 return ((buffer.st_mode & S_IFDIR) != 0) ? path_type::directory : path_type::file;
3791 if(stat(file, &buffer) == 0) {
3792 return ((buffer.st_mode & S_IFDIR) != 0) ? path_type::directory : path_type::file;
3795 return path_type::nonexistent;
3799 CLI11_INLINE ExistingFileValidator::ExistingFileValidator() : Validator(
"FILE") {
3800 func_ = [](std::string &filename) {
3801 auto path_result = check_path(filename.c_str());
3802 if(path_result == path_type::nonexistent) {
3803 return "File does not exist: " + filename;
3805 if(path_result == path_type::directory) {
3806 return "File is actually a directory: " + filename;
3808 return std::string();
3812 CLI11_INLINE ExistingDirectoryValidator::ExistingDirectoryValidator() : Validator(
"DIR") {
3813 func_ = [](std::string &filename) {
3814 auto path_result = check_path(filename.c_str());
3815 if(path_result == path_type::nonexistent) {
3816 return "Directory does not exist: " + filename;
3818 if(path_result == path_type::file) {
3819 return "Directory is actually a file: " + filename;
3821 return std::string();
3825 CLI11_INLINE ExistingPathValidator::ExistingPathValidator() : Validator(
"PATH(existing)") {
3826 func_ = [](std::string &filename) {
3827 auto path_result = check_path(filename.c_str());
3828 if(path_result == path_type::nonexistent) {
3829 return "Path does not exist: " + filename;
3831 return std::string();
3835 CLI11_INLINE NonexistentPathValidator::NonexistentPathValidator() : Validator(
"PATH(non-existing)") {
3836 func_ = [](std::string &filename) {
3837 auto path_result = check_path(filename.c_str());
3838 if(path_result != path_type::nonexistent) {
3839 return "Path already exists: " + filename;
3841 return std::string();
3845 CLI11_INLINE IPV4Validator::IPV4Validator() : Validator(
"IPV4") {
3846 func_ = [](std::string &ip_addr) {
3847 auto result = CLI::detail::split(ip_addr,
'.');
3848 if(result.size() != 4) {
3849 return std::string(
"Invalid IPV4 address must have four parts (") + ip_addr +
')';
3852 for(
const auto &var : result) {
3853 bool retval = detail::lexical_cast(var, num);
3855 return std::string(
"Failed parsing number (") + var +
')';
3857 if(num < 0 || num > 255) {
3858 return std::string(
"Each IP number must be between 0 and 255 ") + var;
3861 return std::string();
3867 CLI11_INLINE FileOnDefaultPath::FileOnDefaultPath(std::string default_path,
bool enableErrorReturn)
3868 : Validator(
"FILE") {
3869 func_ = [default_path, enableErrorReturn](std::string &filename) {
3870 auto path_result = detail::check_path(filename.c_str());
3871 if(path_result == detail::path_type::nonexistent) {
3872 std::string test_file_path = default_path;
3873 if(default_path.back() !=
'/' && default_path.back() !=
'\\') {
3875 test_file_path +=
'/';
3877 test_file_path.append(filename);
3878 path_result = detail::check_path(test_file_path.c_str());
3879 if(path_result == detail::path_type::file) {
3880 filename = test_file_path;
3882 if(enableErrorReturn) {
3883 return "File does not exist: " + filename;
3887 return std::string{};
3893 description(
"SIZE [b, kb(=1000b), kib(=1024b), ...]");
3899 CLI11_INLINE std::map<std::string, AsSizeValue::result_t> AsSizeValue::init_mapping(
bool kb_is_1000) {
3900 std::map<std::string, result_t> m;
3901 result_t k_factor = kb_is_1000 ? 1000 : 1024;
3902 result_t ki_factor = 1024;
3906 for(std::string p : {
"k",
"m",
"g",
"t",
"p",
"e"}) {
3917 CLI11_INLINE std::map<std::string, AsSizeValue::result_t> AsSizeValue::get_mapping(
bool kb_is_1000) {
3919 static auto m = init_mapping(
true);
3922 static auto m = init_mapping(
false);
3928 CLI11_INLINE std::pair<std::string, std::string> split_program_name(std::string commandline) {
3930 std::pair<std::string, std::string> vals;
3932 auto esp = commandline.find_first_of(
' ', 1);
3933 while(detail::check_path(commandline.substr(0, esp).c_str()) != path_type::file) {
3934 esp = commandline.find_first_of(
' ', esp + 1);
3935 if(esp == std::string::npos) {
3938 if(commandline[0] ==
'"' || commandline[0] ==
'\'' || commandline[0] ==
'`') {
3939 bool embeddedQuote =
false;
3940 auto keyChar = commandline[0];
3941 auto end = commandline.find_first_of(keyChar, 1);
3942 while((end != std::string::npos) && (commandline[end - 1] ==
'\\')) {
3943 end = commandline.find_first_of(keyChar, end + 1);
3944 embeddedQuote =
true;
3946 if(end != std::string::npos) {
3947 vals.first = commandline.substr(1, end - 1);
3950 vals.first = find_and_replace(vals.first, std::string(
"\\") + keyChar, std::string(1, keyChar));
3953 esp = commandline.find_first_of(
' ', 1);
3956 esp = commandline.find_first_of(
' ', 1);
3962 if(vals.first.empty()) {
3963 vals.first = commandline.substr(0, esp);
3968 vals.second = (esp < commandline.length() - 1) ? commandline.substr(esp + 1) : std::string{};
3987 enum class AppFormatMode {
4024 virtual std::string
make_help(
const App *, std::string, AppFormatMode)
const = 0;
4041 CLI11_NODISCARD std::string
get_label(std::string key)
const {
4055 using funct_t = std::function<std::string(
const App *, std::string, AppFormatMode)>;
4068 std::string
make_help(
const App *app, std::string name, AppFormatMode mode)
const override {
4069 return lambda_(app, name, mode);
4088 CLI11_NODISCARD
virtual std::string
4089 make_group(std::string group,
bool is_positional, std::vector<const Option *> opts)
const;
4095 std::string
make_groups(
const App *app, AppFormatMode mode)
const;
4113 virtual std::string
make_usage(
const App *app, std::string name)
const;
4116 std::string
make_help(
const App * , std::string, AppFormatMode)
const override;
4123 virtual std::string
make_option(
const Option *opt,
bool is_positional)
const {
4124 std::stringstream out;
4125 detail::format_help(
4148 using results_t = std::vector<std::string>;
4150 using callback_t = std::function<bool(
const results_t &)>;
4155 using Option_p = std::unique_ptr<Option>;
4157 enum class MultiOptionPolicy : char {
4200 template <
typename T>
void copy_to(T *other)
const;
4207 if(!detail::valid_alias_name_string(name)) {
4211 return static_cast<CRTP *>(
this);
4217 return static_cast<CRTP *>(
this);
4223 CRTP *always_capture_default(
bool value =
true) {
4225 return static_cast<CRTP *>(
this);
4261 auto *
self = static_cast<CRTP *>(
this);
4262 self->multi_option_policy(MultiOptionPolicy::TakeLast);
4268 auto *
self = static_cast<CRTP *>(
this);
4269 self->multi_option_policy(MultiOptionPolicy::TakeFirst);
4275 auto self = static_cast<CRTP *>(
this);
4276 self->multi_option_policy(MultiOptionPolicy::TakeAll);
4282 auto *
self = static_cast<CRTP *>(
this);
4283 self->multi_option_policy(MultiOptionPolicy::Join);
4289 auto self = static_cast<CRTP *>(
this);
4290 self->delimiter_ = delim;
4291 self->multi_option_policy(MultiOptionPolicy::Join);
4298 return static_cast<CRTP *>(
this);
4304 return static_cast<CRTP *>(
this);
4347 class Option :
public OptionBase<Option> {
4355 std::vector<std::string> snames_{};
4358 std::vector<std::string> lnames_{};
4362 std::vector<std::pair<std::string, std::string>> default_flag_values_{};
4365 std::vector<std::string> fnames_{};
4368 std::string pname_{};
4371 std::string envname_{};
4378 std::string description_{};
4381 std::string default_str_{};
4384 std::string option_text_{};
4389 std::function<std::string()> type_name_{[]() {
return std::string(); }};
4392 std::function<std::string()> default_function_{};
4400 int type_size_max_{1};
4402 int type_size_min_{1};
4405 int expected_min_{1};
4407 int expected_max_{1};
4410 std::vector<Validator> validators_{};
4413 std::set<Option *> needs_{};
4416 std::set<Option *> excludes_{};
4423 App *parent_{
nullptr};
4426 callback_t callback_{};
4433 results_t results_{};
4435 results_t proc_results_{};
4437 enum class option_state : char {
4444 option_state current_option_state_{option_state::parsing};
4446 bool allow_extra_args_{
false};
4448 bool flag_like_{
false};
4450 bool run_callback_for_default_{
false};
4452 bool inject_separator_{
false};
4454 bool trigger_on_result_{
false};
4456 bool force_callback_{
false};
4460 Option(std::string option_name, std::string option_description, callback_t callback, App *parent)
4461 : description_(std::move(option_description)), parent_(parent), callback_(std::move(callback)) {
4462 std::tie(snames_, lnames_, pname_) = detail::get_names(detail::split_names(option_name));
4469 Option(
const Option &) =
delete;
4470 Option &operator=(
const Option &) =
delete;
4473 CLI11_NODISCARD std::size_t count()
const {
return results_.size(); }
4476 CLI11_NODISCARD
bool empty()
const {
return results_.empty(); }
4479 explicit operator bool()
const {
return !empty() || force_callback_; }
4484 current_option_state_ = option_state::parsing;
4492 Option *expected(
int value);
4495 Option *expected(
int value_min,
int value_max);
4499 Option *allow_extra_args(
bool value =
true) {
4500 allow_extra_args_ = value;
4504 CLI11_NODISCARD
bool get_allow_extra_args()
const {
return allow_extra_args_; }
4506 Option *trigger_on_parse(
bool value =
true) {
4507 trigger_on_result_ = value;
4511 CLI11_NODISCARD
bool get_trigger_on_parse()
const {
return trigger_on_result_; }
4514 Option *force_callback(
bool value =
true) {
4515 force_callback_ = value;
4519 CLI11_NODISCARD
bool get_force_callback()
const {
return force_callback_; }
4523 Option *run_callback_for_default(
bool value =
true) {
4524 run_callback_for_default_ = value;
4528 CLI11_NODISCARD
bool get_run_callback_for_default()
const {
return run_callback_for_default_; }
4531 Option *check(Validator validator,
const std::string &validator_name =
"");
4534 Option *check(std::function<std::string(
const std::string &)> Validator,
4535 std::string Validator_description =
"",
4536 std::string Validator_name =
"");
4539 Option *transform(Validator Validator,
const std::string &Validator_name =
"");
4542 Option *transform(
const std::function<std::string(std::string)> &func,
4543 std::string transform_description =
"",
4544 std::string transform_name =
"");
4547 Option *each(
const std::function<
void(std::string)> &func);
4550 Validator *get_validator(
const std::string &Validator_name =
"");
4553 Validator *get_validator(
int index);
4556 Option *needs(Option *opt) {
4564 template <
typename T = App> Option *needs(std::string opt_name) {
4565 auto opt = static_cast<T *>(parent_)->get_option_no_throw(opt_name);
4566 if(opt ==
nullptr) {
4567 throw IncorrectConstruction::MissingOption(opt_name);
4573 template <
typename A,
typename B,
typename... ARG> Option *needs(A opt, B opt1, ARG... args) {
4575 return needs(opt1, args...);
4579 bool remove_needs(Option *opt);
4582 Option *excludes(Option *opt);
4585 template <
typename T = App> Option *excludes(std::string opt_name) {
4586 auto opt = static_cast<T *>(parent_)->get_option_no_throw(opt_name);
4587 if(opt ==
nullptr) {
4588 throw IncorrectConstruction::MissingOption(opt_name);
4590 return excludes(opt);
4594 template <
typename A,
typename B,
typename... ARG> Option *excludes(A opt, B opt1, ARG... args) {
4596 return excludes(opt1, args...);
4600 bool remove_excludes(Option *opt);
4603 Option *envname(std::string name) {
4604 envname_ = std::move(name);
4612 template <
typename T = App> Option *ignore_case(
bool value =
true);
4618 template <
typename T = App> Option *ignore_underscore(
bool value =
true);
4621 Option *multi_option_policy(MultiOptionPolicy value = MultiOptionPolicy::Throw);
4624 Option *disable_flag_override(
bool value =
true) {
4633 CLI11_NODISCARD
int get_type_size()
const {
return type_size_min_; }
4636 CLI11_NODISCARD
int get_type_size_min()
const {
return type_size_min_; }
4638 CLI11_NODISCARD
int get_type_size_max()
const {
return type_size_max_; }
4641 CLI11_NODISCARD
bool get_inject_separator()
const {
return inject_separator_; }
4644 CLI11_NODISCARD std::string get_envname()
const {
return envname_; }
4647 CLI11_NODISCARD std::set<Option *> get_needs()
const {
return needs_; }
4650 CLI11_NODISCARD std::set<Option *> get_excludes()
const {
return excludes_; }
4653 CLI11_NODISCARD std::string get_default_str()
const {
return default_str_; }
4656 CLI11_NODISCARD callback_t get_callback()
const {
return callback_; }
4659 CLI11_NODISCARD
const std::vector<std::string> &get_lnames()
const {
return lnames_; }
4662 CLI11_NODISCARD
const std::vector<std::string> &get_snames()
const {
return snames_; }
4665 CLI11_NODISCARD
const std::vector<std::string> &get_fnames()
const {
return fnames_; }
4667 CLI11_NODISCARD
const std::string &get_single_name()
const {
4668 if(!lnames_.empty()) {
4671 if(!pname_.empty()) {
4674 if(!snames_.empty()) {
4680 CLI11_NODISCARD
int get_expected()
const {
return expected_min_; }
4683 CLI11_NODISCARD
int get_expected_min()
const {
return expected_min_; }
4685 CLI11_NODISCARD
int get_expected_max()
const {
return expected_max_; }
4688 CLI11_NODISCARD
int get_items_expected_min()
const {
return type_size_min_ * expected_min_; }
4691 CLI11_NODISCARD
int get_items_expected_max()
const {
4692 int t = type_size_max_;
4693 return detail::checked_multiply(t, expected_max_) ? t : detail::expected_max_vector_size;
4696 CLI11_NODISCARD
int get_items_expected()
const {
return get_items_expected_min(); }
4699 CLI11_NODISCARD
bool get_positional()
const {
return pname_.length() > 0; }
4702 CLI11_NODISCARD
bool nonpositional()
const {
return (snames_.size() + lnames_.size()) > 0; }
4705 CLI11_NODISCARD
bool has_description()
const {
return description_.length() > 0; }
4708 CLI11_NODISCARD
const std::string &get_description()
const {
return description_; }
4711 Option *description(std::string option_description) {
4712 description_ = std::move(option_description);
4716 Option *option_text(std::string text) {
4717 option_text_ = std::move(text);
4721 CLI11_NODISCARD
const std::string &get_option_text()
const {
return option_text_; }
4731 CLI11_NODISCARD std::string get_name(
bool positional =
false,
4732 bool all_options =
false 4740 void run_callback();
4743 CLI11_NODISCARD
const std::string &matching_name(
const Option &other)
const;
4746 bool operator==(
const Option &other)
const {
return !matching_name(other).empty(); }
4749 CLI11_NODISCARD
bool check_name(
const std::string &name)
const;
4752 CLI11_NODISCARD
bool check_sname(std::string name)
const {
4753 return (detail::find_member(std::move(name), snames_, ignore_case_) >= 0);
4757 CLI11_NODISCARD
bool check_lname(std::string name)
const {
4758 return (detail::find_member(std::move(name), lnames_, ignore_case_, ignore_underscore_) >= 0);
4762 CLI11_NODISCARD
bool check_fname(std::string name)
const {
4763 if(fnames_.empty()) {
4766 return (detail::find_member(std::move(name), fnames_, ignore_case_, ignore_underscore_) >= 0);
4771 CLI11_NODISCARD std::string get_flag_value(
const std::string &name, std::string input_value)
const;
4774 Option *add_result(std::string s);
4777 Option *add_result(std::string s,
int &results_added);
4780 Option *add_result(std::vector<std::string> s);
4783 CLI11_NODISCARD
const results_t &results()
const {
return results_; }
4786 CLI11_NODISCARD results_t reduced_results()
const;
4789 template <
typename T>
void results(T &output)
const {
4790 bool retval =
false;
4791 if(current_option_state_ >= option_state::reduced || (results_.size() == 1 && validators_.empty())) {
4792 const results_t &res = (proc_results_.empty()) ? results_ : proc_results_;
4793 retval = detail::lexical_conversion<T, T>(res, output);
4796 if(results_.empty()) {
4797 if(!default_str_.empty()) {
4799 _add_result(std::string(default_str_), res);
4800 _validate_results(res);
4802 _reduce_results(extra, res);
4803 if(!extra.empty()) {
4804 res = std::move(extra);
4810 res = reduced_results();
4812 retval = detail::lexical_conversion<T, T>(res, output);
4815 throw ConversionError(get_name(), results_);
4820 template <
typename T> CLI11_NODISCARD T as()
const {
4827 CLI11_NODISCARD
bool get_callback_run()
const {
return (current_option_state_ == option_state::callback_run); }
4834 Option *type_name_fn(std::function<std::string()> typefun) {
4835 type_name_ = std::move(typefun);
4840 Option *type_name(std::string typeval) {
4841 type_name_fn([typeval]() {
return typeval; });
4846 Option *type_size(
int option_type_size);
4849 Option *type_size(
int option_type_size_min,
int option_type_size_max);
4852 void inject_separator(
bool value =
true) { inject_separator_ = value; }
4855 Option *default_function(
const std::function<std::string()> &func) {
4856 default_function_ = func;
4861 Option *capture_default_str() {
4862 if(default_function_) {
4863 default_str_ = default_function_();
4869 Option *default_str(std::string val) {
4870 default_str_ = std::move(val);
4876 template <
typename X> Option *default_val(
const X &val) {
4877 std::string val_str = detail::to_string(val);
4878 auto old_option_state = current_option_state_;
4879 results_t old_results{std::move(results_)};
4882 add_result(val_str);
4884 if(run_callback_for_default_ && !trigger_on_result_) {
4886 current_option_state_ = option_state::parsing;
4888 _validate_results(results_);
4889 current_option_state_ = old_option_state;
4891 }
catch(
const CLI::Error &) {
4893 results_ = std::move(old_results);
4894 current_option_state_ = old_option_state;
4897 results_ = std::move(old_results);
4898 default_str_ = std::move(val_str);
4903 CLI11_NODISCARD std::string get_type_name()
const;
4907 void _validate_results(results_t &res)
const;
4912 void _reduce_results(results_t &out,
const results_t &original)
const;
4915 std::string _validate(std::string &result,
int index)
const;
4918 int _add_result(std::string &&result, std::vector<std::string> &res)
const;
4925 other->group(group_);
4926 other->required(required_);
4927 other->ignore_case(ignore_case_);
4928 other->ignore_underscore(ignore_underscore_);
4929 other->configurable(configurable_);
4930 other->disable_flag_override(disable_flag_override_);
4931 other->delimiter(delimiter_);
4932 other->always_capture_default(always_capture_default_);
4933 other->multi_option_policy(multi_option_policy_);
4936 CLI11_INLINE Option *Option::expected(
int value) {
4938 expected_min_ = -value;
4939 if(expected_max_ < expected_min_) {
4940 expected_max_ = expected_min_;
4942 allow_extra_args_ =
true;
4944 }
else if(value == detail::expected_max_vector_size) {
4946 expected_max_ = detail::expected_max_vector_size;
4947 allow_extra_args_ =
true;
4950 expected_min_ = value;
4951 expected_max_ = value;
4952 flag_like_ = (expected_min_ == 0);
4957 CLI11_INLINE Option *Option::expected(
int value_min,
int value_max) {
4959 value_min = -value_min;
4963 value_max = detail::expected_max_vector_size;
4965 if(value_max < value_min) {
4966 expected_min_ = value_max;
4967 expected_max_ = value_min;
4969 expected_max_ = value_max;
4970 expected_min_ = value_min;
4976 CLI11_INLINE Option *Option::check(Validator validator,
const std::string &validator_name) {
4977 validator.non_modifying();
4978 validators_.push_back(std::move(validator));
4979 if(!validator_name.empty())
4980 validators_.back().name(validator_name);
4984 CLI11_INLINE Option *Option::check(std::function<std::string(
const std::string &)> Validator,
4985 std::string Validator_description,
4986 std::string Validator_name) {
4987 validators_.emplace_back(Validator, std::move(Validator_description), std::move(Validator_name));
4988 validators_.back().non_modifying();
4992 CLI11_INLINE Option *Option::transform(Validator Validator,
const std::string &Validator_name) {
4993 validators_.insert(validators_.begin(), std::move(Validator));
4994 if(!Validator_name.empty())
4995 validators_.front().name(Validator_name);
4999 CLI11_INLINE Option *Option::transform(
const std::function<std::string(std::string)> &func,
5000 std::string transform_description,
5001 std::string transform_name) {
5002 validators_.insert(validators_.begin(),
5004 [func](std::string &val) {
5006 return std::string{};
5008 std::move(transform_description),
5009 std::move(transform_name)));
5014 CLI11_INLINE Option *Option::each(
const std::function<
void(std::string)> &func) {
5015 validators_.emplace_back(
5016 [func](std::string &inout) {
5018 return std::string{};
5024 CLI11_INLINE Validator *Option::get_validator(
const std::string &Validator_name) {
5025 for(
auto &Validator : validators_) {
5026 if(Validator_name == Validator.get_name()) {
5030 if((Validator_name.empty()) && (!validators_.empty())) {
5031 return &(validators_.front());
5033 throw OptionNotFound(std::string{
"Validator "} + Validator_name +
" Not Found");
5036 CLI11_INLINE Validator *Option::get_validator(
int index) {
5038 if(index >= 0 && index < static_cast<int>(validators_.size())) {
5039 return &(validators_[static_cast<decltype(validators_)::size_type>(index)]);
5041 throw OptionNotFound(
"Validator index is not valid");
5044 CLI11_INLINE
bool Option::remove_needs(Option *opt) {
5045 auto iterator = std::find(std::begin(needs_), std::end(needs_), opt);
5047 if(iterator == std::end(needs_)) {
5050 needs_.erase(iterator);
5054 CLI11_INLINE Option *Option::excludes(Option *opt) {
5056 throw(IncorrectConstruction(
"and option cannot exclude itself"));
5058 excludes_.insert(opt);
5061 opt->excludes_.insert(
this);
5069 CLI11_INLINE
bool Option::remove_excludes(Option *opt) {
5070 auto iterator = std::find(std::begin(excludes_), std::end(excludes_), opt);
5072 if(iterator == std::end(excludes_)) {
5075 excludes_.erase(iterator);
5079 template <
typename T> Option *Option::ignore_case(
bool value) {
5080 if(!ignore_case_ && value) {
5081 ignore_case_ = value;
5082 auto *parent = static_cast<T *>(parent_);
5083 for(
const Option_p &opt : parent->options_) {
5084 if(opt.get() ==
this) {
5087 const auto &omatch = opt->matching_name(*
this);
5088 if(!omatch.empty()) {
5089 ignore_case_ =
false;
5090 throw OptionAlreadyAdded(
"adding ignore case caused a name conflict with " + omatch);
5094 ignore_case_ = value;
5099 template <
typename T> Option *Option::ignore_underscore(
bool value) {
5101 if(!ignore_underscore_ && value) {
5102 ignore_underscore_ = value;
5103 auto *parent = static_cast<T *>(parent_);
5104 for(
const Option_p &opt : parent->options_) {
5105 if(opt.get() ==
this) {
5108 const auto &omatch = opt->matching_name(*
this);
5109 if(!omatch.empty()) {
5110 ignore_underscore_ =
false;
5111 throw OptionAlreadyAdded(
"adding ignore underscore caused a name conflict with " + omatch);
5115 ignore_underscore_ = value;
5120 CLI11_INLINE Option *Option::multi_option_policy(MultiOptionPolicy value) {
5121 if(value != multi_option_policy_) {
5122 if(multi_option_policy_ == MultiOptionPolicy::Throw && expected_max_ == detail::expected_max_vector_size &&
5123 expected_min_ > 1) {
5125 expected_max_ = expected_min_;
5127 multi_option_policy_ = value;
5128 current_option_state_ = option_state::parsing;
5133 CLI11_NODISCARD CLI11_INLINE std::string Option::get_name(
bool positional,
bool all_options)
const {
5134 if(get_group().empty())
5139 std::vector<std::string> name_list;
5142 if((positional && (!pname_.empty())) || (snames_.empty() && lnames_.empty())) {
5143 name_list.push_back(pname_);
5145 if((get_items_expected() == 0) && (!fnames_.empty())) {
5146 for(
const std::string &sname : snames_) {
5147 name_list.push_back(
"-" + sname);
5148 if(check_fname(sname)) {
5149 name_list.back() +=
"{" + get_flag_value(sname,
"") +
"}";
5153 for(
const std::string &lname : lnames_) {
5154 name_list.push_back(
"--" + lname);
5155 if(check_fname(lname)) {
5156 name_list.back() +=
"{" + get_flag_value(lname,
"") +
"}";
5160 for(
const std::string &sname : snames_)
5161 name_list.push_back(
"-" + sname);
5163 for(
const std::string &lname : lnames_)
5164 name_list.push_back(
"--" + lname);
5167 return detail::join(name_list);
5175 if(!lnames_.empty())
5176 return std::string(2,
'-') + lnames_[0];
5179 if(!snames_.empty())
5180 return std::string(1,
'-') + snames_[0];
5186 CLI11_INLINE
void Option::run_callback() {
5187 if(force_callback_ && results_.empty()) {
5188 add_result(default_str_);
5190 if(current_option_state_ == option_state::parsing) {
5191 _validate_results(results_);
5192 current_option_state_ = option_state::validated;
5195 if(current_option_state_ < option_state::reduced) {
5196 _reduce_results(proc_results_, results_);
5197 current_option_state_ = option_state::reduced;
5199 if(current_option_state_ >= option_state::reduced) {
5200 current_option_state_ = option_state::callback_run;
5204 const results_t &send_results = proc_results_.empty() ? results_ : proc_results_;
5205 bool local_result = callback_(send_results);
5208 throw ConversionError(get_name(), results_);
5212 CLI11_NODISCARD CLI11_INLINE
const std::string &Option::matching_name(
const Option &other)
const {
5213 static const std::string estring;
5214 for(
const std::string &sname : snames_)
5215 if(other.check_sname(sname))
5217 for(
const std::string &lname : lnames_)
5218 if(other.check_lname(lname))
5222 ignore_underscore_) {
5223 for(
const std::string &sname : other.snames_)
5224 if(check_sname(sname))
5226 for(
const std::string &lname : other.lnames_)
5227 if(check_lname(lname))
5233 CLI11_NODISCARD CLI11_INLINE
bool Option::check_name(
const std::string &name)
const {
5235 if(name.length() > 2 && name[0] ==
'-' && name[1] ==
'-')
5236 return check_lname(name.substr(2));
5237 if(name.length() > 1 && name.front() ==
'-')
5238 return check_sname(name.substr(1));
5239 if(!pname_.empty()) {
5240 std::string local_pname = pname_;
5241 std::string local_name = name;
5242 if(ignore_underscore_) {
5243 local_pname = detail::remove_underscore(local_pname);
5244 local_name = detail::remove_underscore(local_name);
5247 local_pname = detail::to_lower(local_pname);
5248 local_name = detail::to_lower(local_name);
5250 if(local_name == local_pname) {
5255 if(!envname_.empty()) {
5257 return (name == envname_);
5262 CLI11_NODISCARD CLI11_INLINE std::string Option::get_flag_value(
const std::string &name,
5263 std::string input_value)
const {
5264 static const std::string trueString{
"true"};
5265 static const std::string falseString{
"false"};
5266 static const std::string emptyString{
"{}"};
5268 if(disable_flag_override_) {
5269 if(!((input_value.empty()) || (input_value == emptyString))) {
5270 auto default_ind = detail::find_member(name, fnames_, ignore_case_, ignore_underscore_);
5271 if(default_ind >= 0) {
5273 if(default_flag_values_[static_cast<std::size_t>(default_ind)].second != input_value) {
5274 throw(ArgumentMismatch::FlagOverride(name));
5277 if(input_value != trueString) {
5278 throw(ArgumentMismatch::FlagOverride(name));
5283 auto ind = detail::find_member(name, fnames_, ignore_case_, ignore_underscore_);
5284 if((input_value.empty()) || (input_value == emptyString)) {
5286 return (ind < 0) ? trueString : default_flag_values_[static_cast<std::size_t>(ind)].second;
5288 return (ind < 0) ? default_str_ : default_flag_values_[static_cast<std::size_t>(ind)].second;
5293 if(default_flag_values_[static_cast<std::size_t>(ind)].second == falseString) {
5295 auto val = detail::to_flag_value(input_value);
5296 return (val == 1) ? falseString : (val == (-1) ? trueString : std::to_string(-val));
5297 }
catch(
const std::invalid_argument &) {
5305 CLI11_INLINE Option *Option::add_result(std::string s) {
5306 _add_result(std::move(s), results_);
5307 current_option_state_ = option_state::parsing;
5311 CLI11_INLINE Option *Option::add_result(std::string s,
int &results_added) {
5312 results_added = _add_result(std::move(s), results_);
5313 current_option_state_ = option_state::parsing;
5317 CLI11_INLINE Option *Option::add_result(std::vector<std::string> s) {
5318 current_option_state_ = option_state::parsing;
5319 for(
auto &str : s) {
5320 _add_result(std::move(str), results_);
5325 CLI11_NODISCARD CLI11_INLINE results_t Option::reduced_results()
const {
5326 results_t res = proc_results_.empty() ? results_ : proc_results_;
5327 if(current_option_state_ < option_state::reduced) {
5328 if(current_option_state_ == option_state::parsing) {
5330 _validate_results(res);
5334 _reduce_results(extra, res);
5335 if(!extra.empty()) {
5336 res = std::move(extra);
5343 CLI11_INLINE Option *Option::type_size(
int option_type_size) {
5344 if(option_type_size < 0) {
5346 type_size_max_ = -option_type_size;
5347 type_size_min_ = -option_type_size;
5348 expected_max_ = detail::expected_max_vector_size;
5350 type_size_max_ = option_type_size;
5351 if(type_size_max_ < detail::expected_max_vector_size) {
5352 type_size_min_ = option_type_size;
5354 inject_separator_ =
true;
5356 if(type_size_max_ == 0)
5362 CLI11_INLINE Option *Option::type_size(
int option_type_size_min,
int option_type_size_max) {
5363 if(option_type_size_min < 0 || option_type_size_max < 0) {
5365 expected_max_ = detail::expected_max_vector_size;
5366 option_type_size_min = (std::abs)(option_type_size_min);
5367 option_type_size_max = (std::abs)(option_type_size_max);
5370 if(option_type_size_min > option_type_size_max) {
5371 type_size_max_ = option_type_size_min;
5372 type_size_min_ = option_type_size_max;
5374 type_size_min_ = option_type_size_min;
5375 type_size_max_ = option_type_size_max;
5377 if(type_size_max_ == 0) {
5380 if(type_size_max_ >= detail::expected_max_vector_size) {
5381 inject_separator_ =
true;
5386 CLI11_NODISCARD CLI11_INLINE std::string Option::get_type_name()
const {
5387 std::string full_type_name = type_name_();
5388 if(!validators_.empty()) {
5389 for(
const auto &Validator : validators_) {
5390 std::string vtype = Validator.get_description();
5391 if(!vtype.empty()) {
5392 full_type_name +=
":" + vtype;
5396 return full_type_name;
5399 CLI11_INLINE
void Option::_validate_results(results_t &res)
const {
5401 if(!validators_.empty()) {
5402 if(type_size_max_ > 1) {
5404 if(get_items_expected_max() < static_cast<int>(res.size()) &&
5405 multi_option_policy_ == CLI::MultiOptionPolicy::TakeLast) {
5407 index = get_items_expected_max() - static_cast<int>(res.size());
5410 for(std::string &result : res) {
5411 if(detail::is_separator(result) && type_size_max_ != type_size_min_ && index >= 0) {
5415 auto err_msg = _validate(result, (index >= 0) ? (index % type_size_max_) : index);
5416 if(!err_msg.empty())
5417 throw ValidationError(get_name(), err_msg);
5422 if(expected_max_ < static_cast<int>(res.size()) &&
5423 multi_option_policy_ == CLI::MultiOptionPolicy::TakeLast) {
5425 index = expected_max_ - static_cast<int>(res.size());
5427 for(std::string &result : res) {
5428 auto err_msg = _validate(result, index);
5430 if(!err_msg.empty())
5431 throw ValidationError(get_name(), err_msg);
5437 CLI11_INLINE
void Option::_reduce_results(results_t &out,
const results_t &original)
const {
5444 switch(multi_option_policy_) {
5445 case MultiOptionPolicy::TakeAll:
5447 case MultiOptionPolicy::TakeLast: {
5449 std::size_t trim_size = std::min<std::size_t>(
5450 static_cast<std::size_t>(std::max<int>(get_items_expected_max(), 1)), original.size());
5451 if(original.size() != trim_size) {
5452 out.assign(original.end() - static_cast<results_t::difference_type>(trim_size), original.end());
5455 case MultiOptionPolicy::TakeFirst: {
5456 std::size_t trim_size = std::min<std::size_t>(
5457 static_cast<std::size_t>(std::max<int>(get_items_expected_max(), 1)), original.size());
5458 if(original.size() != trim_size) {
5459 out.assign(original.begin(), original.begin() + static_cast<results_t::difference_type>(trim_size));
5462 case MultiOptionPolicy::Join:
5463 if(results_.size() > 1) {
5464 out.push_back(detail::join(original, std::string(1, (delimiter_ ==
'\0') ?
'\n' : delimiter_)));
5467 case MultiOptionPolicy::Sum:
5468 out.push_back(detail::sum_string_vector(original));
5470 case MultiOptionPolicy::Throw:
5472 auto num_min = static_cast<std::size_t>(get_items_expected_min());
5473 auto num_max = static_cast<std::size_t>(get_items_expected_max());
5480 if(original.size() < num_min) {
5481 throw ArgumentMismatch::AtLeast(get_name(), static_cast<int>(num_min), original.size());
5483 if(original.size() > num_max) {
5484 throw ArgumentMismatch::AtMost(get_name(), static_cast<int>(num_max), original.size());
5492 if(original.size() == 1 && original[0] ==
"{}" && get_items_expected_min() > 0) {
5493 out.push_back(
"{}");
5494 out.push_back(
"%%");
5496 }
else if(out.size() == 1 && out[0] ==
"{}" && get_items_expected_min() > 0) {
5497 out.push_back(
"%%");
5501 CLI11_INLINE std::string Option::_validate(std::string &result,
int index)
const {
5502 std::string err_msg;
5503 if(result.empty() && expected_min_ == 0) {
5507 for(
const auto &vali : validators_) {
5508 auto v = vali.get_application_index();
5509 if(v == -1 || v == index) {
5511 err_msg = vali(result);
5512 }
catch(
const ValidationError &err) {
5513 err_msg = err.what();
5515 if(!err_msg.empty())
5523 CLI11_INLINE
int Option::_add_result(std::string &&result, std::vector<std::string> &res)
const {
5524 int result_count = 0;
5525 if(allow_extra_args_ && !result.empty() && result.front() ==
'[' &&
5526 result.back() ==
']') {
5529 for(
auto &var : CLI::detail::split(result.substr(1),
',')) {
5531 result_count += _add_result(std::move(var), res);
5534 return result_count;
5536 if(delimiter_ ==
'\0') {
5537 res.push_back(std::move(result));
5540 if((result.find_first_of(delimiter_) != std::string::npos)) {
5541 for(
const auto &var : CLI::detail::split(result, delimiter_)) {
5548 res.push_back(std::move(result));
5552 return result_count;
5558 #define CLI11_PARSE(app, argc, argv) \ 5560 (app).parse((argc), (argv)); \ 5561 } catch(const CLI::ParseError &e) { \ 5562 return (app).exit(e); \ 5567 enum class Classifier { NONE, POSITIONAL_MARK, SHORT, LONG, WINDOWS_STYLE, SUBCOMMAND, SUBCOMMAND_TERMINATOR };
5571 namespace FailureMessage {
5572 std::string simple(
const App *app,
const Error &e);
5573 std::string help(
const App *app,
const Error &e);
5578 enum class config_extras_mode : char { error = 0, ignore, ignore_all, capture };
5582 using App_p = std::shared_ptr<App>;
5587 template <typename T, enable_if_t<!std::is_integral<T>::value || (
sizeof(T) <= 1U), detail::enabler> = detail::dummy>
5588 Option *default_flag_modifiers(Option *opt) {
5589 return opt->always_capture_default();
5593 template <typename T, enable_if_t<std::is_integral<T>::value && (
sizeof(T) > 1U), detail::enabler> = detail::dummy>
5594 Option *default_flag_modifiers(Option *opt) {
5595 return opt->multi_option_policy(MultiOptionPolicy::Sum)->default_str(
"0")->force_callback();
5695 using missing_t = std::vector<std::pair<detail::Classifier, std::string>>;
5750 enum class startup_mode : char { stable, enabled, disabled };
5805 App(std::string app_description, std::string app_name,
App *parent);
5812 explicit App(std::string app_description =
"", std::string app_name =
"")
5813 :
App(app_description, app_name, nullptr) {
5814 set_help_flag(
"-h,--help",
"Print this help message and exit");
5817 App(
const App &) =
delete;
5818 App &operator=(
const App &) =
delete;
5821 virtual ~App() =
default;
5860 App *
name(std::string app_name =
"");
5906 (
default_startup == startup_mode::disabled) ? startup_mode::disabled : startup_mode::stable;
5982 formatter_ = std::make_shared<FormatterLambda>(fmt);
6017 callback_t option_callback,
6018 std::string option_description =
"",
6019 bool defaulted =
false,
6020 std::function<std::string()> func = {});
6023 template <
typename AssignTo,
6024 typename ConvertTo = AssignTo,
6025 enable_if_t<!std::is_const<ConvertTo>::value, detail::enabler> = detail::dummy>
6028 std::string option_description =
"") {
6030 auto fun = [&variable](
const CLI::results_t &res) {
6031 return detail::lexical_conversion<AssignTo, ConvertTo>(res, variable);
6034 Option *opt =
add_option(option_name, fun, option_description,
false, [&variable]() {
6035 return CLI::detail::checked_to_string<AssignTo, ConvertTo>(variable);
6037 opt->type_name(detail::type_name<ConvertTo>());
6042 opt->type_size(detail::type_count_min<ConvertTo>::value, (std::max)(Tcount, XCcount));
6043 opt->expected(detail::expected_count<ConvertTo>::value);
6044 opt->run_callback_for_default();
6049 template <typename AssignTo, enable_if_t<!std::is_const<AssignTo>::value, detail::enabler> = detail::dummy>
6052 std::string option_description =
"") {
6054 auto fun = [&variable](
const CLI::results_t &res) {
6055 return detail::lexical_conversion<AssignTo, AssignTo>(res, variable);
6058 Option *opt =
add_option(option_name, fun, option_description,
false, []() {
return std::string{}; });
6059 opt->type_name(detail::type_name<AssignTo>());
6061 opt->expected(detail::expected_count<AssignTo>::value);
6062 opt->run_callback_for_default();
6067 template <
typename ArgType>
6069 const std::function<
void(
const ArgType &)> &func,
6070 std::string option_description =
"") {
6072 auto fun = [func](
const CLI::results_t &res) {
6074 bool result = detail::lexical_conversion<ArgType, ArgType>(res, variable);
6081 Option *opt =
add_option(option_name, std::move(fun), option_description,
false);
6082 opt->type_name(detail::type_name<ArgType>());
6084 opt->expected(detail::expected_count<ArgType>::value);
6090 return add_option(option_name, CLI::callback_t{}, std::string{},
false);
6094 template <
typename T,
6095 enable_if_t<std::is_const<T>::value && std::is_constructible<std::string, T>::value, detail::enabler> =
6097 Option *
add_option(std::string option_name, T &option_description) {
6098 return add_option(option_name, CLI::callback_t(), option_description,
false);
6102 Option *
set_help_flag(std::string flag_name =
"",
const std::string &help_description =
"");
6105 Option *
set_help_all_flag(std::string help_name =
"",
const std::string &help_description =
"");
6109 const std::string &versionString =
"",
6110 const std::string &version_help =
"Display program version information and exit");
6114 std::function<std::string()> vfunc,
6115 const std::string &version_help =
"Display program version information and exit");
6119 Option *_add_flag_internal(std::string flag_name, CLI::callback_t fun, std::string flag_description);
6123 Option *
add_flag(std::string flag_name) {
return _add_flag_internal(flag_name, CLI::callback_t(), std::string{}); }
6128 template <
typename T,
6129 enable_if_t<std::is_const<T>::value && std::is_constructible<std::string, T>::value, detail::enabler> =
6131 Option *
add_flag(std::string flag_name, T &flag_description) {
6132 return _add_flag_internal(flag_name, CLI::callback_t(), flag_description);
6137 template <
typename T,
6138 enable_if_t<!detail::is_mutable_container<T>::value && !std::is_const<T>::value &&
6139 !std::is_constructible<std::function<void(
int)>, T>::value,
6140 detail::enabler> = detail::dummy>
6143 std::string flag_description =
"") {
6145 CLI::callback_t fun = [&flag_result](
const CLI::results_t &res) {
6146 return CLI::detail::lexical_cast(res[0], flag_result);
6148 auto *opt = _add_flag_internal(flag_name, std::move(fun), std::move(flag_description));
6149 return detail::default_flag_modifiers<T>(opt);
6153 template <
typename T,
6154 enable_if_t<!std::is_assignable<std::function<void(std::int64_t)> &, T>::value, detail::enabler> =
6157 std::vector<T> &flag_results,
6158 std::string flag_description =
"") {
6159 CLI::callback_t fun = [&flag_results](
const CLI::results_t &res) {
6161 for(
const auto &elem : res) {
6162 flag_results.emplace_back();
6163 retval &= detail::lexical_cast(elem, flag_results.back());
6167 return _add_flag_internal(flag_name, std::move(fun), std::move(flag_description))
6168 ->multi_option_policy(MultiOptionPolicy::TakeAll)
6169 ->run_callback_for_default();
6174 std::function<
void(
void)>
function,
6175 std::string flag_description =
"");
6179 std::function<
void(std::int64_t)>
function,
6180 std::string flag_description =
"");
6183 Option *
add_flag(std::string flag_name,
6185 std::function<
void(std::int64_t)>
function,
6186 std::string flag_description =
"") {
6187 return add_flag_function(std::move(flag_name), std::move(
function), std::move(flag_description));
6192 Option *
set_config(std::string option_name =
"",
6193 std::string default_filename =
"",
6194 const std::string &help_message =
"Read an ini file",
6195 bool config_required =
false);
6201 template <
typename T = Option_group>
6203 if(!detail::valid_alias_name_string(group_name)) {
6206 auto option_group = std::make_shared<T>(std::move(group_description), group_name,
this);
6207 auto *ptr = option_group.get();
6209 App_p app_ptr = std::dynamic_pointer_cast<App>(option_group);
6219 App *
add_subcommand(std::string subcommand_name =
"", std::string subcommand_description =
"");
6256 CLI11_NODISCARD std::size_t
count_all()
const;
6331 explicit operator bool()
const {
return parsed_ > 0; }
6351 void parse(
int argc,
const char *
const *argv);
6357 void parse(std::string commandline,
bool program_name_included =
false);
6361 void parse(std::vector<std::string> &args);
6364 void parse(std::vector<std::string> &&args);
6366 void parse_from_stream(std::istream &input);
6374 int exit(
const Error &e, std::ostream &out = std::cout, std::ostream &err = std::cerr)
const;
6381 CLI11_NODISCARD std::size_t
count(std::string option_name)
const {
return get_option(option_name)->count(); }
6389 std::vector<const App *>
get_subcommands(
const std::function<
bool(
const App *)> &filter)
const;
6408 if(opt ==
nullptr) {
6417 if(app ==
nullptr) {
6431 App *needs(Option *opt) {
6432 if(opt ==
nullptr) {
6440 if(app ==
nullptr) {
6441 throw OptionNotFound(
"nullptr passed");
6444 throw OptionNotFound(
"cannot self reference in needs");
6467 footer_ = std::move(footer_string);
6477 CLI11_NODISCARD std::string
config_to_str(
bool default_also =
false,
bool write_description =
false)
const {
6483 CLI11_NODISCARD std::string
help(std::string prev =
"", AppFormatMode mode = AppFormatMode::Normal)
const;
6486 CLI11_NODISCARD std::string
version()
const;
6500 #if CLI11_USE_STATIC_RTTI == 0 6517 std::vector<const Option *>
get_options(
const std::function<
bool(
const Option *)> filter = {})
const;
6520 std::vector<Option *>
get_options(
const std::function<
bool(Option *)> filter = {});
6526 CLI11_NODISCARD
const Option *
get_option_no_throw(std::string option_name)
const noexcept;
6529 CLI11_NODISCARD
const Option *
get_option(std::string option_name)
const {
6531 if(opt ==
nullptr) {
6540 if(opt ==
nullptr) {
6661 CLI11_NODISCARD std::string
get_display_name(
bool with_aliases =
false)
const;
6664 CLI11_NODISCARD
bool check_name(std::string name_to_check)
const;
6667 CLI11_NODISCARD std::vector<std::string>
get_groups()
const;
6673 CLI11_NODISCARD std::vector<std::string>
remaining(
bool recurse =
false)
const;
6679 CLI11_NODISCARD std::size_t
remaining_size(
bool recurse =
false)
const;
6696 void run_callback(
bool final_mode =
false,
bool suppress_final_callback =
false);
6699 CLI11_NODISCARD
bool _valid_subcommand(
const std::string ¤t,
bool ignore_used =
true)
const;
6702 CLI11_NODISCARD detail::Classifier
_recognize(
const std::string ¤t,
6703 bool ignore_used_subcommands =
true)
const;
6738 void _parse(std::vector<std::string> &args);
6741 void _parse(std::vector<std::string> &&args);
6757 bool _parse_single(std::vector<std::string> &args,
bool &positional_only);
6772 CLI11_NODISCARD
App *
6773 _find_subcommand(
const std::string &subc_name,
bool ignore_disabled,
bool ignore_used)
const noexcept;
6783 bool _parse_arg(std::vector<std::string> &args, detail::Classifier current_type);
6795 void _move_to_missing(detail::Classifier val_type,
const std::string &val);
6805 Option_group(std::string group_description, std::string group_name,
App *parent)
6806 :
App(std::move(group_description),
"", parent) {
6822 template <
typename... Args>
void add_options(Option *opt, Args... args) {
6830 subc->get_parent()->remove_subcommand(subcom);
6837 CLI11_INLINE
void TriggerOn(App *trigger_app, App *app_to_enable);
6840 CLI11_INLINE
void TriggerOn(App *trigger_app, std::vector<App *> apps_to_enable);
6843 CLI11_INLINE
void TriggerOff(App *trigger_app, App *app_to_enable);
6846 CLI11_INLINE
void TriggerOff(App *trigger_app, std::vector<App *> apps_to_enable);
6849 CLI11_INLINE
void deprecate_option(Option *opt,
const std::string &replacement =
"");
6852 inline void deprecate_option(App *app,
const std::string &option_name,
const std::string &replacement =
"") {
6853 auto *opt = app->get_option(option_name);
6854 deprecate_option(opt, replacement);
6858 inline void deprecate_option(App &app,
const std::string &option_name,
const std::string &replacement =
"") {
6859 auto *opt = app.get_option(option_name);
6860 deprecate_option(opt, replacement);
6864 CLI11_INLINE
void retire_option(App *app, Option *opt);
6867 CLI11_INLINE
void retire_option(App &app, Option *opt);
6870 CLI11_INLINE
void retire_option(App *app,
const std::string &option_name);
6873 CLI11_INLINE
void retire_option(App &app,
const std::string &option_name);
6875 namespace FailureMessage {
6878 CLI11_INLINE std::string simple(
const App *app,
const Error &e);
6881 CLI11_INLINE std::string help(
const App *app,
const Error &e);
6891 template <
typename... Args>
static decltype(
auto)
parse_arg(
App *app, Args &&...args) {
6892 return app->
_parse_arg(std::forward<Args>(args)...);
6896 template <
typename... Args>
static decltype(
auto)
parse_subcommand(
App *app, Args &&...args) {
6900 template <
typename... Args>
6904 return app->
_parse_arg(std::forward<Args>(args)...);
6908 template <
typename... Args>
6922 CLI11_INLINE
App::App(std::string app_description, std::string app_name,
App *parent)
6923 : name_(std::move(app_name)), description_(std::move(app_description)), parent_(parent) {
6973 if(app_name.empty() || !detail::valid_alias_name_string(app_name)) {
6981 throw(
OptionAlreadyAdded(
"alias already matches an existing subcommand: " + app_name));
7007 if(!match.empty()) {
7009 throw OptionAlreadyAdded(
"ignore case would cause subcommand name conflicts: " + match);
7021 if(!match.empty()) {
7023 throw OptionAlreadyAdded(
"ignore underscore would cause subcommand name conflicts: " + match);
7031 callback_t option_callback,
7032 std::string option_description,
7034 std::function<std::string()> func) {
7035 Option myopt{option_name, option_description, option_callback,
this};
7037 if(std::find_if(std::begin(
options_), std::end(
options_), [&myopt](
const Option_p &v) {
return *v == myopt; }) ==
7040 Option_p &option =
options_.back();
7041 option.reset(
new Option(option_name, option_description, option_callback,
this));
7044 option->default_function(func);
7048 option->capture_default_str();
7054 if(!defaulted && option->get_always_capture_default())
7055 option->capture_default_str();
7057 return option.get();
7061 const auto &matchname = opt->matching_name(myopt);
7062 if(!matchname.empty()) {
7063 throw(
OptionAlreadyAdded(
"added option matched existing option name: " + matchname));
7078 if(!flag_name.empty()) {
7094 if(!help_name.empty()) {
7102 CLI11_INLINE Option *
7111 if(!flag_name.empty()) {
7113 flag_name, [versionString]() {
throw(
CLI::CallForVersion(versionString, 0)); }, version_help);
7120 CLI11_INLINE Option *
7128 if(!flag_name.empty()) {
7137 CLI11_INLINE Option *App::_add_flag_internal(std::string flag_name, CLI::callback_t fun, std::string flag_description) {
7138 Option *opt =
nullptr;
7139 if(detail::has_default_flag_values(flag_name)) {
7141 auto flag_defaults = detail::get_default_flag_values(flag_name);
7142 detail::remove_default_flag_values(flag_name);
7143 opt =
add_option(std::move(flag_name), std::move(fun), std::move(flag_description),
false);
7144 for(
const auto &fname : flag_defaults)
7145 opt->fnames_.push_back(fname.first);
7146 opt->default_flag_values_ = std::move(flag_defaults);
7148 opt =
add_option(std::move(flag_name), std::move(fun), std::move(flag_description),
false);
7151 if(opt->get_positional()) {
7152 auto pos_name = opt->get_name(
true);
7154 throw IncorrectConstruction::PositionalFlag(pos_name);
7156 opt->multi_option_policy(MultiOptionPolicy::TakeLast);
7158 opt->required(
false);
7163 std::function<
void(
void)>
function,
7164 std::string flag_description) {
7166 CLI::callback_t fun = [
function](
const CLI::results_t &res) {
7167 bool trigger{
false};
7168 auto result = CLI::detail::lexical_cast(res[0], trigger);
7169 if(result && trigger) {
7174 return _add_flag_internal(flag_name, std::move(fun), std::move(flag_description));
7177 CLI11_INLINE Option *
7179 std::function<
void(std::int64_t)>
function,
7180 std::string flag_description) {
7182 CLI::callback_t fun = [
function](
const CLI::results_t &res) {
7183 std::int64_t flag_count{0};
7184 CLI::detail::lexical_cast(res[0], flag_count);
7185 function(flag_count);
7188 return _add_flag_internal(flag_name, std::move(fun), std::move(flag_description))
7189 ->multi_option_policy(MultiOptionPolicy::Sum);
7193 std::string default_filename,
7194 const std::string &help_message,
7195 bool config_required) {
7204 if(!option_name.empty()) {
7206 if(config_required) {
7209 if(!default_filename.empty()) {
7210 config_ptr_->default_str(std::move(default_filename));
7221 op->remove_needs(opt);
7222 op->remove_excludes(opt);
7231 std::find_if(std::begin(
options_), std::end(
options_), [opt](
const Option_p &v) {
return v.get() == opt; });
7232 if(iterator != std::end(
options_)) {
7240 if(!subcommand_name.empty() && !detail::valid_name_string(subcommand_name)) {
7241 if(!detail::valid_first_char(subcommand_name[0])) {
7242 throw IncorrectConstruction(
"Subcommand name starts with invalid character, '!' and '-' are not allowed");
7244 for(
auto c : subcommand_name) {
7245 if(!detail::valid_later_char(c)) {
7247 "'), all characters are allowed except" 7248 "'=',':','{','}', and ' '");
7252 CLI::App_p subcom = std::shared_ptr<App>(
new App(std::move(subcommand_description), subcommand_name,
this));
7261 if(!mstrg.empty()) {
7262 throw(
OptionAlreadyAdded(
"subcommand name or alias matches existing subcommand: " + mstrg));
7264 subcom->parent_ =
this;
7272 sub->remove_excludes(subcom);
7273 sub->remove_needs(subcom);
7276 auto iterator = std::find_if(
7286 if(subcom ==
nullptr)
7289 if(subcomptr.get() == subcom)
7290 return subcomptr.get();
7303 auto uindex = static_cast<unsigned>(index);
7311 if(subcom ==
nullptr)
7314 if(subcomptr.get() == subcom)
7321 if(subcomptr->check_name(subcom))
7328 auto uindex = static_cast<unsigned>(index);
7337 if(app->name_.empty() && app->group_ == group_name) {
7347 cnt += opt->count();
7350 cnt += sub->count_all();
7365 for(
const Option_p &opt :
options_) {
7373 CLI11_INLINE
void App::parse(
int argc,
const char *
const *argv) {
7380 std::vector<std::string> args;
7381 args.reserve(static_cast<std::size_t>(argc) - 1U);
7382 for(
auto i = static_cast<std::size_t>(argc) - 1U; i > 0U; --i)
7383 args.emplace_back(argv[i]);
7384 parse(std::move(args));
7387 CLI11_INLINE
void App::parse(std::string commandline,
bool program_name_included) {
7389 if(program_name_included) {
7390 auto nstr = detail::split_program_name(commandline);
7395 commandline = std::move(nstr.second);
7397 detail::trim(commandline);
7400 if(!commandline.empty()) {
7401 commandline = detail::find_and_modify(commandline,
"=", detail::escape_detect);
7403 commandline = detail::find_and_modify(commandline,
":", detail::escape_detect);
7406 auto args = detail::split_up(std::move(commandline));
7408 args.erase(std::remove(args.begin(), args.end(), std::string{}), args.end());
7409 std::reverse(args.begin(), args.end());
7411 parse(std::move(args));
7452 CLI11_INLINE
void App::parse_from_stream(std::istream &input) {
7463 CLI11_INLINE
int App::exit(
const Error &e, std::ostream &out, std::ostream &err)
const {
7466 if(e.get_name() ==
"RuntimeError")
7467 return e.get_exit_code();
7469 if(e.get_name() ==
"CallForHelp") {
7471 return e.get_exit_code();
7474 if(e.get_name() ==
"CallForAllHelp") {
7475 out <<
help(
"", AppFormatMode::All);
7476 return e.get_exit_code();
7479 if(e.get_name() ==
"CallForVersion") {
7480 out << e.what() << std::endl;
7481 return e.get_exit_code();
7484 if(e.get_exit_code() != static_cast<int>(ExitCodes::Success)) {
7489 return e.get_exit_code();
7493 std::vector<const App *> subcomms(
subcommands_.size());
7498 subcomms.erase(std::remove_if(std::begin(subcomms),
7500 [&filter](
const App *app) {
return !filter(app); }),
7501 std::end(subcomms));
7514 std::remove_if(std::begin(subcomms), std::end(subcomms), [&filter](
App *app) {
return !filter(app); }),
7515 std::end(subcomms));
7535 auto *other_app = *iterator;
7537 other_app->remove_excludes(
this);
7559 CLI11_NODISCARD CLI11_INLINE std::string
App::help(std::string prev, AppFormatMode mode)
const {
7567 if(!selected_subcommands.empty()) {
7568 return selected_subcommands.at(0)->help(prev, mode);
7570 return formatter_->make_help(
this, prev, mode);
7590 CLI11_INLINE std::vector<const Option *>
App::get_options(
const std::function<
bool(
const Option *)> filter)
const {
7591 std::vector<const Option *> options(
options_.size());
7593 std::begin(
options_), std::end(
options_), std::begin(options), [](
const Option_p &val) {
return val.get(); });
7596 options.erase(std::remove_if(std::begin(options),
7598 [&filter](
const Option *opt) {
return !filter(opt); }),
7605 CLI11_INLINE std::vector<Option *>
App::get_options(
const std::function<
bool(Option *)> filter) {
7606 std::vector<Option *> options(
options_.size());
7608 std::begin(
options_), std::end(
options_), std::begin(options), [](
const Option_p &val) {
return val.get(); });
7612 std::remove_if(std::begin(options), std::end(options), [&filter](Option *opt) {
return !filter(opt); }),
7620 for(Option_p &opt : options_) {
7621 if(opt->check_name(option_name)) {
7625 for(
auto &subc : subcommands_) {
7627 if(subc->get_name().empty()) {
7628 auto *opt = subc->get_option_no_throw(option_name);
7629 if(opt !=
nullptr) {
7638 for(
const Option_p &opt : options_) {
7639 if(opt->check_name(option_name)) {
7643 for(
const auto &subc : subcommands_) {
7645 if(subc->get_name().empty()) {
7646 auto *opt = subc->get_option_no_throw(option_name);
7647 if(opt !=
nullptr) {
7657 return std::string(
"[Option Group: ") +
get_group() +
"]";
7659 if(
aliases_.empty() || !with_aliases) {
7662 std::string dispname =
name_;
7663 for(
const auto &lalias :
aliases_) {
7664 dispname.push_back(
',');
7665 dispname.push_back(
' ');
7666 dispname.append(lalias);
7672 std::string local_name =
name_;
7674 local_name = detail::remove_underscore(
name_);
7675 name_to_check = detail::remove_underscore(name_to_check);
7678 local_name = detail::to_lower(
name_);
7679 name_to_check = detail::to_lower(name_to_check);
7682 if(local_name == name_to_check) {
7687 les = detail::remove_underscore(les);
7690 les = detail::to_lower(les);
7692 if(les == name_to_check) {
7700 std::vector<std::string> groups;
7702 for(
const Option_p &opt :
options_) {
7704 if(std::find(groups.begin(), groups.end(), opt->get_group()) == groups.end()) {
7705 groups.push_back(opt->get_group());
7712 CLI11_NODISCARD CLI11_INLINE std::vector<std::string>
App::remaining(
bool recurse)
const {
7713 std::vector<std::string> miss_list;
7714 for(
const std::pair<detail::Classifier, std::string> &miss :
missing_) {
7715 miss_list.push_back(std::get<1>(miss));
7721 if(sub->name_.empty() && !sub->missing_.empty()) {
7722 for(
const std::pair<detail::Classifier, std::string> &miss : sub->missing_) {
7723 miss_list.push_back(std::get<1>(miss));
7731 std::vector<std::string> output = sub->remaining(recurse);
7732 std::copy(std::begin(output), std::end(output), std::back_inserter(miss_list));
7739 std::vector<std::string> miss_list =
remaining(recurse);
7740 std::reverse(std::begin(miss_list), std::end(miss_list));
7745 auto remaining_options = static_cast<std::size_t>(std::count_if(
7746 std::begin(
missing_), std::end(
missing_), [](
const std::pair<detail::Classifier, std::string> &val) {
7747 return val.first != detail::Classifier::POSITIONAL_MARK;
7752 remaining_options += sub->remaining_size(recurse);
7755 return remaining_options;
7760 auto pcount = std::count_if(std::begin(
options_), std::end(
options_), [](
const Option_p &opt) {
7761 return opt->get_items_expected_max() >= detail::expected_max_vector_size && !opt->nonpositional();
7764 auto pcount_req = std::count_if(std::begin(
options_), std::end(
options_), [](
const Option_p &opt) {
7765 return opt->get_items_expected_max() >= detail::expected_max_vector_size && !opt->nonpositional() &&
7766 opt->get_required();
7768 if(pcount - pcount_req > 1) {
7773 std::size_t nameless_subs{0};
7776 if(app->get_name().empty())
7783 throw(
InvalidError(
"Required min options greater than required max options", ExitCodes::InvalidError));
7788 InvalidError(
"Required min options greater than number of available options", ExitCodes::InvalidError));
7800 if(app->has_automatic_name_) {
7803 if(app->name_.empty()) {
7804 app->fallthrough_ =
false;
7805 app->prefix_command_ =
false;
7808 app->parent_ =
this;
7821 if(subc->parent_ ==
this) {
7822 subc->run_callback(
true, suppress_final_callback);
7827 if(subc->name_.empty() && subc->count_all() > 0) {
7828 subc->run_callback(
true, suppress_final_callback);
7846 if(com !=
nullptr) {
7853 CLI11_NODISCARD CLI11_INLINE detail::Classifier
App::_recognize(
const std::string ¤t,
7854 bool ignore_used_subcommands)
const {
7855 std::string dummy1, dummy2;
7858 return detail::Classifier::POSITIONAL_MARK;
7860 return detail::Classifier::SUBCOMMAND;
7861 if(detail::split_long(current, dummy1, dummy2))
7862 return detail::Classifier::LONG;
7863 if(detail::split_short(current, dummy1, dummy2)) {
7864 if(dummy1[0] >=
'0' && dummy1[0] <=
'9') {
7866 return detail::Classifier::NONE;
7869 return detail::Classifier::SHORT;
7872 return detail::Classifier::WINDOWS_STYLE;
7873 if((current ==
"++") && !
name_.empty() &&
parent_ !=
nullptr)
7874 return detail::Classifier::SUBCOMMAND_TERMINATOR;
7875 return detail::Classifier::NONE;
7880 bool config_required =
config_ptr_->get_required();
7882 auto config_files =
config_ptr_->as<std::vector<std::string>>();
7883 if(config_files.empty() || config_files.front().empty()) {
7884 if(config_required) {
7885 throw FileError::Missing(
"no specified config file");
7889 for(
auto rit = config_files.rbegin(); rit != config_files.rend(); ++rit) {
7890 const auto &config_file = *rit;
7891 auto path_result = detail::check_path(config_file.c_str());
7892 if(path_result == detail::path_type::file) {
7900 if(config_required || file_given)
7903 }
else if(config_required || file_given) {
7904 throw FileError::Missing(config_file);
7911 for(
const Option_p &opt :
options_) {
7912 if(opt->count() == 0 && !opt->envname_.empty()) {
7913 char *buffer =
nullptr;
7914 std::string ename_string;
7919 if(_dupenv_s(&buffer, &sz, opt->envname_.c_str()) == 0 && buffer !=
nullptr) {
7920 ename_string = std::string(buffer);
7925 buffer = std::getenv(opt->envname_.c_str());
7926 if(buffer !=
nullptr)
7927 ename_string = std::string(buffer);
7930 if(!ename_string.empty()) {
7931 opt->add_result(ename_string);
7937 if(sub->get_name().empty() || !sub->parse_complete_callback_)
7938 sub->_process_env();
7946 if(sub->get_name().empty() && sub->parse_complete_callback_) {
7947 if(sub->count_all() > 0) {
7948 sub->_process_callbacks();
7949 sub->run_callback();
7954 for(
const Option_p &opt :
options_) {
7955 if((*opt) && !opt->get_callback_run()) {
7956 opt->run_callback();
7960 if(!sub->parse_complete_callback_) {
7961 sub->_process_callbacks();
7970 if(help_ptr !=
nullptr && help_ptr->count() > 0)
7971 trigger_help =
true;
7972 if(help_all_ptr !=
nullptr && help_all_ptr->count() > 0)
7973 trigger_all_help =
true;
7978 sub->_process_help_flags(trigger_help, trigger_all_help);
7981 }
else if(trigger_all_help) {
7983 }
else if(trigger_help) {
7990 bool excluded{
false};
7991 std::string excluder;
7993 if(opt->count() > 0) {
7995 excluder = opt->get_name();
7999 if(subc->count_all() > 0) {
8001 excluder = subc->get_display_name();
8013 bool missing_needed{
false};
8014 std::string missing_need;
8016 if(opt->count() == 0) {
8017 missing_needed =
true;
8018 missing_need = opt->get_name();
8022 if(subc->count_all() == 0) {
8023 missing_needed =
true;
8024 missing_need = subc->get_display_name();
8027 if(missing_needed) {
8035 std::size_t used_options = 0;
8036 for(
const Option_p &opt :
options_) {
8038 if(opt->count() != 0) {
8042 if(opt->get_required() && opt->count() == 0) {
8046 for(
const Option *opt_req : opt->needs_)
8047 if(opt->count() > 0 && opt_req->count() == 0)
8050 for(
const Option *opt_ex : opt->excludes_)
8051 if(opt->count() > 0 && opt_ex->count() != 0)
8068 if(sub->name_.empty() && sub->count_all() > 0) {
8074 auto option_list = detail::join(
options_, [
this](
const Option_p &ptr) {
8076 return std::string{};
8078 return ptr->get_name(
false,
true);
8082 if(!subc_list.empty()) {
8083 option_list +=
"," + detail::join(subc_list, [](
const App *app) {
return app->
get_display_name(); });
8092 if(sub->name_.empty() && sub->required_ ==
false) {
8093 if(sub->count_all() == 0) {
8106 if(sub->count() > 0 || sub->name_.empty()) {
8107 sub->_process_requirements();
8110 if(sub->required_ && sub->count_all() == 0) {
8141 if(num_left_over > 0) {
8147 if(sub->count() > 0)
8148 sub->_process_extras();
8155 if(num_left_over > 0) {
8162 if(sub->count() > 0)
8163 sub->_process_extras(args);
8170 if(sub->get_name().empty())
8171 sub->increment_parsed();
8178 bool positional_only =
false;
8180 while(!args.empty()) {
8208 bool positional_only =
false;
8210 while(!args.empty()) {
8233 throw ConfigError::Extras(item.fullname());
8238 if(level < item.
parents.size()) {
8249 if(item.
name ==
"++") {
8260 if(item.
name ==
"--") {
8270 if(item.
name.size() == 1) {
8285 if(!op->get_configurable()) {
8289 throw ConfigError::NotConfigurable(item.
fullname());
8294 if(op->get_expected_min() == 0) {
8295 if(item.
inputs.size() <= 1) {
8298 res = op->get_flag_value(item.
name, res);
8300 op->add_result(res);
8303 if(static_cast<int>(item.
inputs.size()) > op->get_items_expected_max()) {
8304 if(op->get_items_expected_max() > 1) {
8305 throw ArgumentMismatch::AtMost(item.
fullname(), op->get_items_expected_max(), item.
inputs.size());
8307 throw ConversionError::TooManyInputsFlag(item.
fullname());
8310 op->add_result(item.
inputs);
8319 detail::Classifier classifier = positional_only ? detail::Classifier::NONE :
_recognize(args.back());
8320 switch(classifier) {
8321 case detail::Classifier::POSITIONAL_MARK:
8323 positional_only =
true;
8330 case detail::Classifier::SUBCOMMAND_TERMINATOR:
8335 case detail::Classifier::SUBCOMMAND:
8338 case detail::Classifier::LONG:
8339 case detail::Classifier::SHORT:
8340 case detail::Classifier::WINDOWS_STYLE:
8344 case detail::Classifier::NONE:
8348 positional_only =
true;
8353 throw HorribleError(
"unrecognized classifier (you should not see this!)");
8360 std::size_t retval = 0;
8361 for(
const Option_p &opt :
options_) {
8362 if(opt->get_positional() && (!required_only || opt->get_required())) {
8363 if(opt->get_items_expected_min() > 0 && static_cast<int>(opt->count()) < opt->get_items_expected_min()) {
8364 retval += static_cast<std::size_t>(opt->get_items_expected_min()) - opt->count();
8372 for(
const Option_p &opt :
options_) {
8373 if(opt->get_positional() && ((static_cast<int>(opt->count()) < opt->get_items_expected_min()))) {
8383 const std::string &positional = args.back();
8387 auto arg_rem = args.size();
8389 if(arg_rem <= remreq) {
8390 for(
const Option_p &opt :
options_) {
8391 if(opt->get_positional() && opt->required_) {
8392 if(static_cast<int>(opt->count()) < opt->get_items_expected_min()) {
8394 std::string pos = positional;
8395 pos = opt->_validate(pos, 0);
8403 if(opt->get_inject_separator()) {
8404 if(!opt->results().empty() && !opt->results().back().empty()) {
8405 opt->add_result(std::string{});
8408 if(opt->get_trigger_on_parse() &&
8409 opt->current_option_state_ == Option::option_state::callback_run) {
8412 opt->add_result(positional);
8413 if(opt->get_trigger_on_parse()) {
8414 opt->run_callback();
8423 for(
const Option_p &opt :
options_) {
8425 if(opt->get_positional() &&
8426 (static_cast<int>(opt->count()) < opt->get_items_expected_min() || opt->get_allow_extra_args())) {
8428 std::string pos = positional;
8429 pos = opt->_validate(pos, 0);
8434 if(opt->get_inject_separator()) {
8435 if(!opt->results().empty() && !opt->results().back().empty()) {
8436 opt->add_result(std::string{});
8439 if(opt->get_trigger_on_parse() && opt->current_option_state_ == Option::option_state::callback_run) {
8442 opt->add_result(positional);
8443 if(opt->get_trigger_on_parse()) {
8444 opt->run_callback();
8453 if((subc->name_.empty()) && (!subc->disabled_)) {
8454 if(subc->_parse_positional(args,
false)) {
8455 if(!subc->pre_parse_called_) {
8456 subc->_trigger_pre_parse(args.size());
8469 if(haltOnSubcommand) {
8480 if(com !=
nullptr && (com->parent_->require_subcommand_max_ == 0 ||
8481 com->parent_->require_subcommand_max_ > com->parent_->parsed_subcommands_.size())) {
8496 while(!args.empty()) {
8505 CLI11_NODISCARD CLI11_INLINE
App *
8507 for(
const App_p &com : subcommands_) {
8508 if(com->disabled_ && ignore_disabled)
8510 if(com->get_name().empty()) {
8511 auto *subc = com->
_find_subcommand(subc_name, ignore_disabled, ignore_used);
8512 if(subc !=
nullptr) {
8516 if(com->check_name(subc_name)) {
8517 if((!*com) || !ignore_used)
8530 if(com !=
nullptr) {
8536 auto *parent_app = com->parent_;
8537 while(parent_app !=
this) {
8538 parent_app->_trigger_pre_parse(args.size());
8540 parent_app->parsed_subcommands_.push_back(com);
8542 parent_app = parent_app->parent_;
8548 throw HorribleError(
"Subcommand " + args.back() +
" missing");
8552 CLI11_INLINE
bool App::_parse_arg(std::vector<std::string> &args, detail::Classifier current_type) {
8554 std::string current = args.back();
8556 std::string arg_name;
8560 switch(current_type) {
8561 case detail::Classifier::LONG:
8562 if(!detail::split_long(current, arg_name, value))
8563 throw HorribleError(
"Long parsed but missing (you should not see this):" + args.back());
8565 case detail::Classifier::SHORT:
8566 if(!detail::split_short(current, arg_name, rest))
8567 throw HorribleError(
"Short parsed but missing! You should not see this");
8569 case detail::Classifier::WINDOWS_STYLE:
8570 if(!detail::split_windows_style(current, arg_name, value))
8571 throw HorribleError(
"windows option parsed but missing! You should not see this");
8573 case detail::Classifier::SUBCOMMAND:
8574 case detail::Classifier::SUBCOMMAND_TERMINATOR:
8575 case detail::Classifier::POSITIONAL_MARK:
8576 case detail::Classifier::NONE:
8578 throw HorribleError(
"parsing got called with invalid option! You should not see this");
8581 auto op_ptr = std::find_if(std::begin(
options_), std::end(
options_), [arg_name, current_type](
const Option_p &opt) {
8582 if(current_type == detail::Classifier::LONG)
8583 return opt->check_lname(arg_name);
8584 if(current_type == detail::Classifier::SHORT)
8585 return opt->check_sname(arg_name);
8587 return opt->check_lname(arg_name) || opt->check_sname(arg_name);
8593 if(subc->name_.empty() && !subc->disabled_) {
8594 if(subc->_parse_arg(args, current_type)) {
8595 if(!subc->pre_parse_called_) {
8596 subc->_trigger_pre_parse(args.size());
8621 Option_p &op = *op_ptr;
8623 if(op->get_inject_separator()) {
8624 if(!op->results().empty() && !op->results().back().empty()) {
8625 op->add_result(std::string{});
8628 if(op->get_trigger_on_parse() && op->current_option_state_ == Option::option_state::callback_run) {
8631 int min_num = (std::min)(op->get_type_size_min(), op->get_items_expected_min());
8632 int max_num = op->get_items_expected_max();
8635 if(max_num >= detail::expected_max_vector_size / 16 && !op->get_allow_extra_args()) {
8636 auto tmax = op->get_type_size_max();
8637 max_num = detail::checked_multiply(tmax, op->get_expected_min()) ? tmax : detail::expected_max_vector_size;
8641 int result_count = 0;
8644 auto res = op->get_flag_value(arg_name, value);
8645 op->add_result(res);
8647 }
else if(!value.empty()) {
8648 op->add_result(value, result_count);
8650 collected += result_count;
8652 }
else if(!rest.empty()) {
8653 op->add_result(rest, result_count);
8656 collected += result_count;
8660 while(min_num > collected && !args.empty()) {
8661 std::string current_ = args.back();
8663 op->add_result(current_, result_count);
8665 collected += result_count;
8668 if(min_num > collected) {
8669 throw ArgumentMismatch::TypedAtLeast(op->get_name(), min_num, op->get_type_name());
8673 if(max_num > collected || op->get_allow_extra_args()) {
8676 while((collected < max_num || op->get_allow_extra_args()) && !args.empty() &&
8677 _recognize(args.back(),
false) == detail::Classifier::NONE) {
8679 if(remreqpos >= args.size()) {
8683 std::string arg = args.back();
8684 arg = op->_validate(arg, 0);
8689 op->add_result(args.back(), result_count);
8692 collected += result_count;
8696 if(!args.empty() &&
_recognize(args.back()) == detail::Classifier::POSITIONAL_MARK)
8699 if(min_num == 0 && max_num > 0 && collected == 0) {
8700 auto res = op->get_flag_value(arg_name, std::string{});
8701 op->add_result(res);
8706 if(min_num > 0 && (collected % op->get_type_size_max()) != 0) {
8707 if(op->get_type_size_max() != op->get_type_size_min()) {
8708 op->add_result(std::string{});
8710 throw ArgumentMismatch::PartialType(op->get_name(), op->get_type_size_min(), op->get_type_name());
8713 if(op->get_trigger_on_parse()) {
8718 args.push_back(rest);
8730 if(!
name_.empty()) {
8745 auto *fallthrough_parent =
parent_;
8746 while((fallthrough_parent->parent_ !=
nullptr) && (fallthrough_parent->get_name().empty())) {
8747 fallthrough_parent = fallthrough_parent->
parent_;
8749 return fallthrough_parent;
8753 const App &base)
const {
8754 static const std::string estring;
8759 if(subc.get() != &subcom) {
8760 if(subc->disabled_) {
8764 if(subc->check_name(subcom.
get_name())) {
8768 if(!subc->get_name().empty()) {
8770 return subc->get_name();
8773 for(
const auto &les : subcom.
aliases_) {
8774 if(subc->check_name(les)) {
8779 for(
const auto &les : subc->aliases_) {
8785 if(subc->get_name().empty()) {
8787 if(!cmpres.empty()) {
8794 if(!cmpres.empty()) {
8805 missing_.emplace_back(val_type, val);
8810 if(subc->name_.empty() && subc->allow_extras_) {
8811 subc->missing_.emplace_back(val_type, val);
8816 missing_.emplace_back(val_type, val);
8820 if(opt ==
nullptr) {
8826 if(app == subc.get()) {
8841 std::find_if(std::begin(
options_), std::end(
options_), [opt](
const Option_p &v) {
return v.get() == opt; });
8842 if(iterator != std::end(
options_)) {
8843 const auto &opt_p = *iterator;
8844 if(std::find_if(std::begin(app->
options_), std::end(app->
options_), [&opt_p](
const Option_p &v) {
8845 return (*v == *opt_p);
8848 app->
options_.push_back(std::move(*iterator));
8858 CLI11_INLINE
void TriggerOn(
App *trigger_app,
App *app_to_enable) {
8864 CLI11_INLINE
void TriggerOn(App *trigger_app, std::vector<App *> apps_to_enable) {
8865 for(
auto &app : apps_to_enable) {
8866 app->enabled_by_default(
false);
8867 app->disabled_by_default();
8870 trigger_app->preparse_callback([apps_to_enable](std::size_t) {
8871 for(
const auto &app : apps_to_enable) {
8872 app->disabled(
false);
8877 CLI11_INLINE
void TriggerOff(App *trigger_app, App *app_to_enable) {
8878 app_to_enable->disabled_by_default(
false);
8879 app_to_enable->enabled_by_default();
8880 trigger_app->preparse_callback([app_to_enable](std::size_t) { app_to_enable->disabled(); });
8883 CLI11_INLINE
void TriggerOff(App *trigger_app, std::vector<App *> apps_to_enable) {
8884 for(
auto &app : apps_to_enable) {
8885 app->disabled_by_default(
false);
8886 app->enabled_by_default();
8889 trigger_app->preparse_callback([apps_to_enable](std::size_t) {
8890 for(
const auto &app : apps_to_enable) {
8896 CLI11_INLINE
void deprecate_option(Option *opt,
const std::string &replacement) {
8897 Validator deprecate_warning{[opt, replacement](std::string &) {
8898 std::cout << opt->get_name() <<
" is deprecated please use '" << replacement
8900 return std::string();
8903 deprecate_warning.application_index(0);
8904 opt->check(deprecate_warning);
8905 if(!replacement.empty()) {
8906 opt->description(opt->get_description() +
" DEPRECATED: please use '" + replacement +
"' instead");
8910 CLI11_INLINE
void retire_option(App *app, Option *opt) {
8912 auto *option_copy = temp.add_option(opt->get_name(
false,
true))
8913 ->type_size(opt->get_type_size_min(), opt->get_type_size_max())
8914 ->expected(opt->get_expected_min(), opt->get_expected_max())
8915 ->allow_extra_args(opt->get_allow_extra_args());
8917 app->remove_option(opt);
8918 auto *opt2 = app->add_option(option_copy->get_name(
false,
true),
"option has been retired and has no effect")
8919 ->type_name(
"RETIRED")
8920 ->default_str(
"RETIRED")
8921 ->type_size(option_copy->get_type_size_min(), option_copy->get_type_size_max())
8922 ->expected(option_copy->get_expected_min(), option_copy->get_expected_max())
8923 ->allow_extra_args(option_copy->get_allow_extra_args());
8925 Validator retired_warning{[opt2](std::string &) {
8926 std::cout <<
"WARNING " << opt2->get_name() <<
" is retired and has no effect\n";
8927 return std::string();
8930 retired_warning.application_index(0);
8931 opt2->check(retired_warning);
8934 CLI11_INLINE
void retire_option(App &app, Option *opt) { retire_option(&app, opt); }
8936 CLI11_INLINE
void retire_option(App *app,
const std::string &option_name) {
8938 auto *opt = app->get_option_no_throw(option_name);
8939 if(opt !=
nullptr) {
8940 retire_option(app, opt);
8943 auto *opt2 = app->add_option(option_name,
"option has been retired and has no effect")
8944 ->type_name(
"RETIRED")
8946 ->default_str(
"RETIRED");
8947 Validator retired_warning{[opt2](std::string &) {
8948 std::cout <<
"WARNING " << opt2->get_name() <<
" is retired and has no effect\n";
8949 return std::string();
8952 retired_warning.application_index(0);
8953 opt2->check(retired_warning);
8956 CLI11_INLINE
void retire_option(App &app,
const std::string &option_name) { retire_option(&app, option_name); }
8958 namespace FailureMessage {
8960 CLI11_INLINE std::string simple(
const App *app,
const Error &e) {
8961 std::string header = std::string(e.what()) +
"\n";
8962 std::vector<std::string> names;
8965 if(app->get_help_ptr() !=
nullptr)
8966 names.push_back(app->get_help_ptr()->get_name());
8968 if(app->get_help_all_ptr() !=
nullptr)
8969 names.push_back(app->get_help_all_ptr()->get_name());
8973 header +=
"Run with " + detail::join(names,
" or ") +
" for more information.\n";
8978 CLI11_INLINE std::string help(
const App *app,
const Error &e) {
8979 std::string header = std::string(
"ERROR: ") + e.get_name() +
": " + e.what() +
"\n";
8980 header += app->help();
8991 std::string convert_arg_for_ini(
const std::string &arg,
char stringQuote =
'"',
char characterQuote =
'\'');
8994 std::string ini_join(
const std::vector<std::string> &args,
8996 char arrayStart =
'[',
8997 char arrayEnd =
']',
8998 char stringQuote =
'"',
8999 char characterQuote =
'\'');
9001 std::vector<std::string> generate_parents(
const std::string §ion, std::string &name,
char parentSeparator);
9004 void checkParentSegments(std::vector<ConfigItem> &output,
const std::string ¤tSection,
char parentSeparator);
9012 CLI11_INLINE std::string convert_arg_for_ini(
const std::string &arg,
char stringQuote,
char characterQuote) {
9014 return std::string(2, stringQuote);
9017 if(arg ==
"true" || arg ==
"false" || arg ==
"nan" || arg ==
"inf") {
9021 if(arg.compare(0, 2,
"0x") != 0 && arg.compare(0, 2,
"0X") != 0) {
9023 if(detail::lexical_cast(arg, val)) {
9028 if(arg.size() == 1) {
9029 return std::string(1, characterQuote) + arg + characterQuote;
9032 if(arg.front() ==
'0') {
9034 if(std::all_of(arg.begin() + 2, arg.end(), [](
char x) {
9035 return (x >=
'0' && x <=
'9') || (x >=
'A' && x <=
'F') || (x >=
'a' && x <=
'f');
9039 }
else if(arg[1] ==
'o') {
9040 if(std::all_of(arg.begin() + 2, arg.end(), [](
char x) {
return (x >=
'0' && x <=
'7'); })) {
9043 }
else if(arg[1] ==
'b') {
9044 if(std::all_of(arg.begin() + 2, arg.end(), [](
char x) {
return (x ==
'0' || x ==
'1'); })) {
9049 if(arg.find_first_of(stringQuote) == std::string::npos) {
9050 return std::string(1, stringQuote) + arg + stringQuote;
9052 return characterQuote + arg + characterQuote;
9055 CLI11_INLINE std::string ini_join(
const std::vector<std::string> &args,
9060 char characterQuote) {
9062 if(args.size() > 1 && arrayStart !=
'\0') {
9063 joined.push_back(arrayStart);
9065 std::size_t start = 0;
9066 for(
const auto &arg : args) {
9068 joined.push_back(sepChar);
9069 if(!std::isspace<char>(sepChar, std::locale())) {
9070 joined.push_back(
' ');
9073 joined.append(convert_arg_for_ini(arg, stringQuote, characterQuote));
9075 if(args.size() > 1 && arrayEnd !=
'\0') {
9076 joined.push_back(arrayEnd);
9081 CLI11_INLINE std::vector<std::string>
9082 generate_parents(
const std::string §ion, std::string &name,
char parentSeparator) {
9083 std::vector<std::string> parents;
9084 if(detail::to_lower(section) !=
"default") {
9085 if(section.find(parentSeparator) != std::string::npos) {
9086 parents = detail::split(section, parentSeparator);
9088 parents = {section};
9091 if(name.find(parentSeparator) != std::string::npos) {
9092 std::vector<std::string> plist = detail::split(name, parentSeparator);
9093 name = plist.back();
9094 detail::remove_quotes(name);
9096 parents.insert(parents.end(), plist.begin(), plist.end());
9100 for(
auto &parent : parents) {
9101 detail::remove_quotes(parent);
9107 checkParentSegments(std::vector<ConfigItem> &output,
const std::string ¤tSection,
char parentSeparator) {
9109 std::string estring;
9110 auto parents = detail::generate_parents(currentSection, estring, parentSeparator);
9111 if(!output.empty() && output.back().name ==
"--") {
9112 std::size_t msize = (parents.size() > 1U) ? parents.size() : 2;
9113 while(output.back().parents.size() >= msize) {
9114 output.push_back(output.back());
9115 output.back().parents.pop_back();
9118 if(parents.size() > 1) {
9119 std::size_t common = 0;
9120 std::size_t mpair = (std::min)(output.back().parents.size(), parents.size() - 1);
9121 for(std::size_t ii = 0; ii < mpair; ++ii) {
9122 if(output.back().parents[ii] != parents[ii]) {
9127 if(common == mpair) {
9130 while(output.back().parents.size() > common + 1) {
9131 output.push_back(output.back());
9132 output.back().parents.pop_back();
9135 for(std::size_t ii = common; ii < parents.size() - 1; ++ii) {
9136 output.emplace_back();
9137 output.back().parents.assign(parents.begin(), parents.begin() + static_cast<std::ptrdiff_t>(ii) + 1);
9138 output.back().name =
"++";
9141 }
else if(parents.size() > 1) {
9142 for(std::size_t ii = 0; ii < parents.size() - 1; ++ii) {
9143 output.emplace_back();
9144 output.back().parents.assign(parents.begin(), parents.begin() + static_cast<std::ptrdiff_t>(ii) + 1);
9145 output.back().name =
"++";
9150 output.emplace_back();
9151 output.back().parents = std::move(parents);
9152 output.back().name =
"++";
9158 std::string currentSection =
"default";
9159 std::string previousSection =
"default";
9160 std::vector<ConfigItem> output;
9163 bool inSection{
false};
9164 char aStart = (isINIArray) ?
'[' :
arrayStart;
9165 char aEnd = (isINIArray) ?
']' :
arrayEnd;
9167 int currentSectionIndex{0};
9168 while(getline(input, line)) {
9169 std::vector<std::string> items_buffer;
9173 std::size_t len = line.length();
9178 if(line.front() ==
'[' && line.back() ==
']') {
9179 if(currentSection !=
"default") {
9181 output.emplace_back();
9182 output.back().parents = detail::generate_parents(currentSection, name,
parentSeparatorChar);
9183 output.back().name =
"--";
9185 currentSection = line.substr(1, len - 2);
9187 if(currentSection.size() > 1 && currentSection.front() ==
'[' && currentSection.back() ==
']') {
9188 currentSection = currentSection.substr(1, currentSection.size() - 2);
9190 if(detail::to_lower(currentSection) ==
"default") {
9191 currentSection =
"default";
9196 if(currentSection == previousSection) {
9197 ++currentSectionIndex;
9199 currentSectionIndex = 0;
9200 previousSection = currentSection;
9206 if(line.front() ==
';' || line.front() ==
'#' || line.front() ==
commentChar) {
9212 if(pos != std::string::npos) {
9213 name = detail::trim_copy(line.substr(0, pos));
9214 std::string item = detail::trim_copy(line.substr(pos + 1));
9216 if(cloc != std::string::npos) {
9217 item.erase(cloc, std::string::npos);
9220 if(item.size() > 1 && item.front() == aStart) {
9221 for(std::string multiline; item.back() != aEnd && std::getline(input, multiline);) {
9222 detail::trim(multiline);
9225 items_buffer = detail::split_up(item.substr(1, item.length() - 2), aSep);
9226 }
else if((isDefaultArray || isINIArray) && item.find_first_of(aSep) != std::string::npos) {
9227 items_buffer = detail::split_up(item, aSep);
9228 }
else if((isDefaultArray || isINIArray) && item.find_first_of(
' ') != std::string::npos) {
9229 items_buffer = detail::split_up(item);
9231 items_buffer = {item};
9234 name = detail::trim_copy(line);
9236 if(cloc != std::string::npos) {
9237 name.erase(cloc, std::string::npos);
9241 items_buffer = {
"true"};
9244 detail::remove_quotes(name);
9247 for(
auto &it : items_buffer) {
9248 detail::remove_quotes(it);
9251 std::vector<std::string> parents = detail::generate_parents(currentSection, name,
parentSeparatorChar);
9262 parents.erase(parents.begin());
9265 if(!output.empty() && name == output.back().name && parents == output.back().parents) {
9266 output.back().inputs.insert(output.back().inputs.end(), items_buffer.begin(), items_buffer.end());
9268 output.emplace_back();
9269 output.back().parents = std::move(parents);
9270 output.back().name = std::move(name);
9271 output.back().inputs = std::move(items_buffer);
9274 if(currentSection !=
"default") {
9277 output.emplace_back();
9278 output.back().parents = detail::generate_parents(currentSection, ename,
parentSeparatorChar);
9279 output.back().name =
"--";
9280 while(output.back().parents.size() > 1) {
9281 output.push_back(output.back());
9282 output.back().parents.pop_back();
9288 CLI11_INLINE std::string
9290 std::stringstream out;
9291 std::string commentLead;
9293 commentLead.push_back(
' ');
9295 std::vector<std::string> groups = app->
get_groups();
9296 bool defaultUsed =
false;
9297 groups.insert(groups.begin(), std::string(
"Options"));
9299 out << commentLead << detail::fix_newlines(commentLead, app->
get_description()) <<
'\n';
9301 for(
auto &group : groups) {
9302 if(group ==
"Options" || group.empty()) {
9308 if(write_description && group !=
"Options" && !group.empty()) {
9309 out <<
'\n' << commentLead << group <<
" Options\n";
9314 if(opt->get_configurable()) {
9315 if(opt->get_group() != group) {
9316 if(!(group ==
"Options" && opt->get_group().empty())) {
9320 std::string name = prefix + opt->get_single_name();
9321 std::string value = detail::ini_join(
9324 if(value.empty() && default_also) {
9325 if(!opt->get_default_str().empty()) {
9327 }
else if(opt->get_expected_min() == 0) {
9329 }
else if(opt->get_run_callback_for_default()) {
9334 if(!value.empty()) {
9335 if(!opt->get_fnames().empty()) {
9336 value = opt->get_flag_value(name, value);
9338 if(write_description && opt->has_description()) {
9340 out << commentLead << detail::fix_newlines(commentLead, opt->get_description()) <<
'\n';
9348 for(
const App *subcom : subcommands) {
9349 if(subcom->get_name().empty()) {
9350 if(write_description && !subcom->get_group().empty()) {
9351 out <<
'\n' << commentLead << subcom->get_group() <<
" Options\n";
9353 out <<
to_config(subcom, default_also, write_description, prefix);
9357 for(
const App *subcom : subcommands) {
9358 if(!subcom->get_name().empty()) {
9360 if(!prefix.empty() || app->
get_parent() ==
nullptr) {
9361 out <<
'[' << prefix << subcom->get_name() <<
"]\n";
9365 while(p->get_parent() !=
nullptr) {
9367 p = p->get_parent();
9369 out <<
'[' << subname <<
"]\n";
9371 out <<
to_config(subcom, default_also, write_description,
"");
9374 subcom, default_also, write_description, prefix + subcom->get_name() +
parentSeparatorChar);
9387 CLI11_INLINE std::string
9389 std::stringstream out;
9391 out <<
"\n" << group <<
":\n";
9392 for(
const Option *opt : opts) {
9400 std::vector<const Option *> opts =
9401 app->
get_options([](
const Option *opt) {
return !opt->get_group().empty() && opt->get_positional(); });
9410 std::stringstream out;
9411 std::vector<std::string> groups = app->
get_groups();
9414 for(
const std::string &group : groups) {
9415 std::vector<const Option *> opts = app->
get_options([app, mode, &group](
const Option *opt) {
9416 return opt->get_group() == group
9417 && opt->nonpositional()
9418 && (mode != AppFormatMode::Sub
9422 if(!group.empty() && !opts.empty()) {
9425 if(group != groups.back())
9438 desc +=
" REQUIRED ";
9440 if((max_options == min_options) && (min_options > 0)) {
9441 if(min_options == 1) {
9442 desc +=
" \n[Exactly 1 of the following options is required]";
9444 desc +=
" \n[Exactly " + std::to_string(min_options) +
"options from the following list are required]";
9446 }
else if(max_options > 0) {
9447 if(min_options > 0) {
9448 desc +=
" \n[Between " + std::to_string(min_options) +
" and " + std::to_string(max_options) +
9449 " of the follow options are required]";
9451 desc +=
" \n[At most " + std::to_string(max_options) +
" of the following options are allowed]";
9453 }
else if(min_options > 0) {
9454 desc +=
" \n[At least " + std::to_string(min_options) +
" of the following options are required]";
9456 return (!desc.empty()) ? desc +
"\n" : std::string{};
9460 std::stringstream out;
9462 out <<
get_label(
"Usage") <<
":" << (name.empty() ?
"" :
" ") << name;
9464 std::vector<std::string> groups = app->
get_groups();
9467 std::vector<const Option *> non_pos_options =
9468 app->
get_options([](
const Option *opt) {
return opt->nonpositional(); });
9469 if(!non_pos_options.empty())
9470 out <<
" [" <<
get_label(
"OPTIONS") <<
"]";
9473 std::vector<const Option *> positionals = app->
get_options([](
const Option *opt) {
return opt->get_positional(); });
9476 if(!positionals.empty()) {
9478 std::vector<std::string> positional_names(positionals.size());
9479 std::transform(positionals.begin(), positionals.end(), positional_names.begin(), [
this](
const Option *opt) {
9483 out <<
" " << detail::join(positional_names,
" ");
9488 [](
const CLI::App *subc) { return ((!subc->get_disabled()) && (!subc->get_name().empty())); })
9503 if(footer.empty()) {
9504 return std::string{};
9506 return "\n" + footer +
"\n";
9513 if(mode == AppFormatMode::Sub)
9516 std::stringstream out;
9534 std::stringstream out;
9539 std::vector<std::string> subcmd_groups_seen;
9540 for(
const App *com : subcommands) {
9541 if(com->get_name().empty()) {
9542 if(!com->get_group().empty()) {
9547 std::string group_key = com->get_group();
9548 if(!group_key.empty() &&
9549 std::find_if(subcmd_groups_seen.begin(), subcmd_groups_seen.end(), [&group_key](std::string a) {
9550 return detail::to_lower(a) == detail::to_lower(group_key);
9551 }) == subcmd_groups_seen.end())
9552 subcmd_groups_seen.push_back(group_key);
9556 for(
const std::string &group : subcmd_groups_seen) {
9557 out <<
"\n" << group <<
":\n";
9559 [&group](
const App *sub_app) {
return detail::to_lower(sub_app->
get_group()) == detail::to_lower(group); });
9560 for(
const App *new_com : subcommands_group) {
9561 if(new_com->get_name().empty())
9563 if(mode != AppFormatMode::All) {
9566 out << new_com->help(new_com->get_name(), AppFormatMode::Sub);
9576 std::stringstream out;
9582 std::stringstream out;
9594 std::string tmp = detail::find_and_replace(out.str(),
"\n\n",
"\n");
9595 tmp = tmp.substr(0, tmp.size() - 1);
9598 return detail::find_and_replace(tmp,
"\n",
"\n ") +
"\n";
9603 return opt->get_name(
true,
false);
9605 return opt->get_name(
false,
true);
9609 std::stringstream out;
9611 if(!opt->get_option_text().empty()) {
9612 out <<
" " << opt->get_option_text();
9614 if(opt->get_type_size() != 0) {
9615 if(!opt->get_type_name().empty())
9616 out <<
" " <<
get_label(opt->get_type_name());
9617 if(!opt->get_default_str().empty())
9618 out <<
" [" << opt->get_default_str() <<
"] ";
9619 if(opt->get_expected_max() == detail::expected_max_vector_size)
9621 else if(opt->get_expected_min() > 1)
9622 out <<
" x " << opt->get_expected();
9624 if(opt->get_required())
9627 if(!opt->get_envname().empty())
9628 out <<
" (" <<
get_label(
"Env") <<
":" << opt->get_envname() <<
")";
9629 if(!opt->get_needs().empty()) {
9630 out <<
" " <<
get_label(
"Needs") <<
":";
9631 for(
const Option *op : opt->get_needs())
9632 out <<
" " << op->get_name();
9634 if(!opt->get_excludes().empty()) {
9635 out <<
" " <<
get_label(
"Excludes") <<
":";
9636 for(
const Option *op : opt->get_excludes())
9637 out <<
" " << op->get_name();
9647 std::stringstream out;
9649 if(opt->get_expected_max() >= detail::expected_max_vector_size)
9651 else if(opt->get_expected_max() > 1)
9652 out <<
"(" << opt->get_expected() <<
"x)";
9654 return opt->get_required() ? out.str() :
"[" + out.str() +
"]";
9662 PXR_NAMESPACE_CLOSE_SCOPE
Anything that can error in Parse.
bool required_
True if this is a required option.
std::function< void()> parse_complete_callback_
This is a function that runs when parsing has finished.
App * silent(bool silence=true)
silence the subcommand from showing up in the processed list
ConfigBase * section(const std::string §ionName)
specify a particular section of the configuration file to use
CLI11_NODISCARD App * get_option_group(std::string group_name) const
Check to see if an option group is part of this App.
bool prefix_command_
If true, return immediately on an unrecognized option (implies allow_extras) INHERITABLE.
bool _parse_single(std::vector< std::string > &args, bool &positional_only)
Parse "one" argument (some may eat more than one), delegate to parent if fails, add to missing if mis...
CLI11_NODISCARD std::vector< ConfigItem > from_file(const std::string &name) const
Parse a config file, throw an error (ParseError:ConfigParseError or FileError) on failure.
void _configure()
configure subcommands to enable parsing through the current object set the correct fallthrough and pr...
Check for an existing path.
Option * add_flag_function(std::string flag_name, std::function< void(std::int64_t)> function, std::string flag_description="")
Add option for callback with an integer value.
App * callback(std::function< void()> app_callback)
Set a callback for execution when all parsing and processing has completed.
Validator(std::string validator_desc)
Construct a Validator with just the description string.
CLI11_NODISCARD Validator active(bool active_val=true) const
Specify whether the Validator is active or not.
Option * add_flag_callback(std::string flag_name, std::function< void(void)> function, std::string flag_description="")
Add option for callback that is triggered with a true flag and takes no arguments.
static auto parse_subcommand(App *app, Args &&...args) -> typename std::result_of< decltype(&App::_parse_subcommand)(App, Args...)>::type
Wrap _parse_subcommand, perfectly forward arguments and return.
CLI11_NODISCARD std::shared_ptr< Config > get_config_formatter() const
Access the config formatter.
char arrayStart
the character used to start an array '\0' is a default to not use
CLI11_NODISCARD bool get_allow_extras() const
Get the status of allow extras.
std::string operator()(std::string &str) const
This is the required operator for a Validator - provided to help users (CLI11 uses the member func di...
CLI11_NODISCARD bool get_validate_positionals() const
Get the status of validating positionals.
App * _get_fallthrough_parent()
Get the appropriate parent to fallthrough to which is the first one that has a name or the main app.
Handy helper to access the element_type generically.
std::function< void(std::size_t)> pre_parse_callback_
This is a function that runs prior to the start of parsing.
static auto second(Q &&pair_value) -> decltype(std::forward< Q >(pair_value))
Get the second value (really just the underlying value)
Option * set_config(std::string option_name="", std::string default_filename="", const std::string &help_message="Read an ini file", bool config_required=false)
Set a configuration ini file option, or clear it if no name passed.
Option * set_help_flag(std::string flag_name="", const std::string &help_description="")
Set a help flag, replace the existing one if present.
Thrown when validation of results fails.
Range(T min_val, T max_val, const std::string &validator_name=std::string{})
This produces a range with min and max inclusive.
bool validate_optional_arguments_
If set to true optional vector arguments are validated before assigning INHERITABLE.
App(std::string app_description="", std::string app_name="")
Create a new program. Pass in the same arguments as main(), along with a help string.
This class is simply to allow tests access to App's protected functions.
App * required(bool require=true)
Remove the error when extras are left over on the command line.
App * config_formatter(std::shared_ptr< Config > fmt)
Set the config formatter.
int exit(const Error &e, std::ostream &out=std::cout, std::ostream &err=std::cerr) const
Print a nice error message and return the exit code.
bool always_capture_default_
Automatically capture default value.
App * require_option()
The argumentless form of require option requires 1 or more options be used.
bool disable_flag_override_
Disable overriding flag values with '=value'.
CLI11_NODISCARD std::size_t remaining_size(bool recurse=false) const
This returns the number of remaining options, minus the – separator.
const Option * operator[](const std::string &option_name) const
Shortcut bracket operator for getting a pointer to an option.
CLI11_NODISCARD std::string help(std::string prev="", AppFormatMode mode=AppFormatMode::Normal) const
Makes a help message, using the currently configured formatter Will only do one subcommand at a time.
Option * set_help_all_flag(std::string help_name="", const std::string &help_description="")
Set a help all flag, replaced the existing one if present.
void run_callback(bool final_mode=false, bool suppress_final_callback=false)
Internal function to run (App) callback, bottom up.
void add_options(Option *opt, Args... args)
Add a bunch of options to the group.
std::string group_
The group membership.
App * allow_config_extras(bool allow=true)
ignore extras in config files
CRTP * take_first()
Set the multi option policy to take last.
ConfigBase * valueSeparator(char vSep)
Specify the delimiter between a name and value.
void _process_extras()
Throw an error if anything is left over and should not be.
CRTP * required(bool value=true)
Set the option as required.
std::uint32_t parsed_
Counts the number of times this command/subcommand was parsed.
CRTP * configurable(bool value=true)
Allow in a configuration file.
This will only trigger for actual void type.
bool got_subcommand(const App *subcom) const
Check to see if given subcommand was selected.
App * fallthrough(bool value=true)
Stop subcommand fallthrough, so that parent commands cannot collect commands after subcommand.
App * add_subcommand(App *subcom)
Add an existing subcommand to be a member of an option_group.
Check for an existing file (returns error message if check fails)
Validator & description(std::string validator_desc)
Specify the type string.
void add_options(Option *opt)
Add an existing option to the Option_group.
Thrown when parsing an INI file and it is missing.
Option * set_version_flag(std::string flag_name="", const std::string &versionString="", const std::string &version_help="Display program version information and exit")
Set a version flag and version display string, replace the existing one if present.
CLI11_NODISCARD const std::vector< std::string > & get_aliases() const
Get the aliases of the current app.
std::vector< App_p > subcommands_
Storage for subcommand list.
CLI11_NODISCARD const App * get_parent() const
Get the parent of this subcommand (or nullptr if main app) (const version)
CLI11_NODISCARD std::vector< std::string > remaining(bool recurse=false) const
This returns the missing options from the current subcommand.
std::size_t require_option_max_
Max number of options allowed. 0 is unlimited (not inheritable)
CLI11_NODISCARD const std::string & section() const
get the section
void _process_requirements()
Verify required options and cross requirements. Subcommands too (only if selected).
CLI11_NODISCARD bool _has_remaining_positionals() const
Count the required remaining positional arguments.
bool ignore_case_
Ignore the case when matching (option, not value)
Thrown when conversion call back fails, such as when an int fails to coerce to a string.
OptionDefaults * ignore_case(bool value=true)
Ignore the case of the option name.
bool configurable_
if set to true the subcommand can be triggered via configuration files INHERITABLE
std::string to_config(const App *, bool default_also, bool write_description, std::string prefix) const override
Convert an app into a configuration.
std::set< App * > exclude_subcommands_
this is a list of subcommands that are exclusionary to this one
CRTP * mandatory(bool value=true)
Support Plumbum term.
void _process_config_file()
Read and process a configuration file (main app only)
Option * help_ptr_
A pointer to the help flag if there is one INHERITABLE.
App * ignore_case(bool value=true)
Ignore case. Subcommands inherit value.
Bound(T max_val)
Range of one value is 0 to value.
Check to see if something is bool (fail check by default)
Option * get_config_ptr()
Get a pointer to the config option.
Thrown when counting a non-existent option.
CLI11_NODISCARD const Option * get_help_all_ptr() const
Get a pointer to the help all flag. (const)
ConfigBase * arrayDelimiter(char aSep)
Specify the delimiter character for an array.
CRTP * take_all()
Set the multi option policy to take all arguments.
uint8_t maximumLayers
the maximum number of layers to allow
Thrown when an excludes option is present.
Option * add_option(std::string option_name, callback_t option_callback, std::string option_description="", bool defaulted=false, std::function< std::string()> func={})
Add an option, will automatically understand the type for common types.
config_extras_mode allow_config_extras_
If ignore, allow extra arguments in the ini file (ie, don't throw an error).
App * prefix_command(bool allow=true)
Do not parse anything after the first unrecognized option and return.
Validate the input as a particular type.
std::vector< std::string > parents
This is the list of parents.
bool remove_needs(Option *opt)
Removes an option from the needs list of this subcommand.
CRTP * delimiter(char value='\0')
Allow in a configuration file.
void _process_help_flags(bool trigger_help=false, bool trigger_all_help=false) const
Run help flag processing if any are found.
void _parse(std::vector< std::string > &args)
Internal parse function.
Multiply a number by a factor using given mapping.
App * require_subcommand(int value)
Require a subcommand to be given (does not affect help call) The number required can be given.
IsMember(T &&set)
This checks to see if an item is in a set (empty function)
CLI::App_p get_subcommand_ptr(App *subcom) const
Check to see if a subcommand is part of this command and get a shared_ptr to it.
Option * help_all_ptr_
A pointer to the help all flag if there is one INHERITABLE.
bool fallthrough_
Allow subcommand fallthrough, so that parent commands can collect commands after subcommand....
void _move_option(Option *opt, App *app)
function that could be used by subclasses of App to shift options around into subcommands
CLI11_NODISCARD int get_application_index() const
Get the current value of the application index.
std::vector< App * > parsed_subcommands_
This is a list of the subcommands collected, in order.
CLI11_NODISCARD std::string version() const
Displays a version string.
bool disabled_
If set to true the subcommand is disabled and cannot be used, ignored for main app.
void _process()
Process callbacks and such.
App * disabled(bool disable=true)
Disable the subcommand or option group.
CLI11_NODISCARD bool get_silent() const
Get the status of silence.
Thrown when an option is set to conflicting values (non-vector and multi args, for example)
Set of overloads to get the type size of an object.
CLI11_NODISCARD std::size_t get_require_subcommand_max() const
Get the required max subcommand value.
AsSizeValue(bool kb_is_1000)
If kb_is_1000 is true, interpret 'kb', 'k' as 1000 and 'kib', 'ki' as 1024 (same applies to higher or...
char delimiter_
Specify a delimiter character for vector arguments.
bool _parse_arg(std::vector< std::string > &args, detail::Classifier current_type)
Parse a short (false) or long (true) argument, must be at the top of the list return true if the argu...
bool silent_
indicator that the subcommand is silent and won't show up in subcommands list This is potentially use...
Option * get_version_ptr()
Get a pointer to the version option.
ConfigBase * index(int16_t sectionIndex)
specify a particular index in the section to use (-1) for all sections to use
Validator operator!() const
Create a validator that fails when a given validator succeeds.
std::vector< Option_p > options_
The list of options, stored locally.
Check for input streamability.
void _process_env()
Get envname options if not yet passed. Runs on all subcommands.
App * disabled_by_default(bool disable=true)
Set the subcommand to be disabled by default, so on clear(), at the start of each parse it is disable...
App * validate_optional_arguments(bool validate=true)
Set the subcommand to validate optional vector arguments before assigning.
virtual CLI11_NODISCARD std::string to_flag(const ConfigItem &item) const
Get a flag value.
CLI11_NODISCARD MultiOptionPolicy get_multi_option_policy() const
The status of the multi option policy.
Option * add_flag(std::string flag_name, T &flag_description)
Add flag with description but with no variable assignment or callback takes a constant string,...
std::shared_ptr< Config > config_formatter_
This is the formatter for help printing. Default provided. INHERITABLE (same pointer)
Option * get_help_ptr()
Get a pointer to the help flag.
startup_mode default_startup
specify the startup mode for the app stable=no change, enabled= startup enabled, disabled=startup dis...
const Option * operator[](const char *option_name) const
Shortcut bracket operator for getting a pointer to an option.
App * group(std::string group_name)
Changes the group membership.
char arraySeparator
the character used to separate elements in an array
std::string description_
Description of the current program/subcommand.
static auto second(Q &&pair_value) -> decltype(std::get< 1 >(std::forward< Q >(pair_value)))
Get the second value (really just the underlying value)
Thrown on construction of a bad name.
bool ignore_underscore_
If true, the program should ignore underscores INHERITABLE.
Modify a path if the file is a particular default location, can be used as Check or transform with th...
Thrown when validation fails before parsing.
bool allow_extras_
If true, allow extra arguments (ie, don't throw an error). INHERITABLE.
This is a successful completion on parsing, supposed to exit.
CLI11_NODISCARD bool parsed() const
Check to see if this subcommand was parsed, true only if received on command line.
CLI11_NODISCARD std::string get_display_name(bool with_aliases=false) const
Get a display name for an app.
Combination of the element type and value type - remove pointer (including smart pointers) and get th...
T * add_option_group(std::string group_name, std::string group_description="")
creates an option group as part of the given app
void copy_to(T *other) const
Copy the contents to another similar class (one based on OptionBase)
App * footer(std::function< std::string()> footer_function)
Set footer.
App * excludes(Option *opt)
Sets excluded options for the subcommand.
App * require_option(int value)
Require an option to be given (does not affect help call) The number required can be given.
ConfigBase * arrayBounds(char aStart, char aEnd)
Specify the start and end characters for an array.
bool immediate_callback_
Flag indicating that the callback for the subcommand should be executed immediately on parse completi...
CLI11_NODISCARD App * _find_subcommand(const std::string &subc_name, bool ignore_disabled, bool ignore_used) const noexcept
Locate a subcommand by name with two conditions, should disabled subcommands be ignored,...
App * description(std::string app_description)
Set the description of the app.
CLI11_NODISCARD std::size_t get_require_option_min() const
Get the required min option value.
CLI11_NODISCARD std::size_t _count_remaining_positionals(bool required_only=false) const
Count the required remaining positional arguments.
Check for an non-existing path.
App * parse_complete_callback(std::function< void()> pc_callback)
Set a callback to execute when parsing has completed for the app.
std::shared_ptr< FormatterBase > formatter_
This is the formatter for help printing. Default provided. INHERITABLE (same pointer)
CLI11_NODISCARD const std::string & _compare_subcommand_names(const App &subcom, const App &base) const
Helper function to run through all possible comparisons of subcommand names to check there is no over...
CLI11_NODISCARD const Option * get_version_ptr() const
Get a pointer to the version option. (const)
CLI11_NODISCARD bool get_validate_optional_arguments() const
Get the status of validating optional vector arguments.
CRTP * take_last()
Set the multi option policy to take last.
CLI11_NODISCARD bool got_subcommand(std::string subcommand_name) const
Check with name instead of pointer to see if subcommand was selected.
bool has_automatic_name_
If set to true the name was automatically generated from the command line vs a user set name.
bool remove_subcommand(App *subcom)
Removes a subcommand from the App. Takes a subcommand pointer. Returns true if found and removed.
std::function< std::string(std::string &)> func_
This is the base function that is to be called.
App * require_subcommand(std::size_t min, std::size_t max)
Explicitly control the number of subcommands required.
CLI11_NODISCARD std::vector< App * > get_subcommands() const
Get a subcommand pointer list to the currently selected subcommands (after parsing by default,...
Option * add_option(Option *opt)
Add an existing option to the Option_group.
bool pre_parse_called_
Flag indicating that the pre_parse_callback has been triggered.
std::ostream & operator<<(std::ostream &in, const T &item)
output streaming for enumerations
OptionDefaults * option_defaults()
Get the OptionDefault object, to set option defaults.
IsMember(T set, F filter_function)
This checks to see if an item is in a set: pointer or copy version.
App * immediate_callback(bool immediate=true)
Set the subcommand callback to be executed immediately on subcommand completion.
bool configurable_
Allow this option to be given in a configuration file.
void failure_message(std::function< std::string(const App *, const Error &e)> function)
Provide a function to print a help message. The function gets access to the App pointer and error.
CRTP * join()
Set the multi option policy to join.
std::function< std::string()> desc_function_
This is the description function, if empty the description_ will be used.
std::string name
This is the name.
forward declare the subtype_count_min structure
Check to see if something is a shared pointer.
bool active_
Enable for Validator to allow it to be disabled if need be.
CLI11_NODISCARD bool get_required() const
Get the status of required.
Option * add_flag(std::string flag_name)
Add a flag with no description or variable assignment.
CRTP * group(const std::string &name)
Changes the group membership.
void swap(UsdStageLoadRules &l, UsdStageLoadRules &r)
Swap the contents of rules l and r.
std::set< App * > need_subcommands_
this is a list of subcommands or option groups that are required by this one, the list is not mutual,...
ConfigINI generates a "standard" INI compliant output.
template to get the underlying value type if it exists or use a default
-h or –help on command line
CLI11_NODISCARD std::string fullname() const
The list of parents and name joined by ".".
int16_t & indexRef()
get a reference to the configuration index
std::vector< std::string > inputs
Listing of inputs.
Construction errors (not in parsing)
std::string name_
The name for search purposes of the Validator.
char arrayEnd
the character used to end an array '\0' is a default to not use
CLI11_NODISCARD const Option * get_config_ptr() const
Get a pointer to the config option. (const)
This is a version of OptionBase that only supports setting values, for defaults.
ConfigBase * comment(char cchar)
Specify the configuration for comment characters.
bool _parse_positional(std::vector< std::string > &args, bool haltOnSubcommand)
Parse a positional, go up the tree to check.
Validator & operation(std::function< std::string(std::string &)> op)
Set the Validator operation function.
void clear()
Reset the parsed data.
Validator operator|(const Validator &other) const
Combining validators is a new validator.
App * validate_positionals(bool validate=true)
Set the subcommand to validate positional arguments before assigning.
char valueDelimiter
the character used separate the name from the value
static auto parse_arg(App *app, Args &&...args) -> typename std::result_of< decltype(&App::_parse_arg)(App, Args...)>::type
Wrap _parse_short, perfectly forward arguments and return.
ConfigBase * maxLayers(uint8_t layers)
Specify the maximum number of parents.
App * excludes(App *app)
Sets excluded subcommands for the subcommand.
CLI11_NODISCARD std::vector< std::string > get_groups() const
Get the groups available directly from this option (in order)
App * ignore_underscore(bool value=true)
Ignore underscore. Subcommands inherit value.
This is the CRTP base class for Option and OptionDefaults.
Option * add_flag(std::string flag_name, std::vector< T > &flag_results, std::string flag_description="")
Vector version to capture multiple flags.
OptionDefaults * multi_option_policy(MultiOptionPolicy value=MultiOptionPolicy::Throw)
Take the last argument if given multiple times.
Thrown when an option already exists.
Option * get_option(std::string option_name)
Get an option by name (non-const version)
CLI11_NODISCARD std::size_t count_all() const
Get a count of all the arguments processed in options and subcommands, this excludes arguments which ...
Validate the given string is a legal ipv4 address.
CLI11_NODISCARD std::size_t get_require_subcommand_min() const
Get the required min subcommand value.
bool positionals_at_end_
specify that positional arguments come at the end of the argument sequence not inheritable
OptionDefaults * ignore_underscore(bool value=true)
Ignore underscores in the option name.
CLI11_NODISCARD const std::string & get_group() const
Get the group of this option.
CLI11_NODISCARD bool check_name(std::string name_to_check) const
Check the name, case insensitive and underscore insensitive if set.
CLI11_NODISCARD bool get_ignore_underscore() const
Check the status of ignore_underscore.
App(std::string app_description, std::string app_name, App *parent)
Special private constructor for subcommand.
Thrown when a required option is missing.
ConfigBase * quoteCharacter(char qString, char qChar)
Specify the quote characters used around strings and characters.
Validator(std::function< std::string(std::string &)> op, std::string validator_desc, std::string validator_name="")
Construct Validator from basic information.
App * parent_
A pointer to the parent if this is a subcommand.
Does not output a diagnostic in CLI11_PARSE, but allows main() to return with a specific error code.
CLI11_NODISCARD std::shared_ptr< FormatterBase > get_formatter() const
Access the formatter.
std::string footer_
Footer to put after all options in the help output INHERITABLE.
MultiOptionPolicy multi_option_policy_
Policy for handling multiple arguments beyond the expected Max.
void _move_to_missing(detail::Classifier val_type, const std::string &val)
Helper function to place extra values in the most appropriate position.
Class wrapping some of the accessors of Validator.
App * allow_windows_style_options(bool value=true)
Allow windows style options, such as /opt.
All errors derive from this one.
CLI11_NODISCARD std::string get_description() const
Generate type description information for the Validator.
CLI11_NODISCARD bool get_required() const
True if this is a required option.
CLI11_NODISCARD detail::Classifier _recognize(const std::string ¤t, bool ignore_used_subcommands=true) const
Selects a Classifier enum based on the type of the current argument.
App * allow_config_extras(config_extras_mode mode)
ignore extras in config files
Options
Adjust AsNumberWithUnit behavior.
CLI11_NODISCARD bool get_modifying() const
Get a boolean if the validator is allowed to modify the input returns true if it can modify the input...
CLI11_NODISCARD bool get_configurable() const
The status of configurable.
CLI11_NODISCARD std::size_t get_require_option_max() const
Get the required max option value.
std::size_t require_subcommand_min_
Minimum required subcommands (not inheritable!)
std::string configSection
Specify the configuration section that should be used.
CLI11_NODISCARD bool get_immediate_callback() const
Get the status of disabled.
CLI11_NODISCARD bool get_prefix_command() const
Get the prefix command status.
std::string & sectionRef()
get a reference to the configuration section
Thrown when extra values are found in an INI file.
App * configurable(bool value=true)
Specify that the subcommand can be triggered by a config file.
App * enabled_by_default(bool enable=true)
Set the subcommand to be enabled by default, so on clear(), at the start of each parse it is enabled ...
CLI11_NODISCARD Validator application_index(int app_index) const
Specify the application index of a validator.
-v or –version on command line
int application_index_
A Validator will only apply to an indexed value (-1 is all elements)
OptionDefaults * delimiter(char value='\0')
set a delimiter character to split up single arguments to treat as multiple inputs
Thrown when the wrong number of arguments has been received.
CLI11_NODISCARD std::string get_footer() const
Generate and return the footer.
void increment_parsed()
Internal function to recursively increment the parsed counter on the current app as well unnamed subc...
bool required_
If set to true the subcommand is required to be processed and used, ignored for main app.
Option * add_option_function(std::string option_name, const std::function< void(const ArgType &)> &func, std::string option_description="")
Add option for a callback of a specific type.
CLI11_NODISCARD bool get_positionals_at_end() const
Check the status of the allow windows style options.
CLI11_NODISCARD std::size_t count(std::string option_name) const
Counts the number of times the given option was passed.
App * footer(std::string footer_string)
Set footer.
Option * config_ptr_
Pointer to the config option.
std::function< void()> final_callback_
This is a function that runs when all processing has completed.
CLI11_NODISCARD bool get_enabled_by_default() const
Get the status of disabled by default.
CLI11_NODISCARD const std::string & get_name() const
Get the name of the Validator.
App * require_option(std::size_t min, std::size_t max)
Explicitly control the number of options required.
void _validate() const
Check the options to make sure there are no conflicts.
bool ignore_case_
If true, the program name is not case sensitive INHERITABLE.
std::vector< std::string > aliases_
Alias names for the subcommand.
Validator operator &(const Validator &other) const
Combining validators is a new validator.
Produce a range (factory). Min and max are inclusive.
Range(T max_val, const std::string &validator_name=std::string{})
Range of one value is 0 to value.
App * formatter_fn(std::function< std::string(const App *, std::string, AppFormatMode)> fmt)
Set the help formatter.
bool allow_windows_style_options_
Allow '/' for options for Windows like options. Defaults to true on Windows, false otherwise....
App * get_subcommand(const App *subcom) const
Check to see if a subcommand is part of this command (doesn't have to be in command line) returns the...
std::string name_
Subcommand name or program name (from parser if name is empty)
App * require_subcommand()
The argumentless form of require subcommand requires 1 or more subcommands.
App * get_parent()
Get the parent of this subcommand (or nullptr if main app)
Extension of App to better manage groups of options.
Validator & application_index(int app_index)
Specify the application index of a validator.
IsMember(T &&set, filter_fn_t filter_fn_1, filter_fn_t filter_fn_2, Args &&...other)
You can pass in as many filter functions as you like, they nest (string only currently)
CLI11_NODISCARD bool get_active() const
Get a boolean if the validator is active.
App * clear_aliases()
clear all the aliases of the current App
CLI11_NODISCARD bool get_allow_windows_style_options() const
Check the status of the allow windows style options.
void _parse_config(const std::vector< ConfigItem > &args)
Parse one config param, return false if not found in any subcommand, remove if it is.
Option * get_option_no_throw(std::string option_name) noexcept
Get an option by name (noexcept non-const version)
CLI11_NODISCARD bool get_fallthrough() const
Check the status of fallthrough.
This can be specialized to override the type deduction for IsMember.
Converts a human-readable size string (with unit literal) to uin64_t size.
std::vector< const Option * > get_options(const std::function< bool(const Option *)> filter={}) const
Get the list of options (user facing function, so returns raw pointers), has optional filter function...
std::string operator()(const std::string &str) const
This is the required operator for a Validator - provided to help users (CLI11 uses the member func di...
void parse(int argc, const char *const *argv)
Parses the command line - throws errors.
A copy of std::void_t from C++17 (helper for C++11 and C++14)
App * allow_extras(bool allow=true)
Remove the error when extras are left over on the command line.
std::set< Option * > need_options_
This is a list of options which are required by this app, the list is not mutual, listed options do n...
Validator & name(std::string validator_name)
Specify the type string.
Option * add_option(std::string option_name, AssignTo &variable, std::string option_description="")
Add option for assigning to a variable.
CLI11_NODISCARD const Option * get_help_ptr() const
Get a pointer to the help flag. (const)
std::vector< Option * > parse_order_
This is a list of pointers to options with the original parse order.
CRTP * join(char delim)
Set the multi option policy to join with a specific delimiter.
bool remove_excludes(Option *opt)
Removes an option from the excludes list of this subcommand.
This class provides a converter for configuration files.
App * add_subcommand(std::string subcommand_name="", std::string subcommand_description="")
Add a subcommand. Inherits INHERITABLE and OptionDefaults, and help flag.
Validator & active(bool active_val=true)
Specify whether the Validator is active or not.
Check to see if something is copyable pointer.
std::vector< ConfigItem > from_config(std::istream &input) const override
Convert a configuration into an app.
App * final_callback(std::function< void()> app_callback)
Set a callback for execution when all parsing and processing has completed aliased as callback.
OptionDefaults option_defaults_
The default values for options, customizable and changeable INHERITABLE.
Bound(T min_val, T max_val)
This bounds a value with min and max inclusive.
static auto first(Q &&pair_value) -> decltype(std::get< 0 >(std::forward< Q >(pair_value)))
Get the first value (really just the underlying value)
virtual ~App()=default
virtual destructor
CLI11_NODISCARD std::size_t count() const
No argument version of count counts the number of times this subcommand was passed in.
CLI11_NODISCARD const std::string & get_name() const
Get the name of the current app.
std::string group_
The group membership INHERITABLE.
Option * add_option_no_stream(std::string option_name, AssignTo &variable, std::string option_description="")
Add option for assigning to a variable.
bool remove_option(Option *opt)
Removes an option from the App. Takes an option pointer. Returns true if found and removed.
virtual void pre_callback()
This allows subclasses to inject code before callbacks but after parse.
CLI11_NODISCARD int16_t index() const
get the section index
std::function< std::string()> footer_callback_
This is a function that generates a footer to put after all other options in help output.
CLI11_NODISCARD bool get_disabled() const
Get the status of disabled.
CLI11_NODISCARD std::string config_to_str(bool default_also=false, bool write_description=false) const
Produce a string that could be read in as a config of the current values of the App.
Adaptor for set-like structure: This just wraps a normal container in a few utilities that do almost ...
ConfigBase * parentSeparator(char sep)
Specify the separator to use for parent layers.
VT_API bool operator==(VtDictionary const &, VtDictionary const &)
Equality comparison.
CLI11_NODISCARD const std::string & get_group() const
Get the group of this subcommand.
CLI11_NODISCARD const std::vector< Option * > & parse_order() const
This gets a vector of pointers with the original parse order.
CLI11_NODISCARD bool get_configurable() const
Check the status of the allow windows style options.
void _process_callbacks()
Process callbacks. Runs on all subcommands.
CLI11_NODISCARD char get_delimiter() const
Get the current delimiter char.
bool _parse_single_config(const ConfigItem &item, std::size_t level=0)
Fill in a single config option.
CLI11_NODISCARD std::string get_description() const
Get the app or subcommand description.
CLI11_NODISCARD bool _valid_subcommand(const std::string ¤t, bool ignore_used=true) const
Check to see if a subcommand is valid. Give up immediately if subcommand max has been reached.
void _trigger_pre_parse(std::size_t remaining_args)
Trigger the pre_parse callback if needed.
static auto first(Q &&pair_value) -> decltype(std::forward< Q >(pair_value))
Get the first value (really just the underlying value)
std::function< std::string(const App *, const Error &e)> failure_message_
The error message printing function INHERITABLE.
App * name(std::string app_name="")
Set a name for the app (empty will use parser to set the name)
char parentSeparatorChar
the separator used to separator parent layers
Option * add_option(std::string option_name)
Add option with no description or variable assignment.
Option * version_ptr_
A pointer to a version flag if there is one.
Option * add_flag(std::string flag_name, T &flag_result, std::string flag_description="")
Other type version accepts all other types that are not vectors such as bool, enum,...
CLI11_NODISCARD std::vector< std::string > remaining_for_passthrough(bool recurse=false) const
This returns the missing options in a form ready for processing by another command line program.
Usually something like –help-all on command line.
This converter works with INI/TOML files; to write INI files use ConfigINI.
App * preparse_callback(std::function< void(std::size_t)> pp_callback)
Set a callback to execute prior to parsing.
CLI11_NODISCARD bool get_ignore_case() const
Check the status of ignore_case.
char commentChar
the character used for comments
char characterQuote
the character to use around single characters
Option * add_option(std::string option_name, T &option_description)
Add option with description but with no variable assignment or callback.
CLI11_NODISCARD bool get_disable_flag_override() const
The status of configurable.
CLI11_NODISCARD bool get_disabled_by_default() const
Get the status of disabled by default.
void _parse_stream(std::istream &input)
Internal function to parse a stream.
bool ignore_underscore_
Ignore underscores when matching (option, not value)
bool validate_positionals_
If set to true positional options are validated before assigning INHERITABLE.
int16_t configIndex
Specify the configuration index to use for arrayed sections.
CLI11_NODISCARD const Option * get_option(std::string option_name) const
Get an option by name.
CLI11_NODISCARD config_extras_mode get_allow_config_extras() const
Get the status of allow extras.
CLI11_NODISCARD Validator name(std::string validator_name) const
Specify the type string.
bool _parse_subcommand(std::vector< std::string > &args)
Parse a subcommand, modify args and continue.
CLI11_NODISCARD bool get_ignore_case() const
The status of ignore case.
Thrown when a requires option is missing.
This will only trigger for actual void type.
App * formatter(std::shared_ptr< FormatterBase > fmt)
Set the help formatter.
CLI11_NODISCARD bool get_always_capture_default() const
Return true if this will automatically capture the default value for help printing.
This is just a safety check to verify selection and parsing match - you should not ever see it String...
Some validators that are provided.
char stringQuote
the character to use around strings
std::size_t require_option_min_
Minimum required options (not inheritable!)
missing_t missing_
Pair of classifier, string for missing options.
Produce a bounded range (factory). Min and max are inclusive.
std::size_t require_subcommand_max_
Max number of subcommands allowed (parsing stops after this number). 0 is unlimited INHERITABLE.
CLI11_NODISCARD bool get_ignore_underscore() const
The status of ignore_underscore.
Verify items are in a set.
Creates a command line program, with very few defaults.
IsMember(std::initializer_list< T > values, Args &&...args)
This allows in-place construction using an initializer list.
Check for an existing directory (returns error message if check fails)
App * alias(std::string app_name)
Set an alias for the app.
App * positionals_at_end(bool value=true)
Specify that the positional arguments are only at the end of the sequence.
Holds values to load into Options.
OptionDefaults * disable_flag_override(bool value=true)
Disable overriding flag values with an '=' segment.
CLI11_NODISCARD std::shared_ptr< ConfigBase > get_config_formatter_base() const
Access the config formatter as a configBase pointer.
static App * get_fallthrough_parent(App *app)
Wrap the fallthrough parent function to make sure that is working correctly.
std::set< Option * > exclude_options_
This is a list of options which are exclusionary to this App, if the options were used this subcomman...
Validator & non_modifying(bool no_modify=true)
Specify whether the Validator can be modifying or not.