31 struct CmdlineParser::Argument {
46 bool repeated_ =
false;
51 : key_(key), longkey_(longkey), keytype_(keytype), desc_(desc),
52 required_(required) { }
55 virtual ~Argument() =
default;
58 virtual const char * type_name()
const = 0;
61 virtual bool process(
int& argc,
const char*
const*& argv) = 0;
64 virtual void print_value(std::ostream& os)
const = 0;
69 if (!keytype_.empty()) {
79 s +=
'-', s += key_, s +=
", ";
84 s +=
"--", s += longkey_;
85 if (!keytype_.empty()) {
93 struct CmdlineParser::ArgumentBool final :
public Argument {
100 bool required,
bool& dest)
101 : Argument(key, longkey, keytype, desc, required), dest_(dest) { }
103 const char * type_name() const final {
return "bool"; }
106 bool process(
int& argc,
const char*
const*& argv)
final {
112 void print_value(std::ostream& os)
const final {
113 os << (dest_ ?
"true" :
"false");
118 struct CmdlineParser::ArgumentInt final :
public Argument {
124 bool required,
int& dest)
125 : Argument(key, longkey, keytype, desc, required), dest_(dest) { }
127 const char * type_name() const final {
return "integer"; }
130 bool process(
int& argc,
const char*
const*& argv)
final {
134 long x = strtol(argv[0], &endptr, 10);
135 if (endptr !=
nullptr && *endptr == 0 &&
138 dest_ =
static_cast<int>(
x);
146 void print_value(std::ostream& os)
const final { os << dest_; }
150 struct CmdlineParser::ArgumentUnsigned final :
public Argument {
154 ArgumentUnsigned(
char key,
const std::string& longkey,
156 bool required,
unsigned int& dest)
157 : Argument(key, longkey, keytype, desc, required), dest_(dest) { }
159 const char * type_name() const final {
return "unsigned"; }
162 bool process(
int& argc,
const char*
const*& argv)
final {
166 unsigned long x = strtoul(argv[0], &endptr, 10);
167 if (endptr !=
nullptr && *endptr == 0 &&
170 dest_ =
static_cast<unsigned int>(
x);
178 void print_value(std::ostream& os)
const final { os << dest_; }
182 struct CmdlineParser::ArgumentSizeT final :
public Argument {
186 ArgumentSizeT(
char key,
const std::string& longkey,
188 bool required,
size_t& dest)
189 : Argument(key, longkey, keytype, desc, required), dest_(dest) { }
191 const char * type_name() const final {
return "size_t"; }
194 bool process(
int& argc,
const char*
const*& argv)
final {
198 unsigned long long x = strtoull(argv[0], &endptr, 10);
199 if (endptr !=
nullptr && *endptr == 0 &&
210 void print_value(std::ostream& os)
const final { os << dest_; }
214 struct CmdlineParser::ArgumentFloat final :
public Argument {
218 ArgumentFloat(
char key,
const std::string& longkey,
220 bool required,
float& dest)
221 : Argument(key, longkey, keytype, desc, required), dest_(dest) { }
223 const char * type_name() const final {
return "float"; }
226 bool process(
int& argc,
const char*
const*& argv)
final {
230 dest_ = strtof(argv[0], &endptr);
231 if (endptr !=
nullptr && *endptr == 0) {
240 void print_value(std::ostream& os)
const final { os << dest_; }
244 struct CmdlineParser::ArgumentDouble final :
public Argument {
248 ArgumentDouble(
char key,
const std::string& longkey,
250 bool required,
double& dest)
251 : Argument(key, longkey, keytype, desc, required), dest_(dest) { }
253 const char * type_name() const final {
return "double"; }
256 bool process(
int& argc,
const char*
const*& argv)
final {
260 dest_ = strtod(argv[0], &endptr);
261 if (endptr !=
nullptr && *endptr == 0) {
270 void print_value(std::ostream& os)
const final { os << dest_; }
275 struct CmdlineParser::ArgumentBytes32 final :
public Argument {
279 ArgumentBytes32(
char key,
const std::string& longkey,
281 bool required, uint32_t& dest)
282 : Argument(key, longkey, keytype, desc, required), dest_(dest) { }
284 const char * type_name() const final {
return "bytes"; }
287 bool process(
int& argc,
const char*
const*& argv)
final {
292 static_cast<uint64_t>(
293 dest_ = static_cast<uint32_t>(dest)) == dest) {
302 void print_value(std::ostream& os)
const final { os << dest_; }
307 struct CmdlineParser::ArgumentBytes64 final :
public Argument {
311 ArgumentBytes64(
char key,
const std::string& longkey,
313 bool required, uint64_t& dest)
314 : Argument(key, longkey, keytype, desc, required), dest_(dest) { }
316 const char * type_name() const final {
return "bytes"; }
319 bool process(
int& argc,
const char*
const*& argv)
final {
331 void print_value(std::ostream& os)
const final { os << dest_; }
335 struct CmdlineParser::ArgumentString final :
public Argument {
339 ArgumentString(
char key,
const std::string& longkey,
342 : Argument(key, longkey, keytype, desc, required), dest_(dest) { }
344 const char * type_name() const final {
return "string"; }
347 bool process(
int& argc,
const char*
const*& argv)
final {
355 void print_value(std::ostream& os)
const final {
356 os <<
'"' << dest_ <<
'"';
361 struct CmdlineParser::ArgumentStringlist final :
public Argument {
362 std::vector<std::string>& dest_;
365 ArgumentStringlist(
char key,
const std::string& longkey,
367 bool required, std::vector<std::string>& dest)
368 : Argument(key, longkey, keytype, desc, required), dest_(dest) {
372 const char * type_name() const final {
return "string list"; }
375 bool process(
int& argc,
const char*
const*& argv)
final {
378 dest_.emplace_back(argv[0]);
383 void print_value(std::ostream& os)
const final {
385 for (
size_t i = 0; i < dest_.size(); ++i) {
388 os <<
'"' << dest_[i] <<
'"';
410 size_t wraplen,
size_t indent_first,
size_t indent_rest,
size_t current,
411 size_t indent_newline) {
413 std::string::size_type t = 0;
414 size_t indent = indent_first;
416 while (t != text.size()) {
417 std::string::size_type to = t, lspace = t;
420 while (to != text.size() && to + current + indent < t + wraplen &&
428 if (to != text.size() && text[to] !=
'\n' && lspace != t)
432 os <<
std::string(indent,
' ') << text.substr(t, to - t) << std::endl;
435 indent = indent_rest;
438 if (to != text.size() && text[to] ==
'\n') {
439 indent = indent_newline;
479 new ArgumentBool(key, longkey, keytype, desc,
false, dest));
486 return add_bool(key, longkey, keytype, dest, desc);
493 new ArgumentInt(key, longkey, keytype, desc,
false, dest));
501 new ArgumentUnsigned(key, longkey, keytype, desc,
false, dest));
515 new ArgumentSizeT(key, longkey, keytype, desc,
false, dest));
523 new ArgumentFloat(key, longkey, keytype, desc,
false, dest));
531 new ArgumentDouble(key, longkey, keytype, desc,
false, dest));
539 new ArgumentBytes32(key, longkey, keytype, desc,
false, dest));
547 new ArgumentBytes64(key, longkey, keytype, desc,
false, dest));
555 new ArgumentString(key, longkey, keytype, desc,
false, dest));
561 const std::string& keytype, std::vector<std::string>& dest,
565 new ArgumentStringlist(key, longkey, keytype, desc,
false, dest));
573 return add_bool(key, longkey,
"", dest, desc);
578 return add_bool(key, longkey, dest, desc);
583 return add_int(key, longkey,
"", dest, desc);
598 return add_size_t(key, longkey,
"", dest, desc);
603 return add_float(key, longkey,
"", dest, desc);
608 return add_double(key, longkey,
"", dest, desc);
613 return add_bytes(key, longkey,
"", dest, desc);
618 return add_bytes(key, longkey,
"", dest, desc);
623 return add_string(key, longkey,
"", dest, desc);
628 std::vector<std::string>& dest,
const std::string& desc) {
636 return add_bool(0, longkey,
"", dest, desc);
641 return add_bool(0, longkey, dest, desc);
646 return add_int(0, longkey,
"", dest, desc);
661 return add_size_t(0, longkey,
"", dest, desc);
666 return add_float(0, longkey,
"", dest, desc);
671 return add_double(0, longkey,
"", dest, desc);
676 return add_bytes(0, longkey,
"", dest, desc);
681 return add_bytes(0, longkey,
"", dest, desc);
686 return add_string(0, longkey,
"", dest, desc);
691 std::vector<std::string>& dest,
const std::string& desc) {
699 param_list_.emplace_back(
new ArgumentInt(0, name,
"", desc,
true, dest));
706 new ArgumentUnsigned(0, name,
"", desc,
true, dest));
717 param_list_.emplace_back(
new ArgumentSizeT(0, name,
"", desc,
true, dest));
723 param_list_.emplace_back(
new ArgumentFloat(0, name,
"", desc,
true, dest));
729 param_list_.emplace_back(
new ArgumentDouble(0, name,
"", desc,
true, dest));
736 new ArgumentBytes32(0, name,
"", desc,
true, dest));
743 new ArgumentBytes64(0, name,
"", desc,
true, dest));
749 param_list_.emplace_back(
new ArgumentString(0, name,
"", desc,
true, dest));
754 const std::string& name, std::vector<std::string>& dest,
757 new ArgumentStringlist(0, name,
"", desc,
true, dest));
765 param_list_.emplace_back(
new ArgumentInt(0, name,
"", desc,
false, dest));
772 new ArgumentUnsigned(0, name,
"", desc,
false, dest));
783 param_list_.emplace_back(
new ArgumentSizeT(0, name,
"", desc,
false, dest));
789 param_list_.emplace_back(
new ArgumentFloat(0, name,
"", desc,
false, dest));
796 new ArgumentDouble(0, name,
"", desc,
false, dest));
803 new ArgumentBytes32(0, name,
"", desc,
false, dest));
810 new ArgumentBytes64(0, name,
"", desc,
false, dest));
817 new ArgumentString(0, name,
"", desc,
false, dest));
822 const std::string& name, std::vector<std::string>& dest,
825 new ArgumentStringlist(0, name,
"", desc,
false, dest));
833 [](
const Argument* a, Argument* b) {
834 return a->longkey_ < b->longkey_;
840 std::ios::fmtflags flags(os.flags());
845 for (ArgumentList::const_iterator it =
param_list_.begin();
847 const Argument* arg = *it;
849 os << (arg->required_ ?
" <" :
" [") << arg->longkey_
850 << (arg->repeated_ ?
" ..." :
"") << (arg->required_ ?
'>' :
']');
860 os <<
"Author: " <<
author_ << std::endl;
867 os <<
"Parameters:" << std::endl;
869 for (ArgumentList::const_iterator it =
param_list_.begin();
871 const Argument* arg = *it;
874 << std::left << arg->param_text();
881 os <<
"Options:" << std::endl;
883 for (ArgumentList::const_iterator it =
option_list_.begin();
885 const Argument* arg = *it;
888 << std::left << arg->option_text();
902 int argc,
const char*
const* argv,
const Argument* arg, std::ostream& os) {
903 os <<
"Error: argument ";
905 os <<
'"' << argv[0] <<
'"';
907 os <<
" for " << arg->type_name() <<
" option " << arg->option_text()
908 << (argc == 0 ?
" is missing!" :
" is invalid!") << std::endl
915 int argc,
const char*
const* argv,
const Argument* arg, std::ostream& os) {
916 os <<
"Error: argument ";
918 os <<
'"' << argv[0] <<
'"';
920 os <<
" for " << arg->type_name() <<
" parameter " << arg->param_text()
921 << (argc == 0 ?
" is missing!" :
" is invalid!") << std::endl
928 int argc,
const char*
const* argv, std::ostream& os) {
933 for (
int i = 0; i < argc; ++i) {
934 if (strcmp(argv[i],
"-h") == 0 || strcmp(argv[i],
"--help") == 0) {
942 bool end_optlist =
false;
945 const char* arg = argv[0];
947 if (arg[0] ==
'-' && !end_optlist) {
958 if ((arg + 2) == (*oi)->longkey_) {
959 if (!(*oi)->process(argc, argv)) {
964 os <<
"Option " << (*oi)->option_text()
966 (*oi)->print_value(os);
967 os <<
'.' << std::endl;
973 os <<
"Error: unknown option \"" << arg <<
"\"." 974 << std::endl << std::endl;
983 os <<
"Invalid option \"" << arg <<
"\"." << std::endl;
986 size_t offset = 1, arg_length = strlen(arg);
990 while (offset < arg_length && argc == old_argc) {
993 if (arg[offset] == (*oi)->key_) {
995 if (!(*oi)->process(argc, argv)) {
1001 << (*oi)->option_text()
1003 (*oi)->print_value(os);
1004 os <<
'.' << std::endl;
1010 os <<
"Error: unknown option \"";
1011 if (arg_length > 2) {
1013 os <<
"-" << arg[offset]
1014 <<
"\" at position " << offset
1015 <<
" in option sequence \"";
1017 os << arg <<
"\"." << std::endl << std::endl;
1027 if (!(*argi)->process(argc, argv)) {
1032 os <<
"Parameter " << (*argi)->param_text() <<
" set to ";
1033 (*argi)->print_value(os);
1034 os <<
'.' << std::endl;
1036 (*argi)->found_ =
true;
1037 if (!(*argi)->repeated_)
1041 os <<
"Error: unexpected extra argument " 1042 <<
"\"" << argv[0] <<
"\"." << std::endl << std::endl;
1052 for (ArgumentList::const_iterator it =
param_list_.begin();
1054 if ((*it)->required_ && !(*it)->found_) {
1055 os <<
"Error: argument for parameter " << (*it)->longkey_
1056 <<
" is required!" << std::endl;
1070 return process(argc, argv, std::cout);
1074 std::ios::fmtflags flags(os.flags());
1079 os <<
"Parameters:" << std::endl;
1081 for (ArgumentList::const_iterator it =
param_list_.begin();
1083 const Argument* arg = *it;
1085 os <<
" " << std::setw(static_cast<int>(maxlong))
1086 << std::left << arg->param_text();
1091 arg->print_value(os);
1098 os <<
"Options:" << std::endl;
1100 for (ArgumentList::const_iterator it =
option_list_.begin();
1102 const Argument* arg = *it;
1104 os <<
" " << std::setw(static_cast<int>(maxlong))
1105 << std::left << arg->option_text();
1110 arg->print_value(os);
void add_opt_param_bytes(const std::string &name, uint32_t &dest, const std::string &desc)
void add_unsigned(char key, const std::string &longkey, unsigned int &dest, const std::string &desc)
static void output_wrap(std::ostream &os, const std::string &text, size_t wraplen, size_t indent_first=0, size_t indent_rest=0, size_t current=0, size_t indent_newline=0)
void add_uint(char key, const std::string &longkey, unsigned int &dest, const std::string &desc)
static uint_pair max()
return an uint_pair instance containing the largest value possible
CmdlineParser & sort()
sort options by key (but not the positional parameters)
void add_param_double(const std::string &name, double &dest, const std::string &desc)
add double parameter [name] with description and store to dest
ArgumentList option_list_
list of options available
void add_param_int(const std::string &name, int &dest, const std::string &desc)
add signed integer parameter [name] with description and store to dest
void set_description(const std::string &description)
Set description of program, text will be wrapped.
~CmdlineParser()
Delete all added arguments.
void add_opt_param_double(const std::string &name, double &dest, const std::string &desc)
add optional double parameter [name] with description and store to dest
void print_option_error(int argc, const char *const *argv, const Argument *arg, std::ostream &os)
print error about option.
void add_opt_param_string(const std::string &name, std::string &dest, const std::string &desc)
add optional string parameter [name] with description and store to dest
bool verbose_process_
verbose processing of arguments
void add_opt_param_uint(const std::string &name, unsigned int &dest, const std::string &desc)
void calc_option_max(const Argument *arg)
update maximum formatting width for new option
void add_param_size_t(const std::string &name, size_t &dest, const std::string &desc)
add size_t parameter [name] with description and store to dest
void add_size_t(char key, const std::string &longkey, size_t &dest, const std::string &desc)
add size_t option -key, –longkey with description and store to dest
void calc_param_max(const Argument *arg)
update maximum formatting width for new parameter
void add_opt_param_unsigned(const std::string &name, unsigned int &dest, const std::string &desc)
void print_result()
print nicely formatted result of processing to std::cout
ArgumentList param_list_
list of parameters, both required and optional
void add_param_bytes(const std::string &name, uint32_t &dest, const std::string &desc)
CmdlineParser()
Constructor.
void add_param_uint(const std::string &name, unsigned int &dest, const std::string &desc)
void add_bytes(char key, const std::string &longkey, uint32_t &dest, const std::string &desc)
void add_opt_param_float(const std::string &name, float &dest, const std::string &desc)
add optional float parameter [name] with description and store to dest
static constexpr int max_type_name_
maximum length of a type_name() result
void add_float(char key, const std::string &longkey, float &dest, const std::string &desc)
add float option -key, –longkey with description and store to dest
const char * program_name_
argv[0] for usage.
bool parse_si_iec_units(const char *str, uint64_t *out_size, char default_unit)
Parse a string like "343KB" or "44 GiB" into the corresponding size in bytes.
std::basic_string< char, std::char_traits< char >, Allocator< char > > string
string with Manager tracking
std::string description_
user set description of program, will be wrapped
Command line parser which automatically fills variables and prints nice usage messages.
size_t param_max_width_
formatting width for parameters, 'param <#>'
void add_param_string(const std::string &name, std::string &dest, const std::string &desc)
add string parameter [name] with description and store to dest
void add_string(char key, const std::string &longkey, std::string &dest, const std::string &desc)
add string option -key, –longkey and store to dest
std::string author_
user set author of program, will be wrapped
unsigned int line_wrap_
set line wrap length
void add_double(char key, const std::string &longkey, double &dest, const std::string &desc)
add double option -key, –longkey with description and store to dest
void add_param_float(const std::string &name, float &dest, const std::string &desc)
add float parameter [name] with description and store to dest
void add_param_stringlist(const std::string &name, std::vector< std::string > &dest, const std::string &desc)
void add_opt_param_int(const std::string &name, int &dest, const std::string &desc)
void set_verbose_process(bool verbose_process)
Set verbose processing of command line arguments.
void add_bool(char key, const std::string &longkey, bool &dest, const std::string &desc)
size_t option_max_width_
formatting width for options, '-s, –switch <#>'
void add_stringlist(char key, const std::string &longkey, std::vector< std::string > &dest, const std::string &desc)
add string list option -key, –longkey and store to dest
void add_opt_param_stringlist(const std::string &name, std::vector< std::string > &dest, const std::string &desc)
void add_opt_param_size_t(const std::string &name, size_t &dest, const std::string &desc)
add optional size_t parameter [name] with description and store to dest
void set_author(const std::string &author)
Set author of program, will be wrapped.
void add_flag(char key, const std::string &longkey, bool &dest, const std::string &desc)
void add_int(char key, const std::string &longkey, int &dest, const std::string &desc)
void add_param_unsigned(const std::string &name, unsigned int &dest, const std::string &desc)
add unsigned integer parameter [name] with description and store to dest
bool process(int argc, const char *const *argv, std::ostream &os)
void print_param_error(int argc, const char *const *argv, const Argument *arg, std::ostream &os)
print error about parameter.