31 #ifndef ARGAGG_ARGAGG_ARGAGG_HPP 
   32 #define ARGAGG_ARGAGG_ARGAGG_HPP 
   37 #endif // #ifdef __unix__ 
   49 #include <unordered_map> 
  165   template <
typename T>
 
  196   template <
typename T>
 
  208   template <
typename T>
 
  209   T 
as(
const T& t) 
const;
 
  223   template <
typename T>
 
  274   template <
typename T>
 
  285   template <
typename T>
 
  286   T 
as(
const T& t) 
const;
 
  300   template <
typename T>
 
  371   template <
typename T>
 
  378   template <
typename T>
 
  493     const char flag) 
const;
 
  501     const char flag) 
const;
 
  652 template <
typename T>
 
  656     return convert::arg<T>(this->
arg);
 
  663 template <
typename T>
 
  668       return convert::arg<T>(this->
arg);
 
  683 template <
typename T>
 
  684 option_result::operator T ()
 const 
  686   return this->as<T>();
 
  691 option_result::operator bool ()
 const 
  693   return this->
arg != 
nullptr;
 
  700   return this->
all.size();
 
  707   return this->
all[index];
 
  714   return this->
all[index];
 
  718 template <
typename T>
 
  721   if (this->
all.size() == 0) {
 
  724   return this->
all.back().as<T>();
 
  728 template <
typename T>
 
  731   if (this->
all.size() == 0) {
 
  734   return this->
all.back().as<T>(t);
 
  738 template <
typename T>
 
  739 option_results::operator T ()
 const 
  741   return this->as<T>();
 
  746 option_results::operator bool ()
 const 
  748   return this->all.size() > 0;
 
  755   const auto it = this->
options.find(name);
 
  756   return ( it != this->
options.end()) && it->second.all.size() > 0;
 
  785   return this->
pos[index];
 
  789 template <
typename T>
 
  792   return convert::arg<T>(this->
pos[i]);
 
  796 template <
typename T>
 
  802     [](
const char* 
arg) {
 
  803       return convert::arg<T>(
arg);
 
  842   const char* name = s + 1;
 
  845   bool is_long = 
false;
 
  876     bool encountered_equal = 
false;
 
  877     return std::all_of(name, name + len, [&](
const char& c) {
 
  878         if (encountered_equal) {
 
  882             encountered_equal = 
true;
 
  922   const char* name = s + 1;
 
  925   bool is_long = 
false;
 
  947   if (!is_long && len > 1) {
 
  953   return std::all_of(name + 1, name + len, [&](
const char& c) {
 
  969   const char flag)
 const 
  977   const char flag)
 const 
  987   const auto existing_long_flag = this->
long_map.find(flag);
 
  988   return existing_long_flag != 
long_map.end();
 
  996   const auto existing_long_flag = this->
long_map.find(flag);
 
  997   if (existing_long_flag == 
long_map.end()) {
 
 1000   return existing_long_flag->second;
 
 1011   for (
auto& defn : definitions) {
 
 1013     if (defn.flags.size() == 0) {
 
 1015       msg << 
"option \"" << defn.name << 
"\" has no flag definitions";
 
 1019     for (
auto& flag : defn.flags) {
 
 1023         msg << 
"flag \"" << flag << 
"\" specified for option \"" << defn.name
 
 1029         const int short_flag_letter = flag[1];
 
 1030         const auto existing_short_flag = map.short_map[short_flag_letter];
 
 1031         bool short_flag_already_exists = (existing_short_flag != 
nullptr);
 
 1032         if (short_flag_already_exists) {
 
 1034           msg << 
"duplicate short flag \"" << flag
 
 1035               << 
"\" found, specified by both option  \"" << defn.name
 
 1036               << 
"\" and option \"" << existing_short_flag->name;
 
 1039         map.short_map[short_flag_letter] = &defn;
 
 1044       if (map.known_long_flag(flag)) {
 
 1045         const auto existing_long_flag = map.get_definition_for_long_flag(flag);
 
 1047         msg << 
"duplicate long flag \"" << flag
 
 1048             << 
"\" found, specified by both option  \"" << defn.name
 
 1049             << 
"\" and option \"" << existing_long_flag->name;
 
 1087     results.options.insert(
 
 1093   bool ignore_flags = 
false;
 
 1096   const char* last_flag_expecting_args = 
nullptr;
 
 1098   unsigned int num_option_args_to_consume = 0;
 
 1104   const char** arg_i = argv + 1;
 
 1105   const char** arg_end = argv + argc;
 
 1107   while (arg_i != arg_end) {
 
 1108     auto arg_i_cstr = *arg_i;
 
 1114     bool treat_as_positional_argument = (
 
 1116         || num_option_args_to_consume > 0
 
 1119     if (treat_as_positional_argument) {
 
 1125       if (num_option_args_to_consume > 0) {
 
 1126         last_option_expecting_args->
arg = arg_i_cstr;
 
 1127         --num_option_args_to_consume;
 
 1135       if (
std::strncmp(arg_i_cstr, 
"--", 2) == 0 && arg_i_len == 2) {
 
 1136         ignore_flags = 
true;
 
 1143       results.pos.push_back(arg_i_cstr);
 
 1149     last_flag_expecting_args = 
nullptr;
 
 1150     last_option_expecting_args = 
nullptr;
 
 1151     num_option_args_to_consume = 0;
 
 1157     bool is_long_flag = (arg_i_cstr[1] == 
'-');
 
 1168       auto long_flag_arg = 
std::strchr(arg_i_cstr, 
'=');
 
 1170       if (long_flag_arg != 
nullptr) {
 
 1171         flag_len = long_flag_arg - arg_i_cstr;
 
 1177         msg << 
"found unexpected flag: " << long_flag_str;
 
 1183       if (long_flag_arg != 
nullptr && defn->num_args == 0) {
 
 1185         msg << 
"found argument for option not expecting an argument: " 
 1193       auto& opt_results = results.options[defn->name];
 
 1195       opt_results.all.push_back(
std::move(opt_result));
 
 1197       if (defn->requires_arguments()) {
 
 1198         bool there_is_an_equal_delimited_arg = (long_flag_arg != 
nullptr);
 
 1199         if (there_is_an_equal_delimited_arg) {
 
 1202           opt_results.all.back().
arg = long_flag_arg + 1;
 
 1204           last_flag_expecting_args = arg_i_cstr;
 
 1205           last_option_expecting_args = &(opt_results.all.back());
 
 1206           num_option_args_to_consume = defn->num_args;
 
 1221     for (
std::size_t sf_idx = 1; sf_idx < arg_i_len; ++sf_idx) {
 
 1222       const auto short_flag = arg_i_cstr[sf_idx];
 
 1226         msg << 
"found non-alphanumeric character '" << arg_i_cstr[sf_idx]
 
 1227             << 
"' in flag group '" << arg_i_cstr << 
"'";
 
 1233         msg << 
"found unexpected flag '" << arg_i_cstr[sf_idx]
 
 1234             << 
"' in flag group '" << arg_i_cstr << 
"'";
 
 1239       auto& opt_results = results.options[defn->name];
 
 1244       opt_results.all.push_back(
std::move(opt_result));
 
 1246       if (defn->requires_arguments()) {
 
 1252         bool is_last_short_flag_in_group = (sf_idx == arg_i_len - 1);
 
 1253         if (is_last_short_flag_in_group) {
 
 1254           last_flag_expecting_args = arg_i_cstr;
 
 1255           last_option_expecting_args = &(opt_results.all.back());
 
 1256           num_option_args_to_consume = defn->num_args;
 
 1266         opt_results.all.back().
arg = arg_i_cstr + sf_idx + 1;
 
 1278   if (num_option_args_to_consume > 0) {
 
 1280     msg << 
"last option \"" << last_flag_expecting_args
 
 1281         << 
"\" expects an argument but the parser ran out of command line " 
 1282         << 
"arguments to parse";
 
 1293   return parse(argc, const_cast<const char**>(argv));
 
 1306   template <
typename T> 
inline 
 1309     char* endptr = 
nullptr;
 
 1311     T ret = 
static_cast<T
>(
std::strtol(arg, &endptr, 0));
 
 1312     if (endptr == arg) {
 
 1314       msg << 
"unable to convert argument to integer: \"" << arg << 
"\"";
 
 1317     if (errno == ERANGE) {
 
 1330   template <
typename T> 
inline 
 1333     char* endptr = 
nullptr;
 
 1336     if (endptr == arg) {
 
 1338       msg << 
"unable to convert argument to integer: \"" << arg << 
"\"";
 
 1341     if (errno == ERANGE) {
 
 1348 #define DEFINE_CONVERSION_FROM_LONG_(TYPE) \ 
 1349   template <> inline \ 
 1350   TYPE arg(const char* arg) \ 
 1352     return long_<TYPE>(arg); \ 
 1365 #undef DEFINE_CONVERSION_FROM_LONG_ 
 1368 #define DEFINE_CONVERSION_FROM_LONG_LONG_(TYPE) \ 
 1369   template <> inline \ 
 1370   TYPE arg(const char* arg) \ 
 1372     return long_long_<TYPE>(arg); \ 
 1378 #undef DEFINE_CONVERSION_FROM_LONG_LONG_ 
 1384     return argagg::convert::arg<int>(
arg) != 0;
 
 1391     char* endptr = 
nullptr;
 
 1394     if (endptr == arg) {
 
 1396       msg << 
"unable to convert argument to integer: \"" << arg << 
"\"";
 
 1399     if (errno == ERANGE) {
 
 1409     char* endptr = 
nullptr;
 
 1412     if (endptr == arg) {
 
 1414       msg << 
"unable to convert argument to integer: \"" << arg << 
"\"";
 
 1417     if (errno == ERANGE) {
 
 1442 : std::ostringstream(), output(output)
 
 1460   constexpr 
int read_end = 0;
 
 1461   constexpr 
int write_end = 1;
 
 1468   if (pipe(read_pipe) == -1) {
 
 1471   if (pipe(write_pipe) == -1) {
 
 1475   auto parent_pid = fork();
 
 1476   bool is_fmt_proc = (parent_pid == 0);
 
 1478     dup2(write_pipe[read_end], STDIN_FILENO);
 
 1479     dup2(read_pipe[write_end], STDOUT_FILENO);
 
 1480     close(write_pipe[read_end]);
 
 1481     close(write_pipe[write_end]);
 
 1482     close(read_pipe[read_end]);
 
 1483     close(read_pipe[write_end]);
 
 1484     const char* argv[] = {
"fmt", NULL};
 
 1485     execvp(const_cast<char*>(argv[0]), const_cast<char**>(argv));
 
 1488   close(write_pipe[read_end]);
 
 1489   close(read_pipe[write_end]);
 
 1490   auto fmt_write_fd = write_pipe[write_end];
 
 1491   auto write_result = write(fmt_write_fd, s.
c_str(), s.
length());
 
 1492   if (write_result != static_cast<ssize_t>(s.
length())) {
 
 1495   close(fmt_write_fd);
 
 1497   auto fmt_read_fd = read_pipe[read_end];
 
 1501     auto read_count = read(
 
 1502       fmt_read_fd, reinterpret_cast<void*>(buf), 
sizeof(buf));
 
 1503     if (read_count <= 0) {
 
 1506     os.
write(buf, static_cast<std::streamsize>(read_count));
 
 1514 #else // #ifdef __unix__ 
 1524 #endif // #ifdef __unix__ 
 1535     for (
auto& flag : definition.flags) {
 
 1537       if (flag != definition.flags.back()) {
 
 1542     os << 
"        " << definition.help << 
std::endl;
 
 1548 #endif // ARGAGG_ARGAGG_ARGAGG_HPP 
#define DEFINE_CONVERSION_FROM_LONG_LONG_(TYPE)
bool has_option(const std::string &name) const 
Used to check if an option was specified at all. 
option_result & operator[](std::size_t index)
Gets a single option parse result by index. 
Represents a single option parse result. 
bool cmd_line_arg_is_option_flag(const char *s)
Checks whether or not a command line argument should be processed as an option flag. This is very similar to is_valid_flag_definition() but must allow for short flag groups (e.g. "-abc") and equal-assigned long flag arguments (e.g. "--output=foo.txt"). 
const char * arg
Argument parsed for this single option. If no argument was parsed this will be set to nullptr...
bool known_short_flag(const char flag) const 
Returns true if the provided short flag exists in the map object. 
std::array< const definition *, 256 > short_map
Maps from a short flag (just a character) to a pointer to the original definition that the flag repre...
This exception is thrown when an option requires an argument but is not provided one. This can happen if another flag was found after the option or if we simply reach the end of the command line arguments. 
std::vector< option_result > all
All option parse results for this option. 
T as() const 
Converts the argument parsed for this single option instance into the given type using the type match...
T as() const 
Converts the argument parsed for the LAST option parse result for the parent definition to the provid...
option_results & operator[](const std::string &name)
Get the parser results for the given definition. If the definition never showed up then the exception...
bool flag_is_short(const char *s)
Tests whether or not a valid flag is short. Assumes the provided cstring is already a valid flag...
const char * program
Returns the name of the program from the original arguments list. This is always the first argument...
std::size_t count() const 
Gets the number of times the option shows up. 
std::string fmt_string(const std::string &s)
Processes the provided string using the fmt util and returns the resulting output as a string...
This exception is thrown when a long option is parsed and is given an argument using the "=" syntax...
bool requires_arguments() const 
Returns true if this option requires arguments. 
unsigned int num_args
Number of arguments this option requires. Must be 0 or 1. All other values have undefined behavior...
T arg(const char *arg)
Explicit instantiations of this function are used to convert arguments to types. 
~fmt_ostream()
Special destructor that will format the accumulated string using fmt (via the argagg::fmt_string() fu...
const definition * get_definition_for_short_flag(const char flag) const 
If the short flag exists in the map object then it is returned by this method. If it doesn't then nul...
A convenience output stream that will accumulate what is streamed to it and then, on destruction...
Contains two maps which aid in option parsing. The first map, short_map, maps from a short flag (just...
fmt_ostream(std::ostream &output)
Construct to output to the provided output stream when this object is destroyed. 
bool wants_no_arguments() const 
Returns true if this option does not want any arguments. 
std::size_t count() const 
Gets the number of positional arguments. 
const std::string name
Name of the option. Option parser results are keyed by this name. 
std::ostream & operator<<(std::ostream &os, const argagg::parser &x)
Writes the option help to the given stream. 
std::unordered_map< std::string, const definition * > long_map
Maps from a long flag (an std::string) to a pointer to the original definition that the flag represen...
const definition * get_definition_for_long_flag(const std::string &flag) const 
If the long flag exists in the map object then it is returned by this method. If it doesn't then null...
std::ostream & output
Reference to the final output stream that the formatted string will be streamed to. 
An option definition which essentially represents what an option is. 
std::vector< std::string > flags
List of strings to match that correspond to this option. Should be fully specified with hyphens (e...
T long_long_(const char *arg)
Templated function for conversion to T using the std::strtoll() function. This is used for anything l...
std::string help
Help string for this option. 
T as(std::size_t i=0) const 
Gets a positional argument converted to the given type. 
bool is_valid_flag_definition(const char *s)
Checks whether a flag in an option definition is valid. I suggest reading through the function source...
parser_map validate_definitions(const std::vector< definition > &definitions)
Validates a collection (specifically an std::vector) of definition objects by checking if the contain...
This exception is thrown when an option's flag is invalid. This can be the case if the flag is not pr...
#define DEFINE_CONVERSION_FROM_LONG_(TYPE)
std::vector< definition > definitions
Vector of the option definitions which inform this parser how to parse the command line arguments...
std::unordered_map< std::string, option_results > options
Maps from definition name to the structure which contains the parser results for that definition...
Represents multiple option parse results for a single option. If treated as a single parse result it ...
std::vector< const char * > pos
Vector of positional arguments. 
std::vector< T > all_as() const 
Gets all positional arguments converted to the given type. 
bool known_long_flag(const std::string &flag) const 
Returns true if the provided long flag exists in the map object. 
This exception is thrown when an option is parsed unexpectedly such as when an argument was expected ...
T long_(const char *arg)
Templated function for conversion to T using the std::strtol() function. This is used for anything lo...
A list of option definitions used to inform how to parse arguments. 
Represents all results of the parser including options and positional arguments. 
parser_results parse(int argc, const char **argv) const 
Parses the provided command line arguments and returns the results as parser_results.