15 explicit ParseError(
const char* msg) : std::runtime_error(msg) {}
16 explicit ParseError(
const std::string& msg) : std::runtime_error(msg) {}
30 virtual
bool matches(const std::
string& flag) const = 0;
31 virtual
void parse_item(const std::vector<std::
string>& arguments) = 0;
33 virtual std::
string printable(
int description_column,
int* chars_before_desc) const = 0;
38 void parse(
const std::string& name,
const std::vector<std::string>& arguments,
bool firstPass,
39 bool ignore_num_arguments =
false)
44 if(!ignore_num_arguments) {
47 std::ostringstream error;
49 error << R
"(Flag ")" << name << R"(" expected at least one argument)";
51 error << R
"(Flag ")" << name << R"(" expected )" << num_arguments() << " argument(s) and received "
72 std::istringstream str(flag_list);
77 if(temp.length() == 1) {
78 fFlags.push_back(
"-" + temp);
79 }
else if(temp.length() > 1) {
80 fFlags.push_back(
"--" + temp);
93 for(
const auto& flag :
fFlags) {
94 if(flag.length() > output.length()) {
101 bool matches(
const std::string& flag)
const override
104 if(flag.at(0) !=
'-' &&
fFlags.empty()) {
108 return std::any_of(
fFlags.begin(),
fFlags.end(), [&flag](
auto cfl) { return cfl == flag; });
133 std::string
printable(
int description_column,
int* chars_before_desc)
const override
135 std::ostringstream output;
139 bool has_singlechar_flag =
false;
140 for(
const auto& flag :
fFlags) {
141 if(flag.length() == 2) {
142 output << flag <<
" ";
143 has_singlechar_flag =
true;
146 for(
const auto& flag :
fFlags) {
147 if(flag.length() != 2) {
148 if(has_singlechar_flag) {
151 output << flag <<
" ";
152 if(has_singlechar_flag) {
162 auto chars = output.tellp();
164 if(chars_before_desc !=
nullptr) {
165 *chars_before_desc =
static_cast<int>(chars);
168 if(description_column != -1 && chars < description_column) {
169 for(
unsigned int i = 0; i < description_column - chars; i++) {
210 void parse_item(
const std::vector<std::string>& arguments)
override
212 std::istringstream str(arguments[0]);
234 fStored_default_value = value;
240 fNum_arguments_expected = 1;
244 void parse_item(
const std::vector<std::string>& arguments)
override
246 if(arguments.empty()) {
249 std::istringstream str(arguments[0]);
258 bool fStored_default_value{
false};
259 int fNum_arguments_expected{0};
265 ArgParseConfigT(std::string flag, std::vector<T>* output_location,
bool firstPass)
270 void parse_item(
const std::vector<std::string>& arguments)
override
272 for(
const auto& arg : arguments) {
273 std::istringstream str(arg);
280 int num_arguments()
const override {
return fNum_arguments_expected; }
290 int fNum_arguments_expected{-1};
333 void parse(
int argc,
char** argv,
bool firstPass)
341 bool double_dash_encountered =
false;
345 std::string arg = argv[iarg++];
347 if(arg.at(0) !=
'-' || double_dash_encountered) {
349 }
else if(arg.substr(0, 2) ==
"--") {
357 if(val->is_required() && !val->is_present()) {
358 std::ostringstream error;
359 error << R
"(Required argument ")" << val->flag_name() << R"(" is not present)";
367 std::ifstream infile(filename);
370 while(std::getline(infile, line)) {
371 size_t colon = line.find(
':');
372 bool has_colon = (colon != std::string::npos);
375 std::string remainder;
377 flag = line.substr(0, colon);
378 std::istringstream(flag) >> flag;
379 if(flag.length() == 1) {
380 flag.insert(0, 1,
'-');
382 flag.insert(0, 2,
'-');
384 remainder = line.substr(colon + 1, line.length());
390 std::vector<std::string> args;
391 std::istringstream str(remainder);
393 while(str >> tmparg) {
394 args.push_back(tmparg);
399 item.
parse(flag, args,
true,
true);
400 item.
parse(flag, args,
false,
true);
402 for(
auto& arg : args) {
404 item.
parse(arg, std::vector<std::string>{arg},
true);
405 item.
parse(arg, std::vector<std::string>{arg},
false);
411 template <
typename T>
419 template <
typename T>
422 return option(
"", output_location, firstPass);
430 for(
auto* item :
values) {
432 item->printable(-1, &length);
433 max_length = std::max(length, max_length);
436 for(
auto it =
values.begin(); it !=
values.end(); it++) {
438 out << item->
printable(max_length,
nullptr);
439 if(it !=
values.end() - 1) {
448 std::string arg = argv[iarg - 1];
449 std::vector<std::string> flag_args;
451 size_t equals_index = arg.find(
'=');
452 if(equals_index == std::string::npos) {
457 flag = arg.substr(0, equals_index);
462 if(equals_index == std::string::npos) {
465 flag_args.push_back(arg.substr(equals_index + 1));
467 item.
parse(flag, flag_args, firstPass);
472 std::string arg = argv[iarg - 1];
473 std::string flag = arg.substr(0, 2);
477 for(
unsigned int ichar = 1; ichar < arg.length(); ichar++) {
478 std::string tmpflag =
"-" + arg.substr(ichar, 1);
479 std::vector<std::string> flag_args;
483 if(arg.length() == 2) {
486 item.
parse(flag, flag_args, firstPass);
489 std::vector<std::string> flag_args{arg.substr(2)};
490 item.
parse(flag, flag_args, firstPass);
497 std::string arg = argv[iarg - 1];
498 std::vector<std::string> flag_args{arg};
501 item.
parse(arg, flag_args, firstPass);
505 static std::vector<std::string>
argument_list(
int argc,
char** argv,
int& iarg,
int max_args)
507 std::vector<std::string> output;
508 bool read_extra =
false;
509 while(iarg < argc && (max_args == -1 || output.size() <
static_cast<size_t>(max_args))) {
510 std::string next_arg = argv[iarg++];
511 if(!next_arg.empty() && next_arg.at(0) ==
'-') {
515 output.push_back(next_arg);
526 if(val->matches(flag)) {
531 std::ostringstream error;
532 if(flag.at(0) ==
'-') {
533 error << R
"(Unknown option: ")" << flag << R"(")";
535 error << R
"(Was passed ")" << flag << R"(" as a non-option argument, when no non-option arguments are allowed)";
std::ostream & operator<<(std::ostream &out, const ArgParser &val)
virtual ArgParseConfig & default_value(T value)=0
std::string fDescription
A description for display on the terminal.
std::string fColour
Colour string to be use for display.
ArgParseConfig(const ArgParseConfig &)=default
ArgParseConfig(ArgParseConfig &&) noexcept=default
bool matches(const std::string &flag) const override
std::string flag_name() const override
virtual ArgParseConfig & description(const std::string &description)
virtual ArgParseConfig & required()
std::string printable(int description_column, int *chars_before_desc) const override
std::vector< std::string > fRawFlags
The flags without the leading dashes.
bool fRequired
Whether the flag must be supplied.
virtual ArgParseConfig & colour(const std::string &colour)
std::vector< std::string > fFlags
The literal flag that is searched for, including leading dashes.
ArgParseConfig(const std::string &flag_list, bool firstPass)
bool is_required() const override
int num_arguments() const override
void parse_item(const std::vector< std::string > &arguments) override
ArgParseConfig< bool > & takes_argument()
ArgParseConfig< bool > & default_value(bool value) override
ArgParseConfigT(const std::string &flag, bool *output_location, bool firstPass)
void parse_item(const std::vector< std::string > &arguments) override
ArgParseConfigT(std::string flag, T *output_location, bool firstPass)
int num_arguments() const override
ArgParseConfig< T > & default_value(T value) override
ArgParseItem(const ArgParseItem &)=default
ArgParseItem(bool firstPass)
virtual bool matches(const std::string &flag) const =0
virtual std::string flag_name() const =0
virtual void parse_item(const std::vector< std::string > &arguments)=0
ArgParseItem(ArgParseItem &&) noexcept=default
void parse(const std::string &name, const std::vector< std::string > &arguments, bool firstPass, bool ignore_num_arguments=false)
virtual bool is_required() const =0
virtual std::string printable(int description_column, int *chars_before_desc) const =0
virtual int num_arguments() const =0
void print(std::ostream &out) const
static std::vector< std::string > argument_list(int argc, char **argv, int &iarg, int max_args)
Reads arguments into a list until finding one that begins with '-'.
void handle_long_flag(int argc, char **argv, int &iarg, bool firstPass)
std::vector< ArgParseItem * > values
void parse(int argc, char **argv, bool firstPass)
ArgParseConfigT< T > & option(const std::string flag, T *output_location, bool firstPass)
void parse_file(std::string &filename)
void handle_default_option(int, char **argv, int &iarg, bool firstPass)
ArgParseItem & get_item(const std::string &flag)
ArgParser(ArgParser &&) noexcept=default
ArgParseConfigT< std::vector< T > > & default_option(std::vector< T > *output_location, bool firstPass)
void handle_short_flag(int argc, char **argv, int &iarg, bool firstPass)
ArgParser(const ArgParser &)=default
ParseError(const std::string &msg)
ParseError(const char *msg)