Chapter 18. Parsing command line options

Index

Option parser generator
Specifying option types
Mutually exclusive options
Combining numeric options
Default option values
Option groups
Defining an option parsing subclass
Localizing option strings
Using gettextmsg() with localizable strings
GNU make macros
Using GNU make macros with automake
#include <x/options.H>
#include <x/locale.H>

x::locale defLocale(x::locale::create(""));

x::option::bool_value verbose_value(option::bool_value::create());

x::option::list options(option::list::create());

options->add(verbose_value, L'v', L"verbose",
             0,
             L"Verbose messages");

options->addDefaultOptions();

x::option::parser optParser(x::option::parser::create(defLocale));

optParser->setOptions(options);

int err=optParser->parseArgv(argc, argv);

if (err == 0)
    err=optParser->validate();

if (err == x::option::parser::err_builtin)
{
    exit(0);
}

if (err)
{
    std::cerr <<optParser->errmessage();
    exit(1);
}

if (verbose_value->value)
{
// ...
}

A set of classes in the x::option namespace implements a flexible mechanism for parsing command line options. They can be used instead of, or together with application properties.

First, objects representing values of individual options get instantiated, then assembled into an option list. Default options, with an internal implemention of those options, get added to the list, if desired. A parser object gets instantiated which takes the list of options, and the actual command line arguments, parses them, and places each parsed option's value, if specified, in its corresponding object. See the documentation for more information and examples.

An alternative to manually writing option parsing code is the option parser generator. The generator produces option parsing code from an XML file that compactly defines the list of options.

Option parser generator

<optclass name="testoptions">
  <option>
    <name>verbose</name>
    <type>bool</type>
    <default>false</default>
    <opt>v</opt>
    <descr>Enable verbose mode</descr>
  </option>

  <option>
    <name>filename</name>
    <type>string</type>
    <opt>-f</opt>
    <longopt>filename</longopt>
    <list />
    <hasvalue />
    <descr>List of input filenames</descr>
    <argdescr>filename</argdescr>
  </option>
  <arg>
    <name>inputfile</name>
    <required />
  </arg>

  <defaultoptions />  
</optclass>

This XML file defines command line options, and gets processed by an XSLT file, installed by default as /usr/share/libcxx/optgen.xsl or as /usr/local/share/libcxx/optgen.xsl. Use an XSLT processor, such as xsltproc, to turn it into a class definition. If this XML file is saved as testoptions.xml:

xsltproc /usr/share/libcxx/optgen.xsl testoptions.xml >testoptions.h

The stylesheet output defines a class specified by the name attribute of the top level optclass element, which is testoptions in this example. This becomes the name of the class:

#include "testoptions.h"

// ...

int main(int argc, char **argv)
{
    testoptions opts;

    std::list<std::string> args(opts.parse(argc, argv)->args);

    if (opts.verbose->isSet())
    {
        std::cout << "-v was provided, and it's " << opts.verbose->value
                  << std::endl;
    }

    for (std::list<std::string>::iterator b(opts.filenames->values.begin()),
         e(opts.filenames->values.end()); b != e; ++b)
    {
        std::cout << "--filename " << *b << std::endl;
    }

    for (std::list<std::string>::iterator b(args.begin()),
         e(args.end()); b != e; ++b)
    {
        std::cout << "argument: " << *b << std::endl;
    }
}

The option class defines a getParser() function that returns an x::option::parser that's been populated with the option list from the class. parse() calls getParser(), parses the argument vector received by main(), calls validate() to check for missing options, then returns the resulting x::option::parser, whose args member is the list of command line arguments with all the options removed.

The options get parsed into the members of the option class whose names are given by each option's name element. Each option defines an option, and all names of all the options, therefore, must be unique and follow the rules for class element names.

The above example defines a verbose option. opt gives option's short character, -v. longopt gives the option's long name that's introduced by two dashes, such as --filename, as shown in the example. An option may have a short character, or a long name, or both.

Option class members are references to objects with an isSet() element that indicates whether the given option was specified. An option's value may be retrieved from the value member. The presence of hasvalue indicates that the option takes a value (see class documentation for more information on the syntax for specifying option values). list indicates that the option may occur more than once. Instead of a value, there is a a std::list names values that contains all the collected values.

default is optional, and sets the default value if the option is not specified. The contents of the default are placed in the generated code directly.

defaultoptions adds and implements the --help and --usage options that combine the defined options with each one's descr, that gives a brief description of the option, and argdescr, the option's value (should be one word) into a generic help and usage blurb. args describe the remaining parameters after all the options get removed.

args do not get validated or used in any way, except as a part of the generic help and usage blurb. They contain only a name, the name of each remaining parameter, with the presence of required indicating that it's mandatory.

required may also appear inside an option, indicating a mandatory option.