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
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:
parent
cc74cbfda7
commit
6086d0778e
@ -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
|
||||||
|
Loading…
x
Reference in New Issue
Block a user