Returns the parser's full program name.
Returns the parser's full program name.- For top-level parsers, this is the same as the parser's name.
#pragma once
#include "types.hpp"
#include <algorithm>
#include <format>
#include <iostream>
#include <ranges>
#include <span>
#ifdef AP_TESTING
namespace ap_testing {
struct argument_parser_test_fixture;
}
#endif
class argument_parser;
};
};
namespace detail {
}
class argument_parser {
public:
return *this;
}
throw invalid_configuration("The program version cannot contain whitespace characters!"
);
return *this;
}
return *this;
}
return *this;
}
return *this;
}
template <util::c_range_of<default_argument> AR>
for (const auto arg_discriminator : arg_discriminators)
return *this;
}
const std::initializer_list<default_argument>& arg_discriminators
) noexcept {
}
) noexcept {
return *this;
}
template <util::c_argument_value_type T = std::string>
}
template <util::c_argument_value_type T = std::string>
argument_group&
group,
const std::string_view
name
) {
const detail::argument_name
arg_name(std::make_optional<std::string>(
name));
}
template <util::c_argument_value_type T = std::string>
const std::string_view
name,
) {
}
template <util::c_argument_value_type T = std::string>
) {
);
}
template <util::c_argument_value_type T = std::string>
const std::string_view
name,
) {
? detail::
: detail::argument_name{
};
}
template <util::c_argument_value_type T = std::string>
) {
);
}
template <bool StoreImplicitly = true>
const std::string_view
name,
) {
}
template <bool StoreImplicitly = true>
) {
}
template <bool StoreImplicitly = true>
const std::string_view
name,
) {
}
template <bool StoreImplicitly = true>
) {
}
argument_group&
add_group(
const std::string_view
name)
noexcept {
}
);
throw std::logic_error(std::format(
"A subparser with the given name () already exists in parser '{}'",
(*subparser_it)->_name,
));
);
}
}
template <util::c_forward_range_of<std::string, util::type_validator::convertible> AR>
parsing_state
state(*
this);
throw parsing_failure(std::format(
"Failed to deduce the argument for values [{}]",
util::join(
state.unknown_args)
));
}
}
template <util::c_forward_range_of<std::string, util::type_validator::convertible> AR>
try {
}
std::cerr <<
"[ap::error] " <<
err.what() << std::endl
}
}
}
template <util::c_forward_range_of<std::string, util::type_validator::convertible> AR>
parsing_state
state(*
this,
true);
return std::move(
state.unknown_args);
}
}
template <util::c_forward_range_of<std::string, util::type_validator::convertible> AR>
try {
}
std::cerr <<
"[ap::error] " <<
err.what() << std::endl
}
}
}
}
}
}
);
return *this;
}
}
}
}
template <util::c_argument_value_type T = std::string>
try {
}
catch (const std::bad_any_cast&) {
throw type_error::invalid_value_type<T>(
arg->
name());
}
}
template <util::c_argument_value_type T = std::string, std::convertible_to<T> U>
try {
}
catch (const std::logic_error&) {
}
catch (const std::bad_any_cast&) {
throw type_error::invalid_value_type<T>(
arg->
name());
}
}
template <util::c_argument_value_type T = std::string>
try {
std::ranges::copy(
);
}
catch (const std::bad_any_cast&) {
throw type_error::invalid_value_type<T>(
arg->
name());
}
}
<< '\n';
}
<< std::endl;
}
friend std::ostream&
operator<<(std::ostream&
os,
const argument_parser&
parser)
noexcept {
}
#ifdef AP_TESTING
friend struct ::ap_testing::argument_parser_test_fixture;
#endif
private:
using arg_ptr_t = std::shared_ptr<detail::argument_base>;
struct parsing_state {
}
const bool
};
),
throw invalid_configuration("The program name cannot be empty!");
throw invalid_configuration("The program name cannot contain whitespace characters!");
}
arg_name,
"An argument name cannot be empty."
);
arg_name,
"An argument name cannot contain whitespaces."
);
std::format(
"An argument name cannot begin with a flag prefix character ({}).",
)
);
arg_name,
"An argument name cannot begin with a digit."
);
}
) const noexcept {
}
) const noexcept {
};
}
) const noexcept {
return true;
return true;
return false;
}
if (
group._parser !=
this)
throw std::logic_error(std::format(
"An argument group '{}' does not belong to the given parser.",
group.
_name
));
}
template <util::c_forward_iterator_of<std::string, util::type_validator::convertible> AIt>
});
return;
}
}
}
continue;
}
throw invalid_configuration(std::format(
"Required positional argument [{}] cannot be defined after a non-required "
"positional argument [{}].",
));
}
}
template <util::c_forward_iterator_of<std::string, util::type_validator::convertible> AIt>
) {
});
}
) {
detail::argument_token
tok{
};
return;
}
if (
state.parse_known_only) {
return;
}
std::cerr <<
"[ap::warning] Unknown argument '" <<
tok.
value <<
"' will be ignored."
<< std::endl;
return;
break;
}
}
) const noexcept {
}
return true;
}
return false;
)
);
return false;
}
}
return true;
}
) noexcept {
const auto match_type =
return std::ranges::find_if(
);
}
) const noexcept {
default:
}
}
return;
}
else
}
if (
not tok.is_valid_flag_token()) {
if (
state.parse_known_only) {
return;
}
else {
}
}
for (
const auto&
arg :
tok.args) {
else
}
}
return;
}
}
}
if (
state.curr_arg->set_value(std::string(
value)))
return;
if (
state.curr_arg->is_positional()
}
}
bool suppress_group_checks = false;
bool suppress_arg_checks = false;
if (
arg->suppresses_group_checks())
suppress_group_checks = true;
if (
arg->suppresses_arg_checks())
suppress_arg_checks = true;
}
};
return {suppress_group_checks, suppress_arg_checks};
}
const argument_group&
group,
const bool suppress_group_checks,
const bool suppress_arg_checks
) const {
if (
group._arguments.empty())
return;
if (
not suppress_group_checks) {
const auto n_used_args =
static_cast<std::size_t
>(std::ranges::count_if(
group._arguments, [](
const auto&
arg) { return arg->is_used(); }
));
if (
group._mutually_exclusive) {
throw parsing_failure(std::format(
"At most one argument from the mutually exclusive group '{}' can be used",
));
group._arguments, [](
const auto&
arg) { return arg->is_used(); }
);
return;
}
}
throw parsing_failure(std::format(
"At least one argument from the required group '{}' must be used",
group.
_name
));
}
for (
const auto&
arg :
group._arguments)
}
if (suppress_arg_checks)
return;
throw parsing_failure(
std::format(
"No values parsed for a required argument [{}]",
arg->
name().str())
);
}
}
}
return nullptr;
}
return;
std::vector<detail::help_builder>
builders;
}
const noexcept {
return not arg->is_hidden();
});
return;
if (
group._mutually_exclusive)
}
else {
std::vector<detail::help_builder>
builders;
}
}
std::string
false;
};
namespace detail {
) noexcept {
switch (arg_discriminator) {
arg_parser.add_positional_argument("input")
.help("Input file path");
break;
arg_parser.add_positional_argument("output").help("Output file path");
break;
arg_parser.add_optional_argument<none_type>("help", "h")
.help("Display the help message");
break;
arg_parser.add_optional_argument<none_type>("version", "v")
.action<action_type::on_flag>([&arg_parser]() {
arg_parser.print_version();
std::exit(EXIT_SUCCESS);
})
.help("Dsiplay program version info");
break;
arg_parser.add_optional_argument("input", "i")
.nargs(1ull)
.help("Input file path");
break;
arg_parser.add_optional_argument("output", "o").nargs(1ull).help("Output file path");
break;
arg_parser.add_optional_argument("input", "i")
.help("Input files paths");
break;
arg_parser.add_optional_argument("output", "o")
.help("Output files paths");
break;
}
}
}
}
static std::unique_ptr< argument_group > create(argument_parser &parser, std::string_view name)
Factory method to create an argument group.
std::vector< arg_ptr_t > arg_ptr_vec_t
std::string _program_name
The name of the program in the format "<parent-parser-names>... <program-name>".
argument_parser & program_version(const version &version) noexcept
Set the program version.
optional_argument< T > & add_optional_argument(const std::string_view name, const detail::argument_name_discriminator name_discr=n_primary)
Adds an optional argument to the parser's configuration.
std::vector< std::string > try_parse_known_args(int argc, char *argv[])
Parses the known command-line arguments and exits on error.
void _verify_group_requirements(const argument_group &group, const bool suppress_group_checks, const bool suppress_arg_checks) const
Verifies whether the requirements of the given argument group are satisfied.
void _validate_group(const argument_group &group)
Check if the given group belongs to the parser.
std::string_view program_name() const noexcept
void _parse_flag_token(const detail::argument_token &tok, parsing_state &state)
Parse a single command-line argument flag token.
bool finalized() const noexcept
Check whether the parser has finalized parsing its own arguments.
static constexpr std::uint8_t _indent_width
~argument_parser()=default
std::shared_ptr< detail::argument_base > arg_ptr_t
arg_group_ptr_vec_t _argument_groups
The list of argument groups.
arg_ptr_vec_t _optional_args
The list of optional arguments.
arg_token_vec_t _tokenize(AIt args_begin, const AIt args_end, const parsing_state &state)
Converts the command-line arguments into a list of tokens.
std::optional< std::string > _program_description
The description of the program.
bool _validate_flag_token(detail::argument_token &tok) noexcept
Check if a flag token is valid based on its value.
std::pair< bool, bool > _are_checks_suppressed() const noexcept
Check whether required argument group checks or argument checks suppressing is enabled.
void print_help(const bool verbose, std::ostream &os=std::cout) const noexcept
Prints the argument parser's help message to an output stream.
optional_argument< bool > & add_flag(const std::string_view name, const detail::argument_name_discriminator name_discr=n_primary)
Adds a boolean flag argument (an optional argument with value_type = bool) to the parser's configurat...
argument_parser(const argument_parser &)=delete
void _verify_arg_name_pattern(const std::string_view arg_name) const
Verifies the pattern of an argument name and if it's invalid, an error is thrown.
void _parse_token(const detail::argument_token &tok, parsing_state &state)
Parse a single command-line argument token.
std::string _name
The name of the parser.
std::string_view name() const noexcept
Returns the parser's name.
void _verify_argument_requirements(const arg_ptr_t &arg, const bool suppress_arg_checks) const
Verifies whether the requirements of the given argument are satisfied.
bool _is_arg_name_used(const detail::argument_name &arg_name, const detail::argument_name::match_type m_type=detail::argument_name::m_any) const noexcept
Check if an argument name is already used.
std::unique_ptr< argument_group > arg_group_ptr_t
arg_ptr_vec_t _positional_args
The list of positional arguments.
arg_parser_ptr_vec_t _subparsers
The list of subparsers.
argument_parser & program_description(std::string_view description) noexcept
Set the program description.
T value(std::string_view arg_name) const
Get the value of the given argument.
bool _invoked
A flag indicating whether the parser has been invoked to parse arguments.
std::string_view _strip_flag_prefix(const detail::argument_token &tok) const noexcept
Removes the flag prefix from a flag token's value.
static constexpr char _flag_prefix_char
void _validate_argument_configuration() const
Validate whether the definition/configuration of the parser's arguments is correct.
void _parse_args_impl(AIt args_begin, const AIt args_end, parsing_state &state)
Implementation of parsing command-line arguments.
T value_or(std::string_view arg_name, U &&fallback_value) const
Get the value of the given argument, if it has any, or a fallback value, if not.
void _verify_final_state() const
Verifies the correctness of the parsed command-line arguments.
bool has_value(std::string_view arg_name) const noexcept
Check if the given argument has a value.
bool _verbose
Verbosity flag.
argument_group & _gr_optional_args
The optional argument group.
arg_ptr_t _get_argument(std::string_view arg_name) const noexcept
Get the argument with the specified name.
argument_parser & resolved_parser() noexcept
Returns the deepest invoked parser.
argument_group & add_group(const std::string_view name) noexcept
Adds an argument group with the given name to the parser's configuration.
argument_parser & operator=(const argument_parser &)=delete
std::vector< T > values(std::string_view arg_name) const
Get all values of the given argument.
void _parse_value_token(const detail::argument_token &tok, parsing_state &state)
Parse a single command-line argument value token.
void _set_argument_value(const std::string_view value, parsing_state &state) noexcept
Set the value for the currently processed argument.
argument_parser & default_arguments(const AR &arg_discriminators) noexcept
Add default arguments to the argument parser.
bool invoked() const noexcept
Check whether this parser was invoked.
void _print_group(std::ostream &os, const argument_group &group, const bool verbose) const noexcept
Print the given argument list to an output stream.
static constexpr std::uint8_t _primary_flag_prefix_length
std::unique_ptr< argument_parser > arg_parser_ptr_t
std::vector< arg_group_ptr_t > arg_group_ptr_vec_t
std::vector< std::string > parse_known_args(int argc, char *argv[])
Parses the known command-line arguments.
argument_parser & verbose(const bool v=true) noexcept
Set the verbosity mode.
static constexpr std::string_view _flag_prefix
typename arg_ptr_vec_t::iterator arg_ptr_vec_iter_t
auto _name_match_predicate(const std::string_view arg_name, const detail::argument_name::match_type m_type=detail::argument_name::m_any) const noexcept
Returns a unary predicate function which checks if the given name matches the argument's name.
std::vector< arg_parser_ptr_t > arg_parser_ptr_vec_t
unknown_policy _unknown_policy
Policy for unknown arguments.
void try_parse_args(int argc, char *argv[])
Parses the command-line arguments and exits on error.
positional_argument< T > & add_positional_argument(const std::string_view name)
Adds a positional argument to the parser's configuration.
void print_version(std::ostream &os=std::cout) const noexcept
Prints the argument parser's version info to an output stream.
std::vector< detail::argument_token > arg_token_vec_t
arg_ptr_vec_iter_t _find_opt_arg(const detail::argument_token &flag_tok) noexcept
Find an optional argument based on a flag token.
argument_parser & add_subparser(const std::string_view name)
Adds an subparser with the given name to the parser's configuration.
typename arg_token_vec_t::const_iterator arg_token_vec_iter_t
bool is_used(std::string_view arg_name) const noexcept
Check if a specific argument was used in the command-line.
bool _validate_compound_flag_token(detail::argument_token &tok) noexcept
Check if a flag token is a valid compound argument flag based on its value.
argument_parser & unknown_arguments_policy(const unknown_policy policy) noexcept
Set the unknown argument flags handling policy.
std::size_t count(std::string_view arg_name) const noexcept
Get the given argument's usage count.
void _print_subparsers(std::ostream &os) const noexcept
detail::argument_token::token_type _deduce_token_type(const std::string_view arg_value) const noexcept
Returns the most appropriate initial token type based on a command-line argument's value.
bool _finalized
A flag indicating whether the parsing process has been finalized.
static constexpr std::uint8_t _secondary_flag_prefix_length
void _tokenize_arg(const std::string_view arg_value, arg_token_vec_t &toks, const parsing_state &state)
Appends an argument token(s) created from arg_value to the toks vector.
friend std::ostream & operator<<(std::ostream &os, const argument_parser &parser) noexcept
Prints the argument parser's details to an output stream.
std::optional< std::string > _program_version
The version of the program.
void parse_args(int argc, char *argv[])
Parses the command-line arguments.
argument_group & _gr_positional_args
The positional argument group.
std::string join(const R &range, const std::string_view delimiter=", ")
Joins elements of a range into a single string with a delimiter.
ap::action_type::on_flag::type print_help(const argument_parser &parser, const std::optional< int > exit_code=std::nullopt, std::ostream &os=std::cout) noexcept
Returns an on-flag action which prints the argument parser's help message.
util::callable_type< ap::action_type::observe, std::string > check_file_exists() noexcept
Returns an observe action which checks whether lower_bound file with the given name exists.
argument_name_discriminator
Argument name member discriminator.
@ n_primary
Represents the primary name (used with a long flag prefix –).
void add_default_argument(const default_argument, argument_parser &) noexcept
Adds a predefined/default positional argument to the parser.
constexpr range at_least(const count_type n) noexcept
range class builder function. Creates a range [n, inf).
bool contains_whitespaces(std::string_view str) noexcept
Checks whether a string contains any whitespace characters.
unknown_policy
The enumeration of policies for handling unknown arguments.
@ warn
Issue a warning when an unknown argument is encountered.
@ as_values
Treat unknown arguments as positional values.
@ ignore
Ignore unknown arguments.
@ fail
Throw an exception when an unknown argument is encountered.
default_argument
The enumeration of default arguments provided by the library.
@ p_output
A positional argument representing a single output file path. Equivalent to:
@ o_help
An optional argument representing the program's help flag. Equivalent to:
@ p_input
A positional argument representing a single input file path. Equivalent to:
@ o_input
A positional argument representing multiple input file paths. Equivalent to:
@ o_multi_input
A positional argument representing multiple input file paths. Equivalent to:
@ o_version
An optional argument representing the program's version flag. Equivalent to:
@ o_output
A positional argument representing multiple output file paths. Equivalent to:
@ o_multi_output
A positional argument representing multiple output file paths. Equivalent to:
void set_parser(argument_parser &parser)
Update the parser-specific parameters of the state object.
parsing_state(argument_parser &parser, const bool parse_known_only=false)
std::vector< std::string > unknown_args
A vector of unknown argument values.
const bool parse_known_only
A flag indicating whether only known arguments should be parsed.
arg_ptr_vec_iter_t curr_pos_arg_it
An iterator pointing to the next positional argument to be processed.
arg_ptr_t curr_arg
The currently processed argument.
Base type for the argument parser functionality errors/exceptions.
match_type
Specifies the type of argument name match.
@ m_any
Matches either the primary or the secondary name.
@ m_primary
Matches only the primary name.
@ m_secondary
Matches only the secondary name.
token_type
The token type discriminator.
@ t_flag_compound
Represents a compound flag argument (secondary flag matching multiple arguments).
@ t_value
Represents a value argument.
@ t_flag_secondary
Represents a secondary (-) flag argument.
@ t_flag_primary
Represents a primary (–) flag argument.
static invalid_configuration argument_name_used(const detail::argument_name &arg_name) noexcept
static invalid_configuration invalid_argument_name(const std::string_view arg_name, const std::string_view reason) noexcept
static lookup_failure argument_not_found(const std::string_view &arg_name) noexcept
static parsing_failure invalid_nvalues(const detail::argument_name &arg_name, const std::weak_ordering ordering) noexcept
static parsing_failure unknown_argument(const std::string_view arg_name) noexcept