59 #include <sys/types.h> 61 #include <type_traits> 69 #define CLI11_VERSION_MAJOR 1 70 #define CLI11_VERSION_MINOR 6 71 #define CLI11_VERSION_PATCH 0 72 #define CLI11_VERSION "1.6.0" 81 #if !(defined(_MSC_VER) && __cplusplus == 199711L) && !defined(__INTEL_COMPILER) 82 #if __cplusplus >= 201402L 84 #if __cplusplus >= 201703L 86 #if __cplusplus > 201703L 91 #elif defined(_MSC_VER) && __cplusplus == 199711L 94 #if _MSVC_LANG >= 201402L 96 #if _MSVC_LANG > 201402L && _MSC_VER >= 1910 98 #if __MSVC_LANG > 201703L && _MSC_VER >= 1910 105 #if defined(CLI11_CPP14) 106 #define CLI11_DEPRECATED(reason) [[deprecated(reason)]] 107 #elif defined(_MSC_VER) 108 #define CLI11_DEPRECATED(reason) __declspec(deprecated(reason)) 110 #define CLI11_DEPRECATED(reason) __attribute__((deprecated(reason))) 120 #if defined(CLI11_CPP17) && __has_include(<optional>) && \ 121 !defined(CLI11_STD_OPTIONAL) 122 #define CLI11_STD_OPTIONAL 1 125 #if defined(CLI11_CPP14) && __has_include(<experimental/optional>) && \ 126 !defined(CLI11_EXPERIMENTAL_OPTIONAL) 127 #define CLI11_EXPERIMENTAL_OPTIONAL 1 130 #if __has_include(<boost/optional.hpp>) && !defined(CLI11_BOOST_OPTIONAL) 131 #include <boost/version.hpp> 132 #if BOOST_VERSION >= 105800 133 #define CLI11_BOOST_OPTIONAL 1 139 #if CLI11_STD_OPTIONAL 142 #if CLI11_EXPERIMENTAL_OPTIONAL 143 #include <experimental/optional> 145 #if CLI11_BOOST_OPTIONAL 146 #include <boost/optional.hpp> 162 #if CLI11_STD_OPTIONAL 163 template <
typename T> std::istream &
operator>>(std::istream &in, std::optional<T> &val) {
171 #if CLI11_EXPERIMENTAL_OPTIONAL 172 template <
typename T> std::istream &
operator>>(std::istream &in, std::experimental::optional<T> &val) {
180 #if CLI11_BOOST_OPTIONAL 181 template <
typename T> std::istream &
operator>>(std::istream &in, boost::optional<T> &val) {
190 #if CLI11_STD_OPTIONAL 192 #elif CLI11_EXPERIMENTAL_OPTIONAL 193 using std::experimental::optional;
194 #elif CLI11_BOOST_OPTIONAL 195 using boost::optional;
199 #if CLI11_STD_OPTIONAL || CLI11_EXPERIMENTAL_OPTIONAL || CLI11_BOOST_OPTIONAL 200 #define CLI11_OPTIONAL 1 212 inline std::vector<std::string>
split(
const std::string &s,
char delim) {
213 std::vector<std::string> elems;
216 elems.emplace_back(
"");
218 std::stringstream ss;
221 while(std::getline(ss, item, delim)) {
222 elems.push_back(item);
229 template <
typename T> std::string
join(
const T &v, std::string delim =
",") {
230 std::ostringstream s;
232 for(
const auto &i : v) {
241 template <
typename T> std::string
rjoin(
const T &v, std::string delim =
",") {
242 std::ostringstream s;
243 for(
size_t start = 0; start < v.size(); start++) {
246 s << v[v.size() - start - 1];
255 auto it = std::find_if(str.begin(), str.end(), [](
char ch) {
return !std::isspace<char>(ch, std::locale()); });
256 str.erase(str.begin(), it);
261 inline std::string &
ltrim(std::string &
str,
const std::string &filter) {
262 auto it = std::find_if(str.begin(), str.end(), [&filter](
char ch) {
return filter.find(ch) == std::string::npos; });
263 str.erase(str.begin(), it);
269 auto it = std::find_if(str.rbegin(), str.rend(), [](
char ch) {
return !std::isspace<char>(ch, std::locale()); });
270 str.erase(it.base(), str.end());
275 inline std::string &
rtrim(std::string &
str,
const std::string &filter) {
277 std::find_if(str.rbegin(), str.rend(), [&filter](
char ch) {
return filter.find(ch) == std::string::npos; });
278 str.erase(it.base(), str.end());
286 inline std::string &
trim(std::string &
str,
const std::string filter) {
return ltrim(
rtrim(str, filter), filter); }
295 inline std::string
trim_copy(
const std::string &
str,
const std::string &filter) {
297 return trim(s, filter);
300 inline std::ostream &
format_help(std::ostream &out, std::string name, std::string description,
size_t wid) {
302 out << std::setw(static_cast<int>(wid)) << std::left << name;
303 if(!description.empty()) {
304 if(name.length() >= wid)
305 out <<
"\n" << std::setw(static_cast<int>(wid)) <<
"";
313 template <
typename T>
bool valid_first_char(T c) {
return std::isalpha(c, std::locale()) || c ==
'_'; }
317 return std::isalnum(c, std::locale()) || c ==
'_' || c ==
'.' || c ==
'-';
324 for(
auto c : str.substr(1))
332 std::transform(std::begin(str), std::end(str), std::begin(str), [](
const std::string::value_type &x) {
333 return std::tolower(x, std::locale());
341 std::vector<char> delims = {
'\'',
'\"'};
342 auto find_ws = [](
char ch) {
return std::isspace<char>(ch, std::locale()); };
345 std::vector<std::string> output;
347 while(!str.empty()) {
349 auto end = str.find(
'\'', 1);
350 if(end != std::string::npos) {
351 output.push_back(str.substr(1, end - 1));
352 str = str.substr(end + 1);
354 output.push_back(str.substr(1));
357 }
else if(str[0] ==
'\"') {
358 auto end = str.find(
'\"', 1);
359 if(end != std::string::npos) {
360 output.push_back(str.substr(1, end - 1));
361 str = str.substr(end + 1);
363 output.push_back(str.substr(1));
368 auto it = std::find_if(std::begin(str), std::end(str), find_ws);
369 if(it != std::end(str)) {
370 std::string value = std::string(str.begin(), it);
371 output.push_back(value);
372 str = std::string(it, str.end());
374 output.push_back(str);
388 inline std::string
fix_newlines(std::string leader, std::string input) {
389 std::string::size_type n = 0;
390 while(n != std::string::npos && n < input.size()) {
391 n = input.find(
'\n', n);
392 if(n != std::string::npos) {
393 input = input.substr(0, n + 1) + leader + input.substr(n + 1);
409 #define CLI11_ERROR_DEF(parent, name) \ 411 name(std::string name, std::string msg, int exit_code) : parent(std::move(name), std::move(msg), exit_code) {} \ 412 name(std::string name, std::string msg, ExitCodes exit_code) \ 413 : parent(std::move(name), std::move(msg), exit_code) {} \ 416 name(std::string msg, ExitCodes exit_code) : parent(#name, std::move(msg), exit_code) {} \ 417 name(std::string msg, int exit_code) : parent(#name, std::move(msg), exit_code) {} 420 #define CLI11_ERROR_SIMPLE(name) \ 421 explicit name(std::string msg) : name(#name, msg, ExitCodes::name) {} 454 class Error :
public std::runtime_error {
456 std::string name{
"Error"};
464 : runtime_error(msg), exit_code(exit_code), name(
std::move(name)) {}
466 Error(std::string name, std::string msg,
ExitCodes exit_code) :
Error(name, msg, static_cast<int>(exit_code)) {}
494 name +
": You can't change expected arguments after you've changed the multi option policy!");
500 return IncorrectConstruction(name +
": multi_option_policy only works for flags and exact value options");
511 return BadNameString(
"Must have a name, not just dashes: " + name);
514 return BadNameString(
"Only one positional name allowed, remove: " + name);
577 :
ConversionError("The value " + member + " is not an allowed value for " + name) {}
615 : ("Expected at least " +
std::
to_string(-expected) + " arguments to " + name +
645 :
ExtrasError((args.size() > 1 ? "The following arguments were not expected: "
646 : "The following argument was not expected: ") +
647 detail::
rjoin(args, " "),
657 return ConfigError(item +
": This option is not allowed in a configuration file");
684 #undef CLI11_ERROR_DEF 685 #undef CLI11_ERROR_SIMPLE 703 template <
typename T>
struct is_vector {
static const bool value =
false; };
705 template <
class T,
class A>
struct is_vector<
std::vector<T, A>> {
static bool const value =
true; };
707 template <
typename T>
struct is_bool {
static const bool value =
false; };
709 template <>
struct is_bool<bool> {
static bool const value =
true; };
725 template <
typename T,
731 template <
typename T,
737 template <typename T, enable_if_t<std::is_floating_point<T>::value, detail::enabler> =
detail::dummy>
743 template <typename T, enable_if_t<is_vector<T>::value, detail::enabler> =
detail::dummy>
748 template <
typename T,
758 template <
typename T,
763 long long output_ll = std::stoll(input, &n, 0);
764 output =
static_cast<T
>(output_ll);
765 return n == input.size() &&
static_cast<long long>(output) == output_ll;
766 }
catch(
const std::invalid_argument &) {
768 }
catch(
const std::out_of_range &) {
774 template <
typename T,
777 if(!input.empty() && input.front() ==
'-')
782 unsigned long long output_ll = std::stoull(input, &n, 0);
783 output =
static_cast<T
>(output_ll);
784 return n == input.size() &&
static_cast<unsigned long long>(output) == output_ll;
785 }
catch(
const std::invalid_argument &) {
787 }
catch(
const std::out_of_range &) {
793 template <typename T, enable_if_t<std::is_floating_point<T>::value, detail::enabler> =
detail::dummy>
797 output =
static_cast<T
>(std::stold(input, &n));
798 return n == input.size();
799 }
catch(
const std::invalid_argument &) {
801 }
catch(
const std::out_of_range &) {
807 template <
typename T,
809 std::is_assignable<T &, std::string>::value,
817 template <
typename T,
819 !std::is_assignable<T &, std::string>::value,
822 std::istringstream is;
826 return !is.fail() && !is.rdbuf()->in_avail();
838 inline bool split_short(
const std::string ¤t, std::string &name, std::string &rest) {
839 if(current.size() > 1 && current[0] ==
'-' &&
valid_first_char(current[1])) {
840 name = current.substr(1, 1);
841 rest = current.substr(2);
848 inline bool split_long(
const std::string ¤t, std::string &name, std::string &value) {
849 if(current.size() > 2 && current.substr(0, 2) ==
"--" &&
valid_first_char(current[2])) {
850 auto loc = current.find(
"=");
851 if(loc != std::string::npos) {
852 name = current.substr(2, loc - 2);
853 value = current.substr(loc + 1);
855 name = current.substr(2);
864 inline std::vector<std::string>
split_names(std::string current) {
865 std::vector<std::string> output;
867 while((val = current.find(
",")) != std::string::npos) {
868 output.push_back(
trim_copy(current.substr(0, val)));
869 current = current.substr(val + 1);
876 inline std::tuple<std::vector<std::string>, std::vector<std::string>, std::string>
879 std::vector<std::string> short_names;
880 std::vector<std::string> long_names;
881 std::string pos_name;
883 for(std::string name : input) {
884 if(name.length() == 0)
886 else if(name.length() > 1 && name[0] ==
'-' && name[1] !=
'-') {
888 short_names.emplace_back(1, name[1]);
891 }
else if(name.length() > 2 && name.substr(0, 2) ==
"--") {
892 name = name.substr(2);
894 long_names.push_back(name);
897 }
else if(name ==
"-" || name ==
"--") {
900 if(pos_name.length() > 0)
906 return std::tuple<std::vector<std::string>, std::vector<std::string>, std::string>(
907 short_names, long_names, pos_name);
922 inline std::string ini_join(std::vector<std::string> args) {
923 std::ostringstream s;
925 for(
const auto &arg : args) {
929 auto it = std::find_if(arg.begin(), arg.end(), [](
char ch) {
return std::isspace<char>(ch, std::locale()); });
932 else if(arg.find(R
"(")") == std::string::npos) 933 s << R"(")" << arg << R"(")"; 935 s << R
"(')" << arg << R"(')"; 946 std::vector<std::string> parents;
952 std::vector<std::string> inputs;
955 std::string fullname()
const {
956 std::vector<std::string> tmp = parents;
957 tmp.emplace_back(name);
965 std::vector<ConfigItem> items;
969 virtual std::string to_config(
const App *,
bool,
bool, std::string)
const = 0;
972 virtual std::vector<ConfigItem> from_config(std::istream &)
const = 0;
975 virtual std::vector<std::string> to_flag(
const ConfigItem &item)
const {
976 if(item.inputs.size() == 1) {
977 std::string val = item.inputs.at(0);
980 if(val ==
"true" || val ==
"on" || val ==
"yes") {
981 return std::vector<std::string>(1);
982 }
else if(val ==
"false" || val ==
"off" || val ==
"no") {
983 return std::vector<std::string>();
986 size_t ui = std::stoul(val);
987 return std::vector<std::string>(ui);
988 }
catch(
const std::invalid_argument &) {
998 std::vector<ConfigItem> from_file(
const std::string &name) {
999 std::ifstream input{name};
1003 return from_config(input);
1007 virtual ~Config() =
default;
1011 class ConfigINI :
public Config {
1013 std::string to_config(
const App *,
bool default_also,
bool write_description, std::string prefix)
const override;
1015 std::vector<ConfigItem> from_config(std::istream &input)
const override {
1017 std::string section =
"default";
1019 std::vector<ConfigItem> output;
1021 while(getline(input, line)) {
1022 std::vector<std::string> items;
1025 size_t len = line.length();
1026 if(len > 1 && line[0] ==
'[' && line[len - 1] ==
']') {
1027 section = line.substr(1, len - 2);
1028 }
else if(len > 0 && line[0] !=
';') {
1029 output.emplace_back();
1030 ConfigItem &out = output.back();
1033 auto pos = line.find(
'=');
1034 if(pos != std::string::npos) {
1044 out.parents = {section};
1047 if(out.name.find(
'.') != std::string::npos) {
1048 std::vector<std::string> plist =
detail::split(out.name,
'.');
1049 out.name = plist.back();
1051 out.parents.insert(out.parents.end(), plist.begin(), plist.end());
1054 out.inputs.insert(std::end(out.inputs), std::begin(items), std::end(items));
1080 std::function<std::string(const std::string &filename)> func;
1084 std::string operator()(
const std::string &filename)
const {
return func(filename); };
1087 Validator operator&(
const Validator &other)
const {
1089 newval.tname = (tname == other.tname ? tname :
"");
1092 const std::function<std::string(const std::string &filename)> &f1 = func;
1093 const std::function<std::string(const std::string &filename)> &f2 = other.func;
1095 newval.func = [f1, f2](
const std::string &filename) {
1096 std::string s1 = f1(filename);
1097 std::string s2 = f2(filename);
1098 if(!s1.empty() && !s2.empty())
1099 return s1 +
" & " + s2;
1107 Validator operator|(
const Validator &other)
const {
1109 newval.tname = (tname == other.tname ? tname :
"");
1112 const std::function<std::string(const std::string &filename)> &f1 = func;
1113 const std::function<std::string(const std::string &filename)> &f2 = other.func;
1115 newval.func = [f1, f2](
const std::string &filename) {
1116 std::string s1 = f1(filename);
1117 std::string s2 = f2(filename);
1118 if(s1.empty() || s2.empty())
1119 return std::string();
1121 return s1 +
" & " + s2;
1133 struct ExistingFileValidator :
public Validator {
1134 ExistingFileValidator() {
1136 func = [](
const std::string &filename) {
1138 bool exist = stat(filename.c_str(), &buffer) == 0;
1139 bool is_dir = (buffer.st_mode & S_IFDIR) != 0;
1141 return "File does not exist: " + filename;
1143 return "File is actually a directory: " + filename;
1145 return std::string();
1151 struct ExistingDirectoryValidator :
public Validator {
1152 ExistingDirectoryValidator() {
1154 func = [](
const std::string &filename) {
1156 bool exist = stat(filename.c_str(), &buffer) == 0;
1157 bool is_dir = (buffer.st_mode & S_IFDIR) != 0;
1159 return "Directory does not exist: " + filename;
1160 }
else if(!is_dir) {
1161 return "Directory is actually a file: " + filename;
1163 return std::string();
1169 struct ExistingPathValidator :
public Validator {
1170 ExistingPathValidator() {
1172 func = [](
const std::string &filename) {
1174 bool const exist = stat(filename.c_str(), &buffer) == 0;
1176 return "Path does not exist: " + filename;
1178 return std::string();
1184 struct NonexistentPathValidator :
public Validator {
1185 NonexistentPathValidator() {
1187 func = [](
const std::string &filename) {
1189 bool exist = stat(filename.c_str(), &buffer) == 0;
1191 return "Path already exists: " + filename;
1193 return std::string();
1202 const detail::ExistingFileValidator ExistingFile;
1205 const detail::ExistingDirectoryValidator ExistingDirectory;
1208 const detail::ExistingPathValidator ExistingPath;
1211 const detail::NonexistentPathValidator NonexistentPath;
1214 struct Range :
public Validator {
1215 template <
typename T> Range(T min, T max) {
1216 std::stringstream out;
1217 out << detail::type_name<T>() <<
" in [" << min <<
" - " << max <<
"]";
1220 func = [min, max](std::string input) {
1223 if(val < min || val > max)
1226 return std::string();
1231 template <
typename T>
explicit Range(T max) : Range(static_cast<T>(0), max) {}
1250 enum class AppFormatMode {
1260 class FormatterBase {
1266 size_t column_width_{30};
1270 std::map<std::string, std::string> labels_;
1277 FormatterBase() =
default;
1278 FormatterBase(
const FormatterBase &) =
default;
1279 FormatterBase(FormatterBase &&) =
default;
1280 virtual ~FormatterBase() =
default;
1283 virtual std::string make_help(
const App *, std::string, AppFormatMode)
const = 0;
1290 void label(std::string key, std::string val) { labels_[key] = val; }
1293 void column_width(
size_t val) { column_width_ = val; }
1300 std::string get_label(std::string key)
const {
1301 if(labels_.find(key) == labels_.end())
1304 return labels_.at(key);
1308 size_t get_column_width()
const {
return column_width_; }
1314 class FormatterLambda final :
public FormatterBase {
1315 using funct_t = std::function<std::string(const App *, std::string, AppFormatMode)>;
1320 explicit FormatterLambda(funct_t funct) : lambda_(std::move(funct)) {}
1323 std::string make_help(
const App *
app, std::string name, AppFormatMode mode)
const override {
1324 return lambda_(app, name, mode);
1328 class Formatter :
public FormatterBase {
1330 Formatter() =
default;
1331 Formatter(
const Formatter &) =
default;
1332 Formatter(Formatter &&) =
default;
1339 virtual std::string make_group(std::string group,
bool is_positional, std::vector<const Option *> opts)
const;
1342 virtual std::string make_positionals(
const App *
app)
const;
1345 std::string make_groups(
const App *app, AppFormatMode mode)
const;
1348 virtual std::string make_subcommands(
const App *app, AppFormatMode mode)
const;
1351 virtual std::string make_subcommand(
const App *sub)
const;
1354 virtual std::string make_expanded(
const App *sub)
const;
1357 virtual std::string make_footer(
const App *app)
const;
1360 virtual std::string make_description(
const App *app)
const;
1363 virtual std::string make_usage(
const App *app, std::string name)
const;
1366 std::string make_help(
const App *, std::string, AppFormatMode)
const override;
1373 virtual std::string make_option(
const Option *opt,
bool is_positional)
const {
1374 std::stringstream out;
1376 out, make_option_name(opt, is_positional) + make_option_opts(opt), make_option_desc(opt), column_width_);
1381 virtual std::string make_option_name(
const Option *,
bool)
const;
1384 virtual std::string make_option_opts(
const Option *)
const;
1387 virtual std::string make_option_desc(
const Option *)
const;
1390 virtual std::string make_option_usage(
const Option *opt)
const;
1401 using results_t = std::vector<std::string>;
1402 using callback_t = std::function<bool(results_t)>;
1407 using Option_p = std::unique_ptr<Option>;
1409 enum class MultiOptionPolicy { Throw, TakeLast, TakeFirst, Join };
1411 template <
typename CRTP>
class OptionBase {
1416 std::string group_ = std::string(
"Options");
1419 bool required_{
false};
1422 bool ignore_case_{
false};
1425 bool configurable_{
true};
1428 MultiOptionPolicy multi_option_policy_{MultiOptionPolicy::Throw};
1430 template <
typename T>
void copy_to(T *other)
const {
1431 other->group(group_);
1432 other->required(required_);
1433 other->ignore_case(ignore_case_);
1434 other->configurable(configurable_);
1435 other->multi_option_policy(multi_option_policy_);
1442 CRTP *group(std::string name) {
1444 return static_cast<CRTP *
>(
this);
1449 CRTP *required(
bool value =
true) {
1451 return static_cast<CRTP *
>(
this);
1455 CRTP *mandatory(
bool value =
true) {
return required(value); }
1460 const std::string &get_group()
const {
return group_; }
1463 bool get_required()
const {
return required_; }
1466 bool get_ignore_case()
const {
return ignore_case_; }
1469 bool get_configurable()
const {
return configurable_; }
1472 MultiOptionPolicy get_multi_option_policy()
const {
return multi_option_policy_; }
1478 auto self =
static_cast<CRTP *
>(
this);
1479 self->multi_option_policy(MultiOptionPolicy::TakeLast);
1484 CRTP *take_first() {
1485 auto self =
static_cast<CRTP *
>(
this);
1486 self->multi_option_policy(MultiOptionPolicy::TakeFirst);
1492 auto self =
static_cast<CRTP *
>(
this);
1493 self->multi_option_policy(MultiOptionPolicy::Join);
1498 CRTP *configurable(
bool value =
true) {
1499 configurable_ = value;
1500 return static_cast<CRTP *
>(
this);
1504 class OptionDefaults :
public OptionBase<OptionDefaults> {
1506 OptionDefaults() =
default;
1511 OptionDefaults *multi_option_policy(MultiOptionPolicy value = MultiOptionPolicy::Throw) {
1512 multi_option_policy_ = value;
1517 OptionDefaults *ignore_case(
bool value =
true) {
1518 ignore_case_ = value;
1523 class Option :
public OptionBase<Option> {
1531 std::vector<std::string> snames_;
1534 std::vector<std::string> lnames_;
1540 std::string envname_;
1547 std::string description_;
1550 std::string defaultval_;
1555 std::function<std::string()> type_name_{[]() {
return std::string(); }};
1558 bool default_{
false};
1573 std::vector<std::function<std::string(std::string &)>> validators_;
1576 std::set<Option *> requires_;
1579 std::set<Option *> excludes_;
1589 callback_t callback_;
1592 bool short_circuit_{
false};
1602 bool callback_run_{
false};
1608 std::string name, std::string description, std::function<
bool(results_t)> callback,
bool defaulted, App *parent)
1609 : description_(std::move(description)), default_(defaulted), parent_(parent),
1610 callback_(callback ? std::move(callback) : [](results_t) {
return true; }) {
1619 size_t count()
const {
return results_.size(); }
1622 size_t empty()
const {
return results_.empty(); }
1625 operator bool()
const {
return !empty(); }
1628 void clear() { results_.clear(); }
1635 Option *expected(
int value) {
1645 else if(expected_ == value)
1649 else if(type_size_ >= 0)
1653 else if(value != 1 && multi_option_policy_ != MultiOptionPolicy::Throw)
1661 Option *check(
const Validator &validator) {
1662 validators_.emplace_back(validator.func);
1663 if(!validator.tname.empty())
1669 Option *check(std::function<std::string(
const std::string &)> validator) {
1670 validators_.emplace_back(validator);
1675 Option *transform(std::function<std::string(std::string)> func) {
1676 validators_.emplace_back([func](std::string &inout) {
1678 inout = func(inout);
1680 return std::string(e.what());
1682 return std::string();
1688 Option *each(std::function<
void(std::string)> func) {
1689 validators_.emplace_back([func](std::string &inout) {
1691 return std::string();
1697 Option *needs(Option *opt) {
1698 auto tup = requires_.insert(opt);
1705 template <
typename T = App> Option *needs(std::string opt_name) {
1706 for(
const Option_p &opt : dynamic_cast<T *>(parent_)->options_)
1707 if(opt.get() !=
this && opt->check_name(opt_name))
1708 return needs(opt.get());
1713 template <
typename A,
typename B,
typename... ARG> Option *needs(A opt, B opt1, ARG... args) {
1715 return needs(opt1, args...);
1719 Option *excludes(Option *opt) {
1720 excludes_.insert(opt);
1723 opt->excludes_.insert(
this);
1732 template <
typename T = App> Option *excludes(std::string opt_name) {
1733 for(
const Option_p &opt : dynamic_cast<T *>(parent_)->options_)
1734 if(opt.get() !=
this && opt->check_name(opt_name))
1735 return excludes(opt.get());
1740 template <
typename A,
typename B,
typename... ARG> Option *excludes(A opt, B opt1, ARG... args) {
1742 return excludes(opt1, args...);
1746 Option *envname(std::string name) {
1755 template <
typename T = App> Option *ignore_case(
bool value =
true) {
1756 ignore_case_ = value;
1757 auto *parent =
dynamic_cast<T *
>(parent_);
1759 for(
const Option_p &opt : parent->options_)
1760 if(opt.get() !=
this && *opt == *
this)
1767 Option *multi_option_policy(MultiOptionPolicy value = MultiOptionPolicy::Throw) {
1769 if(get_items_expected() < 0)
1771 multi_option_policy_ = value;
1778 Option *short_circuit(
bool value =
true) {
1779 short_circuit_ = value;
1788 int get_type_size()
const {
return type_size_; }
1791 std::string get_envname()
const {
return envname_; }
1794 std::set<Option *> get_needs()
const {
return requires_; }
1797 std::set<Option *> get_excludes()
const {
return excludes_; }
1800 std::string get_defaultval()
const {
return defaultval_; }
1803 bool get_short_circuit()
const {
return short_circuit_; }
1806 callback_t get_callback()
const {
return callback_; }
1809 const std::vector<std::string> get_lnames()
const {
return lnames_; }
1812 const std::vector<std::string> get_snames()
const {
return snames_; }
1815 int get_expected()
const {
return expected_; }
1833 int get_items_expected()
const {
1834 return std::abs(type_size_ * expected_) *
1835 ((multi_option_policy_ != MultiOptionPolicy::Throw || (expected_ < 0 && type_size_ < 0) ? -1 : 1));
1839 int get_default()
const {
return default_; }
1842 bool get_positional()
const {
return pname_.length() > 0; }
1845 bool nonpositional()
const {
return (snames_.size() + lnames_.size()) > 0; }
1848 bool has_description()
const {
return description_.length() > 0; }
1851 const std::string &get_description()
const {
return description_; }
1861 std::string get_name(
bool positional =
false,
1862 bool all_options =
false 1867 std::vector<std::string> name_list;
1870 if((positional && pname_.length()) || (snames_.empty() && lnames_.empty()))
1871 name_list.push_back(pname_);
1873 for(
const std::string &sname : snames_)
1874 name_list.push_back(
"-" + sname);
1876 for(
const std::string &lname : lnames_)
1877 name_list.push_back(
"--" + lname);
1888 else if(!lnames_.empty())
1889 return std::string(
"--") + lnames_[0];
1892 else if(!snames_.empty())
1893 return std::string(
"-") + snames_[0];
1906 void run_callback() {
1909 if(!validators_.empty()) {
1910 for(std::string &result : results_)
1911 for(
const std::function<std::string(std::string &)> &vali : validators_) {
1912 std::string err_msg = vali(result);
1913 if(!err_msg.empty())
1922 int trim_size = std::min(std::max(
std::abs(get_items_expected()), 1), static_cast<int>(results_.size()));
1925 if(multi_option_policy_ == MultiOptionPolicy::TakeLast) {
1927 results_t partial_result{results_.end() - trim_size, results_.end()};
1928 local_result = !callback_(partial_result);
1930 }
else if(multi_option_policy_ == MultiOptionPolicy::TakeFirst) {
1931 results_t partial_result{results_.begin(), results_.begin() + trim_size};
1932 local_result = !callback_(partial_result);
1934 }
else if(multi_option_policy_ == MultiOptionPolicy::Join) {
1935 results_t partial_result = {
detail::join(results_,
"\n")};
1936 local_result = !callback_(partial_result);
1940 if(get_items_expected() > 0) {
1941 if(results_.size() !=
static_cast<size_t>(get_items_expected()))
1944 }
else if(get_items_expected() < 0) {
1946 if(results_.size() <
static_cast<size_t>(-get_items_expected()) ||
1947 results_.size() %
static_cast<size_t>(
std::abs(get_type_size())) != 0)
1950 local_result = !callback_(results_);
1959 for(
const std::string &sname : snames_)
1960 if(other.check_sname(sname))
1962 for(
const std::string &lname : lnames_)
1963 if(other.check_lname(lname))
1966 for(
const std::string &sname : other.snames_)
1967 if(check_sname(sname))
1969 for(
const std::string &lname : other.lnames_)
1970 if(check_lname(lname))
1976 bool check_name(std::string name)
const {
1978 if(name.length() > 2 && name.substr(0, 2) ==
"--")
1979 return check_lname(name.substr(2));
1980 else if(name.length() > 1 && name.substr(0, 1) ==
"-")
1981 return check_sname(name.substr(1));
1983 std::string local_pname = pname_;
1988 return name == local_pname;
1993 bool check_sname(std::string name)
const {
1996 return std::find_if(std::begin(snames_), std::end(snames_), [&name](std::string local_sname) {
1998 }) != std::end(snames_);
2000 return std::find(std::begin(snames_), std::end(snames_), name) != std::end(snames_);
2004 bool check_lname(std::string name)
const {
2007 return std::find_if(std::begin(lnames_), std::end(lnames_), [&name](std::string local_sname) {
2009 }) != std::end(lnames_);
2011 return std::find(std::begin(lnames_), std::end(lnames_), name) != std::end(lnames_);
2015 Option *add_result(std::string s) {
2016 results_.push_back(s);
2017 callback_run_ =
false;
2022 Option *set_results(std::vector<std::string> results) {
2024 callback_run_ =
false;
2029 std::vector<std::string> results()
const {
return results_; }
2032 bool get_callback_run()
const {
return callback_run_; }
2039 Option *type_name_fn(std::function<std::string()> typefun) {
2040 type_name_ = typefun;
2045 Option *
type_name(std::string typeval) {
2046 type_name_fn([typeval]() {
return typeval; });
2052 Option *set_type_name(std::string typeval) {
return type_name(typeval); }
2055 Option *type_size(
int type_size) {
2056 type_size_ = type_size;
2065 Option *default_str(std::string val) {
2071 Option *default_val(std::string val) {
2073 auto old_results = results_;
2076 results_ = std::move(old_results);
2081 std::string get_type_name()
const {
return type_name_(); }
2091 #define CLI11_PARSE(app, argc, argv) \ 2093 (app).parse((argc), (argv)); \ 2094 } catch(const CLI::ParseError &e) { \ 2095 return (app).exit(e); \ 2100 enum class Classifer { NONE, POSITIONAL_MARK, SHORT, LONG, SUBCOMMAND };
2104 namespace FailureMessage {
2105 std::string simple(
const App *
app,
const Error &e);
2106 std::string help(
const App *app,
const Error &e);
2111 using App_p = std::unique_ptr<App>;
2119 friend detail::AppFriend;
2131 std::string description_;
2134 bool allow_extras_{
false};
2137 bool allow_config_extras_{
false};
2140 bool prefix_command_{
false};
2143 std::function<void()> callback_;
2150 OptionDefaults option_defaults_;
2153 std::vector<Option_p> options_;
2160 std::string footer_;
2163 Option *help_ptr_{
nullptr};
2166 Option *help_all_ptr_{
nullptr};
2169 std::shared_ptr<FormatterBase> formatter_{
new Formatter()};
2172 std::function<std::string(const App *, const Error &e)> failure_message_ = FailureMessage::simple;
2178 using missing_t = std::vector<std::pair<detail::Classifer, std::string>>;
2186 std::vector<Option *> parse_order_;
2189 std::vector<App *> parsed_subcommands_;
2196 std::vector<App_p> subcommands_;
2199 bool ignore_case_{
false};
2202 bool fallthrough_{
false};
2205 App *parent_{
nullptr};
2208 bool parsed_{
false};
2211 size_t require_subcommand_min_ = 0;
2214 size_t require_subcommand_max_ = 0;
2217 std::string group_{
"Subcommands"};
2224 std::string config_name_;
2227 bool config_required_{
false};
2230 Option *config_ptr_{
nullptr};
2233 std::shared_ptr<Config> config_formatter_{
new ConfigINI()};
2238 App(std::string description_, std::string name, App *parent)
2239 : name_(std::move(name)), description_(std::move(description_)), parent_(parent) {
2241 if(parent_ !=
nullptr) {
2242 if(parent_->help_ptr_ !=
nullptr)
2243 set_help_flag(parent_->help_ptr_->get_name(
false,
true), parent_->help_ptr_->get_description());
2244 if(parent_->help_all_ptr_ !=
nullptr)
2245 set_help_all_flag(parent_->help_all_ptr_->get_name(
false,
true),
2246 parent_->help_all_ptr_->get_description());
2249 option_defaults_ = parent_->option_defaults_;
2252 failure_message_ = parent_->failure_message_;
2253 allow_extras_ = parent_->allow_extras_;
2254 allow_config_extras_ = parent_->allow_config_extras_;
2255 prefix_command_ = parent_->prefix_command_;
2256 ignore_case_ = parent_->ignore_case_;
2257 fallthrough_ = parent_->fallthrough_;
2258 group_ = parent_->group_;
2259 footer_ = parent_->footer_;
2260 formatter_ = parent_->formatter_;
2261 config_formatter_ = parent_->config_formatter_;
2262 require_subcommand_max_ = parent_->require_subcommand_max_;
2271 explicit App(std::string description_ =
"", std::string name =
"") : App(description_, name,
nullptr) {
2272 set_help_flag(
"-h,--help",
"Print this help message and exit");
2276 virtual ~App() =
default;
2284 App *callback(std::function<
void()> callback) {
2285 callback_ = callback;
2290 App *name(std::string name =
"") {
2296 App *allow_extras(
bool allow =
true) {
2297 allow_extras_ = allow;
2303 App *allow_config_extras(
bool allow =
true) {
2304 allow_extras(allow);
2305 allow_config_extras_ = allow;
2310 App *prefix_command(
bool allow =
true) {
2311 prefix_command_ = allow;
2316 App *ignore_case(
bool value =
true) {
2317 ignore_case_ = value;
2318 if(parent_ !=
nullptr) {
2319 for(
const auto &subc : parent_->subcommands_) {
2320 if(subc.get() !=
this && (this->check_name(subc->name_) || subc->check_name(this->name_)))
2328 App *formatter(std::shared_ptr<FormatterBase> fmt) {
2334 App *formatter_fn(std::function<std::string(
const App *, std::string, AppFormatMode)> fmt) {
2335 formatter_ = std::make_shared<FormatterLambda>(fmt);
2340 App *config_formatter(std::shared_ptr<Config> fmt) {
2341 config_formatter_ = fmt;
2346 bool parsed()
const {
return parsed_; }
2349 OptionDefaults *option_defaults() {
return &option_defaults_; }
2369 Option *add_option(std::string name, callback_t callback, std::string description =
"",
bool defaulted =
false) {
2370 Option myopt{name, description, callback, defaulted,
this};
2372 if(std::find_if(std::begin(options_), std::end(options_), [&myopt](
const Option_p &v) {
2374 }) == std::end(options_)) {
2375 options_.emplace_back();
2376 Option_p &option = options_.back();
2377 option.reset(
new Option(name, description, callback, defaulted,
this));
2378 option_defaults_.copy_to(option.get());
2379 return option.get();
2386 Option *add_option(std::string name,
2388 std::string description =
"") {
2390 CLI::callback_t fun = [&variable](CLI::results_t res) {
return detail::lexical_cast(res[0], variable); };
2392 Option *opt = add_option(name, fun, description,
false);
2393 opt->type_name(detail::type_name<T>());
2398 template <typename T, enable_if_t<!is_vector<T>::value, detail::enabler> =
detail::dummy>
2399 Option *add_option(std::string name,
2401 std::string description,
2404 CLI::callback_t fun = [&variable](CLI::results_t res) {
return detail::lexical_cast(res[0], variable); };
2406 Option *opt = add_option(name, fun, description, defaulted);
2407 opt->type_name(detail::type_name<T>());
2409 std::stringstream out;
2411 opt->default_str(out.str());
2417 template <
typename T>
2418 Option *add_option(std::string name,
2419 std::vector<T> &variable,
2420 std::string description =
"") {
2422 CLI::callback_t fun = [&variable](CLI::results_t res) {
2425 for(
const auto &a : res) {
2426 variable.emplace_back();
2429 return (!variable.empty()) && retval;
2432 Option *opt = add_option(name, fun, description,
false);
2433 opt->type_name(detail::type_name<T>())->type_size(-1);
2438 template <
typename T>
2439 Option *add_option(std::string name,
2440 std::vector<T> &variable,
2441 std::string description,
2444 CLI::callback_t fun = [&variable](CLI::results_t res) {
2447 for(
const auto &a : res) {
2448 variable.emplace_back();
2451 return (!variable.empty()) && retval;
2454 Option *opt = add_option(name, fun, description, defaulted);
2455 opt->type_name(detail::type_name<T>())->type_size(-1);
2462 Option *set_help_flag(std::string name =
"", std::string description =
"") {
2463 if(help_ptr_ !=
nullptr) {
2464 remove_option(help_ptr_);
2465 help_ptr_ =
nullptr;
2470 help_ptr_ = add_flag_function(name, [](
size_t) ->
void {
throw CallForHelp(); }, description);
2471 help_ptr_->short_circuit(
true);
2472 help_ptr_->configurable(
false);
2479 Option *set_help_all_flag(std::string name =
"", std::string description =
"") {
2480 if(help_all_ptr_ !=
nullptr) {
2481 remove_option(help_all_ptr_);
2482 help_all_ptr_ =
nullptr;
2487 help_all_ptr_ = add_flag_function(name, [](
size_t) ->
void {
throw CallForAllHelp(); }, description);
2488 help_all_ptr_->short_circuit(
true);
2489 help_all_ptr_->configurable(
false);
2492 return help_all_ptr_;
2496 Option *add_flag(std::string name, std::string description =
"") {
2497 CLI::callback_t fun = [](CLI::results_t) {
return true; };
2499 Option *opt = add_option(name, fun, description,
false);
2500 if(opt->get_positional())
2507 template <
typename T,
2509 Option *add_flag(std::string name,
2511 std::string description =
"") {
2514 CLI::callback_t fun = [&count](CLI::results_t res) {
2515 count =
static_cast<T
>(res.size());
2519 Option *opt = add_option(name, fun, description,
false);
2520 if(opt->get_positional())
2528 template <typename T, enable_if_t<is_bool<T>::value, detail::enabler> =
detail::dummy>
2529 Option *add_flag(std::string name,
2531 std::string description =
"") {
2534 CLI::callback_t fun = [&count](CLI::results_t res) {
2536 return res.size() == 1;
2539 Option *opt = add_option(name, fun, description,
false);
2540 if(opt->get_positional())
2543 opt->multi_option_policy(CLI::MultiOptionPolicy::TakeLast);
2548 Option *add_flag_function(std::string name,
2549 std::function<
void(
size_t)>
function,
2550 std::string description =
"") {
2552 CLI::callback_t fun = [
function](CLI::results_t res) {
2553 auto count =
static_cast<size_t>(res.size());
2558 Option *opt = add_option(name, fun, description,
false);
2559 if(opt->get_positional())
2566 Option *add_flag(std::string name,
2568 std::function<
void(
size_t)>
function,
2569 std::string description =
"") {
2570 return add_flag_function(name,
function, description);
2575 template <
typename T>
2576 Option *add_set(std::string name,
2578 const std::set<T> &&options,
2579 std::string description =
"") {
2582 CLI::callback_t fun = [&member, options, simple_name](CLI::results_t res) {
2586 return std::find(std::begin(options), std::end(options), member) != std::end(options);
2589 Option *opt = add_option(name, fun, description,
false);
2590 std::string typeval = detail::type_name<T>();
2592 opt->type_name(typeval);
2597 template <
typename T>
2598 Option *add_set(std::string name,
2600 const std::set<T> &options,
2601 std::string description =
"") {
2604 CLI::callback_t fun = [&member, &options, simple_name](CLI::results_t res) {
2608 return std::find(std::begin(options), std::end(options), member) != std::end(options);
2611 Option *opt = add_option(name, fun, description,
false);
2613 [&options]() {
return std::string(detail::type_name<T>()) +
" in {" +
detail::join(options) +
"}"; });
2619 template <
typename T>
2620 Option *add_set(std::string name,
2622 const std::set<T> &&options,
2623 std::string description,
2627 CLI::callback_t fun = [&member, options, simple_name](CLI::results_t res) {
2631 return std::find(std::begin(options), std::end(options), member) != std::end(options);
2634 Option *opt = add_option(name, fun, description, defaulted);
2635 std::string typeval = detail::type_name<T>();
2637 opt->type_name(typeval);
2639 std::stringstream out;
2641 opt->default_str(out.str());
2647 template <
typename T>
2648 Option *add_set(std::string name,
2650 const std::set<T> &options,
2651 std::string description,
2655 CLI::callback_t fun = [&member, &options, simple_name](CLI::results_t res) {
2659 return std::find(std::begin(options), std::end(options), member) != std::end(options);
2662 Option *opt = add_option(name, fun, description, defaulted);
2664 [&options]() {
return std::string(detail::type_name<T>()) +
" in {" +
detail::join(options) +
"}"; });
2666 std::stringstream out;
2668 opt->default_str(out.str());
2674 Option *add_set_ignore_case(std::string name,
2675 std::string &member,
2676 const std::set<std::string> &&options,
2677 std::string description =
"") {
2680 CLI::callback_t fun = [&member, options, simple_name](CLI::results_t res) {
2682 auto iter = std::find_if(std::begin(options), std::end(options), [&member](std::string val) {
2685 if(iter == std::end(options))
2693 Option *opt = add_option(name, fun, description,
false);
2694 std::string typeval = detail::type_name<std::string>();
2696 opt->type_name(typeval);
2702 Option *add_set_ignore_case(std::string name,
2703 std::string &member,
2704 const std::set<std::string> &options,
2705 std::string description =
"") {
2708 CLI::callback_t fun = [&member, &options, simple_name](CLI::results_t res) {
2710 auto iter = std::find_if(std::begin(options), std::end(options), [&member](std::string val) {
2713 if(iter == std::end(options))
2721 Option *opt = add_option(name, fun, description,
false);
2722 opt->type_name_fn([&options]() {
2723 return std::string(detail::type_name<std::string>()) +
" in {" +
detail::join(options) +
"}";
2730 Option *add_set_ignore_case(std::string name,
2731 std::string &member,
2732 const std::set<std::string> &&options,
2733 std::string description,
2737 CLI::callback_t fun = [&member, options, simple_name](CLI::results_t res) {
2739 auto iter = std::find_if(std::begin(options), std::end(options), [&member](std::string val) {
2742 if(iter == std::end(options))
2750 Option *opt = add_option(name, fun, description, defaulted);
2751 std::string typeval = detail::type_name<std::string>();
2753 opt->type_name(typeval);
2755 opt->default_str(member);
2761 Option *add_set_ignore_case(std::string name,
2762 std::string &member,
2763 const std::set<std::string> &options,
2764 std::string description,
2768 CLI::callback_t fun = [&member, &options, simple_name](CLI::results_t res) {
2770 auto iter = std::find_if(std::begin(options), std::end(options), [&member](std::string val) {
2773 if(iter == std::end(options))
2781 Option *opt = add_option(name, fun, description, defaulted);
2782 opt->type_name_fn([&options]() {
2783 return std::string(detail::type_name<std::string>()) +
" in {" +
detail::join(options) +
"}";
2786 opt->default_str(member);
2792 template <
typename T>
2793 Option *add_complex(std::string name,
2795 std::string description =
"",
2796 bool defaulted =
false,
2797 std::string label =
"COMPLEX") {
2800 CLI::callback_t fun = [&variable, simple_name, label](results_t res) {
2801 if(res[1].back() ==
'i')
2810 CLI::Option *opt = add_option(name, fun, description, defaulted);
2811 opt->type_name(label)->type_size(2);
2813 std::stringstream out;
2815 opt->default_str(out.str());
2821 Option *set_config(std::string name =
"",
2822 std::string default_filename =
"",
2823 std::string help =
"Read an ini file",
2824 bool required =
false) {
2827 if(config_ptr_ !=
nullptr)
2828 remove_option(config_ptr_);
2832 config_name_ = default_filename;
2833 config_required_ = required;
2834 config_ptr_ = add_option(name, config_name_, help, !default_filename.empty());
2835 config_ptr_->configurable(
false);
2842 bool remove_option(Option *opt) {
2844 std::find_if(std::begin(options_), std::end(options_), [opt](
const Option_p &v) {
return v.get() == opt; });
2845 if(iterator != std::end(options_)) {
2846 options_.erase(iterator);
2857 App *add_subcommand(std::string name, std::string description =
"") {
2858 subcommands_.emplace_back(
new App(description, name,
this));
2859 for(
const auto &subc : subcommands_)
2860 if(subc.get() != subcommands_.back().get())
2861 if(subc->check_name(subcommands_.back()->name_) || subcommands_.back()->check_name(subc->name_))
2863 return subcommands_.back().get();
2867 App *get_subcommand(App *subcom)
const {
2868 for(
const App_p &subcomptr : subcommands_)
2869 if(subcomptr.get() == subcom)
2875 App *get_subcommand(std::string subcom)
const {
2876 for(
const App_p &subcomptr : subcommands_)
2877 if(subcomptr->check_name(subcom))
2878 return subcomptr.get();
2883 App *group(std::string name) {
2889 App *require_subcommand() {
2890 require_subcommand_min_ = 1;
2891 require_subcommand_max_ = 0;
2898 App *require_subcommand(
int value) {
2900 require_subcommand_min_ = 0;
2901 require_subcommand_max_ =
static_cast<size_t>(-value);
2903 require_subcommand_min_ =
static_cast<size_t>(value);
2904 require_subcommand_max_ =
static_cast<size_t>(value);
2911 App *require_subcommand(
size_t min,
size_t max) {
2912 require_subcommand_min_ = min;
2913 require_subcommand_max_ = max;
2919 App *fallthrough(
bool value =
true) {
2920 fallthrough_ = value;
2926 operator bool()
const {
return parsed_; }
2935 virtual void pre_callback() {}
2946 parsed_subcommands_.clear();
2948 for(
const Option_p &opt : options_) {
2951 for(
const App_p &
app : subcommands_) {
2958 void parse(
int argc,
const char *
const *argv) {
2963 std::vector<std::string> args;
2964 for(
int i = argc - 1; i > 0; i--)
2965 args.emplace_back(argv[i]);
2971 void parse(std::vector<std::string> &args) {
2987 void failure_message(std::function<std::string(
const App *,
const Error &e)>
function) {
2988 failure_message_ =
function;
2992 int exit(
const Error &e, std::ostream &out = std::cout, std::ostream &err = std::cerr)
const {
2995 if(dynamic_cast<const CLI::RuntimeError *>(&e) !=
nullptr)
2998 if(dynamic_cast<const CLI::CallForHelp *>(&e) !=
nullptr) {
3003 if(dynamic_cast<const CLI::CallForAllHelp *>(&e) !=
nullptr) {
3004 out << help(
"", AppFormatMode::All);
3009 if(failure_message_)
3010 err << failure_message_(
this, e) << std::flush;
3021 size_t count(std::string name)
const {
3022 for(
const Option_p &opt : options_) {
3023 if(opt->check_name(name)) {
3024 return opt->count();
3032 std::vector<App *> get_subcommands()
const {
return parsed_subcommands_; }
3036 std::vector<const App *> get_subcommands(
const std::function<
bool(
const App *)> &filter)
const {
3037 std::vector<const App *> subcomms(subcommands_.size());
3038 std::transform(std::begin(subcommands_), std::end(subcommands_), std::begin(subcomms), [](
const App_p &v) {
3043 subcomms.erase(std::remove_if(std::begin(subcomms),
3045 [&filter](
const App *
app) {
return !filter(app); }),
3046 std::end(subcomms));
3054 std::vector<App *> get_subcommands(
const std::function<
bool(App *)> &filter) {
3055 std::vector<App *> subcomms(subcommands_.size());
3056 std::transform(std::begin(subcommands_), std::end(subcommands_), std::begin(subcomms), [](
const App_p &v) {
3062 std::remove_if(std::begin(subcomms), std::end(subcomms), [&filter](App *
app) {
return !filter(app); }),
3063 std::end(subcomms));
3070 bool got_subcommand(App *subcom)
const {
3072 return get_subcommand(subcom)->parsed_;
3076 bool got_subcommand(std::string name)
const {
return get_subcommand(name)->parsed_; }
3083 App *footer(std::string footer) {
3090 std::string config_to_str(
bool default_also =
false,
bool write_description =
false)
const {
3091 return config_formatter_->to_config(
this, default_also, write_description,
"");
3096 std::string help(std::string prev =
"", AppFormatMode mode = AppFormatMode::Normal)
const {
3100 prev +=
" " + get_name();
3103 auto selected_subcommands = get_subcommands();
3104 if(!selected_subcommands.empty())
3105 return selected_subcommands.at(0)->help(prev);
3107 return formatter_->make_help(
this, prev, mode);
3112 App *set_footer(std::string msg) {
return footer(msg); }
3116 App *set_name(std::string msg) {
return name(msg); }
3120 App *set_callback(std::function<
void()> fn) {
return callback(fn); }
3127 std::shared_ptr<FormatterBase> get_formatter()
const {
return formatter_; }
3130 std::shared_ptr<Config> get_config_formatter()
const {
return config_formatter_; }
3133 std::string get_description()
const {
return description_; }
3136 std::vector<const Option *> get_options(
const std::function<
bool(
const Option *)> filter = {})
const {
3137 std::vector<const Option *> options(options_.size());
3138 std::transform(std::begin(options_), std::end(options_), std::begin(options), [](
const Option_p &val) {
3143 options.erase(std::remove_if(std::begin(options),
3145 [&filter](
const Option *opt) {
return !filter(opt); }),
3153 const Option *get_option(std::string name)
const {
3154 for(
const Option_p &opt : options_) {
3155 if(opt->check_name(name)) {
3163 Option *get_option(std::string name) {
3164 for(Option_p &opt : options_) {
3165 if(opt->check_name(name)) {
3173 bool get_ignore_case()
const {
return ignore_case_; }
3176 bool get_fallthrough()
const {
return fallthrough_; }
3179 const std::string &get_group()
const {
return group_; }
3182 std::string get_footer()
const {
return footer_; }
3185 size_t get_require_subcommand_min()
const {
return require_subcommand_min_; }
3188 size_t get_require_subcommand_max()
const {
return require_subcommand_max_; }
3191 bool get_prefix_command()
const {
return prefix_command_; }
3194 bool get_allow_extras()
const {
return allow_extras_; }
3197 bool get_allow_config_extras()
const {
return allow_config_extras_; }
3200 Option *get_help_ptr() {
return help_ptr_; }
3203 const Option *get_help_ptr()
const {
return help_ptr_; }
3206 const Option *get_help_all_ptr()
const {
return help_all_ptr_; }
3209 Option *get_config_ptr() {
return config_ptr_; }
3212 const Option *get_config_ptr()
const {
return config_ptr_; }
3215 App *get_parent() {
return parent_; }
3218 const App *get_parent()
const {
return parent_; }
3221 std::string get_name()
const {
return name_; }
3224 bool check_name(std::string name_to_check)
const {
3225 std::string local_name = name_;
3231 return local_name == name_to_check;
3235 std::vector<std::string> get_groups()
const {
3236 std::vector<std::string> groups;
3238 for(
const Option_p &opt : options_) {
3240 if(std::find(groups.begin(), groups.end(), opt->get_group()) == groups.end()) {
3241 groups.push_back(opt->get_group());
3249 const std::vector<Option *> &parse_order()
const {
return parse_order_; }
3252 std::vector<std::string> remaining(
bool recurse =
false)
const {
3253 std::vector<std::string> miss_list;
3254 for(
const std::pair<detail::Classifer, std::string> &miss : missing_) {
3255 miss_list.push_back(std::get<1>(miss));
3260 for(
const App *sub : parsed_subcommands_) {
3261 std::vector<std::string> output = sub->remaining(recurse);
3262 std::copy(std::begin(output), std::end(output), std::back_inserter(miss_list));
3269 size_t remaining_size(
bool recurse =
false)
const {
3270 auto count =
static_cast<size_t>(std::count_if(
3271 std::begin(missing_), std::end(missing_), [](
const std::pair<detail::Classifer, std::string> &val) {
3272 return val.first != detail::Classifer::POSITIONAL_MARK;
3275 for(
const App_p &sub : subcommands_) {
3276 count += sub->remaining_size(recurse);
3288 void _validate()
const {
3289 auto count = std::count_if(std::begin(options_), std::end(options_), [](
const Option_p &opt) {
3290 return opt->get_items_expected() < 0 && opt->get_positional();
3294 for(
const App_p &
app : subcommands_)
3299 void run_callback() {
3303 for(App *subc : get_subcommands()) {
3304 subc->run_callback();
3309 bool _valid_subcommand(
const std::string ¤t)
const {
3311 if(require_subcommand_max_ != 0 && parsed_subcommands_.size() >= require_subcommand_max_) {
3312 return parent_ !=
nullptr && parent_->_valid_subcommand(current);
3315 for(
const App_p &com : subcommands_)
3316 if(com->check_name(current) && !*com)
3320 return parent_ !=
nullptr && parent_->_valid_subcommand(current);
3324 detail::Classifer _recognize(
const std::string ¤t)
const {
3325 std::string dummy1, dummy2;
3328 return detail::Classifer::POSITIONAL_MARK;
3329 if(_valid_subcommand(current))
3330 return detail::Classifer::SUBCOMMAND;
3332 return detail::Classifer::LONG;
3334 return detail::Classifer::SHORT;
3335 return detail::Classifer::NONE;
3339 void _parse(std::vector<std::string> &args) {
3341 bool positional_only =
false;
3343 while(!args.empty()) {
3344 _parse_single(args, positional_only);
3347 for(
const Option_p &opt : options_)
3348 if(opt->get_short_circuit() && opt->count() > 0)
3349 opt->run_callback();
3352 if(config_ptr_ !=
nullptr) {
3354 config_ptr_->run_callback();
3355 config_required_ =
true;
3357 if(!config_name_.empty()) {
3359 std::vector<ConfigItem> values = config_formatter_->from_file(config_name_);
3360 _parse_config(values);
3362 if(config_required_)
3369 for(
const Option_p &opt : options_) {
3370 if(opt->count() == 0 && !opt->envname_.empty()) {
3371 char *buffer =
nullptr;
3372 std::string ename_string;
3377 if(_dupenv_s(&buffer, &sz, opt->envname_.c_str()) == 0 && buffer !=
nullptr) {
3378 ename_string = std::string(buffer);
3383 buffer = std::getenv(opt->envname_.c_str());
3384 if(buffer !=
nullptr)
3385 ename_string = std::string(buffer);
3388 if(!ename_string.empty()) {
3389 opt->add_result(ename_string);
3395 for(
const Option_p &opt : options_) {
3396 if(opt->count() > 0 && !opt->get_callback_run()) {
3397 opt->run_callback();
3402 for(
const Option_p &opt : options_) {
3404 if(opt->get_required() || opt->count() != 0) {
3406 if(opt->get_items_expected() < 0 && opt->count() <
static_cast<size_t>(-opt->get_items_expected()))
3410 if(opt->get_required() && opt->count() == 0)
3414 for(
const Option *opt_req : opt->requires_)
3415 if(opt->count() > 0 && opt_req->count() == 0)
3418 for(
const Option *opt_ex : opt->excludes_)
3419 if(opt->count() > 0 && opt_ex->count() != 0)
3423 auto selected_subcommands = get_subcommands();
3424 if(require_subcommand_min_ > selected_subcommands.size())
3428 if(!(allow_extras_ || prefix_command_)) {
3429 size_t num_left_over = remaining_size();
3430 if(num_left_over > 0) {
3431 args = remaining(
false);
3436 if(parent_ ==
nullptr) {
3437 args = remaining(
false);
3445 void _parse_config(std::vector<ConfigItem> &args) {
3446 for(ConfigItem item : args) {
3447 if(!_parse_single_config(item) && !allow_config_extras_)
3453 bool _parse_single_config(
const ConfigItem &item,
size_t level = 0) {
3454 if(level < item.parents.size()) {
3457 std::cout << item.parents.at(level) << std::endl;
3458 subcom = get_subcommand(item.parents.at(level));
3462 return subcom->_parse_single_config(item, level + 1);
3467 op = get_option(
"--" + item.name);
3470 if(get_allow_config_extras())
3472 missing_.emplace_back(detail::Classifer::NONE, item.fullname());
3476 if(!op->get_configurable())
3481 if(op->get_type_size() == 0) {
3482 op->set_results(config_formatter_->to_flag(item));
3484 op->set_results(item.inputs);
3494 void _parse_single(std::vector<std::string> &args,
bool &positional_only) {
3496 detail::Classifer classifer = positional_only ? detail::Classifer::NONE : _recognize(args.back());
3498 case detail::Classifer::POSITIONAL_MARK:
3499 missing_.emplace_back(classifer, args.back());
3501 positional_only =
true;
3503 case detail::Classifer::SUBCOMMAND:
3504 _parse_subcommand(args);
3506 case detail::Classifer::LONG:
3508 _parse_arg(args,
true);
3510 case detail::Classifer::SHORT:
3512 _parse_arg(args,
false);
3514 case detail::Classifer::NONE:
3516 _parse_positional(args);
3521 size_t _count_remaining_positionals(
bool required =
false)
const {
3523 for(
const Option_p &opt : options_)
3524 if(opt->get_positional() && (!required || opt->get_required()) && opt->get_items_expected() > 0 &&
3525 static_cast<int>(opt->count()) < opt->get_items_expected())
3526 retval = static_cast<size_t>(opt->get_items_expected()) - opt->count();
3532 void _parse_positional(std::vector<std::string> &args) {
3534 std::string positional = args.back();
3535 for(
const Option_p &opt : options_) {
3537 if(opt->get_positional() &&
3538 (
static_cast<int>(opt->count()) < opt->get_items_expected() || opt->get_items_expected() < 0)) {
3540 opt->add_result(positional);
3541 parse_order_.push_back(opt.get());
3547 if(parent_ !=
nullptr && fallthrough_)
3548 return parent_->_parse_positional(args);
3551 missing_.emplace_back(detail::Classifer::NONE, positional);
3553 if(prefix_command_) {
3554 while(!args.empty()) {
3555 missing_.emplace_back(detail::Classifer::NONE, args.back());
3565 void _parse_subcommand(std::vector<std::string> &args) {
3566 if(_count_remaining_positionals(
true) > 0)
3567 return _parse_positional(args);
3568 for(
const App_p &com : subcommands_) {
3569 if(com->check_name(args.back())) {
3571 if(std::find(std::begin(parsed_subcommands_), std::end(parsed_subcommands_), com.get()) ==
3572 std::end(parsed_subcommands_))
3573 parsed_subcommands_.push_back(com.get());
3578 if(parent_ !=
nullptr)
3579 return parent_->_parse_subcommand(args);
3581 throw HorribleError(
"Subcommand " + args.back() +
" missing");
3585 void _parse_arg(std::vector<std::string> &args,
bool second_dash) {
3587 detail::Classifer current_type = second_dash ? detail::Classifer::LONG : detail::Classifer::SHORT;
3589 std::string current = args.back();
3597 throw HorribleError(
"Long parsed but missing (you should not see this):" + args.back());
3600 throw HorribleError(
"Short parsed but missing! You should not see this");
3603 auto op_ptr = std::find_if(std::begin(options_), std::end(options_), [name, second_dash](
const Option_p &opt) {
3604 return second_dash ? opt->check_lname(name) : opt->check_sname(name);
3608 if(op_ptr == std::end(options_)) {
3610 if(parent_ !=
nullptr && fallthrough_)
3611 return parent_->_parse_arg(args, second_dash);
3615 missing_.emplace_back(current_type, current);
3623 Option_p &op = *op_ptr;
3625 int num = op->get_items_expected();
3631 if(!value.empty()) {
3635 op->add_result(value);
3636 parse_order_.push_back(op.get());
3638 }
else if(num == 0) {
3640 parse_order_.push_back(op.get());
3642 }
else if(!rest.empty()) {
3645 op->add_result(rest);
3646 parse_order_.push_back(op.get());
3653 while(!args.empty() && _recognize(args.back()) == detail::Classifer::NONE) {
3654 if(collected >= -num) {
3658 if(_count_remaining_positionals() > 0)
3661 op->add_result(args.back());
3662 parse_order_.push_back(op.get());
3668 if(!args.empty() && _recognize(args.back()) == detail::Classifer::POSITIONAL_MARK)
3672 while(num > 0 && !args.empty()) {
3674 std::string current_ = args.back();
3676 op->add_result(current_);
3677 parse_order_.push_back(op.get());
3687 args.push_back(rest);
3692 namespace FailureMessage {
3694 inline std::string simple(
const App *
app,
const Error &e) {
3695 std::string header = std::string(e.what()) +
"\n";
3696 if(app->get_help_ptr() !=
nullptr)
3697 header +=
"Run with " + app->get_help_ptr()->get_name() +
" for more information.\n";
3701 inline std::string help(
const App *app,
const Error &e) {
3702 std::string header = std::string(
"ERROR: ") + e.
get_name() +
": " + e.what() +
"\n";
3703 header += app->help();
3714 template <
typename... Args>
3715 static auto parse_arg(App *
app, Args &&... args) ->
3716 typename std::result_of<decltype (&App::_parse_arg)(App, Args...)>
::type {
3717 return app->_parse_arg(std::forward<Args>(args)...);
3721 template <
typename... Args>
3722 static auto parse_subcommand(App *app, Args &&... args) ->
3723 typename std::result_of<decltype (&App::_parse_subcommand)(App, Args...)>
::type {
3724 return app->_parse_subcommand(std::forward<Args>(args)...);
3736 ConfigINI::to_config(
const App *
app,
bool default_also,
bool write_description, std::string prefix)
const {
3737 std::stringstream out;
3738 for(
const Option *opt : app->get_options({})) {
3741 if(!opt->get_lnames().empty() && opt->get_configurable()) {
3742 std::string name = prefix + opt->get_lnames()[0];
3746 if(opt->get_type_size() != 0) {
3749 if(opt->count() > 0)
3750 value = detail::ini_join(opt->results());
3753 else if(default_also && !opt->get_defaultval().empty())
3754 value = opt->get_defaultval();
3756 }
else if(opt->count() == 1) {
3760 }
else if(opt->count() > 1) {
3764 }
else if(opt->count() == 0 && default_also) {
3768 if(!value.empty()) {
3769 if(write_description && opt->has_description()) {
3770 if(static_cast<int>(out.tellp()) != 0) {
3775 out << name <<
"=" << value << std::endl;
3780 for(
const App *subcom : app->get_subcommands({}))
3781 out << to_config(subcom, default_also, write_description, prefix + subcom->get_name() +
".");
3793 Formatter::make_group(std::string group,
bool is_positional, std::vector<const Option *> opts)
const {
3794 std::stringstream out;
3796 out <<
"\n" << group <<
":\n";
3797 for(
const Option *opt : opts) {
3798 out << make_option(opt, is_positional);
3804 inline std::string Formatter::make_positionals(
const App *
app)
const {
3805 std::vector<const Option *> opts =
3806 app->get_options([](
const Option *opt) {
return !opt->get_group().empty() && opt->get_positional(); });
3809 return std::string();
3811 return make_group(get_label(
"Positionals"),
true, opts);
3814 inline std::string Formatter::make_groups(
const App *app, AppFormatMode mode)
const {
3815 std::stringstream out;
3816 std::vector<std::string> groups = app->get_groups();
3819 for(
const std::string &group : groups) {
3820 std::vector<const Option *> opts = app->get_options([app, mode, &group](
const Option *opt) {
3821 return opt->get_group() == group
3822 && opt->nonpositional()
3823 && (mode != AppFormatMode::Sub
3824 || (app->get_help_ptr() != opt
3825 && app->get_help_all_ptr() != opt));
3827 if(!group.empty() && !opts.empty()) {
3828 out << make_group(group,
false, opts);
3830 if(group != groups.back())
3838 inline std::string Formatter::make_description(
const App *app)
const {
3839 std::string desc = app->get_description();
3847 inline std::string Formatter::make_usage(
const App *app, std::string name)
const {
3848 std::stringstream out;
3850 out << get_label(
"Usage") <<
":" << (name.empty() ?
"" :
" ") << name;
3852 std::vector<std::string> groups = app->get_groups();
3855 std::vector<const Option *> non_pos_options =
3856 app->get_options([](
const Option *opt) {
return opt->nonpositional(); });
3857 if(!non_pos_options.empty())
3858 out <<
" [" << get_label(
"OPTIONS") <<
"]";
3861 std::vector<const Option *> positionals = app->get_options([](
const Option *opt) {
return opt->get_positional(); });
3864 if(!positionals.empty()) {
3866 std::vector<std::string> positional_names(positionals.size());
3867 std::transform(positionals.begin(), positionals.end(), positional_names.begin(), [
this](
const Option *opt) {
3868 return make_option_usage(opt);
3875 if(!app->get_subcommands({}).empty()) {
3876 out <<
" " << (app->get_require_subcommand_min() == 0 ?
"[" :
"")
3877 << get_label(app->get_require_subcommand_max() < 2 || app->get_require_subcommand_min() > 1 ?
"SUBCOMMAND" 3879 << (app->get_require_subcommand_min() == 0 ?
"]" :
"");
3887 inline std::string Formatter::make_footer(
const App *app)
const {
3888 std::string footer = app->get_footer();
3890 return footer +
"\n";
3895 inline std::string Formatter::make_help(
const App *app, std::string name, AppFormatMode mode)
const {
3899 if(mode == AppFormatMode::Sub)
3900 return make_expanded(app);
3902 std::stringstream out;
3904 out << make_description(app);
3905 out << make_usage(app, name);
3906 out << make_positionals(app);
3907 out << make_groups(app, mode);
3908 out << make_subcommands(app, mode);
3909 out << make_footer(app);
3914 inline std::string Formatter::make_subcommands(
const App *app, AppFormatMode mode)
const {
3915 std::stringstream out;
3917 std::vector<const App *> subcommands = app->get_subcommands({});
3920 std::vector<std::string> subcmd_groups_seen;
3921 for(
const App *com : subcommands) {
3922 std::string group_key = com->get_group();
3923 if(!group_key.empty() &&
3924 std::find_if(subcmd_groups_seen.begin(), subcmd_groups_seen.end(), [&group_key](std::string a) {
3926 }) == subcmd_groups_seen.end())
3927 subcmd_groups_seen.push_back(group_key);
3931 for(
const std::string &group : subcmd_groups_seen) {
3932 out <<
"\n" << group <<
":\n";
3933 std::vector<const App *> subcommands_group = app->get_subcommands(
3935 for(
const App *new_com : subcommands_group) {
3936 if(mode != AppFormatMode::All) {
3937 out << make_subcommand(new_com);
3939 out << new_com->help(new_com->get_name(), AppFormatMode::Sub);
3940 if(new_com != subcommands_group.back())
3949 inline std::string Formatter::make_subcommand(
const App *sub)
const {
3950 std::stringstream out;
3955 inline std::string Formatter::make_expanded(
const App *sub)
const {
3956 std::stringstream out;
3957 if(sub->get_description().empty())
3958 out << sub->get_name();
3960 out << sub->get_name() <<
" -> " << sub->get_description();
3961 out << make_groups(sub, AppFormatMode::Sub);
3965 inline std::string Formatter::make_option_name(
const Option *opt,
bool is_positional)
const {
3967 return opt->get_name(
true,
false);
3969 return opt->get_name(
false,
true);
3972 inline std::string Formatter::make_option_opts(
const Option *opt)
const {
3973 std::stringstream out;
3975 if(opt->get_type_size() != 0) {
3976 if(!opt->get_type_name().empty())
3977 out <<
" " << get_label(opt->get_type_name());
3978 if(!opt->get_defaultval().empty())
3979 out <<
"=" << opt->get_defaultval();
3980 if(opt->get_expected() > 1)
3981 out <<
" x " << opt->get_expected();
3982 if(opt->get_expected() == -1)
3984 if(opt->get_required())
3985 out <<
" " << get_label(
"REQUIRED");
3987 if(!opt->get_envname().empty())
3988 out <<
" (" << get_label(
"Env") <<
":" << opt->get_envname() <<
")";
3989 if(!opt->get_needs().empty()) {
3990 out <<
" " << get_label(
"Needs") <<
":";
3991 for(
const Option *op : opt->get_needs())
3992 out <<
" " << op->get_name();
3994 if(!opt->get_excludes().empty()) {
3995 out <<
" " << get_label(
"Excludes") <<
":";
3996 for(
const Option *op : opt->get_excludes())
3997 out <<
" " << op->get_name();
4002 inline std::string Formatter::make_option_desc(
const Option *opt)
const {
return opt->get_description(); }
4004 inline std::string Formatter::make_option_usage(
const Option *opt)
const {
4006 std::stringstream out;
4007 out << make_option_name(opt,
true);
4009 if(opt->get_expected() > 1)
4011 else if(opt->get_expected() < 0)
4014 return opt->get_required() ? out.str() :
"[" + out.str() +
"]";
All errors derive from this one.
std::string to_lower(std::string str)
Return a lower case version of a string.
constexpr bool operator==(const day &x, const day &y) noexcept
constexpr const char * type_name()
This one should not be used, since vector types print the internal type.
-h or –help on command line
std::basic_istream< CharT, Traits > & operator>>(std::basic_istream< CharT, Traits > &is, const parse_manip< Parsable, CharT, Traits, Alloc > &x)
constexpr enabler dummy
An instance to use in EnableIf.
Does not output a diagnostic in CLI11_PARSE, but allows to return from main() with a specific error c...
static BadNameString BadLongName(std::string name)
std::string & ltrim(std::string &str)
Trim whitespace from left of string.
ConversionError(std::string name, std::vector< std::string > results)
auto parse(const std::basic_string< CharT, Traits, Alloc > &format, Parsable &tp) -> decltype(from_stream(std::declval< std::basic_istream< CharT, Traits > & >(), format.c_str(), tp), parse_manip< Parsable, CharT, Traits, Alloc >
bool lexical_cast(std::string input, T &output)
Signed integers / enums.
std::vector< std::string > split_up(std::string str)
Split a string '"one two" "three"' into 'one two', 'three'.
bool split_short(const std::string ¤t, std::string &name, std::string &rest)
Error(std::string name, std::string msg, ExitCodes exit_code)
Thrown when an excludes option is present.
std::string trim_copy(const std::string &str)
Make a copy of the string and then trim it.
std::string type(const x_type &a_param)
static IncorrectConstruction Set0Opt(std::string name)
static BadNameString DashesOnly(std::string name)
bool split_long(const std::string ¤t, std::string &name, std::string &value)
enabler
Simple empty scoped class.
static IncorrectConstruction AfterMultiOpt(std::string name)
typename std::enable_if< B, T >::type enable_if_t
std::string rjoin(const T &v, std::string delim=",")
Join a string in reverse order.
static RequiredError Subcommand(size_t min_subcom)
Error(std::string name, std::string msg, int exit_code=static_cast< int >(ExitCodes::BaseClass))
Thrown when an option is set to conflicting values (non-vector and multi args, for example) ...
#define CLI11_DEPRECATED(reason)
static IncorrectConstruction SetFlag(std::string name)
static IncorrectConstruction MultiOptionPolicy(std::string name)
std::vector< std::string > split_names(std::string current)
static IncorrectConstruction PositionalFlag(std::string name)
bool valid_later_char(T c)
Verify following characters of an option.
bool valid_name_string(const std::string &str)
Verify an option name.
std::string & rtrim(std::string &str)
Trim whitespace from right of string.
bool valid_first_char(T c)
Verify the first character of an option.
std::tuple< std::vector< std::string >, std::vector< std::string >, std::string > get_names(const std::vector< std::string > &input)
Get a vector of short names, one of long names, and a single name.
Thrown when a requires option is missing.
static IncorrectConstruction MissingOption(std::string name)
static IncorrectConstruction ChangeNotVector(std::string name)
static OptionAlreadyAdded Requires(std::string name, std::string other)
Usually somethign like –help-all on command line.
#define CLI11_ERROR_DEF(parent, name)
Thrown when extra values are found in an INI file.
static BadNameString MultiPositionalNames(std::string name)
Thrown when validation fails before parsing.
Thrown when parsing an INI file and it is missing.
static ArgumentMismatch AtLeast(std::string name, int num)
static BadNameString OneCharName(std::string name)
#define CLI11_ERROR_SIMPLE(name)
constexpr std::chrono::duration< Rep, Period > abs(std::chrono::duration< Rep, Period > d)
std::ostream & format_help(std::ostream &out, std::string name, std::string description, size_t wid)
Print a two part "help" string.
static OptionAlreadyAdded Excludes(std::string name, std::string other)
Construction errors (not in parsing)
static FileError Missing(std::string name)
Thrown when an option already exists.
Thrown when counting a non-existent option.
This is a successful completion on parsing, supposed to exit.
std::string fix_newlines(std::string leader, std::string input)
static ArgumentMismatch TypedAtLeast(std::string name, int num, std::string type)
static ConversionError TooManyInputsFlag(std::string name)
std::string to_string(std::uint64_t x)
Thrown on construction of a bad name.
static ConfigError NotConfigurable(std::string item)
static ConfigError Extras(std::string item)
Anything that can error in Parse.
int get_exit_code() const
Thrown when the wrong number of arguments has been received.
Thrown when conversion call back fails, such as when an int fails to coerce to a string.
std::vector< std::string > split(const std::string &s, char delim)
Split a string by a delim.
std::string & trim(std::string &str)
Trim whitespace from string.
std::string get_name() const
std::string join(const T &v, std::string delim=",")
Simple function to join a string.
Thrown when a required option is missing.
static ConversionError TrueFalse(std::string name)
Thrown when validation of results fails.