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<string, string> reg_foo(const string& 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<string>(), 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<string> 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<wchar_t, 368 char></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<string> 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