feat update
All checks were successful
rpcrypto-build / build (Debug, himix200.toolchain.cmake) (push) Successful in 1m5s
rpcrypto-build / build (Debug, hisiv510.toolchain.cmake) (push) Successful in 1m4s
rpcrypto-build / build (Release, himix200.toolchain.cmake) (push) Successful in 1m13s
rpcrypto-build / build (Release, hisiv510.toolchain.cmake) (push) Successful in 1m26s
linux-hisiv500-gcc / linux-gcc-hisiv500 (push) Successful in 1m26s
linux-mips64-gcc / linux-gcc-mips64el (push) Successful in 1m38s
linux-x64-gcc / linux-gcc (push) Successful in 1m39s

This commit is contained in:
tqcq 2024-01-22 21:22:55 +08:00
parent cc74cbfda7
commit 6086d0778e

View File

@ -50,7 +50,6 @@
#include <utility> #include <utility>
#include <vector> #include <vector>
/** /**
* @brief * @brief
* There are only two hard things in Computer Science: cache invalidation and * There are only two hard things in Computer Science: cache invalidation and
@ -100,42 +99,35 @@
*/ */
namespace argagg { namespace argagg {
/** /**
* @brief * @brief
* This exception is thrown when a long option is parsed and is given an * This exception is thrown when a long option is parsed and is given an
* argument using the "=" syntax but the option doesn't expect an argument. * argument using the "=" syntax but the option doesn't expect an argument.
*/ */
struct unexpected_argument_error struct unexpected_argument_error : public std::runtime_error {
: public std::runtime_error {
using std::runtime_error::runtime_error; using std::runtime_error::runtime_error;
}; };
/** /**
* @brief * @brief
* This exception is thrown when an option is parsed unexpectedly such as when * This exception is thrown when an option is parsed unexpectedly such as when
* an argument was expected for a previous option or if an option was found * an argument was expected for a previous option or if an option was found
* that has not been defined. * that has not been defined.
*/ */
struct unexpected_option_error struct unexpected_option_error : public std::runtime_error {
: public std::runtime_error {
using std::runtime_error::runtime_error; using std::runtime_error::runtime_error;
}; };
/** /**
* @brief * @brief
* This exception is thrown when an option requires an argument but is not * 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 * 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. * if we simply reach the end of the command line arguments.
*/ */
struct option_lacks_argument_error struct option_lacks_argument_error : public std::runtime_error {
: public std::runtime_error {
using std::runtime_error::runtime_error; using std::runtime_error::runtime_error;
}; };
/** /**
* @brief * @brief
* This exception is thrown when an option's flag is invalid. This can be the * This exception is thrown when an option's flag is invalid. This can be the
@ -143,12 +135,10 @@ struct option_lacks_argument_error
* alpha-numeric characters after the hypens. See is_valid_flag_definition() * alpha-numeric characters after the hypens. See is_valid_flag_definition()
* for more details. * for more details.
*/ */
struct invalid_flag struct invalid_flag : public std::runtime_error {
: public std::runtime_error {
using std::runtime_error::runtime_error; using std::runtime_error::runtime_error;
}; };
/** /**
* @brief * @brief
* The set of template instantiations that convert C-strings to other types for * The set of template instantiations that convert C-strings to other types for
@ -165,8 +155,7 @@ namespace convert {
template<typename T> template<typename T>
T arg(const char *arg); T arg(const char *arg);
} }// namespace convert
/** /**
* @brief * @brief
@ -222,10 +211,8 @@ struct option_result {
*/ */
template<typename T> template<typename T>
operator T() const; operator T() const;
}; };
/** /**
* @brief * @brief
* Represents multiple option parse results for a single option. If treated as * Represents multiple option parse results for a single option. If treated as
@ -299,10 +286,8 @@ struct option_results {
*/ */
template<typename T> template<typename T>
operator T() const; operator T() const;
}; };
/** /**
* @brief * @brief
* Represents all results of the parser including options and positional * Represents all results of the parser including options and positional
@ -377,10 +362,8 @@ struct parser_results {
*/ */
template<typename T> template<typename T>
std::vector<T> all_as() const; std::vector<T> all_as() const;
}; };
/** /**
* @brief * @brief
* An option definition which essentially represents what an option is. * An option definition which essentially represents what an option is.
@ -425,10 +408,8 @@ struct definition {
* Returns true if this option requires arguments. * Returns true if this option requires arguments.
*/ */
bool requires_arguments() const; bool requires_arguments() const;
}; };
/** /**
* @brief * @brief
* Checks whether or not a command line argument should be processed as an * Checks whether or not a command line argument should be processed as an
@ -436,27 +417,21 @@ struct definition {
* allow for short flag groups (e.g. "-abc") and equal-assigned long flag * allow for short flag groups (e.g. "-abc") and equal-assigned long flag
* arguments (e.g. "--output=foo.txt"). * arguments (e.g. "--output=foo.txt").
*/ */
bool cmd_line_arg_is_option_flag( bool cmd_line_arg_is_option_flag(const char *s);
const char* s);
/** /**
* @brief * @brief
* Checks whether a flag in an option definition is valid. I suggest reading * Checks whether a flag in an option definition is valid. I suggest reading
* through the function source to understand what dictates a valid. * through the function source to understand what dictates a valid.
*/ */
bool is_valid_flag_definition( bool is_valid_flag_definition(const char *s);
const char* s);
/** /**
* @brief * @brief
* Tests whether or not a valid flag is short. Assumes the provided cstring is * Tests whether or not a valid flag is short. Assumes the provided cstring is
* already a valid flag. * already a valid flag.
*/ */
bool flag_is_short( bool flag_is_short(const char *s);
const char* s);
/** /**
* @brief * @brief
@ -489,35 +464,30 @@ struct parser_map {
* @brief * @brief
* Returns true if the provided short flag exists in the map object. * Returns true if the provided short flag exists in the map object.
*/ */
bool known_short_flag( bool known_short_flag(const char flag) const;
const char flag) const;
/** /**
* @brief * @brief
* If the short flag exists in the map object then it is returned by this * If the short flag exists in the map object then it is returned by this
* method. If it doesn't then nullptr will be returned. * method. If it doesn't then nullptr will be returned.
*/ */
const definition* get_definition_for_short_flag( const definition *get_definition_for_short_flag(const char flag) const;
const char flag) const;
/** /**
* @brief * @brief
* Returns true if the provided long flag exists in the map object. * Returns true if the provided long flag exists in the map object.
*/ */
bool known_long_flag( bool known_long_flag(const std::string &flag) const;
const std::string& flag) const;
/** /**
* @brief * @brief
* If the long flag exists in the map object then it is returned by this * If the long flag exists in the map object then it is returned by this
* method. If it doesn't then nullptr will be returned. * method. If it doesn't then nullptr will be returned.
*/ */
const definition* get_definition_for_long_flag( const definition *
const std::string& flag) const; get_definition_for_long_flag(const std::string &flag) const;
}; };
/** /**
* @brief * @brief
* Validates a collection (specifically an std::vector) of @ref definition * Validates a collection (specifically an std::vector) of @ref definition
@ -525,9 +495,7 @@ struct parser_map {
* definition objects is not valid then an exception is thrown. Upon successful * definition objects is not valid then an exception is thrown. Upon successful
* validation a @ref parser_map object is returned. * validation a @ref parser_map object is returned.
*/ */
parser_map validate_definitions( parser_map validate_definitions(const std::vector<definition> &definitions);
const std::vector<definition>& definitions);
/** /**
* @brief * @brief
@ -561,10 +529,8 @@ struct parser {
* which is typically frowned upon but is safe here. * which is typically frowned upon but is safe here.
*/ */
parser_results parse(int argc, char **argv) const; parser_results parse(int argc, char **argv) const;
}; };
/** /**
* @brief * @brief
* A convenience output stream that will accumulate what is streamed to it and * A convenience output stream that will accumulate what is streamed to it and
@ -611,10 +577,8 @@ struct fmt_ostream : public std::ostringstream {
* stored. * stored.
*/ */
~fmt_ostream(); ~fmt_ostream();
}; };
/** /**
* @brief * @brief
* Processes the provided string using the fmt util and returns the resulting * Processes the provided string using the fmt util and returns the resulting
@ -632,25 +596,21 @@ struct fmt_ostream : public std::ostringstream {
*/ */
std::string fmt_string(const std::string &s); std::string fmt_string(const std::string &s);
}// namespace argagg }// namespace argagg
/** /**
* @brief * @brief
* Writes the option help to the given stream. * Writes the option help to the given stream.
*/ */
std::ostream &operator<<(std::ostream &os, const argagg::parser &x); std::ostream &operator<<(std::ostream &os, const argagg::parser &x);
// ---- end of declarations, header-only implementations follow ---- // ---- end of declarations, header-only implementations follow ----
namespace argagg { namespace argagg {
template<typename T> template<typename T>
T option_result::as() const T
option_result::as() const
{ {
if (this->arg) { if (this->arg) {
return convert::arg<T>(this->arg); return convert::arg<T>(this->arg);
@ -659,9 +619,9 @@ T option_result::as() const
} }
} }
template<typename T> template<typename T>
T option_result::as(const T& t) const T
option_result::as(const T &t) const
{ {
if (this->arg) { if (this->arg) {
try { try {
@ -679,44 +639,39 @@ T option_result::as(const T& t) const
} }
} }
template<typename T> template<typename T>
option_result::operator T() const option_result::operator T() const
{ {
return this->as<T>(); return this->as<T>();
} }
template<>
template <> inline inline option_result::operator bool() const
option_result::operator bool () const
{ {
return this->arg != nullptr; return this->arg != nullptr;
} }
inline std::size_t
inline option_results::count() const
std::size_t option_results::count() const
{ {
return this->all.size(); return this->all.size();
} }
inline option_result &
inline option_results::operator[](std::size_t index)
option_result& option_results::operator [] (std::size_t index)
{ {
return this->all[index]; return this->all[index];
} }
inline const option_result &
inline option_results::operator[](std::size_t index) const
const option_result& option_results::operator [] (std::size_t index) const
{ {
return this->all[index]; return this->all[index];
} }
template<typename T> template<typename T>
T option_results::as() const T
option_results::as() const
{ {
if (this->all.size() == 0) { if (this->all.size() == 0) {
throw std::out_of_range("no option arguments to convert"); throw std::out_of_range("no option arguments to convert");
@ -724,118 +679,97 @@ T option_results::as() const
return this->all.back().as<T>(); return this->all.back().as<T>();
} }
template<typename T> template<typename T>
T option_results::as(const T& t) const T
option_results::as(const T &t) const
{ {
if (this->all.size() == 0) { if (this->all.size() == 0) { return t; }
return t;
}
return this->all.back().as<T>(t); return this->all.back().as<T>(t);
} }
template<typename T> template<typename T>
option_results::operator T() const option_results::operator T() const
{ {
return this->as<T>(); return this->as<T>();
} }
template<>
template <> inline inline option_results::operator bool() const
option_results::operator bool () const
{ {
return this->all.size() > 0; return this->all.size() > 0;
} }
inline bool
inline parser_results::has_option(const std::string &name) const
bool parser_results::has_option(const std::string& name) const
{ {
const auto it = this->options.find(name); const auto it = this->options.find(name);
return (it != this->options.end()) && it->second.all.size() > 0; return (it != this->options.end()) && it->second.all.size() > 0;
} }
inline option_results &
inline parser_results::operator[](const std::string &name)
option_results& parser_results::operator [] (const std::string& name)
{ {
return this->options.at(name); return this->options.at(name);
} }
inline const option_results &
inline
const option_results&
parser_results::operator[](const std::string &name) const parser_results::operator[](const std::string &name) const
{ {
return this->options.at(name); return this->options.at(name);
} }
inline std::size_t
inline parser_results::count() const
std::size_t parser_results::count() const
{ {
return this->pos.size(); return this->pos.size();
} }
inline const char *
inline parser_results::operator[](std::size_t index) const
const char* parser_results::operator [] (std::size_t index) const
{ {
return this->pos[index]; return this->pos[index];
} }
template<typename T> template<typename T>
T parser_results::as(std::size_t i) const T
parser_results::as(std::size_t i) const
{ {
return convert::arg<T>(this->pos[i]); return convert::arg<T>(this->pos[i]);
} }
template<typename T> template<typename T>
std::vector<T> parser_results::all_as() const std::vector<T>
parser_results::all_as() const
{ {
std::vector<T> v(this->pos.size()); std::vector<T> v(this->pos.size());
std::transform( std::transform(this->pos.begin(), this->pos.end(), v.begin(),
this->pos.begin(), this->pos.end(), v.begin(), [](const char *arg) { return convert::arg<T>(arg); });
[](const char* arg) {
return convert::arg<T>(arg);
});
return v; return v;
} }
inline bool
inline definition::wants_no_arguments() const
bool definition::wants_no_arguments() const
{ {
return this->num_args == 0; return this->num_args == 0;
} }
inline bool
inline definition::requires_arguments() const
bool definition::requires_arguments() const
{ {
return this->num_args > 0; return this->num_args > 0;
} }
inline bool
inline cmd_line_arg_is_option_flag(const char *s)
bool cmd_line_arg_is_option_flag(
const char* s)
{ {
auto len = std::strlen(s); auto len = std::strlen(s);
// The shortest possible flag has two characters: a hyphen and an // The shortest possible flag has two characters: a hyphen and an
// alpha-numeric character. // alpha-numeric character.
if (len < 2) { if (len < 2) { return false; }
return false;
}
// All flags must start with a hyphen. // All flags must start with a hyphen.
if (s[0] != '-') { if (s[0] != '-') { return false; }
return false;
}
// Shift the name forward by a character to account for the initial hyphen. // Shift the name forward by a character to account for the initial hyphen.
// This means if s was originally "-v" then name will be "v". // This means if s was originally "-v" then name will be "v".
@ -847,9 +781,7 @@ bool cmd_line_arg_is_option_flag(
is_long = true; is_long = true;
// Just -- is not a valid flag. // Just -- is not a valid flag.
if (len == 2) { if (len == 2) { return false; }
return false;
}
// Shift the name forward to account for the extra hyphen. This means if s // Shift the name forward to account for the extra hyphen. This means if s
// was originally "--output" then name will be "output". // was originally "--output" then name will be "output".
@ -859,9 +791,7 @@ bool cmd_line_arg_is_option_flag(
// The first character of the flag name must be alpha-numeric. This is to // The first character of the flag name must be alpha-numeric. This is to
// prevent things like "---a" from being valid flags. // prevent things like "---a" from being valid flags.
len = std::strlen(name); len = std::strlen(name);
if (!std::isalnum(name[0])) { if (!std::isalnum(name[0])) { return false; }
return false;
}
// At this point in is_valid_flag_definition() we would check if the short // At this point in is_valid_flag_definition() we would check if the short
// flag has only one character. At command line specification you can group // flag has only one character. At command line specification you can group
@ -899,23 +829,17 @@ bool cmd_line_arg_is_option_flag(
return true; return true;
} }
inline bool
inline is_valid_flag_definition(const char *s)
bool is_valid_flag_definition(
const char* s)
{ {
auto len = std::strlen(s); auto len = std::strlen(s);
// The shortest possible flag has two characters: a hyphen and an // The shortest possible flag has two characters: a hyphen and an
// alpha-numeric character. // alpha-numeric character.
if (len < 2) { if (len < 2) { return false; }
return false;
}
// All flags must start with a hyphen. // All flags must start with a hyphen.
if (s[0] != '-') { if (s[0] != '-') { return false; }
return false;
}
// Shift the name forward by a character to account for the initial hyphen. // Shift the name forward by a character to account for the initial hyphen.
// This means if s was originally "-v" then name will be "v". // This means if s was originally "-v" then name will be "v".
@ -927,9 +851,7 @@ bool is_valid_flag_definition(
is_long = true; is_long = true;
// Just -- is not a valid flag. // Just -- is not a valid flag.
if (len == 2) { if (len == 2) { return false; }
return false;
}
// Shift the name forward to account for the extra hyphen. This means if s // Shift the name forward to account for the extra hyphen. This means if s
// was originally "--output" then name will be "output". // was originally "--output" then name will be "output".
@ -939,14 +861,10 @@ bool is_valid_flag_definition(
// The first character of the flag name must be alpha-numeric. This is to // The first character of the flag name must be alpha-numeric. This is to
// prevent things like "---a" from being valid flags. // prevent things like "---a" from being valid flags.
len = std::strlen(name); len = std::strlen(name);
if (!std::isalnum(name[0])) { if (!std::isalnum(name[0])) { return false; }
return false;
}
// If this is a short flag then it must only have one character. // If this is a short flag then it must only have one character.
if (!is_long && len > 1) { if (!is_long && len > 1) { return false; }
return false;
}
// The rest of the characters must be alpha-numeric, but long flags are // The rest of the characters must be alpha-numeric, but long flags are
// allowed to have hyphens too. // allowed to have hyphens too.
@ -955,55 +873,41 @@ bool is_valid_flag_definition(
}); });
} }
inline bool
inline flag_is_short(const char *s)
bool flag_is_short(
const char* s)
{ {
return s[0] == '-' && std::isalnum(s[1]); return s[0] == '-' && std::isalnum(s[1]);
} }
inline bool
inline parser_map::known_short_flag(const char flag) const
bool parser_map::known_short_flag(
const char flag) const
{ {
return this->short_map[flag] != nullptr; return this->short_map[flag] != nullptr;
} }
inline const definition *
inline parser_map::get_definition_for_short_flag(const char flag) const
const definition* parser_map::get_definition_for_short_flag(
const char flag) const
{ {
return this->short_map[flag]; return this->short_map[flag];
} }
inline bool
inline parser_map::known_long_flag(const std::string &flag) const
bool parser_map::known_long_flag(
const std::string& flag) const
{ {
const auto existing_long_flag = this->long_map.find(flag); const auto existing_long_flag = this->long_map.find(flag);
return existing_long_flag != long_map.end(); return existing_long_flag != long_map.end();
} }
inline const definition *
inline parser_map::get_definition_for_long_flag(const std::string &flag) const
const definition* parser_map::get_definition_for_long_flag(
const std::string& flag) const
{ {
const auto existing_long_flag = this->long_map.find(flag); const auto existing_long_flag = this->long_map.find(flag);
if (existing_long_flag == long_map.end()) { if (existing_long_flag == long_map.end()) { return nullptr; }
return nullptr;
}
return existing_long_flag->second; return existing_long_flag->second;
} }
inline parser_map
inline validate_definitions(const std::vector<definition> &definitions)
parser_map validate_definitions(
const std::vector<definition>& definitions)
{ {
std::unordered_map<std::string, const definition *> long_map; std::unordered_map<std::string, const definition *> long_map;
parser_map map{{{nullptr}}, std::move(long_map)}; parser_map map{{{nullptr}}, std::move(long_map)};
@ -1020,15 +924,17 @@ parser_map validate_definitions(
if (!is_valid_flag_definition(flag.data())) { if (!is_valid_flag_definition(flag.data())) {
std::ostringstream msg; std::ostringstream msg;
msg << "flag \"" << flag << "\" specified for option \"" << defn.name msg << "flag \"" << flag << "\" specified for option \""
<< "\" is invalid"; << defn.name << "\" is invalid";
throw invalid_flag(msg.str()); throw invalid_flag(msg.str());
} }
if (flag_is_short(flag.data())) { if (flag_is_short(flag.data())) {
const int short_flag_letter = flag[1]; const int short_flag_letter = flag[1];
const auto existing_short_flag = map.short_map[short_flag_letter]; const auto existing_short_flag =
bool short_flag_already_exists = (existing_short_flag != nullptr); map.short_map[short_flag_letter];
bool short_flag_already_exists =
(existing_short_flag != nullptr);
if (short_flag_already_exists) { if (short_flag_already_exists) {
std::ostringstream msg; std::ostringstream msg;
msg << "duplicate short flag \"" << flag msg << "duplicate short flag \"" << flag
@ -1042,7 +948,8 @@ parser_map validate_definitions(
// If we're here then this is a valid, long-style flag. // If we're here then this is a valid, long-style flag.
if (map.known_long_flag(flag)) { if (map.known_long_flag(flag)) {
const auto existing_long_flag = map.get_definition_for_long_flag(flag); const auto existing_long_flag =
map.get_definition_for_long_flag(flag);
std::ostringstream msg; std::ostringstream msg;
msg << "duplicate long flag \"" << flag msg << "duplicate long flag \"" << flag
<< "\" found, specified by both option \"" << defn.name << "\" found, specified by both option \"" << defn.name
@ -1056,9 +963,8 @@ parser_map validate_definitions(
return map; return map;
} }
inline parser_results
inline parser::parse(int argc, const char **argv) const
parser_results parser::parse(int argc, const char** argv) const
{ {
// Inspect each definition to see if its valid. You may wonder "why don't // Inspect each definition to see if its valid. You may wonder "why don't
// you do this validation on construction?" I had thought about it but // you do this validation on construction?" I had thought about it but
@ -1084,8 +990,7 @@ parser_results parser::parse(int argc, const char** argv) const
// Add an empty option result for each definition. // Add an empty option result for each definition.
for (const auto &defn : this->definitions) { for (const auto &defn : this->definitions) {
option_results opt_results{{}}; option_results opt_results{{}};
results.options.insert( results.options.insert(std::make_pair(defn.name, opt_results));
std::make_pair(defn.name, opt_results));
} }
// Don't start off ignoring flags. We only ignore flags after a -- shows up // Don't start off ignoring flags. We only ignore flags after a -- shows up
@ -1111,11 +1016,9 @@ parser_results parser::parse(int argc, const char** argv) const
// Some behavior to note: if the previous option is expecting an argument // Some behavior to note: if the previous option is expecting an argument
// then the next entry will be treated as a positional argument even if // then the next entry will be treated as a positional argument even if
// it looks like a flag. // it looks like a flag.
bool treat_as_positional_argument = ( bool treat_as_positional_argument =
ignore_flags (ignore_flags || num_option_args_to_consume > 0
|| num_option_args_to_consume > 0 || !cmd_line_arg_is_option_flag(arg_i_cstr));
|| !cmd_line_arg_is_option_flag(arg_i_cstr)
);
if (treat_as_positional_argument) { if (treat_as_positional_argument) {
// If last option is expecting some specific positive number of // If last option is expecting some specific positive number of
@ -1195,7 +1098,8 @@ parser_results parser::parse(int argc, const char** argv) const
opt_results.all.push_back(std::move(opt_result)); opt_results.all.push_back(std::move(opt_result));
if (defn->requires_arguments()) { if (defn->requires_arguments()) {
bool there_is_an_equal_delimited_arg = (long_flag_arg != nullptr); bool there_is_an_equal_delimited_arg =
(long_flag_arg != nullptr);
if (there_is_an_equal_delimited_arg) { if (there_is_an_equal_delimited_arg) {
// long_flag_arg would be "=foo" in the "--output=foo" case so we // long_flag_arg would be "=foo" in the "--output=foo" case so we
// increment by 1 to get rid of the equal sign. // increment by 1 to get rid of the equal sign.
@ -1223,8 +1127,9 @@ parser_results parser::parse(int argc, const char** argv) const
if (!std::isalnum(short_flag)) { if (!std::isalnum(short_flag)) {
std::ostringstream msg; std::ostringstream msg;
msg << "found non-alphanumeric character '" << arg_i_cstr[sf_idx] msg << "found non-alphanumeric character '"
<< "' in flag group '" << arg_i_cstr << "'"; << arg_i_cstr[sf_idx] << "' in flag group '" << arg_i_cstr
<< "'";
throw std::domain_error(msg.str()); throw std::domain_error(msg.str());
} }
@ -1286,25 +1191,23 @@ parser_results parser::parse(int argc, const char** argv) const
return results; return results;
} }
inline parser_results
inline parser::parse(int argc, char **argv) const
parser_results parser::parse(int argc, char** argv) const
{ {
return parse(argc, const_cast<const char **>(argv)); return parse(argc, const_cast<const char **>(argv));
} }
namespace convert { namespace convert {
/** /**
* @brief * @brief
* Templated function for conversion to T using the @ref std::strtol() * Templated function for conversion to T using the @ref std::strtol()
* function. This is used for anything long length or shorter (long, int, * function. This is used for anything long length or shorter (long, int,
* short, char). * short, char).
*/ */
template <typename T> inline template<typename T>
T long_(const char* arg) inline T
long_(const char *arg)
{ {
char *endptr = nullptr; char *endptr = nullptr;
errno = 0; errno = 0;
@ -1320,15 +1223,15 @@ namespace convert {
return ret; return ret;
} }
/** /**
* @brief * @brief
* Templated function for conversion to T using the @ref std::strtoll() * Templated function for conversion to T using the @ref std::strtoll()
* function. This is used for anything long long length or shorter (long * function. This is used for anything long long length or shorter (long
* long). * long).
*/ */
template <typename T> inline template<typename T>
T long_long_(const char* arg) inline T
long_long_(const char *arg)
{ {
char *endptr = nullptr; char *endptr = nullptr;
errno = 0; errno = 0;
@ -1344,10 +1247,9 @@ namespace convert {
return ret; return ret;
} }
#define DEFINE_CONVERSION_FROM_LONG_(TYPE) \ #define DEFINE_CONVERSION_FROM_LONG_(TYPE) \
template <> inline \ template<> \
TYPE arg(const char* arg) \ inline TYPE arg(const char *arg) \
{ \ { \
return long_<TYPE>(arg); \ return long_<TYPE>(arg); \
} }
@ -1364,10 +1266,9 @@ namespace convert {
#undef DEFINE_CONVERSION_FROM_LONG_ #undef DEFINE_CONVERSION_FROM_LONG_
#define DEFINE_CONVERSION_FROM_LONG_LONG_(TYPE) \ #define DEFINE_CONVERSION_FROM_LONG_LONG_(TYPE) \
template <> inline \ template<> \
TYPE arg(const char* arg) \ inline TYPE arg(const char *arg) \
{ \ { \
return long_long_<TYPE>(arg); \ return long_long_<TYPE>(arg); \
} }
@ -1377,16 +1278,16 @@ namespace convert {
#undef DEFINE_CONVERSION_FROM_LONG_LONG_ #undef DEFINE_CONVERSION_FROM_LONG_LONG_
template<>
template <> inline inline bool
bool arg(const char* arg) arg(const char *arg)
{ {
return argagg::convert::arg<int>(arg) != 0; return argagg::convert::arg<int>(arg) != 0;
} }
template<>
template <> inline inline float
float arg(const char* arg) arg(const char *arg)
{ {
char *endptr = nullptr; char *endptr = nullptr;
errno = 0; errno = 0;
@ -1402,9 +1303,9 @@ namespace convert {
return ret; return ret;
} }
template<>
template <> inline inline double
double arg(const char* arg) arg(const char *arg)
{ {
char *endptr = nullptr; char *endptr = nullptr;
errno = 0; errno = 0;
@ -1420,42 +1321,33 @@ namespace convert {
return ret; return ret;
} }
template<>
template <> inline inline const char *
const char* arg(const char* arg) arg(const char *arg)
{ {
return arg; return arg;
} }
template<>
template <> inline inline std::string
std::string arg(const char* arg) arg(const char *arg)
{ {
return std::string(arg); return std::string(arg);
} }
} }// namespace convert
inline fmt_ostream::fmt_ostream(std::ostream &output)
: std::ostringstream(),
output(output)
{}
inline inline fmt_ostream::~fmt_ostream() { output << fmt_string(this->str()); }
fmt_ostream::fmt_ostream(std::ostream& output)
: std::ostringstream(), output(output)
{
}
inline
fmt_ostream::~fmt_ostream()
{
output << fmt_string(this->str());
}
#ifdef __unix__ #ifdef __unix__
inline std::string
inline fmt_string(const std::string &s)
std::string fmt_string(const std::string& s)
{ {
constexpr int read_end = 0; constexpr int read_end = 0;
constexpr int write_end = 1; constexpr int write_end = 1;
@ -1465,12 +1357,8 @@ std::string fmt_string(const std::string& s)
int read_pipe[2]; int read_pipe[2];
int write_pipe[2]; int write_pipe[2];
if (pipe(read_pipe) == -1) { if (pipe(read_pipe) == -1) { return s; }
return s; if (pipe(write_pipe) == -1) { return s; }
}
if (pipe(write_pipe) == -1) {
return s;
}
auto parent_pid = fork(); auto parent_pid = fork();
bool is_fmt_proc = (parent_pid == 0); bool is_fmt_proc = (parent_pid == 0);
@ -1489,20 +1377,16 @@ std::string fmt_string(const std::string& s)
close(read_pipe[write_end]); close(read_pipe[write_end]);
auto fmt_write_fd = write_pipe[write_end]; auto fmt_write_fd = write_pipe[write_end];
auto write_result = write(fmt_write_fd, s.c_str(), s.length()); auto write_result = write(fmt_write_fd, s.c_str(), s.length());
if (write_result != static_cast<ssize_t>(s.length())) { if (write_result != static_cast<ssize_t>(s.length())) { return s; }
return s;
}
close(fmt_write_fd); close(fmt_write_fd);
auto fmt_read_fd = read_pipe[read_end]; auto fmt_read_fd = read_pipe[read_end];
std::ostringstream os; std::ostringstream os;
char buf[64]; char buf[64];
while (true) { while (true) {
auto read_count = read( auto read_count =
fmt_read_fd, reinterpret_cast<void*>(buf), sizeof(buf)); read(fmt_read_fd, reinterpret_cast<void *>(buf), sizeof(buf));
if (read_count <= 0) { if (read_count <= 0) { break; }
break;
}
os.write(buf, static_cast<std::streamsize>(read_count)); os.write(buf, static_cast<std::streamsize>(read_count));
} }
close(fmt_read_fd); close(fmt_read_fd);
@ -1510,33 +1394,42 @@ std::string fmt_string(const std::string& s)
return os.str(); return os.str();
} }
#else// #ifdef __unix__ #else// #ifdef __unix__
inline std::string
inline fmt_string(const std::string &s)
std::string fmt_string(const std::string& s)
{ {
return s; return s;
} }
#endif// #ifdef __unix__ #endif// #ifdef __unix__
}// namespace argagg }// namespace argagg
//
namespace ulib {
using parser = argagg::parser;
using parser_results = argagg::parser_results;
using option_results = argagg::option_results;
using option_result = argagg::option_result;
using definition = argagg::definition;
using fmt_ostream = argagg::fmt_ostream;
inline inline std::string
std::ostream& operator << (std::ostream& os, const argagg::parser& x) fmt_string(const std::string &s)
{
return argagg::fmt_string(s);
};
}// namespace ulib
inline std::ostream &
operator<<(std::ostream &os, const argagg::parser &x)
{ {
for (auto &definition : x.definitions) { for (auto &definition : x.definitions) {
os << " "; os << " ";
for (auto &flag : definition.flags) { for (auto &flag : definition.flags) {
os << flag; os << flag;
if (flag != definition.flags.back()) { if (flag != definition.flags.back()) { os << ", "; }
os << ", ";
}
} }
os << std::endl; os << std::endl;
os << " " << definition.help << std::endl; os << " " << definition.help << std::endl;
@ -1544,5 +1437,4 @@ std::ostream& operator << (std::ostream& os, const argagg::parser& x)
return os; return os;
} }
#endif// ARGAGG_ARGAGG_ARGAGG_HPP #endif// ARGAGG_ARGAGG_ARGAGG_HPP