22 #include <sys/types.h> 30 #include <type_traits> 39 #define CLI11_VERSION_MAJOR 1 40 #define CLI11_VERSION_MINOR 4 41 #define CLI11_VERSION_PATCH 0 42 #define CLI11_VERSION "1.4.0" 53 inline std::vector<std::string>
split(
const std::string &s,
char delim) {
54 std::vector<std::string> elems;
57 elems.emplace_back(
"");
62 while(std::getline(ss, item, delim)) {
63 elems.push_back(item);
70 template <
typename T> std::string
join(
const T &v, std::string delim =
",") {
73 for(
const auto &i : v) {
82 template <
typename T> std::string
rjoin(
const T &v, std::string delim =
",") {
84 for(
size_t start = 0; start < v.size(); start++) {
87 s << v[v.size() - start - 1];
96 auto it = std::find_if(str.begin(), str.end(), [](
char ch) {
return !std::isspace<char>(ch, std::locale()); });
97 str.erase(str.begin(), it);
102 inline std::string &
ltrim(std::string &
str,
const std::string &filter) {
103 auto it = std::find_if(str.begin(), str.end(), [&filter](
char ch) {
return filter.find(ch) == std::string::npos; });
104 str.erase(str.begin(), it);
110 auto it = std::find_if(str.rbegin(), str.rend(), [](
char ch) {
return !std::isspace<char>(ch, std::locale()); });
111 str.erase(it.base(), str.end());
116 inline std::string &
rtrim(std::string &
str,
const std::string &filter) {
118 std::find_if(str.rbegin(), str.rend(), [&filter](
char ch) {
return filter.find(ch) == std::string::npos; });
119 str.erase(it.base(), str.end());
127 inline std::string &
trim(std::string &
str,
const std::string filter) {
return ltrim(
rtrim(str, filter), filter); }
136 inline std::string
trim_copy(
const std::string &
str,
const std::string &filter) {
138 return trim(s, filter);
141 inline void format_help(std::stringstream &out, std::string name, std::string description,
size_t wid) {
143 out << std::setw(static_cast<int>(wid)) << std::left << name;
144 if(!description.empty()) {
145 if(name.length() >= wid)
146 out << std::endl << std::setw(static_cast<int>(wid)) <<
"";
153 template <
typename T>
bool valid_first_char(T c) {
return std::isalpha(c, std::locale()) || c ==
'_'; }
157 return std::isalnum(c, std::locale()) || c ==
'_' || c ==
'.' || c ==
'-';
164 for(
auto c : str.substr(1))
172 std::transform(std::begin(str), std::end(str), std::begin(str), [](
const std::string::value_type &x) {
173 return std::tolower(x, std::locale());
181 std::vector<char> delims = {
'\'',
'\"'};
182 auto find_ws = [](
char ch) {
return std::isspace<char>(ch, std::locale()); };
185 std::vector<std::string> output;
187 while(!str.empty()) {
189 auto end = str.find(
'\'', 1);
190 if(end != std::string::npos) {
191 output.push_back(str.substr(1, end - 1));
192 str = str.substr(end + 1);
194 output.push_back(str.substr(1));
197 }
else if(str[0] ==
'\"') {
198 auto end = str.find(
'\"', 1);
199 if(end != std::string::npos) {
200 output.push_back(str.substr(1, end - 1));
201 str = str.substr(end + 1);
203 output.push_back(str.substr(1));
208 auto it = std::find_if(std::begin(str), std::end(str), find_ws);
209 if(it != std::end(str)) {
210 std::string value = std::string(str.begin(), it);
211 output.push_back(value);
212 str = std::string(it, str.end());
214 output.push_back(str);
228 inline std::string
fix_newlines(std::string leader, std::string input) {
229 std::string::size_type n = 0;
230 while(n != std::string::npos && n < input.size()) {
231 n = input.find(
'\n', n);
232 if(n != std::string::npos) {
233 input = input.substr(0, n + 1) + leader + input.substr(n + 1);
248 #define CLI11_ERROR_DEF(parent, name) \ 250 name(std::string name, std::string msg, int exit_code) : parent(std::move(name), std::move(msg), exit_code) {} \ 251 name(std::string name, std::string msg, ExitCodes exit_code) \ 252 : parent(std::move(name), std::move(msg), exit_code) {} \ 255 name(std::string msg, ExitCodes exit_code) : parent(#name, std::move(msg), exit_code) {} \ 256 name(std::string msg, int exit_code) : parent(#name, std::move(msg), exit_code) {} 259 #define CLI11_ERROR_SIMPLE(name) \ 260 name(std::string msg) : name(#name, msg, ExitCodes::name) {} 293 class Error :
public std::runtime_error {
295 std::string name{
"Error"};
303 : runtime_error(msg), exit_code(exit_code), name(std::move(name)) {}
305 Error(std::string name, std::string msg,
ExitCodes exit_code) :
Error(name, msg, static_cast<int>(exit_code)) {}
330 name +
": You can't change expected arguments after you've changed the multi option policy!");
336 return IncorrectConstruction(name +
": multi_option_policy only works for flags and single value options");
347 return BadNameString(
"Must have a name, not just dashes: " + name);
349 static BadNameString MultiPositionalNames(std::string name) {
350 return BadNameString(
"Only one positional name allowed, remove: " + name);
398 static FileError Missing(std::string name) {
return FileError(name +
" was not readable (missing?)"); }
406 :
ConversionError(
"The value " + member +
" is not an allowed value for " + name) {}
432 return RequiredError(
"Requires at least " + std::to_string(min_subcom) +
" subcommands",
442 :
ArgumentMismatch(expected > 0 ? (
"Expected exactly " + std::to_string(expected) +
" arguments to " + name +
443 ", got " + std::to_string(recieved))
444 : (
"Expected at least " + std::to_string(-expected) +
" arguments to " + name +
445 ", got " + std::to_string(recieved)),
449 return ArgumentMismatch(name +
": At least " + std::to_string(num) +
" required");
451 static ArgumentMismatch TypedAtLeast(std::string name,
int num, std::string type) {
452 return ArgumentMismatch(name +
": " + std::to_string(num) +
" required " + type +
" missing");
474 :
ExtrasError((args.size() > 1 ?
"The following arguments were not expected: " 475 :
"The following argument was not expected: ") +
484 static INIError Extras(std::string item) {
return INIError(
"INI was not able to parse " + item); }
485 static INIError NotConfigurable(std::string item) {
486 return INIError(item +
": This option is not allowed in a configuration file");
527 template <
bool B,
class T =
void>
using enable_if_t =
typename std::enable_if<B, T>::type;
529 template <
typename T>
struct is_vector {
static const bool value =
false; };
531 template <
class T,
class A>
struct is_vector<std::vector<T, A>> {
static bool const value =
true; };
533 template <
typename T>
struct is_bool {
static const bool value =
false; };
535 template <>
struct is_bool<bool> {
static bool const value =
true; };
551 template <
typename T,
557 template <
typename T,
563 template <typename T, enable_if_t<std::is_floating_point<T>::value, detail::enabler> =
detail::dummy>
569 template <typename T, enable_if_t<is_vector<T>::value, detail::enabler> =
detail::dummy>
574 template <
typename T,
584 template <
typename T,
590 long long output_ll = std::stoll(input, &n, 0);
591 output =
static_cast<T
>(output_ll);
592 return n == input.size() &&
static_cast<long long>(output) == output_ll;
593 }
catch(
const std::invalid_argument &) {
595 }
catch(
const std::out_of_range &) {
601 template <
typename T,
604 if(!input.empty() && input.front() ==
'-')
609 unsigned long long output_ll = std::stoull(input, &n, 0);
610 output =
static_cast<T
>(output_ll);
611 return n == input.size() &&
static_cast<unsigned long long>(output) == output_ll;
612 }
catch(
const std::invalid_argument &) {
614 }
catch(
const std::out_of_range &) {
620 template <typename T, enable_if_t<std::is_floating_point<T>::value, detail::enabler> =
detail::dummy>
624 output =
static_cast<T
>(std::stold(input, &n));
625 return n == input.size();
626 }
catch(
const std::invalid_argument &) {
628 }
catch(
const std::out_of_range &) {
634 template <
typename T,
636 std::is_assignable<T &, std::string>::value,
644 template <
typename T,
646 !std::is_assignable<T &, std::string>::value,
652 #if defined(__GNUC__) && !defined(__clang__) && !defined(__INTEL_COMPILER) && __GNUC__ == 4 && (__GNUC_MINOR__ < 8) 653 std::istringstream is;
655 static thread_local std::istringstream is;
660 return !is.fail() && !is.rdbuf()->in_avail();
672 inline bool split_short(
const std::string ¤t, std::string &name, std::string &rest) {
673 if(current.size() > 1 && current[0] ==
'-' &&
valid_first_char(current[1])) {
674 name = current.substr(1, 1);
675 rest = current.substr(2);
682 inline bool split_long(
const std::string ¤t, std::string &name, std::string &value) {
683 if(current.size() > 2 && current.substr(0, 2) ==
"--" &&
valid_first_char(current[2])) {
684 auto loc = current.find(
"=");
685 if(loc != std::string::npos) {
686 name = current.substr(2, loc - 2);
687 value = current.substr(loc + 1);
689 name = current.substr(2);
698 inline std::vector<std::string>
split_names(std::string current) {
699 std::vector<std::string> output;
701 while((val = current.find(
",")) != std::string::npos) {
702 output.push_back(
trim_copy(current.substr(0, val)));
703 current = current.substr(val + 1);
710 inline std::tuple<std::vector<std::string>, std::vector<std::string>, std::string>
713 std::vector<std::string> short_names;
714 std::vector<std::string> long_names;
715 std::string pos_name;
717 for(std::string name : input) {
718 if(name.length() == 0)
720 else if(name.length() > 1 && name[0] ==
'-' && name[1] !=
'-') {
722 short_names.emplace_back(1, name[1]);
724 throw BadNameString::OneCharName(name);
725 }
else if(name.length() > 2 && name.substr(0, 2) ==
"--") {
726 name = name.substr(2);
728 long_names.push_back(name);
730 throw BadNameString::BadLongName(name);
731 }
else if(name ==
"-" || name ==
"--") {
732 throw BadNameString::DashesOnly(name);
734 if(pos_name.length() > 0)
735 throw BadNameString::MultiPositionalNames(name);
740 return std::tuple<std::vector<std::string>, std::vector<std::string>, std::string>(
741 short_names, long_names, pos_name);
752 inline std::string inijoin(std::vector<std::string> args) {
753 std::ostringstream s;
755 for(
const auto &arg : args) {
759 auto it = std::find_if(arg.begin(), arg.end(), [](
char ch) {
return std::isspace<char>(ch, std::locale()); });
762 else if(arg.find(R
"(")") == std::string::npos) 763 s << R"(")" << arg << R"(")"; 765 s << R
"(')" << arg << R"(')"; 773 std::string fullname;
776 std::vector<std::string> inputs;
785 std::string parent()
const {
786 std::vector<std::string> plist =
detail::split(fullname,
'.');
787 if(plist.size() > (level + 1))
794 std::string name()
const {
795 std::vector<std::string> plist =
detail::split(fullname,
'.');
796 return plist.at(plist.size() - 1);
801 inline std::vector<ini_ret_t> parse_ini(std::istream &input) {
802 std::string name, line;
803 std::string section =
"default";
805 std::vector<ini_ret_t> output;
807 while(getline(input, line)) {
808 std::vector<std::string> items;
811 size_t len = line.length();
812 if(len > 1 && line[0] ==
'[' && line[len - 1] ==
']') {
813 section = line.substr(1, len - 2);
814 }
else if(len > 0 && line[0] !=
';') {
815 output.emplace_back();
816 ini_ret_t &out = output.back();
819 auto pos = line.find(
"=");
820 if(pos != std::string::npos) {
832 out.fullname = section +
"." + name;
834 out.inputs.insert(std::end(out.inputs), std::begin(items), std::end(items));
841 inline std::vector<ini_ret_t> parse_ini(
const std::string &name) {
843 std::ifstream input{name};
845 throw FileError::Missing(name);
847 return parse_ini(input);
865 inline std::string ExistingFile(
const std::string &filename) {
867 bool exist = stat(filename.c_str(), &buffer) == 0;
868 bool is_dir = (buffer.st_mode & S_IFDIR) != 0;
870 return "File does not exist: " + filename;
872 return "File is actually a directory: " + filename;
874 return std::string();
878 inline std::string ExistingDirectory(
const std::string &filename) {
880 bool exist = stat(filename.c_str(), &buffer) == 0;
881 bool is_dir = (buffer.st_mode & S_IFDIR) != 0;
883 return "Directory does not exist: " + filename;
885 return "Directory is actually a file: " + filename;
887 return std::string();
891 inline std::string ExistingPath(
const std::string &filename) {
893 bool const exist = stat(filename.c_str(), &buffer) == 0;
895 return "Path does not exist: " + filename;
897 return std::string();
901 inline std::string NonexistentPath(
const std::string &filename) {
903 bool exist = stat(filename.c_str(), &buffer) == 0;
905 return "Path already exists: " + filename;
907 return std::string();
911 template <
typename T> std::function<std::string(const std::string &)> Range(T min, T max) {
912 return [min, max](std::string input) {
915 if(val < min || val > max)
916 return "Value " + input +
" not in range " + std::to_string(min) +
" to " + std::to_string(max);
918 return std::string();
923 template <
typename T> std::function<std::string(const std::string &)> Range(T max) {
924 return Range(static_cast<T>(0), max);
935 using results_t = std::vector<std::string>;
936 using callback_t = std::function<bool(results_t)>;
941 using Option_p = std::unique_ptr<Option>;
943 enum class MultiOptionPolicy { Throw, TakeLast, TakeFirst, Join };
945 template <
typename CRTP>
class OptionBase {
950 std::string group_{
"Options"};
953 bool required_{
false};
956 bool ignore_case_{
false};
959 bool configurable_{
true};
962 MultiOptionPolicy multi_option_policy_{MultiOptionPolicy::Throw};
964 template <
typename T>
void copy_to(T *other)
const {
965 other->group(group_);
966 other->required(required_);
967 other->ignore_case(ignore_case_);
968 other->configurable(configurable_);
969 other->multi_option_policy(multi_option_policy_);
976 CRTP *group(std::string name) {
978 return static_cast<CRTP *
>(
this);
983 CRTP *required(
bool value =
true) {
985 return static_cast<CRTP *
>(
this);
989 CRTP *mandatory(
bool value =
true) {
return required(value); }
994 const std::string &get_group()
const {
return group_; }
997 bool get_required()
const {
return required_; }
1000 bool get_ignore_case()
const {
return ignore_case_; }
1003 bool get_configurable()
const {
return configurable_; }
1006 MultiOptionPolicy get_multi_option_policy()
const {
return multi_option_policy_; }
1012 CRTP *
self =
static_cast<CRTP *
>(
this);
1013 self->multi_option_policy(MultiOptionPolicy::TakeLast);
1018 CRTP *take_first() {
1019 CRTP *
self =
static_cast<CRTP *
>(
this);
1020 self->multi_option_policy(MultiOptionPolicy::TakeFirst);
1026 CRTP *
self =
static_cast<CRTP *
>(
this);
1027 self->multi_option_policy(MultiOptionPolicy::Join);
1032 CRTP *configurable(
bool value =
true) {
1033 configurable_ = value;
1034 return static_cast<CRTP *
>(
this);
1038 class OptionDefaults :
public OptionBase<OptionDefaults> {
1040 OptionDefaults() =
default;
1045 OptionDefaults *multi_option_policy(MultiOptionPolicy value = MultiOptionPolicy::Throw) {
1046 multi_option_policy_ = value;
1051 OptionDefaults *ignore_case(
bool value =
true) {
1052 ignore_case_ = value;
1057 class Option :
public OptionBase<Option> {
1065 std::vector<std::string> snames_;
1068 std::vector<std::string> lnames_;
1074 std::string envname_;
1081 std::string description_;
1084 std::string defaultval_;
1087 std::string typeval_;
1090 bool default_{
false};
1100 bool changeable_{
false};
1103 std::vector<std::function<std::string(std::string &)>> validators_;
1106 std::set<Option *> requires_;
1109 std::set<Option *> excludes_;
1119 callback_t callback_;
1129 bool callback_run_{
false};
1134 Option(std::string name,
1135 std::string description =
"",
1136 std::function<
bool(results_t)> callback = [](results_t) {
return true; },
1137 bool default_ =
true,
1138 App *parent =
nullptr)
1139 : description_(std::move(description)), default_(default_), parent_(parent), callback_(std::move(callback)) {
1148 size_t count()
const {
return results_.size(); }
1151 operator bool()
const {
return count() > 0; }
1154 void clear() { results_.clear(); }
1161 Option *expected(
int value) {
1162 if(expected_ == value)
1165 throw IncorrectConstruction::Set0Opt(single_name());
1166 else if(!changeable_)
1167 throw IncorrectConstruction::ChangeNotVector(single_name());
1168 else if(value != 1 && multi_option_policy_ != MultiOptionPolicy::Throw)
1169 throw IncorrectConstruction::AfterMultiOpt(single_name());
1176 Option *check(std::function<std::string(
const std::string &)> validator) {
1177 validators_.emplace_back(validator);
1182 Option *transform(std::function<std::string(std::string)> func) {
1183 validators_.emplace_back([func](std::string &inout) {
1185 inout = func(inout);
1187 return std::string(e.what());
1189 return std::string();
1195 Option *needs(Option *opt) {
1196 auto tup = requires_.insert(opt);
1198 throw OptionAlreadyAdded::Requires(get_name(), opt->get_name());
1203 template <
typename T = App> Option *needs(std::string opt_name) {
1204 for(
const Option_p &opt : dynamic_cast<T *>(parent_)->options_)
1205 if(opt.get() !=
this && opt->check_name(opt_name))
1206 return needs(opt.get());
1207 throw IncorrectConstruction::MissingOption(opt_name);
1211 template <
typename A,
typename B,
typename... ARG> Option *needs(
A opt, B opt1, ARG... args) {
1213 return needs(opt1, args...);
1216 #if __cplusplus <= 201703L 1217 Option *requires(Option *opt) {
return needs(opt); }
1221 template <
typename T = App> Option *requires(std::string opt_name) {
return needs<T>(opt_name); }
1224 template <
typename A,
typename B,
typename... ARG> Option *requires(A opt, B opt1, ARG... args) {
1226 return needs(opt1, args...);
1231 Option *excludes(Option *opt) {
1232 auto tup = excludes_.insert(opt);
1234 throw OptionAlreadyAdded::Excludes(get_name(), opt->get_name());
1239 template <
typename T = App> Option *excludes(std::string opt_name) {
1240 for(
const Option_p &opt : dynamic_cast<T *>(parent_)->options_)
1241 if(opt.get() !=
this && opt->check_name(opt_name))
1242 return excludes(opt.get());
1243 throw IncorrectConstruction::MissingOption(opt_name);
1247 template <
typename A,
typename B,
typename... ARG> Option *excludes(A opt, B opt1, ARG... args) {
1249 return excludes(opt1, args...);
1253 Option *envname(std::string name) {
1262 template <
typename T = App> Option *ignore_case(
bool value =
true) {
1263 ignore_case_ = value;
1264 auto *parent =
dynamic_cast<T *
>(parent_);
1266 for(
const Option_p &opt : parent->options_)
1267 if(opt.get() !=
this && *opt == *
this)
1274 Option *multi_option_policy(MultiOptionPolicy value = MultiOptionPolicy::Throw) {
1275 if(get_expected() != 0 && get_expected() != 1)
1276 throw IncorrectConstruction::MultiOptionPolicy(single_name());
1277 multi_option_policy_ = value;
1286 int get_expected()
const {
return expected_; }
1289 int get_default()
const {
return default_; }
1292 bool get_positional()
const {
return pname_.length() > 0; }
1295 bool nonpositional()
const {
return (snames_.size() + lnames_.size()) > 0; }
1298 bool has_description()
const {
return description_.length() > 0; }
1301 const std::string &get_description()
const {
return description_; }
1304 std::string get_pname()
const {
return pname_; }
1311 std::string get_name(
bool opt_only =
false)
const {
1312 std::vector<std::string> name_list;
1313 if(!opt_only && pname_.length() > 0)
1314 name_list.push_back(pname_);
1315 for(
const std::string &sname : snames_)
1316 name_list.push_back(
"-" + sname);
1317 for(
const std::string &lname : lnames_)
1318 name_list.push_back(
"--" + lname);
1323 std::string help_positional()
const {
1324 std::string out = pname_;
1325 if(get_expected() > 1)
1326 out = out +
"(" + std::to_string(get_expected()) +
"x)";
1327 else if(get_expected() == -1)
1329 out = get_required() ? out :
"[" + out +
"]";
1334 std::string single_name()
const {
1335 if(!lnames_.empty())
1336 return std::string(
"--") + lnames_[0];
1337 else if(!snames_.empty())
1338 return std::string(
"-") + snames_[0];
1344 std::string help_name(
bool opt_only =
false)
const {
1345 std::stringstream out;
1346 out << get_name(opt_only) << help_aftername();
1351 std::string help_pname()
const {
1352 std::stringstream out;
1353 out << get_pname() << help_aftername();
1358 std::string help_aftername()
const {
1359 std::stringstream out;
1361 if(get_expected() != 0) {
1362 if(!typeval_.empty())
1363 out <<
" " << typeval_;
1364 if(!defaultval_.empty())
1365 out <<
"=" << defaultval_;
1366 if(get_expected() > 1)
1367 out <<
" x " << get_expected();
1368 if(get_expected() == -1)
1371 if(!envname_.empty())
1372 out <<
" (env:" << envname_ <<
")";
1373 if(!requires_.empty()) {
1374 out <<
" Requires:";
1375 for(
const Option *opt : requires_)
1376 out <<
" " << opt->get_name();
1378 if(!excludes_.empty()) {
1379 out <<
" Excludes:";
1380 for(
const Option *opt : excludes_)
1381 out <<
" " << opt->get_name();
1391 void run_callback() {
1394 if(!validators_.empty()) {
1395 for(std::string &result : results_)
1396 for(
const std::function<std::string(std::string &)> &vali : validators_) {
1397 std::string err_msg = vali(result);
1398 if(!err_msg.empty())
1406 if(multi_option_policy_ == MultiOptionPolicy::TakeLast) {
1407 results_t partial_result = {results_.back()};
1408 local_result = !callback_(partial_result);
1409 }
else if(multi_option_policy_ == MultiOptionPolicy::TakeFirst) {
1410 results_t partial_result = {results_.at(0)};
1411 local_result = !callback_(partial_result);
1412 }
else if(multi_option_policy_ == MultiOptionPolicy::Join) {
1413 results_t partial_result = {
detail::join(results_,
"\n")};
1414 local_result = !callback_(partial_result);
1416 if((expected_ > 0 && results_.size() !=
static_cast<size_t>(expected_)) ||
1417 (expected_ < 0 && results_.size() <
static_cast<size_t>(-expected_)))
1420 local_result = !callback_(results_);
1428 bool operator==(
const Option &other)
const {
1429 for(
const std::string &sname : snames_)
1430 if(other.check_sname(sname))
1432 for(
const std::string &lname : lnames_)
1433 if(other.check_lname(lname))
1436 for(
const std::string &sname : other.snames_)
1437 if(check_sname(sname))
1439 for(
const std::string &lname : other.lnames_)
1440 if(check_lname(lname))
1446 bool check_name(std::string name)
const {
1448 if(name.length() > 2 && name.substr(0, 2) ==
"--")
1449 return check_lname(name.substr(2));
1450 else if(name.length() > 1 && name.substr(0, 1) ==
"-")
1451 return check_sname(name.substr(1));
1453 std::string local_pname = pname_;
1458 return name == local_pname;
1463 bool check_sname(std::string name)
const {
1466 return std::find_if(std::begin(snames_), std::end(snames_), [&name](std::string local_sname) {
1468 }) != std::end(snames_);
1470 return std::find(std::begin(snames_), std::end(snames_), name) != std::end(snames_);
1474 bool check_lname(std::string name)
const {
1477 return std::find_if(std::begin(lnames_), std::end(lnames_), [&name](std::string local_sname) {
1479 }) != std::end(lnames_);
1481 return std::find(std::begin(lnames_), std::end(lnames_), name) != std::end(lnames_);
1485 void add_result(std::string s) {
1486 results_.push_back(s);
1487 callback_run_ =
false;
1491 std::vector<std::string> results()
const {
return results_; }
1494 bool get_callback_run()
const {
return callback_run_; }
1501 void set_custom_option(std::string typeval,
int expected = 1) {
1503 expected_ = expected;
1506 changeable_ = expected < 0;
1510 void set_default_str(std::string val) { defaultval_ = val; }
1513 void set_default_val(std::string val) {
1514 set_default_str(val);
1515 auto old_results = results_;
1518 results_ = std::move(old_results);
1522 void set_type_name(std::string val) { typeval_ = val; }
1525 std::string get_type_name()
const {
return typeval_; }
1533 bool _has_help_positional()
const {
1534 return get_positional() && (has_description() || !requires_.empty() || !excludes_.empty());
1546 #define CLI11_PARSE(app, argc, argv) \ 1548 (app).parse((argc), (argv)); \ 1549 } catch(const CLI::ParseError &e) { \ 1550 return (app).exit(e); \ 1555 enum class Classifer { NONE, POSITIONAL_MARK, SHORT, LONG, SUBCOMMAND };
1559 namespace FailureMessage {
1560 std::string simple(
const App *app,
const Error &e);
1561 std::string help(
const App *app,
const Error &e);
1566 using App_p = std::unique_ptr<App>;
1574 friend detail::AppFriend;
1583 std::string name_{
"program"};
1586 std::string description_;
1589 bool allow_extras_{
false};
1592 bool allow_ini_extras_{
false};
1595 bool prefix_command_{
false};
1598 std::function<void()> callback_;
1605 OptionDefaults option_defaults_;
1608 std::vector<Option_p> options_;
1615 std::string footer_;
1618 Option *help_ptr_{
nullptr};
1621 std::function<std::string(const App *, const Error &e)> failure_message_ = FailureMessage::simple;
1627 using missing_t = std::vector<std::pair<detail::Classifer, std::string>>;
1635 std::vector<Option *> parse_order_;
1638 std::vector<App *> parsed_subcommands_;
1645 std::vector<App_p> subcommands_;
1648 bool ignore_case_{
false};
1651 bool fallthrough_{
false};
1654 App *parent_{
nullptr};
1657 bool parsed_{
false};
1660 size_t require_subcommand_min_ = 0;
1663 size_t require_subcommand_max_ = 0;
1666 std::string group_{
"Subcommands"};
1673 std::string config_name_;
1676 bool config_required_{
false};
1679 Option *config_ptr_{
nullptr};
1684 App(std::string description_, App *parent) : description_(std::move(description_)), parent_(parent) {
1686 if(parent_ !=
nullptr) {
1687 if(parent_->help_ptr_ !=
nullptr)
1688 set_help_flag(parent_->help_ptr_->get_name(), parent_->help_ptr_->get_description());
1691 option_defaults_ = parent_->option_defaults_;
1694 failure_message_ = parent_->failure_message_;
1695 allow_extras_ = parent_->allow_extras_;
1696 allow_ini_extras_ = parent_->allow_ini_extras_;
1697 prefix_command_ = parent_->prefix_command_;
1698 ignore_case_ = parent_->ignore_case_;
1699 fallthrough_ = parent_->fallthrough_;
1700 group_ = parent_->group_;
1701 footer_ = parent_->footer_;
1702 require_subcommand_max_ = parent_->require_subcommand_max_;
1711 App(std::string description_ =
"") : App(description_,
nullptr) {
1712 set_help_flag(
"-h,--help",
"Print this help message and exit");
1721 App *set_callback(std::function<
void()> callback) {
1722 callback_ = callback;
1727 App *allow_extras(
bool allow =
true) {
1728 allow_extras_ = allow;
1734 App *allow_ini_extras(
bool allow =
true) {
1735 allow_extras(allow);
1736 allow_ini_extras_ = allow;
1741 App *prefix_command(
bool allow =
true) {
1742 prefix_command_ = allow;
1747 App *ignore_case(
bool value =
true) {
1748 ignore_case_ = value;
1749 if(parent_ !=
nullptr) {
1750 for(
const auto &subc : parent_->subcommands_) {
1751 if(subc.get() !=
this && (this->check_name(subc->name_) || subc->check_name(this->name_)))
1759 bool parsed()
const {
return parsed_; }
1762 OptionDefaults *option_defaults() {
return &option_defaults_; }
1782 Option *add_option(std::string name, callback_t callback, std::string description =
"",
bool defaulted =
false) {
1783 Option myopt{name, description, callback, defaulted,
this};
1785 if(std::find_if(std::begin(options_), std::end(options_), [&myopt](
const Option_p &v) {
1787 }) == std::end(options_)) {
1788 options_.emplace_back();
1789 Option_p &option = options_.back();
1790 option.reset(
new Option(name, description, callback, defaulted,
this));
1791 option_defaults_.copy_to(option.get());
1792 return option.get();
1799 Option *add_option(std::string name,
1801 std::string description =
"") {
1804 CLI::callback_t fun = [&variable, simple_name](CLI::results_t res) {
1808 Option *opt = add_option(name, fun, description,
false);
1809 opt->set_custom_option(detail::type_name<T>());
1814 template <typename T, enable_if_t<!is_vector<T>::value, detail::enabler> =
detail::dummy>
1815 Option *add_option(std::string name,
1817 std::string description,
1821 CLI::callback_t fun = [&variable, simple_name](CLI::results_t res) {
1825 Option *opt = add_option(name, fun, description, defaulted);
1826 opt->set_custom_option(detail::type_name<T>());
1828 std::stringstream out;
1830 opt->set_default_str(out.str());
1836 template <
typename T>
1837 Option *add_option(std::string name,
1838 std::vector<T> &variable,
1839 std::string description =
"") {
1841 CLI::callback_t fun = [&variable](CLI::results_t res) {
1844 for(
const auto &a : res) {
1845 variable.emplace_back();
1848 return (!variable.empty()) && retval;
1851 Option *opt = add_option(name, fun, description,
false);
1852 opt->set_custom_option(detail::type_name<T>(), -1);
1857 template <
typename T>
1858 Option *add_option(std::string name,
1859 std::vector<T> &variable,
1860 std::string description,
1863 CLI::callback_t fun = [&variable](CLI::results_t res) {
1866 for(
const auto &a : res) {
1867 variable.emplace_back();
1870 return (!variable.empty()) && retval;
1873 Option *opt = add_option(name, fun, description, defaulted);
1874 opt->set_custom_option(detail::type_name<T>(), -1);
1876 opt->set_default_str(
"[" +
detail::join(variable) +
"]");
1881 Option *set_help_flag(std::string name =
"", std::string description =
"") {
1882 if(help_ptr_ !=
nullptr) {
1883 remove_option(help_ptr_);
1884 help_ptr_ =
nullptr;
1889 help_ptr_ = add_flag(name, description);
1890 help_ptr_->configurable(
false);
1897 Option *add_flag(std::string name, std::string description =
"") {
1898 CLI::callback_t fun = [](CLI::results_t) {
return true; };
1900 Option *opt = add_option(name, fun, description,
false);
1901 if(opt->get_positional())
1902 throw IncorrectConstruction::PositionalFlag(name);
1903 opt->set_custom_option(
"", 0);
1908 template <
typename T,
1910 Option *add_flag(std::string name,
1912 std::string description =
"") {
1915 CLI::callback_t fun = [&
count](CLI::results_t res) {
1916 count =
static_cast<T
>(res.size());
1920 Option *opt = add_option(name, fun, description,
false);
1921 if(opt->get_positional())
1922 throw IncorrectConstruction::PositionalFlag(name);
1923 opt->set_custom_option(
"", 0);
1929 template <typename T, enable_if_t<is_bool<T>::value, detail::enabler> =
detail::dummy>
1930 Option *add_flag(std::string name,
1932 std::string description =
"") {
1935 CLI::callback_t fun = [&
count](CLI::results_t res) {
1937 return res.size() == 1;
1940 Option *opt = add_option(name, fun, description,
false);
1941 if(opt->get_positional())
1942 throw IncorrectConstruction::PositionalFlag(name);
1943 opt->set_custom_option(
"", 0);
1944 opt->multi_option_policy(CLI::MultiOptionPolicy::TakeLast);
1949 Option *add_flag_function(std::string name,
1950 std::function<
void(
size_t)>
function,
1951 std::string description =
"") {
1953 CLI::callback_t fun = [
function](CLI::results_t res) {
1954 auto count =
static_cast<size_t>(res.size());
1959 Option *opt = add_option(name, fun, description,
false);
1960 if(opt->get_positional())
1961 throw IncorrectConstruction::PositionalFlag(name);
1962 opt->set_custom_option(
"", 0);
1966 #if __cplusplus >= 201402L 1967 Option *add_flag(std::string name,
1969 std::function<
void(
size_t)>
function,
1970 std::string description =
"") {
1971 return add_flag_function(name,
function, description);
1976 template <
typename T>
1977 Option *add_set(std::string name,
1979 std::set<T> options,
1980 std::string description =
"") {
1983 CLI::callback_t fun = [&member, options, simple_name](CLI::results_t res) {
1987 return std::find(std::begin(options), std::end(options), member) != std::end(options);
1990 Option *opt = add_option(name, fun, description,
false);
1991 std::string typeval = detail::type_name<T>();
1993 opt->set_custom_option(typeval);
1998 template <
typename T>
1999 Option *add_set(std::string name,
2001 std::set<T> options,
2002 std::string description,
2006 CLI::callback_t fun = [&member, options, simple_name](CLI::results_t res) {
2010 return std::find(std::begin(options), std::end(options), member) != std::end(options);
2013 Option *opt = add_option(name, fun, description, defaulted);
2014 std::string typeval = detail::type_name<T>();
2016 opt->set_custom_option(typeval);
2018 std::stringstream out;
2020 opt->set_default_str(out.str());
2026 Option *add_set_ignore_case(std::string name,
2027 std::string &member,
2028 std::set<std::string> options,
2029 std::string description =
"") {
2032 CLI::callback_t fun = [&member, options, simple_name](CLI::results_t res) {
2034 auto iter = std::find_if(std::begin(options), std::end(options), [&member](std::string val) {
2037 if(iter == std::end(options))
2045 Option *opt = add_option(name, fun, description,
false);
2046 std::string typeval = detail::type_name<std::string>();
2048 opt->set_custom_option(typeval);
2054 Option *add_set_ignore_case(std::string name,
2055 std::string &member,
2056 std::set<std::string> options,
2057 std::string description,
2061 CLI::callback_t fun = [&member, options, simple_name](CLI::results_t res) {
2063 auto iter = std::find_if(std::begin(options), std::end(options), [&member](std::string val) {
2066 if(iter == std::end(options))
2074 Option *opt = add_option(name, fun, description, defaulted);
2075 std::string typeval = detail::type_name<std::string>();
2077 opt->set_custom_option(typeval);
2079 opt->set_default_str(member);
2085 template <
typename T>
2086 Option *add_complex(std::string name,
2088 std::string description =
"",
2089 bool defaulted =
false,
2090 std::string label =
"COMPLEX") {
2093 CLI::callback_t fun = [&variable, simple_name, label](results_t res) {
2094 if(res[1].back() ==
'i')
2103 CLI::Option *opt = add_option(name, fun, description, defaulted);
2104 opt->set_custom_option(label, 2);
2106 std::stringstream out;
2108 opt->set_default_str(out.str());
2114 Option *set_config(std::string name =
"",
2115 std::string default_filename =
"",
2116 std::string help =
"Read an ini file",
2117 bool required =
false) {
2120 if(config_ptr_ !=
nullptr)
2121 remove_option(config_ptr_);
2125 config_name_ = default_filename;
2126 config_required_ = required;
2127 config_ptr_ = add_option(name, config_name_, help, !default_filename.empty());
2128 config_ptr_->configurable(
false);
2135 bool remove_option(Option *opt) {
2137 std::find_if(std::begin(options_), std::end(options_), [opt](
const Option_p &v) {
return v.get() == opt; });
2138 if(iterator != std::end(options_)) {
2139 options_.erase(iterator);
2150 App *add_subcommand(std::string name, std::string description =
"") {
2151 subcommands_.emplace_back(
new App(description,
this));
2152 subcommands_.back()->name_ = name;
2153 for(
const auto &subc : subcommands_)
2154 if(subc.get() != subcommands_.back().get())
2155 if(subc->check_name(subcommands_.back()->name_) || subcommands_.back()->check_name(subc->name_))
2157 return subcommands_.back().get();
2161 App *get_subcommand(App *subcom)
const {
2162 for(
const App_p &subcomptr : subcommands_)
2163 if(subcomptr.get() == subcom)
2169 App *get_subcommand(std::string subcom)
const {
2170 for(
const App_p &subcomptr : subcommands_)
2171 if(subcomptr->check_name(subcom))
2172 return subcomptr.get();
2177 App *group(std::string name) {
2183 App *require_subcommand() {
2184 require_subcommand_min_ = 1;
2185 require_subcommand_max_ = 0;
2192 App *require_subcommand(
int value) {
2194 require_subcommand_min_ = 0;
2195 require_subcommand_max_ =
static_cast<size_t>(-value);
2197 require_subcommand_min_ =
static_cast<size_t>(value);
2198 require_subcommand_max_ =
static_cast<size_t>(value);
2205 App *require_subcommand(
size_t min,
size_t max) {
2206 require_subcommand_min_ = min;
2207 require_subcommand_max_ = max;
2213 App *fallthrough(
bool value =
true) {
2214 fallthrough_ = value;
2220 operator bool()
const {
return parsed_; }
2229 virtual void pre_callback() {}
2237 void parse(
int argc,
char **argv) {
2239 std::vector<std::string> args;
2240 for(
int i = argc - 1; i > 0; i--)
2241 args.emplace_back(argv[i]);
2247 void parse(std::vector<std::string> &args) {
2254 void set_failure_message(std::function<std::string(
const App *,
const Error &e)>
function) {
2255 failure_message_ =
function;
2259 int exit(
const Error &e, std::ostream &out = std::cout, std::ostream &err = std::cerr)
const {
2262 if(dynamic_cast<const CLI::RuntimeError *>(&e) !=
nullptr)
2265 if(dynamic_cast<const CLI::CallForHelp *>(&e) !=
nullptr) {
2271 if(failure_message_)
2272 err << failure_message_(
this, e) << std::flush;
2283 parsed_subcommands_.clear();
2285 for(
const Option_p &opt : options_) {
2288 for(
const App_p &app : subcommands_) {
2298 size_t count(std::string name)
const {
2299 for(
const Option_p &opt : options_) {
2300 if(opt->check_name(name)) {
2301 return opt->count();
2309 std::vector<App *> get_subcommands(
bool parsed =
true)
const {
2311 return parsed_subcommands_;
2313 std::vector<App *> subcomms(subcommands_.size());
2314 std::transform(std::begin(subcommands_), std::end(subcommands_), std::begin(subcomms), [](
const App_p &v) {
2322 bool got_subcommand(App *subcom)
const {
2324 return get_subcommand(subcom)->parsed_;
2328 bool got_subcommand(std::string name)
const {
return get_subcommand(name)->parsed_; }
2335 App *set_footer(std::string footer) {
2343 config_to_str(
bool default_also =
false, std::string prefix =
"",
bool write_description =
false)
const {
2344 std::stringstream out;
2345 for(
const Option_p &opt : options_) {
2348 if(!opt->lnames_.empty() && opt->get_configurable()) {
2349 std::string name = prefix + opt->lnames_[0];
2353 if(opt->get_expected() != 0) {
2356 if(opt->count() > 0)
2357 value = detail::inijoin(opt->results());
2360 else if(default_also && !opt->defaultval_.empty())
2361 value = opt->defaultval_;
2363 }
else if(opt->count() == 1) {
2367 }
else if(opt->count() > 1) {
2368 value = std::to_string(opt->count());
2371 }
else if(opt->count() == 0 && default_also) {
2375 if(!value.empty()) {
2376 if(write_description && opt->has_description()) {
2377 if(static_cast<int>(out.tellp()) != 0) {
2382 out << name <<
"=" << value << std::endl;
2386 for(
const App_p &subcom : subcommands_)
2387 out << subcom->config_to_str(default_also, prefix + subcom->name_ +
".");
2392 std::string help(
size_t wid = 30, std::string prev =
"")
const {
2397 prev +=
" " + name_;
2399 auto selected_subcommands = get_subcommands();
2400 if(!selected_subcommands.empty())
2401 return selected_subcommands.at(0)->help(wid, prev);
2403 std::stringstream out;
2404 out << description_ << std::endl;
2405 out <<
"Usage: " << prev;
2409 std::set<std::string> groups;
2410 for(
const Option_p &opt : options_) {
2411 if(opt->nonpositional()) {
2413 groups.insert(opt->get_group());
2418 out <<
" [OPTIONS]";
2422 for(
const Option_p &opt : options_)
2423 if(opt->get_positional()) {
2427 out <<
" " << opt->help_positional();
2428 if(opt->_has_help_positional())
2432 if(!subcommands_.empty()) {
2433 if(require_subcommand_min_ > 0)
2434 out <<
" SUBCOMMAND";
2436 out <<
" [SUBCOMMAND]";
2443 out << std::endl <<
"Positionals:" << std::endl;
2444 for(
const Option_p &opt : options_) {
2447 if(opt->_has_help_positional())
2454 for(
const std::string &group : groups) {
2457 out << std::endl << group <<
":" << std::endl;
2458 for(
const Option_p &opt : options_) {
2459 if(opt->nonpositional() && opt->get_group() == group)
2466 if(!subcommands_.empty()) {
2467 std::set<std::string> subcmd_groups_seen;
2468 for(
const App_p &com : subcommands_) {
2470 if(group_key.empty() || subcmd_groups_seen.count(group_key) != 0)
2473 subcmd_groups_seen.insert(group_key);
2474 out << std::endl << com->get_group() <<
":" << std::endl;
2475 for(
const App_p &new_com : subcommands_)
2481 if(!footer_.empty()) {
2482 out << std::endl << footer_ << std::endl;
2493 bool get_ignore_case()
const {
return ignore_case_; }
2496 bool get_fallthrough()
const {
return fallthrough_; }
2499 const std::string &get_group()
const {
return group_; }
2502 std::string get_footer()
const {
return footer_; }
2505 size_t get_require_subcommand_min()
const {
return require_subcommand_min_; }
2508 size_t get_require_subcommand_max()
const {
return require_subcommand_max_; }
2511 bool get_prefix_command()
const {
return prefix_command_; }
2514 bool get_allow_extras()
const {
return allow_extras_; }
2517 bool get_allow_ini_extras()
const {
return allow_ini_extras_; }
2520 Option *get_help_ptr() {
return help_ptr_; }
2523 const Option *get_help_ptr()
const {
return help_ptr_; }
2526 Option *get_config_ptr() {
return config_ptr_; }
2529 App *get_parent() {
return parent_; }
2532 const Option *get_config_ptr()
const {
return config_ptr_; }
2534 std::string get_name()
const {
return name_; }
2537 bool check_name(std::string name_to_check)
const {
2538 std::string local_name = name_;
2544 return local_name == name_to_check;
2548 const std::vector<Option *> &parse_order()
const {
return parse_order_; }
2551 std::vector<std::string> remaining(
bool recurse =
false)
const {
2552 std::vector<std::string> miss_list;
2553 for(
const std::pair<detail::Classifer, std::string> &miss : missing_) {
2554 miss_list.push_back(std::get<1>(miss));
2557 for(
const App *sub : parsed_subcommands_) {
2558 std::vector<std::string> output = sub->remaining(recurse);
2559 std::copy(std::begin(output), std::end(output), std::back_inserter(miss_list));
2566 size_t remaining_size(
bool recurse =
false)
const {
2567 size_t count = std::count_if(
2568 std::begin(missing_), std::end(missing_), [](
const std::pair<detail::Classifer, std::string> &val) {
2569 return val.first != detail::Classifer::POSITIONAL_MARK;
2572 for(
const App_p &sub : subcommands_) {
2573 count += sub->remaining_size(recurse);
2585 void _validate()
const {
2586 auto count = std::count_if(std::begin(options_), std::end(options_), [](
const Option_p &opt) {
2587 return opt->get_expected() == -1 && opt->get_positional();
2591 for(
const App_p &app : subcommands_)
2596 void run_callback() {
2600 for(App *subc : get_subcommands()) {
2601 subc->run_callback();
2606 bool _valid_subcommand(
const std::string ¤t)
const {
2608 if(require_subcommand_max_ != 0 && parsed_subcommands_.size() >= require_subcommand_max_) {
2609 return parent_ !=
nullptr && parent_->_valid_subcommand(current);
2612 for(
const App_p &com : subcommands_)
2613 if(com->check_name(current) && !*com)
2617 return parent_ !=
nullptr && parent_->_valid_subcommand(current);
2621 detail::Classifer _recognize(
const std::string ¤t)
const {
2622 std::string dummy1, dummy2;
2625 return detail::Classifer::POSITIONAL_MARK;
2626 if(_valid_subcommand(current))
2627 return detail::Classifer::SUBCOMMAND;
2629 return detail::Classifer::LONG;
2631 return detail::Classifer::SHORT;
2632 return detail::Classifer::NONE;
2636 void _parse(std::vector<std::string> &args) {
2638 bool positional_only =
false;
2640 while(!args.empty()) {
2641 _parse_single(args, positional_only);
2644 if(help_ptr_ !=
nullptr && help_ptr_->count() > 0) {
2649 if(config_ptr_ !=
nullptr) {
2651 config_ptr_->run_callback();
2652 config_required_ =
true;
2654 if(!config_name_.empty()) {
2656 std::vector<detail::ini_ret_t> values = detail::parse_ini(config_name_);
2657 while(!values.empty()) {
2658 if(!_parse_ini(values)) {
2659 throw INIError::Extras(values.back().fullname);
2663 if(config_required_)
2670 for(
const Option_p &opt : options_) {
2671 if(opt->count() == 0 && !opt->envname_.empty()) {
2672 char *buffer =
nullptr;
2673 std::string ename_string;
2678 if(_dupenv_s(&buffer, &sz, opt->envname_.c_str()) == 0 && buffer !=
nullptr) {
2679 ename_string = std::string(buffer);
2684 buffer = std::getenv(opt->envname_.c_str());
2685 if(buffer !=
nullptr)
2686 ename_string = std::string(buffer);
2689 if(!ename_string.empty()) {
2690 opt->add_result(ename_string);
2696 for(
const Option_p &opt : options_) {
2697 if(opt->count() > 0 && !opt->get_callback_run()) {
2698 opt->run_callback();
2703 for(
const Option_p &opt : options_) {
2705 if(opt->get_required() || opt->count() != 0) {
2707 if(opt->get_expected() < 0 && opt->count() <
static_cast<size_t>(-opt->get_expected()))
2708 throw ArgumentMismatch::AtLeast(opt->single_name(), -opt->get_expected());
2711 if(opt->get_required() && opt->count() == 0)
2715 for(
const Option *opt_req : opt->requires_)
2716 if(opt->count() > 0 && opt_req->count() == 0)
2717 throw RequiresError(opt->single_name(), opt_req->single_name());
2719 for(
const Option *opt_ex : opt->excludes_)
2720 if(opt->count() > 0 && opt_ex->count() != 0)
2721 throw ExcludesError(opt->single_name(), opt_ex->single_name());
2724 auto selected_subcommands = get_subcommands();
2725 if(require_subcommand_min_ > selected_subcommands.size())
2726 throw RequiredError::Subcommand(require_subcommand_min_);
2729 if(!(allow_extras_ || prefix_command_)) {
2730 size_t num_left_over = remaining_size();
2731 if(num_left_over > 0) {
2732 args = remaining(
false);
2743 bool _parse_ini(std::vector<detail::ini_ret_t> &args) {
2744 detail::ini_ret_t ¤t = args.back();
2745 std::string parent = current.parent();
2746 std::string name = current.name();
2749 if(!parent.empty()) {
2751 for(
const App_p &com : subcommands_)
2752 if(com->check_name(parent))
2753 return com->_parse_ini(args);
2757 auto op_ptr = std::find_if(
2758 std::begin(options_), std::end(options_), [name](
const Option_p &v) {
return v->check_lname(name); });
2760 if(op_ptr == std::end(options_)) {
2761 if(allow_ini_extras_) {
2763 missing_.emplace_back(detail::Classifer::NONE, current.fullname);
2771 Option_p &op = *op_ptr;
2773 if(!op->get_configurable())
2774 throw INIError::NotConfigurable(current.fullname);
2776 if(op->results_.empty()) {
2778 if(op->get_expected() == 0) {
2779 if(current.inputs.size() == 1) {
2780 std::string val = current.inputs.at(0);
2782 if(val ==
"true" || val ==
"on" || val ==
"yes")
2783 op->results_ = {
""};
2784 else if(val ==
"false" || val ==
"off" || val ==
"no")
2788 size_t ui = std::stoul(val);
2789 for(
size_t i = 0; i < ui; i++)
2790 op->results_.emplace_back(
"");
2791 }
catch(
const std::invalid_argument &) {
2792 throw ConversionError::TrueFalse(current.fullname);
2795 throw ConversionError::TooManyInputsFlag(current.fullname);
2797 op->results_ = current.inputs;
2808 void _parse_single(std::vector<std::string> &args,
bool &positional_only) {
2810 detail::Classifer classifer = positional_only ? detail::Classifer::NONE : _recognize(args.back());
2812 case detail::Classifer::POSITIONAL_MARK:
2813 missing_.emplace_back(classifer, args.back());
2815 positional_only =
true;
2817 case detail::Classifer::SUBCOMMAND:
2818 _parse_subcommand(args);
2820 case detail::Classifer::LONG:
2822 _parse_arg(args,
true);
2824 case detail::Classifer::SHORT:
2826 _parse_arg(args,
false);
2828 case detail::Classifer::NONE:
2830 _parse_positional(args);
2835 size_t _count_remaining_positionals(
bool required =
false)
const {
2837 for(
const Option_p &opt : options_)
2838 if(opt->get_positional() && (!required || opt->get_required()) && opt->get_expected() > 0 &&
2839 static_cast<int>(opt->count()) < opt->get_expected())
2840 retval = static_cast<size_t>(opt->get_expected()) - opt->count();
2846 void _parse_positional(std::vector<std::string> &args) {
2848 std::string positional = args.back();
2849 for(
const Option_p &opt : options_) {
2851 if(opt->get_positional() &&
2852 (
static_cast<int>(opt->count()) < opt->get_expected() || opt->get_expected() < 0)) {
2854 opt->add_result(positional);
2855 parse_order_.push_back(opt.get());
2861 if(parent_ !=
nullptr && fallthrough_)
2862 return parent_->_parse_positional(args);
2865 missing_.emplace_back(detail::Classifer::NONE, positional);
2867 if(prefix_command_) {
2868 while(!args.empty()) {
2869 missing_.emplace_back(detail::Classifer::NONE, args.back());
2879 void _parse_subcommand(std::vector<std::string> &args) {
2880 if(_count_remaining_positionals(
true) > 0)
2881 return _parse_positional(args);
2882 for(
const App_p &com : subcommands_) {
2883 if(com->check_name(args.back())) {
2885 if(std::find(std::begin(parsed_subcommands_), std::end(parsed_subcommands_), com.get()) ==
2886 std::end(parsed_subcommands_))
2887 parsed_subcommands_.push_back(com.get());
2892 if(parent_ !=
nullptr)
2893 return parent_->_parse_subcommand(args);
2895 throw HorribleError(
"Subcommand " + args.back() +
" missing");
2899 void _parse_arg(std::vector<std::string> &args,
bool second_dash) {
2901 detail::Classifer current_type = second_dash ? detail::Classifer::LONG : detail::Classifer::SHORT;
2903 std::string current = args.back();
2911 throw HorribleError(
"Long parsed but missing (you should not see this):" + args.back());
2914 throw HorribleError(
"Short parsed but missing! You should not see this");
2917 auto op_ptr = std::find_if(std::begin(options_), std::end(options_), [name, second_dash](
const Option_p &opt) {
2918 return second_dash ? opt->check_lname(name) : opt->check_sname(name);
2922 if(op_ptr == std::end(options_)) {
2924 if(parent_ !=
nullptr && fallthrough_)
2925 return parent_->_parse_arg(args, second_dash);
2929 missing_.emplace_back(current_type, current);
2937 Option_p &op = *op_ptr;
2939 int num = op->get_expected();
2941 if(!value.empty()) {
2944 op->add_result(value);
2945 parse_order_.push_back(op.get());
2946 }
else if(num == 0) {
2948 parse_order_.push_back(op.get());
2949 }
else if(!rest.empty()) {
2952 op->add_result(rest);
2953 parse_order_.push_back(op.get());
2960 while(!args.empty() && _recognize(args.back()) == detail::Classifer::NONE) {
2961 if(collected >= -num) {
2965 if(_count_remaining_positionals() > 0)
2969 if(std::any_of(std::begin(options_), std::end(options_), [](
const Option_p &opt) {
2970 return opt->get_positional() && opt->get_expected() < 0;
2974 op->add_result(args.back());
2975 parse_order_.push_back(op.get());
2981 while(num > 0 && !args.empty()) {
2983 std::string current_ = args.back();
2985 op->add_result(current_);
2986 parse_order_.push_back(op.get());
2990 throw ArgumentMismatch::TypedAtLeast(op->single_name(), num, op->get_type_name());
2996 args.push_back(rest);
3001 namespace FailureMessage {
3003 inline std::string simple(
const App *app,
const Error &e) {
3004 std::string header = std::string(e.what()) +
"\n";
3005 if(app->get_help_ptr() !=
nullptr)
3006 header +=
"Run with " + app->get_help_ptr()->single_name() +
" for more information.\n";
3010 inline std::string help(
const App *app,
const Error &e) {
3011 std::string header = std::string(
"ERROR: ") + e.
get_name() +
": " + e.what() +
"\n";
3012 header += app->help();
3023 template <
typename... Args>
3024 static auto parse_arg(App *app, Args &&... args) ->
3025 typename std::result_of<decltype (&App::_parse_arg)(App, Args...)>::type {
3026 return app->_parse_arg(std::forward<Args>(args)...);
3030 template <
typename... Args>
3031 static auto parse_subcommand(App *app, Args &&... args) ->
3032 typename std::result_of<decltype (&App::_parse_subcommand)(App, Args...)>::type {
3033 return app->_parse_subcommand(std::forward<Args>(args)...);
All errors derive from this one.
Definition: CL11.hpp:293
std::string to_lower(std::string str)
Return a lower case version of a string.
Definition: CL11.hpp:171
#define CLI11_ERROR_SIMPLE(name)
Definition: CL11.hpp:259
-h or –help on command line
Definition: CL11.hpp:383
Does not output a diagnostic in CLI11_PARSE, but allows to return from main() with a specific error c...
Definition: CL11.hpp:389
std::string & ltrim(std::string &str)
Trim whitespace from left of string.
Definition: CL11.hpp:95
bool lexical_cast(std::string input, T &output)
Signed integers / enums.
Definition: CL11.hpp:587
std::vector< std::string > split_up(std::string str)
Split a string '"one two" "three"' into 'one two', 'three'.
Definition: CL11.hpp:179
bool split_short(const std::string ¤t, std::string &name, std::string &rest)
Definition: CL11.hpp:672
Thrown when an excludes option is present.
Definition: CL11.hpp:464
Error(std::string name, std::string msg, int exit_code=static_cast< int >(ExitCodes::BaseClass))
Definition: CL11.hpp:302
#define CLI11_ERROR_DEF(parent, name)
Definition: CL11.hpp:248
std::string trim_copy(const std::string &str)
Make a copy of the string and then trim it.
Definition: CL11.hpp:130
size_t count(const std::string &str, const std::string &sub)
Definition: Strings.h:153
bool split_long(const std::string ¤t, std::string &name, std::string &value)
Definition: CL11.hpp:682
std::string reverse(std::string x)
Definition: Strings.h:185
constexpr const char * type_name()
This one should not be used, since vector types print the internal type.
Definition: CL11.hpp:553
std::string rjoin(const T &v, std::string delim=",")
Join a string in reverse order.
Definition: CL11.hpp:82
Thrown when an option is set to conflicting values (non-vector and multi args, for example) ...
Definition: CL11.hpp:316
Thrown when extra values are found in an INI file.
Definition: CL11.hpp:481
std::string str(BindingTree *t)
Definition: BindingTree.h:195
std::string get_name() const
Definition: CL11.hpp:300
std::vector< std::string > split_names(std::string current)
Definition: CL11.hpp:698
bool valid_later_char(T c)
Verify following characters of an option.
Definition: CL11.hpp:156
bool valid_name_string(const std::string &str)
Verify an option name.
Definition: CL11.hpp:161
typename std::enable_if< B, T >::type enable_if_t
Definition: CL11.hpp:527
std::string & rtrim(std::string &str)
Trim whitespace from right of string.
Definition: CL11.hpp:109
bool valid_first_char(T c)
Verify the first character of an option.
Definition: CL11.hpp:153
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.
Definition: CL11.hpp:711
Thrown when a requires option is missing.
Definition: CL11.hpp:457
SExpNode parse(std::vector< std::string > &tok)
Wrapper to parse to remove outer (...)
Definition: SExpression.h:172
Thrown when validation fails before parsing.
Definition: CL11.hpp:491
ExitCodes
Definition: CL11.hpp:264
Thrown when parsing an INI file and it is missing.
Definition: CL11.hpp:395
const auto empty
Definition: DSL.h:8
Error(std::string name, std::string msg, ExitCodes exit_code)
Definition: CL11.hpp:305
int get_exit_code() const
Definition: CL11.hpp:298
Construction errors (not in parsing)
Definition: CL11.hpp:311
Thrown when an option already exists.
Definition: CL11.hpp:355
Thrown when counting a non-existent option.
Definition: CL11.hpp:508
enabler
Simple empty scoped class.
Definition: CL11.hpp:540
This is a successful completion on parsing, supposed to exit.
Definition: CL11.hpp:377
std::string fix_newlines(std::string leader, std::string input)
Definition: CL11.hpp:228
Thrown on construction of a bad name.
Definition: CL11.hpp:341
void reset()
Definition: FleetStatistics.h:20
Anything that can error in Parse.
Definition: CL11.hpp:370
Thrown when the wrong number of arguments has been received.
Definition: CL11.hpp:438
Thrown when conversion call back fails, such as when an int fails to coerce to a string.
Definition: CL11.hpp:402
std::vector< std::string > split(const std::string &s, char delim)
Split a string by a delim.
Definition: CL11.hpp:53
std::string & trim(std::string &str)
Trim whitespace from string.
Definition: CL11.hpp:124
std::string join(const T &v, std::string delim=",")
Simple function to join a string.
Definition: CL11.hpp:70
Thrown when a required option is missing.
Definition: CL11.hpp:425
constexpr enabler dummy
An instance to use in EnableIf.
Definition: CL11.hpp:543
void format_help(std::stringstream &out, std::string name, std::string description, size_t wid)
Print a two part "help" string.
Definition: CL11.hpp:141
Thrown when validation of results fails.
Definition: CL11.hpp:418