38#error This file should only be included once in any given source (.cpp) file.
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
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
183#include <sys/types.h>
190PXR_NAMESPACE_OPEN_SCOPE
202template <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);
211using enums::operator<<;
216constexpr int expected_max_vector_size{1 << 29};
219CLI11_INLINE std::vector<std::string> split(
const std::string &s,
char delim);
222template <
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++;
237 typename =
typename std::enable_if<!std::is_constructible<std::string, Callable>::value>::type>
238std::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();
255template <
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];
268CLI11_INLINE std::string <rim(std::string &str);
271CLI11_INLINE std::string <rim(std::string &str,
const std::string &filter);
274CLI11_INLINE std::string &rtrim(std::string &str);
277CLI11_INLINE std::string &rtrim(std::string &str,
const std::string &filter);
280inline std::string &trim(std::string &str) {
return ltrim(rtrim(str)); }
283inline std::string &trim(std::string &str,
const std::string filter) {
return ltrim(rtrim(str, filter), filter); }
286inline std::string trim_copy(
const std::string &str) {
292CLI11_INLINE std::string &remove_quotes(std::string &str);
298CLI11_INLINE std::string fix_newlines(
const std::string &leader, std::string input);
301inline std::string trim_copy(
const std::string &str,
const std::string &filter) {
303 return trim(s, filter);
306CLI11_INLINE std::ostream &
307format_help(std::ostream &out, std::string name,
const std::string &description, std::size_t wid);
310CLI11_INLINE std::ostream &format_aliases(std::ostream &out,
const std::vector<std::string> &aliases, std::size_t wid);
314template <
typename T>
bool valid_first_char(T c) {
return ((c !=
'-') && (c !=
'!') && (c !=
' ') && c !=
'\n'); }
317template <
typename T>
bool valid_later_char(T c) {
321 return ((c !=
'=') && (c !=
':') && (c !=
'{') && (c !=
' ') && c !=
'\n');
325CLI11_INLINE
bool valid_name_string(
const std::string &str);
328inline 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);
334inline bool is_separator(
const std::string &str) {
335 static const std::string sep(
"%%");
336 return (str.empty() || str == sep);
340inline bool isalpha(
const std::string &str) {
341 return std::all_of(str.begin(), str.end(), [](
char c) { return std::isalpha(c, std::locale()); });
345inline 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());
353inline std::string remove_underscore(std::string str) {
354 str.erase(std::remove(std::begin(str), std::end(str),
'_'), std::end(str));
359CLI11_INLINE std::string find_and_replace(std::string str, std::string from, std::string to);
362inline bool has_default_flag_values(
const std::string &flags) {
363 return (flags.find_first_of(
"{!") != std::string::npos);
366CLI11_INLINE
void remove_default_flag_values(std::string &flags);
369CLI11_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);
376template <
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);
386CLI11_INLINE std::vector<std::string> split_up(std::string str,
char delimiter =
'\0');
392CLI11_INLINE std::size_t escape_detect(std::string &str, std::size_t offset);
395CLI11_INLINE std::string &add_quotes_if_needed(std::string &str);
403CLI11_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);
419CLI11_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);
425CLI11_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);
431CLI11_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());
437CLI11_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());
444CLI11_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);
454CLI11_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);
466CLI11_INLINE std::ostream &
467format_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)) <<
"";
484CLI11_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);
501CLI11_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))
512CLI11_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();
524CLI11_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());
537CLI11_INLINE std::ptrdiff_t
538find_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);
565CLI11_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;
617CLI11_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] ==
'=') ?
'-' :
'/'))
629CLI11_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) {}
662enum class ExitCodes {
664 IncorrectConstruction = 100,
691class 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
982enum class enabler {};
985constexpr enabler dummy = {};
993template <
bool B,
class T =
void>
using enable_if_t =
typename std::enable_if<B, T>::type;
996template <
typename... Ts>
struct make_void {
using type = void; };
999template <
typename... Ts>
using void_t =
typename make_void<Ts...>::type;
1002template <
bool B,
class T,
class F>
using conditional_t =
typename std::conditional<B, T, F>::type;
1005template <
typename T>
struct is_bool : std::false_type {};
1008template <>
struct is_bool<bool> : std::true_type {};
1028template <>
struct IsMemberType<const char *> {
using type = std::string; };
1038template <
typename T,
typename Enable =
void>
struct element_type {
using type = T; };
1040template <
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;
1049template <
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);
1066template <
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"
1096template <
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
1124template <
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;
1157template <typename T, enable_if_t<is_istreamable<T>::value, detail::enabler> = detail::dummy>
1158bool from_stream(
const std::string &istring, T &obj) {
1159 std::istringstream is;
1162 return !is.fail() && !is.rdbuf()->in_avail();
1165template <typename T, enable_if_t<!is_istreamable<T>::value, detail::enabler> = detail::dummy>
1166bool from_stream(
const std::string & , T & ) {
1171template <
typename T,
typename _ =
void>
struct is_mutable_container : std::false_type {};
1176template <
typename T>
1177struct 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> {};
1189template <
typename T,
typename _ =
void>
struct is_readable_container : std::false_type {};
1194template <
typename T>
1195struct 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 {};
1201template <
typename T,
typename _ =
void>
struct is_wrapper : std::false_type {};
1204template <
typename T>
1205struct is_wrapper<T, conditional_t<false, void_t<typename T::value_type>, void>> :
public std::true_type {};
1208template <
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;
1220template <typename T, enable_if_t<std::is_convertible<T, std::string>::value, detail::enabler> = detail::dummy>
1221auto to_string(T &&value) ->
decltype(std::forward<T>(value)) {
1222 return std::forward<T>(value);
1226template <
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>
1229std::string to_string(
const T &value) {
1230 return std::string(value);
1234template <
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>
1238std::string to_string(T &&value) {
1239 std::stringstream stream;
1241 return stream.str();
1245template <
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>
1249std::string to_string(T &&) {
1254template <
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>
1258std::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) +
"]"};
1273template <
typename T1,
1276 enable_if_t<std::is_same<T1, T2>::value, detail::enabler> = detail::dummy>
1277auto checked_to_string(T &&value) ->
decltype(to_string(std::forward<T>(value))) {
1278 return to_string(std::forward<T>(value));
1282template <
typename T1,
1285 enable_if_t<!std::is_same<T1, T2>::value, detail::enabler> = detail::dummy>
1286std::string checked_to_string(T &&) {
1287 return std::string{};
1290template <typename T, enable_if_t<std::is_arithmetic<T>::value, detail::enabler> = detail::dummy>
1291std::string value_string(
const T &value) {
1292 return std::to_string(value);
1295template <typename T, enable_if_t<std::is_enum<T>::value, detail::enabler> = detail::dummy>
1296std::string value_string(
const T &value) {
1297 return std::to_string(
static_cast<typename std::underlying_type<T>::type
>(value));
1300template <
typename T,
1301 enable_if_t<!std::is_enum<T>::value && !std::is_arithmetic<T>::value, detail::enabler> = detail::dummy>
1302auto value_string(
const T &value) ->
decltype(to_string(value)) {
1303 return to_string(value);
1307template <
typename T,
typename def,
typename Enable =
void>
struct wrapped_type {
using type = def; };
1310template <
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;
1315template <
typename T,
typename Enable =
void>
struct type_count_base {
static const int value{0}; };
1318template <
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};
1326template <
typename T>
1327struct 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};
1332template <
typename T>
struct type_count_base<T, typename
std::enable_if<is_mutable_container<T>::value>::type> {
1345template <
typename T,
typename Enable =
void>
struct type_count {
static const int value{0}; };
1348template <
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};
1356template <
typename T>
struct type_count<T, typename
std::enable_if<is_complex<T>::value>::type> {
1357 static constexpr int value{2};
1361template <
typename T>
struct type_count<T, typename
std::enable_if<is_mutable_container<T>::value>::type> {
1366template <
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> {
1374template <
typename T, std::
size_t I>
1375constexpr typename std::enable_if<I == type_count_base<T>::value,
int>::type tuple_type_size() {
1380template <
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>();
1386template <
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>()};
1391template <
typename T>
struct subtype_count {
1392 static constexpr int value{is_mutable_container<T>::value ? expected_max_vector_size : type_count<T>::value};
1396template <
typename T,
typename Enable =
void>
struct type_count_min {
static const int value{0}; };
1399template <
typename T>
1400struct 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};
1408template <
typename T>
struct type_count_min<T, typename
std::enable_if<is_complex<T>::value>::type> {
1409 static constexpr int value{1};
1413template <
typename T>
1414struct 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};
1421template <
typename T, std::
size_t I>
1422constexpr typename std::enable_if<I == type_count_base<T>::value,
int>::type tuple_type_size_min() {
1427template <
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>();
1433template <
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>()};
1438template <
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};
1445template <
typename T,
typename Enable =
void>
struct expected_count {
static const int value{0}; };
1448template <
typename T>
1449struct 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};
1455template <
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};
1460template <
typename T>
1461struct 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};
1466enum 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,
1491template <
typename T,
typename Enable =
void>
struct classify_object {
1492 static constexpr object_category value{object_category::other};
1496template <
typename T>
1497struct 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};
1505template <
typename T>
1506struct 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};
1513template <
typename T>
1514struct 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};
1519template <
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};
1524template <
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};
1529template <
typename T>
1530struct 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};
1537template <
typename T>
1538struct 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};
1547template <
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};
1551template <
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};
1557template <
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;
1568template <
typename T>
1569struct 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};
1576template <
typename T>
1577struct 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};
1585template <
typename T>
1586struct 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};
1594template <
typename T>
1595struct 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};
1603template <
typename T>
1604struct 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};
1620template <
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};
1630template <
typename T,
1631 enable_if_t<classify_object<T>::value == object_category::char_value, detail::enabler> = detail::dummy>
1632constexpr const char *type_name() {
1636template <
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>
1640constexpr const char *type_name() {
1644template <
typename T,
1645 enable_if_t<classify_object<T>::value == object_category::unsigned_integral, detail::enabler> = detail::dummy>
1646constexpr const char *type_name() {
1650template <
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>
1655constexpr const char *type_name() {
1660template <
typename T,
1661 enable_if_t<classify_object<T>::value == object_category::enumeration, detail::enabler> = detail::dummy>
1662constexpr const char *type_name() {
1667template <
typename T,
1668 enable_if_t<classify_object<T>::value == object_category::boolean_value, detail::enabler> = detail::dummy>
1669constexpr const char *type_name() {
1674template <
typename T,
1675 enable_if_t<classify_object<T>::value == object_category::complex_number, detail::enabler> = detail::dummy>
1676constexpr const char *type_name() {
1681template <
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>
1685constexpr const char *type_name() {
1689template <
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>
1692std::string type_name();
1695template <
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>
1699std::string type_name();
1702template <
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>
1705inline std::string type_name() {
1706 return type_name<typename std::decay<typename std::tuple_element<0, T>::type>::type>();
1710template <
typename T, std::
size_t I>
1711inline typename std::enable_if<I == type_count_base<T>::value, std::string>::type tuple_name() {
1712 return std::string{};
1716template <
typename T, std::
size_t I>
1717inline 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() ==
',')
1726template <
typename T,
1727 enable_if_t<classify_object<T>::value == object_category::tuple_value && type_count_base<T>::value >= 2,
1729inline std::string type_name() {
1730 auto tname = std::string(1,
'[') + tuple_name<T, 0>();
1731 tname.push_back(
']');
1736template <
typename T,
1737 enable_if_t<classify_object<T>::value == object_category::container_value ||
1738 classify_object<T>::value == object_category::wrapper_value,
1740inline std::string type_name() {
1741 return type_name<typename T::value_type>();
1747template <typename T, enable_if_t<std::is_unsigned<T>::value, detail::enabler> = detail::dummy>
1748bool 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);
1768template <typename T, enable_if_t<std::is_signed<T>::value, detail::enabler> = detail::dummy>
1769bool 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);
1788inline 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);
1831template <
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>
1835bool lexical_cast(
const std::string &input, T &output) {
1836 return integral_conversion(input, output);
1840template <
typename T,
1841 enable_if_t<classify_object<T>::value == object_category::char_value, detail::enabler> = detail::dummy>
1842bool 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);
1851template <
typename T,
1852 enable_if_t<classify_object<T>::value == object_category::boolean_value, detail::enabler> = detail::dummy>
1853bool 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] !=
'-');
1869template <
typename T,
1870 enable_if_t<classify_object<T>::value == object_category::floating_point, detail::enabler> = detail::dummy>
1871bool 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());
1882template <
typename T,
1883 enable_if_t<classify_object<T>::value == object_category::complex_number, detail::enabler> = detail::dummy>
1884bool 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);
1914template <
typename T,
1915 enable_if_t<classify_object<T>::value == object_category::string_assignable, detail::enabler> = detail::dummy>
1916bool lexical_cast(
const std::string &input, T &output) {
1924 enable_if_t<classify_object<T>::value == object_category::string_constructible, detail::enabler> = detail::dummy>
1925bool lexical_cast(
const std::string &input, T &output) {
1931template <
typename T,
1932 enable_if_t<classify_object<T>::value == object_category::enumeration, detail::enabler> = detail::dummy>
1933bool 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);
1943template <
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>
1947bool 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);
1956template <
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>
1960bool 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>
1973bool 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>
1993bool 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>
2006bool lexical_cast(
const std::string &input, T &output) {
2008 if(lexical_cast(input, val)) {
2012 return from_stream(input, output);
2016template <
typename T,
2017 enable_if_t<classify_object<T>::value == object_category::other && std::is_assignable<T &, int>::value,
2018 detail::enabler> = detail::dummy>
2019bool lexical_cast(
const std::string &input, T &output) {
2021 if(integral_conversion(input, val)) {
2023#pragma warning(push)
2024#pragma warning(disable : 4800)
2037 return from_stream(input, output);
2042template <
typename T,
2043 enable_if_t<classify_object<T>::value == object_category::other && !std::is_assignable<T &, int>::value,
2044 detail::enabler> = detail::dummy>
2045bool 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);
2054template <
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>
2060bool lexical_assign(
const std::string &input, AssignTo &output) {
2061 return lexical_cast(input, output);
2065template <
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>
2071bool lexical_assign(
const std::string &input, AssignTo &output) {
2073 output = AssignTo{};
2077 return lexical_cast(input, output);
2081template <
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>
2086bool lexical_assign(
const std::string &input, AssignTo &output) {
2088 typename AssignTo::value_type emptyVal{};
2092 return lexical_cast(input, output);
2097template <
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>
2103bool lexical_assign(
const std::string &input, AssignTo &output) {
2109 if(lexical_cast(input, val)) {
2117template <
typename AssignTo,
2119 enable_if_t<!std::is_same<AssignTo, ConvertTo>::value && std::is_assignable<AssignTo &, ConvertTo &>::value,
2120 detail::enabler> = detail::dummy>
2121bool 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>
2137bool 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;
2147template <
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>
2152bool lexical_conversion(
const std::vector<std ::string> &strings, AssignTo &output) {
2153 return lexical_assign<AssignTo, ConvertTo>(strings[0], output);
2158template <
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>
2163bool 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};
2178template <
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>
2183bool 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());
2207template <class AssignTo, class ConvertTo, enable_if_t<is_complex<ConvertTo>::value, detail::enabler> = detail::dummy>
2208bool 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);
2227template <
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>
2232bool 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;
2247template <
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>
2252bool lexical_conversion(std::vector<std::string> strings, AssignTo &output);
2255template <
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>
2262bool lexical_conversion(
const std::vector<std::string> &strings, AssignTo &output);
2265template <
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>
2271bool lexical_conversion(
const std::vector<std::string> &strings, AssignTo &output);
2275template <
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>
2281bool 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{};
2294template <
class AssignTo,
class ConvertTo, std::
size_t I>
2295inline typename std::enable_if<(I >= type_count_base<AssignTo>::value),
bool>::type
2296tuple_conversion(
const std::vector<std::string> &, AssignTo &) {
2301template <
class AssignTo,
class ConvertTo>
2302inline typename std::enable_if<!is_mutable_container<ConvertTo>::value && type_count<ConvertTo>::value == 1,
bool>::type
2303tuple_type_conversion(std::vector<std::string> &strings, AssignTo &output) {
2304 auto retval = lexical_assign<AssignTo, ConvertTo>(strings[0], output);
2305 strings.erase(strings.begin());
2310template <
class AssignTo,
class ConvertTo>
2311inline typename std::enable_if<!is_mutable_container<ConvertTo>::value && (type_count<ConvertTo>::value > 1) &&
2312 type_count<ConvertTo>::value == type_count_min<ConvertTo>::value,
2314tuple_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);
2321template <
class AssignTo,
class ConvertTo>
2322inline typename std::enable_if<is_mutable_container<ConvertTo>::value ||
2323 type_count<ConvertTo>::value != type_count_min<ConvertTo>::value,
2325tuple_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);
2344template <
class AssignTo,
class ConvertTo, std::
size_t I>
2345inline typename std::enable_if<(I < type_count_base<AssignTo>::value),
bool>::type
2346tuple_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);
2359template <
class AssignTo,
2361 enable_if_t<is_mutable_container<AssignTo>::value && is_mutable_container<ConvertTo>::value &&
2362 type_count_base<ConvertTo>::value == 2,
2364bool 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());
2384template <
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),
2390bool 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);
2398template <
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)),
2405bool 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));
2436template <
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>
2441bool 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};
2455template <
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>
2460bool 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)) {
2475inline 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);
2516CLI11_INLINE
bool split_short(
const std::string ¤t, std::string &name, std::string &rest);
2519CLI11_INLINE
bool split_long(
const std::string ¤t, std::string &name, std::string &value);
2522CLI11_INLINE
bool split_windows_style(
const std::string ¤t, std::string &name, std::string &value);
2525CLI11_INLINE std::vector<std::string> split_names(std::string current);
2528CLI11_INLINE std::vector<std::pair<std::string, std::string>> get_default_flag_values(
const std::string &str);
2531CLI11_INLINE std::tuple<std::vector<std::string>, std::vector<std::string>, std::string>
2532get_names(
const std::vector<std::string> &input);
2540CLI11_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);
2549CLI11_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);
2564CLI11_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);
2579CLI11_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));
2590CLI11_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);
2616CLI11_INLINE std::tuple<std::vector<std::string>, std::vector<std::string>, std::string>
2617get_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);
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;
2801using 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);
2963enum class path_type { nonexistent, file, directory };
2966CLI11_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) {}
3076const Range NonNegativeNumber((std::numeric_limits<double>::max)(),
"NONNEGATIVE");
3079const 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) {}
3113template <
typename T,
3114 enable_if_t<is_copyable_ptr<typename std::remove_reference<T>::type>::value, detail::enabler> = detail::dummy>
3115auto smart_deref(T value) ->
decltype(*value) {
3121 enable_if_t<!is_copyable_ptr<typename std::remove_reference<T>::type>::value, detail::enabler> = detail::dummy>
3122typename std::remove_reference<T>::type &smart_deref(T &value) {
3126template <
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),
3132 [](
const iteration_type_t &v) {
return detail::pair_adaptor<element_t>::first(v); },
3139template <
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) {
3146 std::string res{detail::to_string(detail::pair_adaptor<element_t>::first(v))};
3150 res += detail::to_string(detail::pair_adaptor<element_t>::second(v));
3159template <
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>;
3169template <typename T, typename V, enable_if_t<!has_find<T, V>::value, detail::enabler> = detail::dummy>
3170auto 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) {
3174 return (detail::pair_adaptor<element_t>::first(v) == val);
3176 return {(it != std::end(setref)), it};
3180template <typename T, typename V, enable_if_t<has_find<T, V>::value, detail::enabler> = detail::dummy>
3181auto 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};
3188template <
typename T,
typename V>
3189auto 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) {
3200 V a{detail::pair_adaptor<element_t>::first(v)};
3201 a = filter_function(a);
3204 return {(it != std::end(setref)), it};
3211template <
typename T>
3212inline 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));
3219template <
typename T>
3220inline 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);
3225template <
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)) {
3241template <
typename T>
3242typename 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)); },
3319template <
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>
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)); },
3456inline std::string ignore_case(std::string item) {
return detail::to_lower(item); }
3459inline std::string ignore_underscore(std::string item) {
return detail::remove_underscore(item); }
3462inline 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 <<
']';
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);
3647CLI11_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{};
3741Validator::_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
3759CLI11_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;
3783CLI11_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;
3799CLI11_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();
3812CLI11_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();
3825CLI11_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();
3835CLI11_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();
3845CLI11_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();
3867CLI11_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), ...]");
3899CLI11_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"}) {
3917CLI11_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);
3928CLI11_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{};
3987enum 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(
4148using results_t = std::vector<std::string>;
4150using callback_t = std::function<bool(
const results_t &)>;
4155using Option_p = std::unique_ptr<Option>;
4157enum 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);
4347class 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 {
4762 CLI11_NODISCARD
bool check_fname(std::string name)
const {
4763 if(fnames_.empty()) {
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_);
4936CLI11_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);
4957CLI11_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;
4976CLI11_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);
4984CLI11_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();
4992CLI11_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);
4999CLI11_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)));
5014CLI11_INLINE Option *Option::each(
const std::function<
void(std::string)> &func) {
5015 validators_.emplace_back(
5016 [func](std::string &inout) {
5018 return std::string{};
5024CLI11_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");
5036CLI11_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");
5044CLI11_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);
5054CLI11_INLINE Option *Option::excludes(Option *opt) {
5056 throw(IncorrectConstruction(
"and option cannot exclude itself"));
5058 excludes_.insert(opt);
5061 opt->excludes_.insert(
this);
5069CLI11_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);
5079template <
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;
5099template <
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;
5120CLI11_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;
5133CLI11_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];
5186CLI11_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_);
5212CLI11_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))
5233CLI11_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_);
5262CLI11_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 &) {
5305CLI11_INLINE Option *Option::add_result(std::string s) {
5306 _add_result(std::move(s), results_);
5307 current_option_state_ = option_state::parsing;
5311CLI11_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;
5317CLI11_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_);
5325CLI11_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);
5343CLI11_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)
5362CLI11_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;
5386CLI11_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;
5399CLI11_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);
5437CLI11_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(
"%%");
5501CLI11_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())
5523CLI11_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); \
5567enum class Classifier { NONE, POSITIONAL_MARK, SHORT, LONG, WINDOWS_STYLE, SUBCOMMAND, SUBCOMMAND_TERMINATOR };
5571namespace FailureMessage {
5572std::string simple(
const App *app,
const Error &e);
5573std::string help(
const App *app,
const Error &e);
5578enum class config_extras_mode :
char { error = 0, ignore, ignore_all, capture };
5582using App_p = std::shared_ptr<App>;
5587template <typename T, enable_if_t<!std::is_integral<T>::value || (
sizeof(T) <= 1U), detail::enabler> = detail::dummy>
5588Option *default_flag_modifiers(Option *opt) {
5589 return opt->always_capture_default();
5593template <typename T, enable_if_t<std::is_integral<T>::value && (
sizeof(T) > 1U), detail::enabler> = detail::dummy>
5594Option *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;
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 =
"");
6184 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);
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) {
6439 App *needs(App *app) {
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);
6837CLI11_INLINE
void TriggerOn(App *trigger_app, App *app_to_enable);
6840CLI11_INLINE
void TriggerOn(App *trigger_app, std::vector<App *> apps_to_enable);
6843CLI11_INLINE
void TriggerOff(App *trigger_app, App *app_to_enable);
6846CLI11_INLINE
void TriggerOff(App *trigger_app, std::vector<App *> apps_to_enable);
6849CLI11_INLINE
void deprecate_option(Option *opt,
const std::string &replacement =
"");
6852inline 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);
6858inline 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);
6864CLI11_INLINE
void retire_option(App *app, Option *opt);
6867CLI11_INLINE
void retire_option(App &app, Option *opt);
6870CLI11_INLINE
void retire_option(App *app,
const std::string &option_name);
6873CLI11_INLINE
void retire_option(App &app,
const std::string &option_name);
6875namespace FailureMessage {
6878CLI11_INLINE std::string simple(
const App *app,
const Error &e);
6881CLI11_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) {
6901 template <
typename... Args>
6904 return app->
_parse_arg(std::forward<Args>(args)...);
6908 template <
typename... Args>
6922CLI11_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()) {
7102CLI11_INLINE Option *
7111 if(!flag_name.empty()) {
7113 flag_name, [versionString]() {
throw(
CLI::CallForVersion(versionString, 0)); }, version_help);
7120CLI11_INLINE Option *
7128 if(!flag_name.empty()) {
7137CLI11_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));
7177CLI11_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_) {
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));
7387CLI11_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));
7452CLI11_INLINE
void App::parse_from_stream(std::istream &input) {
7463CLI11_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);
7559CLI11_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);
7590CLI11_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); }),
7605CLI11_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());
7712CLI11_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};
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));
7803 if(app->
name_.empty()) {
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) {
7853CLI11_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(); });
8089 for(App_p &sub : subcommands_) {
8092 if(sub->name_.empty() && sub->required_ ==
false) {
8093 if(sub->count_all() == 0) {
8094 if(require_option_min_ > 0 && require_option_min_ <= used_options) {
8099 if(require_option_max_ > 0 && used_options >= require_option_min_) {
8106 if(sub->count() > 0 || sub->name_.empty()) {
8107 sub->_process_requirements();
8110 if(sub->required_ && sub->count_all() == 0) {
8111 throw(CLI::RequiredError(sub->get_display_name()));
8116CLI11_INLINE
void App::_process() {
8120 _process_config_file();
8127 _process_callbacks();
8128 _process_help_flags();
8132 _process_callbacks();
8133 _process_help_flags();
8135 _process_requirements();
8138CLI11_INLINE
void App::_process_extras() {
8139 if(!(allow_extras_ || prefix_command_)) {
8140 std::size_t num_left_over = remaining_size();
8141 if(num_left_over > 0) {
8146 for(App_p &sub : subcommands_) {
8147 if(sub->count() > 0)
8148 sub->_process_extras();
8152CLI11_INLINE
void App::_process_extras(std::vector<std::string> &args) {
8153 if(!(allow_extras_ || prefix_command_)) {
8154 std::size_t num_left_over = remaining_size();
8155 if(num_left_over > 0) {
8156 args = remaining(
false);
8161 for(App_p &sub : subcommands_) {
8162 if(sub->count() > 0)
8163 sub->_process_extras(args);
8167CLI11_INLINE
void App::increment_parsed() {
8169 for(App_p &sub : subcommands_) {
8170 if(sub->get_name().empty())
8171 sub->increment_parsed();
8175CLI11_INLINE
void App::_parse(std::vector<std::string> &args) {
8177 _trigger_pre_parse(args.size());
8178 bool positional_only =
false;
8180 while(!args.empty()) {
8181 if(!_parse_single(args, positional_only)) {
8186 if(parent_ ==
nullptr) {
8190 _process_extras(args);
8193 args = remaining_for_passthrough(
false);
8194 }
else if(parse_complete_callback_) {
8196 _process_callbacks();
8197 _process_help_flags();
8198 _process_requirements();
8199 run_callback(
false,
true);
8203CLI11_INLINE
void App::_parse(std::vector<std::string> &&args) {
8207 _trigger_pre_parse(args.size());
8208 bool positional_only =
false;
8210 while(!args.empty()) {
8211 _parse_single(args, positional_only);
8219CLI11_INLINE
void App::_parse_stream(std::istream &input) {
8220 auto values = config_formatter_->from_config(input);
8221 _parse_config(values);
8223 _trigger_pre_parse(values.size());
8230CLI11_INLINE
void App::_parse_config(
const std::vector<ConfigItem> &args) {
8232 if(!_parse_single_config(item) && allow_config_extras_ == config_extras_mode::error)
8233 throw ConfigError::Extras(item.fullname());
8237CLI11_INLINE
bool App::_parse_single_config(
const ConfigItem &item, std::size_t level) {
8238 if(level < item.
parents.size()) {
8240 auto *subcom = get_subcommand(item.
parents.at(level));
8241 auto result = subcom->_parse_single_config(item, level + 1);
8249 if(item.
name ==
"++") {
8252 _trigger_pre_parse(2);
8253 if(parent_ !=
nullptr) {
8254 parent_->parsed_subcommands_.push_back(
this);
8260 if(item.
name ==
"--") {
8261 if(configurable_ && parse_complete_callback_) {
8262 _process_callbacks();
8263 _process_requirements();
8268 Option *op = get_option_no_throw(
"--" + item.
name);
8270 if(item.
name.size() == 1) {
8271 op = get_option_no_throw(
"-" + item.
name);
8275 op = get_option_no_throw(item.
name);
8279 if(get_allow_config_extras() == config_extras_mode::capture)
8281 missing_.emplace_back(detail::Classifier::NONE, item.
fullname());
8285 if(!op->get_configurable()) {
8286 if(get_allow_config_extras() == config_extras_mode::ignore_all) {
8289 throw ConfigError::NotConfigurable(item.
fullname());
8294 if(op->get_expected_min() == 0) {
8295 if(item.
inputs.size() <= 1) {
8297 auto res = config_formatter_->to_flag(item);
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);
8317CLI11_INLINE
bool App::_parse_single(std::vector<std::string> &args,
bool &positional_only) {
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;
8324 if((!_has_remaining_positionals()) && (parent_ !=
nullptr)) {
8327 _move_to_missing(classifier,
"--");
8330 case detail::Classifier::SUBCOMMAND_TERMINATOR:
8335 case detail::Classifier::SUBCOMMAND:
8336 retval = _parse_subcommand(args);
8338 case detail::Classifier::LONG:
8339 case detail::Classifier::SHORT:
8340 case detail::Classifier::WINDOWS_STYLE:
8342 _parse_arg(args, classifier);
8344 case detail::Classifier::NONE:
8346 retval = _parse_positional(args,
false);
8347 if(retval && positionals_at_end_) {
8348 positional_only =
true;
8353 throw HorribleError(
"unrecognized classifier (you should not see this!)");
8359CLI11_NODISCARD CLI11_INLINE std::size_t App::_count_remaining_positionals(
bool required_only)
const {
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();
8371CLI11_NODISCARD CLI11_INLINE
bool App::_has_remaining_positionals()
const {
8372 for(
const Option_p &opt : options_) {
8373 if(opt->get_positional() && ((
static_cast<int>(opt->count()) < opt->get_items_expected_min()))) {
8381CLI11_INLINE
bool App::_parse_positional(std::vector<std::string> &args,
bool haltOnSubcommand) {
8383 const std::string &positional = args.back();
8385 if(positionals_at_end_) {
8387 auto arg_rem = args.size();
8388 auto remreq = _count_remaining_positionals(
true);
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()) {
8393 if(validate_positionals_) {
8394 std::string pos = positional;
8395 pos = opt->_validate(pos, 0);
8401 parse_order_.push_back(opt.get());
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())) {
8427 if(validate_positionals_) {
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();
8446 parse_order_.push_back(opt.get());
8452 for(
auto &subc : subcommands_) {
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());
8463 if(parent_ !=
nullptr && fallthrough_)
8464 return _get_fallthrough_parent()->_parse_positional(args,
static_cast<bool>(parse_complete_callback_));
8467 auto *com = _find_subcommand(args.back(),
true,
false);
8468 if(com !=
nullptr && (require_subcommand_max_ == 0 || require_subcommand_max_ > parsed_subcommands_.size())) {
8469 if(haltOnSubcommand) {
8478 auto *parent_app = (parent_ !=
nullptr) ? _get_fallthrough_parent() :
this;
8479 com = parent_app->_find_subcommand(args.back(),
true,
false);
8480 if(com !=
nullptr && (com->parent_->require_subcommand_max_ == 0 ||
8481 com->parent_->require_subcommand_max_ > com->parent_->parsed_subcommands_.size())) {
8485 if(positionals_at_end_) {
8489 if(parent_ !=
nullptr && name_.empty()) {
8493 _move_to_missing(detail::Classifier::NONE, positional);
8495 if(prefix_command_) {
8496 while(!args.empty()) {
8497 _move_to_missing(detail::Classifier::NONE, args.back());
8505CLI11_NODISCARD CLI11_INLINE
App *
8506App::_find_subcommand(
const std::string &subc_name,
bool ignore_disabled,
bool ignore_used)
const noexcept {
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)
8524CLI11_INLINE
bool App::_parse_subcommand(std::vector<std::string> &args) {
8525 if(_count_remaining_positionals(
true) > 0) {
8526 _parse_positional(args,
false);
8529 auto *com = _find_subcommand(args.back(),
true,
true);
8530 if(com !=
nullptr) {
8533 parsed_subcommands_.push_back(com);
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_;
8547 if(parent_ ==
nullptr)
8548 throw HorribleError(
"Subcommand " + args.back() +
" missing");
8552CLI11_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);
8591 if(op_ptr == std::end(options_)) {
8592 for(
auto &subc : subcommands_) {
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());
8604 if(parent_ !=
nullptr && name_.empty()) {
8609 if(parent_ !=
nullptr && fallthrough_)
8610 return _get_fallthrough_parent()->_parse_arg(args, current_type);
8614 _move_to_missing(current_type, current);
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);
8646 parse_order_.push_back(op.get());
8647 }
else if(!value.empty()) {
8648 op->add_result(value, result_count);
8649 parse_order_.push_back(op.get());
8650 collected += result_count;
8652 }
else if(!rest.empty()) {
8653 op->add_result(rest, result_count);
8654 parse_order_.push_back(op.get());
8656 collected += result_count;
8660 while(min_num > collected && !args.empty()) {
8661 std::string current_ = args.back();
8663 op->add_result(current_, result_count);
8664 parse_order_.push_back(op.get());
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()) {
8674 auto remreqpos = _count_remaining_positionals(
true);
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()) {
8682 if(validate_optional_arguments_) {
8683 std::string arg = args.back();
8684 arg = op->_validate(arg, 0);
8689 op->add_result(args.back(), result_count);
8690 parse_order_.push_back(op.get());
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);
8702 parse_order_.push_back(op.get());
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);
8723CLI11_INLINE
void App::_trigger_pre_parse(std::size_t remaining_args) {
8724 if(!pre_parse_called_) {
8725 pre_parse_called_ =
true;
8726 if(pre_parse_callback_) {
8727 pre_parse_callback_(remaining_args);
8729 }
else if(immediate_callback_) {
8730 if(!name_.empty()) {
8731 auto pcnt = parsed_;
8732 auto extras = std::move(missing_);
8735 pre_parse_called_ =
true;
8736 missing_ = std::move(extras);
8741CLI11_INLINE
App *App::_get_fallthrough_parent() {
8742 if(parent_ ==
nullptr) {
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;
8752CLI11_NODISCARD CLI11_INLINE
const std::string &App::_compare_subcommand_names(
const App &subcom,
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()) {
8786 const auto &cmpres = _compare_subcommand_names(subcom, *subc);
8787 if(!cmpres.empty()) {
8793 const auto &cmpres = _compare_subcommand_names(*subc, subcom);
8794 if(!cmpres.empty()) {
8803CLI11_INLINE
void App::_move_to_missing(detail::Classifier val_type,
const std::string &val) {
8804 if(allow_extras_ || subcommands_.empty()) {
8805 missing_.emplace_back(val_type, val);
8809 for(
auto &subc : subcommands_) {
8810 if(subc->name_.empty() && subc->allow_extras_) {
8811 subc->missing_.emplace_back(val_type, val);
8816 missing_.emplace_back(val_type, val);
8819CLI11_INLINE
void App::_move_option(Option *opt,
App *app) {
8820 if(opt ==
nullptr) {
8825 for(
auto &subc : subcommands_) {
8826 if(app == subc.get()) {
8834 if((help_ptr_ == opt) || (help_all_ptr_ == opt))
8837 if(config_ptr_ == opt)
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));
8849 options_.erase(iterator);
8858CLI11_INLINE
void TriggerOn(
App *trigger_app,
App *app_to_enable) {
8864CLI11_INLINE
void TriggerOn(App *trigger_app, std::vector<App *> apps_to_enable) {
8865 for(
auto &app : apps_to_enable) {
8871 for(
const auto &app : apps_to_enable) {
8877CLI11_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(); });
8883CLI11_INLINE
void TriggerOff(App *trigger_app, std::vector<App *> apps_to_enable) {
8884 for(
auto &app : apps_to_enable) {
8890 for(
const auto &app : apps_to_enable) {
8896CLI11_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");
8910CLI11_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);
8934CLI11_INLINE
void retire_option(App &app, Option *opt) { retire_option(&app, opt); }
8936CLI11_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);
8956CLI11_INLINE
void retire_option(App &app,
const std::string &option_name) { retire_option(&app, option_name); }
8958namespace FailureMessage {
8960CLI11_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";
8978CLI11_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();
8991std::string convert_arg_for_ini(
const std::string &arg,
char stringQuote =
'"',
char characterQuote =
'\'');
8994std::string ini_join(
const std::vector<std::string> &args,
8996 char arrayStart =
'[',
8997 char arrayEnd =
']',
8998 char stringQuote =
'"',
8999 char characterQuote =
'\'');
9001std::vector<std::string> generate_parents(
const std::string §ion, std::string &name,
char parentSeparator);
9004void checkParentSegments(std::vector<ConfigItem> &output,
const std::string ¤tSection,
char parentSeparator);
9012CLI11_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;
9055CLI11_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);
9081CLI11_INLINE std::vector<std::string>
9082generate_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);
9107checkParentSegments(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 =
"++";
9156inline std::vector<ConfigItem> ConfigBase::from_config(std::istream &input)
const {
9158 std::string currentSection =
"default";
9159 std::string previousSection =
"default";
9160 std::vector<ConfigItem> output;
9161 bool isDefaultArray = (arrayStart ==
'[' && arrayEnd ==
']' && arraySeparator ==
',');
9162 bool isINIArray = (arrayStart ==
'\0' || arrayStart ==
' ') && arrayStart == arrayEnd;
9163 bool inSection{
false};
9164 char aStart = (isINIArray) ?
'[' : arrayStart;
9165 char aEnd = (isINIArray) ?
']' : arrayEnd;
9166 char aSep = (isINIArray && arraySeparator ==
' ') ?
',' : arraySeparator;
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";
9193 detail::checkParentSegments(output, currentSection, parentSeparatorChar);
9196 if(currentSection == previousSection) {
9197 ++currentSectionIndex;
9199 currentSectionIndex = 0;
9200 previousSection = currentSection;
9206 if(line.front() ==
';' || line.front() ==
'#' || line.front() == commentChar) {
9211 auto pos = line.find(valueDelimiter);
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));
9215 auto cloc = item.find(commentChar);
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);
9235 auto cloc = name.find(commentChar);
9236 if(cloc != std::string::npos) {
9237 name.erase(cloc, std::string::npos);
9241 items_buffer = {
"true"};
9243 if(name.find(parentSeparatorChar) == std::string::npos) {
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);
9252 if(parents.size() > maximumLayers) {
9255 if(!configSection.empty() && !inSection) {
9256 if(parents.empty() || parents.front() != configSection) {
9259 if(configIndex >= 0 && currentSectionIndex != configIndex) {
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();
9288CLI11_INLINE std::string
9289ConfigBase::to_config(
const App *app,
bool default_also,
bool write_description, std::string prefix)
const {
9290 std::stringstream out;
9291 std::string commentLead;
9292 commentLead.push_back(commentChar);
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(
9322 opt->reduced_results(), arraySeparator, arrayStart, arrayEnd, stringQuote, characterQuote);
9324 if(value.empty() && default_also) {
9325 if(!opt->get_default_str().empty()) {
9326 value = detail::convert_arg_for_ini(opt->get_default_str(), stringQuote, characterQuote);
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';
9342 out << name << valueDelimiter << value <<
'\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";
9363 std::string subname = app->
get_name() + parentSeparatorChar + subcom->get_name();
9365 while(p->get_parent() !=
nullptr) {
9366 subname = p->
get_name() + parentSeparatorChar + subname;
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);
9387CLI11_INLINE std::string
9388Formatter::make_group(std::string group,
bool is_positional, std::vector<const Option *> opts)
const {
9389 std::stringstream out;
9391 out <<
"\n" << group <<
":\n";
9392 for(
const Option *opt : opts) {
9393 out << make_option(opt, is_positional);
9399CLI11_INLINE std::string Formatter::make_positionals(
const App *app)
const {
9400 std::vector<const Option *> opts =
9401 app->
get_options([](
const Option *opt) {
return !opt->get_group().empty() && opt->get_positional(); });
9406 return make_group(get_label(
"Positionals"),
true, opts);
9409CLI11_INLINE std::string Formatter::make_groups(
const App *app, AppFormatMode mode)
const {
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()) {
9423 out << make_group(group,
false, opts);
9425 if(group != groups.back())
9433CLI11_INLINE std::string Formatter::make_description(
const App *app)
const {
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{};
9459CLI11_INLINE std::string Formatter::make_usage(
const App *app, std::string name)
const {
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) {
9480 return make_option_usage(opt);
9483 out <<
" " << detail::join(positional_names,
" ");
9488 [](
const CLI::App *subc) { return ((!subc->get_disabled()) && (!subc->get_name().empty())); })
9501CLI11_INLINE std::string Formatter::make_footer(
const App *app)
const {
9503 if(footer.empty()) {
9504 return std::string{};
9506 return "\n" + footer +
"\n";
9509CLI11_INLINE std::string Formatter::make_help(
const App *app, std::string name, AppFormatMode mode)
const {
9513 if(mode == AppFormatMode::Sub)
9514 return make_expanded(app);
9516 std::stringstream out;
9523 out << make_description(app);
9524 out << make_usage(app, name);
9525 out << make_positionals(app);
9526 out << make_groups(app, mode);
9527 out << make_subcommands(app, mode);
9528 out << make_footer(app);
9533CLI11_INLINE std::string Formatter::make_subcommands(
const App *app, AppFormatMode mode)
const {
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()) {
9543 out << make_expanded(com);
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) {
9564 out << make_subcommand(new_com);
9566 out << new_com->help(new_com->get_name(), AppFormatMode::Sub);
9575CLI11_INLINE std::string Formatter::make_subcommand(
const App *sub)
const {
9576 std::stringstream out;
9581CLI11_INLINE std::string Formatter::make_expanded(
const App *sub)
const {
9582 std::stringstream out;
9585 out << make_description(sub);
9587 detail::format_aliases(out, sub->
get_aliases(), column_width_ + 2);
9589 out << make_positionals(sub);
9590 out << make_groups(sub, AppFormatMode::Sub);
9591 out << make_subcommands(sub, AppFormatMode::Sub);
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";
9601CLI11_INLINE std::string Formatter::make_option_name(
const Option *opt,
bool is_positional)
const {
9603 return opt->get_name(
true,
false);
9605 return opt->get_name(
false,
true);
9608CLI11_INLINE std::string Formatter::make_option_opts(
const Option *opt)
const {
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())
9625 out <<
" " << get_label(
"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();
9643CLI11_INLINE std::string Formatter::make_option_desc(
const Option *opt)
const {
return opt->get_description(); }
9645CLI11_INLINE std::string Formatter::make_option_usage(
const Option *opt)
const {
9647 std::stringstream out;
9648 out << make_option_name(opt,
true);
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() +
"]";
9662PXR_NAMESPACE_CLOSE_SCOPE
Creates a command line program, with very few defaults.
Option * add_flag(std::string flag_name)
Add a flag with no description or variable assignment.
bool fallthrough_
Allow subcommand fallthrough, so that parent commands can collect commands after subcommand....
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.
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...
bool required_
If set to true the subcommand is required to be processed and used, ignored for main app.
CLI11_NODISCARD std::size_t get_require_option_max() const
Get the required max option value.
bool ignore_case_
If true, the program name is not case sensitive INHERITABLE.
CLI11_NODISCARD std::size_t get_require_subcommand_min() const
Get the required min subcommand value.
App * silent(bool silence=true)
silence the subcommand from showing up in the processed list
CLI11_NODISCARD bool get_positionals_at_end() const
Check the status of the allow windows style options.
bool remove_needs(Option *opt)
Removes an option from the needs list of this subcommand.
CLI11_NODISCARD const std::vector< std::string > & get_aliases() const
Get the aliases of the current app.
std::uint32_t parsed_
Counts the number of times this command/subcommand was parsed.
App * fallthrough(bool value=true)
Stop subcommand fallthrough, so that parent commands cannot collect commands after subcommand.
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.
std::vector< Option * > parse_order_
This is a list of pointers to options with the original parse order.
void run_callback(bool final_mode=false, bool suppress_final_callback=false)
Internal function to run (App) callback, bottom up.
OptionDefaults * option_defaults()
Get the OptionDefault object, to set option defaults.
App * final_callback(std::function< void()> app_callback)
Set a callback for execution when all parsing and processing has completed aliased as callback.
Option * add_option_no_stream(std::string option_name, AssignTo &variable, std::string option_description="")
Add option for assigning to a variable.
bool silent_
indicator that the subcommand is silent and won't show up in subcommands list This is potentially use...
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.
virtual ~App()=default
virtual destructor
void _process_extras()
Throw an error if anything is left over and should not be.
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::function< void()> parse_complete_callback_
This is a function that runs when parsing has finished.
std::string group_
The group membership INHERITABLE.
Option * get_version_ptr()
Get a pointer to the version option.
App * ignore_case(bool value=true)
Ignore case. Subcommands inherit value.
virtual void pre_callback()
This allows subclasses to inject code before callbacks but after parse.
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.
bool _parse_subcommand(std::vector< std::string > &args)
Parse a subcommand, modify args and continue.
std::vector< Option_p > options_
The list of options, stored locally.
App * ignore_underscore(bool value=true)
Ignore underscore. Subcommands inherit value.
App(std::string app_description, std::string app_name, App *parent)
Special private constructor for subcommand.
Option * get_option_no_throw(std::string option_name) noexcept
Get an option by name (noexcept non-const version)
CLI11_NODISCARD const Option * get_version_ptr() const
Get a pointer to the version option. (const)
Option * add_option(std::string option_name)
Add option with no description or variable assignment.
bool ignore_underscore_
If true, the program should ignore underscores INHERITABLE.
CLI11_NODISCARD bool get_disabled_by_default() const
Get the status of disabled by default.
CLI11_NODISCARD std::shared_ptr< ConfigBase > get_config_formatter_base() const
Access the config formatter as a configBase pointer.
bool _parse_single_config(const ConfigItem &item, std::size_t level=0)
Fill in a single config option.
Option * get_help_ptr()
Get a pointer to the help flag.
Option * help_all_ptr_
A pointer to the help all flag if there is one INHERITABLE.
CLI11_NODISCARD bool _has_remaining_positionals() const
Count the required remaining positional arguments.
bool allow_windows_style_options_
Allow '/' for options for Windows like options. Defaults to true on Windows, false otherwise....
const Option * operator[](const char *option_name) const
Shortcut bracket operator for getting a pointer to an option.
CLI11_NODISCARD bool get_immediate_callback() const
Get the status of disabled.
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,...
Option * set_help_flag(std::string flag_name="", const std::string &help_description="")
Set a help flag, replace the existing one if present.
bool immediate_callback_
Flag indicating that the callback for the subcommand should be executed immediately on parse completi...
CLI11_NODISCARD const Option * get_help_all_ptr() const
Get a pointer to the help all flag. (const)
CLI11_NODISCARD const std::string & get_name() const
Get the name of the current app.
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.
void increment_parsed()
Internal function to recursively increment the parsed counter on the current app as well unnamed subc...
CLI11_NODISCARD bool get_ignore_underscore() const
Check the status of ignore_underscore.
App * allow_config_extras(config_extras_mode mode)
ignore extras in config files
App * require_option(int value)
Require an option to be given (does not affect help call) The number required can be given.
bool positionals_at_end_
specify that positional arguments come at the end of the argument sequence not inheritable
bool remove_option(Option *opt)
Removes an option from the App. Takes an option pointer. Returns true if found and removed.
void _process()
Process callbacks and such.
CLI11_NODISCARD bool got_subcommand(std::string subcommand_name) const
Check with name instead of pointer to see if subcommand was selected.
CLI11_NODISCARD bool get_validate_optional_arguments() const
Get the status of validating optional vector arguments.
std::function< std::string()> footer_callback_
This is a function that generates a footer to put after all other options in help output.
App * allow_config_extras(bool allow=true)
ignore extras in config files
CLI11_NODISCARD std::shared_ptr< Config > get_config_formatter() const
Access the config formatter.
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...
App * _get_fallthrough_parent()
Get the appropriate parent to fallthrough to which is the first one that has a name or the main app.
App * allow_windows_style_options(bool value=true)
Allow windows style options, such as /opt.
std::string name_
Subcommand name or program name (from parser if name is empty)
App * validate_positionals(bool validate=true)
Set the subcommand to validate positional arguments before assigning.
CLI11_NODISCARD std::size_t count_all() const
Get a count of all the arguments processed in options and subcommands, this excludes arguments which ...
const Option * operator[](const std::string &option_name) const
Shortcut bracket operator for getting a pointer to an option.
App * allow_extras(bool allow=true)
Remove the error when extras are left over on the command line.
App * require_subcommand()
The argumentless form of require subcommand requires 1 or more subcommands.
App * footer(std::function< std::string()> footer_function)
Set footer.
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...
CLI11_NODISCARD bool get_validate_positionals() const
Get the status of validating positionals.
T * add_option_group(std::string group_name, std::string group_description="")
creates an option group as part of the given app
CLI11_NODISCARD std::vector< std::string > get_groups() const
Get the groups available directly from this option (in order)
App * require_subcommand(std::size_t min, std::size_t max)
Explicitly control the number of subcommands required.
CLI11_NODISCARD bool get_fallthrough() const
Check the status of fallthrough.
App * group(std::string group_name)
Changes the group membership.
App * alias(std::string app_name)
Set an alias for the app.
void _validate() const
Check the options to make sure there are no conflicts.
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::size_t require_option_max_
Max number of options allowed. 0 is unlimited (not inheritable)
CLI11_NODISCARD bool get_allow_extras() const
Get the status of allow extras.
void _process_requirements()
Verify required options and cross requirements. Subcommands too (only if selected).
Option * add_option(std::string option_name, AssignTo &variable, std::string option_description="")
Add option for assigning to a variable.
bool _parse_positional(std::vector< std::string > &args, bool haltOnSubcommand)
Parse a positional, go up the tree to check.
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 * parse_complete_callback(std::function< void()> pc_callback)
Set a callback to execute when parsing has completed for the app.
App * excludes(Option *opt)
Sets excluded options for the subcommand.
std::vector< App * > parsed_subcommands_
This is a list of the subcommands collected, in order.
CLI11_NODISCARD std::size_t _count_remaining_positionals(bool required_only=false) const
Count the required remaining positional arguments.
CLI11_NODISCARD const Option * get_help_ptr() const
Get a pointer to the help flag. (const)
CLI11_NODISCARD const std::string & get_group() const
Get the group of this subcommand.
Option * add_flag(std::string flag_name, std::vector< T > &flag_results, std::string flag_description="")
Vector version to capture multiple flags.
void _process_callbacks()
Process callbacks. Runs on all subcommands.
std::set< App * > exclude_subcommands_
this is a list of subcommands that are exclusionary to this one
App * required(bool require=true)
Remove the error when extras are left over on the command line.
App * preparse_callback(std::function< void(std::size_t)> pp_callback)
Set a callback to execute prior to parsing.
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.
CLI11_NODISCARD const std::vector< Option * > & parse_order() const
This gets a vector of pointers with the original parse order.
App * footer(std::string footer_string)
Set footer.
App * parent_
A pointer to the parent if this is a subcommand.
CLI11_NODISCARD std::size_t get_require_option_min() const
Get the required min option value.
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 remove_excludes(Option *opt)
Removes an option from the excludes list of this subcommand.
CLI11_NODISCARD bool parsed() const
Check to see if this subcommand was parsed, true only if received on command line.
std::function< void(std::size_t)> pre_parse_callback_
This is a function that runs prior to the start of parsing.
App * formatter_fn(std::function< std::string(const App *, std::string, AppFormatMode)> fmt)
Set the help formatter.
Option * help_ptr_
A pointer to the help flag if there is one INHERITABLE.
bool remove_subcommand(App *subcom)
Removes a subcommand from the App. Takes a subcommand pointer. Returns true if found and removed.
CLI11_NODISCARD bool get_configurable() const
Check the status of the allow windows style options.
App * prefix_command(bool allow=true)
Do not parse anything after the first unrecognized option and return.
CLI11_NODISCARD bool get_ignore_case() const
Check the status of ignore_case.
void _configure()
configure subcommands to enable parsing through the current object set the correct fallthrough and pr...
std::function< void()> final_callback_
This is a function that runs when all processing has completed.
CLI11_NODISCARD std::string get_footer() const
Generate and return the footer.
void _process_config_file()
Read and process a configuration file (main app only)
CLI11_NODISCARD std::vector< App * > get_subcommands() const
Get a subcommand pointer list to the currently selected subcommands (after parsing by default,...
missing_t missing_
Pair of classifier, string for missing options.
bool prefix_command_
If true, return immediately on an unrecognized option (implies allow_extras) INHERITABLE.
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,...
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 * description(std::string app_description)
Set the description of the app.
std::size_t require_subcommand_max_
Max number of subcommands allowed (parsing stops after this number). 0 is unlimited INHERITABLE.
App * excludes(App *app)
Sets excluded subcommands for the subcommand.
CLI11_NODISCARD config_extras_mode get_allow_config_extras() const
Get the status of allow extras.
App * formatter(std::shared_ptr< FormatterBase > fmt)
Set the help formatter.
bool disabled_
If set to true the subcommand is disabled and cannot be used, ignored for main app.
CLI11_NODISCARD std::shared_ptr< FormatterBase > get_formatter() const
Access the formatter.
void _process_env()
Get envname options if not yet passed. Runs on all subcommands.
bool validate_optional_arguments_
If set to true optional vector arguments are validated before assigning INHERITABLE.
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 ...
std::set< Option * > exclude_options_
This is a list of options which are exclusionary to this App, if the options were used this subcomman...
App * require_option(std::size_t min, std::size_t max)
Explicitly control the number of options required.
void _parse(std::vector< std::string > &args)
Internal parse function.
CLI11_NODISCARD const Option * get_config_ptr() const
Get a pointer to the config option. (const)
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,...
void clear()
Reset the parsed data.
CLI11_NODISCARD std::string get_description() const
Get the app or subcommand description.
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.
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.
CLI11_NODISCARD App * get_option_group(std::string group_name) const
Check to see if an option group is part of this App.
App * name(std::string app_name="")
Set a name for the app (empty will use parser to set the name)
void _move_option(Option *opt, App *app)
function that could be used by subclasses of App to shift options around into subcommands
App * clear_aliases()
clear all the aliases of the current App
Option * get_config_ptr()
Get a pointer to the config option.
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...
std::vector< App_p > subcommands_
Storage for subcommand list.
App * positionals_at_end(bool value=true)
Specify that the positional arguments are only at the end of the sequence.
CLI11_NODISCARD bool get_allow_windows_style_options() const
Check the status of the allow windows style options.
std::shared_ptr< FormatterBase > formatter_
This is the formatter for help printing. Default provided. INHERITABLE (same pointer)
CLI11_NODISCARD std::vector< std::string > remaining(bool recurse=false) const
This returns the missing options from the current subcommand.
std::function< std::string(const App *, const Error &e)> failure_message_
The error message printing function INHERITABLE.
std::string footer_
Footer to put after all options in the help output INHERITABLE.
std::vector< std::string > aliases_
Alias names for the subcommand.
App * disabled(bool disable=true)
Disable the subcommand or option group.
CLI11_NODISCARD std::size_t remaining_size(bool recurse=false) const
This returns the number of remaining options, minus the – separator.
bool configurable_
if set to true the subcommand can be triggered via configuration files INHERITABLE
CLI11_NODISCARD bool get_disabled() const
Get the status of disabled.
CLI11_NODISCARD std::size_t count() const
No argument version of count counts the number of times this subcommand was passed in.
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.
CLI11_NODISCARD std::string get_display_name(bool with_aliases=false) const
Get a display name for an app.
CLI11_NODISCARD bool check_name(std::string name_to_check) const
Check the name, case insensitive and underscore insensitive if set.
void _process_help_flags(bool trigger_help=false, bool trigger_all_help=false) const
Run help flag processing if any are found.
Option * version_ptr_
A pointer to a version flag if there is one.
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...
std::shared_ptr< Config > config_formatter_
This is the formatter for help printing. Default provided. INHERITABLE (same pointer)
App * add_subcommand(std::string subcommand_name="", std::string subcommand_description="")
Add a subcommand. Inherits INHERITABLE and OptionDefaults, and help flag.
App * configurable(bool value=true)
Specify that the subcommand can be triggered by a config file.
bool validate_positionals_
If set to true positional options are validated before assigning INHERITABLE.
App * require_option()
The argumentless form of require option requires 1 or more options be used.
CLI11_NODISCARD bool get_prefix_command() const
Get the prefix command status.
config_extras_mode allow_config_extras_
If ignore, allow extra arguments in the ini file (ie, don't throw an error).
void _trigger_pre_parse(std::size_t remaining_args)
Trigger the pre_parse callback if needed.
App * validate_optional_arguments(bool validate=true)
Set the subcommand to validate optional vector arguments before assigning.
CLI11_NODISCARD bool get_required() const
Get the status of required.
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 * 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.
Option * get_option(std::string option_name)
Get an option by name (non-const version)
App * get_parent()
Get the parent of this subcommand (or nullptr if main app)
CLI11_NODISCARD const Option * get_option(std::string option_name) const
Get an option by name.
App * immediate_callback(bool immediate=true)
Set the subcommand callback to be executed immediately on subcommand completion.
CLI11_NODISCARD std::size_t count(std::string option_name) const
Counts the number of times the given option was passed.
OptionDefaults option_defaults_
The default values for options, customizable and changeable INHERITABLE.
startup_mode default_startup
specify the startup mode for the app stable=no change, enabled= startup enabled, disabled=startup dis...
std::size_t require_subcommand_min_
Minimum required subcommands (not inheritable!)
bool pre_parse_called_
Flag indicating that the pre_parse_callback has been triggered.
void _parse_stream(std::istream &input)
Internal function to parse a stream.
App * callback(std::function< void()> app_callback)
Set a callback for execution when all parsing and processing has completed.
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.
CLI11_NODISCARD std::string version() const
Displays a version string.
Option * add_option(std::string option_name, T &option_description)
Add option with description but with no variable assignment or callback.
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.
std::string description_
Description of the current program/subcommand.
CLI11_NODISCARD bool get_silent() const
Get the status of silence.
CLI11_NODISCARD const App * get_parent() const
Get the parent of this subcommand (or nullptr if main app) (const version)
bool allow_extras_
If true, allow extra arguments (ie, don't throw an error). INHERITABLE.
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.
CLI11_NODISCARD bool get_enabled_by_default() const
Get the status of disabled by default.
void parse(int argc, const char *const *argv)
Parses the command line - throws errors.
void _move_to_missing(detail::Classifier val_type, const std::string &val)
Helper function to place extra values in the most appropriate position.
App * require_subcommand(int value)
Require a subcommand to be given (does not affect help call) The number required can be given.
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 has_automatic_name_
If set to true the name was automatically generated from the command line vs a user set name.
bool got_subcommand(const App *subcom) const
Check to see if given subcommand was selected.
std::size_t require_option_min_
Minimum required options (not inheritable!)
CLI11_NODISCARD std::size_t get_require_subcommand_max() const
Get the required max subcommand value.
Option * config_ptr_
Pointer to the config option.
App * config_formatter(std::shared_ptr< Config > fmt)
Set the config formatter.
Thrown when the wrong number of arguments has been received.
Multiply a number by a factor using given mapping.
Options
Adjust AsNumberWithUnit behavior.
Converts a human-readable size string (with unit literal) to uin64_t size.
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...
Thrown on construction of a bad name.
Produce a bounded range (factory). Min and max are inclusive.
Bound(T min_val, T max_val)
This bounds a value with min and max inclusive.
Bound(T max_val)
Range of one value is 0 to value.
Usually something like –help-all on command line.
-h or –help on command line
-v or –version on command line
This converter works with INI/TOML files; to write INI files use ConfigINI.
CLI11_NODISCARD const std::string & section() const
get the section
ConfigBase * valueSeparator(char vSep)
Specify the delimiter between a name and value.
ConfigBase * arrayDelimiter(char aSep)
Specify the delimiter character for an array.
ConfigBase * parentSeparator(char sep)
Specify the separator to use for parent layers.
ConfigBase * quoteCharacter(char qString, char qChar)
Specify the quote characters used around strings and characters.
int16_t & indexRef()
get a reference to the configuration index
ConfigBase * section(const std::string §ionName)
specify a particular section of the configuration file to use
ConfigBase * index(int16_t sectionIndex)
specify a particular index in the section to use (-1) for all sections to use
std::string & sectionRef()
get a reference to the configuration section
CLI11_NODISCARD int16_t index() const
get the section index
ConfigBase * arrayBounds(char aStart, char aEnd)
Specify the start and end characters for an array.
ConfigBase * comment(char cchar)
Specify the configuration for comment characters.
ConfigBase * maxLayers(uint8_t layers)
Specify the maximum number of parents.
Thrown when extra values are found in an INI file.
This class provides a converter for configuration files.
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.
virtual CLI11_NODISCARD std::string to_flag(const ConfigItem &item) const
Get a flag value.
virtual std::string to_config(const App *, bool, bool, std::string) const =0
Convert an app into a configuration.
virtual std::vector< ConfigItem > from_config(std::istream &) const =0
Convert a configuration into an app.
virtual ~Config()=default
Virtual destructor.
ConfigINI generates a "standard" INI compliant output.
Construction errors (not in parsing)
Thrown when conversion call back fails, such as when an int fails to coerce to a string.
Class wrapping some of the accessors of Validator.
All errors derive from this one.
Thrown when an excludes option is present.
Thrown when parsing an INI file and it is missing.
Modify a path if the file is a particular default location, can be used as Check or transform with th...
This is just a safety check to verify selection and parsing match - you should not ever see it String...
Thrown when an option is set to conflicting values (non-vector and multi args, for example)
Thrown when validation fails before parsing.
Verify items are in a set.
IsMember(std::initializer_list< T > values, Args &&...args)
This allows in-place construction using an initializer list.
IsMember(T &&set)
This checks to see if an item is in a set (empty function)
IsMember(T set, F filter_function)
This checks to see if an item is in a set: pointer or copy version.
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)
Extension of App to better manage groups of options.
void add_options(Option *opt, Args... args)
Add a bunch of options to the group.
void add_options(Option *opt)
Add an existing option to the Option_group.
Option * add_option(Option *opt)
Add an existing option to the Option_group.
App * add_subcommand(App *subcom)
Add an existing subcommand to be a member of an option_group.
Thrown when an option already exists.
This is the CRTP base class for Option and OptionDefaults.
bool required_
True if this is a required option.
bool ignore_case_
Ignore the case when matching (option, not value)
CRTP * take_all()
Set the multi option policy to take all arguments.
CRTP * take_first()
Set the multi option policy to take last.
CRTP * join(char delim)
Set the multi option policy to join with a specific delimiter.
std::string group_
The group membership.
char delimiter_
Specify a delimiter character for vector arguments.
bool ignore_underscore_
Ignore underscores when matching (option, not value)
CLI11_NODISCARD char get_delimiter() const
Get the current delimiter char.
CRTP * mandatory(bool value=true)
Support Plumbum term.
CRTP * take_last()
Set the multi option policy to take last.
CLI11_NODISCARD bool get_ignore_underscore() const
The status of ignore_underscore.
CRTP * join()
Set the multi option policy to join.
CRTP * delimiter(char value='\0')
Allow in a configuration file.
bool disable_flag_override_
Disable overriding flag values with '=value'.
CLI11_NODISCARD const std::string & get_group() const
Get the group of this option.
CLI11_NODISCARD bool get_always_capture_default() const
Return true if this will automatically capture the default value for help printing.
CRTP * required(bool value=true)
Set the option as required.
CLI11_NODISCARD bool get_configurable() const
The status of configurable.
CLI11_NODISCARD bool get_ignore_case() const
The status of ignore case.
void copy_to(T *other) const
Copy the contents to another similar class (one based on OptionBase)
bool configurable_
Allow this option to be given in a configuration file.
CRTP * configurable(bool value=true)
Allow in a configuration file.
CLI11_NODISCARD bool get_disable_flag_override() const
The status of configurable.
MultiOptionPolicy multi_option_policy_
Policy for handling multiple arguments beyond the expected Max.
CLI11_NODISCARD bool get_required() const
True if this is a required option.
bool always_capture_default_
Automatically capture default value.
CLI11_NODISCARD MultiOptionPolicy get_multi_option_policy() const
The status of the multi option policy.
CRTP * group(const std::string &name)
Changes the group membership.
This is a version of OptionBase that only supports setting values, for defaults.
OptionDefaults * multi_option_policy(MultiOptionPolicy value=MultiOptionPolicy::Throw)
Take the last argument if given multiple times.
OptionDefaults * disable_flag_override(bool value=true)
Disable overriding flag values with an '=' segment.
OptionDefaults * ignore_case(bool value=true)
Ignore the case of the option name.
OptionDefaults * ignore_underscore(bool value=true)
Ignore underscores in the option name.
OptionDefaults * delimiter(char value='\0')
set a delimiter character to split up single arguments to treat as multiple inputs
Thrown when counting a non-existent option.
Anything that can error in Parse.
Produce a range (factory). Min and max are inclusive.
Range(T min_val, T max_val, const std::string &validator_name=std::string{})
This produces a range with min and max inclusive.
Range(T max_val, const std::string &validator_name=std::string{})
Range of one value is 0 to value.
Thrown when a required option is missing.
Thrown when a requires option is missing.
Does not output a diagnostic in CLI11_PARSE, but allows main() to return with a specific error code.
This is a successful completion on parsing, supposed to exit.
Validate the input as a particular type.
Thrown when validation of results fails.
Some validators that are provided.
bool active_
Enable for Validator to allow it to be disabled if need be.
Validator & non_modifying(bool no_modify=true)
Specify whether the Validator can be modifying or not.
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 Validator active(bool active_val=true) const
Specify whether the Validator is active or not.
CLI11_NODISCARD const std::string & get_name() const
Get the name of the Validator.
std::string name_
The name for search purposes of the Validator.
CLI11_NODISCARD Validator name(std::string validator_name) const
Specify the type string.
int application_index_
A Validator will only apply to an indexed value (-1 is all elements)
std::function< std::string(std::string &)> func_
This is the base function that is to be called.
CLI11_NODISCARD int get_application_index() const
Get the current value of the application index.
Validator operator|(const Validator &other) const
Combining validators is a new validator.
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...
Validator & application_index(int app_index)
Specify the application index of a validator.
Validator operator!() const
Create a validator that fails when a given validator succeeds.
Validator & name(std::string validator_name)
Specify the type string.
CLI11_NODISCARD bool get_active() const
Get a boolean if the validator is active.
Validator & description(std::string validator_desc)
Specify the type string.
CLI11_NODISCARD std::string get_description() const
Generate type description information for the Validator.
CLI11_NODISCARD Validator application_index(int app_index) const
Specify the application index of a validator.
Validator operator&(const Validator &other) const
Combining validators is a new validator.
Validator & active(bool active_val=true)
Specify whether the Validator is active or not.
Validator(std::string validator_desc)
Construct a Validator with just the description string.
std::function< std::string()> desc_function_
This is the description function, if empty the description_ will be used.
Validator(std::function< std::string(std::string &)> op, std::string validator_desc, std::string validator_name="")
Construct Validator from basic information.
Validator & operation(std::function< std::string(std::string &)> op)
Set the Validator operation function.
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...
Check for an existing directory (returns error message if check fails)
Check for an existing file (returns error message if check fails)
Check for an existing path.
Validate the given string is a legal ipv4 address.
Check for an non-existing path.
Check for input streamability.
GF_API std::ostream & operator<<(std::ostream &, const GfBBox3d &)
Output a GfBBox3d using the format [(range) matrix zeroArea].
Holds values to load into Options.
std::vector< std::string > inputs
Listing of inputs.
std::string name
This is the name.
std::vector< std::string > parents
This is the list of parents.
CLI11_NODISCARD std::string fullname() const
The list of parents and name joined by ".".
This can be specialized to override the type deduction for IsMember.
This class is simply to allow tests access to App's protected functions.
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.
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.
static App * get_fallthrough_parent(App *app)
Wrap the fallthrough parent function to make sure that is working correctly.
Handy helper to access the element_type generically.
Combination of the element type and value type - remove pointer (including smart pointers) and get th...
static auto second(Q &&pair_value) -> decltype(std::get< 1 >(std::forward< Q >(pair_value)))
Get the second value (really just the underlying value)
static auto first(Q &&pair_value) -> decltype(std::get< 0 >(std::forward< Q >(pair_value)))
Get the first value (really just the underlying value)
Adaptor for set-like structure: This just wraps a normal container in a few utilities that do almost ...
static auto second(Q &&pair_value) -> decltype(std::forward< Q >(pair_value))
Get the second value (really just the underlying value)
static auto first(Q &&pair_value) -> decltype(std::forward< Q >(pair_value))
Get the first value (really just the underlying value)
forward declare the subtype_count_min structure
Set of overloads to get the type size of an object.
This will only trigger for actual void type.
This will only trigger for actual void type.
template to get the underlying value type if it exists or use a default
Check to see if something is bool (fail check by default)
Check to see if something is copyable pointer.
Check to see if something is a shared pointer.
A copy of std::void_t from C++17 (helper for C++11 and C++14)