[libcamera-devel,03/30] cam: options: Document the options parser API
diff mbox series

Message ID 20210707021941.20804-4-laurent.pinchart@ideasonboard.com
State Superseded
Headers show
Series
  • Multi-camera support in the cam application
Related show

Commit Message

Laurent Pinchart July 7, 2021, 2:19 a.m. UTC
Before extending the option parser, document its existing API.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 src/cam/options.cpp | 399 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 399 insertions(+)

Comments

Kieran Bingham July 12, 2021, 1:28 p.m. UTC | #1
Hi Laurent,

On 07/07/2021 03:19, Laurent Pinchart wrote:
> Before extending the option parser, document its existing API.
> 
> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> ---
>  src/cam/options.cpp | 399 ++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 399 insertions(+)
> 
> diff --git a/src/cam/options.cpp b/src/cam/options.cpp
> index 41968caa0ccb..da218c4644d3 100644
> --- a/src/cam/options.cpp
> +++ b/src/cam/options.cpp
> @@ -13,10 +13,80 @@
>  
>  #include "options.h"
>  
> +/**
> + * \enum OptionArgument
> + * \brief Indicate if an option takes an argument
> + *
> + * \var OptionArgument::ArgumentNone
> + * \brief The option doesn't accept any argument
> + *
> + * \var OptionArgument::ArgumentRequired
> + * \brief The option requires an argument
> + *
> + * \var OptionArgument::ArgumentOptional
> + * \brief The option accepts an optional argument
> + */
> +
> +/**
> + * \enum OptionType
> + * \brief The type of argument for an option
> + *
> + * \var OptionType::OptionNone
> + * \brief No argument type, used for options that take no argument
> + *
> + * \var OptionType::OptionInteger
> + * \brief Integer argument type, with an optional base prefix (`0` for base 8,
> + * `0x` for base 16, none for base 10)
> + *
> + * \var OptionType::OptionString
> + * \brief String argument
> + *
> + * \var OptionType::OptionKeyValue
> + * \brief key=value list argument
> + */
> +
>  /* -----------------------------------------------------------------------------
>   * Option
>   */
>  
> +/**
> + * \struct Option
> + * \brief Store metadata about an option
> + *
> + * \var Option::opt
> + * \brief The option identifier
> + *
> + * \var Option::type
> + * \brief The type of the option argument
> + *
> + * \var Option::name
> + * \brief The option name
> + *
> + * \var Option::argument
> + * \brief Whether the option accepts an optional argument, a mandatory
> + * argument, or no argument at all
> + *
> + * \var Option::argumentName
> + * \brief The argument name used in the help text
> + *
> + * \var Option::help
> + * \brief The help text (may be a multi-line string)
> + *
> + * \var Option::keyValueParser
> + * \brief For options of type OptionType::OptionKeyValue, the key-value parser
> + * to parse the argument
> + *
> + * \var Option::isArray
> + * \brief Whether the option can appear once or multiple times

That sounds either odd or vague. Is that really the correct definition?

Does the option appear multiple times, or does it store multiple values?



> + *
> + * \fn Option::hasShortOption()
> + * \brief Tell if the option has a short option specifier (e.g. `-f`)
> + * \return True if the option has a short option specifier, false otherwise
> + *
> + * \fn Option::hasLongOption()
> + * \brief Tell if the option has a long option specifier (e.g. `--foo`)
> + * \return True if the option has a long option specifier, false otherwise
> + */
>  struct Option {
>  	int opt;
>  	OptionType type;
> @@ -32,6 +102,10 @@ struct Option {
>  	const char *typeName() const;
>  };
>  
> +/**
> + * \brief Retrieve a string describing the option type
> + * \return A string describing the option type
> + */
>  const char *Option::typeName() const
>  {
>  	switch (type) {
> @@ -55,24 +129,65 @@ const char *Option::typeName() const
>   * OptionBase<T>
>   */
>  
> +/**
> + * \class template<typename T> OptionBase
> + * \brief Container to store the values of parsed options
> + * \tparam T The type through which options are identified
> + *
> + *

Is this double line intentional?


> + * The OptionsBase class is generated by a parser (either OptionsParser or
> + * KeyValueParser) when parsing options. It stores values for all the options
> + * found, and exposes accessor functions to retrieve them. The options are
> + * accessed through an identifier to type \a T, which is an int referencing an
> + * Option::opt for OptionsParser, or a std::string referencing an Option::name
> + * for KeyValueParser.
> + */
> +
> +/**
> + * \fn OptionsBase::OptionsBase()
> + * \brief Construct an OptionsBase instance
> + *
> + * The constructed instance is initially invalid, and will be populated by the
> + * options parser.
> + */
> +
> +/**
> + * \brief Tell if the stored options list is empty
> + * \return True if the container is empty, false otherwise
> + */
>  template<typename T>
>  bool OptionsBase<T>::empty() const
>  {
>  	return values_.empty();
>  }
>  
> +/**
> + * \brief Tell if the options parsing completed successfully
> + * \return True if the container is returned after successfully parsing
> + * options, false if it is returned after an error was detected during parsing
> + */
>  template<typename T>
>  bool OptionsBase<T>::valid() const
>  {
>  	return valid_;
>  }
>  
> +/**
> + * \brief Tell if the option \a opt is specified
> + * \param[in] opt The option to search for
> + * \return True if the \a opt option is set, false otherwise
> + */
>  template<typename T>
>  bool OptionsBase<T>::isSet(const T &opt) const
>  {
>  	return values_.find(opt) != values_.end();
>  }
>  
> +/**
> + * \brief Retrieve the value of option \a opt
> + * \param[in] opt The option to retrieve
> + * \return The value of option \a opt if found, an empty OptionValue otherwise
> + */
>  template<typename T>
>  const OptionValue &OptionsBase<T>::operator[](const T &opt) const
>  {
> @@ -84,6 +199,13 @@ const OptionValue &OptionsBase<T>::operator[](const T &opt) const
>  	return empty;
>  }
>  
> +/**
> + * \brief Mark the container as invalid
> + *
> + * This function can be used in a key-value parser's override of the
> + * KeyValueParser::parse() function to mark the returned options as invalid if
> + * a validation error occurs.
> + */
>  template<typename T>
>  void OptionsBase<T>::invalidate()
>  {
> @@ -144,9 +266,46 @@ template class OptionsBase<std::string>;
>   * KeyValueParser
>   */
>  
> +/**
> + * \class KeyValueParser
> + * \brief A specialized parser for list of key-value pairs
> + *
> + * The KeyValueParser is an options parser for comma-separated lists of
> + * `key=value` pairs. The supported keys are added to the parser with
> + * addOption(). A given key can only appear once in the parsed list.
> + *
> + * Instances of this class can be passed to the OptionsParser::addOption()
> + * function to create options that take key-value pairs as an option argument.
> + * Specialized versions of the key-value parser can be created by inheriting
> + * from this class, to pre-build the options list in the constructor, and to add
> + * custom validation by overriding the parse() function.
> + */
> +
> +/**
> + * \class KeyValueParser::Options
> + * \brief An options list generated by the key-value parser
> + *
> + * This is a specialization of OptionsBase with the option reference type set to
> + * std::string.
> + */
> +
>  KeyValueParser::KeyValueParser() = default;
>  KeyValueParser::~KeyValueParser() = default;
>  
> +/**
> + * \brief Add a supported option to the parser
> + * \param[in] name The option name, corresponding to the key name in the
> + * key=value pair. The name shall be unique.
> + * \param[in] type The type of the value in the key=value pair
> + * \param[in] help The help text
> + * \param[in] argument Whether the value is optional, mandatory or not allowed.
> + * Shall be ArgumentNone if \a type is OptionNone.
> + *
> + * \sa OptionsParser
> + *
> + * \return True if the option was added successfully, false if an error
> + * occurred.
> + */
>  bool KeyValueParser::addOption(const char *name, OptionType type,
>  			       const char *help, OptionArgument argument)
>  {
> @@ -166,6 +325,17 @@ bool KeyValueParser::addOption(const char *name, OptionType type,
>  	return true;
>  }
>  
> +/**
> + * \brief Parse a string containing a list of key-value pairs
> + * \param[in] arguments The key-value pairs string to parse
> + *
> + * If a parsing error occurs, the parsing stops and the function returns an
> + * invalid container. The container is populated with the options successfully
> + * parsed so far.
> + *
> + * \return A valid container with the list of parsed options on success, or an
> + * invalid container otherwise
> + */
>  KeyValueParser::Options KeyValueParser::parse(const char *arguments)
>  {
>  	Options options;
> @@ -278,31 +448,98 @@ void KeyValueParser::usage(int indent)
>   * OptionValue
>   */
>  
> +/**
> + * \class OptionValue
> + * \brief Container to store the value of an option
> + *
> + * The OptionValue class is a variant-type container to store the value of an
> + * option. It supports empty values, integers, strings, key-value lists, as well
> + * as arrays of those types. For array values, all array elements shall have the
> + * same type.
> + */
> +
> +/**
> + * \enum OptionValue::ValueType
> + * \brief The option value type
> + *
> + * \var OptionValue::ValueType::ValueNone
> + * \brief Empty value
> + *
> + * \var OptionValue::ValueType::ValueInteger
> + * \brief Integer value (int)
> + *
> + * \var OptionValue::ValueType::ValueString
> + * \brief String value (std::string)
> + *
> + * \var OptionValue::ValueType::ValueKeyValue
> + * \brief Key-value list value (KeyValueParser::Options)
> + *
> + * \var OptionValue::ValueType::ValueArray
> + * \brief Array value
> + */
> +
> +/**
> + * \brief Construct an empty OptionValue instance
> + *
> + * The value type is set to ValueType::ValueNone.
> + */
>  OptionValue::OptionValue()
>  	: type_(ValueNone), integer_(0)
>  {
>  }
>  
> +/**
> + * \brief Construct an integer OptionValue instance
> + * \param[in] value The integer value
> + *
> + * The value type is set to ValueType::ValueInteger.
> + */
>  OptionValue::OptionValue(int value)
>  	: type_(ValueInteger), integer_(value)
>  {
>  }
>  
> +/**
> + * \brief Construct a string OptionValue instance
> + * \param[in] value The string value
> + *
> + * The value type is set to ValueType::ValueString.
> + */
>  OptionValue::OptionValue(const char *value)
>  	: type_(ValueString), integer_(0), string_(value)
>  {
>  }
>  
> +/**
> + * \brief Construct a string OptionValue instance
> + * \param[in] value The string value
> + *
> + * The value type is set to ValueType::ValueString.
> + */
>  OptionValue::OptionValue(const std::string &value)
>  	: type_(ValueString), integer_(0), string_(value)
>  {
>  }
>  
> +/**
> + * \brief Construct a key-value OptionValue instance
> + * \param[in] value The key-value list
> + *
> + * The value type is set to ValueType::ValueKeyValue.
> + */
>  OptionValue::OptionValue(const KeyValueParser::Options &value)
>  	: type_(ValueKeyValue), integer_(0), keyValues_(value)
>  {
>  }
>  
> +/**
> + * \brief Add an entry to an array value
> + * \param[in] value The entry value
> + *
> + * This function can only be called if the OptionValue type is
> + * ValueType::ValueNone or ValueType::ValueArray. Upon return, the type will be
> + * set to ValueType::ValueArray.
> + */
>  void OptionValue::addValue(const OptionValue &value)
>  {
>  	assert(type_ == ValueNone || type_ == ValueArray);
> @@ -311,26 +548,57 @@ void OptionValue::addValue(const OptionValue &value)
>  	array_.push_back(value);
>  }
>  
> +/**
> + * \fn OptionValue::type()
> + * \brief Retrieve the value type
> + * \return The value type
> + */
> +
> +/**
> + * \brief Cast the value to an int
> + * \return The option value as an int, or 0 if the value type isn't
> + * ValueType::ValueInteger
> + */
>  OptionValue::operator int() const
>  {
>  	return toInteger();
>  }
>  
> +/**
> + * \brief Cast the value to a std::string
> + * \return The option value as an std::string, or an empty string if the value
> + * type isn't ValueType::ValueString
> + */
>  OptionValue::operator std::string() const
>  {
>  	return toString();
>  }
>  
> +/**
> + * \brief Cast the value to a key-value list
> + * \return The option value as a KeyValueParser::Options, or an empty list if
> + * the value type isn't ValueType::ValueKeyValue
> + */
>  OptionValue::operator KeyValueParser::Options() const
>  {
>  	return toKeyValues();
>  }
>  
> +/**
> + * \brief Cast the value to an array
> + * \return The option value as a std::vector of OptionValue, or an empty vector
> + * if the value type isn't ValueType::ValueArray
> + */
>  OptionValue::operator std::vector<OptionValue>() const
>  {
>  	return toArray();
>  }
>  
> +/**
> + * \brief Retrieve the value as an int
> + * \return The option value as an int, or 0 if the value type isn't
> + * ValueType::ValueInteger
> + */
>  int OptionValue::toInteger() const
>  {
>  	if (type_ != ValueInteger)
> @@ -339,6 +607,11 @@ int OptionValue::toInteger() const
>  	return integer_;
>  }
>  
> +/**
> + * \brief Retrieve the value as a std::string
> + * \return The option value as a std::string, or an empty string if the value
> + * type isn't ValueType::ValueString
> + */
>  std::string OptionValue::toString() const
>  {
>  	if (type_ != ValueString)
> @@ -347,6 +620,11 @@ std::string OptionValue::toString() const
>  	return string_;
>  }
>  
> +/**
> + * \brief Retrieve the value as a key-value list
> + * \return The option value as a KeyValueParser::Options, or an empty list if
> + * the value type isn't ValueType::ValueKeyValue
> + */
>  KeyValueParser::Options OptionValue::toKeyValues() const
>  {
>  	if (type_ != ValueKeyValue)
> @@ -355,6 +633,11 @@ KeyValueParser::Options OptionValue::toKeyValues() const
>  	return keyValues_;
>  }
>  
> +/**
> + * \brief Retrieve the value as an array
> + * \return The option value as a std::vector of OptionValue, or an empty vector
> + * if the value type isn't ValueType::ValueArray
> + */
>  std::vector<OptionValue> OptionValue::toArray() const
>  {
>  	if (type_ != ValueArray)
> @@ -367,9 +650,91 @@ std::vector<OptionValue> OptionValue::toArray() const
>   * OptionsParser
>   */
>  
> +/**
> + * \class OptionsParser
> + * \brief A command line options parser
> + *
> + * The OptionsParser class is an easy to use options parser for POSIX-style
> + * command line options. Supports short (e.g. `-f`) and long (e.g. `--foo`)
> + * options, optional and mandatory arguments, automatic parsing arguments for
> + * integer types and comma-separated list of key=value pairs, and multi-value
> + * arguments. It handles help text generation automatically.
> + *
> + * An OptionsParser instance is initialized by adding supported options with
> + * addOption(). Options are specified by an identifier and a name. If the
> + * identifier is an alphanumeric character, it will be used by the parser as a
> + * short option identifier (e.g. `-f`). The name, if specified, will be used as
> + * a long option identifier (e.g. `--foo`). It should not include the double
> + * dashes. The name is optional if the option identifier is an alphanumeric
> + * character and mandatory otherwise.
> + *
> + * An options has a mandatory help text, which is used to print the full options

s/An options/An option/ ?


> + * list with the usage() function. The help text may be a multi-line string.
> + * Correct indentation of the help text is handled automatically.
> + *
> + * Options accept arguments when created with OptionArgument::ArgumentRequired
> + * or OptionArgument::ArgumentOptional. If the argument is required, it can be
> + * specified as a positional argument after the option (e.g. `-f bar`,
> + * `--foo bar`), collated with the short option (e.g. `-fbar`) or separated from


collated doesn't quite sound like an appropriate verb there, but looking
at the first hit of the definition...

 "collect and combine (texts, information, or data)."

it sort of fits ... so I'll move on...





> + * the long option by an equal sign (e.g. `--foo=bar`'). When the argument is
> + * optional, it must be collated with the short option or separated from the
> + * long option by an equal sign.

Why do we have different behaviours when the option is optional or
mandatory - that's not very user friendly.

Does this imply that if the argument to -C was mandatory I could write
  -C 10
or -C10

but if it's optional, I can not write -C 10 ... but I have to know/find
out if it's mandatory or optional?



Anyway, that's documenting existing behaviour - not implementing - so
not a blocker on the patch...


Reveiwed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>


> + * If an option has a required or optional argument, an argument name must be
> + * set when adding the option. The argument name is used in the help text as a
> + * place holder for an argument value. For instance, a `--write` option that
> + * takes a file name as an argument could set the argument name to `filename`,
> + * and the help text would display `--write filename`. This is only used to
> + * clarify the help text and has no effect on option parsing.
> + *
> + * The option type tells the parser how to process the argument. Arguments for
> + * string options (OptionType::OptionString) are stored as-is without any
> + * processing. Arguments for integer options (OptionType::OptionInteger) are
> + * converted to an integer value, using an optional base prefix (`0` for base 8,
> + * `0x` for base 16, none for base 10). Arguments for key-value options are
> + * parsed by a KeyValueParser given to addOption().
> + *
> + * By default, a given option can appear once only in the parsed command line.
> + * If the option is created as an array option, the parser will accept multiple
> + * instances of the option. The order in which identical options are specified
> + * is preserved in the values of an array option.
> + *
> + * After preparing the parser, it can be used any number of times to parse
> + * command line options with the parse() function. The function returns an
> + * Options instance that stores the values for the parsed options. The
> + * Options::isSet() function can be used to test if an option has been found,
> + * and is the only way to access options that take no argument (specified by
> + * OptionType::OptionNone and OptionArgument::ArgumentNone). For options that
> + * accept an argument, the option value can be access by Options::operator[]()
> + * using the option identifier as the key. The order in which different options
> + * are specified on the command line isn't preserved.
> + */
> +
> +/**
> + * \class OptionsParser::Options
> + * \brief An options list generated by the options parser
> + *
> + * This is a specialization of OptionsBase with the option reference type set to
> + * int.
> + */
> +
>  OptionsParser::OptionsParser() = default;
>  OptionsParser::~OptionsParser() = default;
>  
> +/**
> + * \brief Add an option to the parser
> + * \param[in] opt The option identifier
> + * \param[in] type The type of the option argument
> + * \param[in] help The help text (may be a multi-line string)
> + * \param[in] name The option name
> + * \param[in] argument Whether the option accepts an optional argument, a
> + * mandatory argument, or no argument at all
> + * \param[in] argumentName The argument name used in the help text
> + * \param[in] array Whether the option can appear once or multiple times
> + *
> + * \return True if the option was added successfully, false if an error
> + * occurred.
> + */
>  bool OptionsParser::addOption(int opt, OptionType type, const char *help,
>  			      const char *name, OptionArgument argument,
>  			      const char *argumentName, bool array)
> @@ -395,6 +760,19 @@ bool OptionsParser::addOption(int opt, OptionType type, const char *help,
>  	return true;
>  }
>  
> +/**
> + * \brief Add a key-value pair option to the parser
> + * \param[in] opt The option identifier
> + * \param[in] parser The KeyValueParser for the option value
> + * \param[in] help The help text (may be a multi-line string)
> + * \param[in] name The option name
> + * \param[in] array Whether the option can appear once or multiple times
> + *
> + * \sa Option
> + *
> + * \return True if the option was added successfully, false if an error
> + * occurred.
> + */
>  bool OptionsParser::addOption(int opt, KeyValueParser *parser, const char *help,
>  			      const char *name, bool array)
>  {
> @@ -406,6 +784,19 @@ bool OptionsParser::addOption(int opt, KeyValueParser *parser, const char *help,
>  	return true;
>  }
>  
> +/**
> + * \brief Parse command line arguments
> + * \param[in] argc The number of arguments in the \a argv array
> + * \param[in] argv The array of arguments
> + *
> + * If a parsing error occurs, the parsing stops, the function prints an error
> + * message that identifies the invalid argument, prints usage information with
> + * usage(), and returns an invalid container. The container is populated with
> + * the options successfully parsed so far.
> + *
> + * \return A valid container with the list of parsed options on success, or an
> + * invalid container otherwise
> + */
>  OptionsParser::Options OptionsParser::parse(int argc, char **argv)
>  {
>  	OptionsParser::Options options;
> @@ -485,6 +876,14 @@ OptionsParser::Options OptionsParser::parse(int argc, char **argv)
>  	return options;
>  }
>  
> +/**
> + * \brief Print usage text to std::cerr
> + *
> + * The usage text list all the supported option with their arguments. It is
> + * generated automatically from the options added to the parser. Caller of this
> + * function may print additional usage information for the application before
> + * the list of options.
> + */
>  void OptionsParser::usage()
>  {
>  	std::cerr << "Options:" << std::endl;
>
Laurent Pinchart July 12, 2021, 6:18 p.m. UTC | #2
Hi Kieran,

On Mon, Jul 12, 2021 at 02:28:57PM +0100, Kieran Bingham wrote:
> On 07/07/2021 03:19, Laurent Pinchart wrote:
> > Before extending the option parser, document its existing API.
> > 
> > Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> > ---
> >  src/cam/options.cpp | 399 ++++++++++++++++++++++++++++++++++++++++++++
> >  1 file changed, 399 insertions(+)
> > 
> > diff --git a/src/cam/options.cpp b/src/cam/options.cpp
> > index 41968caa0ccb..da218c4644d3 100644
> > --- a/src/cam/options.cpp
> > +++ b/src/cam/options.cpp
> > @@ -13,10 +13,80 @@
> >  
> >  #include "options.h"
> >  
> > +/**
> > + * \enum OptionArgument
> > + * \brief Indicate if an option takes an argument
> > + *
> > + * \var OptionArgument::ArgumentNone
> > + * \brief The option doesn't accept any argument
> > + *
> > + * \var OptionArgument::ArgumentRequired
> > + * \brief The option requires an argument
> > + *
> > + * \var OptionArgument::ArgumentOptional
> > + * \brief The option accepts an optional argument
> > + */
> > +
> > +/**
> > + * \enum OptionType
> > + * \brief The type of argument for an option
> > + *
> > + * \var OptionType::OptionNone
> > + * \brief No argument type, used for options that take no argument
> > + *
> > + * \var OptionType::OptionInteger
> > + * \brief Integer argument type, with an optional base prefix (`0` for base 8,
> > + * `0x` for base 16, none for base 10)
> > + *
> > + * \var OptionType::OptionString
> > + * \brief String argument
> > + *
> > + * \var OptionType::OptionKeyValue
> > + * \brief key=value list argument
> > + */
> > +
> >  /* -----------------------------------------------------------------------------
> >   * Option
> >   */
> >  
> > +/**
> > + * \struct Option
> > + * \brief Store metadata about an option
> > + *
> > + * \var Option::opt
> > + * \brief The option identifier
> > + *
> > + * \var Option::type
> > + * \brief The type of the option argument
> > + *
> > + * \var Option::name
> > + * \brief The option name
> > + *
> > + * \var Option::argument
> > + * \brief Whether the option accepts an optional argument, a mandatory
> > + * argument, or no argument at all
> > + *
> > + * \var Option::argumentName
> > + * \brief The argument name used in the help text
> > + *
> > + * \var Option::help
> > + * \brief The help text (may be a multi-line string)
> > + *
> > + * \var Option::keyValueParser
> > + * \brief For options of type OptionType::OptionKeyValue, the key-value parser
> > + * to parse the argument
> > + *
> > + * \var Option::isArray
> > + * \brief Whether the option can appear once or multiple times
> 
> That sounds either odd or vague. Is that really the correct definition?
> 
> Does the option appear multiple times, or does it store multiple values?

It's really about specifying the option multiple times on the command
line. All values for the option are stored in the array of a single
OptionValue instance.

Would you express it differently ?

> > + *
> > + * \fn Option::hasShortOption()
> > + * \brief Tell if the option has a short option specifier (e.g. `-f`)
> > + * \return True if the option has a short option specifier, false otherwise
> > + *
> > + * \fn Option::hasLongOption()
> > + * \brief Tell if the option has a long option specifier (e.g. `--foo`)
> > + * \return True if the option has a long option specifier, false otherwise
> > + */
> >  struct Option {
> >  	int opt;
> >  	OptionType type;
> > @@ -32,6 +102,10 @@ struct Option {
> >  	const char *typeName() const;
> >  };
> >  
> > +/**
> > + * \brief Retrieve a string describing the option type
> > + * \return A string describing the option type
> > + */
> >  const char *Option::typeName() const
> >  {
> >  	switch (type) {
> > @@ -55,24 +129,65 @@ const char *Option::typeName() const
> >   * OptionBase<T>
> >   */
> >  
> > +/**
> > + * \class template<typename T> OptionBase
> > + * \brief Container to store the values of parsed options
> > + * \tparam T The type through which options are identified
> > + *
> > + *
> 
> Is this double line intentional?

Fixed.

> > + * The OptionsBase class is generated by a parser (either OptionsParser or
> > + * KeyValueParser) when parsing options. It stores values for all the options
> > + * found, and exposes accessor functions to retrieve them. The options are
> > + * accessed through an identifier to type \a T, which is an int referencing an
> > + * Option::opt for OptionsParser, or a std::string referencing an Option::name
> > + * for KeyValueParser.
> > + */
> > +
> > +/**
> > + * \fn OptionsBase::OptionsBase()
> > + * \brief Construct an OptionsBase instance
> > + *
> > + * The constructed instance is initially invalid, and will be populated by the
> > + * options parser.
> > + */
> > +
> > +/**
> > + * \brief Tell if the stored options list is empty
> > + * \return True if the container is empty, false otherwise
> > + */
> >  template<typename T>
> >  bool OptionsBase<T>::empty() const
> >  {
> >  	return values_.empty();
> >  }
> >  
> > +/**
> > + * \brief Tell if the options parsing completed successfully
> > + * \return True if the container is returned after successfully parsing
> > + * options, false if it is returned after an error was detected during parsing
> > + */
> >  template<typename T>
> >  bool OptionsBase<T>::valid() const
> >  {
> >  	return valid_;
> >  }
> >  
> > +/**
> > + * \brief Tell if the option \a opt is specified
> > + * \param[in] opt The option to search for
> > + * \return True if the \a opt option is set, false otherwise
> > + */
> >  template<typename T>
> >  bool OptionsBase<T>::isSet(const T &opt) const
> >  {
> >  	return values_.find(opt) != values_.end();
> >  }
> >  
> > +/**
> > + * \brief Retrieve the value of option \a opt
> > + * \param[in] opt The option to retrieve
> > + * \return The value of option \a opt if found, an empty OptionValue otherwise
> > + */
> >  template<typename T>
> >  const OptionValue &OptionsBase<T>::operator[](const T &opt) const
> >  {
> > @@ -84,6 +199,13 @@ const OptionValue &OptionsBase<T>::operator[](const T &opt) const
> >  	return empty;
> >  }
> >  
> > +/**
> > + * \brief Mark the container as invalid
> > + *
> > + * This function can be used in a key-value parser's override of the
> > + * KeyValueParser::parse() function to mark the returned options as invalid if
> > + * a validation error occurs.
> > + */
> >  template<typename T>
> >  void OptionsBase<T>::invalidate()
> >  {
> > @@ -144,9 +266,46 @@ template class OptionsBase<std::string>;
> >   * KeyValueParser
> >   */
> >  
> > +/**
> > + * \class KeyValueParser
> > + * \brief A specialized parser for list of key-value pairs
> > + *
> > + * The KeyValueParser is an options parser for comma-separated lists of
> > + * `key=value` pairs. The supported keys are added to the parser with
> > + * addOption(). A given key can only appear once in the parsed list.
> > + *
> > + * Instances of this class can be passed to the OptionsParser::addOption()
> > + * function to create options that take key-value pairs as an option argument.
> > + * Specialized versions of the key-value parser can be created by inheriting
> > + * from this class, to pre-build the options list in the constructor, and to add
> > + * custom validation by overriding the parse() function.
> > + */
> > +
> > +/**
> > + * \class KeyValueParser::Options
> > + * \brief An options list generated by the key-value parser
> > + *
> > + * This is a specialization of OptionsBase with the option reference type set to
> > + * std::string.
> > + */
> > +
> >  KeyValueParser::KeyValueParser() = default;
> >  KeyValueParser::~KeyValueParser() = default;
> >  
> > +/**
> > + * \brief Add a supported option to the parser
> > + * \param[in] name The option name, corresponding to the key name in the
> > + * key=value pair. The name shall be unique.
> > + * \param[in] type The type of the value in the key=value pair
> > + * \param[in] help The help text
> > + * \param[in] argument Whether the value is optional, mandatory or not allowed.
> > + * Shall be ArgumentNone if \a type is OptionNone.
> > + *
> > + * \sa OptionsParser
> > + *
> > + * \return True if the option was added successfully, false if an error
> > + * occurred.
> > + */
> >  bool KeyValueParser::addOption(const char *name, OptionType type,
> >  			       const char *help, OptionArgument argument)
> >  {
> > @@ -166,6 +325,17 @@ bool KeyValueParser::addOption(const char *name, OptionType type,
> >  	return true;
> >  }
> >  
> > +/**
> > + * \brief Parse a string containing a list of key-value pairs
> > + * \param[in] arguments The key-value pairs string to parse
> > + *
> > + * If a parsing error occurs, the parsing stops and the function returns an
> > + * invalid container. The container is populated with the options successfully
> > + * parsed so far.
> > + *
> > + * \return A valid container with the list of parsed options on success, or an
> > + * invalid container otherwise
> > + */
> >  KeyValueParser::Options KeyValueParser::parse(const char *arguments)
> >  {
> >  	Options options;
> > @@ -278,31 +448,98 @@ void KeyValueParser::usage(int indent)
> >   * OptionValue
> >   */
> >  
> > +/**
> > + * \class OptionValue
> > + * \brief Container to store the value of an option
> > + *
> > + * The OptionValue class is a variant-type container to store the value of an
> > + * option. It supports empty values, integers, strings, key-value lists, as well
> > + * as arrays of those types. For array values, all array elements shall have the
> > + * same type.
> > + */
> > +
> > +/**
> > + * \enum OptionValue::ValueType
> > + * \brief The option value type
> > + *
> > + * \var OptionValue::ValueType::ValueNone
> > + * \brief Empty value
> > + *
> > + * \var OptionValue::ValueType::ValueInteger
> > + * \brief Integer value (int)
> > + *
> > + * \var OptionValue::ValueType::ValueString
> > + * \brief String value (std::string)
> > + *
> > + * \var OptionValue::ValueType::ValueKeyValue
> > + * \brief Key-value list value (KeyValueParser::Options)
> > + *
> > + * \var OptionValue::ValueType::ValueArray
> > + * \brief Array value
> > + */
> > +
> > +/**
> > + * \brief Construct an empty OptionValue instance
> > + *
> > + * The value type is set to ValueType::ValueNone.
> > + */
> >  OptionValue::OptionValue()
> >  	: type_(ValueNone), integer_(0)
> >  {
> >  }
> >  
> > +/**
> > + * \brief Construct an integer OptionValue instance
> > + * \param[in] value The integer value
> > + *
> > + * The value type is set to ValueType::ValueInteger.
> > + */
> >  OptionValue::OptionValue(int value)
> >  	: type_(ValueInteger), integer_(value)
> >  {
> >  }
> >  
> > +/**
> > + * \brief Construct a string OptionValue instance
> > + * \param[in] value The string value
> > + *
> > + * The value type is set to ValueType::ValueString.
> > + */
> >  OptionValue::OptionValue(const char *value)
> >  	: type_(ValueString), integer_(0), string_(value)
> >  {
> >  }
> >  
> > +/**
> > + * \brief Construct a string OptionValue instance
> > + * \param[in] value The string value
> > + *
> > + * The value type is set to ValueType::ValueString.
> > + */
> >  OptionValue::OptionValue(const std::string &value)
> >  	: type_(ValueString), integer_(0), string_(value)
> >  {
> >  }
> >  
> > +/**
> > + * \brief Construct a key-value OptionValue instance
> > + * \param[in] value The key-value list
> > + *
> > + * The value type is set to ValueType::ValueKeyValue.
> > + */
> >  OptionValue::OptionValue(const KeyValueParser::Options &value)
> >  	: type_(ValueKeyValue), integer_(0), keyValues_(value)
> >  {
> >  }
> >  
> > +/**
> > + * \brief Add an entry to an array value
> > + * \param[in] value The entry value
> > + *
> > + * This function can only be called if the OptionValue type is
> > + * ValueType::ValueNone or ValueType::ValueArray. Upon return, the type will be
> > + * set to ValueType::ValueArray.
> > + */
> >  void OptionValue::addValue(const OptionValue &value)
> >  {
> >  	assert(type_ == ValueNone || type_ == ValueArray);
> > @@ -311,26 +548,57 @@ void OptionValue::addValue(const OptionValue &value)
> >  	array_.push_back(value);
> >  }
> >  
> > +/**
> > + * \fn OptionValue::type()
> > + * \brief Retrieve the value type
> > + * \return The value type
> > + */
> > +
> > +/**
> > + * \brief Cast the value to an int
> > + * \return The option value as an int, or 0 if the value type isn't
> > + * ValueType::ValueInteger
> > + */
> >  OptionValue::operator int() const
> >  {
> >  	return toInteger();
> >  }
> >  
> > +/**
> > + * \brief Cast the value to a std::string
> > + * \return The option value as an std::string, or an empty string if the value
> > + * type isn't ValueType::ValueString
> > + */
> >  OptionValue::operator std::string() const
> >  {
> >  	return toString();
> >  }
> >  
> > +/**
> > + * \brief Cast the value to a key-value list
> > + * \return The option value as a KeyValueParser::Options, or an empty list if
> > + * the value type isn't ValueType::ValueKeyValue
> > + */
> >  OptionValue::operator KeyValueParser::Options() const
> >  {
> >  	return toKeyValues();
> >  }
> >  
> > +/**
> > + * \brief Cast the value to an array
> > + * \return The option value as a std::vector of OptionValue, or an empty vector
> > + * if the value type isn't ValueType::ValueArray
> > + */
> >  OptionValue::operator std::vector<OptionValue>() const
> >  {
> >  	return toArray();
> >  }
> >  
> > +/**
> > + * \brief Retrieve the value as an int
> > + * \return The option value as an int, or 0 if the value type isn't
> > + * ValueType::ValueInteger
> > + */
> >  int OptionValue::toInteger() const
> >  {
> >  	if (type_ != ValueInteger)
> > @@ -339,6 +607,11 @@ int OptionValue::toInteger() const
> >  	return integer_;
> >  }
> >  
> > +/**
> > + * \brief Retrieve the value as a std::string
> > + * \return The option value as a std::string, or an empty string if the value
> > + * type isn't ValueType::ValueString
> > + */
> >  std::string OptionValue::toString() const
> >  {
> >  	if (type_ != ValueString)
> > @@ -347,6 +620,11 @@ std::string OptionValue::toString() const
> >  	return string_;
> >  }
> >  
> > +/**
> > + * \brief Retrieve the value as a key-value list
> > + * \return The option value as a KeyValueParser::Options, or an empty list if
> > + * the value type isn't ValueType::ValueKeyValue
> > + */
> >  KeyValueParser::Options OptionValue::toKeyValues() const
> >  {
> >  	if (type_ != ValueKeyValue)
> > @@ -355,6 +633,11 @@ KeyValueParser::Options OptionValue::toKeyValues() const
> >  	return keyValues_;
> >  }
> >  
> > +/**
> > + * \brief Retrieve the value as an array
> > + * \return The option value as a std::vector of OptionValue, or an empty vector
> > + * if the value type isn't ValueType::ValueArray
> > + */
> >  std::vector<OptionValue> OptionValue::toArray() const
> >  {
> >  	if (type_ != ValueArray)
> > @@ -367,9 +650,91 @@ std::vector<OptionValue> OptionValue::toArray() const
> >   * OptionsParser
> >   */
> >  
> > +/**
> > + * \class OptionsParser
> > + * \brief A command line options parser
> > + *
> > + * The OptionsParser class is an easy to use options parser for POSIX-style
> > + * command line options. Supports short (e.g. `-f`) and long (e.g. `--foo`)
> > + * options, optional and mandatory arguments, automatic parsing arguments for
> > + * integer types and comma-separated list of key=value pairs, and multi-value
> > + * arguments. It handles help text generation automatically.
> > + *
> > + * An OptionsParser instance is initialized by adding supported options with
> > + * addOption(). Options are specified by an identifier and a name. If the
> > + * identifier is an alphanumeric character, it will be used by the parser as a
> > + * short option identifier (e.g. `-f`). The name, if specified, will be used as
> > + * a long option identifier (e.g. `--foo`). It should not include the double
> > + * dashes. The name is optional if the option identifier is an alphanumeric
> > + * character and mandatory otherwise.
> > + *
> > + * An options has a mandatory help text, which is used to print the full options
> 
> s/An options/An option/ ?

Are you copying my leading questions style ? :-)

> > + * list with the usage() function. The help text may be a multi-line string.
> > + * Correct indentation of the help text is handled automatically.
> > + *
> > + * Options accept arguments when created with OptionArgument::ArgumentRequired
> > + * or OptionArgument::ArgumentOptional. If the argument is required, it can be
> > + * specified as a positional argument after the option (e.g. `-f bar`,
> > + * `--foo bar`), collated with the short option (e.g. `-fbar`) or separated from
> 
> collated doesn't quite sound like an appropriate verb there, but looking
> at the first hit of the definition...
> 
>  "collect and combine (texts, information, or data)."
> 
> it sort of fits ... so I'll move on...

I'm you think there's a more appropriate term I'll be happy to change
it.

> > + * the long option by an equal sign (e.g. `--foo=bar`'). When the argument is
> > + * optional, it must be collated with the short option or separated from the
> > + * long option by an equal sign.
> 
> Why do we have different behaviours when the option is optional or
> mandatory - that's not very user friendly.
> 
> Does this imply that if the argument to -C was mandatory I could write
>   -C 10
> or -C10
> 
> but if it's optional, I can not write -C 10 ... but I have to know/find
> out if it's mandatory or optional?

That's the getopt() behaviour. We could depart from it, but as it's a
well established standard, it may cause more harm than good. We would
also need to reimplement getopt().

> Anyway, that's documenting existing behaviour - not implementing - so
> not a blocker on the patch...
> 
> Reveiwed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>

s/Reveiwed/Reviewed/ ;-)

> > + * If an option has a required or optional argument, an argument name must be
> > + * set when adding the option. The argument name is used in the help text as a
> > + * place holder for an argument value. For instance, a `--write` option that
> > + * takes a file name as an argument could set the argument name to `filename`,
> > + * and the help text would display `--write filename`. This is only used to
> > + * clarify the help text and has no effect on option parsing.
> > + *
> > + * The option type tells the parser how to process the argument. Arguments for
> > + * string options (OptionType::OptionString) are stored as-is without any
> > + * processing. Arguments for integer options (OptionType::OptionInteger) are
> > + * converted to an integer value, using an optional base prefix (`0` for base 8,
> > + * `0x` for base 16, none for base 10). Arguments for key-value options are
> > + * parsed by a KeyValueParser given to addOption().
> > + *
> > + * By default, a given option can appear once only in the parsed command line.
> > + * If the option is created as an array option, the parser will accept multiple
> > + * instances of the option. The order in which identical options are specified
> > + * is preserved in the values of an array option.
> > + *
> > + * After preparing the parser, it can be used any number of times to parse
> > + * command line options with the parse() function. The function returns an
> > + * Options instance that stores the values for the parsed options. The
> > + * Options::isSet() function can be used to test if an option has been found,
> > + * and is the only way to access options that take no argument (specified by
> > + * OptionType::OptionNone and OptionArgument::ArgumentNone). For options that
> > + * accept an argument, the option value can be access by Options::operator[]()
> > + * using the option identifier as the key. The order in which different options
> > + * are specified on the command line isn't preserved.
> > + */
> > +
> > +/**
> > + * \class OptionsParser::Options
> > + * \brief An options list generated by the options parser
> > + *
> > + * This is a specialization of OptionsBase with the option reference type set to
> > + * int.
> > + */
> > +
> >  OptionsParser::OptionsParser() = default;
> >  OptionsParser::~OptionsParser() = default;
> >  
> > +/**
> > + * \brief Add an option to the parser
> > + * \param[in] opt The option identifier
> > + * \param[in] type The type of the option argument
> > + * \param[in] help The help text (may be a multi-line string)
> > + * \param[in] name The option name
> > + * \param[in] argument Whether the option accepts an optional argument, a
> > + * mandatory argument, or no argument at all
> > + * \param[in] argumentName The argument name used in the help text
> > + * \param[in] array Whether the option can appear once or multiple times
> > + *
> > + * \return True if the option was added successfully, false if an error
> > + * occurred.
> > + */
> >  bool OptionsParser::addOption(int opt, OptionType type, const char *help,
> >  			      const char *name, OptionArgument argument,
> >  			      const char *argumentName, bool array)
> > @@ -395,6 +760,19 @@ bool OptionsParser::addOption(int opt, OptionType type, const char *help,
> >  	return true;
> >  }
> >  
> > +/**
> > + * \brief Add a key-value pair option to the parser
> > + * \param[in] opt The option identifier
> > + * \param[in] parser The KeyValueParser for the option value
> > + * \param[in] help The help text (may be a multi-line string)
> > + * \param[in] name The option name
> > + * \param[in] array Whether the option can appear once or multiple times
> > + *
> > + * \sa Option
> > + *
> > + * \return True if the option was added successfully, false if an error
> > + * occurred.
> > + */
> >  bool OptionsParser::addOption(int opt, KeyValueParser *parser, const char *help,
> >  			      const char *name, bool array)
> >  {
> > @@ -406,6 +784,19 @@ bool OptionsParser::addOption(int opt, KeyValueParser *parser, const char *help,
> >  	return true;
> >  }
> >  
> > +/**
> > + * \brief Parse command line arguments
> > + * \param[in] argc The number of arguments in the \a argv array
> > + * \param[in] argv The array of arguments
> > + *
> > + * If a parsing error occurs, the parsing stops, the function prints an error
> > + * message that identifies the invalid argument, prints usage information with
> > + * usage(), and returns an invalid container. The container is populated with
> > + * the options successfully parsed so far.
> > + *
> > + * \return A valid container with the list of parsed options on success, or an
> > + * invalid container otherwise
> > + */
> >  OptionsParser::Options OptionsParser::parse(int argc, char **argv)
> >  {
> >  	OptionsParser::Options options;
> > @@ -485,6 +876,14 @@ OptionsParser::Options OptionsParser::parse(int argc, char **argv)
> >  	return options;
> >  }
> >  
> > +/**
> > + * \brief Print usage text to std::cerr
> > + *
> > + * The usage text list all the supported option with their arguments. It is
> > + * generated automatically from the options added to the parser. Caller of this
> > + * function may print additional usage information for the application before
> > + * the list of options.
> > + */
> >  void OptionsParser::usage()
> >  {
> >  	std::cerr << "Options:" << std::endl;
> >

Patch
diff mbox series

diff --git a/src/cam/options.cpp b/src/cam/options.cpp
index 41968caa0ccb..da218c4644d3 100644
--- a/src/cam/options.cpp
+++ b/src/cam/options.cpp
@@ -13,10 +13,80 @@ 
 
 #include "options.h"
 
+/**
+ * \enum OptionArgument
+ * \brief Indicate if an option takes an argument
+ *
+ * \var OptionArgument::ArgumentNone
+ * \brief The option doesn't accept any argument
+ *
+ * \var OptionArgument::ArgumentRequired
+ * \brief The option requires an argument
+ *
+ * \var OptionArgument::ArgumentOptional
+ * \brief The option accepts an optional argument
+ */
+
+/**
+ * \enum OptionType
+ * \brief The type of argument for an option
+ *
+ * \var OptionType::OptionNone
+ * \brief No argument type, used for options that take no argument
+ *
+ * \var OptionType::OptionInteger
+ * \brief Integer argument type, with an optional base prefix (`0` for base 8,
+ * `0x` for base 16, none for base 10)
+ *
+ * \var OptionType::OptionString
+ * \brief String argument
+ *
+ * \var OptionType::OptionKeyValue
+ * \brief key=value list argument
+ */
+
 /* -----------------------------------------------------------------------------
  * Option
  */
 
+/**
+ * \struct Option
+ * \brief Store metadata about an option
+ *
+ * \var Option::opt
+ * \brief The option identifier
+ *
+ * \var Option::type
+ * \brief The type of the option argument
+ *
+ * \var Option::name
+ * \brief The option name
+ *
+ * \var Option::argument
+ * \brief Whether the option accepts an optional argument, a mandatory
+ * argument, or no argument at all
+ *
+ * \var Option::argumentName
+ * \brief The argument name used in the help text
+ *
+ * \var Option::help
+ * \brief The help text (may be a multi-line string)
+ *
+ * \var Option::keyValueParser
+ * \brief For options of type OptionType::OptionKeyValue, the key-value parser
+ * to parse the argument
+ *
+ * \var Option::isArray
+ * \brief Whether the option can appear once or multiple times
+ *
+ * \fn Option::hasShortOption()
+ * \brief Tell if the option has a short option specifier (e.g. `-f`)
+ * \return True if the option has a short option specifier, false otherwise
+ *
+ * \fn Option::hasLongOption()
+ * \brief Tell if the option has a long option specifier (e.g. `--foo`)
+ * \return True if the option has a long option specifier, false otherwise
+ */
 struct Option {
 	int opt;
 	OptionType type;
@@ -32,6 +102,10 @@  struct Option {
 	const char *typeName() const;
 };
 
+/**
+ * \brief Retrieve a string describing the option type
+ * \return A string describing the option type
+ */
 const char *Option::typeName() const
 {
 	switch (type) {
@@ -55,24 +129,65 @@  const char *Option::typeName() const
  * OptionBase<T>
  */
 
+/**
+ * \class template<typename T> OptionBase
+ * \brief Container to store the values of parsed options
+ * \tparam T The type through which options are identified
+ *
+ *
+ * The OptionsBase class is generated by a parser (either OptionsParser or
+ * KeyValueParser) when parsing options. It stores values for all the options
+ * found, and exposes accessor functions to retrieve them. The options are
+ * accessed through an identifier to type \a T, which is an int referencing an
+ * Option::opt for OptionsParser, or a std::string referencing an Option::name
+ * for KeyValueParser.
+ */
+
+/**
+ * \fn OptionsBase::OptionsBase()
+ * \brief Construct an OptionsBase instance
+ *
+ * The constructed instance is initially invalid, and will be populated by the
+ * options parser.
+ */
+
+/**
+ * \brief Tell if the stored options list is empty
+ * \return True if the container is empty, false otherwise
+ */
 template<typename T>
 bool OptionsBase<T>::empty() const
 {
 	return values_.empty();
 }
 
+/**
+ * \brief Tell if the options parsing completed successfully
+ * \return True if the container is returned after successfully parsing
+ * options, false if it is returned after an error was detected during parsing
+ */
 template<typename T>
 bool OptionsBase<T>::valid() const
 {
 	return valid_;
 }
 
+/**
+ * \brief Tell if the option \a opt is specified
+ * \param[in] opt The option to search for
+ * \return True if the \a opt option is set, false otherwise
+ */
 template<typename T>
 bool OptionsBase<T>::isSet(const T &opt) const
 {
 	return values_.find(opt) != values_.end();
 }
 
+/**
+ * \brief Retrieve the value of option \a opt
+ * \param[in] opt The option to retrieve
+ * \return The value of option \a opt if found, an empty OptionValue otherwise
+ */
 template<typename T>
 const OptionValue &OptionsBase<T>::operator[](const T &opt) const
 {
@@ -84,6 +199,13 @@  const OptionValue &OptionsBase<T>::operator[](const T &opt) const
 	return empty;
 }
 
+/**
+ * \brief Mark the container as invalid
+ *
+ * This function can be used in a key-value parser's override of the
+ * KeyValueParser::parse() function to mark the returned options as invalid if
+ * a validation error occurs.
+ */
 template<typename T>
 void OptionsBase<T>::invalidate()
 {
@@ -144,9 +266,46 @@  template class OptionsBase<std::string>;
  * KeyValueParser
  */
 
+/**
+ * \class KeyValueParser
+ * \brief A specialized parser for list of key-value pairs
+ *
+ * The KeyValueParser is an options parser for comma-separated lists of
+ * `key=value` pairs. The supported keys are added to the parser with
+ * addOption(). A given key can only appear once in the parsed list.
+ *
+ * Instances of this class can be passed to the OptionsParser::addOption()
+ * function to create options that take key-value pairs as an option argument.
+ * Specialized versions of the key-value parser can be created by inheriting
+ * from this class, to pre-build the options list in the constructor, and to add
+ * custom validation by overriding the parse() function.
+ */
+
+/**
+ * \class KeyValueParser::Options
+ * \brief An options list generated by the key-value parser
+ *
+ * This is a specialization of OptionsBase with the option reference type set to
+ * std::string.
+ */
+
 KeyValueParser::KeyValueParser() = default;
 KeyValueParser::~KeyValueParser() = default;
 
+/**
+ * \brief Add a supported option to the parser
+ * \param[in] name The option name, corresponding to the key name in the
+ * key=value pair. The name shall be unique.
+ * \param[in] type The type of the value in the key=value pair
+ * \param[in] help The help text
+ * \param[in] argument Whether the value is optional, mandatory or not allowed.
+ * Shall be ArgumentNone if \a type is OptionNone.
+ *
+ * \sa OptionsParser
+ *
+ * \return True if the option was added successfully, false if an error
+ * occurred.
+ */
 bool KeyValueParser::addOption(const char *name, OptionType type,
 			       const char *help, OptionArgument argument)
 {
@@ -166,6 +325,17 @@  bool KeyValueParser::addOption(const char *name, OptionType type,
 	return true;
 }
 
+/**
+ * \brief Parse a string containing a list of key-value pairs
+ * \param[in] arguments The key-value pairs string to parse
+ *
+ * If a parsing error occurs, the parsing stops and the function returns an
+ * invalid container. The container is populated with the options successfully
+ * parsed so far.
+ *
+ * \return A valid container with the list of parsed options on success, or an
+ * invalid container otherwise
+ */
 KeyValueParser::Options KeyValueParser::parse(const char *arguments)
 {
 	Options options;
@@ -278,31 +448,98 @@  void KeyValueParser::usage(int indent)
  * OptionValue
  */
 
+/**
+ * \class OptionValue
+ * \brief Container to store the value of an option
+ *
+ * The OptionValue class is a variant-type container to store the value of an
+ * option. It supports empty values, integers, strings, key-value lists, as well
+ * as arrays of those types. For array values, all array elements shall have the
+ * same type.
+ */
+
+/**
+ * \enum OptionValue::ValueType
+ * \brief The option value type
+ *
+ * \var OptionValue::ValueType::ValueNone
+ * \brief Empty value
+ *
+ * \var OptionValue::ValueType::ValueInteger
+ * \brief Integer value (int)
+ *
+ * \var OptionValue::ValueType::ValueString
+ * \brief String value (std::string)
+ *
+ * \var OptionValue::ValueType::ValueKeyValue
+ * \brief Key-value list value (KeyValueParser::Options)
+ *
+ * \var OptionValue::ValueType::ValueArray
+ * \brief Array value
+ */
+
+/**
+ * \brief Construct an empty OptionValue instance
+ *
+ * The value type is set to ValueType::ValueNone.
+ */
 OptionValue::OptionValue()
 	: type_(ValueNone), integer_(0)
 {
 }
 
+/**
+ * \brief Construct an integer OptionValue instance
+ * \param[in] value The integer value
+ *
+ * The value type is set to ValueType::ValueInteger.
+ */
 OptionValue::OptionValue(int value)
 	: type_(ValueInteger), integer_(value)
 {
 }
 
+/**
+ * \brief Construct a string OptionValue instance
+ * \param[in] value The string value
+ *
+ * The value type is set to ValueType::ValueString.
+ */
 OptionValue::OptionValue(const char *value)
 	: type_(ValueString), integer_(0), string_(value)
 {
 }
 
+/**
+ * \brief Construct a string OptionValue instance
+ * \param[in] value The string value
+ *
+ * The value type is set to ValueType::ValueString.
+ */
 OptionValue::OptionValue(const std::string &value)
 	: type_(ValueString), integer_(0), string_(value)
 {
 }
 
+/**
+ * \brief Construct a key-value OptionValue instance
+ * \param[in] value The key-value list
+ *
+ * The value type is set to ValueType::ValueKeyValue.
+ */
 OptionValue::OptionValue(const KeyValueParser::Options &value)
 	: type_(ValueKeyValue), integer_(0), keyValues_(value)
 {
 }
 
+/**
+ * \brief Add an entry to an array value
+ * \param[in] value The entry value
+ *
+ * This function can only be called if the OptionValue type is
+ * ValueType::ValueNone or ValueType::ValueArray. Upon return, the type will be
+ * set to ValueType::ValueArray.
+ */
 void OptionValue::addValue(const OptionValue &value)
 {
 	assert(type_ == ValueNone || type_ == ValueArray);
@@ -311,26 +548,57 @@  void OptionValue::addValue(const OptionValue &value)
 	array_.push_back(value);
 }
 
+/**
+ * \fn OptionValue::type()
+ * \brief Retrieve the value type
+ * \return The value type
+ */
+
+/**
+ * \brief Cast the value to an int
+ * \return The option value as an int, or 0 if the value type isn't
+ * ValueType::ValueInteger
+ */
 OptionValue::operator int() const
 {
 	return toInteger();
 }
 
+/**
+ * \brief Cast the value to a std::string
+ * \return The option value as an std::string, or an empty string if the value
+ * type isn't ValueType::ValueString
+ */
 OptionValue::operator std::string() const
 {
 	return toString();
 }
 
+/**
+ * \brief Cast the value to a key-value list
+ * \return The option value as a KeyValueParser::Options, or an empty list if
+ * the value type isn't ValueType::ValueKeyValue
+ */
 OptionValue::operator KeyValueParser::Options() const
 {
 	return toKeyValues();
 }
 
+/**
+ * \brief Cast the value to an array
+ * \return The option value as a std::vector of OptionValue, or an empty vector
+ * if the value type isn't ValueType::ValueArray
+ */
 OptionValue::operator std::vector<OptionValue>() const
 {
 	return toArray();
 }
 
+/**
+ * \brief Retrieve the value as an int
+ * \return The option value as an int, or 0 if the value type isn't
+ * ValueType::ValueInteger
+ */
 int OptionValue::toInteger() const
 {
 	if (type_ != ValueInteger)
@@ -339,6 +607,11 @@  int OptionValue::toInteger() const
 	return integer_;
 }
 
+/**
+ * \brief Retrieve the value as a std::string
+ * \return The option value as a std::string, or an empty string if the value
+ * type isn't ValueType::ValueString
+ */
 std::string OptionValue::toString() const
 {
 	if (type_ != ValueString)
@@ -347,6 +620,11 @@  std::string OptionValue::toString() const
 	return string_;
 }
 
+/**
+ * \brief Retrieve the value as a key-value list
+ * \return The option value as a KeyValueParser::Options, or an empty list if
+ * the value type isn't ValueType::ValueKeyValue
+ */
 KeyValueParser::Options OptionValue::toKeyValues() const
 {
 	if (type_ != ValueKeyValue)
@@ -355,6 +633,11 @@  KeyValueParser::Options OptionValue::toKeyValues() const
 	return keyValues_;
 }
 
+/**
+ * \brief Retrieve the value as an array
+ * \return The option value as a std::vector of OptionValue, or an empty vector
+ * if the value type isn't ValueType::ValueArray
+ */
 std::vector<OptionValue> OptionValue::toArray() const
 {
 	if (type_ != ValueArray)
@@ -367,9 +650,91 @@  std::vector<OptionValue> OptionValue::toArray() const
  * OptionsParser
  */
 
+/**
+ * \class OptionsParser
+ * \brief A command line options parser
+ *
+ * The OptionsParser class is an easy to use options parser for POSIX-style
+ * command line options. Supports short (e.g. `-f`) and long (e.g. `--foo`)
+ * options, optional and mandatory arguments, automatic parsing arguments for
+ * integer types and comma-separated list of key=value pairs, and multi-value
+ * arguments. It handles help text generation automatically.
+ *
+ * An OptionsParser instance is initialized by adding supported options with
+ * addOption(). Options are specified by an identifier and a name. If the
+ * identifier is an alphanumeric character, it will be used by the parser as a
+ * short option identifier (e.g. `-f`). The name, if specified, will be used as
+ * a long option identifier (e.g. `--foo`). It should not include the double
+ * dashes. The name is optional if the option identifier is an alphanumeric
+ * character and mandatory otherwise.
+ *
+ * An options has a mandatory help text, which is used to print the full options
+ * list with the usage() function. The help text may be a multi-line string.
+ * Correct indentation of the help text is handled automatically.
+ *
+ * Options accept arguments when created with OptionArgument::ArgumentRequired
+ * or OptionArgument::ArgumentOptional. If the argument is required, it can be
+ * specified as a positional argument after the option (e.g. `-f bar`,
+ * `--foo bar`), collated with the short option (e.g. `-fbar`) or separated from
+ * the long option by an equal sign (e.g. `--foo=bar`'). When the argument is
+ * optional, it must be collated with the short option or separated from the
+ * long option by an equal sign.
+ *
+ * If an option has a required or optional argument, an argument name must be
+ * set when adding the option. The argument name is used in the help text as a
+ * place holder for an argument value. For instance, a `--write` option that
+ * takes a file name as an argument could set the argument name to `filename`,
+ * and the help text would display `--write filename`. This is only used to
+ * clarify the help text and has no effect on option parsing.
+ *
+ * The option type tells the parser how to process the argument. Arguments for
+ * string options (OptionType::OptionString) are stored as-is without any
+ * processing. Arguments for integer options (OptionType::OptionInteger) are
+ * converted to an integer value, using an optional base prefix (`0` for base 8,
+ * `0x` for base 16, none for base 10). Arguments for key-value options are
+ * parsed by a KeyValueParser given to addOption().
+ *
+ * By default, a given option can appear once only in the parsed command line.
+ * If the option is created as an array option, the parser will accept multiple
+ * instances of the option. The order in which identical options are specified
+ * is preserved in the values of an array option.
+ *
+ * After preparing the parser, it can be used any number of times to parse
+ * command line options with the parse() function. The function returns an
+ * Options instance that stores the values for the parsed options. The
+ * Options::isSet() function can be used to test if an option has been found,
+ * and is the only way to access options that take no argument (specified by
+ * OptionType::OptionNone and OptionArgument::ArgumentNone). For options that
+ * accept an argument, the option value can be access by Options::operator[]()
+ * using the option identifier as the key. The order in which different options
+ * are specified on the command line isn't preserved.
+ */
+
+/**
+ * \class OptionsParser::Options
+ * \brief An options list generated by the options parser
+ *
+ * This is a specialization of OptionsBase with the option reference type set to
+ * int.
+ */
+
 OptionsParser::OptionsParser() = default;
 OptionsParser::~OptionsParser() = default;
 
+/**
+ * \brief Add an option to the parser
+ * \param[in] opt The option identifier
+ * \param[in] type The type of the option argument
+ * \param[in] help The help text (may be a multi-line string)
+ * \param[in] name The option name
+ * \param[in] argument Whether the option accepts an optional argument, a
+ * mandatory argument, or no argument at all
+ * \param[in] argumentName The argument name used in the help text
+ * \param[in] array Whether the option can appear once or multiple times
+ *
+ * \return True if the option was added successfully, false if an error
+ * occurred.
+ */
 bool OptionsParser::addOption(int opt, OptionType type, const char *help,
 			      const char *name, OptionArgument argument,
 			      const char *argumentName, bool array)
@@ -395,6 +760,19 @@  bool OptionsParser::addOption(int opt, OptionType type, const char *help,
 	return true;
 }
 
+/**
+ * \brief Add a key-value pair option to the parser
+ * \param[in] opt The option identifier
+ * \param[in] parser The KeyValueParser for the option value
+ * \param[in] help The help text (may be a multi-line string)
+ * \param[in] name The option name
+ * \param[in] array Whether the option can appear once or multiple times
+ *
+ * \sa Option
+ *
+ * \return True if the option was added successfully, false if an error
+ * occurred.
+ */
 bool OptionsParser::addOption(int opt, KeyValueParser *parser, const char *help,
 			      const char *name, bool array)
 {
@@ -406,6 +784,19 @@  bool OptionsParser::addOption(int opt, KeyValueParser *parser, const char *help,
 	return true;
 }
 
+/**
+ * \brief Parse command line arguments
+ * \param[in] argc The number of arguments in the \a argv array
+ * \param[in] argv The array of arguments
+ *
+ * If a parsing error occurs, the parsing stops, the function prints an error
+ * message that identifies the invalid argument, prints usage information with
+ * usage(), and returns an invalid container. The container is populated with
+ * the options successfully parsed so far.
+ *
+ * \return A valid container with the list of parsed options on success, or an
+ * invalid container otherwise
+ */
 OptionsParser::Options OptionsParser::parse(int argc, char **argv)
 {
 	OptionsParser::Options options;
@@ -485,6 +876,14 @@  OptionsParser::Options OptionsParser::parse(int argc, char **argv)
 	return options;
 }
 
+/**
+ * \brief Print usage text to std::cerr
+ *
+ * The usage text list all the supported option with their arguments. It is
+ * generated automatically from the options added to the parser. Caller of this
+ * function may print additional usage information for the application before
+ * the list of options.
+ */
 void OptionsParser::usage()
 {
 	std::cerr << "Options:" << std::endl;