In the tutorial section, we saw several examples of library usage. Here we will describe the overall library design including the primary components and their function. The library has three main components:
To be a little more concrete, the In the tutorial we've learned how those components can be used by the
For that outside world, the storage component is the most important. It provides a class which stores all option values and that class can be freely passed around your program to modules which need access to the options. All the other components can be used only in the place where the actual parsing is the done. However, it might also make sense for the individual program modules to describe their options and pass them to the main module, which will merge all options. Of course, this is only important when the number of options is large and declaring them in one place becomes troublesome. The options description component has three main classes:
For almost every library, those classes could be created in a
conventional way: that is, you'd create new options using constructors and
then call the options_description desc; desc.add_options() ("help", "produce help") ("optimization", value<int>()->default_value(10), "optimization level") ;
The call to the
Note that in addition to the
The information about an option is divided into syntactic and
semantic. Syntactic information includes the name of the option and the
number of tokens which can be used to specify the value. This
information is used by parsers to group tokens into (name, value) pairs,
where value is just a vector of strings
( This separation is an important part of library design. The parsers use only the syntactic layer, which takes away some of the freedom to use overly complex structures. For example, it's not easy to parse syntax like: calc --expression=1 + 2/3 because it's not possible to parse 1 + 2/3 without knowing that it's a C expression. With a little help from the user the task becomes trivial, and the syntax clear: calc --expression="1 + 2/3"
The syntactic information is provided by the
Consider the following example: options_description desc; desc.add_options() ("help", "produce help message") ("compression", value<string>(), "compression level") ("verbose", value<string>()->zero_tokens(), "verbosity level") ("email", value<string>()->multitoken(), "email to send to") ; For the first parameter, we specify only the name and the description. No value can be specified in the parsed source. For the first option, the user must specify a value, using a single token. For the third option, the user may either provide a single token for the value, or no token at all. For the last option, the value can span several tokens. For example, the following command line is OK: test --help --compression 10 --verbose --email beadle@mars beadle2@mars
Sometimes the description can get rather long, for example, when several option's values need separate documentation. Below we describe some simple formatting mechanisms you can use. The description string has one or more paragraphs, separated by the newline character ('\n'). When an option is output, the library will compute the indentation for options's description. Each of the paragraph is output as a separate line with that intentation. If a paragraph does not fit on one line it is spanned over multiple lines (which will have the same indentation). You may specify additional indent for the first specified by inserting spaces at the beginning of a paragraph. For example: options.add_options() ("help", " A long help msg a long help msg a long help msg a long help msg a long help msg a long help msg a long help msg a long help msg ") ; will specify a four-space indent for the first line. The output will look like: --help A long help msg a long help msg a long help msg a long help msg a long help msg a long help msg a long help msg a long help msg
For the case where line is wrapped, you can want an additional indent for wrapped text. This can be done by inserting a tabulator character ('\t') at the desired position. For example: options.add_options() ("well_formated", "As you can see this is a very well formatted option description.\n" "You can do this for example:\n\n" "Values:\n" " Value1: \tdoes this and that, bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla\n" " Value2: \tdoes something else, bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla\n\n" " This paragraph has a first line indent only, bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla"); will produce: --well_formated As you can see this is a very well formatted option description. You can do this for example: Values: Value1: does this and that, bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla Value2: does something else, bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla This paragraph has a first line indent only, bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla The tab character is removed before output. Only one tabulator per paragraph is allowed, otherwisee an exception of type program_options::error is thrown. Finally, the tabulator is ignored if it's is not on the first line of the paragraph or is on the last possible position of the first line. The semantic information is completely provided by the
options_description desc; desc.add_options() ("compression", value<int>()->default_value(10), "compression level") ("email", value< vector<string> >() ->composing()->notifier(&your_function), "email") ;
These declarations specify that default value of the first option is 10,
that the second option can appear several times and all instances should
be merged, and that after parsing is done, the library will call
function Our definition of option as (name, value) pairs is simple and useful, but in one special case of the command line, there's a problem. A command line can include a positional option, which does not specify any name at all, for example: archiver --compression=9 /etc/passwd Here, the "/etc/passwd" element does not have any option name. One solution is to ask the user to extract positional options himself and process them as he likes. However, there's a nicer approach -- provide a method to automatically assign the names for positional options, so that the above command line can be interpreted the same way as: archiver --compression=9 --input-file=/etc/passwd
The positional_options_description pd; pd.add("input-file", 1); specifies that for exactly one, first, positional option the name will be "input-file". It's possible to specify that a number, or even all positional options, be given the same name. positional_options_description pd; pd.add("output-file", 2).add("input-file", -1); In the above example, the first two positional options will be associated with name "output-file", and any others with the name "input-file".
The parsers component splits input sources into (name, value) pairs.
Each parser looks for possible options and consults the options
description component to determine if the option is known and how its value
is specified. In the simplest case, the name is explicitly specified,
which allows the library to decide if such option is known. If it is known, the
To invoke a parser you typically call a function, passing the options
description and command line or config file or something else.
The results of parsing are returned as an instance of the There are three exceptions to the above model -- all related to traditional usage of the command line. While they require some support from the options description component, the additional complexity is tolerable.
The storage component is responsible for:
Let's consider an example: variables_map vm; store(parse_command_line(argc, argv, desc), vm); store(parse_config_file("example.cfg", desc), vm); notify(vm);
The The priority is handled in a simple way: the
The
The option names are relative to the section names, so the following configuration file part: [gui.accessibility] visual_bell=yes is equivalent to gui.accessibility.visual_bell=yes Environment variables are string variables
which are available to all programs via the The environment variables can be parsed with the
If you have an option that should be specified via environment
variable, you need make up the variable's name. To avoid name clashes,
we suggest that you use a sufficiently unique prefix for environment
variables. Also, while option names are most likely in lower case,
environment variables conventionally use upper case. So, for an option
name The above logic is sufficient in many cases, but it is also
possible to pass, as the second parameter of the The following table describes all the important symbols in the library, for quick access.
|