• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1<?xml version="1.0" standalone="yes"?>
2<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
3     "http://www.boost.org/tools/boostbook/dtd/boostbook.dtd"
4[
5    <!ENTITY % entities SYSTEM "program_options.ent" >
6    %entities;
7]>
8<section id="program_options.howto">
9
10  <title>How To</title>
11
12  <para>This section describes how the library can be used in specific
13  situations.</para>
14
15<!--
16
17validators
18positional options
19options groups/hidden options
20
21-->
22  <section>
23    <title>Non-conventional Syntax</title>
24
25    <para>Sometimes, standard command line syntaxes are not enough. For
26    example, the gcc compiler has "-frtti" and -fno-rtti" options, and this
27    syntax is not directly supported.
28    </para>
29
30    <indexterm><primary>additional parser</primary></indexterm>
31    <para>For such cases, the library allows the user to provide an
32    <firstterm>additional parser</firstterm> -- a function which will be called on each
33    command line element, before any processing by the library. If the
34    additional parser recognises the syntax, it returns the option name and
35    value, which are used directly. The above example can be handled by the
36    following code:
37    </para>
38
39    <para>
40      <programlisting>
41pair&lt;string, string&gt; reg_foo(const string&amp; s)
42{
43    if (s.find("-f") == 0) {
44        if (s.substr(2, 3) == "no-")
45            return make_pair(s.substr(5), string("false"));
46        else
47            return make_pair(s.substr(2), string("true"));
48    } else {
49        return make_pair(string(), string());
50    }
51}
52</programlisting>
53      Here's the definition of the additional parser. When parsing the command
54      line, we pass the additional parser:
55<programlisting>
56store(command_line_parser(ac, av).options(desc).extra_parser(reg_foo)
57        .run(), vm);
58</programlisting>
59      The complete example can be found in the "example/custom_syntax.cpp"
60      file.
61    </para>
62  </section>
63
64  <section>
65    <title>Response Files</title>
66
67    <indexterm><primary>response files</primary></indexterm>
68
69    <para>Some operating system have very low limits of the command line
70      length. The common way to work around those limitations is using
71      <firstterm>response files</firstterm>.  A response file is just a
72      configuration file which uses the same syntax as the command line. If
73      the command line specifies a name of response file to use, it's loaded
74      and parsed in addition to the command line.  The library does not
75      provide direct support for response files, so you'll need to write some
76      extra code.
77    </para>
78
79    <para>
80      First, you need to define an option for the response file:
81<programlisting>
82("response-file", value&lt;string&gt;(),
83     "can be specified with '@name', too")
84</programlisting>
85    </para>
86
87    <para>Second, you'll need an additional parser to support the standard syntax
88    for specifying response files: "@file":
89<programlisting><![CDATA[
90pair<string, string> at_option_parser(string const&s)
91{
92    if ('@' == s[0])
93        return std::make_pair(string("response-file"), s.substr(1));
94    else
95        return pair<string, string>();
96}
97]]>
98</programlisting>
99    </para>
100
101    <para>Finally, when the "response-file" option is found, you'll have to
102    load that file and pass it to the command line parser. This part is the
103    hardest. We'll use the Boost.Tokenizer library, which works but has some
104    limitations. You might also consider Boost.StringAlgo. The code is:
105<programlisting><![CDATA[
106if (vm.count("response-file")) {
107     // Load the file and tokenize it
108     ifstream ifs(vm["response-file"].as<string>().c_str());
109     if (!ifs) {
110         cout << "Could not open the response file\n";
111         return 1;
112     }
113     // Read the whole file into a string
114     stringstream ss;
115     ss << ifs.rdbuf();
116     // Split the file content
117     char_separator<char> sep(" \n\r");
118     std::string ResponsefileContents( ss.str() );
119     tokenizer<char_separator<char> > tok(ResponsefileContents, sep);
120     vector<string> args;
121     copy(tok.begin(), tok.end(), back_inserter(args));
122     // Parse the file and store the options
123     store(command_line_parser(args).options(desc).run(), vm);
124}
125]]>
126</programlisting>
127      The complete example can be found in the "example/response_file.cpp"
128      file.
129    </para>
130
131  </section>
132
133  <section>
134    <title>Winmain Command Line</title>
135
136    <para>On the Windows operating system, GUI applications receive the
137    command line as a single string, not split into elements. For that reason,
138    the command line parser cannot be used directly. At least on some
139    compilers, it is possible to obtain
140    the split command line, but it's not clear if all compilers support the
141    same mechanism on all versions of the operating system. The
142    <code>split_winmain</code> function is a portable mechanism provided
143    by the library.</para>
144
145    <para>Here's an example of use:
146<programlisting>
147vector&lt;string&gt; args = split_winmain(lpCmdLine);
148store(command_line_parser(args).options(desc).run(), vm);
149</programlisting>
150      The <code>split_winmain</code> function is overloaded for <code>wchar_t</code> strings, so can
151      also be used in Unicode applications.
152    </para>
153
154  </section>
155
156  <section>
157    <title>Option Groups and Hidden Options</title>
158
159    <para>Having a single instance of the &options_description; class with all
160    the program's options can be problematic:
161      <itemizedlist>
162        <listitem>
163          <para>Some options make sense only for specific source, for example,
164          configuration files.</para>
165        </listitem>
166        <listitem>
167          <para>The user would prefer some structure in the generated help message.</para>
168        </listitem>
169        <listitem>
170          <para>Some options shouldn't appear in the generated help message at all.</para>
171        </listitem>
172      </itemizedlist>
173    </para>
174
175    <para>To solve the above issues, the library allows a programmer to create several
176      instances of the &options_description; class, which can be merged in
177      different combinations. The following example will define three groups of
178      options: command line specific, and two options group for specific program
179      modules, only one of which is shown in the generated help message.
180    </para>
181
182    <para>Each group is defined using standard syntax. However, you should
183      use reasonable names for each &options_description; instance:
184<programlisting><![CDATA[
185options_description general("General options");
186general.add_options()
187    ("help", "produce a help message")
188    ("help-module", value<string>(),
189        "produce a help for a given module")
190    ("version", "output the version number")
191    ;
192
193options_description gui("GUI options");
194gui.add_options()
195    ("display", value<string>(), "display to use")
196    ;
197
198options_description backend("Backend options");
199backend.add_options()
200    ("num-threads", value<int>(), "the initial number of threads")
201    ;
202]]></programlisting>
203    </para>
204
205    <para>After declaring options groups, we merge them in two
206      combinations. The first will include all options and be used for parsing. The
207      second will be used for the "--help" option.
208<programlisting>
209// Declare an options description instance which will include
210// all the options
211options_description all("Allowed options");
212all.add(general).add(gui).add(backend);
213
214// Declare an options description instance which will be shown
215// to the user
216options_description visible("Allowed options");
217visible.add(general).add(gui);
218</programlisting>
219    </para>
220
221    <para>What is left is to parse and handle the options:
222<programlisting><![CDATA[
223variables_map vm;
224store(parse_command_line(ac, av, all), vm);
225
226if (vm.count("help"))
227{
228    cout << visible;
229    return 0;
230}
231if (vm.count("help-module")) {
232    const string& s = vm["help-module"].as<string>();
233    if (s == "gui") {
234        cout << gui;
235    } else if (s == "backend") {
236        cout << backend;
237    } else {
238        cout << "Unknown module '"
239             << s << "' in the --help-module option\n";
240        return 1;
241    }
242    return 0;
243}
244if (vm.count("num-threads")) {
245    cout << "The 'num-threads' options was set to "
246         << vm["num-threads"].as<int>() << "\n";
247}
248]]></programlisting>
249      When parsing the command line, all options are allowed. The "--help"
250      message, however, does not include the "Backend options" group -- the
251      options in that group are hidden. The user can explicitly force the
252      display of that options group by passing "--help-module backend"
253      option. The complete example can be found in the
254      "example/option_groups.cpp" file.
255    </para>
256
257  </section>
258
259  <section>
260    <title>Custom Validators</title>
261
262    <para>By default, the conversion of option's value from string into C++
263      type is done using iostreams, which sometimes is not convenient. The
264      library allows the user to customize the conversion for specific
265      classes. In order to do so, the user should provide suitable overload of
266      the <code>validate</code> function.
267    </para>
268
269    <para>
270      Let's first define a simple class:
271<programlisting><![CDATA[
272struct magic_number {
273public:
274    magic_number(int n) : n(n) {}
275    int n;
276};
277]]></programlisting> and then overload the <code>validate</code> function:
278<programlisting><![CDATA[
279void validate(boost::any& v,
280              const std::vector<std::string>& values,
281              magic_number* target_type, int)
282{
283    static regex r("\\d\\d\\d-(\\d\\d\\d)");
284
285    using namespace boost::program_options;
286
287    // Make sure no previous assignment to 'a' was made.
288    validators::check_first_occurrence(v);
289    // Extract the first string from 'values'. If there is more than
290    // one string, it's an error, and exception will be thrown.
291    const string& s = validators::get_single_string(values);
292
293    // Do regex match and convert the interesting part to
294    // int.
295    smatch match;
296    if (regex_match(s, match, r)) {
297        v = any(magic_number(lexical_cast<int>(match[1])));
298    } else {
299        throw validation_error(validation_error::invalid_option_value);
300    }
301}
302]]>
303</programlisting>The function takes four parameters. The first is the storage
304      for the value, and in this case is either empty or contains an instance of
305      the <code>magic_number</code> class. The second is the list of strings
306      found in the next occurrence of the option. The remaining two parameters
307      are needed to workaround the lack of partial template specialization and
308      partial function template ordering on some compilers.
309    </para>
310
311    <para>The function first checks that we don't try to assign to the same
312      option twice. Then it checks that only a single string was passed
313      in. Next the string is verified with the help of the Boost.Regex
314      library. If that test is passed, the parsed value is stored into the
315      <code>v</code> variable.
316    </para>
317
318    <para>The complete example can be found in the "example/regex.cpp" file.
319    </para>
320
321
322  </section>
323
324  <section>
325    <title>Unicode Support</title>
326
327    <para>To use the library with Unicode, you'd need to:
328      <itemizedlist>
329        <listitem>
330          <para>Use Unicode-aware parsers for Unicode input</para>
331        </listitem>
332        <listitem>
333          <para>Require Unicode support for options which need it</para>
334        </listitem>
335      </itemizedlist>
336    </para>
337
338    <para>Most of the parsers have Unicode versions. For example, the
339      &parse_command_line; function has an overload which takes
340      <code>wchar_t</code> strings, instead of ordinary <code>char</code>.
341    </para>
342
343    <para>Even if some of the parsers are Unicode-aware, it does not mean you
344    need to change definition of all the options. In fact, for many options,
345    like integer ones, it makes no sense. To make use of Unicode you'll need
346    <emphasis>some</emphasis> Unicode-aware options. They are different from
347    ordinary options in that they accept <code>wstring</code> input, and
348    process it using wide character streams. Creating an Unicode-aware option
349    is easy: just use the the <code>wvalue</code> function instead of the
350    regular <code>value</code>.
351    </para>
352
353    <para>When an ascii parser passes data to an ascii option, or a Unicode
354      parser passes data to a Unicode option, the data are not changed at
355      all. So, the ascii option will see a string in local 8-bit encoding, and
356      the Unicode option will see whatever string was passed as the Unicode
357      input.
358    </para>
359
360    <para>What happens when Unicode data is passed to an ascii option, and
361      vice versa? The library automatically performs the conversion from
362      Unicode to local 8-bit encoding. For example, if command line is in
363      ascii, but you use <code>wstring</code> options, then the ascii input
364      will be converted into Unicode.
365    </para>
366
367    <para>To perform the conversion, the library uses the <code>codecvt&lt;wchar_t,
368    char&gt;</code> locale facet from the global locale. If
369    you want to work with strings that use local 8-bit encoding (as opposed to
370    7-bit ascii subset), your application should start with:
371      <programlisting>
372locale::global(locale(""));
373      </programlisting>
374      which would set up the conversion facet according to the user's selected
375      locale.
376    </para>
377
378    <para>It's wise to check the status of the C++ locale support on your
379      implementation, though. The quick test involves three steps:
380      <orderedlist>
381        <listitem>
382          <para>Go the the "test" directory and build the "test_convert" binary.</para>
383        </listitem>
384        <listitem>
385          <para>Set some non-ascii locale in the environment. On Linux, one can
386          run, for example: <screen>
387$ export LC_CTYPE=ru_RU.KOI8-R
388</screen>
389          </para>
390        </listitem>
391        <listitem>
392          <para>Run the "test_convert" binary with any non-ascii string in the
393            selected encoding as its parameter. If you see a list of Unicode codepoints,
394            everything's OK. Otherwise, locale support on your system might be
395            broken.</para>
396        </listitem>
397      </orderedlist>
398    </para>
399
400    </section>
401
402    <section>
403      <title>Allowing Unknown Options</title>
404
405      <para>Usually, the library throws an exception on unknown option names. This
406      behaviour can be changed. For example, only some part of your application uses
407      <libraryname>Program_options</libraryname>, and you wish to pass unrecognized options to another part of
408      the program, or even to another application.</para>
409
410      <para>To allow unregistered options on the command line, you need to use
411      the &basic_command_line_parser; class for parsing (not &parse_command_line;)
412      and call the <methodname alt="boost::program_options::basic_command_line_parser::allow_unregistered">allow_unregistered</methodname>
413      method of that class:
414      <programlisting>
415parsed_options parsed =
416    command_line_parser(argc, argv).options(desc).allow_unregistered().run();
417      </programlisting>
418
419      For each token that looks like an option, but does not have a known name,
420      an instance of &basic_option; will be added to the result.
421      The <code>string_key</code> and <code>value</code> fields of the instance will contain results
422      of syntactic parsing of the token, the <code>unregistered</code> field will be set to <code>true</code>,
423      and the <code>original_tokens</code> field will contain the token as it appeared on the command line.
424      </para>
425
426      <para>If you want to pass the unrecognized options further, the
427      <functionname alt="boost::program_options::collect_unrecognized">collect_unrecognized</functionname> function can be used.
428      The function will collect original tokens for all unrecognized values, and optionally, all found positional options.
429      Say, if your code handles a few options, but does not handle positional options at all, you can use the function like this:
430      <programlisting>
431vector&lt;string&gt; to_pass_further = collect_unrecognized(parsed.options, include_positional);
432      </programlisting>
433
434      </para>
435
436    </section>
437
438    <section>
439      <title>Testing Option Presence</title>
440
441      <para>Until now we have tested whether an option has been set using the
442      <methodname alt="boost::program_options::variables_map::count">count</methodname> method on the &variables_map;
443      class; as you are repeating the (string literal) name of the option this is prone to typos and/or errors
444      resulting from renaming the option in one place but not the other:
445        <programlisting><![CDATA[
446po::options_description desc("Allowed options");
447desc.add_options()
448    ("compression", po::value<int>(), "set compression level")
449;
450
451po::variables_map vm;
452po::store(po::parse_command_line(ac, av, desc), vm);
453po::notify(vm);
454
455if (vm.count("compression")) {
456    cout << "Compression level was set to "
457 << vm["compression"].as<int>() << ".\n";
458} else {
459    cout << "Compression level was not set.\n";
460}
461]]>
462        </programlisting>
463      </para>
464
465      <para>Instead, you can use a variable of type <classname alt="boost::optional">boost::optional</classname>;
466      <libraryname>Program_options</libraryname> provides special support for <libraryname>Boost.Optional</libraryname>
467      such that if the user specifies the option the <classname alt="boost::optional">boost::optional</classname>
468      variable will be initialized to the appropriate value:
469        <programlisting><![CDATA[
470po::options_description desc("Allowed options");
471boost::optional<int> compression;
472desc.add_options()
473    ("compression", po::value(&compression), "set compression level")
474;
475
476po::variables_map vm;
477po::store(po::parse_command_line(ac, av, desc), vm);
478po::notify(vm);
479
480if (compression) {
481    cout << "Compression level was set to " << *compression << ".\n";
482} else {
483    cout << "Compression level was not set.\n";
484}
485]]>
486        </programlisting>
487      </para>
488    </section>
489
490</section>
491
492<!--
493     Local Variables:
494     mode: nxml
495     sgml-indent-data: t
496     sgml-parent-document: ("userman.xml" "chapter")
497     sgml-set-face: t
498     End:
499-->
500