API

Argo’s API consists of a number of related classes in the following namespaces:

  • argo: general objects

  • argo::action: action specific functionality

  • argo::handler: argument handlers

  • argo::program: program information

  • argo::nargs: cardinality behavior

The core functionality resides in the argo::core namespace and is not intended for direct usage by client code, with a minor exception for some of the methods of the core::Context object.

Note

A good source of API examples is to look at the unit-tests for the library.

Arguments

class Arguments

Arguments is the toplevel parser of arguments. It is configured step-by-step by iteratively adding handlers to it.

Public Functions

inline Arguments()

Default constructor.

inline explicit Arguments(const Configuration &config)

Constructs the parser with the given configuration.

inline Arguments(const Arguments &other)

Copy constructs the parser.

inline Arguments(Arguments &&other)

Move constructs the parser.

inline Arguments &operator=(const Arguments &other)

Copy assigns the parser.

inline Arguments &operator=(Arguments &&other)

Move assigns the parser.

inline const Configuration &configuration() const

Returns the configuration.

inline bool add(const core::handler::IHandler &handler)

Adds the given handler to the parser. Returns a boolean indicating success.

inline bool merge(const Arguments &other, bool replace = true)

Merges the given parser by adding all its handlers. If a handler conflicts, the handler of the other parser is used when replace = true or skipped when replace = false.

inline Result parse(const std::vector<std::string> &arguments, const bool skip_first_argument = false)

Parses the given arguments. By default, the first argument is not skipped. Useful for unit-testing or when the arguments are not directly read from argv.

template<typename CharArrayType>
inline Result parse(unsigned int argc, CharArrayType argv, const bool skip_first_argument = true)

Parses the given C-style arguments. By default, the first argument is skipped. Useful to directly pass the arguments of main where the first argument is the application’s executable name.

inline bool print_usage(std::ostream &os) const

Prints the usage section to the given output stream.

inline bool print_help(std::ostream &os) const

Prints the help section to the given output stream.

inline bool print_version(std::ostream &os) const

Prints the version section to the given output stream.

inline void set_formatter(const formatter::Interface &formatter)

Sets the output formatter.

inline const formatter::Interface &formatter() const

Returns the output formatter.

inline formatter::Interface &formatter()

Returns the output formatter.

Configuration

struct Configuration

Configuration is a structure containing parser behavior and program information.

Public Members

program::Info program = {}

Program information.

struct Parser

Public Members

bool help = true

Addition of the --help flag.

bool version = true

Addition of the --version flag.

bool responsefile = true

Addition of the default response file handler.

bool dash_names = true

Named arguments on the command line have underscores turned to dashes.

bool implicit_values = true

When false, values must explicitly be set, e.g. --option a --option b, instead of --option a b

bool argument_values = false

When true, values can be of the form --value or -v

bool empty_values = false

When true, values can be empty.

Program

The argo::program namespace contains objects holding program specific information. This is mostly useful for displaying help and output error messages.

struct program::Info

Aggregate of program-related information.

Public Members

Name name

Program name.

Description description

Program description.

Version version

Program version information.

std::string copyright

Copyright information.

struct program::Description

Holds program descriptions: goal and intended usage.

Public Members

std::string brief

Short description: a one-liner describing the program’s goal.

std::string extended

Long description which may span multiple lines.

std::string usage

Describes the program’s usage, i.e. its argument invocation. When empty, the output formatters are responsible for generating this information based on the available handlers. However, when the string is not empty, output formatters should use this instead.

struct program::Name

Holds the program’s different name aliases.

Public Members

std::string brief

Short name of the program. For example: gcc.

std::string extended

Long name of the program. For example: GNU Compiler Collection.

struct program::Version

Holds the program’s version information.

Public Functions

inline bool is_set() const

Indicates if the version is set.

Public Members

unsigned major

Major version number.

unsigned minor

Minor version number.

unsigned patch

Patch version number.

std::string githash

Git revision hash.

Handlers

Handlers are delegate parsers: the toplevel Arguments parser searches for handlers that ‘recognize’ the current argument. If found, the parsing is delegated to that handler allowing it to process any required values before yielding back control.

Handlers have certain properties:

  • Cardinality: controlled by the nargs methods, it determines the number of values a handler expects:
    • nargs(n): fixed number of n values

    • nargs("?"): zero or one value

    • nargs("*"): zero or more values

    • nargs("+"): one or more values

  • Help: controlled by the help method, it is a description of the handled argument, usually used by formatters in the help output

  • Required/Optional: controlled by the required/optional methods, they indicate whether the argument is required, i.e. must be present in the processed arguments. By default, all handlers are optional.

  • Actionable: controlled by the action method, it is a list of attached Actions that are invoked on the processed values

Options

Options are named arguments that expect values, depending on the cardinality. By default, a single value is expected.

Examples of invocations for which options are suitable are:

--bar 1
--foo 1 2 3
--foo 1 --foo 2
--foo=1,2
--foo=1,2 --foo 3

The handler::Option class implements the required behavior.

class handler::Option : public core::handler::IHandler, public core::handler::property::Named, public core::handler::property::Help<Option>, public core::handler::property::Required<Option>, public core::handler::property::Cardinality<Option>, public core::handler::property::Actionable<Option>

Handler that processes arguments with values.

Public Functions

inline explicit Option(const std::string &first, const std::string &second)

Constructs an option with a longhand and shorthand. They may be provided in any order. This constructor is useful if no direct variable binding can be done. Using this constructor implies adding a custom action later in order to create a valid Option.

inline explicit Option(const std::string &name)

Constructs an option with a longhand or shorthand. This constructor is useful if no direct variable binding can be done. Using this constructor implies adding a custom action later in order to create a valid Option.

inline explicit Option(const char *first, const char *second)

Constructs an option with a longhand and shorthand. They may be provided in any order. This constructor is useful if no direct variable binding can be done. Using this constructor implies adding a custom action later in order to create a valid Option.

inline explicit Option(const char *name)

Constructs an option with a longhand or shorthand.

template<typename Variable, typename = typename std::enable_if<!std::is_const<Variable>::value>::type>
inline explicit Option(const std::string &first, const std::string &second, Variable &variable)

Constructs an option with a longhand and shorthand. They may be provided in any order. Any values will be stored in the given variable.

template<typename Variable, typename = typename std::enable_if<!std::is_const<Variable>::value>::type>
inline explicit Option(const std::string &name, Variable &variable)

Constructs an option with a longhand or shorthand. Any values will be stored in the given variable.

inline virtual bool is_valid() const override

Indicates if the handler is correctly configured.

inline virtual std::string name() const override

Returns the handler’s name.

inline virtual std::string type() const override

Returns the handler’s type description.

inline virtual bool accept(core::handler::visitor::IConstVisitor &visitor) const override

Accepts a constant visitor. Returns a boolean indicating success.

inline virtual bool accept(core::handler::visitor::IMutatingVisitor &visitor) override

Accepts a mutating visitor. Returns a boolean indicating success.

inline virtual core::handler::Ptr clone() const override

Returns a cloned version of the handler.

inline virtual bool parse(core::Context &context) override

Takes over the parsing process in the current context. Returns a boolean indicating success.

inline virtual bool is_satisfied(core::Context &context) const override

Indicates if the handler is satisfied were the parsing to stop at this point.

inline bool has_longhand() const

Indicates if a longhand is set.

inline std::string longhand() const

Returns the longhand. Note that the longhand must be set.

inline bool has_shorthand() const

Indicates if a shorthand is set.

inline std::string shorthand() const

Returns the shorthand. Note that the shorthand must be set.

inline std::string help() const

Returns the help description.

inline Option &help(const std::string description)

Sets the help description and returns the handler.

inline bool is_required() const

Indicates if the handler is required.

inline Option &required(const Condition &condition = []() { return true;})

Marks the handler as required and returns it.

inline bool is_optional() const

Indicates if the handler is optional. This is the default state.

inline Option &optional(const Condition &condition = []() { return false;})

Marks the handler as optional and returns it.

inline Option &nargs(const std::string &type)

Sets the expected number of arguments and returns the handler.

inline Option &nargs(const unsigned nr)

Sets the expected fixed number of arguments and returns the handler.

inline std::string nargs_type() const

Returns the cardinality description.

inline std::string nargs_symbol() const

Returns the cardinality symbol.

inline Option &action(const action::IAction &action)

Adds an action to the handler and returns it.

inline Option &require(const action::IAction &requirement)

Adds a requirement to the handler and returns it. Note that this is syntactic sugar since it has the same effect as calling action.

Note that named arguments such as options always have dashed names. That is to say: adding an option --foo_bar, will silently be replaced by --foo-bar.

Toggles

Toggles are named arguments that expect at most one value. This value must be ‘truthy’: something that can be interpreted as either true or false. The following table indicates which values (case insensitive) are considered true or false.

Value

Interpretation

true

true

1

true

yes

true

y

true

false

false

0

false

no

false

n

false

Any other value results in an error. Note that this intepretation is not limited to toggles and holds for any type conversion to a bool.

A useful feature for toggles is that they automagically support negations. For example, adding a toggle --debug mapped to bool debug = false would not only set debug=true when --debug true is parsed, but would also set it to true if --no-debug false is parsed.

Consider the following toy example:

struct {
   bool debug = default_value;
} options;
Arguments args;
args.add(handler::Toggle{"--debug", options.debug});
const auto result = args.parse(raw_args);
std::cout << std::boolalpha << options.debug << std::endl;

This would result in the following input/output table:

Command line

default_value

Output

–debug

true

true

–debug true

true

true

–debug false

true

false

–no-debug

true

false

–no-debug true

true

false

–no-debug false

true

true

–debug

false

true

–debug true

false

true

–debug false

false

false

–no-debug

false

false

–no-debug true

false

false

–no-debug false

false

true

The handler::Toggle class implements the required behavior.

class handler::Toggle : public core::handler::IHandler, public core::handler::property::Named, public core::handler::property::Help<Toggle>, public core::handler::property::Required<Toggle>, public core::handler::property::Actionable<Toggle>

A handler that processes toggles: arguments that toggle boolean values.

Public Functions

inline explicit Toggle(const std::string &first, const std::string &second, const std::function<bool(core::Context&, const bool)> &setter)

Constructs a toggle with a longhand and shorthand. They may be provided in any order. The passed setter function will be called with the truthy value when the handler is triggered. This version of the setter function can alter the parsing process.

inline explicit Toggle(const std::string &first, const std::string &second, const std::function<void(const bool)> &setter)

Constructs a toggle with a longhand and shorthand. They may be provided in any order. The passed setter function will be called with the truthy value when the handler is triggered. This version of the setter function cannot alter the parsing process.

inline explicit Toggle(const std::string &first, const std::string &second, const std::function<bool(core::Context&, const bool)> &setter, const std::function<bool()> &getter)

Constructs a toggle with a longhand and shorthand. They may be provided in any order. The passed setter function will be called with the truthy value when the handler is triggered. This version of the setter function can alter the parsing process. The passed getter is useful for formatters to display helpful output.

inline explicit Toggle(const std::string &first, const std::string &second, bool &variable)

Constructs a toggle with a longhand and shorthand. They may be provided in any order. The passed variable will be toggled when the handler is triggered.

inline explicit Toggle(const std::string &name, const std::function<bool(core::Context&, const bool)> &setter)

Constructs a toggle with a longhand or shorthand. The passed setter function will be called with the truthy value when the handler is triggered. This version of the setter function cal alter the parsing process.

inline explicit Toggle(const std::string &name, const std::function<void(const bool)> &setter)

Constructs a toggle with a longhand or shorthand. The passed setter function will be called with the truthy value when the handler is triggered. This version of the setter function cannot alter the parsing process.

inline explicit Toggle(const std::string &name, const std::function<bool(core::Context&, const bool)> &setter, const std::function<bool()> &getter)

Constructs a toggle with a longhand or shorthand. The passed setter function will be called with the truthy value when the handler is triggered. This version of the setter function cannot alter the parsing process. The passed getter is useful for formatters to display helpful output.

inline explicit Toggle(const std::string &name, bool &variable)

Constructs a toggle with a longhand or shorthand. The passed variable will be toggled when the handler is triggered.

inline virtual bool is_valid() const override

Indicates if the handler is correctly configured.

inline virtual std::string name() const override

Returns the handler’s name.

inline virtual std::string type() const override

Returns the handler’s type description.

inline Toggle &with_negation(const std::string &longhand)

Sets the negation longhand. For example, constructing a “–debug” toggle will automatically respond to a “–no-debug” argument. If the latter name is to be different, it can be set using this method.

inline std::string negation_longhand() const

Returns the negation longhand.

inline bool has_default_value() const

Indicates if the default value is available.

inline bool default_value() const

Returns the default value. This assumes has_default_value() returns true.

inline virtual bool accept(core::handler::visitor::IConstVisitor &visitor) const override

Accepts a constant visitor. Returns a boolean indicating success.

inline virtual bool accept(core::handler::visitor::IMutatingVisitor &visitor) override

Accepts a mutating visitor. Returns a boolean indicating success.

inline virtual core::handler::Ptr clone() const override

Returns a cloned version of the handler.

inline virtual bool parse(core::Context &context) override

Takes over the parsing process in the current context. Returns a boolean indicating success.

inline virtual bool is_satisfied(core::Context &context) const override

Indicates if the handler is satisfied were the parsing to stop at this point.

inline bool has_longhand() const

Indicates if a longhand is set.

inline std::string longhand() const

Returns the longhand. Note that the longhand must be set.

inline bool has_shorthand() const

Indicates if a shorthand is set.

inline std::string shorthand() const

Returns the shorthand. Note that the shorthand must be set.

inline std::string help() const

Returns the help description.

inline Toggle &help(const std::string description)

Sets the help description and returns the handler.

inline bool is_required() const

Indicates if the handler is required.

inline Toggle &required(const Condition &condition = []() { return true;})

Marks the handler as required and returns it.

inline bool is_optional() const

Indicates if the handler is optional. This is the default state.

inline Toggle &optional(const Condition &condition = []() { return false;})

Marks the handler as optional and returns it.

inline Toggle &action(const action::IAction &action)

Adds an action to the handler and returns it.

inline Toggle &require(const action::IAction &requirement)

Adds a requirement to the handler and returns it. Note that this is syntactic sugar since it has the same effect as calling action.

Flags

Flags are named arguments that do not expect any value. They serve as triggers, nothing more.

Examples of invocations for which flags are suitable are:

--foo

The handler::Flag class implements the required behavior.

class handler::Flag : public core::handler::IHandler, public core::handler::property::Named, public core::handler::property::Help<Flag>, public core::handler::property::Required<Flag>, public core::handler::property::Actionable<Flag>

A handler that processes flags: shorthand or longhand arguments without values.

Public Functions

inline explicit Flag(const std::string &first, const std::string &second)

Constructs a flag with a longhand and shorthand. They may be provided in any order.

inline explicit Flag(const std::string &name)

Constructs an option with a longhand or shorthand.

inline virtual bool is_valid() const override

Indicates if the handler is correctly configured.

inline virtual std::string name() const override

Returns the handler’s name.

inline virtual std::string type() const override

Returns the handler’s type description.

inline virtual bool accept(core::handler::visitor::IConstVisitor &visitor) const override

Accepts a constant visitor. Returns a boolean indicating success.

inline virtual bool accept(core::handler::visitor::IMutatingVisitor &visitor) override

Accepts a mutating visitor. Returns a boolean indicating success.

inline virtual core::handler::Ptr clone() const override

Returns a cloned version of the handler.

inline virtual bool parse(core::Context &context) override

Takes over the parsing process in the current context. Returns a boolean indicating success.

inline virtual bool is_satisfied(core::Context &context) const override

Indicates if the handler is satisfied were the parsing to stop at this point.

inline bool has_longhand() const

Indicates if a longhand is set.

inline std::string longhand() const

Returns the longhand. Note that the longhand must be set.

inline bool has_shorthand() const

Indicates if a shorthand is set.

inline std::string shorthand() const

Returns the shorthand. Note that the shorthand must be set.

inline std::string help() const

Returns the help description.

inline Flag &help(const std::string description)

Sets the help description and returns the handler.

inline bool is_required() const

Indicates if the handler is required.

inline Flag &required(const Condition &condition = []() { return true;})

Marks the handler as required and returns it.

inline bool is_optional() const

Indicates if the handler is optional. This is the default state.

inline Flag &optional(const Condition &condition = []() { return false;})

Marks the handler as optional and returns it.

inline Flag &action(const action::IAction &action)

Adds an action to the handler and returns it.

inline Flag &require(const action::IAction &requirement)

Adds a requirement to the handler and returns it. Note that this is syntactic sugar since it has the same effect as calling action.

Positional arguments

Positional arguments are unnamed arguments which are actually references to values passed in the command line, like a list of input or output files. Argo first looks for options, custom handlers, and then positional arguments. Care needs to be taken with positional arguments. For example, it generally doesn’t make much sense to have more than one positional argument with nargs = "*". This is in contrast with options, where it could make sense to multiple optional arguments with nargs="*".

Examples of invocations for which positional arguments are suitable are:

a.cpp.obj b.cpp.obj c.a

The handler::Positional class implements the required behavior.

class handler::Positional : public core::handler::IHandler, public core::handler::property::Help<Positional>, public core::handler::property::Required<Positional>, public core::handler::property::Cardinality<Positional>, public core::handler::property::Actionable<Positional>

A handler that processes positional arguments: unnamed arguments that signal values.

Public Functions

inline explicit Positional(const std::string &name)

Constructs the positional handler with the given name. Note that the name may not be a shorthand or longhand. It is merely used in the generation of help output and error messages.

template<typename Variable>
inline explicit Positional(const std::string &name, Variable &variable)

Constructs the positional handler with the given name. Note that the name may not be a shorthand or longhand. It is merely used in the generation of help output and error messages. Any values are stored in the given variable.

inline virtual bool is_valid() const override

Indicates if the handler is correctly configured.

inline virtual std::string name() const override

Returns the handler’s name.

inline virtual std::string type() const override

Returns the handler’s type description.

inline virtual bool accept(core::handler::visitor::IConstVisitor &visitor) const override

Accepts a constant visitor. Returns a boolean indicating success.

inline virtual bool accept(core::handler::visitor::IMutatingVisitor &visitor) override

Accepts a mutating visitor. Returns a boolean indicating success.

inline virtual core::handler::Ptr clone() const override

Returns a cloned version of the handler.

inline virtual bool parse(core::Context &context) override

Takes over the parsing process in the current context. Returns a boolean indicating success.

inline virtual bool is_satisfied(core::Context &context) const override

Indicates if the handler is satisfied were the parsing to stop at this point.

inline std::string help() const

Returns the help description.

inline Positional &help(const std::string description)

Sets the help description and returns the handler.

inline bool is_required() const

Indicates if the handler is required.

inline Positional &required(const Condition &condition = []() { return true;})

Marks the handler as required and returns it.

inline bool is_optional() const

Indicates if the handler is optional. This is the default state.

inline Positional &optional(const Condition &condition = []() { return false;})

Marks the handler as optional and returns it.

inline Positional &nargs(const std::string &type)

Sets the expected number of arguments and returns the handler.

inline Positional &nargs(const unsigned nr)

Sets the expected fixed number of arguments and returns the handler.

inline std::string nargs_type() const

Returns the cardinality description.

inline std::string nargs_symbol() const

Returns the cardinality symbol.

inline Positional &action(const action::IAction &action)

Adds an action to the handler and returns it.

inline Positional &require(const action::IAction &requirement)

Adds a requirement to the handler and returns it. Note that this is syntactic sugar since it has the same effect as calling action.

Interface

Custom handlers can be implemented by subclassing the handler::Interface class. For example, the default response file handler class handler::ResponseFile is actually does this.

class handler::Interface : public core::handler::IHandler, public core::handler::property::Help<Interface>

A handler that can serve as a base class for custom handlers.

Subclassed by handler::ResponseFile

Public Functions

virtual std::string help() const = 0

Returns the help description.

virtual bool is_valid() const = 0

Indicates if the handler is correctly configured.

virtual std::string name() const = 0

Returns the handler’s name.

virtual std::string type() const = 0

Returns the handler’s type description.

virtual Ptr clone() const = 0

Returns a cloned version of the handler.

virtual bool parse(Context &context) = 0

Takes over the parsing process in the current context. Returns a boolean indicating success.

virtual bool is_satisfied(Context &context) const = 0

Indicates if the handler is satisfied were the parsing to stop at this point.

inline Interface &help(const std::string description)

Sets the help description and returns the handler.

Response files

Response files are files containing command line arguments. See ResponseFile. The required behavior is implemented by the handler::ResponseFile class.

class handler::ResponseFile : public handler::Interface

A handler that processes response files.

Public Functions

inline explicit ResponseFile(const std::string &identifier = "@")

Constructs the response file handler with the given identifier. By default, the commonly used @ character is chosen. As such, invocations such as ./app @/path/to/response/file.rsp are processed by this handler. Note that the path to the response file must immediately follow the identifier string. In the case of the @character there is therefore no white space between the @ the response file.

inline virtual bool is_valid() const override

Indicates if the handler is correctly configured.

inline virtual std::string name() const override

Returns the handler’s name.

inline virtual std::string type() const override

Returns the handler’s type description.

inline virtual std::string help() const override

Returns the help description.

inline Interface &help(const std::string description)

Sets the help description and returns the handler.

Groups

Groups are collection of handlers with limited properties:

  • a name, mostly useful for formatters

  • and an optional/ required marker

Note that the latter can override the optional/required behavior of individual handlers in the group. This behavior depends on the group type. There are three built-in group types:

Custom groups

The handler::group hierarchy can be extended. It suffices to subclass the handler::group::Interface and implement the clone and is_satisfied methods. In fact, all built-in group types differ only in the implementation of these methods where - obviously - the latter method determines the group behavior.

class handler::group::Interface : public core::handler::IHandler, public core::handler::property::Help<Interface>, public core::handler::property::Required<Interface>

Subclassed by handler::group::Exclusive, handler::group::Inclusive, handler::group::Simple

Public Functions

inline explicit Interface(const std::string &name, const std::string &type)

Constructs the group with the given name and type description.

inline Interface(const Interface &other)

Copy constructs the group.

inline Interface &operator=(const Interface &other)

Copy assigns the group.

inline virtual bool is_valid() const override

Indicates if the handler is correctly configured.

inline virtual std::string name() const override

Returns the handler’s name.

inline virtual bool accept(core::handler::visitor::IConstVisitor &visitor) const override

Accepts a constant visitor. Returns a boolean indicating success.

inline virtual bool accept(core::handler::visitor::IMutatingVisitor &visitor) override

Accepts a mutating visitor. Returns a boolean indicating success.

inline virtual std::string type() const override

Returns the handler’s type description.

virtual Ptr clone() const = 0

Returns a cloned version of the handler.

virtual bool is_satisfied(Context &context) const = 0

Indicates if the handler is satisfied were the parsing to stop at this point.

inline std::string help() const

Returns the help description.

inline Interface &help(const std::string description)

Sets the help description and returns the handler.

inline bool is_required() const

Indicates if the handler is required.

inline Interface &required(const Condition &condition = []() { return true;})

Marks the handler as required and returns it.

inline bool is_optional() const

Indicates if the handler is optional. This is the default state.

inline Interface &optional(const Condition &condition = []() { return false;})

Marks the handler as optional and returns it.

Simple groups

All handlers in a simple group must be satisfied, i.e. their properties such as expected number of arguments, required, etc. must be met. Additionally, optional simple groups do not require any of the handlers to have been triggered. On the other hand, required simple groups must have at least one handler that triggered during the parsing process.

For practical examples, check out the unit-tests.

class handler::group::Simple : public handler::group::Interface

Group that holds a simple collection of handlers.

Public Functions

inline virtual bool is_valid() const override

Indicates if the handler is correctly configured.

inline virtual std::string name() const override

Returns the handler’s name.

inline virtual bool accept(core::handler::visitor::IConstVisitor &visitor) const override

Accepts a constant visitor. Returns a boolean indicating success.

inline virtual bool accept(core::handler::visitor::IMutatingVisitor &visitor) override

Accepts a mutating visitor. Returns a boolean indicating success.

inline virtual std::string type() const override

Returns the handler’s type description.

inline std::string help() const

Returns the help description.

inline Interface &help(const std::string description)

Sets the help description and returns the handler.

inline bool is_required() const

Indicates if the handler is required.

inline Interface &required(const Condition &condition = []() { return true;})

Marks the handler as required and returns it.

inline bool is_optional() const

Indicates if the handler is optional. This is the default state.

inline Interface &optional(const Condition &condition = []() { return false;})

Marks the handler as optional and returns it.

Inclusive groups

The presence of handlers in an inclusive group is forced depending on whether any handler within the group triggered. In other words, if one handler is triggered then all other handlers must be triggered as well. Additionally, optional inclusive groups do not require any of the handlers to have been triggered (even those marked as required) whereas required inclusive groups enforce the presence of all handlers. Put simply: a required inclusive groups is equivalent to a simple group (be it optional or required) where all handlers of the simple group are required.

For practical examples, check out the unit-tests.

class handler::group::Inclusive : public handler::group::Interface

Group in which the presence of any one option/group within it, forces the presence of the others.

Public Functions

inline virtual core::handler::Ptr clone() const override

Returns a cloned version of the handler.

inline virtual bool is_satisfied(core::Context &context) const override

Indicates if the handler is satisfied were the parsing to stop at this point.

inline virtual bool is_valid() const override

Indicates if the handler is correctly configured.

inline virtual std::string name() const override

Returns the handler’s name.

inline virtual bool accept(core::handler::visitor::IConstVisitor &visitor) const override

Accepts a constant visitor. Returns a boolean indicating success.

inline virtual bool accept(core::handler::visitor::IMutatingVisitor &visitor) override

Accepts a mutating visitor. Returns a boolean indicating success.

inline virtual std::string type() const override

Returns the handler’s type description.

inline std::string help() const

Returns the help description.

inline Interface &help(const std::string description)

Sets the help description and returns the handler.

inline bool is_required() const

Indicates if the handler is required.

inline Interface &required(const Condition &condition = []() { return true;})

Marks the handler as required and returns it.

inline bool is_optional() const

Indicates if the handler is optional. This is the default state.

inline Interface &optional(const Condition &condition = []() { return false;})

Marks the handler as optional and returns it.

Exclusive groups

Similarly to inclusive groups, the presence of handlers in an exclusive group is forced depending on whether any handler within the group triggered. In other words, if one handler is triggered then none ofthe other handlers must be triggered as well. Additionally, optional exclusive groups do not require a single handler to have been triggered (even those marked as required).

For practical examples, check out the unit-tests.

class handler::group::Exclusive : public handler::group::Interface

Group in which the presence of any one option/group within it, forces the exclusion of the others.

Public Functions

inline virtual core::handler::Ptr clone() const override

Returns a cloned version of the handler.

inline virtual bool is_satisfied(core::Context &context) const override

Indicates if the handler is satisfied were the parsing to stop at this point.

inline virtual bool is_valid() const override

Indicates if the handler is correctly configured.

inline virtual std::string name() const override

Returns the handler’s name.

inline virtual bool accept(core::handler::visitor::IConstVisitor &visitor) const override

Accepts a constant visitor. Returns a boolean indicating success.

inline virtual bool accept(core::handler::visitor::IMutatingVisitor &visitor) override

Accepts a mutating visitor. Returns a boolean indicating success.

inline virtual std::string type() const override

Returns the handler’s type description.

inline std::string help() const

Returns the help description.

inline Interface &help(const std::string description)

Sets the help description and returns the handler.

inline bool is_required() const

Indicates if the handler is required.

inline Interface &required(const Condition &condition = []() { return true;})

Marks the handler as required and returns it.

inline bool is_optional() const

Indicates if the handler is optional. This is the default state.

inline Interface &optional(const Condition &condition = []() { return false;})

Marks the handler as optional and returns it.

Note

It is left up to the user to make sure that handlers contained in exclusive groups play well. For instance, placing more than one required handler in an exclusive group will most likely not be the sought after behavior.

Actions

Actions are callbacks attached to handlers. They are a central part of Argo’s architecture: when a handler consumes a value, all attached handlers are invoked with the value. They can then do any required computation or modify the parsing process using the core::Context class. For instance, they can generate errors or abort the parsing.

The most useful action is the action::run() action with all its overloads:

template<typename Type = std::string>
Run<Type> action::run(const typename Run<Type>::function_type &fnc)

Creates an action that accepts a callback with prototype bool(const Type). By default, Type = std::string.

template<typename Type = std::string>
Run<Type> action::run(const typename Run<Type>::function_with_context_type &fnc)

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

Warning

doxygenfunction: Unable to resolve function “action::run” with arguments (const std::function<boolcore::Context&>&) in doxygen xml output for project “Argo” from directory: ../doxyxml/. Potential matches:

- Run<std::string> run(const std::function<bool(core::Context&)> &fnc)
- Run<std::string> run(const std::function<void()> &fnc)
- template<typename Type = std::string> Run<Type> run(const typename Run<Type>::function_type &fnc)
- template<typename Type = std::string> Run<Type> run(const typename Run<Type>::function_with_context_type &fnc)

Warning

doxygenfunction: Unable to resolve function “action::run” with arguments (const std::function<void>&) in doxygen xml output for project “Argo” from directory: ../doxyxml/. Potential matches:

- Run<std::string> run(const std::function<bool(core::Context&)> &fnc)
- Run<std::string> run(const std::function<void()> &fnc)
- template<typename Type = std::string> Run<Type> run(const typename Run<Type>::function_type &fnc)
- template<typename Type = std::string> Run<Type> run(const typename Run<Type>::function_with_context_type &fnc)

All action::run() actions are free functions that return an action::Run which implements action::Interface:

template<typename Type>
class Run : public action::Interface<Type>

Action that performs all required conversions and then invokes the associated callback function.

When designing complex actions, it might be necessary to subclass action::Interface. However, this is very unlikely and it will usually be sufficient to create a callback and pass it to action::Run. In fact, this is how the other built-in action action::store() (with all the overloads) is implemented:

template<typename Type, typename ConstType>
Run<Type> action::store(Type &variable, ConstType const_value)

Stores the const_value in the given variable when the associated handler triggers. ConstType must be copy-assignable to Type.

template<typename Type>
Run<Type> action::store(Type &variable)

Stores the parsed value in the given variable.

template<typename Type>
Run<Type> action::store(std::list<Type> &variable)

Appends the parsed values in-order to the given list.

template<typename Type>
Run<Type> action::store(std::set<Type> &variable)

Inserts the parsed values in the given set.

template<typename Type>
Run<Type> action::store(std::vector<Type> &variable)

Appends the parsed values in-order to the given vector.

Warning

Client-code must take care not to pass in lambda expressions which hold references to variables that are out-of-scope at the time of execution of the lambda expressions. The latter happens during the parsing.

Requirements

Requirements reflect restrictions that apply to the parsed values. A collection of built-in requirements is available in the require namespace:

template<typename Collection, typename Type = typename core::traits::conversion<typename std::remove_cv<typename Collection::value_type>::type>::result_type>
action::Run<Type> require::any_of(const Collection &values)

Verifies that the parsed value is any of the given values.

template<typename Collection, typename Type = typename core::traits::conversion<typename std::remove_cv<typename Collection::value_type>::type>::result_type>
action::Run<Type> require::none_of(const Collection &values)

Verifies that the parsed value is none of the given values.

template<typename Type, typename = typename std::is_arithmetic<Type>::type>
action::Run<Type> require::greater_than(Type cutoff)

Verifies that the parsed value is greater than the given value.

template<typename Type, typename = typename std::is_arithmetic<Type>::type>
action::Run<Type> require::greater_than_or_equal(Type cutoff)

Verifies that the parsed value is greater than or equal to the given value.

template<typename Type, typename = typename std::is_arithmetic<Type>::type>
action::Run<Type> require::lesser_than(Type cutoff)

Verifies that the parsed value is lesser than the given value.

template<typename Type, typename = typename std::is_arithmetic<Type>::type>
action::Run<Type> require::lesser_than_or_equal(Type cutoff)

Verifies that the parsed value is lesser than or equal to the given value.

There are also range-based requirements in the require::range namespace:

template<typename Type, typename = typename std::is_arithmetic<Type>::type>
action::Run<Type> require::range::closed_closed(Type first, Type last)

Verifies that the parsed value lies within the range [first, last].

template<typename Type, typename = typename std::is_arithmetic<Type>::type>
action::Run<Type> require::range::closed_open(Type first, Type last)

Verifies that the parsed value lies within the range [first, last[.

template<typename Type, typename = typename std::is_arithmetic<Type>::type>
action::Run<Type> require::range::open_closed(Type first, Type last)

Verifies that the parsed value lies within the range ]first, last].

template<typename Type, typename = typename std::is_arithmetic<Type>::type>
action::Run<Type> require::range::open_open(Type first, Type last)

Verifies that the parsed value lies within the range ]first, last[.

You can of course pass your own requirements as an action. In fact, requirements are syntactic sugar since calling require has the same effect as calling action: requirements are of type action::IAction.

Type conversions

By its very nature, all command line arguments enter the application as strings. Argo takes care of all required conversions from std::string to the requested type. This type can often be deduced automatically, for instance when handlers are constructed with binding to some target variable in which to store the values. However, when attaching actions, the value must be explicitly stated. As previously mentioned, the action::Run class invokes the associated callbacks with the converted values. Most relevant built-in types are supported:

  • (unsigned) short

  • (unsigned) int

  • (unsigned) long

  • (unsigned) long long

  • float

  • double

  • bool

  • Enumeration types providing a Nr_ member as final item. This is purely a convenience utility and usage is subject to client code discretion

Note that this list implies support for all std::(u)int_<n>_t types as the latter are not part of the C++ language but defined in terms of the types listed above which are often referred to as the fundamental types.

Automatic conversions can be extended by specializing the core::traits::conversion structure. For example, the following built-in specialization provides the conversion to double precision floating point values:

template <>
struct conversion<double>
{
    using result_type = double;
    static constexpr const char *description = "a double";
    static optional<double> run(std::string value)
    {
        REPLACE_METRIC_SYMBOLS;
        double dvalue;
        if (!convert(dvalue, value)) return nullopt;
        return dvalue;
    }
};

Finally, std::optional<T> (since C++17) is optionally supported (pun intended). To enable support, define ARGO_ENABLE_STD_OPTIONAL prior to including the library:

#define ARGO_ENABLE_STD_OPTIONAL 1
#include <argo/Argo.hpp>

or in your build system, e.g. -DARGO_ENABLE_STD_OPTIONAL=1

Scientific notation and metric prefixes

Some syntactic sugar is available for conversions of numbers: scientific notation such as 2e3 and metric prefixes are recognized. For the latter, the following table indicates the supported symbols:

Prefix

Symbol

Power of 10

deka

D

1e1

hecto

h

1e2

kilo

k or K

1e3

mega

M

1e6

giga

G

1e9

tera

T

1e12

peta

P

1e15

exa

E

1e18

Result

The result of the parsing process is not much more than a status code and an optional error message. This is in contrast to other frameworks where the result is often a variant type object in which all arguments are collected. In Argo’s design, this offers very few advantages and causes more issues in the ‘success path’ (sometimes referred to as the hot path) of the code than anything else. In Argo, actions are triggered during the parsing process allowing for more type safety and a more flexible approach in the success path. Consequently, the result of the parsing is limited and given by a small aggregate.

struct Result

Aggregate holding the end result of the parsing process.

Public Members

ReturnCode status = ReturnCode::SuccessAndContinue

Return code status.

std::string message

Empty unless ReturnCode::Error, in which case it contains a descriptive error message which is intended for the end user.

std::vector<std::string> arguments

The normalized and expanded arguments that were processed. This includes normalizing invocations such as --foo 1 --foo=2,3 to --foo 1 2 3 and expanding all response files.

ReturnCode

There are three possible outcome states for the parsing process, represented by the ReturnCode enum class.

enum ReturnCode

Enumeration class that holds the three end states of the parsing process.

Values:

enumerator Error

Indicates an error occurred during parsing. The intent is to signal the application to handle the error and exit.

enumerator SuccessAndAbort

Indicates parsing was successful. The intent is to signal the application that although no error occurred, it should still abort. Usually used by flags like --help.

enumerator SuccessAndContinue

Indicates parsing was successful. The intent is to signal the application that it may proceed with normal execution.

Formatter

The format of all generated output is provided by a formatter object which implements the formatter::Interface. Formatters can be set using Arguments::set_formatter().

Interface

class formatter::Interface

Interface serving as a base class for concrete formatters.

Subclassed by formatter::Default

Public Functions

inline virtual void set_width(unsigned width)

Sets the output width. Note that a width of 0 corresponds to full width, i.e. the entire width of the terminal console.

inline virtual unsigned width() const

Returns the output width.

virtual std::string format_error(const core::Context &context, const std::string &message) const = 0

Returns the formatted error message.

virtual std::string format_usage(const core::Context &context) const = 0

Returns the formatted usage section.

virtual std::string format_help(const core::Context &context) const = 0

Returns the formatted help section.

virtual std::string format_version(const core::Context &context) const = 0

Returns the formatted version section.

Default

The default formatter provides clear, helpful and beautiful output. It also supports colors via ANSI escape codes. It can in itself serve as a base class for custom formatters.

class formatter::Default : public formatter::Interface

Default formatter.

Public Functions

inline virtual unsigned width() const override

Returns the output width.

inline virtual std::string format_error(const core::Context &context, const std::string &message) const override

Returns the formatted error message.

inline virtual std::string format_usage(const core::Context &context) const override

Returns the formatted usage section.

inline virtual std::string format_help(const core::Context &context) const override

Returns the formatted help section.

inline virtual std::string format_version(const core::Context &context) const override

Returns the formatted version section.

inline virtual void set_width(unsigned width)

Sets the output width. Note that a width of 0 corresponds to full width, i.e. the entire width of the terminal console.

ResponseFile

As an alternative to placing all the options on the command line, some applications accept special files called response files: plain text files that list command line arguments. This may be useful due to limitations of your build environment or as a convenience for your build process. Arguments in a response file are interpreted as if they were present at that place in the invocation. Each argument in a response file must begin and end on the same line. You cannot use the backslash character to concatenate lines. Comments are supported by prefixing lines with the // characters, similar to C/C++ comments.

An example of an invocation with a response file could look like:

$ ./app --foo @options.rsp

where options.rsp might look like:

//This is a response file listing some command line arguments
--bar
--foobar 1 2 3
//--barfoo
--barbar foofoo

In the above example, the invocation would be equivalent to:

$ ./app --foo --bar --foobar 1 2 3 --barbar foofoo

On Windows, response files can be a necessary way of circumventing the limitations of the CreateProcessA API function, which limits the command line string to 32,768 characters.

Argo has built-in support for response files via the handler::ResponseFile argument handler. If a custom response file handler is required, the ResponseFile parser class can be used for the implementation:

class ResponseFile

Response file parser.

Public Functions

inline bool parse(const std::string &filename)

Parses the given reponse file and returns a boolean indicating success.

inline std::string filename() const

Returns the filename of the last parsed response file.

inline int argc() const

Returns the number of parsed arguments.

inline std::vector<std::string> argv() const

Returns the parsed arguments.

Note that one or more response files may be provided in an invocation and that these may be combined with other command line arguments. Furthermore, response file parsing is enabled by default in the Configuration.

Core Functionality

This section limits itself to the core functionality that is likely to be used by client code, i.e. low threshold usage. More intrusive development will require consulting the actual code.

The primary class with which interaction is likely is the core::Context, a class which holds the parsing context: the active parser, its configuration, the current argument to be processed, etc.

class core::Context

Class that allows access and modification of the parsing state.

Public Functions

inline Error error()

Returns an Error object for usage within the caller’s scope. The result’s status will be set to ReturnCode::Error.

inline void abort()

Signals the parsing to process to abort. The result’s status will be set to ReturnCode::SuccessAndAbort.

inline void switch_parser(Arguments &parser)

Switches to another parser which will continue the processing using the current context.

inline bool is_current_parser(const Arguments &parser)

Indicates if the given parser is the parser processing the current context.

inline const Configuration &config() const

Returns the configuration of the active parser.

Another widely used class is the core::Error class, which is a helper utility class for generating error messages.

class core::Error

Class that sets the current result’s status to ReturnCode::Error and assigns the given message.

Public Functions

template<typename T>
inline Error &operator<<(T &&value)

Appends the given message and returns the object.

For example, the following code attaches an action to handler to validate some input. If the input doesn’t satisfy some criterium, it ends the parsing process with an error message:

handler.action(action::run<unsigned int>([](core::Context &context, unsigned int value) {
   if (value % 2 == 0)
   {
      context.error() << "Value must be even (not " << value << ")";
      return false;
   }
   else return true;
}));