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)
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.
int main(int argc, char **argv)
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)
std::string get_name() const
Thrown when extra values are found in an INI file.
static BadNameString MultiPositionalNames(std::string name)
Thrown when validation fails before parsing.
const x_value & at(const std::map< x_key, x_value > &a_map, const x_key &a_key, const x_value &a_default)
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.
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 >
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.
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 join(const T &v, std::string delim=",")
Simple function to join a string.
Thrown when a required option is missing.
int get_exit_code() const
static ConversionError TrueFalse(std::string name)
Thrown when validation of results fails.