38 #error This file should only be included once in any given source (.cpp) file.
58 #include <type_traits>
73 #error This file cannot be included alongside a different CLI11 header.
76 #define CLI11_VERSION_MAJOR 2
77 #define CLI11_VERSION_MINOR 3
78 #define CLI11_VERSION_PATCH 1
79 #define CLI11_VERSION "2.3.1"
85 #if !(defined(_MSC_VER) && __cplusplus == 199711L) && !defined(__INTEL_COMPILER)
86 #if __cplusplus >= 201402L
88 #if __cplusplus >= 201703L
90 #if __cplusplus > 201703L
95 #elif defined(_MSC_VER) && __cplusplus == 199711L
98 #if _MSVC_LANG >= 201402L
100 #if _MSVC_LANG > 201402L && _MSC_VER >= 1910
102 #if _MSVC_LANG > 201703L && _MSC_VER >= 1910
109 #if defined(CLI11_CPP14)
110 #define CLI11_DEPRECATED(reason) [[deprecated(reason)]]
111 #elif defined(_MSC_VER)
112 #define CLI11_DEPRECATED(reason) __declspec(deprecated(reason))
114 #define CLI11_DEPRECATED(reason) __attribute__((deprecated(reason)))
118 #if !defined(CLI11_CPP17) || \
119 (defined(__GNUC__) && !defined(__llvm__) && !defined(__INTEL_COMPILER) && __GNUC__ < 10 && __GNUC__ > 4)
120 #define CLI11_NODISCARD
122 #define CLI11_NODISCARD [[nodiscard]]
126 #ifndef CLI11_USE_STATIC_RTTI
127 #if(defined(_HAS_STATIC_RTTI) && _HAS_STATIC_RTTI)
128 #define CLI11_USE_STATIC_RTTI 1
129 #elif defined(__cpp_rtti)
130 #if(defined(_CPPRTTI) && _CPPRTTI == 0)
131 #define CLI11_USE_STATIC_RTTI 1
133 #define CLI11_USE_STATIC_RTTI 0
135 #elif(defined(__GCC_RTTI) && __GXX_RTTI)
136 #define CLI11_USE_STATIC_RTTI 0
138 #define CLI11_USE_STATIC_RTTI 1
146 #define CLI11_INLINE inline
153 #if defined CLI11_CPP17 && defined __has_include && !defined CLI11_HAS_FILESYSTEM
154 #if __has_include(<filesystem>)
156 #if defined __MAC_OS_X_VERSION_MIN_REQUIRED && __MAC_OS_X_VERSION_MIN_REQUIRED < 101500
157 #define CLI11_HAS_FILESYSTEM 0
158 #elif defined(__wasi__)
160 #define CLI11_HAS_FILESYSTEM 0
162 #include <filesystem>
163 #if defined __cpp_lib_filesystem && __cpp_lib_filesystem >= 201703
164 #if defined _GLIBCXX_RELEASE && _GLIBCXX_RELEASE >= 9
165 #define CLI11_HAS_FILESYSTEM 1
166 #elif defined(__GLIBCXX__)
168 #define CLI11_HAS_FILESYSTEM 0
170 #define CLI11_HAS_FILESYSTEM 1
173 #define CLI11_HAS_FILESYSTEM 0
179 #if defined CLI11_HAS_FILESYSTEM && CLI11_HAS_FILESYSTEM > 0
180 #include <filesystem>
182 #include <sys/stat.h>
183 #include <sys/types.h>
211 using enums::operator<<;
223 std::ostringstream
s;
229 s << delim << *beg++;
235 template <
typename T,
239 std::ostringstream
s;
242 auto loc = s.tellp();
244 auto nloc = s.tellp();
256 std::ostringstream
s;
260 s << v[v.size() -
start - 1];
303 return trim(s, filter);
314 template <
typename T>
bool valid_first_char(T
c) {
return ((c !=
'-') && (c !=
'!') && (c !=
' ') && c !=
'\n'); }
321 return ((c !=
'=') && (c !=
':') && (c !=
'{') && (c !=
' ') && c !=
'\n');
330 return (str.find_first_of(badChars) == std::string::npos);
336 return (str.empty() || str == sep);
341 return std::all_of(str.begin(), str.end(), [](
char c) {
return std::isalpha(
c, std::locale()); });
347 return std::tolower(x, std::locale());
363 return (flags.find_first_of(
"{!") != std::string::npos);
370 const std::vector<std::string> names,
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);
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);
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);
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);
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());
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());
445 if(str.length() > 1 && (str.front() ==
'"' || str.front() ==
'\'')) {
446 if(str.front() == str.back()) {
448 str.erase(str.begin(), str.begin() + 1);
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);
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)) <<
"";
485 if(!aliases.empty()) {
486 out << std::setw(static_cast<int>(wid)) <<
" aliases: ";
488 for(
const auto &alias : aliases) {
506 for(
auto c = str.begin() + 1;
c != e; ++
c)
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();
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());
541 if(ignore_underscore) {
553 }
else if(ignore_underscore) {
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));
600 output.push_back(value);
603 output.push_back(str);
610 embeddedQuote =
false;
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] ==
'=') ?
'-' :
'/'))
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) {}
691 class Error :
public std::runtime_error {
692 int actual_exit_code;
701 : runtime_error(msg), actual_exit_code(exit_code), error_name(std::move(name)) {}
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);
751 return BadNameString(
"Only one positional name allowed, remove: " + name);
821 :
ConversionError(
"The value " + member +
" is not an allowed value for " + name) {}
844 if(min_subcom == 1) {
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) +
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 " +
869 "were given from [" + option_list +
"]",
881 : (
"Expected at least " +
std::to_string(-expected) +
" arguments to " + name +
901 " required for each element");
923 :
ExtrasError((args.size() > 1 ?
"The following arguments were not expected: "
924 :
"The following argument was not expected: ") +
929 (args.size() > 1 ?
"The following arguments were not expected: "
930 :
"The following argument was not expected: ") +
941 return ConfigError(item +
": This option is not allowed in a configuration file");
968 #undef CLI11_ERROR_DEF
969 #undef CLI11_ERROR_SIMPLE
1005 template <
typename T>
struct is_bool : std::false_type {};
1008 template <>
struct is_bool<bool> : std::true_type {};
1014 template <
typename T>
struct is_shared_ptr<std::shared_ptr<T>> : std::true_type {};
1017 template <
typename T>
struct is_shared_ptr<const std::shared_ptr<T>> : std::true_type {};
1041 using type =
typename std::pointer_traits<T>::element_type;
1049 template <
typename T,
typename _ =
void>
struct pair_adaptor : std::false_type {
1055 template <
typename Q>
static auto first(Q &&pair_value) -> decltype(std::forward<Q>(pair_value)) {
1056 return std::forward<Q>(pair_value);
1059 template <
typename Q>
static auto second(Q &&pair_value) -> decltype(std::forward<Q>(pair_value)) {
1060 return std::forward<Q>(pair_value);
1066 template <
typename T>
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"
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;
1118 #pragma GCC diagnostic pop
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;
1159 std::istringstream is;
1162 return !is.fail() && !is.rdbuf()->in_avail();
1176 template <
typename T>
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> {};
1194 template <
typename T>
1198 :
public std::true_type {};
1201 template <
typename T,
typename _ =
void>
struct is_wrapper : std::false_type {};
1204 template <
typename T>
1209 template <
typename SS>
1213 template <
typename>
static auto test(...) -> std::false_type;
1216 static constexpr
bool value = decltype(test<S>(0))::value;
1221 auto to_string(T &&value) -> decltype(std::forward<T>(value)) {
1222 return std::forward<T>(
value);
1226 template <
typename T,
1234 template <
typename T,
1239 std::stringstream
stream;
1241 return stream.str();
1245 template <
typename T,
1254 template <
typename T,
1259 auto cval = variable.begin();
1260 auto end = variable.end();
1264 std::vector<std::string> defaults;
1265 while(cval !=
end) {
1273 template <
typename T1,
1278 return to_string(std::forward<T>(value));
1282 template <
typename T1,
1300 template <
typename T,
1307 template <
typename T,
typename def,
typename Enable =
void>
struct wrapped_type {
using type = def; };
1310 template <
typename T,
typename def>
struct wrapped_type<
T, def, typename std::enable_if<is_wrapper<T>::value>
::type> {
1315 template <
typename T,
typename Enable =
void>
struct type_count_base {
static const int value{0}; };
1318 template <
typename T>
1320 typename std::enable_if<!is_tuple_like<T>::value && !is_mutable_container<T>::value &&
1321 !std::is_void<T>::value>
::type> {
1322 static constexpr
int value{1};
1326 template <
typename T>
1345 template <
typename T,
typename Enable =
void>
struct type_count {
static const int value{0}; };
1348 template <
typename T>
1350 typename std::enable_if<!is_wrapper<T>::value && !is_tuple_like<T>::value && !is_complex<T>::value &&
1351 !std::is_void<T>::value>
::type> {
1352 static constexpr
int value{1};
1357 static constexpr
int value{2};
1361 template <
typename T>
struct type_count<
T, typename std::enable_if<is_mutable_container<T>::value>
::type> {
1366 template <
typename T>
1368 typename std::enable_if<is_wrapper<T>::value && !is_complex<T>::value && !is_tuple_like<T>::value &&
1369 !is_mutable_container<T>::value>
::type> {
1374 template <
typename T, std::
size_t I>
1380 template <
typename T, std::
size_t I>
1386 template <
typename T>
struct type_count<
T, typename std::enable_if<is_tuple_like<T>::value>
::type> {
1387 static constexpr
int value{tuple_type_size<T, 0>()};
1391 template <
typename T>
struct subtype_count {
1396 template <
typename T,
typename Enable =
void>
struct type_count_min {
static const int value{0}; };
1399 template <
typename T>
1400 struct type_count_min<
1402 typename std::enable_if<!is_mutable_container<T>::value && !is_tuple_like<T>::value && !is_wrapper<T>::value &&
1403 !is_complex<T>::value && !std::is_void<T>::value>
::type> {
1408 template <
typename T>
struct type_count_min<
T, typename std::enable_if<is_complex<T>::value>
::type> {
1409 static constexpr
int value{1};
1413 template <
typename T>
1414 struct type_count_min<
1416 typename std::enable_if<is_wrapper<T>::value && !is_complex<T>::value && !is_tuple_like<T>::value>
::type> {
1421 template <
typename T, std::
size_t I>
1427 template <
typename T, std::
size_t I>
1433 template <
typename T>
struct type_count_min<
T, typename std::enable_if<is_tuple_like<T>::value>
::type> {
1434 static constexpr
int value{tuple_type_size_min<T, 0>()};
1438 template <
typename T>
struct subtype_count_min {
1441 : type_count_min<
T>::value};
1445 template <
typename T,
typename Enable =
void>
struct expected_count {
static const int value{0}; };
1448 template <
typename T>
1449 struct expected_count<
T,
1450 typename std::enable_if<!is_mutable_container<T>::value && !is_wrapper<T>::value &&
1451 !std::is_void<T>::value>
::type> {
1452 static constexpr
int value{1};
1455 template <
typename T>
struct expected_count<
T, typename std::enable_if<is_mutable_container<T>::value>
::type> {
1460 template <
typename T>
1461 struct expected_count<
T, typename std::enable_if<!is_mutable_container<T>::value && is_wrapper<T>::value>
::type> {
1466 enum class object_category :
int {
1469 unsigned_integral = 4,
1472 floating_point = 10,
1473 number_constructible = 12,
1474 double_constructible = 14,
1475 integer_constructible = 16,
1477 string_assignable = 23,
1478 string_constructible = 24,
1482 complex_number = 60,
1484 container_value = 80,
1491 template <
typename T,
typename Enable =
void>
struct classify_object {
1492 static constexpr object_category value{object_category::other};
1496 template <
typename T>
1497 struct classify_object<
1499 typename std::enable_if<std::is_integral<T>::value && !std::is_same<T, char>::value && std::is_signed<T>::value &&
1500 !is_bool<T>::value && !std::is_enum<T>::value>
::type> {
1501 static constexpr object_category value{object_category::integral_value};
1505 template <
typename T>
1506 struct classify_object<
T,
1507 typename std::enable_if<std::is_integral<T>::value && std::is_unsigned<T>::value &&
1508 !std::is_same<T, char>::value && !is_bool<T>::value>
::type> {
1509 static constexpr object_category value{object_category::unsigned_integral};
1513 template <
typename T>
1514 struct classify_object<
T, typename std::enable_if<std::is_same<T, char>::value && !std::is_enum<T>::value>
::type> {
1515 static constexpr object_category value{object_category::char_value};
1519 template <
typename T>
struct classify_object<
T, typename std::enable_if<is_bool<T>::value>
::type> {
1520 static constexpr object_category value{object_category::boolean_value};
1524 template <
typename T>
struct classify_object<
T, typename std::enable_if<std::is_floating_point<T>::value>
::type> {
1525 static constexpr object_category value{object_category::floating_point};
1529 template <
typename T>
1530 struct classify_object<
T,
1531 typename std::enable_if<!std::is_floating_point<T>::value && !std::is_integral<T>::value &&
1532 std::is_assignable<T &, std::string>::value>
::type> {
1533 static constexpr object_category value{object_category::string_assignable};
1537 template <
typename T>
1538 struct classify_object<
1540 typename std::enable_if<!std::is_floating_point<T>::value && !std::is_integral<T>::value &&
1541 !std::is_assignable<T &, std::string>::value && (type_count<T>::value == 1) &&
1542 std::is_constructible<T, std::string>::value>
::type> {
1543 static constexpr object_category value{object_category::string_constructible};
1547 template <
typename T>
struct classify_object<
T, typename std::enable_if<std::is_enum<T>::value>
::type> {
1548 static constexpr object_category value{object_category::enumeration};
1551 template <
typename T>
struct classify_object<
T, typename std::enable_if<is_complex<T>::value>
::type> {
1552 static constexpr object_category value{object_category::complex_number};
1557 template <
typename T>
struct uncommon_type {
1568 template <
typename T>
1569 struct classify_object<
T,
1570 typename std::enable_if<(!is_mutable_container<T>::value && is_wrapper<T>::value &&
1571 !is_tuple_like<T>::value && uncommon_type<T>::value)>
::type> {
1572 static constexpr object_category value{object_category::wrapper_value};
1576 template <
typename T>
1577 struct classify_object<
T,
1578 typename std::enable_if<uncommon_type<T>::value && type_count<T>::value == 1 &&
1579 !is_wrapper<T>::value && is_direct_constructible<T, double>::value &&
1580 is_direct_constructible<T, int>::value>
::type> {
1581 static constexpr object_category value{object_category::number_constructible};
1585 template <
typename T>
1586 struct classify_object<
T,
1587 typename std::enable_if<uncommon_type<T>::value && type_count<T>::value == 1 &&
1588 !is_wrapper<T>::value && !is_direct_constructible<T, double>::value &&
1589 is_direct_constructible<T, int>::value>
::type> {
1590 static constexpr object_category value{object_category::integer_constructible};
1594 template <
typename T>
1595 struct classify_object<
T,
1596 typename std::enable_if<uncommon_type<T>::value && type_count<T>::value == 1 &&
1597 !is_wrapper<T>::value && is_direct_constructible<T, double>::value &&
1598 !is_direct_constructible<T, int>::value>
::type> {
1599 static constexpr object_category value{object_category::double_constructible};
1603 template <
typename T>
1604 struct classify_object<
1606 typename std::enable_if<is_tuple_like<T>::value &&
1607 ((type_count<T>::value >= 2 && !is_wrapper<T>::value) ||
1608 (uncommon_type<T>::value && !is_direct_constructible<T, double>::value &&
1609 !is_direct_constructible<T, int>::value) ||
1610 (uncommon_type<T>::value && type_count<T>::value >= 2))>
::type> {
1611 static constexpr object_category value{object_category::tuple_value};
1620 template <
typename T>
struct classify_object<
T, typename std::enable_if<is_mutable_container<T>::value>
::type> {
1621 static constexpr object_category value{object_category::container_value};
1630 template <
typename T,
1636 template <
typename T,
1644 template <
typename T,
1650 template <
typename T,
1660 template <
typename T,
1667 template <
typename T,
1674 template <
typename T,
1681 template <
typename T,
1689 template <
typename T,
1695 template <
typename T,
1702 template <
typename T,
1710 template <
typename T, std::
size_t I>
1716 template <
typename T, std::
size_t I>
1719 tuple_name<T, I + 1>();
1720 if(str.back() ==
',')
1726 template <
typename T,
1730 auto tname =
std::string(1,
'[') + tuple_name<T, 0>();
1731 tname.push_back(
']');
1736 template <
typename T,
1737 enable_if_t<classify_object<T>::value == object_category::container_value ||
1741 return type_name<typename T::value_type>();
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);
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);
1791 if(val == trueString) {
1794 if(val == falseString) {
1798 std::int64_t ret = 0;
1799 if(val.size() == 1) {
1800 if(val[0] >=
'1' && val[0] <=
'9') {
1801 return (static_cast<std::int64_t>(val[0]) -
'0');
1816 throw std::invalid_argument(
"unrecognized character");
1820 if(val == trueString || val ==
"on" || val ==
"yes" || val ==
"enable") {
1822 }
else if(val == falseString || val ==
"off" || val ==
"no" || val ==
"disable") {
1825 ret = std::stoll(val);
1831 template <
typename T,
1832 enable_if_t<classify_object<T>::value == object_category::integral_value ||
1840 template <
typename T,
1841 enable_if_t<classify_object<T>::value == object_category::char_value, detail::enabler> =
detail::dummy>
1843 if(input.size() == 1) {
1844 output =
static_cast<T>(input[0]);
1851 template <
typename T,
1852 enable_if_t<classify_object<T>::value == object_category::boolean_value, detail::enabler> =
detail::dummy>
1858 }
catch(
const std::invalid_argument &) {
1860 }
catch(
const std::out_of_range &) {
1863 output = (input[0] !=
'-');
1869 template <
typename T,
1870 enable_if_t<classify_object<T>::value == object_category::floating_point, detail::enabler> =
detail::dummy>
1875 char *val =
nullptr;
1876 auto output_ld = std::strtold(input.c_str(), &
val);
1877 output =
static_cast<T>(output_ld);
1878 return val == (input.c_str() + input.size());
1882 template <
typename T,
1883 enable_if_t<classify_object<T>::value == object_category::complex_number, detail::enabler> =
detail::dummy>
1888 bool worked =
false;
1889 auto nloc = str1.find_last_of(
"+-");
1890 if(nloc != std::string::npos && nloc > 0) {
1892 str1 = str1.substr(nloc);
1893 if(str1.back() ==
'i' || str1.back() ==
'j')
1897 if(str1.back() ==
'i' || str1.back() ==
'j') {
1914 template <
typename T,
1915 enable_if_t<classify_object<T>::value == object_category::string_assignable, detail::enabler> =
detail::dummy>
1924 enable_if_t<classify_object<T>::value == object_category::string_constructible, detail::enabler> =
detail::dummy>
1931 template <
typename T,
1932 enable_if_t<classify_object<T>::value == object_category::enumeration, detail::enabler> =
detail::dummy>
1938 output =
static_cast<T>(
val);
1943 template <
typename T,
1944 enable_if_t<classify_object<T>::value == object_category::wrapper_value &&
1956 template <
typename T,
1957 enable_if_t<classify_object<T>::value == object_category::wrapper_value &&
1972 enable_if_t<classify_object<T>::value == object_category::number_constructible, detail::enabler> =
detail::dummy>
1992 enable_if_t<classify_object<T>::value == object_category::integer_constructible, detail::enabler> =
detail::dummy>
2005 enable_if_t<classify_object<T>::value == object_category::double_constructible, detail::enabler> =
detail::dummy>
2016 template <
typename T,
2023 #pragma warning(push)
2024 #pragma warning(disable : 4800)
2030 #pragma warning(pop)
2042 template <
typename T,
2043 enable_if_t<classify_object<T>::value == object_category::other && !std::is_assignable<T &, int>::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");
2054 template <
typename AssignTo,
2058 classify_object<AssignTo>::value == object_category::string_constructible),
2065 template <
typename AssignTo,
2068 classify_object<AssignTo>::value != object_category::string_assignable &&
2069 classify_object<AssignTo>::value != object_category::string_constructible,
2073 output = AssignTo{};
2081 template <
typename AssignTo,
2084 classify_object<AssignTo>::value == object_category::wrapper_value,
2097 template <
typename AssignTo,
2100 classify_object<AssignTo>::value != object_category::wrapper_value &&
2117 template <
typename AssignTo,
2123 bool parse_result = (!input.empty()) ? lexical_cast<ConvertTo>(input, val) :
true;
2127 return parse_result;
2139 bool parse_result = input.empty() ?
true :
lexical_cast<ConvertTo>(input,
val);
2141 output = AssignTo(val);
2143 return parse_result;
2147 template <
typename AssignTo,
2150 classify_object<AssignTo>::value <= object_category::wrapper_value,
2152 bool lexical_conversion(
const std::vector<std ::string> &
strings, AssignTo &output) {
2153 return lexical_assign<AssignTo, ConvertTo>(strings[0], output);
2158 template <
typename AssignTo,
2163 bool lexical_conversion(
const std::vector<std ::string> &
strings, AssignTo &output) {
2167 bool retval = lexical_assign<decltype(v1), decltype(v1)>(strings[0],
v1);
2168 if(strings.size() > 1) {
2169 retval = retval && lexical_assign<decltype(v2), decltype(v2)>(strings[1],
v2);
2172 output = AssignTo{
v1, v2};
2178 template <
class AssignTo,
2183 bool lexical_conversion(
const std::vector<std ::string> &strings, AssignTo &output) {
2184 output.erase(output.begin(), output.end());
2185 if(strings.size() == 1 && strings[0] ==
"{}") {
2188 bool skip_remaining =
false;
2189 if(strings.size() == 2 && strings[0] ==
"{}" &&
is_separator(strings[1])) {
2190 skip_remaining =
true;
2192 for(
const auto &elem : strings) {
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());
2208 bool lexical_conversion(
const std::vector<std::string> &strings, AssignTo &output) {
2210 if(strings.size() >= 2 && !strings[1].empty()) {
2213 auto str1 = strings[1];
2214 if(str1.back() ==
'i' || str1.back() ==
'j') {
2219 output = ConvertTo{
x,
y};
2223 return lexical_assign<AssignTo, ConvertTo>(strings[0], output);
2227 template <
class AssignTo,
2230 (type_count<ConvertTo>::value == 1),
2232 bool lexical_conversion(
const std::vector<std ::string> &strings, AssignTo &output) {
2235 output.reserve(strings.size());
2236 for(
const auto &elem : strings) {
2238 output.emplace_back();
2239 retval = retval && lexical_assign<typename AssignTo::value_type, ConvertTo>(elem, output.back());
2241 return (!output.empty()) && retval;
2247 template <
class AssignTo,
2252 bool lexical_conversion(std::vector<std::string> strings, AssignTo &output);
2255 template <
class AssignTo,
2258 type_count_base<ConvertTo>::value != 2 &&
2259 ((type_count<ConvertTo>::value > 2) ||
2260 (type_count<ConvertTo>::value > type_count_base<ConvertTo>::value)),
2262 bool lexical_conversion(
const std::vector<std::string> &strings, AssignTo &output);
2265 template <
class AssignTo,
2268 (type_count_base<ConvertTo>::value != type_count<ConvertTo>::value ||
2269 type_count<ConvertTo>::value > 2),
2271 bool lexical_conversion(
const std::vector<std::string> &strings, AssignTo &output);
2275 template <
typename AssignTo,
2281 bool lexical_conversion(
const std::vector<std ::string> &strings, AssignTo &output) {
2283 if(strings.size() > 1 || (!strings.empty() && !(strings.front().empty()))) {
2285 auto retval = lexical_conversion<ConvertTo, ConvertTo>(
strings,
val);
2286 output = AssignTo{val};
2289 output = AssignTo{};
2294 template <
class AssignTo,
class ConvertTo, std::
size_t I>
2296 tuple_conversion(
const std::vector<std::string> &, AssignTo &) {
2301 template <
class AssignTo,
class ConvertTo>
2303 tuple_type_conversion(std::vector<std::string> &strings, AssignTo &output) {
2304 auto retval = lexical_assign<AssignTo, ConvertTo>(strings[0], output);
2305 strings.erase(strings.begin());
2310 template <
class AssignTo,
class ConvertTo>
2314 tuple_type_conversion(std::vector<std::string> &strings, AssignTo &output) {
2315 auto retval = lexical_conversion<AssignTo, ConvertTo>(
strings, output);
2316 strings.erase(strings.begin(), strings.begin() + type_count<ConvertTo>::value);
2321 template <
class AssignTo,
class ConvertTo>
2325 tuple_type_conversion(std::vector<std::string> &strings, AssignTo &output) {
2329 const std::size_t mx{(
std::max)(mx_count, strings.size())};
2337 bool retval = lexical_conversion<AssignTo, ConvertTo>(
2338 std::vector<std::string>(strings.begin(), strings.begin() +
static_cast<std::ptrdiff_t
>(
index)), output);
2339 strings.erase(strings.begin(), strings.begin() +
static_cast<std::ptrdiff_t
>(
index) + 1);
2344 template <
class AssignTo,
class ConvertTo, std::
size_t I>
2346 tuple_conversion(std::vector<std::string> strings, AssignTo &output) {
2348 using ConvertToElement =
typename std::
2350 if(!strings.empty()) {
2352 strings, std::get<I>(output));
2354 retval = retval && tuple_conversion<AssignTo, ConvertTo, I + 1>(std::move(strings), output);
2359 template <
class AssignTo,
2362 type_count_base<ConvertTo>::value == 2,
2364 bool lexical_conversion(std::vector<std::string> strings, AssignTo &output) {
2366 while(!strings.empty()) {
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);
2380 return (!output.empty());
2384 template <
class AssignTo,
2387 (type_count_base<ConvertTo>::value != type_count<ConvertTo>::value ||
2388 type_count<ConvertTo>::value > 2),
2390 bool lexical_conversion(
const std::vector<std ::string> &strings, AssignTo &output) {
2393 "if the conversion type is defined as a tuple it must be the same size as the type you are converting to");
2394 return tuple_conversion<AssignTo, ConvertTo, 0>(
strings, output);
2398 template <
class AssignTo,
2401 type_count_base<ConvertTo>::value != 2 &&
2402 ((type_count<ConvertTo>::value > 2) ||
2403 (type_count<ConvertTo>::value > type_count_base<ConvertTo>::value)),
2405 bool lexical_conversion(
const std::vector<std ::string> &strings, AssignTo &output) {
2408 std::vector<std::string> temp;
2410 std::size_t icount{0};
2411 std::size_t xcm{type_count<ConvertTo>::value};
2412 auto ii_max = strings.size();
2413 while(ii < ii_max) {
2414 temp.push_back(strings[ii]);
2417 if(icount == xcm ||
is_separator(temp.back()) || ii == ii_max) {
2423 lexical_conversion<typename AssignTo::value_type, typename ConvertTo::value_type>(temp, temp_out);
2428 output.insert(output.end(), std::move(temp_out));
2436 template <
typename AssignTo,
2438 enable_if_t<classify_object<ConvertTo>::value == object_category::wrapper_value &&
2441 bool lexical_conversion(
const std::vector<std::string> &strings, AssignTo &output) {
2442 if(strings.empty() || strings.front().empty()) {
2443 output = ConvertTo{};
2447 if(lexical_conversion<typename ConvertTo::value_type, typename ConvertTo::value_type>(strings, val)) {
2448 output = ConvertTo{val};
2455 template <
typename AssignTo,
2457 enable_if_t<classify_object<ConvertTo>::value == object_category::wrapper_value &&
2460 bool lexical_conversion(
const std::vector<std::string> &strings, AssignTo &output) {
2462 if(strings.empty() || strings.front().empty()) {
2463 output = ConvertType{};
2467 if(lexical_conversion<typename ConvertTo::value_type, typename ConvertTo::value_type>(strings, val)) {
2479 for(
const auto &
arg : values) {
2485 }
catch(
const std::exception &) {
2493 for(
const auto &arg : values) {
2500 val == static_cast<std::int64_t>(val)) {
2532 get_names(
const std::vector<std::string> &input);
2541 if(current.size() > 1 && current[0] ==
'-' &&
valid_first_char(current[1])) {
2542 name = current.substr(1, 1);
2543 rest = current.substr(2);
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);
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);
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);
2592 flags.erase(std::remove_if(flags.begin(),
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(
'{');
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);
2619 std::vector<std::string> short_names;
2620 std::vector<std::string> long_names;
2624 if(
name.length() == 0) {
2627 if(
name.length() > 1 &&
name[0] ==
'-' &&
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) ==
"--") {
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);
2678 std::vector<ConfigItem> items{};
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());
2702 throw FileError::Missing(name);
2704 return from_config(input);
2708 virtual ~
Config() =
default;
2715 char commentChar =
'#';
2717 char arrayStart =
'[';
2719 char arrayEnd =
']';
2721 char arraySeparator =
',';
2723 char valueDelimiter =
'=';
2725 char stringQuote =
'"';
2727 char characterQuote =
'\'';
2729 uint8_t maximumLayers{255};
2731 char parentSeparatorChar{
'.'};
2733 int16_t configIndex{-1};
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;
2785 configSection = sectionName;
2795 configIndex = sectionIndex;
2811 arraySeparator =
' ';
2812 valueDelimiter =
'=';
2833 std::function<std::string()> desc_function_{[]() {
return std::string{}; }};
2841 int application_index_ = -1;
2845 bool non_modifying_{
false};
2848 : desc_function_([validator_desc]() {
return validator_desc; }), func_(std::move(
func)) {}
2851 Validator() =
default;
2856 : desc_function_([validator_desc]() {
return validator_desc; }), func_(std::move(op)),
2860 func_ = std::move(op);
2876 desc_function_ = [validator_desc]() {
return validator_desc; };
2885 return desc_function_();
2891 name_ = std::move(validator_name);
2897 newval.
name_ = std::move(validator_name);
2904 active_ = active_val;
2916 non_modifying_ = no_modify;
2921 application_index_ = app_index;
3022 auto val = DesiredType();
3024 return std::string(
"Failed parsing ") + input_string +
" as a " + detail::type_name<DesiredType>();
3028 TypeValidator() : TypeValidator(detail::
type_name<DesiredType>()) {}
3032 const TypeValidator<double>
Number(
"NUMBER");
3048 template <
typename T>
3050 if(validator_name.empty()) {
3051 std::stringstream out;
3052 out << detail::type_name<T>() <<
" in [" << min_val <<
" - " << max_val <<
"]";
3053 description(out.str());
3060 std::stringstream out;
3061 out <<
"Value " << input <<
" not in range [";
3062 out << min_val <<
" - " << max_val <<
"]";
3070 template <
typename T>
3072 :
Range(static_cast<T>(0), max_val, validator_name) {}
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());
3097 return std::string(
"Value ") + input +
" could not be converted";
3101 else if(val > max_val)
3109 template <
typename T>
explicit Bound(T max_val) :
Bound(static_cast<
T>(0), max_val) {}
3113 template <
typename T,
3145 [key_only](
const iteration_type_t &
v) {
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>;
3170 auto search(
const T &set,
const V &val) -> std::pair<bool, decltype(std::begin(detail::smart_deref(set)))> {
3176 return {(it !=
std::end(setref)), it};
3181 auto search(
const T &set,
const V &val) -> std::pair<bool, decltype(std::begin(detail::smart_deref(set)))> {
3183 auto it = setref.find(val);
3184 return {(it !=
std::end(setref)), it};
3188 template <
typename T,
typename V>
3189 auto search(
const T &set,
const V &val,
const std::function<V(V)> &filter_function)
3190 -> std::pair<bool, decltype(std::begin(detail::smart_deref(set)))> {
3193 auto res =
search(set, val);
3194 if((res.first) || (!(filter_function))) {
3201 a = filter_function(
a);
3204 return {(it !=
std::end(setref)), it};
3211 template <
typename T>
3213 if((a > 0) == (b > 0)) {
3219 template <
typename T>
3226 if(a == 0 || b == 0 || a == 1 || b == 1) {
3241 template <
typename T>
3244 if(std::isinf(c) && !std::isinf(a) && !std::isinf(b)) {
3258 template <
typename T,
typename... Args>
3260 :
IsMember(std::vector<
T>(values), std::forward<Args>(
args)...) {}
3267 template <
typename T,
typename F>
explicit IsMember(T set, F filter_function) {
3278 std::function<local_item_t(local_item_t)> filter_fn = filter_function;
3310 template <
typename T,
typename... Args>
3313 std::forward<
T>(set),
3314 [filter_fn_1, filter_fn_2](std::
string a) {
return filter_fn_2(filter_fn_1(
a)); },
3327 template <
typename... Args>
3328 Transformer(std::initializer_list<std::pair<std::string, std::string>> values, Args &&...
args)
3336 template <
typename T,
typename F>
explicit Transformer(T mapping, F filter_function) {
3339 "mapping must produce value pairs");
3348 std::function<local_item_t(local_item_t)> filter_fn = filter_function;
3353 func_ = [mapping, filter_fn](
std::string &input) {
3371 template <
typename T,
typename... Args>
3374 std::forward<
T>(mapping),
3375 [filter_fn_1, filter_fn_2](std::
string a) {
return filter_fn_2(filter_fn_1(
a)); },
3385 template <
typename... Args>
3397 "mapping must produce value pairs");
3407 std::function<local_item_t(local_item_t)> filter_fn = filter_function;
3409 auto tfunc = [mapping]() {
3420 desc_function_ = tfunc;
3422 func_ = [mapping, tfunc, filter_fn](
std::string &input) {
3437 if(output_string == input) {
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)); },
3487 CASE_INSENSITIVE = 1,
3493 template <
typename Number>
3497 description(generate_description<Number>(unit_name, opts));
3498 validate_mapping(mapping, opts);
3510 auto unit_begin = input.end();
3511 while(unit_begin > input.begin() &&
std::isalpha(*(unit_begin - 1), std::locale())) {
3516 input.resize(static_cast<std::size_t>(
std::distance(input.begin(), unit_begin)));
3519 if(opts & UNIT_REQUIRED &&
unit.empty()) {
3522 if(opts & CASE_INSENSITIVE) {
3528 detail::type_name<Number>());
3535 auto it = mapping.find(
unit);
3536 if(it == mapping.end()) {
3538 " unit not recognized. "
3539 "Allowed values: " +
3543 if(!input.empty()) {
3547 detail::type_name<Number>());
3553 " factor would cause number overflow. Use smaller value.");
3556 num =
static_cast<Number>(it->second);
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()) {
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) {
3583 if(lower_mapping.count(
s)) {
3589 mapping = std::move(lower_mapping);
3595 std::stringstream out;
3596 out << detail::type_name<Number>() <<
' ';
3597 if(opts & UNIT_REQUIRED) {
3600 out <<
'[' << name <<
']';
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);
3658 if(non_modifying_) {
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_;
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_;
3708 if(s1.empty() || s2.empty())
3711 return std::string(
"(") + s1 +
") OR (" + s2 +
")";
3720 const std::function<std::string()> &dfunc1 = desc_function_;
3722 auto str = dfunc1();
3726 const std::function<std::string(std::string & res)> &f1 = func_;
3731 return std::string(
"check ") + dfunc1() +
" succeeded improperly";
3743 const std::function<std::string()> &dfunc1 = val1.
desc_function_;
3744 const std::function<std::string()> &dfunc2 = val2.
desc_function_;
3746 desc_function_ = [=]() {
3749 if((f1.empty()) || (f2.empty())) {
3752 return std::string(1,
'(') + f1 +
')' + merger +
'(' + f2 +
')';
3758 #if defined CLI11_HAS_FILESYSTEM && CLI11_HAS_FILESYSTEM > 0
3761 auto stat = std::filesystem::status(
file, ec);
3765 switch(stat.type()) {
3766 case std::filesystem::file_type::none:
3767 case std::filesystem::file_type::not_found:
3769 case std::filesystem::file_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:
3784 #if defined(_MSC_VER)
3785 struct __stat64 buffer;
3786 if(_stat64(
file, &buffer) == 0) {
3791 if(stat(
file, &buffer) == 0) {
3803 return "File does not exist: " +
filename;
3806 return "File is actually a directory: " +
filename;
3816 return "Directory does not exist: " +
filename;
3819 return "Directory is actually a file: " +
filename;
3829 return "Path does not exist: " +
filename;
3839 return "Path already exists: " +
filename;
3849 return std::string(
"Invalid IPV4 address must have four parts (") + ip_addr +
')';
3852 for(
const auto &var :
result) {
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;
3873 if(default_path.back() !=
'/' && default_path.back() !=
'\\') {
3875 test_file_path +=
'/';
3882 if(enableErrorReturn) {
3883 return "File does not exist: " +
filename;
3893 description(
"SIZE [b, kb(=1000b), kib(=1024b), ...]");
3899 CLI11_INLINE std::map<std::string, AsSizeValue::result_t> AsSizeValue::init_mapping(
bool kb_is_1000) {
3900 std::map<std::string, result_t> m;
3901 result_t k_factor = kb_is_1000 ? 1000 : 1024;
3906 for(
std::string p : {
"k",
"m",
"g",
"t",
"p",
"e"}) {
3917 CLI11_INLINE std::map<std::string, AsSizeValue::result_t> AsSizeValue::get_mapping(
bool kb_is_1000) {
3919 static auto m = init_mapping(
true);
3922 static auto m = init_mapping(
false);
3930 std::pair<std::string, std::string> vals;
3932 auto esp = commandline.find_first_of(
' ', 1);
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);
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{};
4055 using funct_t = std::function<std::string(const App *, std::string, AppFormatMode)>;
4069 return lambda_(app, name, mode);
4124 std::stringstream out;
4200 template <
typename T>
void copy_to(T *other)
const;
4211 return static_cast<CRTP *
>(
this);
4217 return static_cast<CRTP *
>(
this);
4225 return static_cast<CRTP *
>(
this);
4261 auto *
self =
static_cast<CRTP *
>(
this);
4268 auto *
self =
static_cast<CRTP *
>(
this);
4275 auto self =
static_cast<CRTP *
>(
this);
4282 auto *
self =
static_cast<CRTP *
>(
this);
4289 auto self =
static_cast<CRTP *
>(
this);
4298 return static_cast<CRTP *
>(
this);
4304 return static_cast<CRTP *
>(
this);
4565 auto opt =
static_cast<T *
>(
parent_)->get_option_no_throw(opt_name);
4566 if(opt ==
nullptr) {
4567 throw IncorrectConstruction::MissingOption(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);