67#define CLI11_VERSION_MAJOR 2
68#define CLI11_VERSION_MINOR 6
69#define CLI11_VERSION_PATCH 2
70#define CLI11_VERSION "2.6.2"
76#if !(defined(_MSC_VER) && __cplusplus == 199711L) && !defined(__INTEL_COMPILER)
77#if __cplusplus >= 201402L
79#if __cplusplus >= 201703L
81#if __cplusplus > 201703L
83#if __cplusplus > 202002L
85#if __cplusplus > 202302L
92#elif defined(_MSC_VER) && __cplusplus == 199711L
95#if _MSVC_LANG >= 201402L
97#if _MSVC_LANG > 201402L && _MSC_VER >= 1910
99#if _MSVC_LANG > 201703L && _MSC_VER >= 1910
101#if _MSVC_LANG > 202002L && _MSC_VER >= 1922
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
143#if defined CLI11_CPP17 && defined __has_include && !defined CLI11_HAS_FILESYSTEM
144#if __has_include(<filesystem>)
146#if defined __MAC_OS_X_VERSION_MIN_REQUIRED && __MAC_OS_X_VERSION_MIN_REQUIRED < 101500
147#define CLI11_HAS_FILESYSTEM 0
148#elif defined(__wasi__)
150#define CLI11_HAS_FILESYSTEM 0
153#if defined __cpp_lib_filesystem && __cpp_lib_filesystem >= 201703
154#if defined _GLIBCXX_RELEASE && _GLIBCXX_RELEASE >= 9
155#define CLI11_HAS_FILESYSTEM 1
156#elif defined(__GLIBCXX__)
158#define CLI11_HAS_FILESYSTEM 0
160#define CLI11_HAS_FILESYSTEM 1
163#define CLI11_HAS_FILESYSTEM 0
170#if !defined(CLI11_CPP26) && !defined(CLI11_HAS_CODECVT)
171#if defined(__GNUC__) && !defined(__llvm__) && !defined(__INTEL_COMPILER) && __GNUC__ < 5
172#define CLI11_HAS_CODECVT 0
174#define CLI11_HAS_CODECVT 1
178#if defined(CLI11_HAS_CODECVT)
179#if CLI11_HAS_CODECVT > 0
183#define CLI11_HAS_CODECVT 0
188#ifndef CLI11_HAS_RTTI
189#if defined(__GXX_RTTI) && __GXX_RTTI == 1
191#define CLI11_HAS_RTTI 1
192#elif defined(_CPPRTTI) && _CPPRTTI == 1
194#define CLI11_HAS_RTTI 1
195#elif defined(__NO_RTTI__) && __NO_RTTI__ == 1
197#define CLI11_HAS_RTTI 0
198#elif defined(__has_feature)
200#if __has_feature(cxx_rtti)
201#define CLI11_HAS_RTTI 1
203#define CLI11_HAS_RTTI 0
205#elif defined(__RTTI) || defined(__INTEL_RTTI__)
207#define CLI11_HAS_RTTI 1
209#define CLI11_HAS_RTTI 0
215#define CLI11_DIAGNOSTIC_PUSH _Pragma("GCC diagnostic push")
216#define CLI11_DIAGNOSTIC_POP _Pragma("GCC diagnostic pop")
218#define CLI11_DIAGNOSTIC_IGNORE_DEPRECATED _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"")
220#elif defined(_MSC_VER)
221#define CLI11_DIAGNOSTIC_PUSH __pragma(warning(push))
222#define CLI11_DIAGNOSTIC_POP __pragma(warning(pop))
224#define CLI11_DIAGNOSTIC_IGNORE_DEPRECATED __pragma(warning(disable : 4996))
227#define CLI11_DIAGNOSTIC_PUSH
228#define CLI11_DIAGNOSTIC_POP
230#define CLI11_DIAGNOSTIC_IGNORE_DEPRECATED
238#define CLI11_INLINE inline
242#if defined CLI11_CPP17
243#define CLI11_MODULE_INLINE inline
245#define CLI11_MODULE_INLINE static
250#if defined CLI11_HAS_FILESYSTEM && CLI11_HAS_FILESYSTEM > 0
254#include <sys/types.h>
261#include <string_view>
264#if defined CLI11_HAS_FILESYSTEM && CLI11_HAS_FILESYSTEM > 0
266#include <string_view>
272#if !(defined(_AMD64_) || defined(_X86_) || defined(_ARM_))
273#if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_X64) || \
276#elif defined(i386) || defined(__i386) || defined(__i386__) || defined(__i386__) || defined(_M_IX86)
278#elif defined(__arm__) || defined(_M_ARM) || defined(_M_ARMT)
280#elif defined(__aarch64__) || defined(_M_ARM64)
282#elif defined(_M_ARM64EC)
300#include <processthreadsapi.h>
309CLI11_INLINE std::string narrow(
const std::wstring &str);
310CLI11_INLINE std::string narrow(
const wchar_t *str);
311CLI11_INLINE std::string narrow(
const wchar_t *str, std::size_t size);
314CLI11_INLINE std::wstring widen(
const std::string &str);
315CLI11_INLINE std::wstring widen(
const char *str);
316CLI11_INLINE std::wstring widen(
const char *str, std::size_t size);
319CLI11_INLINE std::string narrow(std::wstring_view str);
320CLI11_INLINE std::wstring widen(std::string_view str);
323#if defined CLI11_HAS_FILESYSTEM && CLI11_HAS_FILESYSTEM > 0
325CLI11_INLINE std::filesystem::path to_path(std::string_view str);
333#if !CLI11_HAS_CODECVT
335CLI11_INLINE
void set_unicode_locale() {
336 static const std::array<const char *, 3> unicode_locales{{
"C.UTF-8",
"en_US.UTF-8",
".UTF-8"}};
338 for(
const auto &locale_name : unicode_locales) {
339 if(std::setlocale(LC_ALL, locale_name) !=
nullptr) {
343 throw std::runtime_error(
"CLI::narrow: could not set locale to C.UTF-8");
346template <
typename F>
struct scope_guard_t {
349 explicit scope_guard_t(F closure_) : closure(closure_) {}
350 ~scope_guard_t() { closure(); }
353template <
typename F> CLI11_NODISCARD CLI11_INLINE scope_guard_t<F> scope_guard(F &&closure) {
354 return scope_guard_t<F>{std::forward<F>(closure)};
360CLI11_DIAGNOSTIC_IGNORE_DEPRECATED
362CLI11_INLINE std::string narrow_impl(
const wchar_t *str, std::size_t str_size) {
365 return std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>>().to_bytes(str, str + str_size);
368 return std::wstring_convert<std::codecvt_utf8<wchar_t>>().to_bytes(str, str + str_size);
373 std::mbstate_t state = std::mbstate_t();
374 const wchar_t *it = str;
376 std::string old_locale = std::setlocale(LC_ALL,
nullptr);
377 auto sg = scope_guard([&] { std::setlocale(LC_ALL, old_locale.c_str()); });
378 set_unicode_locale();
380 std::size_t new_size = std::wcsrtombs(
nullptr, &it, 0, &state);
381 if(new_size ==
static_cast<std::size_t
>(-1)) {
382 throw std::runtime_error(
"CLI::narrow: conversion error in std::wcsrtombs at offset " +
383 std::to_string(it - str));
385 std::string result(new_size,
'\0');
386 std::wcsrtombs(
const_cast<char *
>(result.data()), &str, new_size, &state);
393CLI11_INLINE std::wstring widen_impl(
const char *str, std::size_t str_size) {
396 return std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>>().from_bytes(str, str + str_size);
399 return std::wstring_convert<std::codecvt_utf8<wchar_t>>().from_bytes(str, str + str_size);
404 std::mbstate_t state = std::mbstate_t();
405 const char *it = str;
407 std::string old_locale = std::setlocale(LC_ALL,
nullptr);
408 auto sg = scope_guard([&] { std::setlocale(LC_ALL, old_locale.c_str()); });
409 set_unicode_locale();
411 std::size_t new_size = std::mbsrtowcs(
nullptr, &it, 0, &state);
412 if(new_size ==
static_cast<std::size_t
>(-1)) {
413 throw std::runtime_error(
"CLI::widen: conversion error in std::mbsrtowcs at offset " +
414 std::to_string(it - str));
416 std::wstring result(new_size, L
'\0');
417 std::mbsrtowcs(
const_cast<wchar_t *
>(result.data()), &str, new_size, &state);
428CLI11_INLINE std::string narrow(
const wchar_t *str, std::size_t str_size) {
return detail::narrow_impl(str, str_size); }
429CLI11_INLINE std::string narrow(
const std::wstring &str) {
return detail::narrow_impl(str.data(), str.size()); }
431CLI11_INLINE std::string narrow(
const wchar_t *str) {
return detail::narrow_impl(str, std::wcslen(str)); }
433CLI11_INLINE std::wstring widen(
const char *str, std::size_t str_size) {
return detail::widen_impl(str, str_size); }
434CLI11_INLINE std::wstring widen(
const std::string &str) {
return detail::widen_impl(str.data(), str.size()); }
436CLI11_INLINE std::wstring widen(
const char *str) {
return detail::widen_impl(str, std::strlen(str)); }
439CLI11_INLINE std::string narrow(std::wstring_view str) {
return detail::narrow_impl(str.data(), str.size()); }
440CLI11_INLINE std::wstring widen(std::string_view str) {
return detail::widen_impl(str.data(), str.size()); }
443#if defined CLI11_HAS_FILESYSTEM && CLI11_HAS_FILESYSTEM > 0
444CLI11_INLINE std::filesystem::path to_path(std::string_view str) {
445 return std::filesystem::path{
461CLI11_INLINE std::vector<std::string> compute_win32_argv();
470CLI11_INLINE std::vector<std::string> compute_win32_argv() {
471 std::vector<std::string> result;
474 auto deleter = [](
wchar_t **ptr) { LocalFree(ptr); };
476 auto wargv = std::unique_ptr<wchar_t *[], decltype(deleter)>(CommandLineToArgvW(GetCommandLineW(), &argc), deleter);
479 if(wargv ==
nullptr) {
480 throw std::runtime_error(
"CommandLineToArgvW failed with code " + std::to_string(GetLastError()));
483 result.reserve(
static_cast<size_t>(argc));
484 for(
size_t i = 0; i < static_cast<size_t>(argc); ++i) {
485 result.push_back(narrow(wargv[i]));
502template <typename T, typename = typename std::enable_if<std::is_enum<T>::value>::type>
506 return in << +static_cast<typename std::underlying_type<T>::type>(item);
512using enums::operator<<;
517CLI11_MODULE_INLINE
constexpr int expected_max_vector_size{1 << 29};
520CLI11_INLINE std::vector<std::string> split(
const std::string &s,
char delim);
523template <
typename T> std::string join(
const T &v, std::string delim =
",") {
524 std::ostringstream s;
525 auto beg = std::begin(v);
526 auto end = std::end(v);
530 s << delim << *beg++;
533 if(!rval.empty() && delim.size() == 1 && rval.back() == delim[0]) {
543 typename =
typename std::enable_if<!std::is_constructible<std::string, Callable>::value>::type>
544std::string join(
const T &v, Callable func, std::string delim =
",") {
545 std::ostringstream s;
546 auto beg = std::begin(v);
547 auto end = std::end(v);
548 auto loc = s.tellp();
550 auto nloc = s.tellp();
561template <
typename T> std::string rjoin(
const T &v, std::string delim =
",") {
562 std::ostringstream s;
563 for(std::size_t start = 0; start < v.size(); start++) {
566 s << v[v.size() - start - 1];
574CLI11_INLINE std::string <rim(std::string &str);
577CLI11_INLINE std::string <rim(std::string &str,
const std::string &filter);
580CLI11_INLINE std::string &rtrim(std::string &str);
583CLI11_INLINE std::string &rtrim(std::string &str,
const std::string &filter);
586inline std::string &trim(std::string &str) {
return ltrim(rtrim(str)); }
589inline std::string &trim(std::string &str,
const std::string filter) {
return ltrim(rtrim(str, filter), filter); }
592inline std::string trim_copy(
const std::string &str) {
598CLI11_INLINE std::string &remove_quotes(std::string &str);
601CLI11_INLINE
void remove_quotes(std::vector<std::string> &args);
607CLI11_INLINE std::string fix_newlines(
const std::string &leader, std::string input);
610inline std::string trim_copy(
const std::string &str,
const std::string &filter) {
612 return trim(s, filter);
616CLI11_INLINE std::ostream &format_aliases(std::ostream &out,
const std::vector<std::string> &aliases, std::size_t wid);
620template <
typename T>
bool valid_first_char(T c) {
621 return ((c !=
'-') && (
static_cast<unsigned char>(c) > 33));
625template <
typename T>
bool valid_later_char(T c) {
629 return ((c !=
'=') && (c !=
':') && (c !=
'{') && ((
static_cast<unsigned char>(c) > 32) || c ==
'\t'));
633CLI11_INLINE
bool valid_name_string(
const std::string &str);
636inline bool valid_alias_name_string(
const std::string &str) {
637 return ((str.find_first_of(
'\n') == std::string::npos) && (str.find_first_of(
'\0') == std::string::npos));
641inline bool is_separator(
const std::string &str) {
642 return (str.empty() || (str.size() == 2 && str[0] ==
'%' && str[1] ==
'%'));
646inline bool isalpha(
const std::string &str) {
647 return std::all_of(str.begin(), str.end(), [](
char c) { return std::isalpha(c, std::locale()); });
651inline std::string to_lower(std::string str) {
652 std::transform(std::begin(str), std::end(str), std::begin(str), [](
const std::string::value_type &x) {
653 return std::tolower(x, std::locale());
659inline std::string remove_underscore(std::string str) {
660 str.erase(std::remove(std::begin(str), std::end(str),
'_'), std::end(str));
666CLI11_INLINE std::string get_group_separators();
669CLI11_INLINE std::string find_and_replace(std::string str, std::string from, std::string to);
672inline bool has_default_flag_values(
const std::string &flags) {
673 return (flags.find_first_of(
"{!") != std::string::npos);
676CLI11_INLINE
void remove_default_flag_values(std::string &flags);
679CLI11_INLINE std::ptrdiff_t find_member(std::string name,
680 const std::vector<std::string> names,
681 bool ignore_case =
false,
682 bool ignore_underscore =
false);
686template <
typename Callable>
inline std::string find_and_modify(std::string str, std::string trigger, Callable modify) {
687 std::size_t start_pos = 0;
688 while((start_pos = str.find(trigger, start_pos)) != std::string::npos) {
689 start_pos = modify(str, start_pos);
696CLI11_INLINE std::size_t close_sequence(
const std::string &str, std::size_t start,
char closure_char);
700CLI11_INLINE std::vector<std::string> split_up(std::string str,
char delimiter =
'\0');
703CLI11_INLINE std::string get_environment_value(
const std::string &env_name);
709CLI11_INLINE std::size_t escape_detect(std::string &str, std::size_t offset);
714CLI11_INLINE
bool has_escapable_character(
const std::string &str);
719CLI11_INLINE std::string add_escaped_characters(
const std::string &str);
722CLI11_INLINE std::string remove_escaped_characters(
const std::string &str);
725CLI11_INLINE std::string binary_escape_string(
const std::string &string_to_escape,
bool force =
false);
727CLI11_INLINE
bool is_binary_escaped_string(
const std::string &escaped_string);
730CLI11_INLINE std::string extract_binary_string(
const std::string &escaped_string);
733CLI11_INLINE
bool process_quoted_string(std::string &str,
734 char string_char =
'\"',
735 char literal_char =
'\'',
736 bool disable_secondary_array_processing =
false);
740CLI11_INLINE std::ostream &streamOutAsParagraph(std::ostream &out,
741 const std::string &text,
742 std::size_t paragraphWidth,
743 const std::string &linePrefix =
"",
744 bool skipPrefixOnFirstLine =
false);
752CLI11_INLINE std::vector<std::string> split(
const std::string &s,
char delim) {
753 std::vector<std::string> elems;
756 elems.emplace_back();
758 std::stringstream ss;
761 while(std::getline(ss, item, delim)) {
762 elems.push_back(item);
768CLI11_INLINE std::string <rim(std::string &str) {
769 auto it = std::find_if(str.begin(), str.end(), [](
char ch) { return !std::isspace<char>(ch, std::locale()); });
770 str.erase(str.begin(), it);
774CLI11_INLINE std::string <rim(std::string &str,
const std::string &filter) {
775 auto it = std::find_if(str.begin(), str.end(), [&filter](
char ch) { return filter.find(ch) == std::string::npos; });
776 str.erase(str.begin(), it);
780CLI11_INLINE std::string &rtrim(std::string &str) {
781 auto it = std::find_if(str.rbegin(), str.rend(), [](
char ch) { return !std::isspace<char>(ch, std::locale()); });
782 str.erase(it.base(), str.end());
786CLI11_INLINE std::string &rtrim(std::string &str,
const std::string &filter) {
788 std::find_if(str.rbegin(), str.rend(), [&filter](
char ch) { return filter.find(ch) == std::string::npos; });
789 str.erase(it.base(), str.end());
793CLI11_INLINE std::string &remove_quotes(std::string &str) {
794 if(str.length() > 1 && (str.front() ==
'"' || str.front() ==
'\'' || str.front() ==
'`')) {
795 if(str.front() == str.back()) {
797 str.erase(str.begin(), str.begin() + 1);
803CLI11_INLINE std::string &remove_outer(std::string &str,
char key) {
804 if(str.length() > 1 && (str.front() == key)) {
805 if(str.front() == str.back()) {
807 str.erase(str.begin(), str.begin() + 1);
813CLI11_INLINE std::string fix_newlines(
const std::string &leader, std::string input) {
814 std::string::size_type n = 0;
815 while(n != std::string::npos && n < input.size()) {
816 n = input.find_first_of(
"\r\n", n);
817 if(n != std::string::npos) {
818 input = input.substr(0, n + 1) + leader + input.substr(n + 1);
825CLI11_INLINE std::ostream &format_aliases(std::ostream &out,
const std::vector<std::string> &aliases, std::size_t wid) {
826 if(!aliases.empty()) {
827 out << std::setw(static_cast<int>(wid)) <<
" aliases: ";
829 for(
const auto &alias : aliases) {
835 out << detail::fix_newlines(
" ", alias);
842CLI11_INLINE
bool valid_name_string(
const std::string &str) {
843 if(str.empty() || !valid_first_char(str[0])) {
847 for(
auto c = str.begin() + 1; c != e; ++c)
848 if(!valid_later_char(*c))
853CLI11_INLINE std::string get_group_separators() {
854 std::string separators{
"_'"};
855#if CLI11_HAS_RTTI != 0
856 char group_separator = std::use_facet<std::numpunct<char>>(std::locale()).thousands_sep();
857 separators.push_back(group_separator);
862CLI11_INLINE std::string find_and_replace(std::string str, std::string from, std::string to) {
864 std::size_t start_pos = 0;
866 while((start_pos = str.find(from, start_pos)) != std::string::npos) {
867 str.replace(start_pos, from.length(), to);
868 start_pos += to.length();
874CLI11_INLINE
void remove_default_flag_values(std::string &flags) {
875 auto loc = flags.find_first_of(
'{', 2);
876 while(loc != std::string::npos) {
877 auto finish = flags.find_first_of(
"},", loc + 1);
878 if((finish != std::string::npos) && (flags[finish] ==
'}')) {
879 flags.erase(flags.begin() +
static_cast<std::ptrdiff_t
>(loc),
880 flags.begin() +
static_cast<std::ptrdiff_t
>(finish) + 1);
882 loc = flags.find_first_of(
'{', loc + 1);
884 flags.erase(std::remove(flags.begin(), flags.end(),
'!'), flags.end());
887CLI11_INLINE std::ptrdiff_t
888find_member(std::string name,
const std::vector<std::string> names,
bool ignore_case,
bool ignore_underscore) {
889 auto it = std::end(names);
891 if(ignore_underscore) {
892 name = detail::to_lower(detail::remove_underscore(name));
893 it = std::find_if(std::begin(names), std::end(names), [&name](std::string local_name) {
894 return detail::to_lower(detail::remove_underscore(local_name)) == name;
897 name = detail::to_lower(name);
898 it = std::find_if(std::begin(names), std::end(names), [&name](std::string local_name) {
899 return detail::to_lower(local_name) == name;
903 }
else if(ignore_underscore) {
904 name = detail::remove_underscore(name);
905 it = std::find_if(std::begin(names), std::end(names), [&name](std::string local_name) {
906 return detail::remove_underscore(local_name) == name;
909 it = std::find(std::begin(names), std::end(names), name);
912 return (it != std::end(names)) ? (it - std::begin(names)) : (-1);
915CLI11_MODULE_INLINE
const std::string &escapedChars(
"\b\t\n\f\r\"\\");
916CLI11_MODULE_INLINE
const std::string &escapedCharsCode(
"btnfr\"\\");
917CLI11_MODULE_INLINE
const std::string &bracketChars(
"\"'`[(<{");
918CLI11_MODULE_INLINE
const std::string &matchBracketChars(
"\"'`])>}");
920CLI11_INLINE
bool has_escapable_character(
const std::string &str) {
921 return (str.find_first_of(escapedChars) != std::string::npos);
924CLI11_INLINE std::string add_escaped_characters(
const std::string &str) {
926 out.reserve(str.size() + 4);
928 auto sloc = escapedChars.find_first_of(s);
929 if(sloc != std::string::npos) {
931 out.push_back(escapedCharsCode[sloc]);
939CLI11_INLINE std::uint32_t hexConvert(
char hc) {
941 if(hc >=
'0' && hc <=
'9') {
943 }
else if(hc >=
'A' && hc <=
'F') {
944 hcode = (hc -
'A' + 10);
945 }
else if(hc >=
'a' && hc <=
'f') {
946 hcode = (hc -
'a' + 10);
950 return static_cast<uint32_t
>(hcode);
953CLI11_INLINE
char make_char(std::uint32_t code) {
return static_cast<char>(
static_cast<unsigned char>(code)); }
955CLI11_INLINE
void append_codepoint(std::string &str, std::uint32_t code) {
957 str.push_back(
static_cast<char>(code));
958 }
else if(code < 0x800) {
960 str.push_back(make_char(0xC0 | code >> 6));
961 str.push_back(make_char(0x80 | (code & 0x3F)));
962 }
else if(code < 0x10000) {
963 if(0xD800 <= code && code <= 0xDFFF) {
964 throw std::invalid_argument(
"[0xD800, 0xDFFF] are not valid UTF-8.");
967 str.push_back(make_char(0xE0 | code >> 12));
968 str.push_back(make_char(0x80 | (code >> 6 & 0x3F)));
969 str.push_back(make_char(0x80 | (code & 0x3F)));
970 }
else if(code < 0x110000) {
972 str.push_back(make_char(0xF0 | code >> 18));
973 str.push_back(make_char(0x80 | (code >> 12 & 0x3F)));
974 str.push_back(make_char(0x80 | (code >> 6 & 0x3F)));
975 str.push_back(make_char(0x80 | (code & 0x3F)));
979CLI11_INLINE std::string remove_escaped_characters(
const std::string &str) {
982 out.reserve(str.size());
983 for(
auto loc = str.begin(); loc < str.end(); ++loc) {
985 if(str.end() - loc < 2) {
986 throw std::invalid_argument(
"invalid escape sequence " + str);
988 auto ecloc = escapedCharsCode.find_first_of(*(loc + 1));
989 if(ecloc != std::string::npos) {
990 out.push_back(escapedChars[ecloc]);
992 }
else if(*(loc + 1) ==
'u') {
994 if(str.end() - loc < 6) {
995 throw std::invalid_argument(
"unicode sequence must have 4 hex codes " + str);
997 std::uint32_t code{0};
998 std::uint32_t mplier{16 * 16 * 16};
999 for(
int ii = 2; ii < 6; ++ii) {
1000 std::uint32_t res = hexConvert(*(loc + ii));
1002 throw std::invalid_argument(
"unicode sequence must have 4 hex codes " + str);
1004 code += res * mplier;
1005 mplier = mplier / 16;
1007 append_codepoint(out, code);
1009 }
else if(*(loc + 1) ==
'U') {
1011 if(str.end() - loc < 10) {
1012 throw std::invalid_argument(
"unicode sequence must have 8 hex codes " + str);
1014 std::uint32_t code{0};
1015 std::uint32_t mplier{16 * 16 * 16 * 16 * 16 * 16 * 16};
1016 for(
int ii = 2; ii < 10; ++ii) {
1017 std::uint32_t res = hexConvert(*(loc + ii));
1019 throw std::invalid_argument(
"unicode sequence must have 8 hex codes " + str);
1021 code += res * mplier;
1022 mplier = mplier / 16;
1024 append_codepoint(out, code);
1026 }
else if(*(loc + 1) ==
'0') {
1027 out.push_back(
'\0');
1030 throw std::invalid_argument(std::string(
"unrecognized escape sequence \\") + *(loc + 1) +
" in " + str);
1033 out.push_back(*loc);
1039CLI11_INLINE std::size_t close_string_quote(
const std::string &str, std::size_t start,
char closure_char) {
1041 for(loc = start + 1; loc < str.size(); ++loc) {
1042 if(str[loc] == closure_char) {
1045 if(str[loc] ==
'\\') {
1053CLI11_INLINE std::size_t close_literal_quote(
const std::string &str, std::size_t start,
char closure_char) {
1054 auto loc = str.find_first_of(closure_char, start + 1);
1055 return (loc != std::string::npos ? loc : str.size());
1058CLI11_INLINE std::size_t close_sequence(
const std::string &str, std::size_t start,
char closure_char) {
1060 auto bracket_loc = matchBracketChars.find(closure_char);
1061 switch(bracket_loc) {
1063 return close_string_quote(str, start, closure_char);
1066#if defined(_MSC_VER) && _MSC_VER < 1920
1067 case(std::size_t)-1:
1069 case std::string::npos:
1071 return close_literal_quote(str, start, closure_char);
1076 std::string closures(1, closure_char);
1077 auto loc = start + 1;
1079 while(loc < str.size()) {
1080 if(str[loc] == closures.back()) {
1081 closures.pop_back();
1082 if(closures.empty()) {
1086 bracket_loc = bracketChars.find(str[loc]);
1087 if(bracket_loc != std::string::npos) {
1088 switch(bracket_loc) {
1090 loc = close_string_quote(str, loc, str[loc]);
1094 loc = close_literal_quote(str, loc, str[loc]);
1097 closures.push_back(matchBracketChars[bracket_loc]);
1103 if(loc > str.size()) {
1109CLI11_INLINE std::vector<std::string> split_up(std::string str,
char delimiter) {
1111 auto find_ws = [delimiter](
char ch) {
1112 return (delimiter ==
'\0') ? std::isspace<char>(ch, std::locale()) : (ch == delimiter);
1116 std::vector<std::string> output;
1117 while(!str.empty()) {
1118 if(bracketChars.find_first_of(str[0]) != std::string::npos) {
1119 auto bracketLoc = bracketChars.find_first_of(str[0]);
1120 auto end = close_sequence(str, 0, matchBracketChars[bracketLoc]);
1121 if(end >= str.size()) {
1122 output.push_back(std::move(str));
1125 output.push_back(str.substr(0, end + 1));
1126 if(end + 2 < str.size()) {
1127 str = str.substr(end + 2);
1134 auto it = std::find_if(std::begin(str), std::end(str), find_ws);
1135 if(it != std::end(str)) {
1136 std::string value = std::string(str.begin(), it);
1137 output.push_back(value);
1138 str = std::string(it + 1, str.end());
1140 output.push_back(str);
1149CLI11_INLINE std::size_t escape_detect(std::string &str, std::size_t offset) {
1150 auto next = str[offset + 1];
1151 if((next ==
'\"') || (next ==
'\'') || (next ==
'`')) {
1152 auto astart = str.find_last_of(
"-/ \"\'`", offset - 1);
1153 if(astart != std::string::npos) {
1154 if(str[astart] == ((str[offset] ==
'=') ?
'-' :
'/'))
1161CLI11_INLINE std::string binary_escape_string(
const std::string &string_to_escape,
bool force) {
1163 std::string escaped_string{};
1165 for(
char c : string_to_escape) {
1168 if(isprint(
static_cast<unsigned char>(c)) == 0) {
1169 std::stringstream stream;
1173 stream << std::hex << static_cast<unsigned int>(
static_cast<unsigned char>(c));
1174 std::string code = stream.str();
1175 escaped_string += std::string(
"\\x") + (code.size() < 2 ?
"0" :
"") + code;
1176 }
else if(c ==
'x' || c ==
'X') {
1178 if(!escaped_string.empty() && escaped_string.back() ==
'\\') {
1179 escaped_string += std::string(
"\\x") + (c ==
'x' ?
"78" :
"58");
1181 escaped_string.push_back(c);
1185 escaped_string.push_back(c);
1188 if(escaped_string != string_to_escape || force) {
1189 auto sqLoc = escaped_string.find(
'\'');
1190 while(sqLoc != std::string::npos) {
1191 escaped_string[sqLoc] =
'\\';
1192 escaped_string.insert(sqLoc + 1,
"x27");
1193 sqLoc = escaped_string.find(
'\'');
1195 escaped_string.insert(0,
"'B\"(");
1196 escaped_string.push_back(
')');
1197 escaped_string.push_back(
'"');
1198 escaped_string.push_back(
'\'');
1200 return escaped_string;
1203CLI11_INLINE
bool is_binary_escaped_string(
const std::string &escaped_string) {
1204 size_t ssize = escaped_string.size();
1205 if(escaped_string.compare(0, 3,
"B\"(") == 0 && escaped_string.compare(ssize - 2, 2,
")\"") == 0) {
1208 return (escaped_string.compare(0, 4,
"'B\"(") == 0 && escaped_string.compare(ssize - 3, 3,
")\"'") == 0);
1211CLI11_INLINE std::string extract_binary_string(
const std::string &escaped_string) {
1212 std::size_t start{0};
1213 std::size_t tail{0};
1214 size_t ssize = escaped_string.size();
1215 if(escaped_string.compare(0, 3,
"B\"(") == 0 && escaped_string.compare(ssize - 2, 2,
")\"") == 0) {
1218 }
else if(escaped_string.compare(0, 4,
"'B\"(") == 0 && escaped_string.compare(ssize - 3, 3,
")\"'") == 0) {
1224 return escaped_string;
1226 std::string outstring;
1228 outstring.reserve(ssize - start - tail);
1229 std::size_t loc = start;
1230 while(loc < ssize - tail) {
1232 if(escaped_string[loc] ==
'\\' && (escaped_string[loc + 1] ==
'x' || escaped_string[loc + 1] ==
'X')) {
1233 auto c1 = escaped_string[loc + 2];
1234 auto c2 = escaped_string[loc + 3];
1236 std::uint32_t res1 = hexConvert(c1);
1237 std::uint32_t res2 = hexConvert(c2);
1238 if(res1 <= 0x0F && res2 <= 0x0F) {
1240 outstring.push_back(
static_cast<char>(res1 * 16 + res2));
1244 outstring.push_back(escaped_string[loc]);
1250CLI11_INLINE
void remove_quotes(std::vector<std::string> &args) {
1251 for(
auto &arg : args) {
1252 if(arg.front() ==
'\"' && arg.back() ==
'\"') {
1255 arg = remove_escaped_characters(arg);
1262CLI11_INLINE
void handle_secondary_array(std::string &str) {
1263 if(str.size() >= 2 && str.front() ==
'[' && str.back() ==
']') {
1265 std::string tstr{
"[["};
1266 for(std::size_t ii = 1; ii < str.size(); ++ii) {
1267 tstr.push_back(str[ii]);
1268 tstr.push_back(str[ii]);
1270 str = std::move(tstr);
1275process_quoted_string(std::string &str,
char string_char,
char literal_char,
bool disable_secondary_array_processing) {
1276 if(str.size() <= 1) {
1279 if(detail::is_binary_escaped_string(str)) {
1280 str = detail::extract_binary_string(str);
1281 if(!disable_secondary_array_processing)
1282 handle_secondary_array(str);
1285 if(str.front() == string_char && str.back() == string_char) {
1286 detail::remove_outer(str, string_char);
1287 if(str.find_first_of(
'\\') != std::string::npos) {
1288 str = detail::remove_escaped_characters(str);
1290 if(!disable_secondary_array_processing)
1291 handle_secondary_array(str);
1294 if((str.front() == literal_char || str.front() ==
'`') && str.back() == str.front()) {
1295 detail::remove_outer(str, str.front());
1296 if(!disable_secondary_array_processing)
1297 handle_secondary_array(str);
1303std::string get_environment_value(
const std::string &env_name) {
1304 std::string ename_string;
1308 char *buffer =
nullptr;
1310 if(_dupenv_s(&buffer, &sz, env_name.c_str()) == 0 && buffer !=
nullptr) {
1311 ename_string = std::string(buffer);
1318 const char *buffer =
nullptr;
1319 buffer = std::getenv(env_name.c_str());
1320 if(buffer !=
nullptr) {
1321 ename_string = std::string(buffer);
1324 return ename_string;
1327CLI11_INLINE std::ostream &streamOutAsParagraph(std::ostream &out,
1328 const std::string &text,
1329 std::size_t paragraphWidth,
1330 const std::string &linePrefix,
1331 bool skipPrefixOnFirstLine) {
1332 if(!skipPrefixOnFirstLine)
1335 std::istringstream lss(text);
1336 std::string line =
"";
1337 while(std::getline(lss, line)) {
1338 std::istringstream iss(line);
1339 std::string word =
"";
1340 std::size_t charsWritten = 0;
1342 while(iss >> word) {
1343 if(charsWritten > 0 && (word.length() + 1 + charsWritten > paragraphWidth)) {
1344 out <<
'\n' << linePrefix;
1347 if(charsWritten == 0) {
1349 charsWritten += word.length();
1352 charsWritten += word.length() + 1;
1357 out <<
'\n' << linePrefix;
1368#define CLI11_ERROR_DEF(parent, name) \
1370 name(std::string ename, std::string msg, int exit_code) : parent(std::move(ename), std::move(msg), exit_code) {} \
1371 name(std::string ename, std::string msg, ExitCodes exit_code) \
1372 : parent(std::move(ename), std::move(msg), exit_code) {} \
1375 name(std::string msg, ExitCodes exit_code) : parent(#name, std::move(msg), exit_code) {} \
1376 name(std::string msg, int exit_code) : parent(#name, std::move(msg), exit_code) {}
1379#define CLI11_ERROR_SIMPLE(name) \
1380 explicit name(std::string msg) : name(#name, msg, ExitCodes::name) {}
1384enum class ExitCodes :
int {
1413class Error :
public std::runtime_error {
1414 int actual_exit_code;
1415 std::string error_name{
"Error"};
1418 CLI11_NODISCARD
int get_exit_code()
const {
return actual_exit_code; }
1420 CLI11_NODISCARD std::string get_name()
const {
return error_name; }
1422 Error(std::string name, std::string msg,
int exit_code =
static_cast<int>(ExitCodes::BaseClass))
1423 : runtime_error(msg), actual_exit_code(exit_code), error_name(std::move(name)) {}
1425 Error(std::string name, std::string msg, ExitCodes exit_code) : Error(name, msg,
static_cast<int>(exit_code)) {}
1453 name +
": You can't change expected arguments after you've changed the multi option policy!");
1459 return IncorrectConstruction(name +
": multi_option_policy only works for flags and exact value options");
1469 return BadNameString(
"Long names strings require 2 dashes " + name);
1476 return BadNameString(
"Names '-','--','++' are reserved and not allowed as option names " + name);
1478 static BadNameString MultiPositionalNames(std::string name) {
1479 return BadNameString(
"Only one positional name allowed, remove: " + name);
1486 explicit OptionAlreadyAdded(std::string name)
1487 : OptionAlreadyAdded(name +
" is already added", ExitCodes::OptionAlreadyAdded) {}
1488 static OptionAlreadyAdded Requires(std::string name, std::string other) {
1489 return {name +
" requires " + other, ExitCodes::OptionAlreadyAdded};
1491 static OptionAlreadyAdded Excludes(std::string name, std::string other) {
1492 return {name +
" excludes " + other, ExitCodes::OptionAlreadyAdded};
1508 Success() : Success(
"Successfully completed, should be caught and quit", ExitCodes::Success) {}
1512class CallForHelp :
public Success {
1513 CLI11_ERROR_DEF(Success, CallForHelp)
1514 CallForHelp() : CallForHelp(
"This should be caught in your main function, see examples", ExitCodes::Success) {}
1518class CallForAllHelp :
public Success {
1519 CLI11_ERROR_DEF(Success, CallForAllHelp)
1521 : CallForAllHelp(
"This should be caught in your main function, see examples", ExitCodes::Success) {}
1525class CallForVersion :
public Success {
1526 CLI11_ERROR_DEF(Success, CallForVersion)
1528 : CallForVersion(
"This should be caught in your main function, see examples", ExitCodes::Success) {}
1534 explicit RuntimeError(
int exit_code = 1) : RuntimeError(
"Runtime error", exit_code) {}
1541 static FileError Missing(std::string name) {
return FileError(name +
" was not readable (missing?)"); }
1547 CLI11_ERROR_SIMPLE(ConversionError)
1548 ConversionError(std::string member, std::string name)
1549 : ConversionError(
"The value " + member +
" is not an allowed value for " + name) {}
1550 ConversionError(std::string name, std::vector<std::string> results)
1551 : ConversionError(
"Could not convert: " + name +
" = " + detail::join(results)) {}
1552 static ConversionError TooManyInputsFlag(std::string name) {
1553 return ConversionError(name +
": too many inputs for a flag");
1555 static ConversionError TrueFalse(std::string name) {
1556 return ConversionError(name +
": Should be true/false or a number");
1563 CLI11_ERROR_SIMPLE(ValidationError)
1564 explicit ValidationError(std::string name, std::string msg) : ValidationError(name +
": " + msg) {}
1570 explicit RequiredError(std::string name) : RequiredError(name +
" is required", ExitCodes::RequiredError) {}
1571 static RequiredError Subcommand(std::size_t min_subcom) {
1572 if(min_subcom == 1) {
1573 return RequiredError(
"A subcommand");
1575 return {
"Requires at least " + std::to_string(min_subcom) +
" subcommands", ExitCodes::RequiredError};
1577 static RequiredError
1578 Option(std::size_t min_option, std::size_t max_option, std::size_t used,
const std::string &option_list) {
1579 if((min_option == 1) && (max_option == 1) && (used == 0))
1580 return RequiredError(
"Exactly 1 option from [" + option_list +
"]");
1581 if((min_option == 1) && (max_option == 1) && (used > 1)) {
1582 return {
"Exactly 1 option from [" + option_list +
"] is required but " + std::to_string(used) +
1584 ExitCodes::RequiredError};
1586 if((min_option == 1) && (used == 0))
1587 return RequiredError(
"At least 1 option from [" + option_list +
"]");
1588 if(used < min_option) {
1589 return {
"Requires at least " + std::to_string(min_option) +
" options used but only " +
1590 std::to_string(used) +
" were given from [" + option_list +
"]",
1591 ExitCodes::RequiredError};
1594 return {
"Requires at most 1 options be given from [" + option_list +
"]", ExitCodes::RequiredError};
1596 return {
"Requires at most " + std::to_string(max_option) +
" options be used but " + std::to_string(used) +
1597 " were given from [" + option_list +
"]",
1598 ExitCodes::RequiredError};
1604 CLI11_ERROR_DEF(
ParseError, ArgumentMismatch)
1605 CLI11_ERROR_SIMPLE(ArgumentMismatch)
1606 ArgumentMismatch(std::string name,
int expected, std::size_t received)
1607 : ArgumentMismatch(expected > 0 ? (
"Expected exactly " + std::to_string(expected) +
" arguments to " + name +
1608 ", got " + std::to_string(received))
1609 : (
"Expected at least " + std::to_string(-expected) +
" arguments to " + name +
1610 ", got " + std::to_string(received)),
1611 ExitCodes::ArgumentMismatch) {}
1613 static ArgumentMismatch AtLeast(std::string name,
int num, std::size_t received) {
1614 return ArgumentMismatch(name +
": At least " + std::to_string(num) +
" required but received " +
1615 std::to_string(received));
1617 static ArgumentMismatch AtMost(std::string name,
int num, std::size_t received) {
1618 return ArgumentMismatch(name +
": At most " + std::to_string(num) +
" required but received " +
1619 std::to_string(received));
1621 static ArgumentMismatch TypedAtLeast(std::string name,
int num, std::string type) {
1622 return ArgumentMismatch(name +
": " + std::to_string(num) +
" required " + type +
" missing");
1624 static ArgumentMismatch FlagOverride(std::string name) {
1625 return ArgumentMismatch(name +
" was given a disallowed flag override");
1627 static ArgumentMismatch PartialType(std::string name,
int num, std::string type) {
1628 return ArgumentMismatch(name +
": " + type +
" only partially specified: " + std::to_string(num) +
1629 " required for each element");
1636 RequiresError(std::string curname, std::string subname)
1637 : RequiresError(curname +
" requires " + subname, ExitCodes::RequiresError) {}
1643 ExcludesError(std::string curname, std::string subname)
1644 : ExcludesError(curname +
" excludes " + subname, ExitCodes::ExcludesError) {}
1650 explicit ExtrasError(std::vector<std::string> args)
1651 : ExtrasError((args.size() > 1 ?
"The following arguments were not expected: "
1652 :
"The following argument was not expected: ") +
1653 detail::join(args,
" "),
1654 ExitCodes::ExtrasError) {}
1655 ExtrasError(
const std::string &name, std::vector<std::string> args)
1657 (args.size() > 1 ?
"The following arguments were not expected: "
1658 :
"The following argument was not expected: ") +
1659 detail::join(args,
" "),
1660 ExitCodes::ExtrasError) {}
1668 static ConfigError NotConfigurable(std::string item) {
1669 return ConfigError(item +
": This option is not allowed in a configuration file");
1676 explicit InvalidError(std::string name)
1677 : InvalidError(name +
": Too many positional arguments with unlimited expected args", ExitCodes::InvalidError) {
1691class OptionNotFound :
public Error {
1692 CLI11_ERROR_DEF(Error, OptionNotFound)
1693 explicit OptionNotFound(std::string name) : OptionNotFound(name +
" not found", ExitCodes::OptionNotFound) {}
1696#undef CLI11_ERROR_DEF
1697#undef CLI11_ERROR_SIMPLE
1710enum class enabler : std::uint8_t {};
1713CLI11_MODULE_INLINE
constexpr enabler dummy = {};
1721template <
bool B,
class T =
void>
using enable_if_t =
typename std::enable_if<B, T>::type;
1729template <
typename... Ts>
using void_t =
typename make_void<Ts...>::type;
1732template <
bool B,
class T,
class F>
using conditional_t =
typename std::conditional<B, T, F>::type;
1735template <
typename T>
struct is_bool : std::false_type {};
1738template <>
struct is_bool<bool> : std::true_type {};
1744template <
typename T>
struct is_shared_ptr<std::shared_ptr<T>> : std::true_type {};
1747template <
typename T>
struct is_shared_ptr<const std::shared_ptr<T>> : std::true_type {};
1761 using type = std::string;
1764namespace adl_detail {
1771 template <
typename TT,
typename SS>
1772 static auto test(
int) ->
decltype(lexical_cast(std::declval<const SS &>(), std::declval<TT &>()), std::true_type());
1774 template <
typename,
typename>
static auto test(...) -> std::false_type;
1777 static constexpr bool value =
decltype(test<T, S>(0))::value;
1793template <
typename T>
struct element_type<T, typename std::enable_if<is_copyable_ptr<T>::value>::type> {
1794 using type =
typename std::pointer_traits<T>::element_type;
1804template <
typename T,
typename _ =
void>
struct pair_adaptor : std::false_type {
1805 using value_type =
typename T::value_type;
1806 using first_type =
typename std::remove_const<value_type>::type;
1807 using second_type =
typename std::remove_const<value_type>::type;
1810 template <
typename Q>
static auto first(Q &&pair_value) ->
decltype(std::forward<Q>(pair_value)) {
1811 return std::forward<Q>(pair_value);
1814 template <
typename Q>
static auto second(Q &&pair_value) ->
decltype(std::forward<Q>(pair_value)) {
1815 return std::forward<Q>(pair_value);
1821template <
typename T>
1824 conditional_t<false, void_t<typename T::value_type::first_type, typename T::value_type::second_type>, void>>
1826 using value_type =
typename T::value_type;
1827 using first_type =
typename std::remove_const<typename value_type::first_type>::type;
1828 using second_type =
typename std::remove_const<typename value_type::second_type>::type;
1831 template <
typename Q>
static auto first(Q &&pair_value) ->
decltype(std::get<0>(std::forward<Q>(pair_value))) {
1832 return std::get<0>(std::forward<Q>(pair_value));
1835 template <
typename Q>
static auto second(Q &&pair_value) ->
decltype(std::get<1>(std::forward<Q>(pair_value))) {
1836 return std::get<1>(std::forward<Q>(pair_value));
1847#pragma GCC diagnostic push
1848#pragma GCC diagnostic ignored "-Wnarrowing"
1852 template <
typename TT,
typename CC>
1853 static auto test(
int, std::true_type) ->
decltype(
1856#ifdef __NVCC_DIAG_PRAGMA_SUPPORT__
1857#pragma nv_diag_suppress 2361
1859#pragma diag_suppress 2361
1862 TT{std::declval<CC>()}
1864#ifdef __NVCC_DIAG_PRAGMA_SUPPORT__
1865#pragma nv_diag_default 2361
1867#pragma diag_default 2361
1871 std::is_move_assignable<TT>());
1873 template <
typename TT,
typename CC>
static auto test(
int, std::false_type) -> std::false_type;
1875 template <
typename,
typename>
static auto test(...) -> std::false_type;
1878 static constexpr bool value =
decltype(test<T, C>(0,
typename std::is_constructible<T, C>::type()))::value;
1881#pragma GCC diagnostic pop
1888 template <
typename TT,
typename SS>
1889 static auto test(
int) ->
decltype(std::declval<SS &>() << std::declval<TT>(), std::true_type());
1891 template <
typename,
typename>
static auto test(...) -> std::false_type;
1894 static constexpr bool value =
decltype(test<T, S>(0))::value;
1899 template <
typename TT,
typename SS>
1900 static auto test(
int) ->
decltype(std::declval<SS &>() >> std::declval<TT &>(), std::true_type());
1902 template <
typename,
typename>
static auto test(...) -> std::false_type;
1905 static constexpr bool value =
decltype(test<T, S>(0))::value;
1910 template <
typename TT>
1911 static auto test(
int) ->
decltype(std::declval<TT>().real(), std::declval<TT>().imag(), std::true_type());
1913 template <
typename>
static auto test(...) -> std::false_type;
1916 static constexpr bool value =
decltype(test<T>(0))::value;
1920template <typename T, enable_if_t<is_istreamable<T>::value, detail::enabler> = detail::dummy>
1921bool from_stream(
const std::string &istring, T &obj) {
1922 std::istringstream is;
1925 return !is.fail() && !is.rdbuf()->in_avail();
1928template <typename T, enable_if_t<!is_istreamable<T>::value, detail::enabler> = detail::dummy>
1929bool from_stream(
const std::string & , T & ) {
1939template <
typename T>
1942 conditional_t<false,
1943 void_t<typename T::value_type,
1944 decltype(std::declval<T>().end()),
1945 decltype(std::declval<T>().clear()),
1946 decltype(std::declval<T>().insert(std::declval<decltype(std::declval<T>().end())>(),
1947 std::declval<const typename T::value_type &>()))>,
1948 void>> :
public conditional_t<std::is_constructible<T, std::string>::value ||
1949 std::is_constructible<T, std::wstring>::value,
1958template <
typename T>
1961 conditional_t<false, void_t<decltype(std::declval<T>().end()), decltype(std::declval<T>().begin())>, void>>
1962 :
public std::true_type {};
1965template <
typename T,
typename _ =
void>
struct is_wrapper : std::false_type {};
1968template <
typename T>
1969struct is_wrapper<T, conditional_t<false, void_t<typename T::value_type>, void>> :
public std::true_type {};
1974 template <typename SS, enable_if_t<!is_complex<SS>::value, detail::enabler> = detail::dummy>
1977 static auto test(
int) ->
decltype(std::tuple_size<typename std::decay<SS>::type>::value, std::true_type{});
1978 template <
typename>
static auto test(...) -> std::false_type;
1981 static constexpr bool value =
decltype(test<S>(0))::value;
1986 static const int value{0};
1990template <
typename T>
1992 typename std::enable_if<!is_tuple_like<T>::value && !is_mutable_container<T>::value &&
1993 !std::is_void<T>::value>::type> {
1994 static constexpr int value{1};
1998template <
typename T>
1999struct type_count_base<T, typename std::enable_if<is_tuple_like<T>::value && !is_mutable_container<T>::value>::type> {
2000 static constexpr int value{
2001 std::tuple_size<typename std::decay<T>::type>::value};
2005template <
typename T>
struct type_count_base<T, typename std::enable_if<is_mutable_container<T>::value>::type> {
2006 static constexpr int value{type_count_base<typename T::value_type>::value};
2010template <typename T, enable_if_t<std::is_convertible<T, std::string>::value, detail::enabler> = detail::dummy>
2011auto to_string(T &&value) ->
decltype(std::forward<T>(value)) {
2012 return std::forward<T>(value);
2016template <
typename T,
2017 enable_if_t<std::is_constructible<std::string, T>::value && !std::is_convertible<T, std::string>::value,
2018 detail::enabler> = detail::dummy>
2019std::string to_string(T &&value) {
2020 return std::string(value);
2024template <
typename T,
2025 enable_if_t<!std::is_convertible<T, std::string>::value && !std::is_constructible<std::string, T>::value &&
2026 is_ostreamable<T>::value,
2027 detail::enabler> = detail::dummy>
2028std::string to_string(T &&value) {
2029 std::stringstream stream;
2031 return stream.str();
2037template <
typename T,
2038 enable_if_t<!std::is_convertible<T, std::string>::value && !std::is_constructible<std::string, T>::value &&
2039 !is_ostreamable<T>::value && is_tuple_like<T>::value && type_count_base<T>::value == 1,
2040 detail::enabler> = detail::dummy>
2041inline std::string to_string(T &&value);
2044template <
typename T,
2045 enable_if_t<!std::is_convertible<T, std::string>::value && !std::is_constructible<std::string, T>::value &&
2046 !is_ostreamable<T>::value && is_tuple_like<T>::value && type_count_base<T>::value >= 2,
2047 detail::enabler> = detail::dummy>
2048inline std::string to_string(T &&value);
2053 enable_if_t<!std::is_convertible<T, std::string>::value && !std::is_constructible<std::string, T>::value &&
2055 !is_tuple_like<T>::value,
2056 detail::enabler> = detail::dummy>
2057inline std::string to_string(T &&) {
2062template <
typename T,
2063 enable_if_t<!std::is_convertible<T, std::string>::value && !std::is_constructible<std::string, T>::value &&
2065 detail::enabler> = detail::dummy>
2066inline std::string to_string(T &&variable) {
2067 auto cval = variable.begin();
2068 auto end = variable.end();
2072 std::vector<std::string> defaults;
2073 while(cval != end) {
2074 defaults.emplace_back(CLI::detail::to_string(*cval));
2077 return {
"[" + detail::join(defaults) +
"]"};
2083template <
typename T, std::
size_t I>
2084inline typename std::enable_if<I == type_count_base<T>::value, std::string>::type tuple_value_string(T && );
2087template <
typename T, std::
size_t I>
2088inline typename std::enable_if<(I < type_count_base<T>::value), std::string>::type tuple_value_string(T &&value);
2091template <
typename T,
2092 enable_if_t<!std::is_convertible<T, std::string>::value && !std::is_constructible<std::string, T>::value &&
2093 !is_ostreamable<T>::value && is_tuple_like<T>::value && type_count_base<T>::value == 1,
2095inline std::string to_string(T &&value) {
2096 return to_string(std::get<0>(value));
2100template <
typename T,
2101 enable_if_t<!std::is_convertible<T, std::string>::value && !std::is_constructible<std::string, T>::value &&
2102 !is_ostreamable<T>::value && is_tuple_like<T>::value && type_count_base<T>::value >= 2,
2104inline std::string to_string(T &&value) {
2105 auto tname = std::string(1,
'[') + tuple_value_string<T, 0>(value);
2106 tname.push_back(
']');
2111template <
typename T, std::
size_t I>
2112inline typename std::enable_if<I == type_count_base<T>::value, std::string>::type tuple_value_string(T && ) {
2113 return std::string{};
2117template <
typename T, std::
size_t I>
2118inline typename std::enable_if<(I < type_count_base<T>::value), std::string>::type tuple_value_string(T &&value) {
2119 auto str = std::string{to_string(std::get<I>(value))} +
',' + tuple_value_string<T, I + 1>(value);
2120 if(str.back() ==
',')
2126template <
typename T1,
2129 enable_if_t<std::is_same<T1, T2>::value, detail::enabler> = detail::dummy>
2130auto checked_to_string(T &&value) ->
decltype(to_string(std::forward<T>(value))) {
2131 return to_string(std::forward<T>(value));
2135template <
typename T1,
2138 enable_if_t<!std::is_same<T1, T2>::value, detail::enabler> = detail::dummy>
2139std::string checked_to_string(T &&) {
2140 return std::string{};
2143template <typename T, enable_if_t<std::is_arithmetic<T>::value, detail::enabler> = detail::dummy>
2144std::string value_string(
const T &value) {
2145 return std::to_string(value);
2148template <typename T, enable_if_t<std::is_enum<T>::value, detail::enabler> = detail::dummy>
2149std::string value_string(
const T &value) {
2150 return std::to_string(
static_cast<typename std::underlying_type<T>::type
>(value));
2153template <
typename T,
2154 enable_if_t<!std::is_enum<T>::value && !std::is_arithmetic<T>::value, detail::enabler> = detail::dummy>
2155auto value_string(
const T &value) ->
decltype(to_string(value)) {
2156 return to_string(value);
2160template <
typename T,
typename def,
typename Enable =
void>
struct wrapped_type {
2165template <
typename T,
typename def>
struct wrapped_type<T, def, typename std::enable_if<is_wrapper<T>::value>::type> {
2166 using type =
typename T::value_type;
2179 static const int value{0};
2183template <
typename T>
2185 typename std::enable_if<!is_wrapper<T>::value && !is_tuple_like<T>::value && !is_complex<T>::value &&
2186 !std::is_void<T>::value>::type> {
2187 static constexpr int value{1};
2191template <
typename T>
struct type_count<T, typename std::enable_if<is_complex<T>::value>::type> {
2192 static constexpr int value{2};
2196template <
typename T>
struct type_count<T, typename std::enable_if<is_mutable_container<T>::value>::type> {
2201template <
typename T>
2203 typename std::enable_if<is_wrapper<T>::value && !is_complex<T>::value && !is_tuple_like<T>::value &&
2204 !is_mutable_container<T>::value>::type> {
2205 static constexpr int value{type_count<typename T::value_type>::value};
2209template <
typename T, std::
size_t I>
2210constexpr typename std::enable_if<I == type_count_base<T>::value,
int>::type tuple_type_size() {
2215template <
typename T, std::
size_t I>
2216 constexpr typename std::enable_if < I<type_count_base<T>::value,
int>::type tuple_type_size() {
2217 return subtype_count<typename std::tuple_element<I, T>::type>::value + tuple_type_size<T, I + 1>();
2221template <
typename T>
2222struct type_count<T, typename std::enable_if<is_tuple_like<T>::value && !is_complex<T>::value>::type> {
2223 static constexpr int value{tuple_type_size<T, 0>()};
2228 static constexpr int value{is_mutable_container<T>::value ? expected_max_vector_size : type_count<T>::value};
2232template <
typename T,
typename Enable =
void>
struct type_count_min {
2233 static const int value{0};
2237template <
typename T>
2238struct type_count_min<
2240 typename std::enable_if<!is_mutable_container<T>::value && !is_tuple_like<T>::value && !is_wrapper<T>::value &&
2241 !is_complex<T>::value && !std::is_void<T>::value>::type> {
2242 static constexpr int value{type_count<T>::value};
2246template <
typename T>
struct type_count_min<T, typename std::enable_if<is_complex<T>::value>::type> {
2247 static constexpr int value{1};
2251template <
typename T>
2252struct type_count_min<
2254 typename std::enable_if<is_wrapper<T>::value && !is_complex<T>::value && !is_tuple_like<T>::value>::type> {
2255 static constexpr int value{subtype_count_min<typename T::value_type>::value};
2259template <
typename T, std::
size_t I>
2260constexpr typename std::enable_if<I == type_count_base<T>::value,
int>::type tuple_type_size_min() {
2265template <
typename T, std::
size_t I>
2266 constexpr typename std::enable_if < I<type_count_base<T>::value,
int>::type tuple_type_size_min() {
2271template <
typename T>
2272struct type_count_min<T, typename std::enable_if<is_tuple_like<T>::value && !is_complex<T>::value>::type> {
2273 static constexpr int value{tuple_type_size_min<T, 0>()};
2278 static constexpr int value{is_mutable_container<T>::value
2279 ? ((type_count<T>::value < expected_max_vector_size) ? type_count<T>::value : 0)
2280 : type_count_min<T>::value};
2284template <
typename T,
typename Enable =
void>
struct expected_count {
2285 static const int value{0};
2289template <
typename T>
2290struct expected_count<T,
2291 typename std::enable_if<!is_mutable_container<T>::value && !is_wrapper<T>::value &&
2292 !std::is_void<T>::value>::type> {
2293 static constexpr int value{1};
2296template <
typename T>
struct expected_count<T, typename std::enable_if<is_mutable_container<T>::value>::type> {
2297 static constexpr int value{expected_max_vector_size};
2301template <
typename T>
2302struct expected_count<T, typename std::enable_if<!is_mutable_container<T>::value && is_wrapper<T>::value>::type> {
2303 static constexpr int value{expected_count<typename T::value_type>::value};
2307enum class object_category : std::uint8_t {
2310 unsigned_integral = 4,
2313 floating_point = 10,
2314 number_constructible = 12,
2315 double_constructible = 14,
2316 integer_constructible = 16,
2318 string_assignable = 23,
2319 string_constructible = 24,
2320 wstring_assignable = 25,
2321 wstring_constructible = 26,
2325 complex_number = 60,
2327 container_value = 80,
2334template <
typename T,
typename Enable =
void>
struct classify_object {
2335 static constexpr object_category value{object_category::other};
2339template <
typename T>
2340struct classify_object<
2342 typename std::enable_if<std::is_integral<T>::value && !std::is_same<T, char>::value && std::is_signed<T>::value &&
2343 !is_bool<T>::value && !std::is_enum<T>::value>::type> {
2344 static constexpr object_category value{object_category::integral_value};
2348template <
typename T>
2349struct classify_object<T,
2350 typename std::enable_if<std::is_integral<T>::value && std::is_unsigned<T>::value &&
2351 !std::is_same<T, char>::value && !is_bool<T>::value>::type> {
2352 static constexpr object_category value{object_category::unsigned_integral};
2356template <
typename T>
2357struct classify_object<T, typename std::enable_if<std::is_same<T, char>::value && !std::is_enum<T>::value>::type> {
2358 static constexpr object_category value{object_category::char_value};
2362template <
typename T>
struct classify_object<T, typename std::enable_if<is_bool<T>::value>::type> {
2363 static constexpr object_category value{object_category::boolean_value};
2367template <
typename T>
struct classify_object<T, typename std::enable_if<std::is_floating_point<T>::value>::type> {
2368 static constexpr object_category value{object_category::floating_point};
2373#define WIDE_STRING_CHECK \
2374 !std::is_assignable<T &, std::wstring>::value && !std::is_constructible<T, std::wstring>::value
2375#define STRING_CHECK true
2377#define WIDE_STRING_CHECK true
2378#define STRING_CHECK !std::is_assignable<T &, std::string>::value && !std::is_constructible<T, std::string>::value
2382template <
typename T>
2383struct classify_object<
2385 typename std::enable_if<!std::is_floating_point<T>::value && !std::is_integral<T>::value && WIDE_STRING_CHECK &&
2386 std::is_assignable<T &, std::string>::value>::type> {
2387 static constexpr object_category value{object_category::string_assignable};
2391template <
typename T>
2392struct classify_object<
2394 typename std::enable_if<!std::is_floating_point<T>::value && !std::is_integral<T>::value &&
2395 !std::is_assignable<T &, std::string>::value && (type_count<T>::value == 1) &&
2396 WIDE_STRING_CHECK && std::is_constructible<T, std::string>::value>::type> {
2397 static constexpr object_category value{object_category::string_constructible};
2401template <
typename T>
2402struct classify_object<T,
2403 typename std::enable_if<!std::is_floating_point<T>::value && !std::is_integral<T>::value &&
2404 STRING_CHECK && std::is_assignable<T &, std::wstring>::value>::type> {
2405 static constexpr object_category value{object_category::wstring_assignable};
2408template <
typename T>
2409struct classify_object<
2411 typename std::enable_if<!std::is_floating_point<T>::value && !std::is_integral<T>::value &&
2412 !std::is_assignable<T &, std::wstring>::value && (type_count<T>::value == 1) &&
2413 STRING_CHECK && std::is_constructible<T, std::wstring>::value>::type> {
2414 static constexpr object_category value{object_category::wstring_constructible};
2418template <
typename T>
struct classify_object<T, typename std::enable_if<std::is_enum<T>::value>::type> {
2419 static constexpr object_category value{object_category::enumeration};
2422template <
typename T>
struct classify_object<T, typename std::enable_if<is_complex<T>::value>::type> {
2423 static constexpr object_category value{object_category::complex_number};
2428template <
typename T>
struct uncommon_type {
2429 using type =
typename std::conditional<
2430 !std::is_floating_point<T>::value && !std::is_integral<T>::value &&
2431 !std::is_assignable<T &, std::string>::value && !std::is_constructible<T, std::string>::value &&
2432 !std::is_assignable<T &, std::wstring>::value && !std::is_constructible<T, std::wstring>::value &&
2433 !is_complex<T>::value && !is_mutable_container<T>::value && !std::is_enum<T>::value,
2435 std::false_type>::type;
2436 static constexpr bool value = type::value;
2440template <
typename T>
2441struct classify_object<T,
2442 typename std::enable_if<(!is_mutable_container<T>::value && is_wrapper<T>::value &&
2443 !is_tuple_like<T>::value && uncommon_type<T>::value)>::type> {
2444 static constexpr object_category value{object_category::wrapper_value};
2448template <
typename T>
2449struct classify_object<T,
2450 typename std::enable_if<uncommon_type<T>::value && type_count<T>::value == 1 &&
2451 !is_wrapper<T>::value && is_direct_constructible<T, double>::value &&
2452 is_direct_constructible<T, int>::value>::type> {
2453 static constexpr object_category value{object_category::number_constructible};
2457template <
typename T>
2458struct classify_object<T,
2459 typename std::enable_if<uncommon_type<T>::value && type_count<T>::value == 1 &&
2460 !is_wrapper<T>::value && !is_direct_constructible<T, double>::value &&
2461 is_direct_constructible<T, int>::value>::type> {
2462 static constexpr object_category value{object_category::integer_constructible};
2466template <
typename T>
2467struct classify_object<T,
2468 typename std::enable_if<uncommon_type<T>::value && type_count<T>::value == 1 &&
2469 !is_wrapper<T>::value && is_direct_constructible<T, double>::value &&
2470 !is_direct_constructible<T, int>::value>::type> {
2471 static constexpr object_category value{object_category::double_constructible};
2475template <
typename T>
2476struct classify_object<
2478 typename std::enable_if<is_tuple_like<T>::value &&
2479 ((type_count<T>::value >= 2 && !is_wrapper<T>::value) ||
2480 (uncommon_type<T>::value && !is_direct_constructible<T, double>::value &&
2481 !is_direct_constructible<T, int>::value) ||
2482 (uncommon_type<T>::value && type_count<T>::value >= 2))>::type> {
2483 static constexpr object_category value{object_category::tuple_value};
2492template <
typename T>
struct classify_object<T, typename std::enable_if<is_mutable_container<T>::value>::type> {
2493 static constexpr object_category value{object_category::container_value};
2502template <
typename T,
2503 enable_if_t<classify_object<T>::value == object_category::char_value, detail::enabler> = detail::dummy>
2504constexpr const char *type_name() {
2508template <
typename T,
2509 enable_if_t<classify_object<T>::value == object_category::integral_value ||
2510 classify_object<T>::value == object_category::integer_constructible,
2511 detail::enabler> = detail::dummy>
2512constexpr const char *type_name() {
2516template <
typename T,
2517 enable_if_t<classify_object<T>::value == object_category::unsigned_integral, detail::enabler> = detail::dummy>
2518constexpr const char *type_name() {
2522template <
typename T,
2523 enable_if_t<classify_object<T>::value == object_category::floating_point ||
2524 classify_object<T>::value == object_category::number_constructible ||
2525 classify_object<T>::value == object_category::double_constructible,
2526 detail::enabler> = detail::dummy>
2527constexpr const char *type_name() {
2532template <
typename T,
2533 enable_if_t<classify_object<T>::value == object_category::enumeration, detail::enabler> = detail::dummy>
2534constexpr const char *type_name() {
2539template <
typename T,
2540 enable_if_t<classify_object<T>::value == object_category::boolean_value, detail::enabler> = detail::dummy>
2541constexpr const char *type_name() {
2546template <
typename T,
2547 enable_if_t<classify_object<T>::value == object_category::complex_number, detail::enabler> = detail::dummy>
2548constexpr const char *type_name() {
2553template <
typename T,
2554 enable_if_t<classify_object<T>::value >= object_category::string_assignable &&
2555 classify_object<T>::value <= object_category::other,
2556 detail::enabler> = detail::dummy>
2557constexpr const char *type_name() {
2561template <
typename T,
2562 enable_if_t<classify_object<T>::value == object_category::tuple_value && type_count_base<T>::value >= 2,
2563 detail::enabler> = detail::dummy>
2564std::string type_name();
2567template <
typename T,
2568 enable_if_t<classify_object<T>::value == object_category::container_value ||
2569 classify_object<T>::value == object_category::wrapper_value,
2570 detail::enabler> = detail::dummy>
2571std::string type_name();
2574template <
typename T,
2575 enable_if_t<classify_object<T>::value == object_category::tuple_value && type_count_base<T>::value == 1,
2576 detail::enabler> = detail::dummy>
2577inline std::string type_name() {
2578 return type_name<typename std::decay<typename std::tuple_element<0, T>::type>::type>();
2582template <
typename T, std::
size_t I>
2583inline typename std::enable_if<I == type_count_base<T>::value, std::string>::type tuple_name() {
2584 return std::string{};
2588template <
typename T, std::
size_t I>
2589inline typename std::enable_if<(I < type_count_base<T>::value), std::string>::type tuple_name() {
2590 auto str = std::string{type_name<typename std::decay<typename std::tuple_element<I, T>::type>::type>()} +
',' +
2591 tuple_name<T, I + 1>();
2592 if(str.back() ==
',')
2598template <
typename T,
2599 enable_if_t<classify_object<T>::value == object_category::tuple_value && type_count_base<T>::value >= 2,
2601inline std::string type_name() {
2602 auto tname = std::string(1,
'[') + tuple_name<T, 0>();
2603 tname.push_back(
']');
2608template <
typename T,
2609 enable_if_t<classify_object<T>::value == object_category::container_value ||
2610 classify_object<T>::value == object_category::wrapper_value,
2612inline std::string type_name() {
2613 return type_name<typename T::value_type>();
2619template <typename T, enable_if_t<std::is_unsigned<T>::value, detail::enabler> = detail::dummy>
2620bool integral_conversion(
const std::string &input, T &output)
noexcept {
2621 if(input.empty() || input.front() ==
'-') {
2626 std::uint64_t output_ll = std::strtoull(input.c_str(), &val, 0);
2627 if(errno == ERANGE) {
2630 output =
static_cast<T
>(output_ll);
2631 if(val == (input.c_str() + input.size()) &&
static_cast<std::uint64_t
>(output) == output_ll) {
2635 std::int64_t output_sll = std::strtoll(input.c_str(), &val, 0);
2636 if(val == (input.c_str() + input.size())) {
2637 output = (output_sll < 0) ? static_cast<T>(0) : static_cast<T>(output_sll);
2638 return (
static_cast<std::int64_t
>(output) == output_sll);
2641 auto group_separators = get_group_separators();
2642 if(input.find_first_of(group_separators) != std::string::npos) {
2643 std::string nstring = input;
2644 for(
auto &separator : group_separators) {
2645 if(input.find_first_of(separator) != std::string::npos) {
2646 nstring.erase(std::remove(nstring.begin(), nstring.end(), separator), nstring.end());
2649 return integral_conversion(nstring, output);
2652 if(std::isspace(
static_cast<unsigned char>(input.back()))) {
2653 return integral_conversion(trim_copy(input), output);
2655 if(input.compare(0, 2,
"0o") == 0 || input.compare(0, 2,
"0O") == 0) {
2658 output_ll = std::strtoull(input.c_str() + 2, &val, 8);
2659 if(errno == ERANGE) {
2662 output =
static_cast<T
>(output_ll);
2663 return (val == (input.c_str() + input.size()) &&
static_cast<std::uint64_t
>(output) == output_ll);
2665 if(input.compare(0, 2,
"0b") == 0 || input.compare(0, 2,
"0B") == 0) {
2671 output_ll = std::strtoull(input.c_str() + 2, &val, 2);
2672 if(errno == ERANGE) {
2675 output =
static_cast<T
>(output_ll);
2676 return (val == (input.c_str() + input.size()) &&
static_cast<std::uint64_t
>(output) == output_ll);
2683template <typename T, enable_if_t<std::is_signed<T>::value, detail::enabler> = detail::dummy>
2684bool integral_conversion(
const std::string &input, T &output)
noexcept {
2688 char *val =
nullptr;
2690 std::int64_t output_ll = std::strtoll(input.c_str(), &val, 0);
2691 if(errno == ERANGE) {
2694 output =
static_cast<T
>(output_ll);
2695 if(val == (input.c_str() + input.size()) &&
static_cast<std::int64_t
>(output) == output_ll) {
2698 if(input ==
"true") {
2700 output =
static_cast<T
>(1);
2704 auto group_separators = get_group_separators();
2705 if(input.find_first_of(group_separators) != std::string::npos) {
2706 for(
auto &separator : group_separators) {
2707 if(input.find_first_of(separator) != std::string::npos) {
2708 std::string nstring = input;
2709 nstring.erase(std::remove(nstring.begin(), nstring.end(), separator), nstring.end());
2710 return integral_conversion(nstring, output);
2714 if(std::isspace(
static_cast<unsigned char>(input.back()))) {
2715 return integral_conversion(trim_copy(input), output);
2717 if(input.compare(0, 2,
"0o") == 0 || input.compare(0, 2,
"0O") == 0) {
2720 output_ll = std::strtoll(input.c_str() + 2, &val, 8);
2721 if(errno == ERANGE) {
2724 output =
static_cast<T
>(output_ll);
2725 return (val == (input.c_str() + input.size()) &&
static_cast<std::int64_t
>(output) == output_ll);
2727 if(input.compare(0, 2,
"0b") == 0 || input.compare(0, 2,
"0B") == 0) {
2733 output_ll = std::strtoll(input.c_str() + 2, &val, 2);
2734 if(errno == ERANGE) {
2737 output =
static_cast<T
>(output_ll);
2738 return (val == (input.c_str() + input.size()) &&
static_cast<std::int64_t
>(output) == output_ll);
2745inline std::int64_t to_flag_value(std::string val)
noexcept {
2746 static const std::string trueString(
"true");
2747 static const std::string falseString(
"false");
2748 if(val == trueString) {
2751 if(val == falseString) {
2754 val = detail::to_lower(val);
2755 std::int64_t ret = 0;
2756 if(val.size() == 1) {
2757 if(val[0] >=
'1' && val[0] <=
'9') {
2758 return (
static_cast<std::int64_t
>(val[0]) -
'0');
2778 if(val == trueString || val ==
"on" || val ==
"yes" || val ==
"enable") {
2780 }
else if(val == falseString || val ==
"off" || val ==
"no" || val ==
"disable") {
2783 char *loc_ptr{
nullptr};
2784 ret = std::strtoll(val.c_str(), &loc_ptr, 0);
2785 if(loc_ptr != (val.c_str() + val.size()) && errno == 0) {
2793template <
typename T,
2794 enable_if_t<classify_object<T>::value == object_category::integral_value ||
2795 classify_object<T>::value == object_category::unsigned_integral,
2796 detail::enabler> = detail::dummy>
2797bool lexical_cast(
const std::string &input, T &output) {
2798 return integral_conversion(input, output);
2802template <
typename T,
2803 enable_if_t<classify_object<T>::value == object_category::char_value, detail::enabler> = detail::dummy>
2804bool lexical_cast(
const std::string &input, T &output) {
2805 if(input.size() == 1) {
2806 output =
static_cast<T
>(input[0]);
2812 bool result = integral_conversion(input, res);
2814 output =
static_cast<T
>(res);
2820template <
typename T,
2821 enable_if_t<classify_object<T>::value == object_category::boolean_value, detail::enabler> = detail::dummy>
2822bool lexical_cast(
const std::string &input, T &output) {
2824 auto out = to_flag_value(input);
2827 }
else if(errno == ERANGE) {
2828 output = (input[0] !=
'-');
2836template <
typename T,
2837 enable_if_t<classify_object<T>::value == object_category::floating_point, detail::enabler> = detail::dummy>
2838bool lexical_cast(
const std::string &input, T &output) {
2842 char *val =
nullptr;
2843 auto output_ld = std::strtold(input.c_str(), &val);
2844 output =
static_cast<T
>(output_ld);
2845 if(val == (input.c_str() + input.size())) {
2848 while(std::isspace(
static_cast<unsigned char>(*val))) {
2850 if(val == (input.c_str() + input.size())) {
2856 auto group_separators = get_group_separators();
2857 if(input.find_first_of(group_separators) != std::string::npos) {
2858 for(
auto &separator : group_separators) {
2859 if(input.find_first_of(separator) != std::string::npos) {
2860 std::string nstring = input;
2861 nstring.erase(std::remove(nstring.begin(), nstring.end(), separator), nstring.end());
2862 return lexical_cast(nstring, output);
2870template <
typename T,
2871 enable_if_t<classify_object<T>::value == object_category::complex_number, detail::enabler> = detail::dummy>
2872bool lexical_cast(
const std::string &input, T &output) {
2873 using XC =
typename wrapped_type<T, double>::type;
2876 bool worked =
false;
2877 auto nloc = str1.find_last_of(
"+-");
2878 if(nloc != std::string::npos && nloc > 0) {
2879 worked = lexical_cast(str1.substr(0, nloc), x);
2880 str1 = str1.substr(nloc);
2881 if(str1.back() ==
'i' || str1.back() ==
'j')
2883 worked = worked && lexical_cast(str1, y);
2885 if(str1.back() ==
'i' || str1.back() ==
'j') {
2887 worked = lexical_cast(str1, y);
2890 worked = lexical_cast(str1, x);
2898 return from_stream(input, output);
2902template <
typename T,
2903 enable_if_t<classify_object<T>::value == object_category::string_assignable, detail::enabler> = detail::dummy>
2904bool lexical_cast(
const std::string &input, T &output) {
2912 enable_if_t<classify_object<T>::value == object_category::string_constructible, detail::enabler> = detail::dummy>
2913bool lexical_cast(
const std::string &input, T &output) {
2921 enable_if_t<classify_object<T>::value == object_category::wstring_assignable, detail::enabler> = detail::dummy>
2922bool lexical_cast(
const std::string &input, T &output) {
2923 output = widen(input);
2929 enable_if_t<classify_object<T>::value == object_category::wstring_constructible, detail::enabler> = detail::dummy>
2930bool lexical_cast(
const std::string &input, T &output) {
2931 output = T{widen(input)};
2936template <
typename T,
2937 enable_if_t<classify_object<T>::value == object_category::enumeration, detail::enabler> = detail::dummy>
2938bool lexical_cast(
const std::string &input, T &output) {
2939 typename std::underlying_type<T>::type val;
2940 if(!integral_conversion(input, val)) {
2943 output =
static_cast<T
>(val);
2948template <
typename T,
2949 enable_if_t<classify_object<T>::value == object_category::wrapper_value &&
2950 std::is_assignable<T &, typename T::value_type>::value,
2951 detail::enabler> = detail::dummy>
2952bool lexical_cast(
const std::string &input, T &output) {
2953 typename T::value_type val;
2954 if(lexical_cast(input, val)) {
2958 return from_stream(input, output);
2961template <
typename T,
2962 enable_if_t<classify_object<T>::value == object_category::wrapper_value &&
2963 !std::is_assignable<T &, typename T::value_type>::value && std::is_assignable<T &, T>::value,
2964 detail::enabler> = detail::dummy>
2965bool lexical_cast(
const std::string &input, T &output) {
2966 typename T::value_type val;
2967 if(lexical_cast(input, val)) {
2971 return from_stream(input, output);
2977 enable_if_t<classify_object<T>::value == object_category::number_constructible, detail::enabler> = detail::dummy>
2978bool lexical_cast(
const std::string &input, T &output) {
2980 if(integral_conversion(input, val)) {
2986 if(lexical_cast(input, dval)) {
2991 return from_stream(input, output);
2997 enable_if_t<classify_object<T>::value == object_category::integer_constructible, detail::enabler> = detail::dummy>
2998bool lexical_cast(
const std::string &input, T &output) {
3000 if(integral_conversion(input, val)) {
3004 return from_stream(input, output);
3010 enable_if_t<classify_object<T>::value == object_category::double_constructible, detail::enabler> = detail::dummy>
3011bool lexical_cast(
const std::string &input, T &output) {
3013 if(lexical_cast(input, val)) {
3017 return from_stream(input, output);
3021template <
typename T,
3022 enable_if_t<classify_object<T>::value == object_category::other && std::is_assignable<T &, int>::value,
3023 detail::enabler> = detail::dummy>
3024bool lexical_cast(
const std::string &input, T &output) {
3026 if(integral_conversion(input, val)) {
3028#pragma warning(push)
3029#pragma warning(disable : 4800)
3042 return from_stream(input, output);
3047template <
typename T,
3048 enable_if_t<classify_object<T>::value == object_category::other && !std::is_assignable<T &, int>::value &&
3049 is_istreamable<T>::value,
3050 detail::enabler> = detail::dummy>
3051bool lexical_cast(
const std::string &input, T &output) {
3052 return from_stream(input, output);
3057template <
typename T,
3058 enable_if_t<classify_object<T>::value == object_category::other && !std::is_assignable<T &, int>::value &&
3059 !is_istreamable<T>::value && !adl_detail::is_lexical_castable<T>::value,
3060 detail::enabler> = detail::dummy>
3061bool lexical_cast(
const std::string & , T & ) {
3062 static_assert(!std::is_same<T, T>::value,
3063 "option object type must have a lexical cast overload or streaming input operator(>>) defined, if it "
3064 "is convertible from another type use the add_option<T, XC>(...) with XC being the known type");
3070template <
typename AssignTo,
3072 enable_if_t<std::is_same<AssignTo, ConvertTo>::value &&
3073 (classify_object<AssignTo>::value == object_category::string_assignable ||
3074 classify_object<AssignTo>::value == object_category::string_constructible ||
3075 classify_object<AssignTo>::value == object_category::wstring_assignable ||
3076 classify_object<AssignTo>::value == object_category::wstring_constructible),
3077 detail::enabler> = detail::dummy>
3078bool lexical_assign(
const std::string &input, AssignTo &output) {
3079 return lexical_cast(input, output);
3083template <
typename AssignTo,
3085 enable_if_t<std::is_same<AssignTo, ConvertTo>::value && std::is_assignable<AssignTo &, AssignTo>::value &&
3086 classify_object<AssignTo>::value != object_category::string_assignable &&
3087 classify_object<AssignTo>::value != object_category::string_constructible &&
3088 classify_object<AssignTo>::value != object_category::wstring_assignable &&
3089 classify_object<AssignTo>::value != object_category::wstring_constructible,
3090 detail::enabler> = detail::dummy>
3091bool lexical_assign(
const std::string &input, AssignTo &output) {
3093 output = AssignTo{};
3097 return lexical_cast(input, output);
3101template <
typename AssignTo,
3103 enable_if_t<std::is_same<AssignTo, ConvertTo>::value && !std::is_assignable<AssignTo &, AssignTo>::value &&
3104 classify_object<AssignTo>::value == object_category::wrapper_value,
3105 detail::enabler> = detail::dummy>
3106bool lexical_assign(
const std::string &input, AssignTo &output) {
3108 typename AssignTo::value_type emptyVal{};
3112 return lexical_cast(input, output);
3117template <
typename AssignTo,
3119 enable_if_t<std::is_same<AssignTo, ConvertTo>::value && !std::is_assignable<AssignTo &, AssignTo>::value &&
3120 classify_object<AssignTo>::value != object_category::wrapper_value &&
3121 std::is_assignable<AssignTo &, int>::value,
3122 detail::enabler> = detail::dummy>
3123bool lexical_assign(
const std::string &input, AssignTo &output) {
3129 if(lexical_cast(input, val)) {
3130#if defined(__clang__)
3132#pragma clang diagnostic push
3133#pragma clang diagnostic ignored "-Wsign-conversion"
3136#if defined(__clang__)
3137#pragma clang diagnostic pop
3145template <
typename AssignTo,
3147 enable_if_t<!std::is_same<AssignTo, ConvertTo>::value && std::is_assignable<AssignTo &, ConvertTo &>::value,
3148 detail::enabler> = detail::dummy>
3149bool lexical_assign(
const std::string &input, AssignTo &output) {
3151 bool parse_result = (!input.empty()) ? lexical_cast(input, val) : true;
3155 return parse_result;
3162 enable_if_t<!std::is_same<AssignTo, ConvertTo>::value && !std::is_assignable<AssignTo &, ConvertTo &>::value &&
3163 std::is_move_assignable<AssignTo>::value,
3164 detail::enabler> = detail::dummy>
3165bool lexical_assign(
const std::string &input, AssignTo &output) {
3167 bool parse_result = input.empty() ? true : lexical_cast(input, val);
3169 output = AssignTo(val);
3171 return parse_result;
3175template <
typename AssignTo,
3177 enable_if_t<classify_object<ConvertTo>::value <= object_category::other &&
3178 classify_object<AssignTo>::value <= object_category::wrapper_value,
3179 detail::enabler> = detail::dummy>
3180bool lexical_conversion(
const std::vector<std ::string> &strings, AssignTo &output) {
3181 return lexical_assign<AssignTo, ConvertTo>(strings[0], output);
3186template <
typename AssignTo,
3188 enable_if_t<(type_count<AssignTo>::value <= 2) && expected_count<AssignTo>::value == 1 &&
3189 is_tuple_like<ConvertTo>::value && type_count_base<ConvertTo>::value == 2,
3190 detail::enabler> = detail::dummy>
3191bool lexical_conversion(
const std::vector<std ::string> &strings, AssignTo &output) {
3193 using FirstType =
typename std::remove_const<typename std::tuple_element<0, ConvertTo>::type>::type;
3194 using SecondType =
typename std::tuple_element<1, ConvertTo>::type;
3197 bool retval = lexical_assign<FirstType, FirstType>(strings[0], v1);
3198 retval = retval && lexical_assign<SecondType, SecondType>((strings.size() > 1) ? strings[1] : std::string{}, v2);
3200 output = AssignTo{v1, v2};
3206template <
class AssignTo,
3208 enable_if_t<is_mutable_container<AssignTo>::value && is_mutable_container<ConvertTo>::value &&
3209 type_count<ConvertTo>::value == 1,
3210 detail::enabler> = detail::dummy>
3211bool lexical_conversion(
const std::vector<std ::string> &strings, AssignTo &output) {
3212 output.erase(output.begin(), output.end());
3213 if(strings.empty()) {
3216 if(strings.size() == 1 && strings[0] ==
"{}") {
3219 bool skip_remaining =
false;
3220 if(strings.size() == 2 && strings[0] ==
"{}" && is_separator(strings[1])) {
3221 skip_remaining =
true;
3223 for(
const auto &elem : strings) {
3224 typename AssignTo::value_type out;
3225 bool retval = lexical_assign<typename AssignTo::value_type, typename ConvertTo::value_type>(elem, out);
3229 output.insert(output.end(), std::move(out));
3230 if(skip_remaining) {
3234 return (!output.empty());
3238template <class AssignTo, class ConvertTo, enable_if_t<is_complex<ConvertTo>::value, detail::enabler> = detail::dummy>
3239bool lexical_conversion(
const std::vector<std::string> &strings, AssignTo &output) {
3241 if(strings.size() >= 2 && !strings[1].empty()) {
3242 using XC2 =
typename wrapped_type<ConvertTo, double>::type;
3244 auto str1 = strings[1];
3245 if(str1.back() ==
'i' || str1.back() ==
'j') {
3248 auto worked = lexical_cast(strings[0], x) && lexical_cast(str1, y);
3250 output = ConvertTo{x, y};
3254 return lexical_assign<AssignTo, ConvertTo>(strings[0], output);
3258template <
class AssignTo,
3260 enable_if_t<is_mutable_container<AssignTo>::value && (expected_count<ConvertTo>::value == 1) &&
3261 (type_count<ConvertTo>::value == 1),
3262 detail::enabler> = detail::dummy>
3263bool lexical_conversion(
const std::vector<std ::string> &strings, AssignTo &output) {
3266 output.reserve(strings.size());
3267 for(
const auto &elem : strings) {
3269 output.emplace_back();
3270 retval = retval && lexical_assign<typename AssignTo::value_type, ConvertTo>(elem, output.back());
3272 return (!output.empty()) && retval;
3278template <
class AssignTo,
3280 enable_if_t<is_mutable_container<AssignTo>::value && is_mutable_container<ConvertTo>::value &&
3281 type_count_base<ConvertTo>::value == 2,
3282 detail::enabler> = detail::dummy>
3283bool lexical_conversion(std::vector<std::string> strings, AssignTo &output);
3286template <
class AssignTo,
3288 enable_if_t<is_mutable_container<AssignTo>::value && is_mutable_container<ConvertTo>::value &&
3289 type_count_base<ConvertTo>::value != 2 &&
3290 ((type_count<ConvertTo>::value > 2) ||
3291 (type_count<ConvertTo>::value > type_count_base<ConvertTo>::value)),
3292 detail::enabler> = detail::dummy>
3293bool lexical_conversion(
const std::vector<std::string> &strings, AssignTo &output);
3296template <
class AssignTo,
3298 enable_if_t<is_tuple_like<AssignTo>::value && is_tuple_like<ConvertTo>::value &&
3299 (type_count_base<ConvertTo>::value != type_count<ConvertTo>::value ||
3300 type_count<ConvertTo>::value > 2),
3301 detail::enabler> = detail::dummy>
3302bool lexical_conversion(
const std::vector<std::string> &strings, AssignTo &output);
3306template <
typename AssignTo,
3308 enable_if_t<!is_tuple_like<AssignTo>::value && !is_mutable_container<AssignTo>::value &&
3309 classify_object<ConvertTo>::value != object_category::wrapper_value &&
3310 (is_mutable_container<ConvertTo>::value || type_count<ConvertTo>::value > 2),
3311 detail::enabler> = detail::dummy>
3312bool lexical_conversion(
const std::vector<std ::string> &strings, AssignTo &output) {
3314 if(strings.size() > 1 || (!strings.empty() && !(strings.front().empty()))) {
3316 auto retval = lexical_conversion<ConvertTo, ConvertTo>(strings, val);
3317 output = AssignTo{val};
3320 output = AssignTo{};
3325template <
class AssignTo,
class ConvertTo, std::
size_t I>
3326inline typename std::enable_if<(I >= type_count_base<AssignTo>::value),
bool>::type
3327tuple_conversion(
const std::vector<std::string> &, AssignTo &) {
3332template <
class AssignTo,
class ConvertTo>
3333inline typename std::enable_if<!is_mutable_container<ConvertTo>::value && type_count<ConvertTo>::value == 1,
bool>::type
3334tuple_type_conversion(std::vector<std::string> &strings, AssignTo &output) {
3335 auto retval = lexical_assign<AssignTo, ConvertTo>(strings[0], output);
3336 strings.erase(strings.begin());
3341template <
class AssignTo,
class ConvertTo>
3342inline typename std::enable_if<!is_mutable_container<ConvertTo>::value && (type_count<ConvertTo>::value > 1) &&
3343 type_count<ConvertTo>::value == type_count_min<ConvertTo>::value,
3345tuple_type_conversion(std::vector<std::string> &strings, AssignTo &output) {
3346 auto retval = lexical_conversion<AssignTo, ConvertTo>(strings, output);
3347 strings.erase(strings.begin(), strings.begin() + type_count<ConvertTo>::value);
3352template <
class AssignTo,
class ConvertTo>
3353inline typename std::enable_if<is_mutable_container<ConvertTo>::value ||
3354 type_count<ConvertTo>::value != type_count_min<ConvertTo>::value,
3356tuple_type_conversion(std::vector<std::string> &strings, AssignTo &output) {
3358 std::size_t index{subtype_count_min<ConvertTo>::value};
3359 const std::size_t mx_count{subtype_count<ConvertTo>::value};
3360 const std::size_t mx{(std::min)(mx_count, strings.size() - 1)};
3363 if(is_separator(strings[index])) {
3368 bool retval = lexical_conversion<AssignTo, ConvertTo>(
3369 std::vector<std::string>(strings.begin(), strings.begin() +
static_cast<std::ptrdiff_t
>(index)), output);
3370 if(strings.size() > index) {
3371 strings.erase(strings.begin(), strings.begin() +
static_cast<std::ptrdiff_t
>(index) + 1);
3379template <
class AssignTo,
class ConvertTo, std::
size_t I>
3380inline typename std::enable_if<(I < type_count_base<AssignTo>::value),
bool>::type
3381tuple_conversion(std::vector<std::string> strings, AssignTo &output) {
3383 using ConvertToElement =
typename std::
3384 conditional<is_tuple_like<ConvertTo>::value,
typename std::tuple_element<I, ConvertTo>::type, ConvertTo>::type;
3385 if(!strings.empty()) {
3386 retval = retval && tuple_type_conversion<typename std::tuple_element<I, AssignTo>::type, ConvertToElement>(
3387 strings, std::get<I>(output));
3389 retval = retval && tuple_conversion<AssignTo, ConvertTo, I + 1>(std::move(strings), output);
3394template <
class AssignTo,
3396 enable_if_t<is_mutable_container<AssignTo>::value && is_mutable_container<ConvertTo>::value &&
3397 type_count_base<ConvertTo>::value == 2,
3399bool lexical_conversion(std::vector<std::string> strings, AssignTo &output) {
3401 while(!strings.empty()) {
3403 typename std::remove_const<typename std::tuple_element<0, typename ConvertTo::value_type>::type>::type v1;
3404 typename std::tuple_element<1, typename ConvertTo::value_type>::type v2;
3405 bool retval = tuple_type_conversion<decltype(v1), decltype(v1)>(strings, v1);
3406 if(!strings.empty()) {
3407 retval = retval && tuple_type_conversion<decltype(v2), decltype(v2)>(strings, v2);
3410 output.insert(output.end(),
typename AssignTo::value_type{v1, v2});
3415 return (!output.empty());
3419template <
class AssignTo,
3421 enable_if_t<is_tuple_like<AssignTo>::value && is_tuple_like<ConvertTo>::value &&
3422 (type_count_base<ConvertTo>::value != type_count<ConvertTo>::value ||
3423 type_count<ConvertTo>::value > 2),
3425bool lexical_conversion(
const std::vector<std ::string> &strings, AssignTo &output) {
3427 !is_tuple_like<ConvertTo>::value || type_count_base<AssignTo>::value == type_count_base<ConvertTo>::value,
3428 "if the conversion type is defined as a tuple it must be the same size as the type you are converting to");
3429 return tuple_conversion<AssignTo, ConvertTo, 0>(strings, output);
3433template <
class AssignTo,
3435 enable_if_t<is_mutable_container<AssignTo>::value && is_mutable_container<ConvertTo>::value &&
3436 type_count_base<ConvertTo>::value != 2 &&
3437 ((type_count<ConvertTo>::value > 2) ||
3438 (type_count<ConvertTo>::value > type_count_base<ConvertTo>::value)),
3440bool lexical_conversion(
const std::vector<std ::string> &strings, AssignTo &output) {
3443 std::vector<std::string> temp;
3445 std::size_t icount{0};
3446 std::size_t xcm{type_count<ConvertTo>::value};
3447 auto ii_max = strings.size();
3448 while(ii < ii_max) {
3449 temp.push_back(strings[ii]);
3452 if(icount == xcm || is_separator(temp.back()) || ii == ii_max) {
3453 if(
static_cast<int>(xcm) > type_count_min<ConvertTo>::value && is_separator(temp.back())) {
3456 typename AssignTo::value_type temp_out;
3458 lexical_conversion<typename AssignTo::value_type, typename ConvertTo::value_type>(temp, temp_out);
3463 output.insert(output.end(), std::move(temp_out));
3471template <
typename AssignTo,
3473 enable_if_t<classify_object<ConvertTo>::value == object_category::wrapper_value &&
3474 std::is_assignable<ConvertTo &, ConvertTo>::value,
3475 detail::enabler> = detail::dummy>
3476bool lexical_conversion(
const std::vector<std::string> &strings, AssignTo &output) {
3477 if(strings.empty() || strings.front().empty()) {
3478 output = ConvertTo{};
3481 typename ConvertTo::value_type val;
3482 if(lexical_conversion<typename ConvertTo::value_type, typename ConvertTo::value_type>(strings, val)) {
3483 output = ConvertTo{val};
3490template <
typename AssignTo,
3492 enable_if_t<classify_object<ConvertTo>::value == object_category::wrapper_value &&
3493 !std::is_assignable<AssignTo &, ConvertTo>::value,
3494 detail::enabler> = detail::dummy>
3495bool lexical_conversion(
const std::vector<std::string> &strings, AssignTo &output) {
3496 using ConvertType =
typename ConvertTo::value_type;
3497 if(strings.empty() || strings.front().empty()) {
3498 output = ConvertType{};
3502 if(lexical_conversion<typename ConvertTo::value_type, typename ConvertTo::value_type>(strings, val)) {
3510inline std::string sum_string_vector(
const std::vector<std::string> &values) {
3514 for(
const auto &arg : values) {
3516 auto comp = lexical_cast(arg, tv);
3519 auto fv = detail::to_flag_value(arg);
3520 fail = (errno != 0);
3524 tv =
static_cast<double>(fv);
3529 for(
const auto &arg : values) {
3533 std::ostringstream out;
3548CLI11_INLINE
bool split_short(
const std::string ¤t, std::string &name, std::string &rest);
3551CLI11_INLINE
bool split_long(
const std::string ¤t, std::string &name, std::string &value);
3554CLI11_INLINE
bool split_windows_style(
const std::string ¤t, std::string &name, std::string &value);
3557CLI11_INLINE std::vector<std::string> split_names(std::string current);
3560CLI11_INLINE std::vector<std::pair<std::string, std::string>> get_default_flag_values(
const std::string &str);
3563CLI11_INLINE std::tuple<std::vector<std::string>, std::vector<std::string>, std::string>
3564get_names(
const std::vector<std::string> &input,
bool allow_non_standard =
false);
3572CLI11_INLINE
bool split_short(
const std::string ¤t, std::string &name, std::string &rest) {
3573 if(current.size() > 1 && current[0] ==
'-' && valid_first_char(current[1])) {
3574 name = current.substr(1, 1);
3575 rest = current.substr(2);
3581CLI11_INLINE
bool split_long(
const std::string ¤t, std::string &name, std::string &value) {
3582 if(current.size() > 2 && current.compare(0, 2,
"--") == 0 && valid_first_char(current[2])) {
3583 auto loc = current.find_first_of(
'=');
3584 if(loc != std::string::npos) {
3585 name = current.substr(2, loc - 2);
3586 value = current.substr(loc + 1);
3588 name = current.substr(2);
3596CLI11_INLINE
bool split_windows_style(
const std::string ¤t, std::string &name, std::string &value) {
3597 if(current.size() > 1 && current[0] ==
'/' && valid_first_char(current[1])) {
3598 auto loc = current.find_first_of(
':');
3599 if(loc != std::string::npos) {
3600 name = current.substr(1, loc - 1);
3601 value = current.substr(loc + 1);
3603 name = current.substr(1);
3611CLI11_INLINE std::vector<std::string> split_names(std::string current) {
3612 std::vector<std::string> output;
3613 std::size_t val = 0;
3614 while((val = current.find(
',')) != std::string::npos) {
3615 output.push_back(trim_copy(current.substr(0, val)));
3616 current = current.substr(val + 1);
3618 output.push_back(trim_copy(current));
3622CLI11_INLINE std::vector<std::pair<std::string, std::string>> get_default_flag_values(
const std::string &str) {
3623 std::vector<std::string> flags = split_names(str);
3624 flags.erase(std::remove_if(flags.begin(),
3626 [](
const std::string &name) {
3627 return ((name.empty()) || (!(((name.find_first_of(
'{') != std::string::npos) &&
3628 (name.back() ==
'}')) ||
3629 (name[0] ==
'!'))));
3632 std::vector<std::pair<std::string, std::string>> output;
3633 output.reserve(flags.size());
3634 for(
auto &flag : flags) {
3635 auto def_start = flag.find_first_of(
'{');
3636 std::string defval =
"false";
3637 if((def_start != std::string::npos) && (flag.back() ==
'}')) {
3638 defval = flag.substr(def_start + 1);
3640 flag.erase(def_start, std::string::npos);
3642 flag.erase(0, flag.find_first_not_of(
"-!"));
3643 output.emplace_back(flag, defval);
3648CLI11_INLINE std::tuple<std::vector<std::string>, std::vector<std::string>, std::string>
3649get_names(
const std::vector<std::string> &input,
bool allow_non_standard) {
3651 std::vector<std::string> short_names;
3652 std::vector<std::string> long_names;
3653 std::string pos_name;
3654 for(std::string name : input) {
3658 if(name.length() > 1 && name[0] ==
'-' && name[1] !=
'-') {
3659 if(name.length() == 2 && valid_first_char(name[1])) {
3660 short_names.emplace_back(1, name[1]);
3661 }
else if(name.length() > 2) {
3662 if(allow_non_standard) {
3663 name = name.substr(1);
3664 if(valid_name_string(name)) {
3665 short_names.push_back(name);
3667 throw BadNameString::BadLongName(name);
3670 throw BadNameString::MissingDash(name);
3673 throw BadNameString::OneCharName(name);
3675 }
else if(name.length() > 2 && name.substr(0, 2) ==
"--") {
3676 name = name.substr(2);
3677 if(valid_name_string(name)) {
3678 long_names.push_back(name);
3680 throw BadNameString::BadLongName(name);
3682 }
else if(name ==
"-" || name ==
"--" || name ==
"++") {
3683 throw BadNameString::ReservedName(name);
3685 if(!pos_name.empty()) {
3686 throw BadNameString::MultiPositionalNames(name);
3688 if(valid_name_string(name)) {
3691 throw BadNameString::BadPositionalName(name);
3695 return std::make_tuple(short_names, long_names, pos_name);
3717 std::vector<std::string> tmp =
parents;
3718 tmp.emplace_back(
name);
3719 return detail::join(tmp,
".");
3727 std::vector<ConfigItem> items{};
3731 virtual std::string
to_config(
const App *,
bool,
bool, std::string)
const = 0;
3734 virtual std::vector<ConfigItem>
from_config(std::istream &)
const = 0;
3738 if(item.
inputs.size() == 1) {
3739 return item.
inputs.at(0);
3741 if(item.
inputs.empty()) {
3744 throw ConversionError::TooManyInputsFlag(item.
fullname());
3748 CLI11_NODISCARD std::vector<ConfigItem>
from_file(
const std::string &name)
const {
3749#if defined CLI11_HAS_FILESYSTEM && CLI11_HAS_FILESYSTEM > 0
3750 std::ifstream input{to_path(name)};
3752 std::ifstream input{name};
3756 throw FileError::Missing(name);
3797 to_config(
const App * ,
bool default_also,
bool write_description, std::string prefix)
const override;
3799 std::vector<ConfigItem> from_config(std::istream &input)
const override;
3869using ConfigTOML = ConfigBase;
3872class ConfigINI :
public ConfigTOML {
3905 std::function<std::string(std::string &)>
func_{[](std::string &) {
return std::string{}; }};
3915 Validator(std::string validator_desc, std::function<std::string(std::string &)> func)
3916 : desc_function_([validator_desc]() {
return validator_desc; }), func_(std::move(func)) {}
3919 Validator() =
default;
3923 Validator(std::function<std::string(std::string &)> op, std::string validator_desc, std::string validator_name =
"")
3924 :
desc_function_([validator_desc]() {
return validator_desc; }), func_(std::move(op)),
3925 name_(std::move(validator_name)) {}
3927 Validator &
operation(std::function<std::string(std::string &)> op) {
3928 func_ = std::move(op);
3933 std::string operator()(std::string &str)
const;
3938 std::string value = str;
3948 CLI11_NODISCARD
Validator description(std::string validator_desc)
const;
3955 return std::string{};
3958 Validator &
name(std::string validator_name) {
3959 name_ = std::move(validator_name);
3963 CLI11_NODISCARD Validator
name(std::string validator_name)
const {
3964 Validator newval(*
this);
3965 newval.
name_ = std::move(validator_name);
3976 CLI11_NODISCARD Validator
active(
bool active_val =
true)
const {
3977 Validator newval(*
this);
3994 Validator newval(*
this);
4018 void _merge_description(
const Validator &val1,
const Validator &val2,
const std::string &merger);
4022using CustomValidator = Validator;
4030enum class path_type : std::uint8_t { nonexistent, file, directory };
4033CLI11_INLINE path_type check_path(
const char *file)
noexcept;
4038class ExistingFileValidator :
public Validator {
4040 ExistingFileValidator();
4044class ExistingDirectoryValidator :
public Validator {
4046 ExistingDirectoryValidator();
4050class ExistingPathValidator :
public Validator {
4052 ExistingPathValidator();
4056class NonexistentPathValidator :
public Validator {
4058 NonexistentPathValidator();
4061class EscapedStringTransformer :
public Validator {
4063 EscapedStringTransformer();
4085class FileOnDefaultPath :
public Validator {
4087 explicit FileOnDefaultPath(std::string default_path,
bool enableErrorReturn =
true);
4097 template <
typename T>
4098 Range(T min_val, T max_val,
const std::string &validator_name = std::string{}) :
Validator(validator_name) {
4099 if(validator_name.empty()) {
4100 std::stringstream out;
4101 out << detail::type_name<T>() <<
" in [" << min_val <<
" - " << max_val <<
"]";
4102 description(out.str());
4105 func_ = [min_val, max_val](std::string &input) {
4106 using CLI::detail::lexical_cast;
4108 bool converted = lexical_cast(input, val);
4109 if((!converted) || (val < min_val || val > max_val)) {
4110 std::stringstream out;
4111 out <<
"Value " << input <<
" not in range [";
4112 out << min_val <<
" - " << max_val <<
"]";
4115 return std::string{};
4120 template <
typename T>
4121 explicit Range(T max_val,
const std::string &validator_name = std::string{})
4122 :
Range(static_cast<T>(0), max_val, validator_name) {}
4126CLI11_MODULE_INLINE
const Range NonNegativeNumber((std::numeric_limits<double>::max)(),
"NONNEGATIVE");
4129CLI11_MODULE_INLINE
const
4130 Range PositiveNumber((std::numeric_limits<double>::min)(), (std::numeric_limits<double>::max)(),
"POSITIVE");
4137template <
typename T>
4138inline typename std::enable_if<std::is_signed<T>::value, T>::type overflowCheck(
const T &a,
const T &b) {
4139 if((a > 0) == (b > 0)) {
4140 return ((std::numeric_limits<T>::max)() / (std::abs)(a) < (std::abs)(b));
4142 return ((std::numeric_limits<T>::min)() / (std::abs)(a) > -(std::abs)(b));
4145template <
typename T>
4146inline typename std::enable_if<!std::is_signed<T>::value, T>::type overflowCheck(
const T &a,
const T &b) {
4147 return ((std::numeric_limits<T>::max)() / a < b);
4151template <
typename T>
typename std::enable_if<std::is_integral<T>::value,
bool>::type checked_multiply(T &a, T b) {
4152 if(a == 0 || b == 0 || a == 1 || b == 1) {
4156 if(a == (std::numeric_limits<T>::min)() || b == (std::numeric_limits<T>::min)()) {
4159 if(overflowCheck(a, b)) {
4167template <
typename T>
4168typename std::enable_if<std::is_floating_point<T>::value,
bool>::type checked_multiply(T &a, T b) {
4170 if(std::isinf(c) && !std::isinf(a) && !std::isinf(b)) {
4180CLI11_INLINE std::pair<std::string, std::string> split_program_name(std::string commandline);
4189 std::string retstring;
4192 std::string value = str;
4193 retstring =
func_(value);
4195 retstring =
func_(str);
4202 Validator newval(*
this);
4203 newval.
desc_function_ = [validator_desc]() {
return validator_desc; };
4210 newval._merge_description(*
this, other,
" AND ");
4213 const std::function<std::string(std::string & filename)> &f1 =
func_;
4214 const std::function<std::string(std::string & filename)> &f2 = other.
func_;
4216 newval.
func_ = [f1, f2](std::string &input) {
4217 std::string s1 = f1(input);
4218 std::string s2 = f2(input);
4219 if(!s1.empty() && !s2.empty())
4220 return std::string(
"(") + s1 +
") AND (" + s2 +
")";
4232 newval._merge_description(*
this, other,
" OR ");
4235 const std::function<std::string(std::string &)> &f1 =
func_;
4236 const std::function<std::string(std::string &)> &f2 = other.
func_;
4238 newval.
func_ = [f1, f2](std::string &input) {
4239 std::string s1 = f1(input);
4240 std::string s2 = f2(input);
4241 if(s1.empty() || s2.empty())
4242 return std::string();
4244 return std::string(
"(") + s1 +
") OR (" + s2 +
")";
4255 auto str = dfunc1();
4256 return (!str.empty()) ? std::string(
"NOT ") + str : std::string{};
4259 const std::function<std::string(std::string & res)> &f1 =
func_;
4261 newval.
func_ = [f1, dfunc1](std::string &test) -> std::string {
4262 std::string s1 = f1(test);
4264 return std::string(
"check ") + dfunc1() +
" succeeded improperly";
4266 return std::string{};
4274Validator::_merge_description(
const Validator &val1,
const Validator &val2,
const std::string &merger) {
4276 const std::function<std::string()> &dfunc1 = val1.
desc_function_;
4277 const std::function<std::string()> &dfunc2 = val2.
desc_function_;
4280 std::string f1 = dfunc1();
4281 std::string f2 = dfunc2();
4282 if((f1.empty()) || (f2.empty())) {
4285 return std::string(1,
'(') + f1 +
')' + merger +
'(' + f2 +
')';
4291#if defined CLI11_HAS_FILESYSTEM && CLI11_HAS_FILESYSTEM > 0
4292CLI11_INLINE path_type check_path(
const char *file)
noexcept {
4294 auto stat = std::filesystem::status(to_path(file), ec);
4296 return path_type::nonexistent;
4298 switch(stat.type()) {
4299 case std::filesystem::file_type::none:
4300 case std::filesystem::file_type::not_found:
4301 return path_type::nonexistent;
4302 case std::filesystem::file_type::directory:
4303 return path_type::directory;
4304 case std::filesystem::file_type::symlink:
4305 case std::filesystem::file_type::block:
4306 case std::filesystem::file_type::character:
4307 case std::filesystem::file_type::fifo:
4308 case std::filesystem::file_type::socket:
4309 case std::filesystem::file_type::regular:
4310 case std::filesystem::file_type::unknown:
4312 return path_type::file;
4316CLI11_INLINE path_type check_path(
const char *file)
noexcept {
4317#if defined(_MSC_VER)
4318 struct __stat64 buffer;
4319 if(_stat64(file, &buffer) == 0) {
4320 return ((buffer.st_mode & S_IFDIR) != 0) ? path_type::directory : path_type::file;
4324 if(stat(file, &buffer) == 0) {
4325 return ((buffer.st_mode & S_IFDIR) != 0) ? path_type::directory : path_type::file;
4328 return path_type::nonexistent;
4332CLI11_INLINE ExistingFileValidator::ExistingFileValidator() : Validator(
"FILE") {
4333 func_ = [](std::string &filename) {
4334 auto path_result = check_path(filename.c_str());
4335 if(path_result == path_type::nonexistent) {
4336 return "File does not exist: " + filename;
4338 if(path_result == path_type::directory) {
4339 return "File is actually a directory: " + filename;
4341 return std::string();
4345CLI11_INLINE ExistingDirectoryValidator::ExistingDirectoryValidator() :
Validator(
"DIR") {
4346 func_ = [](std::string &filename) {
4347 auto path_result = check_path(filename.c_str());
4348 if(path_result == path_type::nonexistent) {
4349 return "Directory does not exist: " + filename;
4351 if(path_result == path_type::file) {
4352 return "Directory is actually a file: " + filename;
4354 return std::string();
4358CLI11_INLINE ExistingPathValidator::ExistingPathValidator() :
Validator(
"PATH(existing)") {
4359 func_ = [](std::string &filename) {
4360 auto path_result = check_path(filename.c_str());
4361 if(path_result == path_type::nonexistent) {
4362 return "Path does not exist: " + filename;
4364 return std::string();
4368CLI11_INLINE NonexistentPathValidator::NonexistentPathValidator() :
Validator(
"PATH(non-existing)") {
4369 func_ = [](std::string &filename) {
4370 auto path_result = check_path(filename.c_str());
4371 if(path_result != path_type::nonexistent) {
4372 return "Path already exists: " + filename;
4374 return std::string();
4378CLI11_INLINE EscapedStringTransformer::EscapedStringTransformer() {
4379 func_ = [](std::string &str) {
4381 if(str.size() > 1 && (str.front() ==
'\"' || str.front() ==
'\'' || str.front() ==
'`') &&
4382 str.front() == str.back()) {
4383 process_quoted_string(str);
4384 }
else if(str.find_first_of(
'\\') != std::string::npos) {
4385 if(detail::is_binary_escaped_string(str)) {
4386 str = detail::extract_binary_string(str);
4388 str = remove_escaped_characters(str);
4391 return std::string{};
4392 }
catch(
const std::invalid_argument &ia) {
4393 return std::string(ia.what());
4399CLI11_INLINE FileOnDefaultPath::FileOnDefaultPath(std::string default_path,
bool enableErrorReturn)
4400 : Validator(
"FILE") {
4401 func_ = [default_path, enableErrorReturn](std::string &filename) {
4402 auto path_result = detail::check_path(filename.c_str());
4403 if(path_result == detail::path_type::nonexistent) {
4404 std::string test_file_path = default_path;
4405 if(default_path.back() !=
'/' && default_path.back() !=
'\\') {
4407 test_file_path +=
'/';
4409 test_file_path.append(filename);
4410 path_result = detail::check_path(test_file_path.c_str());
4411 if(path_result == detail::path_type::file) {
4412 filename = test_file_path;
4414 if(enableErrorReturn) {
4415 return "File does not exist: " + filename;
4419 return std::string{};
4425CLI11_INLINE std::pair<std::string, std::string> split_program_name(std::string commandline) {
4427 std::pair<std::string, std::string> vals;
4429 auto esp = commandline.find_first_of(
' ', 1);
4430 while(detail::check_path(commandline.substr(0, esp).c_str()) != path_type::file) {
4431 esp = commandline.find_first_of(
' ', esp + 1);
4432 if(esp == std::string::npos) {
4435 if(commandline[0] ==
'"' || commandline[0] ==
'\'' || commandline[0] ==
'`') {
4436 bool embeddedQuote =
false;
4437 auto keyChar = commandline[0];
4438 auto end = commandline.find_first_of(keyChar, 1);
4439 while((end != std::string::npos) && (commandline[end - 1] ==
'\\')) {
4440 end = commandline.find_first_of(keyChar, end + 1);
4441 embeddedQuote =
true;
4443 if(end != std::string::npos) {
4444 vals.first = commandline.substr(1, end - 1);
4447 vals.first = find_and_replace(vals.first, std::string(
"\\") + keyChar, std::string(1, keyChar));
4450 esp = commandline.find_first_of(
' ', 1);
4453 esp = commandline.find_first_of(
' ', 1);
4459 if(vals.first.empty()) {
4460 vals.first = commandline.substr(0, esp);
4465 vals.second = (esp < commandline.length() - 1) ? commandline.substr(esp + 1) : std::string{};
4482class IPV4Validator :
public Validator {
4490template <
typename DesiredType>
class TypeValidator :
public Validator {
4492 explicit TypeValidator(
const std::string &validator_name)
4493 : Validator(validator_name, [](std::string &input_string) {
4494 using CLI::detail::lexical_cast;
4495 auto val = DesiredType();
4496 if(!lexical_cast(input_string, val)) {
4497 return std::string(
"Failed parsing ") + input_string +
" as a " + detail::type_name<DesiredType>();
4499 return std::string{};
4501 TypeValidator() : TypeValidator(detail::type_name<DesiredType>()) {}
4514 template <
typename T>
Bound(T min_val, T max_val) {
4515 std::stringstream out;
4516 out << detail::type_name<T>() <<
" bounded to [" << min_val <<
" - " << max_val <<
"]";
4519 func_ = [min_val, max_val](std::string &input) {
4520 using CLI::detail::lexical_cast;
4522 bool converted = lexical_cast(input, val);
4524 return std::string(
"Value ") + input +
" could not be converted";
4527 input = detail::to_string(min_val);
4528 else if(val > max_val)
4529 input = detail::to_string(max_val);
4531 return std::string{};
4536 template <
typename T>
explicit Bound(T max_val) :
Bound(static_cast<T>(0), max_val) {}
4542CLI11_MODULE_INLINE
const detail::IPV4Validator ValidIPV4;
4545template <
typename T,
4546 enable_if_t<is_copyable_ptr<typename std::remove_reference<T>::type>::value, detail::enabler> = detail::dummy>
4547auto smart_deref(T value) ->
decltype(*value) {
4553 enable_if_t<!is_copyable_ptr<typename std::remove_reference<T>::type>::value, detail::enabler> = detail::dummy>
4554typename std::remove_reference<T>::type &smart_deref(T &value) {
4559template <
typename T> std::string generate_set(
const T &set) {
4560 using element_t =
typename detail::element_type<T>::type;
4561 using iteration_type_t =
typename detail::pair_adaptor<element_t>::value_type;
4562 std::string out(1,
'{');
4563 out.append(detail::join(
4564 detail::smart_deref(set),
4572template <
typename T> std::string generate_map(
const T &map,
bool key_only =
false) {
4573 using element_t =
typename detail::element_type<T>::type;
4574 using iteration_type_t =
typename detail::pair_adaptor<element_t>::value_type;
4575 std::string out(1,
'{');
4576 out.append(detail::join(
4577 detail::smart_deref(map),
4578 [key_only](
const iteration_type_t &v) {
4593 template <
typename CC,
typename VV>
4594 static auto test(
int) ->
decltype(std::declval<CC>().find(std::declval<VV>()), std::true_type());
4595 template <
typename,
typename>
static auto test(...) ->
decltype(std::false_type());
4597 static const auto value =
decltype(test<C, V>(0))::value;
4598 using type = std::integral_constant<bool, value>;
4602template <typename T, typename V, enable_if_t<!has_find<T, V>::value, detail::enabler> = detail::dummy>
4603auto search(
const T &set,
const V &val) -> std::pair<bool,
decltype(std::begin(detail::smart_deref(set)))> {
4604 using element_t =
typename detail::element_type<T>::type;
4605 auto &setref = detail::smart_deref(set);
4606 auto it = std::find_if(std::begin(setref), std::end(setref), [&val](
decltype(*std::begin(setref)) v) {
4609 return {(it != std::end(setref)), it};
4613template <typename T, typename V, enable_if_t<has_find<T, V>::value, detail::enabler> = detail::dummy>
4614auto search(
const T &set,
const V &val) -> std::pair<bool,
decltype(std::begin(detail::smart_deref(set)))> {
4615 auto &setref = detail::smart_deref(set);
4616 auto it = setref.find(val);
4617 return {(it != std::end(setref)), it};
4621template <
typename T,
typename V>
4622auto search(
const T &set,
const V &val,
const std::function<V(V)> &filter_function)
4623 -> std::pair<bool,
decltype(std::begin(detail::smart_deref(set)))> {
4624 using element_t =
typename detail::element_type<T>::type;
4626 auto res = search(set, val);
4627 if((res.first) || (!(filter_function))) {
4631 auto &setref = detail::smart_deref(set);
4632 auto it = std::find_if(std::begin(setref), std::end(setref), [&](
decltype(*std::begin(setref)) v) {
4634 a = filter_function(a);
4637 return {(it != std::end(setref)), it};
4644 using filter_fn_t = std::function<std::string(std::string)>;
4647 template <
typename T,
typename... Args>
4648 IsMember(std::initializer_list<T> values, Args &&...args)
4649 :
IsMember(std::vector<T>(values), std::forward<Args>(args)...) {}
4656 template <
typename T,
typename F>
explicit IsMember(T set, F filter_function) {
4660 using element_t =
typename detail::element_type<T>::type;
4661 using item_t =
typename detail::pair_adaptor<element_t>::first_type;
4663 using local_item_t =
typename IsMemberType<item_t>::type;
4667 std::function<local_item_t(local_item_t)> filter_fn = filter_function;
4670 desc_function_ = [set]() {
return detail::generate_set(detail::smart_deref(set)); };
4674 func_ = [set, filter_fn](std::string &input) {
4675 using CLI::detail::lexical_cast;
4677 if(!lexical_cast(input, b)) {
4683 auto res = detail::search(set, b, filter_fn);
4691 return std::string{};
4695 return input +
" not in " + detail::generate_set(detail::smart_deref(set));
4700 template <
typename T,
typename... Args>
4701 IsMember(T &&set, filter_fn_t filter_fn_1, filter_fn_t filter_fn_2, Args &&...other)
4703 std::forward<T>(set),
4704 [filter_fn_1, filter_fn_2](std::string a) {
return filter_fn_2(filter_fn_1(a)); },
4709template <
typename T>
using TransformPairs = std::vector<std::pair<std::string, T>>;
4714 using filter_fn_t = std::function<std::string(std::string)>;
4717 template <
typename... Args>
4718 Transformer(std::initializer_list<std::pair<std::string, std::string>> values, Args &&...args)
4719 :
Transformer(TransformPairs<std::string>(values), std::forward<Args>(args)...) {}
4726 template <
typename T,
typename F>
explicit Transformer(T mapping, F filter_function) {
4729 "mapping must produce value pairs");
4732 using element_t =
typename detail::element_type<T>::type;
4733 using item_t =
typename detail::pair_adaptor<element_t>::first_type;
4734 using local_item_t =
typename IsMemberType<item_t>::type;
4738 std::function<local_item_t(local_item_t)> filter_fn = filter_function;
4741 desc_function_ = [mapping]() {
return detail::generate_map(detail::smart_deref(mapping)); };
4743 func_ = [mapping, filter_fn](std::string &input) {
4744 using CLI::detail::lexical_cast;
4746 if(!lexical_cast(input, b)) {
4747 return std::string();
4753 auto res = detail::search(mapping, b, filter_fn);
4757 return std::string{};
4762 template <
typename T,
typename... Args>
4763 Transformer(T &&mapping, filter_fn_t filter_fn_1, filter_fn_t filter_fn_2, Args &&...other)
4765 std::forward<T>(mapping),
4766 [filter_fn_1, filter_fn_2](std::string a) {
return filter_fn_2(filter_fn_1(a)); },
4773 using filter_fn_t = std::function<std::string(std::string)>;
4776 template <
typename... Args>
4778 :
CheckedTransformer(TransformPairs<std::string>(values), std::forward<Args>(args)...) {}
4788 "mapping must produce value pairs");
4791 using element_t =
typename detail::element_type<T>::type;
4792 using item_t =
typename detail::pair_adaptor<element_t>::first_type;
4793 using local_item_t =
typename IsMemberType<item_t>::type;
4795 using iteration_type_t =
typename detail::pair_adaptor<element_t>::value_type;
4798 std::function<local_item_t(local_item_t)> filter_fn = filter_function;
4800 auto tfunc = [mapping]() {
4801 std::string out(
"value in ");
4802 out += detail::generate_map(detail::smart_deref(mapping)) +
" OR {";
4803 out += detail::join(
4804 detail::smart_deref(mapping),
4805 [](
const iteration_type_t &v) {
4815 func_ = [mapping, tfunc, filter_fn](std::string &input) {
4816 using CLI::detail::lexical_cast;
4818 bool converted = lexical_cast(input, b);
4823 auto res = detail::search(mapping, b, filter_fn);
4826 return std::string{};
4829 for(
const auto &v : detail::smart_deref(mapping)) {
4831 if(output_string == input) {
4832 return std::string();
4836 return "Check " + input +
" " + tfunc() +
" FAILED";
4841 template <
typename T,
typename... Args>
4844 std::forward<T>(mapping),
4845 [filter_fn_1, filter_fn_2](std::string a) {
return filter_fn_2(filter_fn_1(a)); },
4850inline std::string ignore_case(std::string item) {
return detail::to_lower(item); }
4853inline std::string ignore_underscore(std::string item) {
return detail::remove_underscore(item); }
4856inline std::string ignore_space(std::string item) {
4857 item.erase(std::remove(std::begin(item), std::end(item),
' '), std::end(item));
4858 item.erase(std::remove(std::begin(item), std::end(item),
'\t'), std::end(item));
4873class AsNumberWithUnit :
public Validator {
4881 CASE_INSENSITIVE = 1,
4884 DEFAULT = CASE_INSENSITIVE | UNIT_OPTIONAL
4887 template <
typename Number>
4890 const std::string &unit_name =
"UNIT") {
4891 description(generate_description<Number>(unit_name, opts));
4892 validate_mapping(mapping, opts);
4895 func_ = [mapping, opts](std::string &input) -> std::string {
4898 detail::rtrim(input);
4900 throw ValidationError(
"Input is empty");
4904 auto unit_begin = input.end();
4905 while(unit_begin > input.begin() && std::isalpha(*(unit_begin - 1), std::locale())) {
4909 std::string unit{unit_begin, input.end()};
4910 input.resize(
static_cast<std::size_t
>(std::distance(input.begin(), unit_begin)));
4911 detail::trim(input);
4913 if(opts & UNIT_REQUIRED && unit.empty()) {
4914 throw ValidationError(
"Missing mandatory unit");
4916 if(opts & CASE_INSENSITIVE) {
4917 unit = detail::to_lower(unit);
4920 using CLI::detail::lexical_cast;
4921 if(!lexical_cast(input, num)) {
4922 throw ValidationError(std::string(
"Value ") + input +
" could not be converted to " +
4923 detail::type_name<Number>());
4930 auto it = mapping.find(unit);
4931 if(it == mapping.end()) {
4932 throw ValidationError(unit +
4933 " unit not recognized. "
4934 "Allowed values: " +
4935 detail::generate_map(mapping,
true));
4938 if(!input.empty()) {
4939 using CLI::detail::lexical_cast;
4940 bool converted = lexical_cast(input, num);
4942 throw ValidationError(std::string(
"Value ") + input +
" could not be converted to " +
4943 detail::type_name<Number>());
4946 bool ok = detail::checked_multiply(num, it->second);
4948 throw ValidationError(detail::to_string(num) +
" multiplied by " + unit +
4949 " factor would cause number overflow. Use smaller value.");
4952 num =
static_cast<Number
>(it->second);
4955 input = detail::to_string(num);
4964 template <
typename Number>
static void validate_mapping(std::map<std::string, Number> &mapping,
Options opts) {
4965 for(
auto &kv : mapping) {
4966 if(kv.first.empty()) {
4967 throw ValidationError(
"Unit must not be empty.");
4969 if(!detail::isalpha(kv.first)) {
4970 throw ValidationError(
"Unit must contain only letters.");
4975 if(opts & CASE_INSENSITIVE) {
4976 std::map<std::string, Number> lower_mapping;
4977 for(
auto &kv : mapping) {
4978 auto s = detail::to_lower(kv.first);
4979 if(lower_mapping.count(s)) {
4980 throw ValidationError(std::string(
"Several matching lowercase unit representations are found: ") +
4983 lower_mapping[detail::to_lower(kv.first)] = kv.second;
4985 mapping = std::move(lower_mapping);
4990 template <
typename Number>
static std::string generate_description(
const std::string &
name,
Options opts) {
4991 std::stringstream out;
4992 out << detail::type_name<Number>() <<
' ';
4993 if(opts & UNIT_REQUIRED) {
4996 out <<
'[' <<
name <<
']';
5019 using result_t = std::uint64_t;
5032 static std::map<std::string, result_t> init_mapping(
bool kb_is_1000);
5035 static std::map<std::string, result_t> get_mapping(
bool kb_is_1000);
5038#if defined(CLI11_ENABLE_EXTRA_VALIDATORS) && CLI11_ENABLE_EXTRA_VALIDATORS != 0
5040#if CLI11_HAS_FILESYSTEM
5042enum class Permission : std::uint8_t { none = 0, read = 1, write = 2, exec = 4 };
5043class PermissionValidator :
public Validator {
5045 explicit PermissionValidator(Permission permission);
5050const detail::PermissionValidator ReadPermissions(detail::Permission::read);
5053const detail::PermissionValidator WritePermissions(detail::Permission::write);
5056const detail::PermissionValidator ExecPermissions(detail::Permission::exec);
5065CLI11_INLINE IPV4Validator::IPV4Validator() : Validator(
"IPV4") {
5066 func_ = [](std::string &ip_addr) {
5067 auto cdot = std::count(ip_addr.begin(), ip_addr.end(),
'.');
5069 return std::string(
"Invalid IPV4 address: must have 3 separators");
5071 auto result = CLI::detail::split(ip_addr,
'.');
5072 if(result.size() != 4) {
5073 return std::string(
"Invalid IPV4 address: must have four parts (") + ip_addr +
')';
5076 for(
const auto &var : result) {
5077 using CLI::detail::lexical_cast;
5078 bool retval = lexical_cast(var, num);
5080 return std::string(
"Failed parsing number (") + var +
')';
5082 if(num < 0 || num > 255) {
5083 return std::string(
"Each IP number must be between 0 and 255 ") + var;
5086 return std::string{};
5094 description(
"SIZE [b, kb(=1000b), kib(=1024b), ...]");
5100CLI11_INLINE std::map<std::string, AsSizeValue::result_t> AsSizeValue::init_mapping(
bool kb_is_1000) {
5101 std::map<std::string, result_t> m;
5102 result_t k_factor = kb_is_1000 ? 1000 : 1024;
5103 result_t ki_factor = 1024;
5107 for(std::string p : {
"k",
"m",
"g",
"t",
"p",
"e"}) {
5118CLI11_INLINE std::map<std::string, AsSizeValue::result_t> AsSizeValue::get_mapping(
bool kb_is_1000) {
5120 static auto m = init_mapping(
true);
5123 static auto m = init_mapping(
false);
5130#if defined(CLI11_ENABLE_EXTRA_VALIDATORS) && CLI11_ENABLE_EXTRA_VALIDATORS != 0
5134#if defined CLI11_HAS_FILESYSTEM && CLI11_HAS_FILESYSTEM > 0
5135CLI11_INLINE PermissionValidator::PermissionValidator(Permission permission) {
5136 std::filesystem::perms permission_code = std::filesystem::perms::none;
5137 std::string permission_name;
5138 switch(permission) {
5139 case Permission::read:
5140 permission_code = std::filesystem::perms::owner_read | std::filesystem::perms::group_read |
5141 std::filesystem::perms::others_read;
5142 permission_name =
"read";
5144 case Permission::write:
5145 permission_code = std::filesystem::perms::owner_write | std::filesystem::perms::group_write |
5146 std::filesystem::perms::others_write;
5147 permission_name =
"write";
5149 case Permission::exec:
5150 permission_code = std::filesystem::perms::owner_exec | std::filesystem::perms::group_exec |
5151 std::filesystem::perms::others_exec;
5152 permission_name =
"exec";
5154 case Permission::none:
5156 permission_code = std::filesystem::perms::none;
5159 func_ = [permission_code](std::string &path) {
5161 auto p = std::filesystem::path(path);
5162 if(!std::filesystem::exists(p, ec)) {
5163 return std::string(
"Path does not exist: ") + path;
5166 return std::string(
"Error checking path: ") + ec.message();
5168 if(permission_code == std::filesystem::perms::none) {
5169 return std::string{};
5171 auto perms = std::filesystem::status(p, ec).permissions();
5173 return std::string(
"Error checking path status: ") + ec.message();
5175 if((perms & permission_code) == std::filesystem::perms::none) {
5176 return std::string(
"Path does not have required permissions: ") + path;
5178 return std::string{};
5180 description(
"Path with " + permission_name +
" permission");
5197enum class AppFormatMode : std::uint8_t {
5207class FormatterBase {
5229 bool enable_footer_formatting_{
true};
5233 bool enable_option_type_names_{
true};
5234 bool enable_default_flag_values_{
true};
5254 virtual std::string
make_help(
const App *, std::string, AppFormatMode)
const = 0;
5270 (ratio >= 0.0f) ? ((ratio <= 1.0f) ? ratio : 1.0f / ratio) : ((ratio < -1.0f) ? 1.0f / (-ratio) : -ratio);
5297 CLI11_NODISCARD std::string
get_label(std::string key)
const {
5339 using funct_t = std::function<std::string(
const App *, std::string, AppFormatMode)>;
5352 std::string
make_help(
const App *app, std::string name, AppFormatMode mode)
const override {
5353 return lambda_(app, name, mode);
5359class Formatter :
public FormatterBase {
5361 Formatter() =
default;
5362 Formatter(
const Formatter &) =
default;
5363 Formatter(Formatter &&) =
default;
5364 Formatter &operator=(
const Formatter &) =
default;
5365 Formatter &operator=(Formatter &&) =
default;
5372 CLI11_NODISCARD
virtual std::string
5373 make_group(std::string group,
bool is_positional, std::vector<const Option *> opts)
const;
5379 std::string
make_groups(
const App *app, AppFormatMode mode)
const;
5388 virtual std::string
make_expanded(
const App *sub, AppFormatMode mode)
const;
5397 virtual std::string
make_usage(
const App *app, std::string name)
const;
5400 std::string
make_help(
const App *app, std::string, AppFormatMode mode)
const override;
5427using results_t = std::vector<std::string>;
5429using callback_t = std::function<bool(
const results_t &)>;
5435using Option_p = std::unique_ptr<Option>;
5436using Validator_p = std::shared_ptr<Validator>;
5439enum class MultiOptionPolicy :
char {
5450enum class CallbackPriority : std::uint8_t {
5453 PreRequirementsCheckPreHelp = 2,
5454 PreRequirementsCheck = 3,
5499 template <
typename T>
void copy_to(T *other)
const;
5506 if(!detail::valid_alias_name_string(name)) {
5510 return static_cast<CRTP *
>(
this);
5516 return static_cast<CRTP *
>(
this);
5522 CRTP *always_capture_default(
bool value =
true) {
5524 return static_cast<CRTP *
>(
this);
5563 auto *self =
static_cast<CRTP *
>(
this);
5564 self->multi_option_policy(MultiOptionPolicy::TakeLast);
5570 auto *self =
static_cast<CRTP *
>(
this);
5571 self->multi_option_policy(MultiOptionPolicy::TakeFirst);
5577 auto self =
static_cast<CRTP *
>(
this);
5578 self->multi_option_policy(MultiOptionPolicy::TakeAll);
5584 auto *self =
static_cast<CRTP *
>(
this);
5585 self->multi_option_policy(MultiOptionPolicy::Join);
5591 auto self =
static_cast<CRTP *
>(
this);
5592 self->delimiter_ = delim;
5593 self->multi_option_policy(MultiOptionPolicy::Join);
5600 return static_cast<CRTP *
>(
this);
5606 return static_cast<CRTP *
>(
this);
5614 OptionDefaults() =
default;
5698 std::function<std::string()>
type_name_{[]() {
return std::string(); }};
5769 std::string option_description,
5770 callback_t callback,
5772 bool allow_non_standard =
false)
5774 std::tie(
snames_,
lnames_,
pname_) = detail::get_names(detail::split_names(option_name), allow_non_standard);
5856 Option *
check(std::function<std::string(
const std::string &)> validator_func,
5857 std::string validator_description =
"",
5858 std::string validator_name =
"");
5867 Option *
transform(
const std::function<std::string(std::string)> &transform_func,
5868 std::string transform_description =
"",
5869 std::string transform_name =
"");
5872 Option *
each(
const std::function<
void(std::string)> &func);
5890 auto opt =
static_cast<T *
>(
parent_)->get_option_no_throw(opt_name);
5891 if(opt ==
nullptr) {
5892 throw IncorrectConstruction::MissingOption(opt_name);
5898 template <
typename A,
typename B,
typename... ARG>
Option *
needs(A opt, B opt1, ARG... args) {
5900 return needs(opt1, args...);
5911 auto opt =
static_cast<T *
>(
parent_)->get_option_no_throw(opt_name);
5912 if(opt ==
nullptr) {
5913 throw IncorrectConstruction::MissingOption(opt_name);
5919 template <
typename A,
typename B,
typename... ARG>
Option *
excludes(A opt, B opt1, ARG... args) {
6018 return detail::checked_multiply(t,
expected_max_) ? t : detail::expected_max_vector_size;
6041 Option *option_text(std::string text) {
6046 CLI11_NODISCARD
const std::string &get_option_text()
const {
return option_text_; }
6057 CLI11_NODISCARD std::string
get_name(
bool positional =
false,
6058 bool all_options =
false,
6059 bool disable_default_flag_values =
false
6076 CLI11_NODISCARD
bool check_name(
const std::string &name)
const;
6098 CLI11_NODISCARD std::string
get_flag_value(
const std::string &name, std::string input_value)
const;
6116 template <
typename T>
void results(T &output)
const {
6117 bool retval =
false;
6121 retval = detail::lexical_conversion<T, T>(res, output);
6124 res2.emplace_back();
6126 retval = detail::lexical_conversion<T, T>(
proc_results_, output);
6135 _validate_results(res);
6137 _reduce_results(extra, res);
6138 if(!extra.empty()) {
6139 res = std::move(extra);
6149 retval = detail::lexical_conversion<T, T>(
proc_results_, output);
6157 template <
typename T> CLI11_NODISCARD T
as()
const {
6186 Option *
type_size(
int option_type_size_min,
int option_type_size_max);
6214 std::string val_str = detail::value_string(val);
6216 results_t old_results{std::move(
results_)};
6234 get_name(), std::string(
"given default value(\"") + val_str +
"\") produces an error : " + err.what());
6250 void _validate_results(results_t &res)
const;
6255 void _reduce_results(results_t &out,
const results_t &original)
const;
6258 std::string _validate(std::string &result,
int index)
const;
6261 int _add_result(std::string &&result, std::vector<std::string> &res)
const;
6288 }
else if(value == detail::expected_max_vector_size) {
6303 value_min = -value_min;
6307 value_max = detail::expected_max_vector_size;
6309 if(value_max < value_min) {
6321 validator->non_modifying();
6329 auto vp = std::make_shared<Validator>(std::move(validator));
6330 if(!validator_name.empty()) {
6331 vp->name(validator_name);
6339 std::string validator_description,
6340 std::string validator_name) {
6342 auto vp = std::make_shared<Validator>(
6343 std::move(validator_func), std::move(validator_description), std::move(validator_name));
6344 vp->non_modifying();
6356 auto vp = std::make_shared<Validator>(std::move(validator));
6357 if(!transform_name.empty()) {
6358 vp->name(transform_name);
6365 std::string transform_description,
6366 std::string transform_name) {
6367 auto vp = std::make_shared<Validator>(
6368 [transform_func](std::string &val) {
6369 val = transform_func(val);
6370 return std::string{};
6372 std::move(transform_description),
6373 std::move(transform_name));
6380 auto vp = std::make_shared<Validator>(
6381 [func](std::string &inout) {
6383 return std::string{};
6392 if(validator_name == validator->get_name()) {
6393 return validator.get();
6396 if((validator_name.empty()) && (!
validators_.empty())) {
6399 throw OptionNotFound(std::string{
"Validator "} + validator_name +
" Not Found");
6404 if(index >= 0 && index <
static_cast<int>(
validators_.size())) {
6411 auto iterator = std::find(std::begin(
needs_), std::end(
needs_), opt);
6413 if(iterator == std::end(
needs_)) {
6448 auto *parent =
static_cast<T *
>(
parent_);
6449 for(
const Option_p &opt : parent->options_) {
6450 if(opt.get() ==
this) {
6453 const auto &omatch = opt->matching_name(*
this);
6454 if(!omatch.empty()) {
6456 throw OptionAlreadyAdded(
"adding ignore case caused a name conflict with " + omatch);
6469 auto *parent =
static_cast<T *
>(
parent_);
6470 for(
const Option_p &opt : parent->options_) {
6471 if(opt.get() ==
this) {
6474 const auto &omatch = opt->matching_name(*
this);
6475 if(!omatch.empty()) {
6477 throw OptionAlreadyAdded(
"adding ignore underscore caused a name conflict with " + omatch);
6499CLI11_NODISCARD CLI11_INLINE std::string
6506 std::vector<std::string> name_list;
6510 name_list.push_back(
pname_);
6513 for(
const std::string &sname :
snames_) {
6514 name_list.push_back(
"-" + sname);
6515 if(!disable_default_flag_values &&
check_fname(sname)) {
6520 for(
const std::string &lname :
lnames_) {
6521 name_list.push_back(
"--" + lname);
6522 if(!disable_default_flag_values &&
check_fname(lname)) {
6527 for(
const std::string &sname :
snames_)
6528 name_list.push_back(
"-" + sname);
6530 for(
const std::string &lname :
lnames_)
6531 name_list.push_back(
"--" + lname);
6534 return detail::join(name_list);
6543 return std::string(2,
'-') +
lnames_[0];
6547 return std::string(1,
'-') +
snames_[0];
6554 bool used_default_str =
false;
6556 used_default_str =
true;
6571 if(send_results.empty()) {
6574 bool local_result =
callback_(send_results);
6575 if(used_default_str) {
6587 static const std::string estring;
6589 for(
const std::string &sname :
snames_) {
6595 for(
const std::string &lname :
lnames_) {
6598 if(lname.size() == 1 && bothConfigurable) {
6608 if(bothConfigurable && other.
snames_.empty() && other.
fnames_.empty() && !other.
pname_.empty()) {
6614 for(
const std::string &sname : other.
snames_)
6617 for(
const std::string &lname : other.
lnames_)
6626 if(name.length() > 2 && name[0] ==
'-' && name[1] ==
'-')
6628 if(name.length() > 1 && name.front() ==
'-')
6631 std::string local_pname =
pname_;
6632 std::string local_name = name;
6634 local_pname = detail::remove_underscore(local_pname);
6635 local_name = detail::remove_underscore(local_name);
6638 local_pname = detail::to_lower(local_pname);
6639 local_name = detail::to_lower(local_name);
6641 if(local_name == local_pname) {
6654 std::string input_value)
const {
6655 static const std::string trueString{
"true"};
6656 static const std::string falseString{
"false"};
6657 static const std::string emptyString{
"{}"};
6660 if(!((input_value.empty()) || (input_value == emptyString))) {
6662 if(default_ind >= 0) {
6668 throw(ArgumentMismatch::FlagOverride(name));
6671 if(input_value != trueString) {
6672 throw(ArgumentMismatch::FlagOverride(name));
6678 if((input_value.empty()) || (input_value == emptyString)) {
6689 auto val = detail::to_flag_value(input_value);
6694 return (val == 1) ? falseString : (val == (-1) ? trueString : std::to_string(-val));
6700 _add_result(std::move(s),
results_);
6706 results_added = _add_result(std::move(s),
results_);
6713 for(
auto &str : s) {
6714 _add_result(std::move(str),
results_);
6724 _validate_results(res);
6728 _reduce_results(extra, res);
6729 if(!extra.empty()) {
6730 res = std::move(extra);
6738 if(option_type_size < 0) {
6757 if(option_type_size_min < 0 || option_type_size_max < 0) {
6760 option_type_size_min = (std::abs)(option_type_size_min);
6761 option_type_size_max = (std::abs)(option_type_size_max);
6764 if(option_type_size_min > option_type_size_max) {
6784 std::string vtype = validator->get_description();
6785 if(!vtype.empty()) {
6786 full_type_name +=
":" + vtype;
6790 return full_type_name;
6793CLI11_INLINE
void Option::_validate_results(results_t &res)
const {
6805 for(std::string &result : res) {
6810 auto err_msg = _validate(result, (index >= 0) ? (index %
type_size_max_) : index);
6811 if(!err_msg.empty())
6812 throw ValidationError(
get_name(), err_msg);
6823 for(std::string &result : res) {
6824 auto err_msg = _validate(result, index);
6826 if(!err_msg.empty())
6827 throw ValidationError(
get_name(), err_msg);
6833CLI11_INLINE
void Option::_reduce_results(results_t &out,
const results_t &original)
const {
6841 case MultiOptionPolicy::TakeAll:
6843 case MultiOptionPolicy::TakeLast: {
6845 std::size_t trim_size = std::min<std::size_t>(
6847 if(original.size() != trim_size) {
6848 out.assign(original.end() -
static_cast<results_t::difference_type
>(trim_size), original.end());
6851 case MultiOptionPolicy::Reverse: {
6853 std::size_t trim_size = std::min<std::size_t>(
6855 if(original.size() != trim_size || trim_size > 1) {
6856 out.assign(original.end() -
static_cast<results_t::difference_type
>(trim_size), original.end());
6858 std::reverse(out.begin(), out.end());
6860 case MultiOptionPolicy::TakeFirst: {
6861 std::size_t trim_size = std::min<std::size_t>(
6863 if(original.size() != trim_size) {
6864 out.assign(original.begin(), original.begin() +
static_cast<results_t::difference_type
>(trim_size));
6867 case MultiOptionPolicy::Join:
6869 out.push_back(detail::join(original, std::string(1, (
delimiter_ ==
'\0') ?
'\n' :
delimiter_)));
6872 case MultiOptionPolicy::Sum:
6873 out.push_back(detail::sum_string_vector(original));
6875 case MultiOptionPolicy::Throw:
6885 if(original.size() < num_min) {
6886 throw ArgumentMismatch::AtLeast(
get_name(),
static_cast<int>(num_min), original.size());
6888 if(original.size() > num_max) {
6889 if(original.size() == 2 && num_max == 1 && original[1] ==
"%%" && original[0] ==
"{}") {
6894 throw ArgumentMismatch::AtMost(
get_name(),
static_cast<int>(num_max), original.size());
6904 out.emplace_back(
"{}");
6905 out.emplace_back(
"%%");
6908 out.emplace_back(
"%%");
6912CLI11_INLINE std::string Option::_validate(std::string &result,
int index)
const {
6913 std::string err_msg;
6919 auto v = vali->get_application_index();
6920 if(v == -1 || v == index) {
6922 err_msg = (*vali)(result);
6923 }
catch(
const ValidationError &err) {
6924 err_msg = err.what();
6926 if(!err_msg.empty())
6934CLI11_INLINE
int Option::_add_result(std::string &&result, std::vector<std::string> &res)
const {
6935 int result_count = 0;
6939 if(result.size() >= 4 && result[0] ==
'[' && result[1] ==
'[' && result.back() ==
']' &&
6940 (*(result.end() - 2) ==
']')) {
6942 std::string nstrs{
'['};
6943 bool duplicated{
true};
6944 for(std::size_t ii = 2; ii < result.size() - 2; ii += 2) {
6945 if(result[ii] == result[ii + 1]) {
6946 nstrs.push_back(result[ii]);
6953 nstrs.push_back(
']');
6954 res.push_back(std::move(nstrs));
6956 return result_count;
6961 result.front() ==
'[' &&
6962 result.back() ==
']') {
6965 result.erase(result.begin());
6966 bool skipSection{
false};
6967 for(
auto &var : CLI::detail::split_up(result,
',')) {
6969 result_count += _add_result(std::move(var), res);
6973 return result_count;
6977 res.push_back(std::move(result));
6980 if((result.find_first_of(
delimiter_) != std::string::npos)) {
6981 for(
const auto &var : CLI::detail::split(result,
delimiter_)) {
6988 res.push_back(std::move(result));
6992 return result_count;
6998#define CLI11_PARSE(app, ...) \
7000 (app).parse(__VA_ARGS__); \
7001 } catch(const CLI::ParseError &e) { \
7002 return (app).exit(e); \
7007enum class Classifier : std::uint8_t {
7014 SUBCOMMAND_TERMINATOR
7019namespace FailureMessage {
7021CLI11_INLINE std::string simple(
const App *app,
const Error &e);
7024CLI11_INLINE std::string help(
const App *app,
const Error &e);
7028enum class ExtrasMode : std::uint8_t {
7032 AssumeSingleArgument,
7033 AssumeMultipleArguments,
7038enum class ConfigExtrasMode : std::uint8_t {
Error = 0, Ignore, IgnoreAll, Capture };
7041enum class config_extras_mode : std::uint8_t { error = 0, ignore, ignore_all, capture };
7046enum class PrefixCommandMode : std::uint8_t { Off = 0, SeparatorOnly = 1, On = 2 };
7050using App_p = std::shared_ptr<App>;
7055template <typename T, enable_if_t<!std::is_integral<T>::value || (
sizeof(T) <= 1U), detail::enabler> = detail::dummy>
7056Option *default_flag_modifiers(Option *opt) {
7057 return opt->always_capture_default();
7061template <typename T, enable_if_t<std::is_integral<T>::value && (
sizeof(T) > 1U), detail::enabler> = detail::dummy>
7062Option *default_flag_modifiers(Option *opt) {
7063 return opt->multi_option_policy(MultiOptionPolicy::Sum)->default_str(
"0")->force_callback();
7169 using missing_t = std::vector<std::pair<detail::Classifier, std::string>>;
7228 enum class startup_mode : std::uint8_t { stable, enabled,
disabled };
7290 std::vector<std::string> normalized_argv_{};
7293 std::vector<char *> normalized_argv_view_{};
7297 App(std::string app_description, std::string app_name,
App *parent);
7304 explicit App(std::string app_description =
"", std::string app_name =
"")
7305 :
App(app_description, app_name, nullptr) {
7306 set_help_flag(
"-h,--help",
"Print this help message and exit");
7309 App(
const App &) =
delete;
7310 App &operator=(
const App &) =
delete;
7355 App *
name(std::string app_name =
"");
7362 allow_extras_ = allow ? ExtrasMode::Capture : ExtrasMode::Error;
7418 (
default_startup == startup_mode::disabled) ? startup_mode::disabled : startup_mode::stable;
7464 prefix_command_ = is_prefix ? PrefixCommandMode::On : PrefixCommandMode::Off;
7508 formatter_ = std::make_shared<FormatterLambda>(fmt);
7543 callback_t option_callback,
7544 std::string option_description =
"",
7545 bool defaulted =
false,
7546 std::function<std::string()> func = {});
7549 template <
typename AssignTo,
7550 typename ConvertTo = AssignTo,
7551 enable_if_t<!std::is_const<ConvertTo>::value, detail::enabler> = detail::dummy>
7554 std::string option_description =
"") {
7556 auto fun = [&variable](
const CLI::results_t &res) {
7557 return detail::lexical_conversion<AssignTo, ConvertTo>(res, variable);
7560 Option *opt =
add_option(option_name, fun, option_description,
false, [&variable]() {
7561 return CLI::detail::checked_to_string<AssignTo, ConvertTo>(variable);
7563 opt->
type_name(detail::type_name<ConvertTo>());
7566 auto Tcount = detail::type_count<AssignTo>::value;
7567 auto XCcount = detail::type_count<ConvertTo>::value;
7568 opt->
type_size(detail::type_count_min<ConvertTo>::value, (std::max)(Tcount, XCcount));
7569 opt->
expected(detail::expected_count<ConvertTo>::value);
7575 template <typename AssignTo, enable_if_t<!std::is_const<AssignTo>::value, detail::enabler> = detail::dummy>
7578 std::string option_description =
"") {
7580 auto fun = [&variable](
const CLI::results_t &res) {
7581 return detail::lexical_conversion<AssignTo, AssignTo>(res, variable);
7584 Option *opt =
add_option(option_name, fun, option_description,
false, []() {
return std::string{}; });
7585 opt->
type_name(detail::type_name<AssignTo>());
7586 opt->
type_size(detail::type_count_min<AssignTo>::value, detail::type_count<AssignTo>::value);
7587 opt->
expected(detail::expected_count<AssignTo>::value);
7593 template <
typename ArgType>
7595 const std::function<
void(
const ArgType &)> &func,
7596 std::string option_description =
"") {
7598 auto fun = [func](
const CLI::results_t &res) {
7600 bool result = detail::lexical_conversion<ArgType, ArgType>(res, variable);
7607 Option *opt =
add_option(option_name, std::move(fun), option_description,
false);
7608 opt->
type_name(detail::type_name<ArgType>());
7609 opt->
type_size(detail::type_count_min<ArgType>::value, detail::type_count<ArgType>::value);
7610 opt->
expected(detail::expected_count<ArgType>::value);
7616 return add_option(option_name, CLI::callback_t{}, std::string{},
false);
7620 template <
typename T,
7621 enable_if_t<std::is_const<T>::value && std::is_constructible<std::string, T>::value, detail::enabler> =
7623 Option *
add_option(std::string option_name, T &option_description) {
7624 return add_option(option_name, CLI::callback_t(), option_description,
false);
7628 Option *
set_help_flag(std::string flag_name =
"",
const std::string &help_description =
"");
7635 const std::string &versionString =
"",
7636 const std::string &version_help =
"Display program version information and exit");
7640 std::function<std::string()> vfunc,
7641 const std::string &version_help =
"Display program version information and exit");
7645 Option *_add_flag_internal(std::string flag_name, CLI::callback_t fun, std::string flag_description);
7649 Option *
add_flag(std::string flag_name) {
return _add_flag_internal(flag_name, CLI::callback_t(), std::string{}); }
7654 template <
typename T,
7655 enable_if_t<(std::is_const<typename std::remove_reference<T>::type>::value ||
7656 std::is_rvalue_reference<T &&>::value) &&
7657 std::is_constructible<std::string,
typename std::remove_reference<T>::type>::value,
7658 detail::enabler> = detail::dummy>
7659 Option *
add_flag(std::string flag_name, T &&flag_description) {
7660 return _add_flag_internal(flag_name, CLI::callback_t(), std::forward<T>(flag_description));
7665 template <
typename T,
7666 enable_if_t<!detail::is_mutable_container<T>::value && !std::is_const<T>::value &&
7667 !std::is_constructible<std::function<void(
int)>, T>::value,
7668 detail::enabler> = detail::dummy>
7671 std::string flag_description =
"") {
7673 CLI::callback_t fun = [&flag_result](
const CLI::results_t &res) {
7674 using CLI::detail::lexical_cast;
7675 return lexical_cast(res[0], flag_result);
7677 auto *opt = _add_flag_internal(flag_name, std::move(fun), std::move(flag_description));
7678 return detail::default_flag_modifiers<T>(opt);
7682 template <
typename T,
7683 enable_if_t<!std::is_assignable<std::function<void(std::int64_t)> &, T>::value, detail::enabler> =
7686 std::vector<T> &flag_results,
7687 std::string flag_description =
"") {
7688 CLI::callback_t fun = [&flag_results](
const CLI::results_t &res) {
7690 for(
const auto &elem : res) {
7691 using CLI::detail::lexical_cast;
7692 flag_results.emplace_back();
7693 retval &= lexical_cast(elem, flag_results.back());
7697 return _add_flag_internal(flag_name, std::move(fun), std::move(flag_description))
7704 std::function<
void(
void)> function,
7705 std::string flag_description =
"");
7709 std::function<
void(std::int64_t)> function,
7710 std::string flag_description =
"");
7715 std::function<
void(std::int64_t)> function,
7716 std::string flag_description =
"") {
7717 return add_flag_function(std::move(flag_name), std::move(function), std::move(flag_description));
7722 Option *
set_config(std::string option_name =
"",
7723 std::string default_filename =
"",
7724 const std::string &help_message =
"Read an ini file",
7725 bool config_required =
false);
7731 template <
typename T = Option_group>
7733 if(!detail::valid_alias_name_string(group_name)) {
7736 auto option_group = std::make_shared<T>(std::move(group_description), group_name,
this);
7737 auto *ptr = option_group.get();
7739 App_p app_ptr = std::static_pointer_cast<App>(option_group);
7741 app_ptr->footer_ =
"";
7742 app_ptr->set_help_flag();
7793 CLI11_NODISCARD std::size_t
count_all()
const;
7874 explicit operator bool()
const {
return parsed_ > 0; }
7894 void parse(
int argc,
const char *
const *argv);
7895 void parse(
int argc,
const wchar_t *
const *argv);
7898 template <
class CharT>
void parse_char_t(
int argc,
const CharT *
const *argv);
7905 void parse(std::string commandline,
bool program_name_included =
false);
7906 void parse(std::wstring commandline,
bool program_name_included =
false);
7910 void parse(std::vector<std::string> &args);
7913 void parse(std::vector<std::string> &&args);
7915 void parse_from_stream(std::istream &input);
7923 int exit(
const Error &e, std::ostream &out = std::cout, std::ostream &err = std::cerr)
const;
7938 std::vector<const App *>
get_subcommands(
const std::function<
bool(
const App *)> &filter)
const;
7953 return (sub !=
nullptr) ? (sub->
parsed_ > 0) :
false;
7958 if(opt ==
nullptr) {
7967 if(app ==
nullptr) {
7982 if(opt ==
nullptr) {
7990 if(app ==
nullptr) {
7991 throw OptionNotFound(
"nullptr passed");
7994 throw OptionNotFound(
"cannot self reference in needs");
8017 usage_ = std::move(usage_string);
8021 App *
usage(std::function<std::string()> usage_function) {
8027 footer_ = std::move(footer_string);
8037 CLI11_NODISCARD std::string
config_to_str(
bool default_also =
false,
bool write_description =
false)
const {
8043 CLI11_NODISCARD std::string
help(std::string prev =
"", AppFormatMode mode = AppFormatMode::Normal)
const;
8046 CLI11_NODISCARD std::string
version()
const;
8060#if CLI11_USE_STATIC_RTTI == 0
8077 std::vector<const Option *>
get_options(
const std::function<
bool(
const Option *)> filter = {})
const;
8080 std::vector<Option *>
get_options(
const std::function<
bool(Option *)> filter = {});
8086 CLI11_NODISCARD
const Option *
get_option_no_throw(std::string option_name)
const noexcept;
8089 CLI11_NODISCARD
const Option *
get_option(std::string option_name)
const {
8091 if(opt ==
nullptr) {
8100 if(opt ==
nullptr) {
8243 CLI11_NODISCARD std::string
get_display_name(
bool with_aliases =
false)
const;
8247 CLI11_NODISCARD
bool check_name(std::string name_to_check)
const;
8250 enum class NameMatch : std::uint8_t { none = 0, exact = 1, prefix = 2 };
8258 CLI11_NODISCARD std::vector<std::string>
get_groups()
const;
8264 CLI11_NODISCARD std::vector<std::string>
remaining(
bool recurse =
false)
const;
8270 CLI11_NODISCARD std::size_t
remaining_size(
bool recurse =
false)
const;
8287 void run_callback(
bool final_mode =
false,
bool suppress_final_callback =
false);
8290 CLI11_NODISCARD
bool _valid_subcommand(
const std::string ¤t,
bool ignore_used =
true)
const;
8293 CLI11_NODISCARD detail::Classifier
_recognize(
const std::string ¤t,
8294 bool ignore_used_subcommands =
true)
const;
8313 void _process_help_flags(CallbackPriority priority,
bool trigger_help =
false,
bool trigger_all_help =
false)
const;
8328 void _parse(std::vector<std::string> &args);
8331 void _parse(std::vector<std::string> &&args);
8350 bool _parse_single(std::vector<std::string> &args,
bool &positional_only);
8365 CLI11_NODISCARD
App *
8366 _find_subcommand(
const std::string &subc_name,
bool ignore_disabled,
bool ignore_used)
const noexcept;
8377 bool _parse_arg(std::vector<std::string> &args, detail::Classifier current_type,
bool local_processing_only);
8392 void _move_to_missing(detail::Classifier val_type, const std::
string &val);
8400class Option_group : public
App {
8402 Option_group(std::string group_description, std::string group_name,
App *parent)
8403 :
App(std::move(group_description),
"", parent) {
8406 if(group_name.empty() || group_name.front() ==
'+') {
8424 template <
typename... Args>
void add_options(Option *opt, Args... args) {
8432 subc->get_parent()->remove_subcommand(subcom);
8439CLI11_INLINE
void TriggerOn(
App *trigger_app,
App *app_to_enable);
8442CLI11_INLINE
void TriggerOn(
App *trigger_app, std::vector<App *> apps_to_enable);
8445CLI11_INLINE
void TriggerOff(
App *trigger_app,
App *app_to_enable);
8448CLI11_INLINE
void TriggerOff(
App *trigger_app, std::vector<App *> apps_to_enable);
8451CLI11_INLINE
void deprecate_option(Option *opt,
const std::string &replacement =
"");
8454inline void deprecate_option(
App *app,
const std::string &option_name,
const std::string &replacement =
"") {
8455 auto *opt = app->get_option(option_name);
8456 deprecate_option(opt, replacement);
8460inline void deprecate_option(
App &app,
const std::string &option_name,
const std::string &replacement =
"") {
8461 auto *opt = app.get_option(option_name);
8462 deprecate_option(opt, replacement);
8466CLI11_INLINE
void retire_option(
App *app, Option *opt);
8469CLI11_INLINE
void retire_option(
App &app, Option *opt);
8472CLI11_INLINE
void retire_option(
App *app,
const std::string &option_name);
8475CLI11_INLINE
void retire_option(
App &app,
const std::string &option_name);
8483 template <
typename... Args>
static decltype(
auto)
parse_arg(
App *app, Args &&...args) {
8484 return app->
_parse_arg(std::forward<Args>(args)...);
8488 template <
typename... Args>
static decltype(
auto)
parse_subcommand(
App *app, Args &&...args) {
8493 template <
typename... Args>
8496 return app->
_parse_arg(std::forward<Args>(args)...);
8500 template <
typename... Args>
8517CLI11_INLINE
App::App(std::string app_description, std::string app_name,
App *parent)
8521 if(
parent_->help_ptr_ !=
nullptr)
8523 if(
parent_->help_all_ptr_ !=
nullptr)
8556 normalized_argv_ = detail::compute_win32_argv();
8558 if(!normalized_argv_view_.empty()) {
8559 normalized_argv_view_.clear();
8562 normalized_argv_view_.reserve(normalized_argv_.size());
8563 for(
auto &arg : normalized_argv_) {
8565 normalized_argv_view_.push_back(
const_cast<char *
>(arg.data()));
8568 return normalized_argv_view_.data();
8577 std::string oname =
name_;
8592 if(app_name.empty() || !detail::valid_alias_name_string(app_name)) {
8600 throw(
OptionAlreadyAdded(
"alias already matches an existing subcommand: " + app_name));
8626 if(!match.empty()) {
8628 throw OptionAlreadyAdded(
"ignore case would cause subcommand name conflicts: " + match);
8640 if(!match.empty()) {
8642 throw OptionAlreadyAdded(
"ignore underscore would cause subcommand name conflicts: " + match);
8650 callback_t option_callback,
8651 std::string option_description,
8653 std::function<std::string()> func) {
8658 std::find_if(std::begin(
options_), std::end(
options_), [&myopt](
const Option_p &v) {
return *v == myopt; });
8660 const auto &matchname = (*res)->matching_name(myopt);
8661 throw(
OptionAlreadyAdded(
"added option matched existing option name: " + matchname));
8664 const App *top_level_parent =
this;
8665 while(top_level_parent->
name_.empty() && top_level_parent->
parent_ !=
nullptr) {
8666 top_level_parent = top_level_parent->
parent_;
8673 if(test_name.size() == 3) {
8674 test_name.erase(0, 1);
8678 if(op !=
nullptr && op->get_configurable()) {
8679 throw(
OptionAlreadyAdded(
"added option positional name matches existing option: " + test_name));
8684 if(op !=
nullptr && op->lnames_.empty() && op->snames_.empty()) {
8685 throw(
OptionAlreadyAdded(
"unable to disambiguate with existing option: " + test_name));
8687 }
else if(top_level_parent !=
this) {
8688 for(
auto &ln : myopt.
lnames_) {
8690 if(op !=
nullptr && op->get_configurable()) {
8694 if(op !=
nullptr && op->get_configurable()) {
8699 if(op !=
nullptr && op->get_configurable()) {
8704 for(
auto &sn : myopt.
snames_) {
8706 if(op !=
nullptr && op->get_configurable()) {
8710 if(op !=
nullptr && op->get_configurable()) {
8714 if(op !=
nullptr && op->get_configurable()) {
8721 for(
auto &sname : myopt.
snames_) {
8722 if(sname.length() > 1) {
8723 std::string test_name;
8724 test_name.push_back(
'-');
8725 test_name.push_back(sname.front());
8728 throw(
OptionAlreadyAdded(
"added option interferes with existing short option: " + sname));
8732 for(
auto &opt : top_level_parent->
get_options()) {
8733 for(
const auto &osn : opt->
snames_) {
8734 if(osn.size() > 1) {
8735 std::string test_name;
8736 test_name.push_back(osn.front());
8738 throw(
OptionAlreadyAdded(
"added option interferes with existing non standard option: " + osn));
8745 Option_p &option =
options_.back();
8749 option->default_function(func);
8753 option->capture_default_str();
8759 if(!defaulted && option->get_always_capture_default())
8760 option->capture_default_str();
8762 return option.get();
8773 if(!flag_name.empty()) {
8775 help_ptr_->configurable(
false)->callback_priority(CallbackPriority::First);
8789 if(!help_name.empty()) {
8791 help_all_ptr_->configurable(
false)->callback_priority(CallbackPriority::First);
8806 if(!flag_name.empty()) {
8808 flag_name, [versionString]() {
throw(
CLI::CallForVersion(versionString, 0)); }, version_help);
8809 version_ptr_->configurable(
false)->callback_priority(CallbackPriority::First);
8823 if(!flag_name.empty()) {
8826 version_ptr_->configurable(
false)->callback_priority(CallbackPriority::First);
8832CLI11_INLINE
Option *App::_add_flag_internal(std::string flag_name, CLI::callback_t fun, std::string flag_description) {
8834 if(detail::has_default_flag_values(flag_name)) {
8836 auto flag_defaults = detail::get_default_flag_values(flag_name);
8837 detail::remove_default_flag_values(flag_name);
8838 opt =
add_option(std::move(flag_name), std::move(fun), std::move(flag_description),
false);
8839 for(
const auto &fname : flag_defaults)
8840 opt->
fnames_.push_back(fname.first);
8843 opt =
add_option(std::move(flag_name), std::move(fun), std::move(flag_description),
false);
8847 auto pos_name = opt->
get_name(
true);
8849 throw IncorrectConstruction::PositionalFlag(pos_name);
8858 std::function<
void(
void)> function,
8859 std::string flag_description) {
8861 CLI::callback_t fun = [function](
const CLI::results_t &res) {
8862 using CLI::detail::lexical_cast;
8863 bool trigger{
false};
8864 auto result = lexical_cast(res[0], trigger);
8865 if(result && trigger) {
8870 return _add_flag_internal(flag_name, std::move(fun), std::move(flag_description));
8875 std::function<
void(std::int64_t)> function,
8876 std::string flag_description) {
8878 CLI::callback_t fun = [function](
const CLI::results_t &res) {
8879 using CLI::detail::lexical_cast;
8880 std::int64_t flag_count{0};
8881 lexical_cast(res[0], flag_count);
8882 function(flag_count);
8885 return _add_flag_internal(flag_name, std::move(fun), std::move(flag_description))
8890 std::string default_filename,
8891 const std::string &help_message,
8892 bool config_required) {
8901 if(!option_name.empty()) {
8903 if(config_required) {
8906 if(!default_filename.empty()) {
8907 config_ptr_->default_str(std::move(default_filename));
8912 config_ptr_->multi_option_policy(MultiOptionPolicy::Reverse);
8921 op->remove_needs(opt);
8922 op->remove_excludes(opt);
8933 std::find_if(std::begin(
options_), std::end(
options_), [opt](
const Option_p &v) {
return v.get() == opt; });
8934 if(iterator != std::end(
options_)) {
8942 if(!subcommand_name.empty() && !detail::valid_name_string(subcommand_name)) {
8943 if(!detail::valid_first_char(subcommand_name[0])) {
8945 "Subcommand name starts with invalid character, '!' and '-' and control characters");
8947 for(
auto c : subcommand_name) {
8948 if(!detail::valid_later_char(c)) {
8950 "'), all characters are allowed except"
8951 "'=',':','{','}', ' ', and control characters");
8955 CLI::App_p subcom = std::shared_ptr<App>(
new App(std::move(subcommand_description), subcommand_name,
this));
8964 if(!mstrg.empty()) {
8965 throw(
OptionAlreadyAdded(
"subcommand name or alias matches existing subcommand: " + mstrg));
8967 subcom->parent_ =
this;
8975 sub->remove_excludes(subcom);
8976 sub->remove_needs(subcom);
8979 auto iterator = std::find_if(
8989 if(subcom ==
nullptr)
8992 if(subcomptr.get() == subcom)
8993 return subcomptr.get();
9010 auto uindex =
static_cast<unsigned>(index);
9018 if(subcom ==
nullptr)
9021 if(subcomptr.get() == subcom)
9028 if(subcomptr->check_name(subcom))
9035 auto uindex =
static_cast<unsigned>(index);
9044 if(app->
name_.empty() && app->
group_ == group_name) {
9054 cnt += opt->
count();
9057 cnt += sub->count_all();
9073 for(
const Option_p &opt :
options_) {
9081CLI11_INLINE
void App::parse(
int argc,
const char *
const *argv) { parse_char_t(argc, argv); }
9082CLI11_INLINE
void App::parse(
int argc,
const wchar_t *
const *argv) { parse_char_t(argc, argv); }
9087CLI11_INLINE
const char *maybe_narrow(
const char *str) {
return str; }
9088CLI11_INLINE std::string maybe_narrow(
const wchar_t *str) {
return narrow(str); }
9092template <
class CharT> CLI11_INLINE
void App::parse_char_t(
int argc,
const CharT *
const *argv) {
9096 name_ = detail::maybe_narrow(argv[0]);
9099 std::vector<std::string> args;
9100 args.reserve(
static_cast<std::size_t
>(argc) - 1U);
9101 for(
auto i =
static_cast<std::size_t
>(argc) - 1U; i > 0U; --i)
9102 args.emplace_back(detail::maybe_narrow(argv[i]));
9104 parse(std::move(args));
9107CLI11_INLINE
void App::parse(std::string commandline,
bool program_name_included) {
9109 if(program_name_included) {
9110 auto nstr = detail::split_program_name(commandline);
9115 commandline = std::move(nstr.second);
9117 detail::trim(commandline);
9120 if(!commandline.empty()) {
9121 commandline = detail::find_and_modify(commandline,
"=", detail::escape_detect);
9123 commandline = detail::find_and_modify(commandline,
":", detail::escape_detect);
9126 auto args = detail::split_up(std::move(commandline));
9128 args.erase(std::remove(args.begin(), args.end(), std::string{}), args.end());
9130 detail::remove_quotes(args);
9131 }
catch(
const std::invalid_argument &arg) {
9134 std::reverse(args.begin(), args.end());
9135 parse(std::move(args));
9138CLI11_INLINE
void App::parse(std::wstring commandline,
bool program_name_included) {
9139 parse(narrow(commandline), program_name_included);
9180CLI11_INLINE
void App::parse_from_stream(std::istream &input) {
9191CLI11_INLINE
int App::exit(
const Error &e, std::ostream &out, std::ostream &err)
const {
9194 if(e.get_name() ==
"RuntimeError")
9195 return e.get_exit_code();
9197 if(e.get_name() ==
"CallForHelp") {
9199 return e.get_exit_code();
9202 if(e.get_name() ==
"CallForAllHelp") {
9203 out <<
help(
"", AppFormatMode::All);
9204 return e.get_exit_code();
9207 if(e.get_name() ==
"CallForVersion") {
9208 out << e.what() <<
'\n';
9209 return e.get_exit_code();
9212 if(e.get_exit_code() !=
static_cast<int>(ExitCodes::Success)) {
9217 return e.get_exit_code();
9221 std::vector<const App *> subcomms(
subcommands_.size());
9226 subcomms.erase(std::remove_if(std::begin(subcomms),
9228 [&filter](
const App *app) {
return !filter(app); }),
9229 std::end(subcomms));
9242 std::remove_if(std::begin(subcomms), std::end(subcomms), [&filter](
App *app) {
return !filter(app); }),
9243 std::end(subcomms));
9263 auto *other_app = *iterator;
9265 other_app->remove_excludes(
this);
9287CLI11_NODISCARD CLI11_INLINE std::string
App::help(std::string prev, AppFormatMode mode)
const {
9295 if(!selected_subcommands.empty()) {
9296 return selected_subcommands.back()->help(prev, mode);
9298 return formatter_->make_help(
this, prev, mode);
9319CLI11_INLINE std::vector<const Option *>
App::get_options(
const std::function<
bool(
const Option *)> filter)
const {
9320 std::vector<const Option *> options(
options_.size());
9322 std::begin(
options_), std::end(
options_), std::begin(options), [](
const Option_p &val) {
return val.get(); });
9325 options.erase(std::remove_if(std::begin(options),
9327 [&filter](
const Option *opt) {
return !filter(opt); }),
9332 const App *subc = subcp.get();
9334 std::vector<const Option *> subcopts = subc->
get_options(filter);
9335 options.insert(options.end(), subcopts.begin(), subcopts.end());
9340 std::vector<const Option *> subcopts = fallthrough_parent->get_options(filter);
9341 for(
const auto *opt : subcopts) {
9342 if(std::find_if(options.begin(), options.end(), [opt](
const Option *opt2) {
9343 return opt->check_name(opt2->get_name());
9344 }) == options.end()) {
9345 options.push_back(opt);
9352CLI11_INLINE std::vector<Option *>
App::get_options(
const std::function<
bool(Option *)> filter) {
9353 std::vector<Option *> options(
options_.size());
9355 std::begin(
options_), std::end(
options_), std::begin(options), [](
const Option_p &val) {
return val.get(); });
9359 std::remove_if(std::begin(options), std::end(options), [&filter](Option *opt) {
return !filter(opt); }),
9364 if(subc->get_name().empty() || (!subc->get_group().empty() && subc->get_group().front() ==
'+')) {
9365 auto subcopts = subc->get_options(filter);
9366 options.insert(options.end(), subcopts.begin(), subcopts.end());
9371 std::vector<Option *> subcopts = fallthrough_parent->get_options(filter);
9372 for(
auto *opt : subcopts) {
9373 if(std::find_if(options.begin(), options.end(), [opt](Option *opt2) {
9374 return opt->check_name(opt2->get_name());
9375 }) == options.end()) {
9376 options.push_back(opt);
9391 if(subc->get_name().empty()) {
9392 auto *opt = subc->get_option_no_throw(option_name);
9393 if(opt !=
nullptr) {
9405 for(
const Option_p &opt :
options_) {
9412 if(subc->get_name().empty()) {
9413 auto *opt = subc->get_option_no_throw(option_name);
9414 if(opt !=
nullptr) {
9427 return std::string(
"[Option Group: ") +
get_group() +
"]";
9429 if(
aliases_.empty() || !with_aliases) {
9432 std::string dispname =
name_;
9433 for(
const auto &lalias :
aliases_) {
9434 dispname.push_back(
',');
9435 dispname.push_back(
' ');
9436 dispname.append(lalias);
9443 return (result != NameMatch::none);
9447 std::string local_name =
name_;
9449 local_name = detail::remove_underscore(
name_);
9450 name_to_check = detail::remove_underscore(name_to_check);
9453 local_name = detail::to_lower(
name_);
9454 name_to_check = detail::to_lower(name_to_check);
9457 if(local_name == name_to_check) {
9458 return App::NameMatch::exact;
9461 if(local_name.compare(0, name_to_check.size(), name_to_check) == 0) {
9462 return App::NameMatch::prefix;
9467 les = detail::remove_underscore(les);
9470 les = detail::to_lower(les);
9472 if(les == name_to_check) {
9473 return App::NameMatch::exact;
9476 if(les.compare(0, name_to_check.size(), name_to_check) == 0) {
9477 return App::NameMatch::prefix;
9481 return App::NameMatch::none;
9485 std::vector<std::string> groups;
9487 for(
const Option_p &opt :
options_) {
9489 if(std::find(groups.begin(), groups.end(), opt->
get_group()) == groups.end()) {
9497CLI11_NODISCARD CLI11_INLINE std::vector<std::string>
App::remaining(
bool recurse)
const {
9498 std::vector<std::string> miss_list;
9499 for(
const std::pair<detail::Classifier, std::string> &miss :
missing_) {
9500 miss_list.push_back(std::get<1>(miss));
9506 if(sub->name_.empty() && !sub->missing_.empty()) {
9507 for(
const std::pair<detail::Classifier, std::string> &miss : sub->missing_) {
9508 miss_list.push_back(std::get<1>(miss));
9516 std::vector<std::string> output = sub->remaining(recurse);
9517 std::copy(std::begin(output), std::end(output), std::back_inserter(miss_list));
9524 std::vector<std::string> miss_list =
remaining(recurse);
9525 std::reverse(std::begin(miss_list), std::end(miss_list));
9530 auto remaining_options =
static_cast<std::size_t
>(std::count_if(
9531 std::begin(
missing_), std::end(
missing_), [](
const std::pair<detail::Classifier, std::string> &val) {
9532 return val.first != detail::Classifier::POSITIONAL_MARK;
9537 remaining_options += sub->remaining_size(recurse);
9540 return remaining_options;
9545 auto pcount = std::count_if(std::begin(
options_), std::end(
options_), [](
const Option_p &opt) {
9546 return opt->get_items_expected_max() >= detail::expected_max_vector_size && !opt->nonpositional();
9549 auto pcount_req = std::count_if(std::begin(
options_), std::end(
options_), [](
const Option_p &opt) {
9550 return opt->get_items_expected_max() >= detail::expected_max_vector_size && !opt->nonpositional() &&
9551 opt->get_required();
9553 if(pcount - pcount_req > 1) {
9558 std::size_t nameless_subs{0};
9568 throw(
InvalidError(
"Required min options greater than required max options", ExitCodes::InvalidError));
9573 InvalidError(
"Required min options greater than number of available options", ExitCodes::InvalidError));
9588 if(app->
name_.empty()) {
9606 if(subc->parent_ ==
this) {
9607 subc->run_callback(
true, suppress_final_callback);
9612 if(subc->name_.empty() && subc->count_all() > 0) {
9613 subc->run_callback(
true, suppress_final_callback);
9629 return parent_ !=
nullptr &&
parent_->_valid_subcommand(current, ignore_used);
9632 if(com !=
nullptr) {
9637 return parent_ !=
nullptr &&
parent_->_valid_subcommand(current, ignore_used);
9642CLI11_NODISCARD CLI11_INLINE detail::Classifier
App::_recognize(
const std::string ¤t,
9643 bool ignore_used_subcommands)
const {
9644 std::string dummy1, dummy2;
9647 return detail::Classifier::POSITIONAL_MARK;
9649 return detail::Classifier::SUBCOMMAND;
9650 if(detail::split_long(current, dummy1, dummy2))
9651 return detail::Classifier::LONG;
9652 if(detail::split_short(current, dummy1, dummy2)) {
9653 if((dummy1[0] >=
'0' && dummy1[0] <=
'9') ||
9654 (dummy1[0] ==
'.' && !dummy2.empty() && (dummy2[0] >=
'0' && dummy2[0] <=
'9'))) {
9657 return detail::Classifier::NONE;
9660 return detail::Classifier::SHORT;
9663 return detail::Classifier::WINDOWS_STYLE;
9664 if((current ==
"++") && !
name_.empty() &&
parent_ !=
nullptr)
9665 return detail::Classifier::SUBCOMMAND_TERMINATOR;
9666 auto dotloc = current.find_first_of(
'.');
9667 if(dotloc != std::string::npos) {
9668 auto *cm =
_find_subcommand(current.substr(0, dotloc),
true, ignore_used_subcommands);
9670 auto res = cm->_recognize(current.substr(dotloc + 1), ignore_used_subcommands);
9671 if(res == detail::Classifier::SUBCOMMAND) {
9676 return detail::Classifier::NONE;
9680 auto path_result = detail::check_path(config_file.c_str());
9681 if(path_result == detail::path_type::file) {
9692 }
else if(throw_error) {
9693 throw FileError::Missing(config_file);
9701 bool config_required =
config_ptr_->get_required();
9703 if(!(file_given ||
config_ptr_->envname_.empty())) {
9704 std::string ename_string = detail::get_environment_value(
config_ptr_->envname_);
9705 if(!ename_string.empty()) {
9711 auto config_files =
config_ptr_->as<std::vector<std::string>>();
9712 bool files_used{file_given};
9713 if(config_files.empty() || config_files.front().empty()) {
9714 if(config_required) {
9715 throw FileError(
"config file is required but none was given");
9719 for(
const auto &config_file : config_files) {
9736 for(
const Option_p &opt :
options_) {
9738 std::string ename_string = detail::get_environment_value(opt->
envname_);
9739 if(!ename_string.empty()) {
9740 std::string result = ename_string;
9741 result = opt->_validate(result, 0);
9742 if(result.empty()) {
9750 if(sub->get_name().empty() || (sub->count_all() > 0 && !sub->parse_complete_callback_)) {
9752 sub->_process_env();
9761 if(sub->get_name().empty() && sub->parse_complete_callback_) {
9762 if(sub->count_all() > 0) {
9763 sub->_process_callbacks(priority);
9764 if(priority == CallbackPriority::Normal) {
9766 sub->run_callback();
9772 for(
const Option_p &opt :
options_) {
9780 if(!sub->parse_complete_callback_) {
9781 sub->_process_callbacks(priority);
9791 trigger_help =
true;
9794 trigger_all_help =
true;
9800 sub->_process_help_flags(priority, trigger_help, trigger_all_help);
9804 }
else if(trigger_all_help) {
9806 }
else if(trigger_help) {
9813 bool excluded{
false};
9814 std::string excluder;
9816 if(opt->
count() > 0) {
9822 if(subc->count_all() > 0) {
9824 excluder = subc->get_display_name();
9836 bool missing_needed{
false};
9837 std::string missing_need;
9839 if(opt->
count() == 0) {
9840 missing_needed =
true;
9845 if(subc->count_all() == 0) {
9846 missing_needed =
true;
9847 missing_need = subc->get_display_name();
9850 if(missing_needed) {
9858 std::size_t used_options = 0;
9859 for(
const Option_p &opt :
options_) {
9861 if(opt->
count() != 0) {
9869 for(
const Option *opt_req : opt->
needs_)
9870 if(opt->
count() > 0 && opt_req->
count() == 0)
9873 for(
const Option *opt_ex : opt->
excludes_)
9891 if(sub->name_.empty() && sub->count_all() > 0) {
9897 auto option_list = detail::join(
options_, [
this](
const Option_p &ptr) {
9899 return std::string{};
9901 return ptr->get_name(
false,
true);
9905 if(!subc_list.empty()) {
9906 option_list +=
"," + detail::join(subc_list, [](
const App *app) {
return app->
get_display_name(); });
9915 if(sub->name_.empty() && sub->required_ ==
false) {
9916 if(sub->count_all() == 0) {
9929 if(sub->count() > 0 || sub->name_.empty()) {
9930 sub->_process_requirements();
9933 if(sub->required_ && sub->count_all() == 0) {
9946 std::exception_ptr config_exception;
9955 config_exception = std::current_exception();
9969 if(config_exception) {
9970 std::rethrow_exception(config_exception);
9981 if(num_left_over > 0) {
9987 if(num_left_over > 0) {
9994 if(sub->count() > 0)
9995 sub->_process_extras();
10002 if(sub->get_name().empty())
10003 sub->increment_parsed();
10010 bool positional_only =
false;
10012 while(!args.empty()) {
10049 bool positional_only =
false;
10051 while(!args.empty()) {
10074 throw ConfigError::Extras(item.fullname());
10080 if(item.
inputs.size() <= 1) {
10083 bool converted{
false};
10085 auto val = detail::to_flag_value(res);
10110 throw ConversionError::TooManyInputsFlag(item.
fullname());
10114 for(
const auto &res : inputs) {
10115 bool valid_value{
false};
10117 if(res ==
"true" || res ==
"false" || res ==
"1" || res ==
"0") {
10118 valid_value =
true;
10122 if(valid_res.second == res) {
10123 valid_value =
true;
10142 if(level < item.
parents.size()) {
10144 return (subcom !=
nullptr) ? subcom->_parse_single_config(item, level + 1) :
false;
10147 if(item.
name ==
"++") {
10152 parent_->parsed_subcommands_.push_back(
this);
10158 if(item.
name ==
"--") {
10174 if(op ==
nullptr) {
10175 if(item.
name.size() == 1) {
10178 if(op ==
nullptr) {
10182 if(item.
name.size() == 1) {
10184 if(testop !=
nullptr && testop->get_configurable()) {
10190 std::string iname = item.
name;
10195 if(!options.empty()) {
10199 if(op ==
nullptr) {
10204 for(
const auto &input : item.
inputs) {
10205 missing_.emplace_back(detail::Classifier::NONE, input);
10215 throw ConfigError::NotConfigurable(item.
fullname());
10218 std::vector<std::string> buffer;
10219 bool useBuffer{
false};
10223 buffer.erase(std::remove(buffer.begin(), buffer.end(),
"%%"), buffer.end());
10227 const std::vector<std::string> &inputs = (useBuffer) ? buffer : item.
inputs;
10241 bool retval =
true;
10242 detail::Classifier classifier = positional_only ? detail::Classifier::NONE :
_recognize(args.back());
10243 switch(classifier) {
10244 case detail::Classifier::POSITIONAL_MARK:
10246 positional_only =
true;
10249 missing_.emplace_back(classifier,
"--");
10250 while(!args.empty()) {
10251 missing_.emplace_back(detail::Classifier::NONE, args.back());
10260 case detail::Classifier::SUBCOMMAND_TERMINATOR:
10265 case detail::Classifier::SUBCOMMAND:
10268 case detail::Classifier::LONG:
10269 case detail::Classifier::SHORT:
10270 case detail::Classifier::WINDOWS_STYLE:
10272 retval =
_parse_arg(args, classifier,
false);
10274 case detail::Classifier::NONE:
10278 positional_only =
true;
10283 throw HorribleError(
"unrecognized classifier (you should not see this!)");
10290 std::size_t retval = 0;
10291 for(
const Option_p &opt :
options_) {
10302 for(
const Option_p &opt :
options_) {
10313 const std::string &positional = args.back();
10314 Option *posOpt{
nullptr};
10318 auto arg_rem = args.size();
10320 if(arg_rem <= remreq) {
10321 for(
const Option_p &opt :
options_) {
10325 std::string pos = positional;
10326 pos = opt->_validate(pos, 0);
10331 posOpt = opt.get();
10338 if(posOpt ==
nullptr) {
10339 for(
const Option_p &opt :
options_) {
10344 std::string pos = positional;
10345 pos = opt->_validate(pos, 0);
10350 posOpt = opt.get();
10355 if(posOpt !=
nullptr) {
10358 if(!posOpt->
results().empty() && !posOpt->
results().back().empty()) {
10370 item.
inputs.push_back(positional);
10378 if(!posOpt->
empty()) {
10381 if(!prev.empty()) {
10392 if((subc->name_.empty()) && (!subc->disabled_)) {
10393 if(subc->_parse_positional(args,
false)) {
10394 if(!subc->pre_parse_called_) {
10395 subc->_trigger_pre_parse(args.size());
10408 if(haltOnSubcommand) {
10420 if(com !=
nullptr && (com->parent_->require_subcommand_max_ == 0 ||
10421 com->parent_->require_subcommand_max_ > com->parent_->parsed_subcommands_.size())) {
10426 std::vector<std::string> rargs;
10427 rargs.resize(args.size());
10428 std::reverse_copy(args.begin(), args.end(), rargs.begin());
10439 while(!args.empty()) {
10440 missing_.emplace_back(detail::Classifier::NONE, args.back());
10448CLI11_NODISCARD CLI11_INLINE
App *
10450 App *bcom{
nullptr};
10452 if(com->disabled_ && ignore_disabled)
10454 if(com->get_name().empty()) {
10455 auto *subc = com->_find_subcommand(subc_name, ignore_disabled, ignore_used);
10456 if(subc !=
nullptr) {
10457 if(bcom !=
nullptr) {
10466 auto res = com->check_name_detail(subc_name);
10467 if(res != NameMatch::none) {
10468 if((!*com) || !ignore_used) {
10469 if(res == NameMatch::exact) {
10472 if(bcom !=
nullptr) {
10491 if(com ==
nullptr) {
10493 auto dotloc = args.back().find_first_of(
'.');
10494 if(dotloc != std::string::npos) {
10496 if(com !=
nullptr) {
10497 args.back() = args.back().substr(dotloc + 1);
10498 args.push_back(com->get_display_name());
10502 if(com !=
nullptr) {
10504 if(!com->silent_) {
10508 auto *parent_app = com->parent_;
10509 while(parent_app !=
this) {
10510 parent_app->_trigger_pre_parse(args.size());
10511 if(!com->silent_) {
10512 parent_app->parsed_subcommands_.push_back(com);
10514 parent_app = parent_app->parent_;
10520 throw HorribleError(
"Subcommand " + args.back() +
" missing");
10525App::_parse_arg(std::vector<std::string> &args, detail::Classifier current_type,
bool local_processing_only) {
10527 std::string current = args.back();
10529 std::string arg_name;
10533 switch(current_type) {
10534 case detail::Classifier::LONG:
10535 if(!detail::split_long(current, arg_name, value))
10536 throw HorribleError(
"Long parsed but missing (you should not see this):" + args.back());
10538 case detail::Classifier::SHORT:
10539 if(!detail::split_short(current, arg_name, rest))
10540 throw HorribleError(
"Short parsed but missing! You should not see this");
10542 case detail::Classifier::WINDOWS_STYLE:
10543 if(!detail::split_windows_style(current, arg_name, value))
10544 throw HorribleError(
"windows option parsed but missing! You should not see this");
10546 case detail::Classifier::SUBCOMMAND:
10547 case detail::Classifier::SUBCOMMAND_TERMINATOR:
10548 case detail::Classifier::POSITIONAL_MARK:
10549 case detail::Classifier::NONE:
10551 throw HorribleError(
"parsing got called with invalid option! You should not see this");
10554 auto op_ptr = std::find_if(std::begin(
options_), std::end(
options_), [arg_name, current_type](
const Option_p &opt) {
10555 if(current_type == detail::Classifier::LONG)
10556 return opt->check_lname(arg_name);
10557 if(current_type == detail::Classifier::SHORT)
10558 return opt->check_sname(arg_name);
10560 return opt->check_lname(arg_name) || opt->check_sname(arg_name);
10564 while(op_ptr == std::end(
options_)) {
10567 if(subc->name_.empty() && !subc->disabled_) {
10568 if(subc->_parse_arg(args, current_type, local_processing_only)) {
10569 if(!subc->pre_parse_called_) {
10570 subc->_trigger_pre_parse(args.size());
10577 std::string narg_name;
10578 std::string nvalue;
10579 detail::split_long(std::string{
'-'} + current, narg_name, nvalue);
10580 op_ptr = std::find_if(std::begin(
options_), std::end(
options_), [narg_name](
const Option_p &opt) {
10581 return opt->check_sname(narg_name);
10583 if(op_ptr != std::end(
options_)) {
10584 arg_name = narg_name;
10597 auto dotloc = arg_name.find_first_of(
'.', 1);
10598 if(dotloc != std::string::npos && dotloc < arg_name.size() - 1) {
10601 if(sub !=
nullptr) {
10602 std::string v = args.back();
10604 arg_name = arg_name.substr(dotloc + 1);
10605 if(arg_name.size() > 1) {
10606 args.push_back(std::string(
"--") + v.substr(dotloc + 3));
10607 current_type = detail::Classifier::LONG;
10609 auto nval = v.substr(dotloc + 2);
10610 nval.front() =
'-';
10611 if(nval.size() > 2) {
10613 args.push_back(nval.substr(3));
10616 args.push_back(nval);
10617 current_type = detail::Classifier::SHORT;
10619 std::string dummy1, dummy2;
10621 if((current_type == detail::Classifier::SHORT && detail::valid_first_char(args.back()[1])) ||
10622 detail::split_long(args.back(), dummy1, dummy2)) {
10623 val = sub->_parse_arg(args, current_type,
true);
10627 if(!sub->silent_) {
10634 if(sub->parse_complete_callback_) {
10635 sub->_process_callbacks(CallbackPriority::FirstPreHelp);
10636 sub->_process_help_flags(CallbackPriority::First);
10637 sub->_process_callbacks(CallbackPriority::First);
10638 sub->_process_env();
10639 sub->_process_callbacks(CallbackPriority::PreRequirementsCheckPreHelp);
10640 sub->_process_help_flags(CallbackPriority::PreRequirementsCheck);
10641 sub->_process_callbacks(CallbackPriority::PreRequirementsCheck);
10642 sub->_process_requirements();
10643 sub->_process_callbacks(CallbackPriority::NormalPreHelp);
10644 sub->_process_help_flags(CallbackPriority::Normal);
10645 sub->_process_callbacks(CallbackPriority::Normal);
10646 sub->_process_callbacks(CallbackPriority::LastPreHelp);
10647 sub->_process_help_flags(CallbackPriority::Last);
10648 sub->_process_callbacks(CallbackPriority::Last);
10649 sub->run_callback(
false,
true);
10657 if(local_processing_only) {
10668 while(!args.empty()) {
10669 missing_.emplace_back(detail::Classifier::NONE, args.back());
10672 }
else if(
allow_extras_ == ExtrasMode::AssumeSingleArgument) {
10673 if(!args.empty() &&
_recognize(args.back(),
false) == detail::Classifier::NONE) {
10677 }
else if(
allow_extras_ == ExtrasMode::AssumeMultipleArguments) {
10678 while(!args.empty() &&
_recognize(args.back(),
false) == detail::Classifier::NONE) {
10689 Option_p &op = *op_ptr;
10691 if(op->get_inject_separator()) {
10692 if(!op->results().empty() && !op->results().back().empty()) {
10693 op->add_result(std::string{});
10699 int min_num = (std::min)(op->get_type_size_min(), op->get_items_expected_min());
10700 int max_num = op->get_items_expected_max();
10703 if(max_num >= detail::expected_max_vector_size / 16 && !op->get_allow_extra_args()) {
10704 auto tmax = op->get_type_size_max();
10705 max_num = detail::checked_multiply(tmax, op->get_expected_min()) ? tmax : detail::expected_max_vector_size;
10709 int result_count = 0;
10712 auto res = op->get_flag_value(arg_name, value);
10713 op->add_result(res);
10715 }
else if(!value.empty()) {
10716 op->add_result(value, result_count);
10718 collected += result_count;
10720 }
else if(!rest.empty()) {
10721 op->add_result(rest, result_count);
10724 collected += result_count;
10728 while(min_num > collected && !args.empty()) {
10729 std::string current_ = args.back();
10731 op->add_result(current_, result_count);
10733 collected += result_count;
10736 if(min_num > collected) {
10737 throw ArgumentMismatch::TypedAtLeast(op->get_name(), min_num, op->get_type_name());
10741 if(max_num > collected || op->get_allow_extra_args()) {
10744 while((collected < max_num || op->get_allow_extra_args()) && !args.empty() &&
10745 _recognize(args.back(),
false) == detail::Classifier::NONE) {
10747 if(remreqpos >= args.size()) {
10751 std::string arg = args.back();
10752 arg = op->_validate(arg, 0);
10757 op->add_result(args.back(), result_count);
10760 collected += result_count;
10764 if(!args.empty() &&
_recognize(args.back()) == detail::Classifier::POSITIONAL_MARK)
10767 if(min_num == 0 && max_num > 0 && collected == 0) {
10768 auto res = op->get_flag_value(arg_name, std::string{});
10769 op->add_result(res);
10774 if(min_num > 0 && (collected % op->get_type_size_max()) != 0) {
10775 if(op->get_type_size_max() != op->get_type_size_min()) {
10776 op->add_result(std::string{});
10778 throw ArgumentMismatch::PartialType(op->get_name(), op->get_type_size_min(), op->get_type_name());
10781 if(op->get_trigger_on_parse()) {
10782 op->run_callback();
10784 if(!rest.empty()) {
10786 args.push_back(rest);
10798 if(!
name_.empty()) {
10800 missing_t extras = std::move(
missing_);
10813 auto *fallthrough_parent =
parent_;
10814 while((fallthrough_parent->parent_ !=
nullptr) && (fallthrough_parent->get_name().empty())) {
10815 fallthrough_parent = fallthrough_parent->parent_;
10817 return fallthrough_parent;
10824 const auto *fallthrough_parent =
parent_;
10825 while((fallthrough_parent->parent_ !=
nullptr) && (fallthrough_parent->get_name().empty())) {
10826 fallthrough_parent = fallthrough_parent->parent_;
10828 return fallthrough_parent;
10832 const App &base)
const {
10833 static const std::string estring;
10838 if(subc.get() != &subcom) {
10839 if(subc->disabled_) {
10843 if(subc->check_name(subcom.
get_name())) {
10847 if(!subc->get_name().empty()) {
10849 return subc->get_name();
10852 for(
const auto &les : subcom.
aliases_) {
10853 if(subc->check_name(les)) {
10858 for(
const auto &les : subc->aliases_) {
10864 if(subc->get_name().empty()) {
10866 if(!cmpres.empty()) {
10873 if(!cmpres.empty()) {
10882inline bool capture_extras(ExtrasMode mode) {
10883 return mode == ExtrasMode::Capture || mode == ExtrasMode::AssumeSingleArgument ||
10884 mode == ExtrasMode::AssumeMultipleArguments;
10892 missing_.emplace_back(val_type, val);
10898 if(subc->name_.empty() && capture_extras(subc->allow_extras_)) {
10899 subc->missing_.emplace_back(val_type, val);
10905 missing_.emplace_back(val_type, val);
10910 if(opt ==
nullptr) {
10914 bool found =
false;
10916 if(app == subc.get()) {
10931 std::find_if(std::begin(
options_), std::end(
options_), [opt](
const Option_p &v) {
return v.get() == opt; });
10932 if(iterator != std::end(
options_)) {
10933 const auto &opt_p = *iterator;
10934 if(std::find_if(std::begin(app->
options_), std::end(app->
options_), [&opt_p](
const Option_p &v) {
10935 return (*v == *opt_p);
10938 app->
options_.push_back(std::move(*iterator));
10948CLI11_INLINE
void TriggerOn(
App *trigger_app,
App *app_to_enable) {
10954CLI11_INLINE
void TriggerOn(
App *trigger_app, std::vector<App *> apps_to_enable) {
10955 for(
auto &app : apps_to_enable) {
10960 trigger_app->preparse_callback([apps_to_enable](std::size_t) {
10961 for(
const auto &app : apps_to_enable) {
10967CLI11_INLINE
void TriggerOff(
App *trigger_app,
App *app_to_enable) {
10968 app_to_enable->disabled_by_default(
false);
10969 app_to_enable->enabled_by_default();
10970 trigger_app->preparse_callback([app_to_enable](std::size_t) { app_to_enable->disabled(); });
10973CLI11_INLINE
void TriggerOff(
App *trigger_app, std::vector<App *> apps_to_enable) {
10974 for(
auto &app : apps_to_enable) {
10979 trigger_app->preparse_callback([apps_to_enable](std::size_t) {
10980 for(
const auto &app : apps_to_enable) {
10986CLI11_INLINE
void deprecate_option(
Option *opt,
const std::string &replacement) {
10987 Validator deprecate_warning{[opt, replacement](std::string &) {
10988 std::cout << opt->get_name() <<
" is deprecated please use '" << replacement
10990 return std::string();
10994 opt->check(deprecate_warning);
10995 if(!replacement.empty()) {
10996 opt->description(opt->get_description() +
" DEPRECATED: please use '" + replacement +
"' instead");
11000CLI11_INLINE
void retire_option(
App *app,
Option *opt) {
11002 auto *option_copy = temp.
add_option(opt->get_name(
false,
true))
11003 ->
type_size(opt->get_type_size_min(), opt->get_type_size_max())
11004 ->
expected(opt->get_expected_min(), opt->get_expected_max())
11007 app->remove_option(opt);
11008 auto *opt2 = app->add_option(option_copy->get_name(
false,
true),
"option has been retired and has no effect");
11011 ->
type_size(option_copy->get_type_size_min(), option_copy->get_type_size_max())
11012 ->
expected(option_copy->get_expected_min(), option_copy->get_expected_max())
11017 Validator retired_warning{[opt2](std::string &) {
11018 std::cout <<
"WARNING " << opt2->get_name() <<
" is retired and has no effect\n";
11019 return std::string();
11024 opt2->check(retired_warning);
11027CLI11_INLINE
void retire_option(
App &app,
Option *opt) { retire_option(&app, opt); }
11029CLI11_INLINE
void retire_option(
App *app,
const std::string &option_name) {
11031 auto *opt = app->get_option_no_throw(option_name);
11032 if(opt !=
nullptr) {
11033 retire_option(app, opt);
11036 auto *opt2 = app->add_option(option_name,
"option has been retired and has no effect")
11037 ->type_name(
"RETIRED")
11039 ->default_str(
"RETIRED");
11042 Validator retired_warning{[opt2](std::string &) {
11043 std::cout <<
"WARNING " << opt2->get_name() <<
" is retired and has no effect\n";
11044 return std::string();
11049 opt2->check(retired_warning);
11052CLI11_INLINE
void retire_option(
App &app,
const std::string &option_name) { retire_option(&app, option_name); }
11054namespace FailureMessage {
11056CLI11_INLINE std::string simple(
const App *app,
const Error &e) {
11057 std::string header = std::string(e.what()) +
"\n";
11058 std::vector<std::string> names;
11061 if(app->get_help_ptr() !=
nullptr)
11062 names.push_back(app->get_help_ptr()->get_name());
11064 if(app->get_help_all_ptr() !=
nullptr)
11065 names.push_back(app->get_help_all_ptr()->get_name());
11069 header +=
"Run with " + detail::join(names,
" or ") +
" for more information.\n";
11074CLI11_INLINE std::string help(
const App *app,
const Error &e) {
11075 std::string header = std::string(
"ERROR: ") + e.get_name() +
": " + e.what() +
"\n";
11076 header += app->help();
11087std::string convert_arg_for_ini(
const std::string &arg,
11088 char stringQuote =
'"',
11089 char literalQuote =
'\'',
11090 bool disable_multi_line =
false);
11093std::string ini_join(
const std::vector<std::string> &args,
11094 char sepChar =
',',
11095 char arrayStart =
'[',
11096 char arrayEnd =
']',
11097 char stringQuote =
'"',
11098 char literalQuote =
'\'');
11100void clean_name_string(std::string &name,
const std::string &keyChars);
11102std::vector<std::string> generate_parents(
const std::string §ion, std::string &name,
char parentSeparator);
11105void checkParentSegments(std::vector<ConfigItem> &output,
const std::string ¤tSection,
char parentSeparator);
11111static constexpr auto multiline_literal_quote = R
"(''')";
11112static constexpr auto multiline_string_quote = R
"(""")";
11116CLI11_INLINE
bool is_printable(
const std::string &test_string) {
11117 return std::all_of(test_string.begin(), test_string.end(), [](
char x) {
11118 return (isprint(static_cast<unsigned char>(x)) != 0 || x ==
'\n' || x ==
'\t');
11122CLI11_INLINE std::string
11123convert_arg_for_ini(
const std::string &arg,
char stringQuote,
char literalQuote,
bool disable_multi_line) {
11125 return std::string(2, stringQuote);
11128 if(arg ==
"true" || arg ==
"false" || arg ==
"nan" || arg ==
"inf") {
11132 if(arg.compare(0, 2,
"0x") != 0 && arg.compare(0, 2,
"0X") != 0) {
11133 using CLI::detail::lexical_cast;
11135 if(lexical_cast(arg, val)) {
11136 if(arg.find_first_not_of(
"0123456789.-+eE") == std::string::npos) {
11142 if(arg.size() == 1) {
11143 if(isprint(
static_cast<unsigned char>(arg.front())) == 0) {
11144 return binary_escape_string(arg);
11147 return std::string(1, stringQuote) +
"'" + stringQuote;
11149 return std::string(1, literalQuote) + arg + literalQuote;
11152 if(arg.front() ==
'0') {
11153 if(arg[1] ==
'x') {
11154 if(std::all_of(arg.begin() + 2, arg.end(), [](
char x) {
11155 return (x >=
'0' && x <=
'9') || (x >=
'A' && x <=
'F') || (x >=
'a' && x <=
'f');
11159 }
else if(arg[1] ==
'o') {
11160 if(std::all_of(arg.begin() + 2, arg.end(), [](
char x) { return (x >=
'0' && x <=
'7'); })) {
11163 }
else if(arg[1] ==
'b') {
11164 if(std::all_of(arg.begin() + 2, arg.end(), [](
char x) { return (x ==
'0' || x ==
'1'); })) {
11169 if(!is_printable(arg)) {
11170 return binary_escape_string(arg);
11172 if(detail::has_escapable_character(arg)) {
11173 if(arg.size() > 100 && !disable_multi_line) {
11174 if(arg.find(multiline_literal_quote) != std::string::npos) {
11175 return binary_escape_string(arg,
true);
11177 std::string return_string{multiline_literal_quote};
11178 return_string.reserve(7 + arg.size());
11179 if(arg.front() ==
'\n' || arg.front() ==
'\r') {
11180 return_string.push_back(
'\n');
11182 return_string.append(arg);
11183 if(arg.back() ==
'\n' || arg.back() ==
'\r') {
11184 return_string.push_back(
'\n');
11186 return_string.append(multiline_literal_quote, 3);
11187 return return_string;
11189 return std::string(1, stringQuote) + detail::add_escaped_characters(arg) + stringQuote;
11191 return std::string(1, stringQuote) + arg + stringQuote;
11194CLI11_INLINE std::string ini_join(
const std::vector<std::string> &args,
11199 char literalQuote) {
11200 bool disable_multi_line{
false};
11201 std::string joined;
11202 if(args.size() > 1 && arrayStart !=
'\0') {
11203 joined.push_back(arrayStart);
11204 disable_multi_line =
true;
11206 std::size_t start = 0;
11207 for(
const auto &arg : args) {
11209 joined.push_back(sepChar);
11210 if(!std::isspace<char>(sepChar, std::locale())) {
11211 joined.push_back(
' ');
11214 joined.append(convert_arg_for_ini(arg, stringQuote, literalQuote, disable_multi_line));
11216 if(args.size() > 1 && arrayEnd !=
'\0') {
11217 joined.push_back(arrayEnd);
11222CLI11_INLINE std::vector<std::string>
11223generate_parents(
const std::string §ion, std::string &name,
char parentSeparator) {
11224 std::vector<std::string> parents;
11225 if(detail::to_lower(section) !=
"default") {
11226 if(section.find(parentSeparator) != std::string::npos) {
11227 parents = detail::split_up(section, parentSeparator);
11229 parents = {section};
11232 if(name.find(parentSeparator) != std::string::npos) {
11233 std::vector<std::string> plist = detail::split_up(name, parentSeparator);
11234 name = plist.back();
11236 parents.insert(parents.end(), plist.begin(), plist.end());
11240 detail::remove_quotes(parents);
11241 }
catch(
const std::invalid_argument &iarg) {
11242 throw CLI::ParseError(iarg.what(), CLI::ExitCodes::InvalidError);
11248checkParentSegments(std::vector<ConfigItem> &output,
const std::string ¤tSection,
char parentSeparator) {
11250 std::string estring;
11251 auto parents = detail::generate_parents(currentSection, estring, parentSeparator);
11252 if(!output.empty() && output.back().name ==
"--") {
11253 std::size_t msize = (parents.size() > 1U) ? parents.size() : 2;
11254 while(output.back().parents.size() >= msize) {
11255 output.push_back(output.back());
11256 output.back().parents.pop_back();
11259 if(parents.size() > 1) {
11260 std::size_t common = 0;
11261 std::size_t mpair = (std::min)(output.back().parents.size(), parents.size() - 1);
11262 for(std::size_t ii = 0; ii < mpair; ++ii) {
11263 if(output.back().parents[ii] != parents[ii]) {
11268 if(common == mpair) {
11271 while(output.back().parents.size() > common + 1) {
11272 output.push_back(output.back());
11273 output.back().parents.pop_back();
11276 for(std::size_t ii = common; ii < parents.size() - 1; ++ii) {
11277 output.emplace_back();
11278 output.back().parents.assign(parents.begin(), parents.begin() +
static_cast<std::ptrdiff_t
>(ii) + 1);
11279 output.back().name =
"++";
11282 }
else if(parents.size() > 1) {
11283 for(std::size_t ii = 0; ii < parents.size() - 1; ++ii) {
11284 output.emplace_back();
11285 output.back().parents.assign(parents.begin(), parents.begin() +
static_cast<std::ptrdiff_t
>(ii) + 1);
11286 output.back().name =
"++";
11291 output.emplace_back();
11292 output.back().parents = std::move(parents);
11293 output.back().name =
"++";
11297CLI11_INLINE
bool hasMLString(std::string
const &fullString,
char check) {
11298 if(fullString.length() < 3) {
11301 auto it = fullString.rbegin();
11302 return (*it == check) && (*(it + 1) == check) && (*(it + 2) == check);
11306inline auto find_matching_config(std::vector<ConfigItem> &items,
11307 const std::vector<std::string> &parents,
11308 const std::string &name,
11309 bool fullSearch) ->
decltype(items.begin()) {
11310 if(items.empty()) {
11311 return items.end();
11313 auto search = items.end() - 1;
11315 if(search->parents == parents && search->name == name) {
11318 if(search == items.begin()) {
11322 }
while(fullSearch);
11323 return items.end();
11329 std::string buffer;
11330 std::string currentSection =
"default";
11331 std::string previousSection =
"default";
11332 std::vector<ConfigItem> output;
11335 bool inSection{
false};
11336 bool inMLineComment{
false};
11337 bool inMLineValue{
false};
11339 char aStart = (isINIArray) ?
'[' :
arrayStart;
11340 char aEnd = (isINIArray) ?
']' :
arrayEnd;
11342 int currentSectionIndex{0};
11345 while(getline(input, buffer)) {
11346 std::vector<std::string> items_buffer;
11348 line = detail::trim_copy(buffer);
11349 std::size_t len = line.length();
11354 if(line.compare(0, 3, multiline_string_quote) == 0 || line.compare(0, 3, multiline_literal_quote) == 0) {
11355 inMLineComment =
true;
11356 auto cchar = line.front();
11357 while(inMLineComment) {
11358 if(getline(input, line)) {
11359 detail::trim(line);
11363 if(detail::hasMLString(line, cchar)) {
11364 inMLineComment =
false;
11369 if(line.front() ==
'[' && line.back() ==
']') {
11370 if(currentSection !=
"default") {
11372 output.emplace_back();
11373 output.back().parents = detail::generate_parents(currentSection, name,
parentSeparatorChar);
11374 output.back().name =
"--";
11376 currentSection = line.substr(1, len - 2);
11378 if(currentSection.size() > 1 && currentSection.front() ==
'[' && currentSection.back() ==
']') {
11379 currentSection = currentSection.substr(1, currentSection.size() - 2);
11381 if(detail::to_lower(currentSection) ==
"default") {
11382 currentSection =
"default";
11387 if(currentSection == previousSection) {
11388 ++currentSectionIndex;
11390 currentSectionIndex = 0;
11391 previousSection = currentSection;
11397 if(line.front() ==
';' || line.front() ==
'#' || line.front() ==
commentChar) {
11400 std::size_t search_start = 0;
11401 if(line.find_first_of(
"\"'`") != std::string::npos) {
11402 while(search_start < line.size()) {
11403 auto test_char = line[search_start];
11404 if(test_char ==
'\"' || test_char ==
'\'' || test_char ==
'`') {
11405 search_start = detail::close_sequence(line, search_start, line[search_start]);
11413 search_start = line.find_first_of(line_sep_chars, search_start);
11418 auto delimiter_pos = line.find_first_of(
valueDelimiter, search_start + 1);
11419 auto comment_pos = line.find_first_of(
commentChar, search_start);
11420 if(comment_pos < delimiter_pos) {
11421 delimiter_pos = std::string::npos;
11423 if(delimiter_pos != std::string::npos) {
11425 name = detail::trim_copy(line.substr(0, delimiter_pos));
11426 std::string item = detail::trim_copy(line.substr(delimiter_pos + 1, std::string::npos));
11428 (item.compare(0, 3, multiline_literal_quote) == 0 || item.compare(0, 3, multiline_string_quote) == 0);
11429 if(!mlquote && comment_pos != std::string::npos) {
11430 auto citems = detail::split_up(item,
commentChar);
11431 item = detail::trim_copy(citems.front());
11435 auto keyChar = item.front();
11436 item = buffer.substr(delimiter_pos + 1, std::string::npos);
11437 detail::ltrim(item);
11439 inMLineValue =
true;
11440 bool lineExtension{
false};
11441 bool firstLine =
true;
11442 if(!item.empty() && item.back() ==
'\\' && keyChar ==
'\"') {
11444 lineExtension =
true;
11445 }
else if(detail::hasMLString(item, keyChar)) {
11450 if(keyChar ==
'\"') {
11452 item = detail::remove_escaped_characters(item);
11453 }
catch(
const std::invalid_argument &iarg) {
11457 inMLineValue =
false;
11459 while(inMLineValue) {
11461 if(!std::getline(input, l2)) {
11465 detail::rtrim(line);
11466 if(detail::hasMLString(line, keyChar)) {
11470 if(lineExtension) {
11471 detail::ltrim(line);
11472 }
else if(!(firstLine && item.empty())) {
11473 item.push_back(
'\n');
11477 inMLineValue =
false;
11478 if(!item.empty() && item.back() ==
'\n') {
11481 if(keyChar ==
'\"') {
11483 item = detail::remove_escaped_characters(item);
11484 }
catch(
const std::invalid_argument &iarg) {
11489 if(lineExtension) {
11491 }
else if(!(firstLine && item.empty())) {
11492 item.push_back(
'\n');
11494 lineExtension =
false;
11496 if(!l2.empty() && l2.back() ==
'\\' && keyChar ==
'\"') {
11497 lineExtension =
true;
11503 items_buffer = {item};
11504 }
else if(!item.empty() && item.front() == aStart) {
11505 for(std::string multiline; item.back() != aEnd && std::getline(input, multiline);) {
11506 detail::trim(multiline);
11509 if(item.back() == aEnd) {
11510 items_buffer = detail::split_up(item.substr(1, item.length() - 2), aSep);
11512 items_buffer = detail::split_up(item.substr(1, std::string::npos), aSep);
11514 }
else if((isDefaultArray || isINIArray) && item.find_first_of(aSep) != std::string::npos) {
11515 items_buffer = detail::split_up(item, aSep);
11516 }
else if((isDefaultArray || isINIArray) && item.find_first_of(
' ') != std::string::npos) {
11517 items_buffer = detail::split_up(item,
'\0');
11519 items_buffer = {item};
11522 name = detail::trim_copy(line.substr(0, comment_pos));
11523 items_buffer = {
"true"};
11525 std::vector<std::string> parents;
11528 detail::process_quoted_string(name,
'"',
'\'',
true);
11530 for(
auto &it : items_buffer) {
11533 }
catch(
const std::invalid_argument &ia) {
11547 parents.erase(parents.begin());
11551 if(match != output.end()) {
11554 if(!(match->inputs.back().empty() || items_buffer.front().empty() || match->inputs.back() ==
"%%" ||
11555 items_buffer.front() ==
"%%")) {
11556 match->inputs.emplace_back(
"%%");
11557 match->multiline =
true;
11560 match->inputs.insert(match->inputs.end(), items_buffer.begin(), items_buffer.end());
11562 output.emplace_back();
11563 output.back().parents = std::move(parents);
11564 output.back().name = std::move(name);
11565 output.back().inputs = std::move(items_buffer);
11568 if(currentSection !=
"default") {
11571 output.emplace_back();
11572 output.back().parents = detail::generate_parents(currentSection, ename,
parentSeparatorChar);
11573 output.back().name =
"--";
11574 while(output.back().parents.size() > 1) {
11575 output.push_back(output.back());
11576 output.back().parents.pop_back();
11582CLI11_INLINE std::string &clean_name_string(std::string &name,
const std::string &keyChars) {
11583 if(name.find_first_of(keyChars) != std::string::npos || (name.front() ==
'[' && name.back() ==
']') ||
11584 (name.find_first_of(
"'`\"\\") != std::string::npos)) {
11585 if(name.find_first_of(
'\'') == std::string::npos) {
11586 name.insert(0, 1,
'\'');
11587 name.push_back(
'\'');
11589 if(detail::has_escapable_character(name)) {
11590 name = detail::add_escaped_characters(name);
11592 name.insert(0, 1,
'\"');
11593 name.push_back(
'\"');
11599CLI11_INLINE std::string
11601 std::stringstream out;
11602 std::string commentLead;
11604 commentLead.push_back(
' ');
11606 std::string commentTest =
"#;";
11610 std::string keyChars = commentTest;
11618 std::vector<std::string> groups = app->
get_groups();
11619 bool defaultUsed =
false;
11620 groups.insert(groups.begin(), std::string(
"OPTIONS"));
11622 for(
auto &group : groups) {
11623 if(group ==
"OPTIONS" || group.empty()) {
11627 defaultUsed =
true;
11629 if(write_description && group !=
"OPTIONS" && !group.empty()) {
11630 out <<
'\n' <<
commentChar << commentLead << group <<
" Options\n";
11634 if(opt->get_configurable()) {
11635 if(opt->get_group() != group) {
11636 if(!(group ==
"OPTIONS" && opt->get_group().empty())) {
11640 std::string single_name = opt->get_single_name();
11641 if(single_name.empty()) {
11645 auto results = opt->reduced_results();
11646 if(results.size() > 1 && opt->get_multi_option_policy() == CLI::MultiOptionPolicy::Reverse) {
11647 std::reverse(results.begin(), results.end());
11649 if(opt->get_multi_option_policy() == CLI::MultiOptionPolicy::Sum && opt->count() >= 1 &&
11650 results.size() == 1) {
11653 auto pos = opt->_validate(results[0], 0);
11655 results = opt->results();
11658 if(opt->get_multi_option_policy() == CLI::MultiOptionPolicy::Join && opt->count() > 1) {
11659 char delim = opt->get_delimiter();
11660 if(delim ==
'\0') {
11662 results = opt->results();
11666 auto delim_count = std::count(results[0].begin(), results[0].end(), delim);
11667 if(results[0].back() == delim ||
11668 static_cast<decltype(delim_count)
>(opt->count()) < delim_count - 1 ||
11669 results[0].find(std::string(2, delim)) != std::string::npos) {
11670 results = opt->results();
11676 if(opt->count() == 1 && results.size() == 2 && results.front() ==
"{}" && results.back() ==
"%%") {
11686 bool isDefault =
false;
11687 if(value.empty() && default_also) {
11688 if(!opt->get_default_str().empty()) {
11692 }
else if(opt->get_expected_min() == 0) {
11694 }
else if(opt->get_run_callback_for_default() || !opt->get_required()) {
11697 value =
"\"<REQUIRED>\"";
11702 if(!value.empty()) {
11703 if(!opt->get_fnames().empty()) {
11705 value = opt->get_flag_value(single_name, value);
11708 for(
const auto &test_name : opt->get_fnames()) {
11710 value = opt->get_flag_value(test_name, value);
11711 single_name = test_name;
11718 value = detail::ini_join(
11723 if(write_description && opt->has_description()) {
11724 if(out.tellp() != std::streampos(0)) {
11727 out << commentLead << detail::fix_newlines(commentLead, opt->get_description()) <<
'\n';
11729 clean_name_string(single_name, keyChars);
11731 std::string name = prefix + single_name;
11742 for(
const App *subcom : subcommands) {
11743 if(subcom->get_name().empty()) {
11744 if(!default_also && (subcom->count_all() == 0)) {
11747 if(write_description && !subcom->get_group().empty()) {
11748 out <<
'\n' << commentLead << subcom->get_group() <<
" Options\n";
11762 out <<
to_config(subcom, default_also, write_description, prefix);
11766 for(
const App *subcom : subcommands) {
11767 if(!subcom->get_name().empty()) {
11768 if(!default_also && (subcom->count_all() == 0)) {
11771 std::string subname = subcom->get_name();
11772 clean_name_string(subname, keyChars);
11774 if(subcom->get_configurable() && (default_also || app->
got_subcommand(subcom))) {
11775 if(!prefix.empty() || app->
get_parent() ==
nullptr) {
11777 out <<
'[' << prefix << subname <<
"]\n";
11779 std::string appname = app->
get_name();
11780 clean_name_string(appname, keyChars);
11783 while(p->get_parent() !=
nullptr) {
11784 std::string pname = p->get_name();
11785 clean_name_string(pname, keyChars);
11787 p = p->get_parent();
11789 out <<
'[' << subname <<
"]\n";
11791 out <<
to_config(subcom, default_also, write_description,
"");
11798 if(write_description && !out.str().empty()) {
11799 std::string outString =
11801 return outString + out.str();
11811CLI11_INLINE std::string
11813 std::stringstream out;
11815 out <<
"\n" << group <<
":\n";
11816 for(
const Option *opt : opts) {
11824 std::vector<const Option *> opts =
11834 std::stringstream out;
11835 std::vector<std::string> groups = app->
get_groups();
11838 for(
const std::string &group : groups) {
11839 std::vector<const Option *> opts = app->
get_options([app, mode, &group](
const Option *opt) {
11842 && (mode != AppFormatMode::Sub
11846 if(!group.empty() && !opts.empty()) {
11864 desc +=
" " +
get_label(
"REQUIRED") +
" ";
11867 if(min_options > 0) {
11868 if(max_options == min_options) {
11869 desc +=
" \n[Exactly " + std::to_string(min_options) +
" of the following options are required]";
11870 }
else if(max_options > 0) {
11871 desc +=
" \n[Between " + std::to_string(min_options) +
" and " + std::to_string(max_options) +
11872 " of the following options are required]";
11874 desc +=
" \n[At least " + std::to_string(min_options) +
" of the following options are required]";
11876 }
else if(max_options > 0) {
11877 desc +=
" \n[At most " + std::to_string(max_options) +
" of the following options are allowed]";
11880 return (!desc.empty()) ? desc +
"\n\n" : std::string{};
11885 if(!usage.empty()) {
11886 return usage +
"\n\n";
11889 std::stringstream out;
11897 std::vector<std::string> groups = app->
get_groups();
11900 std::vector<const Option *> non_pos_options =
11902 if(!non_pos_options.empty())
11903 out <<
" [" <<
get_label(
"OPTIONS") <<
"]";
11909 if(!positionals.empty()) {
11911 std::vector<std::string> positional_names(positionals.size());
11912 std::transform(positionals.begin(), positionals.end(), positional_names.begin(), [
this](
const Option *opt) {
11913 return make_option_usage(opt);
11916 out <<
" " << detail::join(positional_names,
" ");
11921 [](
const CLI::App *subc) { return ((!subc->get_disabled()) && (!subc->get_name().empty())); })
11935 if(footer.empty()) {
11936 return std::string{};
11938 return '\n' + footer +
'\n';
11944 if(mode == AppFormatMode::Sub)
11947 std::stringstream out;
11949 if(app->
get_group() !=
"SUBCOMMANDS") {
11954 detail::streamOutAsParagraph(
11968 out << footer_string;
11975 std::stringstream out;
11980 std::vector<std::string> subcmd_groups_seen;
11981 for(
const App *com : subcommands) {
11982 if(com->get_name().empty()) {
11983 if(!com->get_group().empty() && com->get_group().front() !=
'+') {
11988 std::string group_key = com->get_group();
11989 if(!group_key.empty() &&
11990 std::find_if(subcmd_groups_seen.begin(), subcmd_groups_seen.end(), [&group_key](std::string a) {
11991 return detail::to_lower(a) == detail::to_lower(group_key);
11992 }) == subcmd_groups_seen.end())
11993 subcmd_groups_seen.push_back(group_key);
11997 for(
const std::string &group : subcmd_groups_seen) {
11998 out <<
'\n' << group <<
":\n";
12000 [&group](
const App *sub_app) {
return detail::to_lower(sub_app->
get_group()) == detail::to_lower(group); });
12001 for(
const App *new_com : subcommands_group) {
12002 if(new_com->get_name().empty())
12004 if(mode != AppFormatMode::All) {
12007 out << new_com->help(new_com->get_name(), AppFormatMode::Sub);
12017 std::stringstream out;
12020 out << std::setw(static_cast<int>(
column_width_)) << std::left << name;
12021 detail::streamOutAsParagraph(
12028 std::stringstream out;
12032 detail::streamOutAsParagraph(
12047 if(mode == AppFormatMode::Sub && !footer_string.empty()) {
12050 if(footer_string == parent_footer) {
12051 footer_string =
"";
12054 if(!footer_string.empty()) {
12058 out << footer_string;
12065 std::stringstream out;
12066 if(is_positional) {
12069 out << std::setw(static_cast<int>(
column_width_)) << std::left << left;
12071 if(!desc.empty()) {
12072 bool skipFirstLinePrefix =
true;
12075 skipFirstLinePrefix =
false;
12077 detail::streamOutAsParagraph(
12086 const auto names = detail::split(namesCombined,
',');
12087 std::vector<std::string> vshortNames;
12088 std::vector<std::string> vlongNames;
12089 std::for_each(names.begin(), names.end(), [&vshortNames, &vlongNames](
const std::string &name) {
12090 if(name.find(
"--", 0) != std::string::npos)
12091 vlongNames.push_back(name);
12093 vshortNames.push_back(name);
12097 std::string shortNames = detail::join(vshortNames,
", ");
12098 std::string longNames = detail::join(vlongNames,
", ");
12102 const auto shortNamesColumnWidth =
12104 const auto longNamesColumnWidth =
static_cast<int>(
column_width_) - shortNamesColumnWidth;
12105 int shortNamesOverSize = 0;
12108 if(!shortNames.empty()) {
12109 shortNames =
" " + shortNames;
12110 if(longNames.empty() && !opts.empty())
12111 shortNames += opts;
12112 if(!longNames.empty())
12114 if(
static_cast<int>(shortNames.length()) >= shortNamesColumnWidth) {
12116 shortNamesOverSize =
static_cast<int>(shortNames.length()) - shortNamesColumnWidth;
12118 out << std::setw(shortNamesColumnWidth) << std::left << shortNames;
12120 out << std::setw(shortNamesColumnWidth) << std::left <<
"";
12124 shortNamesOverSize =
12125 (std::min)(shortNamesOverSize, longNamesColumnWidth);
12126 const auto adjustedLongNamesColumnWidth = longNamesColumnWidth - shortNamesOverSize;
12129 if(!longNames.empty()) {
12132 if(
static_cast<int>(longNames.length()) >= adjustedLongNamesColumnWidth)
12135 out << std::setw(adjustedLongNamesColumnWidth) << std::left << longNames;
12137 out << std::setw(adjustedLongNamesColumnWidth) << std::left <<
"";
12140 if(!desc.empty()) {
12141 bool skipFirstLinePrefix =
true;
12144 skipFirstLinePrefix =
false;
12146 detail::streamOutAsParagraph(
12157 return opt->
get_name(
true,
false);
12159 return opt->
get_name(
false,
true, !enable_default_flag_values_);
12163 std::stringstream out;
12165 if(!opt->get_option_text().empty()) {
12166 out <<
" " << opt->get_option_text();
12169 if(enable_option_type_names_) {
12188 out <<
" " <<
get_label(
"Needs") <<
":";
12190 out <<
" " << op->get_name();
12193 out <<
" " <<
get_label(
"Excludes") <<
":";
12195 out <<
" " << op->get_name();
12205 std::stringstream out;
12212 return opt->
get_required() ? out.str() :
"[" + out.str() +
"]";
Creates a command line program, with very few defaults.
Definition CLI11.hpp:7073
CLI11_NODISCARD Option * get_option_no_throw(std::string option_name) noexcept
Get an option by name (noexcept non-const version).
Definition CLI11.hpp:9383
bool subcommand_fallthrough_
Allow subcommands to fallthrough, so that parent commands can trigger other subcommands after subcomm...
Definition CLI11.hpp:7215
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.
Definition CLI11.hpp:9191
CLI11_NODISCARD std::string help(std::string prev="", AppFormatMode mode=AppFormatMode::Normal) const
Definition CLI11.hpp:9287
CLI11_NODISCARD std::size_t remaining_size(bool recurse=false) const
This returns the number of remaining options, minus the – separator.
Definition CLI11.hpp:9529
const Option * operator[](const std::string &option_name) const
Shortcut bracket operator for getting a pointer to an option.
Definition CLI11.hpp:8107
CLI11_NODISCARD bool _has_remaining_positionals() const
Count the required remaining positional arguments.
Definition CLI11.hpp:10301
App * configurable(bool value=true)
Specify that the subcommand can be triggered by a config file.
Definition CLI11.hpp:7492
CLI11_NODISCARD bool get_allow_subcommand_prefix_matching() const
Get the status of allowing prefix matching for subcommands.
Definition CLI11.hpp:8183
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.
Definition CLI11.hpp:9642
App * immediate_callback(bool immediate=true)
Set the subcommand callback to be executed immediately on subcommand completion.
Definition CLI11.hpp:8609
Option * set_help_flag(std::string flag_name="", const std::string &help_description="")
Set a help flag, replace the existing one if present.
Definition CLI11.hpp:8765
CLI11_NODISCARD std::string config_to_str(bool default_also=false, bool write_description=false) const
Definition CLI11.hpp:8037
bool allow_non_standard_options_
indicator that the subcommand should allow non-standard option arguments, such as -single_dash_flag
Definition CLI11.hpp:7247
App * usage(std::function< std::string()> usage_function)
Set usage.
Definition CLI11.hpp:8021
CLI11_NODISCARD bool get_enabled_by_default() const
Get the status of disabled by default.
Definition CLI11.hpp:8192
Option * config_ptr_
Pointer to the config option.
Definition CLI11.hpp:7281
CLI11_NODISCARD bool get_allow_non_standard_option_names() const
Get the status of allowing non standard option names.
Definition CLI11.hpp:8180
CLI11_NODISCARD bool get_configurable() const
Check the status of the allow windows style options.
Definition CLI11.hpp:8131
Option * add_option_no_stream(std::string option_name, AssignTo &variable, std::string option_description="")
Add option for assigning to a variable.
Definition CLI11.hpp:7576
CLI11_NODISCARD std::string get_usage() const
Generate and return the usage.
Definition CLI11.hpp:8137
CLI11_NODISCARD std::shared_ptr< FormatterBase > get_formatter() const
Access the formatter.
Definition CLI11.hpp:8052
Option * add_option(std::string option_name)
Add option with no description or variable assignment.
Definition CLI11.hpp:7615
App * subcommand_fallthrough(bool value=true)
Set subcommand fallthrough, set to true so that subcommands on parents are recognized.
Definition CLI11.hpp:7867
App * config_formatter(std::shared_ptr< Config > fmt)
Set the config formatter.
Definition CLI11.hpp:7513
App * allow_config_extras(bool allow=true)
ignore extras in config files
Definition CLI11.hpp:7439
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...
Definition CLI11.hpp:7402
void _move_to_missing(detail::Classifier val_type, const std::string &val)
Helper function to place extra values in the most appropriate position.
Definition CLI11.hpp:10886
CLI11_NODISCARD App * _get_fallthrough_parent() noexcept
Get the appropriate parent to fallthrough to which is the first one that has a name or the main app.
Definition CLI11.hpp:10809
std::size_t require_option_min_
Minimum required options (not inheritable!).
Definition CLI11.hpp:7262
NameMatch
enumeration of matching possibilities
Definition CLI11.hpp:8250
App * silent(bool silence=true)
silence the subcommand from showing up in the processed list
Definition CLI11.hpp:7385
App * clear_aliases()
clear all the aliases of the current App
Definition CLI11.hpp:8237
CLI11_NODISCARD bool get_ignore_underscore() const
Check the status of ignore_underscore.
Definition CLI11.hpp:8116
App * ignore_underscore(bool value=true)
Ignore underscore. Subcommands inherit value.
Definition CLI11.hpp:8635
App * allow_extras(bool allow=true)
Remove the error when extras are left over on the command line.
Definition CLI11.hpp:7361
App * fallthrough(bool value=true)
Definition CLI11.hpp:7861
std::size_t require_subcommand_max_
Max number of subcommands allowed (parsing stops after this number). 0 is unlimited INHERITABLE.
Definition CLI11.hpp:7259
Option * get_config_ptr()
Get a pointer to the config option.
Definition CLI11.hpp:8213
std::vector< App_p > subcommands_
Storage for subcommand list.
Definition CLI11.hpp:7202
CLI11_NODISCARD std::vector< std::string > remaining(bool recurse=false) const
This returns the missing options from the current subcommand.
Definition CLI11.hpp:9497
CLI11_NODISCARD bool get_allow_extras() const
Get the status of allow extras.
Definition CLI11.hpp:8165
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.
Definition CLI11.hpp:9523
std::uint32_t parsed_
Counts the number of times this command/subcommand was parsed.
Definition CLI11.hpp:7253
CLI11_NODISCARD App * get_option_group(std::string group_name) const
Check to see if an option group is part of this App.
Definition CLI11.hpp:9042
App * require_subcommand()
The argumentless form of require subcommand requires 1 or more subcommands.
Definition CLI11.hpp:7802
std::string usage_
Usage to put after program/subcommand description in the help output INHERITABLE.
Definition CLI11.hpp:7139
OptionDefaults option_defaults_
The default values for options, customizable and changeable INHERITABLE.
Definition CLI11.hpp:7129
CLI11_NODISCARD const Option * get_version_ptr() const
Get a pointer to the version option. (const).
Definition CLI11.hpp:8222
void _process_requirements()
Verify required options and cross requirements. Subcommands too (only if selected).
Definition CLI11.hpp:9811
App * allow_extras(ExtrasMode allow)
Remove the error when extras are left over on the command line.
Definition CLI11.hpp:7367
CLI11_NODISCARD std::size_t count_all() const
Definition CLI11.hpp:9051
CLI11_NODISCARD bool get_fallthrough() const
Check the status of fallthrough.
Definition CLI11.hpp:8119
bool disabled_
If set to true the subcommand is disabled and cannot be used, ignored for main app.
Definition CLI11.hpp:7106
CLI11_NODISCARD bool get_prefix_command() const
Get the prefix command status.
Definition CLI11.hpp:8159
Option * add_option(std::string option_name, AssignTo &variable, std::string option_description="")
Add option for assigning to a variable.
Definition CLI11.hpp:7552
CLI11_NODISCARD std::size_t get_require_subcommand_max() const
Get the required max subcommand value.
Definition CLI11.hpp:8150
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.
Definition CLI11.hpp:8798
bool required_
If set to true the subcommand is required to be processed and used, ignored for main app.
Definition CLI11.hpp:7103
bool remove_needs(Option *opt)
Removes an option from the needs list of this subcommand.
Definition CLI11.hpp:9269
const Option * operator[](const char *option_name) const
Shortcut bracket operator for getting a pointer to an option.
Definition CLI11.hpp:8110
CLI11_NODISCARD bool get_immediate_callback() const
Get the status of disabled.
Definition CLI11.hpp:8186
Option * get_help_ptr()
Get a pointer to the help flag.
Definition CLI11.hpp:8204
App * require_subcommand(int value)
Definition CLI11.hpp:7811
void _configure()
Definition CLI11.hpp:9578
CLI11_NODISCARD std::size_t _count_remaining_positionals(bool required_only=false) const
Count the required remaining positional arguments.
Definition CLI11.hpp:10289
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.
Definition CLI11.hpp:8874
OptionDefaults * option_defaults()
Get the OptionDefault object, to set option defaults.
Definition CLI11.hpp:7522
void parse(int argc, const char *const *argv)
Definition CLI11.hpp:9081
void _process_config_file()
Read and process a configuration file (main app only).
Definition CLI11.hpp:9699
std::string footer_
Footer to put after all options in the help output INHERITABLE.
Definition CLI11.hpp:7145
void increment_parsed()
Internal function to recursively increment the parsed counter on the current app as well unnamed subc...
Definition CLI11.hpp:9999
CLI11_NODISCARD bool check_name(std::string name_to_check) const
Definition CLI11.hpp:9441
CLI11_NODISCARD std::string get_footer() const
Generate and return the footer.
Definition CLI11.hpp:8142
App * required(bool require=true)
Remove the error when extras are left over on the command line.
Definition CLI11.hpp:7373
Option * version_ptr_
A pointer to a version flag if there is one.
Definition CLI11.hpp:7157
CLI11_NODISCARD const Option * get_help_all_ptr() const
Get a pointer to the help all flag. (const).
Definition CLI11.hpp:8210
bool remove_subcommand(App *subcom)
Removes a subcommand from the App. Takes a subcommand pointer. Returns true if found and removed.
Definition CLI11.hpp:8972
App * parent_
A pointer to the parent if this is a subcommand.
Definition CLI11.hpp:7268
Option * add_flag(std::string flag_name, T &&flag_description)
Definition CLI11.hpp:7659
std::set< Option * > exclude_options_
Definition CLI11.hpp:7187
void _trigger_pre_parse(std::size_t remaining_args)
Trigger the pre_parse callback if needed.
Definition CLI11.hpp:10791
App * group(std::string group_name)
Changes the group membership.
Definition CLI11.hpp:7796
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.
Definition CLI11.hpp:9017
std::function< std::string()> footer_callback_
This is a function that generates a footer to put after all other options in help output.
Definition CLI11.hpp:7148
ExtrasMode allow_extras_
If true, allow extra arguments (ie, don't throw an error). INHERITABLE.
Definition CLI11.hpp:7090
PrefixCommandMode prefix_command_
If true, cease processing on an unrecognized option (implies allow_extras) INHERITABLE.
Definition CLI11.hpp:7097
std::function< void()> parse_complete_callback_
This is a function that runs when parsing has finished.
Definition CLI11.hpp:7119
CLI11_NODISCARD bool get_subcommand_fallthrough() const
Check the status of subcommand fallthrough.
Definition CLI11.hpp:8122
virtual void pre_callback()
Definition CLI11.hpp:7883
T * add_option_group(std::string group_name, std::string group_description="")
creates an option group as part of the given app
Definition CLI11.hpp:7732
App * get_parent()
Get the parent of this subcommand (or nullptr if main app).
Definition CLI11.hpp:8225
Option * add_flag(std::string flag_name)
Add a flag with no description or variable assignment.
Definition CLI11.hpp:7649
void _validate() const
Definition CLI11.hpp:9543
std::string name_
Subcommand name or program name (from parser if name is empty).
Definition CLI11.hpp:7084
std::vector< App * > parsed_subcommands_
This is a list of the subcommands collected, in order.
Definition CLI11.hpp:7180
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.
Definition CLI11.hpp:7304
CLI11_NODISCARD const Option * get_help_ptr() const
Get a pointer to the help flag. (const).
Definition CLI11.hpp:8207
bool ignore_underscore_
If true, the program should ignore underscores INHERITABLE.
Definition CLI11.hpp:7208
App * allow_windows_style_options(bool value=true)
Definition CLI11.hpp:7480
missing_t missing_
Definition CLI11.hpp:7174
CLI11_NODISCARD bool get_validate_positionals() const
Get the status of validating positionals.
Definition CLI11.hpp:8194
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.
Definition CLI11.hpp:7594
void run_callback(bool final_mode=false, bool suppress_final_callback=false)
Internal function to run (App) callback, bottom up.
Definition CLI11.hpp:9598
bool allow_prefix_matching_
indicator to allow subcommands to match with prefix matching
Definition CLI11.hpp:7250
std::size_t require_subcommand_min_
Minimum required subcommands (not inheritable!).
Definition CLI11.hpp:7256
App * usage(std::string usage_string)
Set usage.
Definition CLI11.hpp:8016
CLI11_NODISCARD NameMatch check_name_detail(std::string name_to_check) const
Definition CLI11.hpp:9446
App * allow_subcommand_prefix_matching(bool allowed=true)
allow prefix matching for subcommands
Definition CLI11.hpp:7397
void _process_env()
Get envname options if not yet passed. Runs on all subcommands.
Definition CLI11.hpp:9735
std::function< std::string(const App *, const Error &e)> failure_message_
The error message printing function INHERITABLE.
Definition CLI11.hpp:7163
void _parse_stream(std::istream &input)
Internal function to parse a stream.
Definition CLI11.hpp:10060
CLI11_NODISCARD std::string get_display_name(bool with_aliases=false) const
Get a display name for an app.
Definition CLI11.hpp:9425
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.
Definition CLI11.hpp:7918
bool has_automatic_name_
If set to true the name was automatically generated from the command line vs a user set name.
Definition CLI11.hpp:7100
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...
Definition CLI11.hpp:10831
void clear()
Reset the parsed data.
Definition CLI11.hpp:9065
CLI11_NODISCARD std::size_t get_require_option_max() const
Get the required max option value.
Definition CLI11.hpp:8156
App * enabled_by_default(bool enable=true)
Definition CLI11.hpp:7413
App * footer(std::string footer_string)
Set footer.
Definition CLI11.hpp:8026
App * get_subcommand(const App *subcom) const
Definition CLI11.hpp:8988
App * require_option(int value)
Definition CLI11.hpp:7840
CLI11_NODISCARD std::string version() const
Displays a version string.
Definition CLI11.hpp:9301
virtual ~App()=default
virtual destructor
CLI11_NODISCARD App * get_subcommand_no_throw(std::string subcom) const noexcept
Definition CLI11.hpp:9004
CLI11_NODISCARD std::size_t count(std::string option_name) const
Counts the number of times the given option was passed.
Definition CLI11.hpp:7930
bool _add_flag_like_result(Option *op, const ConfigItem &item, const std::vector< std::string > &inputs)
store the results for a flag like option
Definition CLI11.hpp:10079
std::vector< Option_p > options_
The list of options, stored locally.
Definition CLI11.hpp:7132
Option * help_all_ptr_
A pointer to the help all flag if there is one INHERITABLE.
Definition CLI11.hpp:7154
bool validate_optional_arguments_
If set to true optional vector arguments are validated before assigning INHERITABLE.
Definition CLI11.hpp:7240
std::function< void()> final_callback_
This is a function that runs when all processing has completed.
Definition CLI11.hpp:7122
bool remove_option(Option *opt)
Removes an option from the App. Takes an option pointer. Returns true if found and removed.
Definition CLI11.hpp:8918
App * require_option()
The argumentless form of require option requires 1 or more options be used.
Definition CLI11.hpp:7831
App(std::string app_description, std::string app_name, App *parent)
Special private constructor for subcommand.
Definition CLI11.hpp:8517
std::function< std::string()> usage_callback_
This is a function that generates a usage to put after program/subcommand description in help output.
Definition CLI11.hpp:7142
App * add_subcommand(std::string subcommand_name="", std::string subcommand_description="")
Add a subcommand. Inherits INHERITABLE and OptionDefaults, and help flag.
Definition CLI11.hpp:8941
App * preparse_callback(std::function< void(std::size_t)> pp_callback)
Definition CLI11.hpp:7349
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.
Definition CLI11.hpp:8857
bool positionals_at_end_
specify that positional arguments come at the end of the argument sequence not inheritable
Definition CLI11.hpp:7226
void _process()
Process callbacks and such.
Definition CLI11.hpp:9939
bool immediate_callback_
Definition CLI11.hpp:7113
bool _parse_single(std::vector< std::string > &args, bool &positional_only)
Definition CLI11.hpp:10240
App * name(std::string app_name="")
Set a name for the app (empty will use parser to set the name).
Definition CLI11.hpp:8574
void _move_option(Option *opt, App *app)
function that could be used by subclasses of App to shift options around into subcommands
Definition CLI11.hpp:10909
CLI11_NODISCARD bool get_required() const
Get the status of required.
Definition CLI11.hpp:8171
void _process_extras()
Throw an error if anything is left over and should not be.
Definition CLI11.hpp:9978
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.
Definition CLI11.hpp:9625
CLI11_NODISCARD PrefixCommandMode get_prefix_command_mode() const
Get the prefix command status.
Definition CLI11.hpp:8162
CLI11_NODISCARD bool get_ignore_case() const
Check the status of ignore_case.
Definition CLI11.hpp:8113
App * parse_complete_callback(std::function< void()> pc_callback)
Definition CLI11.hpp:7342
bool configurable_
if set to true the subcommand can be triggered via configuration files INHERITABLE
Definition CLI11.hpp:7234
CLI11_NODISCARD std::vector< std::string > get_groups() const
Get the groups available directly from this option (in order).
Definition CLI11.hpp:9484
CLI11_NODISCARD bool got_subcommand(std::string subcommand_name) const noexcept
Check with name instead of pointer to see if subcommand was selected.
Definition CLI11.hpp:7951
App * formatter_fn(std::function< std::string(const App *, std::string, AppFormatMode)> fmt)
Set the help formatter.
Definition CLI11.hpp:7507
CLI11_NODISCARD const std::vector< std::string > & get_aliases() const
Get the aliases of the current app.
Definition CLI11.hpp:8234
void _parse_config(const std::vector< ConfigItem > &args)
Definition CLI11.hpp:10071
App * description(std::string app_description)
Set the description of the app.
Definition CLI11.hpp:8071
CLI11_NODISCARD std::shared_ptr< ConfigBase > get_config_formatter_base() const
Access the config formatter as a configBase pointer.
Definition CLI11.hpp:8058
std::string description_
Description of the current program/subcommand.
Definition CLI11.hpp:7087
App * excludes(App *app)
Sets excluded subcommands for the subcommand.
Definition CLI11.hpp:7966
App * allow_non_standard_option_names(bool allowed=true)
allow non standard option names
Definition CLI11.hpp:7391
CLI11_NODISCARD bool get_positionals_at_end() const
Check the status of the allow windows style options.
Definition CLI11.hpp:8128
Option * get_version_ptr()
Get a pointer to the version option.
Definition CLI11.hpp:8219
CLI11_NODISCARD std::size_t get_require_option_min() const
Get the required min option value.
Definition CLI11.hpp:8153
std::size_t require_option_max_
Max number of options allowed. 0 is unlimited (not inheritable).
Definition CLI11.hpp:7265
CLI11_NODISCARD bool get_disabled() const
Get the status of disabled.
Definition CLI11.hpp:8174
CLI11_NODISCARD bool get_allow_windows_style_options() const
Check the status of the allow windows style options.
Definition CLI11.hpp:8125
std::vector< std::string > aliases_
Alias names for the subcommand.
Definition CLI11.hpp:7274
CLI11_NODISCARD bool parsed() const
Check to see if this subcommand was parsed, true only if received on command line.
Definition CLI11.hpp:7519
std::set< App * > exclude_subcommands_
this is a list of subcommands that are exclusionary to this one
Definition CLI11.hpp:7183
CLI11_NODISCARD bool get_disabled_by_default() const
Get the status of disabled by default.
Definition CLI11.hpp:8189
Option * add_flag(std::string flag_name, std::vector< T > &flag_results, std::string flag_description="")
Vector version to capture multiple flags.
Definition CLI11.hpp:7685
ConfigExtrasMode allow_config_extras_
Definition CLI11.hpp:7094
CLI11_NODISCARD std::size_t count() const
Definition CLI11.hpp:7789
bool _parse_positional(std::vector< std::string > &args, bool haltOnSubcommand)
Definition CLI11.hpp:10311
CLI11_NODISCARD Option * get_option(std::string option_name)
Get an option by name (non-const version).
Definition CLI11.hpp:8098
bool ignore_case_
If true, the program name is not case-sensitive INHERITABLE.
Definition CLI11.hpp:7205
CLI11_NODISCARD const std::string & get_group() const
Get the group of this subcommand.
Definition CLI11.hpp:8134
bool _parse_arg(std::vector< std::string > &args, detail::Classifier current_type, bool local_processing_only)
Definition CLI11.hpp:10525
bool silent_
Definition CLI11.hpp:7244
CLI11_NODISCARD const App * get_parent() const
Get the parent of this subcommand (or nullptr if main app) (const version).
Definition CLI11.hpp:8228
std::function< void(std::size_t)> pre_parse_callback_
This is a function that runs prior to the start of parsing.
Definition CLI11.hpp:7116
App * final_callback(std::function< void()> app_callback)
Definition CLI11.hpp:7335
std::string group_
The group membership INHERITABLE.
Definition CLI11.hpp:7271
App * alias(std::string app_name)
Set an alias for the app.
Definition CLI11.hpp:8591
bool pre_parse_called_
Flag indicating that the pre_parse_callback has been triggered.
Definition CLI11.hpp:7109
CLI11_NODISCARD ExtrasMode get_allow_extras_mode() const
Get the mode of allow_extras.
Definition CLI11.hpp:8168
App * validate_positionals(bool validate=true)
Set the subcommand to validate positional arguments before assigning.
Definition CLI11.hpp:7427
Option * help_ptr_
A pointer to the help flag if there is one INHERITABLE.
Definition CLI11.hpp:7151
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.
Definition CLI11.hpp:8889
App * footer(std::function< std::string()> footer_function)
Set footer.
Definition CLI11.hpp:8031
App * ignore_case(bool value=true)
Ignore case. Subcommands inherit value.
Definition CLI11.hpp:8621
App * excludes(Option *opt)
Sets excluded options for the subcommand.
Definition CLI11.hpp:7957
CLI11_NODISCARD std::shared_ptr< Config > get_config_formatter() const
Access the config formatter.
Definition CLI11.hpp:8055
App * prefix_command(PrefixCommandMode mode)
Definition CLI11.hpp:7470
bool remove_excludes(Option *opt)
Removes an option from the excludes list of this subcommand.
Definition CLI11.hpp:9249
CLI11_NODISCARD std::vector< App * > get_subcommands() const
Definition CLI11.hpp:7934
bool got_subcommand(const App *subcom) const
Check to see if given subcommand was selected.
Definition CLI11.hpp:7945
CLI11_NODISCARD config_extras_mode get_allow_config_extras() const
Get the status of allow extras.
Definition CLI11.hpp:8199
App * allow_config_extras(ConfigExtrasMode mode)
ignore extras in config files
Definition CLI11.hpp:7456
bool _parse_subcommand(std::vector< std::string > &args)
Definition CLI11.hpp:10485
App * positionals_at_end(bool value=true)
Specify that the positional arguments are only at the end of the sequence.
Definition CLI11.hpp:7486
bool fallthrough_
Definition CLI11.hpp:7212
std::set< Option * > need_options_
Definition CLI11.hpp:7195
CLI11_NODISCARD bool get_validate_optional_arguments() const
Get the status of validating optional vector arguments.
Definition CLI11.hpp:8196
CLI11_NODISCARD bool get_silent() const
Get the status of silence.
Definition CLI11.hpp:8177
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...
Definition CLI11.hpp:9319
std::set< App * > need_subcommands_
Definition CLI11.hpp:7191
App * validate_optional_arguments(bool validate=true)
Set the subcommand to validate optional vector arguments before assigning.
Definition CLI11.hpp:7433
Option * add_option(std::string option_name, callback_t option_callback, std::string option_description="", bool defaulted=false, std::function< std::string()> func={})
Definition CLI11.hpp:8649
App * formatter(std::shared_ptr< FormatterBase > fmt)
Set the help formatter.
Definition CLI11.hpp:7501
std::vector< Option * > parse_order_
This is a list of pointers to options with the original parse order.
Definition CLI11.hpp:7177
Option * add_option(std::string option_name, T &option_description)
Add option with description but with no variable assignment or callback.
Definition CLI11.hpp:7623
App * prefix_command(bool is_prefix=true)
Definition CLI11.hpp:7463
CLI11_NODISCARD const std::vector< Option * > & parse_order() const
This gets a vector of pointers with the original parse order.
Definition CLI11.hpp:8261
void _parse(std::vector< std::string > &args)
Internal parse function.
Definition CLI11.hpp:10007
bool validate_positionals_
If set to true positional options are validated before assigning INHERITABLE.
Definition CLI11.hpp:7237
bool _parse_single_config(const ConfigItem &item, std::size_t level=0)
Fill in a single config option.
Definition CLI11.hpp:10140
void _process_help_flags(CallbackPriority priority, bool trigger_help=false, bool trigger_all_help=false) const
Definition CLI11.hpp:9786
startup_mode default_startup
Definition CLI11.hpp:7231
App * allow_config_extras(config_extras_mode mode)
ignore extras in config files
Definition CLI11.hpp:7450
Option * add_flag(std::string flag_name, T &flag_result, std::string flag_description="")
Definition CLI11.hpp:7669
void _process_callbacks(CallbackPriority priority)
Process callbacks. Runs on all subcommands.
Definition CLI11.hpp:9757
CLI11_NODISCARD std::string get_description() const
Get the app or subcommand description.
Definition CLI11.hpp:8068
App * require_option(std::size_t min, std::size_t max)
Definition CLI11.hpp:7853
CLI11_NODISCARD char ** ensure_utf8(char **argv)
Convert the contents of argv to UTF-8. Only does something on Windows, does nothing elsewhere.
Definition CLI11.hpp:8552
CLI11_NODISCARD App * _find_subcommand(const std::string &subc_name, bool ignore_disabled, bool ignore_used) const noexcept
Definition CLI11.hpp:10449
CLI11_NODISCARD std::size_t get_require_subcommand_min() const
Get the required min subcommand value.
Definition CLI11.hpp:8147
CLI11_NODISCARD const Option * get_config_ptr() const
Get a pointer to the config option. (const).
Definition CLI11.hpp:8216
CLI11_NODISCARD const std::string & get_name() const
Get the name of the current app.
Definition CLI11.hpp:8231
App * disabled(bool disable=true)
Disable the subcommand or option group.
Definition CLI11.hpp:7379
App * callback(std::function< void()> app_callback)
Definition CLI11.hpp:7324
std::shared_ptr< FormatterBase > formatter_
This is the formatter for help printing. Default provided. INHERITABLE (same pointer).
Definition CLI11.hpp:7160
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.
Definition CLI11.hpp:8781
App * require_subcommand(std::size_t min, std::size_t max)
Definition CLI11.hpp:7824
CLI11_NODISCARD const Option * get_option(std::string option_name) const
Get an option by name.
Definition CLI11.hpp:8089
bool allow_windows_style_options_
Allow '/' for options for Windows like options. Defaults to true on Windows, false otherwise....
Definition CLI11.hpp:7218
std::shared_ptr< Config > config_formatter_
This is the formatter for help printing. Default provided. INHERITABLE (same pointer).
Definition CLI11.hpp:7284
Thrown when the wrong number of arguments has been received.
Definition CLI11.hpp:1603
Definition CLI11.hpp:4873
Options
Definition CLI11.hpp:4879
AsSizeValue(bool kb_is_1000)
Definition CLI11.hpp:5092
Thrown on construction of a bad name.
Definition CLI11.hpp:1464
Bound(T min_val, T max_val)
Definition CLI11.hpp:4514
Bound(T max_val)
Range of one value is 0 to value.
Definition CLI11.hpp:4536
Usually something like –help-all on command line.
Definition CLI11.hpp:1518
-h or –help on command line
Definition CLI11.hpp:1512
-v or –version on command line
Definition CLI11.hpp:1525
This converter works with INI/TOML files; to write INI files use ConfigINI.
Definition CLI11.hpp:3766
std::vector< ConfigItem > from_config(std::istream &input) const override
Convert a configuration into an app.
Definition CLI11.hpp:11327
std::string configSection
Specify the configuration section that should be used.
Definition CLI11.hpp:3793
ConfigBase * comment(char cchar)
Specify the configuration for comment characters.
Definition CLI11.hpp:3801
ConfigBase * arrayDelimiter(char aSep)
Specify the delimiter character for an array.
Definition CLI11.hpp:3812
ConfigBase * quoteCharacter(char qString, char literalChar)
Specify the quote characters used around strings and literal strings.
Definition CLI11.hpp:3822
char arraySeparator
the character used to separate elements in an array
Definition CLI11.hpp:3775
std::string & sectionRef()
get a reference to the configuration section
Definition CLI11.hpp:3843
ConfigBase * arrayBounds(char aStart, char aEnd)
Specify the start and end characters for an array.
Definition CLI11.hpp:3806
ConfigBase * maxLayers(uint8_t layers)
Specify the maximum number of parents.
Definition CLI11.hpp:3828
ConfigBase * allowDuplicateFields(bool value=true)
specify that multiple duplicate arguments should be merged even if not sequential
Definition CLI11.hpp:3862
CLI11_NODISCARD const std::string & section() const
get the section
Definition CLI11.hpp:3845
ConfigBase * commentDefaults(bool comDef=true)
comment default value options
Definition CLI11.hpp:3838
char stringQuote
the character to use around strings
Definition CLI11.hpp:3779
ConfigBase * section(const std::string §ionName)
specify a particular section of the configuration file to use
Definition CLI11.hpp:3847
ConfigBase * valueSeparator(char vSep)
Specify the delimiter between a name and value.
Definition CLI11.hpp:3817
uint8_t maximumLayers
the maximum number of layers to allow
Definition CLI11.hpp:3783
char valueDelimiter
the character used separate the name from the value
Definition CLI11.hpp:3777
char arrayStart
the character used to start an array '\0' is a default to not use
Definition CLI11.hpp:3771
char parentSeparatorChar
the separator used to separator parent layers
Definition CLI11.hpp:3785
bool allowMultipleDuplicateFields
specify the config reader should collapse repeated field names to a single vector
Definition CLI11.hpp:3789
CLI11_NODISCARD int16_t index() const
get the section index
Definition CLI11.hpp:3855
char literalQuote
the character to use around single characters and literal strings
Definition CLI11.hpp:3781
ConfigBase * index(int16_t sectionIndex)
specify a particular index in the section to use (-1) for all sections to use
Definition CLI11.hpp:3857
int16_t & indexRef()
get a reference to the configuration index
Definition CLI11.hpp:3853
char arrayEnd
the character used to end an array '\0' is a default to not use
Definition CLI11.hpp:3773
ConfigBase * parentSeparator(char sep)
Specify the separator to use for parent layers.
Definition CLI11.hpp:3833
bool commentDefaultsBool
comment default values
Definition CLI11.hpp:3787
int16_t configIndex
Specify the configuration index to use for arrayed sections.
Definition CLI11.hpp:3791
std::string to_config(const App *, bool default_also, bool write_description, std::string prefix) const override
Convert an app into a configuration.
Definition CLI11.hpp:11600
char commentChar
the character used for comments
Definition CLI11.hpp:3769
Thrown when extra values are found in an INI file.
Definition CLI11.hpp:1664
This class provides a converter for configuration files.
Definition CLI11.hpp:3725
virtual CLI11_NODISCARD std::string to_flag(const ConfigItem &item) const
Get a flag value.
Definition CLI11.hpp:3737
virtual std::string to_config(const App *, bool, bool, std::string) const =0
Convert an app into a configuration.
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.
Definition CLI11.hpp:3748
virtual ~Config()=default
Virtual destructor.
virtual std::vector< ConfigItem > from_config(std::istream &) const =0
Convert a configuration into an app.
Construction errors (not in parsing).
Definition CLI11.hpp:1431
Thrown when conversion call back fails, such as when an int fails to coerce to a string.
Definition CLI11.hpp:1545
All errors derive from this one.
Definition CLI11.hpp:1413
Thrown when an excludes option is present.
Definition CLI11.hpp:1641
Thrown when parsing an INI file and it is missing.
Definition CLI11.hpp:1538
Definition CLI11.hpp:1683
Thrown when an option is set to conflicting values (non-vector and multi args, for example).
Definition CLI11.hpp:1436
Thrown when validation fails before parsing.
Definition CLI11.hpp:1674
IsMember(T &&set)
This checks to see if an item is in a set (empty function).
Definition CLI11.hpp:4652
IsMember(T set, F filter_function)
Definition CLI11.hpp:4656
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).
Definition CLI11.hpp:4701
IsMember(std::initializer_list< T > values, Args &&...args)
This allows in-place construction using an initializer list.
Definition CLI11.hpp:4648
Thrown when an option already exists.
Definition CLI11.hpp:1484
Definition CLI11.hpp:5463
CRTP * mandatory(bool value=true)
Support Plumbum term.
Definition CLI11.hpp:5520
CRTP * take_all()
Set the multi option policy to take all arguments.
Definition CLI11.hpp:5576
CRTP * group(const std::string &name)
Changes the group membership.
Definition CLI11.hpp:5505
CRTP * join()
Set the multi option policy to join.
Definition CLI11.hpp:5583
bool always_capture_default_
Automatically capture default value.
Definition CLI11.hpp:5490
MultiOptionPolicy multi_option_policy_
Policy for handling multiple arguments beyond the expected Max.
Definition CLI11.hpp:5493
CRTP * join(char delim)
Set the multi option policy to join with a specific delimiter.
Definition CLI11.hpp:5590
CLI11_NODISCARD CallbackPriority get_callback_priority() const
The priority of callback.
Definition CLI11.hpp:5557
CLI11_NODISCARD bool get_always_capture_default() const
Return true if this will automatically capture the default value for help printing.
Definition CLI11.hpp:5551
CLI11_NODISCARD char get_delimiter() const
Get the current delimiter char.
Definition CLI11.hpp:5548
CLI11_NODISCARD bool get_required() const
True if this is a required option.
Definition CLI11.hpp:5533
CRTP * take_first()
Set the multi option policy to take last.
Definition CLI11.hpp:5569
CLI11_NODISCARD bool get_ignore_case() const
The status of ignore case.
Definition CLI11.hpp:5536
bool ignore_case_
Ignore the case when matching (option, not value).
Definition CLI11.hpp:5475
CRTP * configurable(bool value=true)
Allow in a configuration file.
Definition CLI11.hpp:5598
CRTP * delimiter(char value='\0')
Allow in a configuration file.
Definition CLI11.hpp:5604
CLI11_NODISCARD MultiOptionPolicy get_multi_option_policy() const
The status of the multi option policy.
Definition CLI11.hpp:5554
CLI11_NODISCARD bool get_configurable() const
The status of configurable.
Definition CLI11.hpp:5542
bool configurable_
Allow this option to be given in a configuration file.
Definition CLI11.hpp:5481
CallbackPriority callback_priority_
Priority of callback.
Definition CLI11.hpp:5496
bool disable_flag_override_
Disable overriding flag values with '=value'.
Definition CLI11.hpp:5484
bool required_
True if this is a required option.
Definition CLI11.hpp:5472
CRTP * take_last()
Set the multi option policy to take last.
Definition CLI11.hpp:5562
char delimiter_
Specify a delimiter character for vector arguments.
Definition CLI11.hpp:5487
std::string group_
The group membership.
Definition CLI11.hpp:5469
CLI11_NODISCARD bool get_ignore_underscore() const
The status of ignore_underscore.
Definition CLI11.hpp:5539
bool ignore_underscore_
Ignore underscores when matching (option, not value).
Definition CLI11.hpp:5478
CLI11_NODISCARD bool get_disable_flag_override() const
The status of configurable.
Definition CLI11.hpp:5545
CLI11_NODISCARD const std::string & get_group() const
Get the group of this option.
Definition CLI11.hpp:5530
void copy_to(T *other) const
Copy the contents to another similar class (one based on OptionBase).
Definition CLI11.hpp:6267
CRTP * required(bool value=true)
Set the option as required.
Definition CLI11.hpp:5514
Definition CLI11.hpp:5612
OptionDefaults * multi_option_policy(MultiOptionPolicy value=MultiOptionPolicy::Throw)
Take the last argument if given multiple times.
Definition CLI11.hpp:5625
OptionDefaults * ignore_case(bool value=true)
Ignore the case of the option name.
Definition CLI11.hpp:5631
OptionDefaults * ignore_underscore(bool value=true)
Ignore underscores in the option name.
Definition CLI11.hpp:5637
OptionDefaults * callback_priority(CallbackPriority value=CallbackPriority::Normal)
Set the callback priority.
Definition CLI11.hpp:5619
OptionDefaults * delimiter(char value='\0')
set a delimiter character to split up single arguments to treat as multiple inputs
Definition CLI11.hpp:5649
OptionDefaults * disable_flag_override(bool value=true)
Disable overriding flag values with an '=' segment.
Definition CLI11.hpp:5643
Thrown when counting a nonexistent option.
Definition CLI11.hpp:1691
Extension of App to better manage groups of options.
Definition CLI11.hpp:8400
App * add_subcommand(App *subcom)
Add an existing subcommand to be a member of an option_group.
Definition CLI11.hpp:8430
Option * add_option(Option *opt)
Add an existing option to the Option_group.
Definition CLI11.hpp:8414
void add_options(Option *opt, Args... args)
Add a bunch of options to the group.
Definition CLI11.hpp:8424
void add_options(Option *opt)
Add an existing option to the Option_group.
Definition CLI11.hpp:8422
Definition CLI11.hpp:5655
Option * type_size(int option_type_size)
Set a custom option size.
Definition CLI11.hpp:6737
Option * expected(int value)
Set the number of expected arguments.
Definition CLI11.hpp:6280
Option * check(Validator_p validator)
Adds a shared validator.
Definition CLI11.hpp:6320
CLI11_NODISCARD bool get_positional() const
True if the argument can be given directly.
Definition CLI11.hpp:6024
std::string default_str_
A human readable default value, either manually set, captured, or captured by default.
Definition CLI11.hpp:5690
bool run_callback_for_default_
Control option to run the callback to set the default.
Definition CLI11.hpp:5759
CLI11_NODISCARD std::string get_envname() const
The environment variable associated to this value.
Definition CLI11.hpp:5969
CLI11_NODISCARD bool check_name(const std::string &name) const
Check a name. Requires "-" or "--" for short / long, supports positional name.
Definition CLI11.hpp:6624
Option * type_name(std::string typeval)
Set a custom option typestring.
Definition CLI11.hpp:6177
std::function< std::string()> type_name_
Definition CLI11.hpp:5698
option_state
enumeration for the option state machine
Definition CLI11.hpp:5746
@ reduced
a subset of results has been generated
Definition CLI11.hpp:5749
@ callback_run
the callback has been executed
Definition CLI11.hpp:5750
@ validated
the results have been validated
Definition CLI11.hpp:5748
@ parsing
The option is currently collecting parsed results.
Definition CLI11.hpp:5747
option_state current_option_state_
Whether the callback has run (needed for INI parsing).
Definition CLI11.hpp:5753
std::string option_text_
If given, replace the text that describes the option type and usage in the help text.
Definition CLI11.hpp:5693
int type_size_min_
The minimum number of arguments an option should be expecting.
Definition CLI11.hpp:5711
Option * callback_priority(CallbackPriority value=CallbackPriority::Normal)
Definition CLI11.hpp:5844
CLI11_NODISCARD results_t reduced_results() const
Get a copy of the results.
Definition CLI11.hpp:6719
CLI11_NODISCARD std::string get_type_name() const
Get the full typename for this option.
Definition CLI11.hpp:6780
CLI11_NODISCARD bool check_fname(std::string name) const
Requires "--" to be removed from string.
Definition CLI11.hpp:6089
std::string pname_
A positional name.
Definition CLI11.hpp:5677
int expected_min_
The minimum number of expected values.
Definition CLI11.hpp:5714
Option * transform(Validator_p validator)
Adds a shared Validator.
Definition CLI11.hpp:6349
Option * ignore_case(bool value=true)
Definition CLI11.hpp:6445
std::set< Option * > needs_
A list of options that are required with this option.
Definition CLI11.hpp:5722
Option * default_function(const std::function< std::string()> &func)
Set a capture function for the default. Mostly used by App.
Definition CLI11.hpp:6192
CLI11_NODISCARD int get_type_size_min() const
The minimum number of arguments the option expects.
Definition CLI11.hpp:5961
void run_callback()
Process the callback.
Definition CLI11.hpp:6553
CLI11_NODISCARD std::string get_name(bool positional=false, bool all_options=false, bool disable_default_flag_values=false) const
Gets a comma separated list of names. Will include / prefer the positional name if positional is true...
Definition CLI11.hpp:6500
CLI11_NODISCARD bool check_sname(std::string name) const
Requires "-" to be removed from string.
Definition CLI11.hpp:6079
bool trigger_on_result_
flag indicating that the option should trigger the validation and callback chain on each result when ...
Definition CLI11.hpp:5763
bool flag_like_
Specify that the option should act like a flag vs regular option.
Definition CLI11.hpp:5757
std::set< Option * > excludes_
A list of options that are excluded with this option.
Definition CLI11.hpp:5725
bool force_callback_
flag indicating that the option should force the callback regardless if any results present
Definition CLI11.hpp:5765
CLI11_NODISCARD bool get_callback_run() const
See if the callback has been run already.
Definition CLI11.hpp:6164
CLI11_NODISCARD bool get_force_callback() const
The status of force_callback.
Definition CLI11.hpp:5831
std::vector< std::string > fnames_
a list of flag names with specified default values;
Definition CLI11.hpp:5674
Option(std::string option_name, std::string option_description, callback_t callback, App *parent, bool allow_non_standard=false)
Making an option by hand is not defined, it must be made by the App class.
Definition CLI11.hpp:5768
CLI11_NODISCARD bool get_run_callback_for_default() const
Get the current value of run_callback_for_default.
Definition CLI11.hpp:5840
CLI11_NODISCARD std::string get_default_str() const
The default value (for help printing).
Definition CLI11.hpp:5978
CLI11_NODISCARD bool nonpositional() const
True if option has at least one non-positional name.
Definition CLI11.hpp:6027
CLI11_NODISCARD int get_items_expected_min() const
The total min number of expected string values to be used.
Definition CLI11.hpp:6013
CLI11_NODISCARD const std::string & matching_name(const Option &other) const
If options share any of the same names, find it.
Definition CLI11.hpp:6586
CLI11_NODISCARD bool check_lname(std::string name) const
Requires "--" to be removed from string.
Definition CLI11.hpp:6084
CLI11_NODISCARD const results_t & results() const
Get the current complete results set.
Definition CLI11.hpp:6110
Option * disable_flag_override(bool value=true)
Disable flag overrides values, e.g. –flag=is not allowed.
Definition CLI11.hpp:5949
CLI11_NODISCARD int get_items_expected_max() const
Get the maximum number of items expected to be returned and used for the callback.
Definition CLI11.hpp:6016
std::vector< std::string > snames_
A list of the short names (-a) without the leading dashes.
Definition CLI11.hpp:5664
results_t proc_results_
results after reduction
Definition CLI11.hpp:5744
bool remove_excludes(Option *opt)
Remove needs link from an option. Returns true if the option really was in the needs list.
Definition CLI11.hpp:6435
CLI11_NODISCARD std::size_t count() const
Count the total number of times an option was passed.
Definition CLI11.hpp:5785
Option * run_callback_for_default(bool value=true)
Definition CLI11.hpp:5835
void inject_separator(bool value=true)
Set the value of the separator injection flag.
Definition CLI11.hpp:6189
Option * allow_extra_args(bool value=true)
Definition CLI11.hpp:5811
Option * multi_option_policy(MultiOptionPolicy value=MultiOptionPolicy::Throw)
Take the last argument if given multiple times (or another policy).
Definition CLI11.hpp:6486
Option * trigger_on_parse(bool value=true)
Set the value of trigger_on_parse which specifies that the option callback should be triggered on eve...
Definition CLI11.hpp:5818
CLI11_NODISCARD callback_t get_callback() const
Get the callback function.
Definition CLI11.hpp:5981
CLI11_NODISCARD bool get_inject_separator() const
Return the inject_separator flag.
Definition CLI11.hpp:5966
std::vector< Validator_p > validators_
A list of Validators to run on each value parsed.
Definition CLI11.hpp:5719
Option * excludes(Option *opt)
Sets excluded options.
Definition CLI11.hpp:6420
App * parent_
link back up to the parent App for fallthrough
Definition CLI11.hpp:5732
CLI11_NODISCARD bool get_trigger_on_parse() const
The status of trigger on parse.
Definition CLI11.hpp:5823
CLI11_NODISCARD const std::vector< std::string > & get_lnames() const
Get the long names.
Definition CLI11.hpp:5984
int expected_max_
The maximum number of expected values.
Definition CLI11.hpp:5716
CLI11_NODISCARD std::set< Option * > get_excludes() const
The set of options excluded.
Definition CLI11.hpp:5975
CLI11_NODISCARD std::string get_flag_value(const std::string &name, std::string input_value) const
Definition CLI11.hpp:6653
Option * excludes(std::string opt_name)
Can find a string if needed.
Definition CLI11.hpp:5910
CLI11_NODISCARD int get_items_expected() const
The total min number of expected string values to be used.
Definition CLI11.hpp:6021
CLI11_NODISCARD std::set< Option * > get_needs() const
The set of options needed.
Definition CLI11.hpp:5972
std::string description_
The description for help strings.
Definition CLI11.hpp:5687
CLI11_NODISCARD const std::vector< std::string > & get_snames() const
Get the short names.
Definition CLI11.hpp:5987
CLI11_NODISCARD int get_type_size_max() const
The maximum number of arguments the option expects.
Definition CLI11.hpp:5963
bool inject_separator_
flag indicating a separator needs to be injected after each argument call
Definition CLI11.hpp:5761
CLI11_NODISCARD const std::string & get_description() const
Get the description.
Definition CLI11.hpp:6033
Validator * get_validator(const std::string &validator_name="")
Get a named Validator.
Definition CLI11.hpp:6390
CLI11_NODISCARD const std::string & get_single_name() const
Get a single name for the option, first of lname, sname, pname, envname.
Definition CLI11.hpp:5992
CLI11_NODISCARD int get_expected() const
The number of times the option expects to be included.
Definition CLI11.hpp:6005
callback_t callback_
Options store a callback to do all the work.
Definition CLI11.hpp:5735
CLI11_NODISCARD bool empty() const
True if the option was not passed.
Definition CLI11.hpp:5788
CLI11_NODISCARD int get_expected_min() const
The number of times the option expects to be included.
Definition CLI11.hpp:6008
void clear()
Clear the parsed results (mostly for testing).
Definition CLI11.hpp:5794
CLI11_NODISCARD int get_expected_max() const
The max number of times the option expects to be included.
Definition CLI11.hpp:6010
Option * capture_default_str()
Capture the default value from the original value (if it can be captured).
Definition CLI11.hpp:6198
void results(T &output) const
Get the results as a specified type.
Definition CLI11.hpp:6116
Option * default_str(std::string val)
Set the default value string representation (does not change the contained value).
Definition CLI11.hpp:6206
CLI11_NODISCARD int get_type_size() const
The number of arguments the option expects.
Definition CLI11.hpp:5958
std::string envname_
If given, check the environment for this option.
Definition CLI11.hpp:5680
std::function< std::string()> default_function_
Run this function to capture a default (ignore if empty).
Definition CLI11.hpp:5701
CLI11_NODISCARD bool get_allow_extra_args() const
Get the current value of allow extra args.
Definition CLI11.hpp:5816
Option * ignore_underscore(bool value=true)
Definition CLI11.hpp:6465
std::vector< std::pair< std::string, std::string > > default_flag_values_
Definition CLI11.hpp:5671
Option * envname(std::string name)
Sets environment variable to read if no option given.
Definition CLI11.hpp:5928
Option * type_name_fn(std::function< std::string()> typefun)
Set the type function to run when displayed on this option.
Definition CLI11.hpp:6171
Option * default_val(const X &val)
Definition CLI11.hpp:6213
Option * needs(Option *opt)
Sets required options.
Definition CLI11.hpp:5881
int type_size_max_
Definition CLI11.hpp:5709
Option * needs(A opt, B opt1, ARG... args)
Any number supported, any mix of string and Opt.
Definition CLI11.hpp:5898
bool allow_extra_args_
Specify that extra args beyond type_size_max should be allowed.
Definition CLI11.hpp:5755
Option * description(std::string option_description)
Set the description.
Definition CLI11.hpp:6036
std::vector< std::string > lnames_
A list of the long names (--long) without the leading dashes.
Definition CLI11.hpp:5667
Option * force_callback(bool value=true)
Set the value of force_callback.
Definition CLI11.hpp:5826
Option * add_result(std::string s)
Puts a result at the end.
Definition CLI11.hpp:6699
bool remove_needs(Option *opt)
Remove needs link from an option. Returns true if the option really was in the needs list.
Definition CLI11.hpp:6410
bool operator==(const Option &other) const
If options share any of the same names, they are equal (not counting positional).
Definition CLI11.hpp:6073
Option * each(const std::function< void(std::string)> &func)
Adds a user supplied function to run on each item passed in (communicate though lambda capture).
Definition CLI11.hpp:6379
Option * needs(std::string opt_name)
Can find a string if needed.
Definition CLI11.hpp:5889
CLI11_NODISCARD const std::vector< std::string > & get_fnames() const
Get the flag names with specified default values.
Definition CLI11.hpp:5990
CLI11_NODISCARD bool has_description() const
True if option has description.
Definition CLI11.hpp:6030
results_t results_
complete Results of parsing
Definition CLI11.hpp:5742
CLI11_NODISCARD T as() const
Return the results as the specified type.
Definition CLI11.hpp:6157
Option * excludes(A opt, B opt1, ARG... args)
Any number supported, any mix of string and Opt.
Definition CLI11.hpp:5919
Anything that can error in Parse.
Definition CLI11.hpp:1499
Produce a range (factory). Min and max are inclusive.
Definition CLI11.hpp:4091
Range(T min_val, T max_val, const std::string &validator_name=std::string{})
Definition CLI11.hpp:4098
Range(T max_val, const std::string &validator_name=std::string{})
Range of one value is 0 to value.
Definition CLI11.hpp:4121
Thrown when a required option is missing.
Definition CLI11.hpp:1568
Thrown when a requires option is missing.
Definition CLI11.hpp:1634
This is a successful completion on parsing, supposed to exit.
Definition CLI11.hpp:1506
Validate the input as a particular type.
Definition CLI11.hpp:4490
Thrown when validation of results fails.
Definition CLI11.hpp:1561
Some validators that are provided.
Definition CLI11.hpp:3898
Validator operator&(const Validator &other) const
Definition CLI11.hpp:4207
CLI11_NODISCARD int get_application_index() const
Get the current value of the application index.
Definition CLI11.hpp:3999
int application_index_
A Validator will only apply to an indexed value (-1 is all elements).
Definition CLI11.hpp:3909
Validator & non_modifying(bool no_modify=true)
Specify whether the Validator can be modifying or not.
Definition CLI11.hpp:3983
Validator & description(std::string validator_desc)
Specify the type string.
Definition CLI11.hpp:3943
std::string operator()(const std::string &str) const
Definition CLI11.hpp:3937
CLI11_NODISCARD Validator application_index(int app_index) const
Specify the application index of a validator.
Definition CLI11.hpp:3993
Validator operator|(const Validator &other) const
Definition CLI11.hpp:4229
CLI11_NODISCARD bool get_active() const
Get a boolean if the validator is active.
Definition CLI11.hpp:4001
bool active_
Enable for Validator to allow it to be disabled if need be.
Definition CLI11.hpp:3911
bool non_modifying_
specify that a validator should not modify the input
Definition CLI11.hpp:3913
Validator(std::string validator_desc)
Construct a Validator with just the description string.
Definition CLI11.hpp:3921
Validator & name(std::string validator_name)
Specify the type string.
Definition CLI11.hpp:3958
std::function< std::string()> desc_function_
This is the description function, if empty the description_ will be used.
Definition CLI11.hpp:3901
std::function< std::string(std::string &)> func_
Definition CLI11.hpp:3905
CLI11_NODISCARD std::string get_description() const
Generate type description information for the Validator.
Definition CLI11.hpp:3951
CLI11_NODISCARD Validator active(bool active_val=true) const
Specify whether the Validator is active or not.
Definition CLI11.hpp:3976
CLI11_NODISCARD const std::string & get_name() const
Get the name of the Validator.
Definition CLI11.hpp:3969
Validator & active(bool active_val=true)
Specify whether the Validator is active or not.
Definition CLI11.hpp:3971
std::string name_
The name for search purposes of the Validator.
Definition CLI11.hpp:3907
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...
Definition CLI11.hpp:4004
CLI11_NODISCARD Validator name(std::string validator_name) const
Specify the type string.
Definition CLI11.hpp:3963
Validator operator!() const
Create a validator that fails when a given validator succeeds.
Definition CLI11.hpp:4251
std::string operator()(std::string &str) const
Definition CLI11.hpp:4188
Validator & application_index(int app_index)
Specify the application index of a validator.
Definition CLI11.hpp:3988
Validator(std::function< std::string(std::string &)> op, std::string validator_desc, std::string validator_name="")
Construct Validator from basic information.
Definition CLI11.hpp:3923
Validator & operation(std::function< std::string(std::string &)> op)
Set the Validator operation function.
Definition CLI11.hpp:3927
Definition CLI11.hpp:1770
Check for an existing directory (returns error message if check fails).
Definition CLI11.hpp:4044
Check for an existing file (returns error message if check fails).
Definition CLI11.hpp:4038
Check for an existing path.
Definition CLI11.hpp:4050
Check for an non-existing path.
Definition CLI11.hpp:4056
Check for complex.
Definition CLI11.hpp:1909
Definition CLI11.hpp:1851
Check for input streamability.
Definition CLI11.hpp:1898
Definition CLI11.hpp:1887
Definition CLI11.hpp:1973
std::ostream & operator<<(std::ostream &in, const T &item)
output streaming for enumerations
Definition CLI11.hpp:503
Holds values to load into Options.
Definition CLI11.hpp:3705
std::vector< std::string > inputs
Listing of inputs.
Definition CLI11.hpp:3712
std::string name
This is the name.
Definition CLI11.hpp:3710
CLI11_NODISCARD std::string fullname() const
The list of parents and name joined by ".".
Definition CLI11.hpp:3716
bool multiline
indicator if a multiline vector separator was inserted
Definition CLI11.hpp:3714
std::vector< std::string > parents
This is the list of parents.
Definition CLI11.hpp:3707
This can be specialized to override the type deduction for IsMember.
Definition CLI11.hpp:1755
This class is simply to allow tests access to App's protected functions.
Definition CLI11.hpp:8479
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.
Definition CLI11.hpp:8501
static App * get_fallthrough_parent(App *app)
Wrap the fallthrough parent function to make sure that is working correctly.
Definition CLI11.hpp:8507
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.
Definition CLI11.hpp:8494
static const App * get_fallthrough_parent(const App *app)
Wrap the const fallthrough parent function to make sure that is working correctly.
Definition CLI11.hpp:8510
not a pointer
Definition CLI11.hpp:1789
Definition CLI11.hpp:1799
Definition CLI11.hpp:4592
Definition CLI11.hpp:1934
Definition CLI11.hpp:1954
Definition CLI11.hpp:1965
static auto first(Q &&pair_value) -> decltype(std::get< 0 >(std::forward< Q >(pair_value)))
Get the first value (really just the underlying value).
Definition CLI11.hpp:1831
static auto second(Q &&pair_value) -> decltype(std::get< 1 >(std::forward< Q >(pair_value)))
Get the second value (really just the underlying value).
Definition CLI11.hpp:1835
Adaptor for set-like structure: This just wraps a normal container in a few utilities that do almost ...
Definition CLI11.hpp:1804
static auto second(Q &&pair_value) -> decltype(std::forward< Q >(pair_value))
Get the second value (really just the underlying value).
Definition CLI11.hpp:1814
static auto first(Q &&pair_value) -> decltype(std::forward< Q >(pair_value))
Get the first value (really just the underlying value).
Definition CLI11.hpp:1810
forward declare the subtype_count_min structure
Definition CLI11.hpp:2175
Set of overloads to get the type size of an object.
Definition CLI11.hpp:2172
This will only trigger for actual void type.
Definition CLI11.hpp:1985
This will only trigger for actual void type.
Definition CLI11.hpp:2178
template to get the underlying value type if it exists or use a default
Definition CLI11.hpp:2160
Check to see if something is bool (fail check by default).
Definition CLI11.hpp:1735
Check to see if something is copyable pointer.
Definition CLI11.hpp:1750
Check to see if something is a shared pointer.
Definition CLI11.hpp:1741
A copy of std::void_t from C++17 (helper for C++11 and C++14).
Definition CLI11.hpp:1724