88 std::map<std::string,std::string>
vals;
94 std::map<std::string,bool>
flags;
108 add<bool>(
'h',
"help",
"show this help message");
129 std::vector<std::string> choices = {})
134 o.desc = std::move(d);
136 o.choices = std::move(choices);
138 if constexpr(std::is_same_v<T,bool>) {
140 o.type_name =
"flag";
145 if constexpr(std::is_same_v<T,std::string>) o.default_str = def;
146 else o.default_str = std::to_string(def);
147 if (!o.default_str.empty())
148 vals[o.l] = o.default_str;
150 if (!o.choices.empty()) o.type_name =
"enum";
151 else if constexpr(std::is_integral_v<T>) o.type_name =
"int";
152 else if constexpr(std::is_floating_point_v<T>) o.type_name =
"float";
153 else o.type_name =
"string";
155 opts.push_back(std::move(o));
170 std::vector<std::string> choices = {})
175 o.desc = std::move(d);
178 o.choices = std::move(choices);
180 if (!o.choices.empty()) o.type_name =
"enum";
181 else if constexpr(std::is_integral_v<T>) o.type_name =
"int";
182 else if constexpr(std::is_floating_point_v<T>) o.type_name =
"float";
183 else o.type_name =
"string";
197 std::vector<std::string> raw_pos;
199 for (
int i = 1; i < argc; ++i) {
200 std::string a = argv[i];
203 if (a.rfind(
"--",0) == 0) {
204 auto eq = a.find(
'=');
205 std::string name = a.substr(2, (eq==std::string::npos? a.size()-2: eq-2));
207 if (eq != std::string::npos) val = a.substr(eq+1);
209 auto it = std::find_if(
opts.begin(),
opts.end(),
210 [&](
auto &o){ return o.l == name; });
211 if (it ==
opts.end()) {
212 errs.push_back(
"unknown option --" + name);
215 if (!it->takes_val) {
218 if (eq == std::string::npos) {
219 if (i+1 < argc) val = argv[++i];
221 errs.push_back(
"--" + name +
" requires a value");
225 if (!store(*it, name, val))
return false;
230 else if (a.size() > 1 && a[0]==
'-' && a[1] !=
'-') {
232 for (
size_t pos = 1; pos < a.size(); ) {
234 auto it = std::find_if(
opts.begin(),
opts.end(),
235 [&](
auto &o){ return o.s == s; });
236 if (it ==
opts.end()) {
237 errs.push_back(std::string(
"unknown option -") + s);
240 if (!it->takes_val) {
246 if (pos < a.size()) {
251 if (i+1 < argc) val = argv[++i];
253 errs.push_back(std::string(
"-") + s +
" requires a value");
257 if (!store(*it, it->l, val))
return false;
264 raw_pos.push_back(a);
272 for (
auto &o :
opts) {
273 if (o.takes_val && o.required && !
vals.count(o.l)) {
274 errs.push_back(
"missing required --" + o.l);
280 errs.push_back(
"missing positional <" +
positionals[raw_pos.size()].l +
">");
284 errs.push_back(
"unexpected argument '" + raw_pos[
positionals.size()] +
"'");
305 T
get(
const std::string &name)
const {
306 if constexpr(std::is_same_v<T,bool>) {
307 auto f =
flags.find(name);
308 return (f !=
flags.end()) && f->second;
310 auto v =
vals.find(name);
312 throw std::runtime_error(
"no value for " + name);
313 const auto &s = v->second;
314 if constexpr(std::is_same_v<T,std::string>) {
317 else if constexpr(std::is_integral_v<T>) {
318 if constexpr(std::is_signed_v<T>)
return static_cast<T
>(std::stoll(s));
319 else return static_cast<T
>(std::stoull(s));
321 else if constexpr(std::is_floating_point_v<T>) {
322 return static_cast<T
>(std::stod(s));
324 else static_assert(!
sizeof(T),
"unsupported get<T>");
347 return errs.empty() ?
"" : std::string(
"error: ") +
errs[0];
360 throw std::out_of_range(
"no positional at index " + std::to_string(idx));
371 os <<
"Usage: " <<
prog <<
" [options]";
373 os <<
" <" << p.l <<
">";
374 os <<
"\n\nOptions:\n";
378 for (
auto &o :
opts) {
379 std::ostringstream t;
381 << (o.s ?
"-" + std::string(1,o.s) +
", " :
" ")
383 << (o.takes_val ?
"<"+o.type_name+
">" :
"");
384 W = std::max(W, t.str().size());
388 for (
auto &o :
opts) {
389 std::ostringstream nm;
391 << (o.s?
"-" + std::string(1,o.s)+
", " :
" ")
393 << (o.takes_val?
"<"+o.type_name+
">" :
"");
395 << std::string(W - nm.str().size() + 2,
' ')
397 if (o.takes_val && o.required) os <<
" (required)";
398 if (!o.choices.empty()) {
400 for (
size_t i=0; i<o.choices.size(); ++i) {
402 << (i+1<o.choices.size()?
", " :
"");
406 if (!o.default_str.empty() && !o.required)
407 os <<
" (default: " << o.default_str <<
")";
413 os <<
"\nPositional arguments:\n";
415 std::ostringstream nm;
416 nm <<
" " << p.l <<
"<" << p.type_name <<
">";
418 << std::string(W + 2 - nm.str().size(),
' ')
419 << p.desc <<
" (required)\n";
426 bool store(
const Opt &o,
const std::string &key,
const std::string &val) {
427 if (o.type_name ==
"int") {
428 try { std::stoll(val); }
430 errs.push_back(
"invalid integer for --" + key +
": '" + val +
"'");
434 else if (o.type_name ==
"float") {
435 try { std::stod(val); }
437 errs.push_back(
"invalid float for --" + key +
": '" + val +
"'");
441 else if (o.type_name ==
"enum") {
442 if (std::find(o.choices.begin(), o.choices.end(), val) == o.choices.end()) {
443 errs.push_back(
"invalid value for --" + key +
": '" + val +
"'");
An option (named or positional).
Definition simple_arg.hpp:23
bool required
Whether the option is required (true) or optional (false).
Definition simple_arg.hpp:58
std::string default_str
Default value as string (empty if none).
Definition simple_arg.hpp:43
std::string desc
Description of the option.
Definition simple_arg.hpp:38
bool takes_val
Whether the option takes a value (true) or is a flag (false).
Definition simple_arg.hpp:53
std::string type_name
Type name (e.g. "int", "float", "string", "enum", "flag").
Definition simple_arg.hpp:48
char s
Short name (e.g. 'h' for -h).
Definition simple_arg.hpp:28
std::string l
Long name (e.g. "help" for –help).
Definition simple_arg.hpp:33
std::vector< std::string > choices
Allowed choices (for enum types).
Definition simple_arg.hpp:63
void printHelp(std::ostream &os=std::cout) const
Print the help message.
Definition simple_arg.hpp:370
std::map< std::string, bool > flags
The parsed flags.
Definition simple_arg.hpp:94
std::vector< Opt > opts
The list of named options.
Definition simple_arg.hpp:76
std::string errorMsg() const
Get the error message.
Definition simple_arg.hpp:346
void add(char s, std::string l, std::string d, bool req=false, T def=T{}, std::vector< std::string > choices={})
Add a named argument.
Definition simple_arg.hpp:124
bool parse(int argc, char **argv)
Parse the command-line arguments.
Definition simple_arg.hpp:196
SimpleArg(std::string p)
Construct a new Simple Arg object.
Definition simple_arg.hpp:107
void addPositional(std::string l, std::string d, std::vector< std::string > choices={})
Add a positional argument.
Definition simple_arg.hpp:168
bool errors() const
Check if there were any errors during parsing.
Definition simple_arg.hpp:339
std::string prog
The name of the program (usually argv[0]).
Definition simple_arg.hpp:70
bool help() const
Check if help was requested.
Definition simple_arg.hpp:332
std::vector< Opt > positionals
The list of positional options.
Definition simple_arg.hpp:82
T getPositional(size_t idx) const
Get the Positional object.
Definition simple_arg.hpp:358
T get(const std::string &name) const
Get the value of a named argument.
Definition simple_arg.hpp:305
std::map< std::string, std::string > vals
The parsed values.
Definition simple_arg.hpp:88
std::vector< std::string > errs
The list of errors encountered during parsing.
Definition simple_arg.hpp:100